diff --git a/cmd/cloudinitsave/cloudinitsave.go b/cmd/cloudinitsave/cloudinitsave.go index bc57a30b..3125e7cb 100755 --- a/cmd/cloudinitsave/cloudinitsave.go +++ b/cmd/cloudinitsave/cloudinitsave.go @@ -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 { diff --git a/config/cloudinit/datasource/configdrive/configdrive.go b/config/cloudinit/datasource/configdrive/configdrive.go old mode 100644 new mode 100755 index 14e8d249..880aeb7c --- a/config/cloudinit/datasource/configdrive/configdrive.go +++ b/config/cloudinit/datasource/configdrive/configdrive.go @@ -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) + 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) +} diff --git a/config/cloudinit/datasource/configdrive/configdrive_test.go b/config/cloudinit/datasource/configdrive/configdrive_test.go index b3c976a7..6812a3da 100644 --- a/config/cloudinit/datasource/configdrive/configdrive_test.go +++ b/config/cloudinit/datasource/configdrive/configdrive_test.go @@ -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) } diff --git a/config/cloudinit/datasource/datasource.go b/config/cloudinit/datasource/datasource.go old mode 100644 new mode 100755 index e459303c..363ee4a8 --- a/config/cloudinit/datasource/datasource.go +++ b/config/cloudinit/datasource/datasource.go @@ -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 { diff --git a/config/cloudinit/datasource/file/file.go b/config/cloudinit/datasource/file/file.go old mode 100644 new mode 100755 index 5924d703..9478c7f7 --- a/config/cloudinit/datasource/file/file.go +++ b/config/cloudinit/datasource/file/file.go @@ -15,6 +15,7 @@ package file import ( + "fmt" "io/ioutil" "os" @@ -22,16 +23,25 @@ import ( ) type LocalFile struct { - path string + 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 { diff --git a/config/cloudinit/datasource/metadata/metadata.go b/config/cloudinit/datasource/metadata/metadata.go old mode 100644 new mode 100755 index 00e5464b..6d513309 --- a/config/cloudinit/datasource/metadata/metadata.go +++ b/config/cloudinit/datasource/metadata/metadata.go @@ -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 { diff --git a/config/cloudinit/datasource/proccmdline/proc_cmdline.go b/config/cloudinit/datasource/proccmdline/proc_cmdline.go old mode 100644 new mode 100755 index bad49d18..805b2a94 --- a/config/cloudinit/datasource/proccmdline/proc_cmdline.go +++ b/config/cloudinit/datasource/proccmdline/proc_cmdline.go @@ -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" ) @@ -30,7 +32,8 @@ const ( ) type ProcCmdline struct { - Location string + 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 { diff --git a/config/cloudinit/datasource/test/filesystem.go b/config/cloudinit/datasource/test/filesystem.go old mode 100644 new mode 100755 diff --git a/config/cloudinit/datasource/url/url.go b/config/cloudinit/datasource/url/url.go old mode 100644 new mode 100755 index 6d011dae..7973ebb4 --- a/config/cloudinit/datasource/url/url.go +++ b/config/cloudinit/datasource/url/url.go @@ -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 + 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 { diff --git a/config/cloudinit/datasource/vmware/vmware.go b/config/cloudinit/datasource/vmware/vmware.go old mode 100644 new mode 100755 index 2c5ba187..f1593aab --- a/config/cloudinit/datasource/vmware/vmware.go +++ b/config/cloudinit/datasource/vmware/vmware.go @@ -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 { diff --git a/config/cloudinit/datasource/vmware/vmware_amd64.go b/config/cloudinit/datasource/vmware/vmware_amd64.go old mode 100644 new mode 100755 index c87e0899..f805f34b --- a/config/cloudinit/datasource/vmware/vmware_amd64.go +++ b/config/cloudinit/datasource/vmware/vmware_amd64.go @@ -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() } diff --git a/config/cloudinit/datasource/waagent/waagent.go b/config/cloudinit/datasource/waagent/waagent.go old mode 100644 new mode 100755 index 96e35185..da481327 --- a/config/cloudinit/datasource/waagent/waagent.go +++ b/config/cloudinit/datasource/waagent/waagent.go @@ -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) + 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 { diff --git a/config/cloudinit/datasource/waagent/waagent_test.go b/config/cloudinit/datasource/waagent/waagent_test.go index 01e6af56..b455f6bd 100644 --- a/config/cloudinit/datasource/waagent/waagent_test.go +++ b/config/cloudinit/datasource/waagent/waagent_test.go @@ -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) } diff --git a/init/init.go b/init/init.go old mode 100644 new mode 100755 index 23bd27b4..4e86ec11 --- a/init/init.go +++ b/init/init.go @@ -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 err := runCloudInitServices(cfg); err != nil { + log.Error(err) } - 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) { diff --git a/os-config.tpl.yml b/os-config.tpl.yml index dcf3a9cb..6b696581 100644 --- a/os-config.tpl.yml +++ b/os-config.tpl.yml @@ -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}} diff --git a/scripts/run-common b/scripts/run-common index 79fb0af0..62b7475e 100755 --- a/scripts/run-common +++ b/scripts/run-common @@ -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}"