diff --git a/cloudinit/user_data.go b/cloudinit/user_data.go deleted file mode 100644 index 33acdec..0000000 --- a/cloudinit/user_data.go +++ /dev/null @@ -1,30 +0,0 @@ -package cloudinit - -import ( - "bufio" - "bytes" - "fmt" - "log" - "strings" -) - -func ParseUserData(contents []byte) (interface{}, error) { - bytereader := bytes.NewReader(contents) - bufreader := bufio.NewReader(bytereader) - header, _ := bufreader.ReadString('\n') - - if strings.HasPrefix(header, "#!") { - log.Printf("Parsing user-data as script") - return Script(contents), nil - - } else if header == "#cloud-config\n" { - log.Printf("Parsing user-data as cloud-config") - cfg, err := NewCloudConfig(contents) - if err != nil { - log.Fatal(err.Error()) - } - return *cfg, nil - } else { - return nil, fmt.Errorf("Unrecognized user-data header: %s", header) - } -} diff --git a/cloudinit/workspace.go b/cloudinit/workspace.go deleted file mode 100644 index 9659765..0000000 --- a/cloudinit/workspace.go +++ /dev/null @@ -1,66 +0,0 @@ -package cloudinit - -import ( - "fmt" - "io/ioutil" - "os" - "path" -) - -func PrepWorkspace(workspace string) error { - // Ensure workspace exists and is a directory - info, err := os.Stat(workspace) - if err == nil { - if !info.IsDir() { - return fmt.Errorf("%s is not a directory", workspace) - } - } else { - err = os.MkdirAll(workspace, 0755) - if err != nil { - return err - } - } - - // Ensure scripts dir in workspace exists and is a directory - scripts := path.Join(workspace, "scripts") - info, err = os.Stat(scripts) - if err == nil { - if !info.IsDir() { - return fmt.Errorf("%s is not a directory", scripts) - } - } else { - err = os.Mkdir(scripts, 0755) - if err != nil { - return err - } - } - - return nil -} - -func PersistScriptInWorkspace(script Script, workspace string) (string, error) { - scriptsDir := path.Join(workspace, "scripts") - f, err := ioutil.TempFile(scriptsDir, "") - if err != nil { - return "", err - } - defer f.Close() - - f.Chmod(0744) - - _, err = f.Write(script) - if err != nil { - return "", err - } - - // Ensure script has been written to disk before returning, as the - // next natural thing to do is execute it - f.Sync() - - return f.Name(), nil -} - -func PersistScriptUnitNameInWorkspace(name string, workspace string) error { - unitPath := path.Join(workspace, "scripts", "unit-name") - return ioutil.WriteFile(unitPath, []byte(name), 0644) -} diff --git a/cloudinit/write_file.go b/cloudinit/write_file.go deleted file mode 100644 index e8d4ee9..0000000 --- a/cloudinit/write_file.go +++ /dev/null @@ -1,63 +0,0 @@ -package cloudinit - -import ( - "errors" - "fmt" - "io/ioutil" - "os" - "os/exec" - "path" - "strconv" -) - -type WriteFile struct { - Encoding string - Content string - Owner string - Path string - RawFilePermissions string `yaml:"permissions"` -} - -func (wf *WriteFile) Permissions() (os.FileMode, error) { - if wf.RawFilePermissions == "" { - return os.FileMode(0644), nil - } - - // Parse string representation of file mode as octal - perm, err := strconv.ParseInt(wf.RawFilePermissions, 8, 32) - if err != nil { - return 0, errors.New("Unable to parse file permissions as octal integer") - } - return os.FileMode(perm), nil -} - -func ProcessWriteFile(base string, wf *WriteFile) error { - if wf.Encoding != "" { - return fmt.Errorf("Unable to write file with encoding %s", wf.Encoding) - } - - fullPath := path.Join(base, wf.Path) - - if err := os.MkdirAll(path.Dir(fullPath), os.FileMode(0755)); err != nil { - return err - } - - perm, err := wf.Permissions() - if err != nil { - return err - } - - if err := ioutil.WriteFile(fullPath, []byte(wf.Content), perm); err != nil { - return err - } - - if wf.Owner != "" { - // We shell out since we don't have a way to look up unix groups natively - cmd := exec.Command("chown", wf.Owner, fullPath) - if err := cmd.Run(); err != nil { - return err - } - } - - return nil -} diff --git a/coreos-cloudinit.go b/coreos-cloudinit.go index ee81f92..9d1f99c 100644 --- a/coreos-cloudinit.go +++ b/coreos-cloudinit.go @@ -1,21 +1,22 @@ package main import ( - "fmt" + "bufio" + "bytes" "flag" - "io/ioutil" - "os" + "fmt" "log" + "os" + "strings" - "github.com/coreos/coreos-cloudinit/cloudinit" + "github.com/coreos/coreos-cloudinit/datasource" + "github.com/coreos/coreos-cloudinit/initialize" + "github.com/coreos/coreos-cloudinit/system" ) const version = "0.1.2+git" func main() { - var userdata []byte - var err error - var printVersion bool flag.BoolVar(&printVersion, "version", false, "Print the version and exit") @@ -29,7 +30,7 @@ func main() { flag.StringVar(&workspace, "workspace", "/var/lib/coreos-cloudinit", "Base directory coreos-cloudinit should use to store data") var sshKeyName string - flag.StringVar(&sshKeyName, "ssh-key-name", cloudinit.DefaultSSHKeyName, "Add SSH keys to the system with the given name") + flag.StringVar(&sshKeyName, "ssh-key-name", initialize.DefaultSSHKeyName, "Add SSH keys to the system with the given name") flag.Parse() @@ -43,49 +44,48 @@ func main() { os.Exit(1) } + var ds datasource.Datasource if file != "" { - log.Printf("Reading user-data from file: %s", file) - userdata, err = ioutil.ReadFile(file) - if err != nil { - log.Fatal(err.Error()) - } + ds = datasource.NewLocalFile(file) } else if url != "" { - log.Printf("Reading user-data from metadata service") - svc := cloudinit.NewMetadataService(url) - userdata, err = svc.UserData() - if err != nil { - log.Fatal(err.Error()) - } + ds = datasource.NewMetadataService(url) } else { fmt.Println("Provide one of --from-file or --from-url") os.Exit(1) } + log.Printf("Fetching user-data from datasource of type %q", ds.Type()) + userdata, err := ds.Fetch() + if err != nil { + log.Fatalf("Failed fetching user-data from datasource: %v", err) + } + if len(userdata) == 0 { log.Printf("No user data to handle, exiting.") os.Exit(0) } - parsed, err := cloudinit.ParseUserData(userdata) + parsed, err := ParseUserData(userdata) if err != nil { log.Fatalf("Failed parsing user-data: %v", err) } - err = cloudinit.PrepWorkspace(workspace) + env := initialize.NewEnvironment("/", workspace) + err = initialize.PrepWorkspace(env.Workspace()) if err != nil { log.Fatalf("Failed preparing workspace: %v", err) } switch t := parsed.(type) { - case cloudinit.CloudConfig: - err = cloudinit.ApplyCloudConfig(t, sshKeyName) - case cloudinit.Script: + case initialize.CloudConfig: + err = initialize.Apply(t, env) + case system.Script: var path string - path, err = cloudinit.PersistScriptInWorkspace(t, workspace) + path, err = initialize.PersistScriptInWorkspace(t, env.Workspace()) if err == nil { var name string - name, err = cloudinit.ExecuteScript(path) - cloudinit.PersistScriptUnitNameInWorkspace(name, workspace) + name, err = system.ExecuteScript(path) + initialize.PersistUnitNameInWorkspace(name, workspace) } } @@ -93,3 +93,24 @@ func main() { log.Fatalf("Failed resolving user-data: %v", err) } } + +func ParseUserData(contents []byte) (interface{}, error) { + bytereader := bytes.NewReader(contents) + bufreader := bufio.NewReader(bytereader) + header, _ := bufreader.ReadString('\n') + + if strings.HasPrefix(header, "#!") { + log.Printf("Parsing user-data as script") + return system.Script(contents), nil + + } else if header == "#cloud-config\n" { + log.Printf("Parsing user-data as cloud-config") + cfg, err := initialize.NewCloudConfig(contents) + if err != nil { + log.Fatal(err.Error()) + } + return *cfg, nil + } else { + return nil, fmt.Errorf("Unrecognized user-data header: %s", header) + } +} diff --git a/datasource/datasource.go b/datasource/datasource.go new file mode 100644 index 0000000..d78fa3b --- /dev/null +++ b/datasource/datasource.go @@ -0,0 +1,6 @@ +package datasource + +type Datasource interface { + Fetch() ([]byte, error) + Type() string +} diff --git a/datasource/file.go b/datasource/file.go new file mode 100644 index 0000000..c5cb1ae --- /dev/null +++ b/datasource/file.go @@ -0,0 +1,21 @@ +package datasource + +import ( + "io/ioutil" +) + +type localFile struct { + path string +} + +func NewLocalFile(path string) *localFile { + return &localFile{path} +} + +func (self *localFile) Fetch() ([]byte, error) { + return ioutil.ReadFile(self.path) +} + +func (self *localFile) Type() string { + return "local-file" +} diff --git a/cloudinit/metadata_service.go b/datasource/metadata_service.go similarity index 77% rename from cloudinit/metadata_service.go rename to datasource/metadata_service.go index 314831b..899c5a2 100644 --- a/cloudinit/metadata_service.go +++ b/datasource/metadata_service.go @@ -1,4 +1,4 @@ -package cloudinit +package datasource import ( "io/ioutil" @@ -14,7 +14,7 @@ func NewMetadataService(url string) *metadataService { return &metadataService{url, http.Client{}} } -func (ms *metadataService) UserData() ([]byte, error) { +func (ms *metadataService) Fetch() ([]byte, error) { resp, err := ms.client.Get(ms.url) if err != nil { return []byte{}, err @@ -33,4 +33,6 @@ func (ms *metadataService) UserData() ([]byte, error) { return respBytes, nil } - +func (ms *metadataService) Type() string { + return "metadata-service" +} diff --git a/cloudinit/cloud_config.go b/initialize/config.go similarity index 71% rename from cloudinit/cloud_config.go rename to initialize/config.go index a9cb817..4974b44 100644 --- a/cloudinit/cloud_config.go +++ b/initialize/config.go @@ -1,24 +1,25 @@ -package cloudinit +package initialize import ( "fmt" "log" + "path" "github.com/coreos/coreos-cloudinit/third_party/launchpad.net/goyaml" -) -const DefaultSSHKeyName = "coreos-cloudinit" + "github.com/coreos/coreos-cloudinit/system" +) type CloudConfig struct { SSHAuthorizedKeys []string `yaml:"ssh_authorized_keys"` Coreos struct { Etcd EtcdEnvironment Fleet struct{ Autostart bool } - Units []Unit + Units []system.Unit } - WriteFiles []WriteFile `yaml:"write_files"` + WriteFiles []system.File `yaml:"write_files"` Hostname string - Users []User + Users []system.User } func NewCloudConfig(contents []byte) (*CloudConfig, error) { @@ -39,9 +40,9 @@ func (cc CloudConfig) String() string { return stringified } -func ApplyCloudConfig(cfg CloudConfig, sshKeyName string) error { +func Apply(cfg CloudConfig, env *Environment) error { if cfg.Hostname != "" { - if err := SetHostname(cfg.Hostname); err != nil { + if err := system.SetHostname(cfg.Hostname); err != nil { return err } log.Printf("Set hostname to %s", cfg.Hostname) @@ -54,18 +55,18 @@ func ApplyCloudConfig(cfg CloudConfig, sshKeyName string) error { continue } - if UserExists(&user) { + if system.UserExists(&user) { log.Printf("User '%s' exists, ignoring creation-time fields", user.Name) if user.PasswordHash != "" { log.Printf("Setting '%s' user's password", user.Name) - if err := SetUserPassword(user.Name, user.PasswordHash); err != nil { + if err := system.SetUserPassword(user.Name, user.PasswordHash); err != nil { log.Printf("Failed setting '%s' user's password: %v", user.Name, err) return err } } } else { log.Printf("Creating user '%s'", user.Name) - if err := CreateUser(&user); err != nil { + if err := system.CreateUser(&user); err != nil { log.Printf("Failed creating user '%s': %v", user.Name, err) return err } @@ -73,7 +74,7 @@ func ApplyCloudConfig(cfg CloudConfig, sshKeyName string) error { if len(user.SSHAuthorizedKeys) > 0 { log.Printf("Authorizing %d SSH keys for user '%s'", len(user.SSHAuthorizedKeys), user.Name) - if err := AuthorizeSSHKeys(user.Name, sshKeyName, user.SSHAuthorizedKeys); err != nil { + if err := system.AuthorizeSSHKeys(user.Name, env.SSHKeyName(), user.SSHAuthorizedKeys); err != nil { return err } } @@ -81,7 +82,7 @@ func ApplyCloudConfig(cfg CloudConfig, sshKeyName string) error { } if len(cfg.SSHAuthorizedKeys) > 0 { - err := AuthorizeSSHKeys("core", sshKeyName, cfg.SSHAuthorizedKeys) + err := system.AuthorizeSSHKeys("core", env.SSHKeyName(), cfg.SSHAuthorizedKeys) if err == nil { log.Printf("Authorized SSH keys for core user") } else { @@ -91,7 +92,8 @@ func ApplyCloudConfig(cfg CloudConfig, sshKeyName string) error { if len(cfg.WriteFiles) > 0 { for _, file := range cfg.WriteFiles { - if err := ProcessWriteFile("/", &file); err != nil { + file.Path = path.Join(env.Root(), file.Path) + if err := system.WriteFile(&file); err != nil { return err } log.Printf("Wrote file %s to filesystem", file.Path) @@ -99,7 +101,7 @@ func ApplyCloudConfig(cfg CloudConfig, sshKeyName string) error { } if len(cfg.Coreos.Etcd) > 0 { - if err := WriteEtcdEnvironment("/", cfg.Coreos.Etcd); err != nil { + if err := WriteEtcdEnvironment(cfg.Coreos.Etcd, env.Root()); err != nil { log.Fatalf("Failed to write etcd config to filesystem: %v", err) } @@ -109,7 +111,7 @@ func ApplyCloudConfig(cfg CloudConfig, sshKeyName string) error { if len(cfg.Coreos.Units) > 0 { for _, unit := range cfg.Coreos.Units { log.Printf("Placing unit %s on filesystem", unit.Name) - dst, err := PlaceUnit("/", &unit) + dst, err := system.PlaceUnit(&unit, env.Root()) if err != nil { return err } @@ -117,7 +119,7 @@ func ApplyCloudConfig(cfg CloudConfig, sshKeyName string) error { if unit.Group() != "network" { log.Printf("Enabling unit file %s", dst) - if err := EnableUnitFile(dst, unit.Runtime); err != nil { + if err := system.EnableUnitFile(dst, unit.Runtime); err != nil { return err } log.Printf("Enabled unit %s", unit.Name) @@ -125,12 +127,12 @@ func ApplyCloudConfig(cfg CloudConfig, sshKeyName string) error { log.Printf("Skipping enable for network-like unit %s", unit.Name) } } - DaemonReload() - StartUnits(cfg.Coreos.Units) + system.DaemonReload() + system.StartUnits(cfg.Coreos.Units) } if cfg.Coreos.Fleet.Autostart { - err := StartUnitByName("fleet.service") + err := system.StartUnitByName("fleet.service") if err == nil { log.Printf("Started fleet service.") } else { diff --git a/cloudinit/cloud_config_test.go b/initialize/config_test.go similarity index 99% rename from cloudinit/cloud_config_test.go rename to initialize/config_test.go index 76e5b82..4179c6f 100644 --- a/cloudinit/cloud_config_test.go +++ b/initialize/config_test.go @@ -1,4 +1,4 @@ -package cloudinit +package initialize import ( "strings" diff --git a/initialize/env.go b/initialize/env.go new file mode 100644 index 0000000..94d2e70 --- /dev/null +++ b/initialize/env.go @@ -0,0 +1,33 @@ +package initialize + +import ( + "path" +) + +const DefaultSSHKeyName = "coreos-cloudinit" + +type Environment struct { + root string + workspace string + sshKeyName string +} + +func NewEnvironment(root, workspace string) *Environment { + return &Environment{root, workspace, DefaultSSHKeyName} +} + +func (self *Environment) Workspace() string { + return path.Join(self.root, self.workspace) +} + +func (self *Environment) Root() string { + return self.root +} + +func (self *Environment) SSHKeyName() string { + return self.sshKeyName +} + +func (self *Environment) SetSSHKeyName(name string) { + self.sshKeyName = name +} diff --git a/cloudinit/etcd.go b/initialize/etcd.go similarity index 61% rename from cloudinit/etcd.go rename to initialize/etcd.go index 229bd41..7d945dd 100644 --- a/cloudinit/etcd.go +++ b/initialize/etcd.go @@ -1,11 +1,12 @@ -package cloudinit +package initialize import ( "fmt" - "io/ioutil" "os" "path" "strings" + + "github.com/coreos/coreos-cloudinit/system" ) type EtcdEnvironment map[string]string @@ -34,15 +35,12 @@ func (ec EtcdEnvironment) String() (out string) { } // Write an EtcdEnvironment to the appropriate path on disk for etcd.service -func WriteEtcdEnvironment(root string, env EtcdEnvironment) error { - cfgDir := path.Join(root, "etc", "systemd", "system", "etcd.service.d") - cfgFile := path.Join(cfgDir, "20-cloudinit.conf") - - if _, err := os.Stat(cfgDir); err != nil { - if err := os.MkdirAll(cfgDir, os.FileMode(0755)); err != nil { - return err - } +func WriteEtcdEnvironment(env EtcdEnvironment, root string) error { + file := system.File{ + Path: path.Join(root, "etc", "systemd", "system", "etcd.service.d", "20-cloudinit.conf"), + RawFilePermissions: "0644", + Content: env.String(), } - return ioutil.WriteFile(cfgFile, []byte(env.String()), os.FileMode(0644)) + return system.WriteFile(&file) } diff --git a/cloudinit/etcd_test.go b/initialize/etcd_test.go similarity index 96% rename from cloudinit/etcd_test.go rename to initialize/etcd_test.go index c76abc7..46655f3 100644 --- a/cloudinit/etcd_test.go +++ b/initialize/etcd_test.go @@ -1,4 +1,4 @@ -package cloudinit +package initialize import ( "io/ioutil" @@ -55,7 +55,7 @@ func TestEtcdEnvironmentWrittenToDisk(t *testing.T) { } defer syscall.Rmdir(dir) - if err := WriteEtcdEnvironment(dir, ec); err != nil { + if err := WriteEtcdEnvironment(ec, dir); err != nil { t.Fatalf("Processing of EtcdEnvironment failed: %v", err) } diff --git a/initialize/workspace.go b/initialize/workspace.go new file mode 100644 index 0000000..3f21d5a --- /dev/null +++ b/initialize/workspace.go @@ -0,0 +1,48 @@ +package initialize + +import ( + "io/ioutil" + "path" + + "github.com/coreos/coreos-cloudinit/system" +) + +func PrepWorkspace(workspace string) error { + if err := system.EnsureDirectoryExists(workspace); err != nil { + return err + } + + scripts := path.Join(workspace, "scripts") + if err := system.EnsureDirectoryExists(scripts); err != nil { + return err + } + + return nil +} + +func PersistScriptInWorkspace(script system.Script, workspace string) (string, error) { + scriptsPath := path.Join(workspace, "scripts") + tmp, err := ioutil.TempFile(scriptsPath, "") + if err != nil { + return "", err + } + tmp.Close() + + file := system.File{ + Path: tmp.Name(), + RawFilePermissions: "0744", + Content: string(script), + } + + err = system.WriteFile(&file) + return file.Path, err +} + +func PersistUnitNameInWorkspace(name string, workspace string) error { + file := system.File{ + Path: path.Join(workspace, "scripts", "unit-name"), + RawFilePermissions: "0644", + Content: name, + } + return system.WriteFile(&file) +} diff --git a/system/file.go b/system/file.go new file mode 100644 index 0000000..43cd4c2 --- /dev/null +++ b/system/file.go @@ -0,0 +1,77 @@ +package system + +import ( + "errors" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path" + "strconv" +) + +type File struct { + Encoding string + Content string + Owner string + Path string + RawFilePermissions string `yaml:"permissions"` +} + +func (f *File) Permissions() (os.FileMode, error) { + if f.RawFilePermissions == "" { + return os.FileMode(0644), nil + } + + // Parse string representation of file mode as octal + perm, err := strconv.ParseInt(f.RawFilePermissions, 8, 32) + if err != nil { + return 0, errors.New("Unable to parse file permissions as octal integer") + } + return os.FileMode(perm), nil +} + + +func WriteFile(f *File) error { + if f.Encoding != "" { + return fmt.Errorf("Unable to write file with encoding %s", f.Encoding) + } + + if err := os.MkdirAll(path.Dir(f.Path), os.FileMode(0755)); err != nil { + return err + } + + perm, err := f.Permissions() + if err != nil { + return err + } + + if err := ioutil.WriteFile(f.Path, []byte(f.Content), perm); err != nil { + return err + } + + if f.Owner != "" { + // We shell out since we don't have a way to look up unix groups natively + cmd := exec.Command("chown", f.Owner, f.Path) + if err := cmd.Run(); err != nil { + return err + } + } + + return nil +} + +func EnsureDirectoryExists(dir string) error { + info, err := os.Stat(dir) + if err == nil { + if !info.IsDir() { + return fmt.Errorf("%s is not a directory", dir) + } + } else { + err = os.MkdirAll(dir, 0755) + if err != nil { + return err + } + } + return nil +} diff --git a/cloudinit/write_file_test.go b/system/file_test.go similarity index 79% rename from cloudinit/write_file_test.go rename to system/file_test.go index 3e489bf..c8cd3d0 100644 --- a/cloudinit/write_file_test.go +++ b/system/file_test.go @@ -1,4 +1,4 @@ -package cloudinit +package system import ( "io/ioutil" @@ -9,21 +9,23 @@ import ( ) func TestWriteFileUnencodedContent(t *testing.T) { - wf := WriteFile{ - Path: "/tmp/foo", - Content: "bar", - } dir, err := ioutil.TempDir(os.TempDir(), "coreos-cloudinit-") if err != nil { t.Fatalf("Unable to create tempdir: %v", err) } defer syscall.Rmdir(dir) - if err := ProcessWriteFile(dir, &wf); err != nil { - t.Fatalf("Processing of WriteFile failed: %v", err) + fullPath := path.Join(dir, "tmp", "foo") + + wf := File{ + Path: fullPath, + Content: "bar", + RawFilePermissions: "0644", } - fullPath := path.Join(dir, "tmp", "foo") + if err := WriteFile(&wf); err != nil { + t.Fatalf("Processing of WriteFile failed: %v", err) + } fi, err := os.Stat(fullPath) if err != nil { @@ -45,38 +47,40 @@ func TestWriteFileUnencodedContent(t *testing.T) { } func TestWriteFileInvalidPermission(t *testing.T) { - wf := WriteFile{ - Path: "/tmp/foo", - Content: "bar", - RawFilePermissions: "pants", - } dir, err := ioutil.TempDir(os.TempDir(), "coreos-cloudinit-") if err != nil { t.Fatalf("Unable to create tempdir: %v", err) } defer syscall.Rmdir(dir) - if err := ProcessWriteFile(dir, &wf); err == nil { + wf := File{ + Path: path.Join(dir, "tmp", "foo"), + Content: "bar", + RawFilePermissions: "pants", + } + + if err := WriteFile(&wf); err == nil { t.Fatalf("Expected error to be raised when writing file with invalid permission") } } func TestWriteFilePermissions(t *testing.T) { - wf := WriteFile{ - Path: "/tmp/foo", - RawFilePermissions: "0755", - } dir, err := ioutil.TempDir(os.TempDir(), "coreos-cloudinit-") if err != nil { t.Fatalf("Unable to create tempdir: %v", err) } defer syscall.Rmdir(dir) - if err := ProcessWriteFile(dir, &wf); err != nil { - t.Fatalf("Processing of WriteFile failed: %v", err) + fullPath := path.Join(dir, "tmp", "foo") + + wf := File{ + Path: fullPath, + RawFilePermissions: "0755", } - fullPath := path.Join(dir, "tmp", "foo") + if err := WriteFile(&wf); err != nil { + t.Fatalf("Processing of WriteFile failed: %v", err) + } fi, err := os.Stat(fullPath) if err != nil { @@ -89,19 +93,19 @@ func TestWriteFilePermissions(t *testing.T) { } func TestWriteFileEncodedContent(t *testing.T) { - wf := WriteFile{ - Path: "/tmp/foo", - Content: "", - Encoding: "base64", - } - dir, err := ioutil.TempDir(os.TempDir(), "coreos-cloudinit-") if err != nil { t.Fatalf("Unable to create tempdir: %v", err) } defer syscall.Rmdir(dir) - if err := ProcessWriteFile(dir, &wf); err == nil { + wf := File{ + Path: path.Join(dir, "tmp", "foo"), + Content: "", + Encoding: "base64", + } + + if err := WriteFile(&wf); err == nil { t.Fatalf("Expected error to be raised when writing file with encoding") } } diff --git a/cloudinit/ssh_key.go b/system/ssh_key.go similarity index 98% rename from cloudinit/ssh_key.go rename to system/ssh_key.go index 623ee9a..96fa246 100644 --- a/cloudinit/ssh_key.go +++ b/system/ssh_key.go @@ -1,4 +1,4 @@ -package cloudinit +package system import ( "fmt" diff --git a/cloudinit/systemd.go b/system/systemd.go similarity index 94% rename from cloudinit/systemd.go rename to system/systemd.go index 213d88f..5861238 100644 --- a/cloudinit/systemd.go +++ b/system/systemd.go @@ -1,8 +1,7 @@ -package cloudinit +package system import ( "fmt" - "io/ioutil" "log" "os" "os/exec" @@ -36,7 +35,7 @@ func (u *Unit) Group() (group string) { type Script []byte -func PlaceUnit(root string, u *Unit) (string, error) { +func PlaceUnit(u *Unit, root string) (string, error) { dir := "etc" if u.Runtime { dir = "run" @@ -50,7 +49,14 @@ func PlaceUnit(root string, u *Unit) (string, error) { } dst = path.Join(dst, u.Name) - err := ioutil.WriteFile(dst, []byte(u.Content), os.FileMode(0644)) + + file := File{ + Path: dst, + Content: u.Content, + RawFilePermissions: "0644", + } + + err := WriteFile(&file) if err != nil { return "", err } diff --git a/cloudinit/systemd_test.go b/system/systemd_test.go similarity index 94% rename from cloudinit/systemd_test.go rename to system/systemd_test.go index f7089ea..02924b0 100644 --- a/cloudinit/systemd_test.go +++ b/system/systemd_test.go @@ -1,4 +1,4 @@ -package cloudinit +package system import ( "io/ioutil" @@ -26,7 +26,7 @@ Address=10.209.171.177/19 } defer syscall.Rmdir(dir) - if _, err := PlaceUnit(dir, &u); err != nil { + if _, err := PlaceUnit(&u, dir); err != nil { t.Fatalf("PlaceUnit failed: %v", err) } @@ -72,7 +72,7 @@ Where=/media/state } defer syscall.Rmdir(dir) - if _, err := PlaceUnit(dir, &u); err != nil { + if _, err := PlaceUnit(&u, dir); err != nil { t.Fatalf("PlaceUnit failed: %v", err) } diff --git a/cloudinit/user.go b/system/user.go similarity index 99% rename from cloudinit/user.go rename to system/user.go index 9d8a36f..1689bae 100644 --- a/cloudinit/user.go +++ b/system/user.go @@ -1,4 +1,4 @@ -package cloudinit +package system import ( "fmt" diff --git a/test b/test index 30b4dc5..9dae2cd 100755 --- a/test +++ b/test @@ -4,5 +4,7 @@ echo "Building bin/coreos-cloudinit" . build echo "Running tests..." -go test -i github.com/coreos/coreos-cloudinit/cloudinit -go test -v github.com/coreos/coreos-cloudinit/cloudinit +for pkg in "./initialize ./system"; do + go test -i $pkg + go test -v $pkg +done diff --git a/test.yaml b/test.yaml new file mode 100644 index 0000000..8941ecd --- /dev/null +++ b/test.yaml @@ -0,0 +1,7 @@ +#cloud-config + +coreos: + etcd: + discovery_url: https://discovery.etcd.io/0022cb5027f8f5167a874794c3a13e0d + bind-addr: $public_ipv4:4001 + name: polvi