1
0
mirror of https://github.com/rancher/os.git synced 2025-09-03 15:54:24 +00:00

refactor a little and keep the datasource errors for later

Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>
This commit is contained in:
Sven Dowideit
2017-03-01 15:12:56 +10:00
parent 23a4d8ec76
commit 391082fa50
16 changed files with 181 additions and 91 deletions

View File

@@ -20,12 +20,10 @@ import (
"os"
"strings"
"sync"
"syscall"
"time"
yaml "github.com/cloudfoundry-incubator/candiedyaml"
"github.com/docker/docker/pkg/mount"
"github.com/rancher/os/cmd/control"
"github.com/rancher/os/cmd/network"
rancherConfig "github.com/rancher/os/config"
@@ -49,9 +47,6 @@ const (
datasourceInterval = 100 * time.Millisecond
datasourceMaxInterval = 30 * time.Second
datasourceTimeout = 5 * time.Minute
configDevName = "config-2"
configDev = "LABEL=" + configDevName
configDevMountPoint = "/media/config-2"
)
func Main() {
@@ -70,29 +65,8 @@ func Main() {
}
}
func MountConfigDrive() error {
if err := os.MkdirAll(configDevMountPoint, 644); err != nil {
return err
}
configDev := util.ResolveDevice(configDev)
if configDev == "" {
return mount.Mount(configDevName, configDevMountPoint, "9p", "trans=virtio,version=9p2000.L")
}
fsType, err := util.GetFsType(configDev)
if err != nil {
return err
}
return mount.Mount(configDev, configDevMountPoint, fsType, "ro")
}
func UnmountConfigDrive() error {
return syscall.Unmount(configDevMountPoint, 0)
}
func SaveCloudConfig(network bool) error {
log.Debugf("SaveCloudConfig")
userDataBytes, metadata, err := fetchUserData(network)
if err != nil {
return err
@@ -178,6 +152,7 @@ func currentDatasource(network bool) (datasource.Datasource, error) {
dss := getDatasources(cfg, network)
if len(dss) == 0 {
log.Errorf("currentDatasource - none found")
return nil, nil
}
@@ -299,11 +274,13 @@ func selectDatasource(sources []datasource.Datasource) datasource.Datasource {
duration := datasourceInterval
for {
log.Infof("Checking availability of %q\n", s.Type())
log.Infof("cloud-init: Checking availability of %q\n", s.Type())
if s.IsAvailable() {
ds <- s
return
} else if !s.AvailabilityChanges() {
}
log.Errorf("cloud-init: Datasource not ready: %s", s)
if !s.AvailabilityChanges() {
return
}
select {

72
config/cloudinit/datasource/configdrive/configdrive.go Normal file → Executable file
View File

@@ -16,30 +16,59 @@ package configdrive
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"os"
"path"
"syscall"
"github.com/rancher/os/log"
"github.com/docker/docker/pkg/mount"
"github.com/rancher/os/config/cloudinit/datasource"
"github.com/rancher/os/util"
)
const (
configDevName = "config-2"
configDev = "LABEL=" + configDevName
configDevMountPoint = "/media/config-2"
openstackAPIVersion = "latest"
)
type ConfigDrive struct {
root string
readFile func(filename string) ([]byte, error)
lastError error
}
func NewDatasource(root string) *ConfigDrive {
return &ConfigDrive{root, ioutil.ReadFile}
return &ConfigDrive{root, ioutil.ReadFile, nil}
}
func (cd *ConfigDrive) IsAvailable() bool {
_, err := os.Stat(cd.root)
return !os.IsNotExist(err)
if cd.root == configDevMountPoint {
cd.lastError = MountConfigDrive()
if cd.lastError != nil {
log.Error(cd.lastError)
return false
}
defer cd.Finish()
}
_, cd.lastError = os.Stat(cd.root)
return !os.IsNotExist(cd.lastError)
}
func (cd *ConfigDrive) Finish() error {
return UnmountConfigDrive()
}
func (cd *ConfigDrive) String() string {
if cd.lastError != nil {
return fmt.Sprintf("%s: %s (lastError: %s)", cd.Type(), cd.root, cd.lastError)
}
return fmt.Sprintf("%s: %s", cd.Type(), cd.root)
}
func (cd *ConfigDrive) AvailabilityChanges() bool {
@@ -93,10 +122,45 @@ func (cd *ConfigDrive) openstackVersionRoot() string {
}
func (cd *ConfigDrive) tryReadFile(filename string) ([]byte, error) {
if cd.root == configDevMountPoint {
cd.lastError = MountConfigDrive()
if cd.lastError != nil {
log.Error(cd.lastError)
return nil, cd.lastError
}
defer cd.Finish()
}
log.Printf("Attempting to read from %q\n", filename)
data, err := cd.readFile(filename)
if os.IsNotExist(err) {
err = nil
}
if err != nil {
log.Errorf("ERROR read cloud-config file(%s) - err: %q", filename, err)
} else {
log.Debugf("SUCCESS read cloud-config file(%s) - date: %s", filename, string(data))
}
return data, err
}
func MountConfigDrive() error {
if err := os.MkdirAll(configDevMountPoint, 644); err != nil {
return err
}
configDev := util.ResolveDevice(configDev)
if configDev == "" {
return mount.Mount(configDevName, configDevMountPoint, "9p", "trans=virtio,version=9p2000.L")
}
fsType, err := util.GetFsType(configDev)
if err != nil {
return err
}
return mount.Mount(configDev, configDevMountPoint, fsType, "ro")
}
func UnmountConfigDrive() error {
return syscall.Unmount(configDevMountPoint, 0)
}

View File

@@ -57,7 +57,7 @@ func TestFetchMetadata(t *testing.T) {
},
},
} {
cd := ConfigDrive{tt.root, tt.files.ReadFile}
cd := ConfigDrive{tt.root, tt.files.ReadFile, nil}
metadata, err := cd.FetchMetadata()
if err != nil {
t.Fatalf("bad error for %+v: want %v, got %q", tt, nil, err)
@@ -91,7 +91,7 @@ func TestFetchUserdata(t *testing.T) {
"userdata",
},
} {
cd := ConfigDrive{tt.root, tt.files.ReadFile}
cd := ConfigDrive{tt.root, tt.files.ReadFile, nil}
userdata, err := cd.FetchUserdata()
if err != nil {
t.Fatalf("bad error for %+v: want %v, got %q", tt, nil, err)
@@ -116,7 +116,7 @@ func TestConfigRoot(t *testing.T) {
"/media/configdrive/openstack",
},
} {
cd := ConfigDrive{tt.root, nil}
cd := ConfigDrive{tt.root, nil, nil}
if configRoot := cd.ConfigRoot(); configRoot != tt.configRoot {
t.Fatalf("bad config root for %q: want %q, got %q", tt, tt.configRoot, configRoot)
}

3
config/cloudinit/datasource/datasource.go Normal file → Executable file
View File

@@ -25,6 +25,9 @@ type Datasource interface {
FetchMetadata() (Metadata, error)
FetchUserdata() ([]byte, error)
Type() string
String() string
// Finish gives the datasource the oportunity to clean up, unmount or release any open / cache resources
Finish() error
}
type Metadata struct {

16
config/cloudinit/datasource/file/file.go Normal file → Executable file
View File

@@ -15,6 +15,7 @@
package file
import (
"fmt"
"io/ioutil"
"os"
@@ -23,15 +24,24 @@ import (
type LocalFile struct {
path string
lastError error
}
func NewDatasource(path string) *LocalFile {
return &LocalFile{path}
return &LocalFile{path, nil}
}
func (f *LocalFile) IsAvailable() bool {
_, err := os.Stat(f.path)
return !os.IsNotExist(err)
_, f.lastError = os.Stat(f.path)
return !os.IsNotExist(f.lastError)
}
func (f *LocalFile) Finish() error {
return nil
}
func (f *LocalFile) String() string {
return fmt.Sprintf("%s: %s (lastError: %s)", f.Type(), f.path, f.lastError)
}
func (f *LocalFile) AvailabilityChanges() bool {

16
config/cloudinit/datasource/metadata/metadata.go Normal file → Executable file
View File

@@ -15,6 +15,7 @@
package metadata
import (
"fmt"
"net/http"
"strings"
@@ -27,18 +28,27 @@ type Service struct {
APIVersion string
UserdataPath string
MetadataPath string
lastError error
}
func NewDatasource(root, apiVersion, userdataPath, metadataPath string, header http.Header) Service {
if !strings.HasSuffix(root, "/") {
root += "/"
}
return Service{root, pkg.NewHTTPClientHeader(header), apiVersion, userdataPath, metadataPath}
return Service{root, pkg.NewHTTPClientHeader(header), apiVersion, userdataPath, metadataPath, nil}
}
func (ms Service) IsAvailable() bool {
_, err := ms.Client.Get(ms.Root + ms.APIVersion)
return (err == nil)
_, ms.lastError = ms.Client.Get(ms.Root + ms.APIVersion)
return (ms.lastError == nil)
}
func (ms *Service) Finish() error {
return nil
}
func (ms *Service) String() string {
return fmt.Sprintf("%s: %s (lastError: %s)", "metadata", ms.Root+":"+ms.UserdataPath, ms.lastError)
}
func (ms Service) AvailabilityChanges() bool {

22
config/cloudinit/datasource/proccmdline/proc_cmdline.go Normal file → Executable file
View File

@@ -16,10 +16,12 @@ package proccmdline
import (
"errors"
"fmt"
"io/ioutil"
"log"
"strings"
"github.com/rancher/os/log"
"github.com/rancher/os/config/cloudinit/datasource"
"github.com/rancher/os/config/cloudinit/pkg"
)
@@ -31,6 +33,7 @@ const (
type ProcCmdline struct {
Location string
lastError error
}
func NewDatasource() *ProcCmdline {
@@ -38,14 +41,23 @@ func NewDatasource() *ProcCmdline {
}
func (c *ProcCmdline) IsAvailable() bool {
contents, err := ioutil.ReadFile(c.Location)
if err != nil {
var contents []byte
contents, c.lastError = ioutil.ReadFile(c.Location)
if c.lastError != nil {
return false
}
cmdline := strings.TrimSpace(string(contents))
_, err = findCloudConfigURL(cmdline)
return (err == nil)
_, c.lastError = findCloudConfigURL(cmdline)
return (c.lastError == nil)
}
func (c *ProcCmdline) Finish() error {
return nil
}
func (c *ProcCmdline) String() string {
return fmt.Sprintf("%s: %s (lastError: %s)", c.Type(), c.Location, c.lastError)
}
func (c *ProcCmdline) AvailabilityChanges() bool {

0
config/cloudinit/datasource/test/filesystem.go Normal file → Executable file
View File

17
config/cloudinit/datasource/url/url.go Normal file → Executable file
View File

@@ -15,22 +15,33 @@
package url
import (
"fmt"
"github.com/rancher/os/config/cloudinit/datasource"
"github.com/rancher/os/config/cloudinit/pkg"
)
type RemoteFile struct {
url string
lastError error
}
func NewDatasource(url string) *RemoteFile {
return &RemoteFile{url}
return &RemoteFile{url, nil}
}
func (f *RemoteFile) IsAvailable() bool {
client := pkg.NewHTTPClient()
_, err := client.Get(f.url)
return (err == nil)
_, f.lastError = client.Get(f.url)
return (f.lastError == nil)
}
func (f *RemoteFile) Finish() error {
return nil
}
func (f *RemoteFile) String() string {
return fmt.Sprintf("%s: %s (lastError: %s)", f.Type(), f.url, f.lastError)
}
func (f *RemoteFile) AvailabilityChanges() bool {

9
config/cloudinit/datasource/vmware/vmware.go Normal file → Executable file
View File

@@ -29,6 +29,15 @@ type VMWare struct {
ovfFileName string
readConfig readConfigFunction
urlDownload urlDownloadFunction
lastError error
}
func (v VMWare) Finish() error {
return nil
}
func (v VMWare) String() string {
return fmt.Sprintf("%s: %s (lastError: %s)", v.Type(), v.ovfFileName, v.lastError)
}
func (v VMWare) AvailabilityChanges() bool {

9
config/cloudinit/datasource/vmware/vmware_amd64.go Normal file → Executable file
View File

@@ -16,14 +16,15 @@ package vmware
import (
"io/ioutil"
"log"
"os"
"github.com/rancher/os/log"
"github.com/rancher/os/config/cloudinit/pkg"
"github.com/sigma/vmw-guestinfo/rpcvmx"
"github.com/sigma/vmw-guestinfo/vmcheck"
"github.com/sigma/vmw-ovflib"
ovf "github.com/sigma/vmw-ovflib"
)
type ovfWrapper struct {
@@ -69,8 +70,8 @@ func NewDatasource(fileName string) *VMWare {
func (v VMWare) IsAvailable() bool {
if v.ovfFileName != "" {
_, err := os.Stat(v.ovfFileName)
return !os.IsNotExist(err)
_, v.lastError = os.Stat(v.ovfFileName)
return !os.IsNotExist(v.lastError)
}
return vmcheck.IsVirtualWorld()
}

19
config/cloudinit/datasource/waagent/waagent.go Normal file → Executable file
View File

@@ -16,27 +16,38 @@ package waagent
import (
"encoding/xml"
"fmt"
"io/ioutil"
"log"
"net"
"os"
"path"
"github.com/rancher/os/log"
"github.com/rancher/os/config/cloudinit/datasource"
)
type Waagent struct {
root string
readFile func(filename string) ([]byte, error)
lastError error
}
func NewDatasource(root string) *Waagent {
return &Waagent{root, ioutil.ReadFile}
return &Waagent{root, ioutil.ReadFile, nil}
}
func (a *Waagent) IsAvailable() bool {
_, err := os.Stat(path.Join(a.root, "provisioned"))
return !os.IsNotExist(err)
_, a.lastError = os.Stat(path.Join(a.root, "provisioned"))
return !os.IsNotExist(a.lastError)
}
func (a *Waagent) Finish() error {
return nil
}
func (a *Waagent) String() string {
return fmt.Sprintf("%s: %s (lastError: %s)", a.Type(), a.root, a.lastError)
}
func (a *Waagent) AvailabilityChanges() bool {

View File

@@ -86,7 +86,7 @@ func TestFetchMetadata(t *testing.T) {
},
},
} {
a := Waagent{tt.root, tt.files.ReadFile}
a := Waagent{tt.root, tt.files.ReadFile, nil}
metadata, err := a.FetchMetadata()
if err != nil {
t.Fatalf("bad error for %+v: want %v, got %q", tt, nil, err)
@@ -115,7 +115,7 @@ func TestFetchUserdata(t *testing.T) {
test.NewMockFilesystem(test.File{Path: "/var/lib/Waagent/CustomData", Contents: ""}),
},
} {
a := Waagent{tt.root, tt.files.ReadFile}
a := Waagent{tt.root, tt.files.ReadFile, nil}
_, err := a.FetchUserdata()
if err != nil {
t.Fatalf("bad error for %+v: want %v, got %q", tt, nil, err)
@@ -137,7 +137,7 @@ func TestConfigRoot(t *testing.T) {
"/var/lib/Waagent",
},
} {
a := Waagent{tt.root, nil}
a := Waagent{tt.root, nil, nil}
if configRoot := a.ConfigRoot(); configRoot != tt.configRoot {
t.Fatalf("bad config root for %q: want %q, got %q", tt, tt.configRoot, configRoot)
}

22
init/init.go Normal file → Executable file
View File

@@ -12,7 +12,6 @@ import (
"syscall"
"github.com/docker/docker/pkg/mount"
"github.com/rancher/os/cmd/cloudinitsave"
"github.com/rancher/os/config"
"github.com/rancher/os/dfs"
"github.com/rancher/os/log"
@@ -294,29 +293,10 @@ func RunInit() error {
log.Error(err)
}
network := false
for _, datasource := range cfg.Rancher.CloudInit.Datasources {
if cloudinitsave.RequiresNetwork(datasource) {
network = true
break
}
}
if network {
if err := runCloudInitServices(cfg); err != nil {
log.Error(err)
}
} else {
if err := cloudinitsave.MountConfigDrive(); err != nil {
log.Error(err)
}
if err := cloudinitsave.SaveCloudConfig(false); err != nil {
log.Error(err)
}
if err := cloudinitsave.UnmountConfigDrive(); err != nil {
log.Error(err)
}
}
return cfg, nil
},
func(cfg *config.CloudConfig) (*config.CloudConfig, error) {

View File

@@ -1,4 +1,5 @@
rancher:
debug: true
environment:
VERSION: {{.VERSION}}
SUFFIX: {{.SUFFIX}}
@@ -66,6 +67,7 @@ rancher:
cloud_init:
datasources:
- configdrive:/media/config-2
- url:http://example.com/404-error
repositories:
core:
url: {{.OS_SERVICES_REPO}}/{{.REPO_VERSION}}

View File

@@ -48,4 +48,4 @@ REBUILD=1
QEMUARCH=${qemuarch["${ARCH}"]}
TTYCONS=${ttycons["${ARCH}"]}
DEFAULT_KERNEL_ARGS="rancher.debug=false rancher.password=rancher console=${TTYCONS} rancher.autologin=${TTYCONS}"
DEFAULT_KERNEL_ARGS="printk.devkmsg=on rancher.debug=true rancher.password=rancher console=${TTYCONS} rancher.autologin=${TTYCONS}"