1
0
mirror of https://github.com/rancher/os.git synced 2025-07-12 22:27:59 +00:00

Merge pull request #1655 from SvenDowideit/fail-cloud-init-datasources-based-on-error-types

Fail cloud init datasources based on error types
This commit is contained in:
Sven Dowideit 2017-03-06 20:37:44 +10:00 committed by GitHub
commit d26d20d730
20 changed files with 282 additions and 185 deletions

View File

@ -20,12 +20,10 @@ import (
"os" "os"
"strings" "strings"
"sync" "sync"
"syscall"
"time" "time"
yaml "github.com/cloudfoundry-incubator/candiedyaml" yaml "github.com/cloudfoundry-incubator/candiedyaml"
"github.com/docker/docker/pkg/mount"
"github.com/rancher/os/cmd/control" "github.com/rancher/os/cmd/control"
"github.com/rancher/os/cmd/network" "github.com/rancher/os/cmd/network"
rancherConfig "github.com/rancher/os/config" rancherConfig "github.com/rancher/os/config"
@ -49,9 +47,6 @@ const (
datasourceInterval = 100 * time.Millisecond datasourceInterval = 100 * time.Millisecond
datasourceMaxInterval = 30 * time.Second datasourceMaxInterval = 30 * time.Second
datasourceTimeout = 5 * time.Minute datasourceTimeout = 5 * time.Minute
configDevName = "config-2"
configDev = "LABEL=" + configDevName
configDevMountPoint = "/media/config-2"
) )
func Main() { func Main() {
@ -70,34 +65,85 @@ 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 { func SaveCloudConfig(network bool) error {
userDataBytes, metadata, err := fetchUserData(network) log.Debugf("SaveCloudConfig")
cfg := rancherConfig.LoadConfig()
dss := getDatasources(cfg, network)
if len(dss) == 0 {
log.Errorf("currentDatasource - none found")
return nil
}
selectDatasource(dss)
return nil
}
func RequiresNetwork(datasource string) bool {
// TODO: move into the datasources (and metadatasources)
parts := strings.SplitN(datasource, ":", 2)
requiresNetwork, ok := map[string]bool{
"ec2": true,
"file": false,
"url": true,
"cmdline": true,
"configdrive": false,
"digitalocean": true,
"gce": true,
"packet": true,
}[parts[0]]
return ok && requiresNetwork
}
func saveFiles(cloudConfigBytes, scriptBytes []byte, metadata datasource.Metadata) error {
os.MkdirAll(rancherConfig.CloudConfigDir, os.ModeDir|0600)
if len(scriptBytes) > 0 {
log.Infof("Writing to %s", rancherConfig.CloudConfigScriptFile)
if err := util.WriteFileAtomic(rancherConfig.CloudConfigScriptFile, scriptBytes, 500); err != nil {
log.Errorf("Error while writing file %s: %v", rancherConfig.CloudConfigScriptFile, err)
return err
}
}
if len(cloudConfigBytes) > 0 {
if err := util.WriteFileAtomic(rancherConfig.CloudConfigBootFile, cloudConfigBytes, 400); err != nil {
return err
}
// Don't put secrets into the log
//log.Infof("Written to %s:\n%s", rancherConfig.CloudConfigBootFile, string(cloudConfigBytes))
}
metaDataBytes, err := yaml.Marshal(metadata)
if err != nil { if err != nil {
return err return err
} }
if err = util.WriteFileAtomic(rancherConfig.MetaDataFile, metaDataBytes, 400); err != nil {
return err
}
// Don't put secrets into the log
//log.Infof("Written to %s:\n%s", rancherConfig.MetaDataFile, string(metaDataBytes))
return nil
}
func fetchAndSave(ds datasource.Datasource) error {
var metadata datasource.Metadata
log.Infof("Fetching user-data from datasource %s", ds)
userDataBytes, err := ds.FetchUserdata()
if err != nil {
log.Errorf("Failed fetching user-data from datasource: %v", err)
return err
}
log.Infof("Fetching meta-data from datasource of type %v", ds.Type())
metadata, err = ds.FetchMetadata()
if err != nil {
log.Errorf("Failed fetching meta-data from datasource: %v", err)
return err
}
userData := string(userDataBytes) userData := string(userDataBytes)
scriptBytes := []byte{} scriptBytes := []byte{}
@ -127,86 +173,6 @@ func SaveCloudConfig(network bool) error {
return saveFiles(userDataBytes, scriptBytes, metadata) return saveFiles(userDataBytes, scriptBytes, metadata)
} }
func RequiresNetwork(datasource string) bool {
parts := strings.SplitN(datasource, ":", 2)
requiresNetwork, ok := map[string]bool{
"ec2": true,
"file": false,
"url": true,
"cmdline": true,
"configdrive": false,
"digitalocean": true,
"gce": true,
"packet": true,
}[parts[0]]
return ok && requiresNetwork
}
func saveFiles(cloudConfigBytes, scriptBytes []byte, metadata datasource.Metadata) error {
os.MkdirAll(rancherConfig.CloudConfigDir, os.ModeDir|0600)
if len(scriptBytes) > 0 {
log.Infof("Writing to %s", rancherConfig.CloudConfigScriptFile)
if err := util.WriteFileAtomic(rancherConfig.CloudConfigScriptFile, scriptBytes, 500); err != nil {
log.Errorf("Error while writing file %s: %v", rancherConfig.CloudConfigScriptFile, err)
return err
}
}
if len(cloudConfigBytes) > 0 {
if err := util.WriteFileAtomic(rancherConfig.CloudConfigBootFile, cloudConfigBytes, 400); err != nil {
return err
}
log.Infof("Written to %s:\n%s", rancherConfig.CloudConfigBootFile, string(cloudConfigBytes))
}
metaDataBytes, err := yaml.Marshal(metadata)
if err != nil {
return err
}
if err = util.WriteFileAtomic(rancherConfig.MetaDataFile, metaDataBytes, 400); err != nil {
return err
}
log.Infof("Written to %s:\n%s", rancherConfig.MetaDataFile, string(metaDataBytes))
return nil
}
func currentDatasource(network bool) (datasource.Datasource, error) {
cfg := rancherConfig.LoadConfig()
dss := getDatasources(cfg, network)
if len(dss) == 0 {
return nil, nil
}
ds := selectDatasource(dss)
return ds, nil
}
func fetchUserData(network bool) ([]byte, datasource.Metadata, error) {
var metadata datasource.Metadata
ds, err := currentDatasource(network)
if err != nil || ds == nil {
log.Errorf("Failed to select datasource: %v", err)
return nil, metadata, err
}
log.Infof("Fetching user-data from datasource %v", ds.Type())
userDataBytes, err := ds.FetchUserdata()
if err != nil {
log.Errorf("Failed fetching user-data from datasource: %v", err)
return nil, metadata, err
}
log.Infof("Fetching meta-data from datasource of type %v", ds.Type())
metadata, err = ds.FetchMetadata()
if err != nil {
log.Errorf("Failed fetching meta-data from datasource: %v", err)
return nil, metadata, err
}
return userDataBytes, metadata, nil
}
// getDatasources creates a slice of possible Datasources for cloudinit based // getDatasources creates a slice of possible Datasources for cloudinit based
// on the different source command-line flags. // on the different source command-line flags.
func getDatasources(cfg *rancherConfig.CloudConfig, network bool) []datasource.Datasource { func getDatasources(cfg *rancherConfig.CloudConfig, network bool) []datasource.Datasource {
@ -299,13 +265,17 @@ func selectDatasource(sources []datasource.Datasource) datasource.Datasource {
duration := datasourceInterval duration := datasourceInterval
for { for {
log.Infof("Checking availability of %q\n", s.Type()) log.Infof("cloud-init: Checking availability of %q\n", s.Type())
if s.IsAvailable() { if s.IsAvailable() {
log.Infof("cloud-init: Datasource available: %s", s)
ds <- s ds <- s
return return
} else if !s.AvailabilityChanges() { }
if !s.AvailabilityChanges() {
log.Infof("cloud-init: Datasource unavailable, skipping: %s", s)
return return
} }
log.Errorf("cloud-init: Datasource not ready, will retry: %s", s)
select { select {
case <-stop: case <-stop:
return return
@ -325,6 +295,10 @@ func selectDatasource(sources []datasource.Datasource) datasource.Datasource {
var s datasource.Datasource var s datasource.Datasource
select { select {
case s = <-ds: case s = <-ds:
err := fetchAndSave(s)
if err != nil {
log.Errorf("Error fetching cloud-init datasource(%s): %s", s, err)
}
case <-done: case <-done:
case <-time.After(datasourceTimeout): case <-time.After(datasourceTimeout):
} }

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

@ -16,34 +16,67 @@ package configdrive
import ( import (
"encoding/json" "encoding/json"
"fmt"
"io/ioutil" "io/ioutil"
"log"
"os" "os"
"path" "path"
"syscall"
"github.com/rancher/os/log"
"github.com/docker/docker/pkg/mount"
"github.com/rancher/os/config/cloudinit/datasource" "github.com/rancher/os/config/cloudinit/datasource"
"github.com/rancher/os/util"
) )
const ( const (
configDevName = "config-2"
configDev = "LABEL=" + configDevName
configDevMountPoint = "/media/config-2"
openstackAPIVersion = "latest" openstackAPIVersion = "latest"
) )
type ConfigDrive struct { type ConfigDrive struct {
root string root string
readFile func(filename string) ([]byte, error) readFile func(filename string) ([]byte, error)
lastError error
availabilityChanges bool
} }
func NewDatasource(root string) *ConfigDrive { func NewDatasource(root string) *ConfigDrive {
return &ConfigDrive{root, ioutil.ReadFile} return &ConfigDrive{root, ioutil.ReadFile, nil, true}
} }
func (cd *ConfigDrive) IsAvailable() bool { func (cd *ConfigDrive) IsAvailable() bool {
_, err := os.Stat(cd.root) if cd.root == configDevMountPoint {
return !os.IsNotExist(err) cd.lastError = MountConfigDrive()
if cd.lastError != nil {
log.Error(cd.lastError)
// Don't keep retrying if we can't mount
cd.availabilityChanges = false
return false
}
defer cd.Finish()
}
_, cd.lastError = os.Stat(cd.root)
return !os.IsNotExist(cd.lastError)
// TODO: consider changing IsNotExists to not-available _and_ does not change
}
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 { func (cd *ConfigDrive) AvailabilityChanges() bool {
return true return cd.availabilityChanges
} }
func (cd *ConfigDrive) ConfigRoot() string { func (cd *ConfigDrive) ConfigRoot() string {
@ -93,10 +126,43 @@ func (cd *ConfigDrive) openstackVersionRoot() string {
} }
func (cd *ConfigDrive) tryReadFile(filename string) ([]byte, error) { func (cd *ConfigDrive) tryReadFile(filename string) ([]byte, error) {
log.Printf("Attempting to read from %q\n", filename) if cd.root == configDevMountPoint {
cd.lastError = MountConfigDrive()
if cd.lastError != nil {
log.Error(cd.lastError)
return nil, cd.lastError
}
defer cd.Finish()
}
log.Debugf("Attempting to read from %q\n", filename)
data, err := cd.readFile(filename) data, err := cd.readFile(filename)
if os.IsNotExist(err) { if os.IsNotExist(err) {
err = nil err = nil
} }
if err != nil {
log.Errorf("ERROR read cloud-config file(%s) - err: %q", filename, err)
}
return data, err 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, true}
metadata, err := cd.FetchMetadata() metadata, err := cd.FetchMetadata()
if err != nil { if err != nil {
t.Fatalf("bad error for %+v: want %v, got %q", tt, nil, err) t.Fatalf("bad error for %+v: want %v, got %q", tt, nil, err)
@ -91,7 +91,7 @@ func TestFetchUserdata(t *testing.T) {
"userdata", "userdata",
}, },
} { } {
cd := ConfigDrive{tt.root, tt.files.ReadFile} cd := ConfigDrive{tt.root, tt.files.ReadFile, nil, true}
userdata, err := cd.FetchUserdata() userdata, err := cd.FetchUserdata()
if err != nil { if err != nil {
t.Fatalf("bad error for %+v: want %v, got %q", tt, nil, err) 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", "/media/configdrive/openstack",
}, },
} { } {
cd := ConfigDrive{tt.root, nil} cd := ConfigDrive{tt.root, nil, nil, true}
if configRoot := cd.ConfigRoot(); configRoot != tt.configRoot { if configRoot := cd.ConfigRoot(); configRoot != tt.configRoot {
t.Fatalf("bad config root for %q: want %q, got %q", tt, tt.configRoot, 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) FetchMetadata() (Metadata, error)
FetchUserdata() ([]byte, error) FetchUserdata() ([]byte, error)
Type() string 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 { type Metadata struct {

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

@ -15,6 +15,7 @@
package file package file
import ( import (
"fmt"
"io/ioutil" "io/ioutil"
"os" "os"
@ -23,15 +24,24 @@ import (
type LocalFile struct { type LocalFile struct {
path string path string
lastError error
} }
func NewDatasource(path string) *LocalFile { func NewDatasource(path string) *LocalFile {
return &LocalFile{path} return &LocalFile{path, nil}
} }
func (f *LocalFile) IsAvailable() bool { func (f *LocalFile) IsAvailable() bool {
_, err := os.Stat(f.path) _, f.lastError = os.Stat(f.path)
return !os.IsNotExist(err) 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 { func (f *LocalFile) AvailabilityChanges() bool {

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

@ -15,6 +15,7 @@
package metadata package metadata
import ( import (
"fmt"
"net/http" "net/http"
"strings" "strings"
@ -27,18 +28,27 @@ type Service struct {
APIVersion string APIVersion string
UserdataPath string UserdataPath string
MetadataPath string MetadataPath string
lastError error
} }
func NewDatasource(root, apiVersion, userdataPath, metadataPath string, header http.Header) Service { func NewDatasource(root, apiVersion, userdataPath, metadataPath string, header http.Header) Service {
if !strings.HasSuffix(root, "/") { if !strings.HasSuffix(root, "/") {
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 { func (ms Service) IsAvailable() bool {
_, err := ms.Client.Get(ms.Root + ms.APIVersion) _, ms.lastError = ms.Client.Get(ms.Root + ms.APIVersion)
return (err == nil) 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 { 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 ( import (
"errors" "errors"
"fmt"
"io/ioutil" "io/ioutil"
"log"
"strings" "strings"
"github.com/rancher/os/log"
"github.com/rancher/os/config/cloudinit/datasource" "github.com/rancher/os/config/cloudinit/datasource"
"github.com/rancher/os/config/cloudinit/pkg" "github.com/rancher/os/config/cloudinit/pkg"
) )
@ -31,6 +33,7 @@ const (
type ProcCmdline struct { type ProcCmdline struct {
Location string Location string
lastError error
} }
func NewDatasource() *ProcCmdline { func NewDatasource() *ProcCmdline {
@ -38,14 +41,23 @@ func NewDatasource() *ProcCmdline {
} }
func (c *ProcCmdline) IsAvailable() bool { func (c *ProcCmdline) IsAvailable() bool {
contents, err := ioutil.ReadFile(c.Location) var contents []byte
if err != nil { contents, c.lastError = ioutil.ReadFile(c.Location)
if c.lastError != nil {
return false return false
} }
cmdline := strings.TrimSpace(string(contents)) cmdline := strings.TrimSpace(string(contents))
_, err = findCloudConfigURL(cmdline) _, c.lastError = findCloudConfigURL(cmdline)
return (err == nil) 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 { func (c *ProcCmdline) AvailabilityChanges() bool {

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

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

@ -15,25 +15,43 @@
package url package url
import ( import (
"fmt"
"github.com/rancher/os/config/cloudinit/datasource" "github.com/rancher/os/config/cloudinit/datasource"
"github.com/rancher/os/config/cloudinit/pkg" "github.com/rancher/os/config/cloudinit/pkg"
) )
type RemoteFile struct { type RemoteFile struct {
url string url string
lastError error
} }
func NewDatasource(url string) *RemoteFile { func NewDatasource(url string) *RemoteFile {
return &RemoteFile{url} return &RemoteFile{url, nil}
} }
func (f *RemoteFile) IsAvailable() bool { func (f *RemoteFile) IsAvailable() bool {
client := pkg.NewHTTPClient() client := pkg.NewHTTPClient()
_, err := client.Get(f.url) _, f.lastError = client.Get(f.url)
return (err == nil) 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 { func (f *RemoteFile) AvailabilityChanges() bool {
if f.lastError != nil {
// if we have a Network error, then we should retry.
// otherwise, we've made a request to the server, and its said nope.
if _, ok := f.lastError.(pkg.ErrNetwork); !ok {
return false
}
}
return true return true
} }

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

@ -29,6 +29,15 @@ type VMWare struct {
ovfFileName string ovfFileName string
readConfig readConfigFunction readConfig readConfigFunction
urlDownload urlDownloadFunction 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 { 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 ( import (
"io/ioutil" "io/ioutil"
"log"
"os" "os"
"github.com/rancher/os/log"
"github.com/rancher/os/config/cloudinit/pkg" "github.com/rancher/os/config/cloudinit/pkg"
"github.com/sigma/vmw-guestinfo/rpcvmx" "github.com/sigma/vmw-guestinfo/rpcvmx"
"github.com/sigma/vmw-guestinfo/vmcheck" "github.com/sigma/vmw-guestinfo/vmcheck"
"github.com/sigma/vmw-ovflib" ovf "github.com/sigma/vmw-ovflib"
) )
type ovfWrapper struct { type ovfWrapper struct {
@ -69,8 +70,8 @@ func NewDatasource(fileName string) *VMWare {
func (v VMWare) IsAvailable() bool { func (v VMWare) IsAvailable() bool {
if v.ovfFileName != "" { if v.ovfFileName != "" {
_, err := os.Stat(v.ovfFileName) _, v.lastError = os.Stat(v.ovfFileName)
return !os.IsNotExist(err) return !os.IsNotExist(v.lastError)
} }
return vmcheck.IsVirtualWorld() return vmcheck.IsVirtualWorld()
} }

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

@ -16,27 +16,38 @@ package waagent
import ( import (
"encoding/xml" "encoding/xml"
"fmt"
"io/ioutil" "io/ioutil"
"log"
"net" "net"
"os" "os"
"path" "path"
"github.com/rancher/os/log"
"github.com/rancher/os/config/cloudinit/datasource" "github.com/rancher/os/config/cloudinit/datasource"
) )
type Waagent struct { type Waagent struct {
root string root string
readFile func(filename string) ([]byte, error) readFile func(filename string) ([]byte, error)
lastError error
} }
func NewDatasource(root string) *Waagent { func NewDatasource(root string) *Waagent {
return &Waagent{root, ioutil.ReadFile} return &Waagent{root, ioutil.ReadFile, nil}
} }
func (a *Waagent) IsAvailable() bool { func (a *Waagent) IsAvailable() bool {
_, err := os.Stat(path.Join(a.root, "provisioned")) _, a.lastError = os.Stat(path.Join(a.root, "provisioned"))
return !os.IsNotExist(err) 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 { 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() metadata, err := a.FetchMetadata()
if err != nil { if err != nil {
t.Fatalf("bad error for %+v: want %v, got %q", tt, nil, err) 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: ""}), 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() _, err := a.FetchUserdata()
if err != nil { if err != nil {
t.Fatalf("bad error for %+v: want %v, got %q", tt, nil, err) 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", "/var/lib/Waagent",
}, },
} { } {
a := Waagent{tt.root, nil} a := Waagent{tt.root, nil, nil}
if configRoot := a.ConfigRoot(); configRoot != tt.configRoot { if configRoot := a.ConfigRoot(); configRoot != tt.configRoot {
t.Fatalf("bad config root for %q: want %q, got %q", tt, tt.configRoot, 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" "syscall"
"github.com/docker/docker/pkg/mount" "github.com/docker/docker/pkg/mount"
"github.com/rancher/os/cmd/cloudinitsave"
"github.com/rancher/os/config" "github.com/rancher/os/config"
"github.com/rancher/os/dfs" "github.com/rancher/os/dfs"
"github.com/rancher/os/log" "github.com/rancher/os/log"
@ -294,29 +293,10 @@ func RunInit() error {
log.Error(err) 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 { if err := runCloudInitServices(cfg); err != nil {
log.Error(err) 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 return cfg, nil
}, },
func(cfg *config.CloudConfig) (*config.CloudConfig, error) { func(cfg *config.CloudConfig) (*config.CloudConfig, error) {

View File

@ -1,4 +1,5 @@
rancher: rancher:
debug: true
environment: environment:
VERSION: {{.VERSION}} VERSION: {{.VERSION}}
SUFFIX: {{.SUFFIX}} SUFFIX: {{.SUFFIX}}

View File

@ -48,4 +48,4 @@ REBUILD=1
QEMUARCH=${qemuarch["${ARCH}"]} QEMUARCH=${qemuarch["${ARCH}"]}
TTYCONS=${ttycons["${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}"

View File

@ -1,6 +1,6 @@
#cloud-config #cloud-config
rancher: rancher:
console: debian console: alpine
services: services:
missing_image: missing_image:
image: tianon/true image: tianon/true

View File

@ -106,7 +106,8 @@ func (s *QemuSuite) WaitForSSH() error {
if err = cmd.Run(); err == nil { if err = cmd.Run(); err == nil {
break break
} }
time.Sleep(500 * time.Millisecond) fmt.Printf("s%d", i)
time.Sleep(time.Second)
} }
if err != nil { if err != nil {
@ -126,6 +127,7 @@ func (s *QemuSuite) WaitForSSH() error {
if err = cmd.Run(); err == nil { if err = cmd.Run(); err == nil {
return nil return nil
} }
fmt.Printf("d%d", i)
time.Sleep(500 * time.Millisecond) time.Sleep(500 * time.Millisecond)
} }
@ -185,7 +187,7 @@ func (s *QemuSuite) LoadInstallerImage(c *C) {
c.Assert(cmd.Run(), IsNil) c.Assert(cmd.Run(), IsNil)
} }
func (s *QemuSuite) PullAndLoadInstallerImage(c *C, image string) { func (s *QemuSuite) PullAndLoadImage(c *C, image string) {
cmd := exec.Command("sh", "-c", fmt.Sprintf("docker pull %s", image)) cmd := exec.Command("sh", "-c", fmt.Sprintf("docker pull %s", image))
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr

2
tests/network_on_boot_test.go Normal file → Executable file
View File

@ -5,6 +5,6 @@ import . "gopkg.in/check.v1"
func (s *QemuSuite) TestNetworkOnBoot(c *C) { func (s *QemuSuite) TestNetworkOnBoot(c *C) {
s.RunQemu(c, "--cloud-config", "./tests/assets/test_18/cloud-config.yml", "-net", "nic,vlan=1,model=virtio") s.RunQemu(c, "--cloud-config", "./tests/assets/test_18/cloud-config.yml", "-net", "nic,vlan=1,model=virtio")
s.CheckCall(c, "apt-get --version") s.CheckCall(c, "apk --version")
s.CheckCall(c, "sudo system-docker images | grep tianon/true") s.CheckCall(c, "sudo system-docker images | grep tianon/true")
} }

View File

@ -51,7 +51,7 @@ func (s *QemuSuite) DisableTestUpgradeInner(c *C) {
c.Assert(Version, Equals, version) c.Assert(Version, Equals, version)
fmt.Printf("installing %s", startWithVersion) fmt.Printf("installing %s", startWithVersion)
s.PullAndLoadInstallerImage(c, fmt.Sprintf("rancher/os:%s", startWithVersion)) s.PullAndLoadImage(c, fmt.Sprintf("rancher/os:%s", startWithVersion))
//ADD a custom append line and make sure its kept in the upgraded version too //ADD a custom append line and make sure its kept in the upgraded version too
@ -77,10 +77,10 @@ sync
if console != "default" { if console != "default" {
// Can't preload the startWithVersion console image, as some don't exist by that name - not sure how to approach that // Can't preload the startWithVersion console image, as some don't exist by that name - not sure how to approach that
//s.PullAndLoadInstallerImage(c, fmt.Sprintf("rancher/os-%sconsole:%s", console, startWithVersion)) //s.PullAndLoadImage(c, fmt.Sprintf("rancher/os-%sconsole:%s", console, startWithVersion))
// TODO: ouch. probably need to tag the dev / master version as latest cos this won't work // TODO: ouch. probably need to tag the dev / master version as latest cos this won't work
// Need to pull the image here - if we do it at boot, then the test will fail. // Need to pull the image here - if we do it at boot, then the test will fail.
s.PullAndLoadInstallerImage(c, fmt.Sprintf("rancher/os-%sconsole:%s", console, "v0.8.0-rc3")) s.PullAndLoadImage(c, fmt.Sprintf("rancher/os-%sconsole:%s", console, "v0.8.0-rc3"))
s.MakeCall(fmt.Sprintf("sudo ros console switch -f %s", console)) s.MakeCall(fmt.Sprintf("sudo ros console switch -f %s", console))
c.Assert(s.WaitForSSH(), IsNil) c.Assert(s.WaitForSSH(), IsNil)
} }
@ -111,7 +111,7 @@ func (s *QemuSuite) commonTestCode(c *C, startWithVersion, console string) {
c.Assert(Version, Equals, version) c.Assert(Version, Equals, version)
fmt.Printf("installing %s", startWithVersion) fmt.Printf("installing %s", startWithVersion)
s.PullAndLoadInstallerImage(c, fmt.Sprintf("rancher/os:%s", startWithVersion)) s.PullAndLoadImage(c, fmt.Sprintf("rancher/os:%s", startWithVersion))
//ADD a custom append line and make sure its kept in the upgraded version too //ADD a custom append line and make sure its kept in the upgraded version too
@ -137,13 +137,13 @@ sync
if console != "default" { if console != "default" {
// Can't preload the startWithVersion console image, as some don't exist by that name - not sure how to approach that // Can't preload the startWithVersion console image, as some don't exist by that name - not sure how to approach that
//s.PullAndLoadInstallerImage(c, fmt.Sprintf("rancher/os-%sconsole:%s", console, startWithVersion)) //s.PullAndLoadImage(c, fmt.Sprintf("rancher/os-%sconsole:%s", console, startWithVersion))
// TODO: ouch. probably need to tag the dev / master version as latest cos this won't work // TODO: ouch. probably need to tag the dev / master version as latest cos this won't work
// Need to pull the image here - if we do it at boot, then the test will fail. // Need to pull the image here - if we do it at boot, then the test will fail.
if console == "alpine" { if console == "alpine" {
s.PullAndLoadInstallerImage(c, fmt.Sprintf("rancher/os-%sconsole:%s", console, "v0.8.0-rc5")) s.PullAndLoadImage(c, fmt.Sprintf("rancher/os-%sconsole:%s", console, "v0.8.0-rc5"))
} else { } else {
s.PullAndLoadInstallerImage(c, fmt.Sprintf("rancher/os-%sconsole:%s", console, "v0.8.0-rc3")) s.PullAndLoadImage(c, fmt.Sprintf("rancher/os-%sconsole:%s", console, "v0.8.0-rc3"))
} }
s.MakeCall(fmt.Sprintf("sudo ros console switch -f %s", console)) s.MakeCall(fmt.Sprintf("sudo ros console switch -f %s", console))
c.Assert(s.WaitForSSH(), IsNil) c.Assert(s.WaitForSSH(), IsNil)