func TestWriteFileDirective(t *testing.T) { Convey("Given a configuration file containing files to be written", t, func() { configFile, err := os.Open(filepath.Join(testConfigDirectory, "write_files.yaml")) So(err, ShouldBeNil) Convey("It should parse the file names and the file contents", func() { conf, err := cloudconfig.Parse(configFile) So(err, ShouldBeNil) So(conf.Files[0], ShouldStructEqual, cloudconfig.WriteFile{ Path: "/etc/sysconfig/selinux", Permissions: "0644", Owner: "some_user:some_group", Encoding: "b64", Content: "STRING_FILE_CONTENT", }) So(conf.Files[1], ShouldStructEqual, cloudconfig.WriteFile{ Path: "/etc/sysconfig/samba", Content: "# My new /etc/sysconfig/samba file\n\nSMBDOPTIONS=\"-D\"\n", }) /* TODO(tmrts): Test binary file contents * *So(conf.Files[2], ShouldStructEqual, cloudconfig.WriteFile{ * Path: "/bin/arch", * Permissions: "0555", * Content: base64.StdEncoding.EncodeToString([]byte("f0VMRgIBAQAAAAAAAAAAAAIAPgABAAAAwARAAAAAAABAAAAAAAAAAJAVAAAAAAAAAAAAAEAAOAAI")), *}) */ }) }) }
func TestRunCmdParsing(t *testing.T) { Convey("Given a cloud-config file with runcmd directive", t, func() { configFile, err := os.Open(filepath.Join(testConfigDirectory, "runcmd.yaml")) So(err, ShouldBeNil) Convey("It should parse the execute statements", func() { conf, err := cloudconfig.Parse(configFile) So(err, ShouldBeNil) So(conf.Commands[0], ShouldConsistOf, "ls", "-l", "/") So(conf.Commands[1], ShouldConsistOf, "sh", "-xc", "echo $(date) ': hello world!'") So(conf.Commands[2], ShouldConsistOf, "sh", "-c", "echo \"=========hello world'=========\"") So(conf.Commands[3], ShouldConsistOf, "sh", "-c", "ls -l /root") So(conf.Commands[4], ShouldConsistOf, "wget", "http://slashdot.org", "-O", "/tmp/index.html") }) }) }
func TestSSHKeyParsing(t *testing.T) { Convey("Given a cloud-config file containing SSH-key directives", t, func() { configFile, err := os.Open(filepath.Join(testConfigDirectory, "sshkeys.yaml")) So(err, ShouldBeNil) Convey("It should parse the ssh keys", func() { conf, err := cloudconfig.Parse(configFile) So(err, ShouldBeNil) So(conf.AuthorizedKeys["root"], ShouldConsistOf, ssh.Key("ssh-rsa RSA_PUBLIC_KEY_1 mykey@host"), ssh.Key("ssh-rsa RSA_PUBLIC_KEY_2 mykey@host"), ) So(conf.SSHKeyPairs, ShouldConsistOf, ssh.KeyPair{ Public: ssh.Key("ssh-rsa RSA_PUBLIC_KEY smoser@localhost"), Private: ssh.Key("-----BEGIN RSA PRIVATE KEY-----\nRSA_PRIVATE_KEY\n-----END RSA PRIVATE KEY-----\n"), }, ) }) }) }
func TestUserGroupParsing(t *testing.T) { Convey("Given a cloud-config file containing users and/or groups", t, func() { configFile, err := os.Open(filepath.Join(testConfigDirectory, "usergroups.yaml")) So(err, ShouldBeNil) Convey("It should parse the users and groups", func() { c, err := cloudconfig.Parse(configFile) So(err, ShouldBeNil) So(c.Groups["cloud-users"], ShouldBeEmpty) So(c.Users["foobar"], ShouldStructEqual, identity.User{ Name: "foobar", GECOS: "Foo B. Bar", GID: "foobar", SecondaryGroups: []string{"users"}, PasswordHash: "$6$SHA256$PASSWORD_HASH", ExpireDate: "2012-09-01", SELinuxUser: "******", }) So(c.Users["barfoo"], ShouldStructEqual, identity.User{ Name: "barfoo", GECOS: "Bar B. Foo", SecondaryGroups: []string{"users", "admin"}, }) So(c.Users["daemon"], ShouldStructEqual, identity.User{ Name: "daemon", GECOS: "Magic Cloud App Daemon User", IsInactive: true, IsSystemAccount: true, }) }) }) }
// consumeCloudConfig parses the given cloud config file contents and // consumes the parsed directives. func (imp *Implementation) consumeCloudConfig(contents string) error { conf, err := cloudconfig.Parse(strutil.ToReadCloser(contents)) if err != nil { flog.Error("Failed to parse cloud config file", flog.Fields{ Event: "cloudconfig.Parse", Error: err, }, ) return err } flog.Debug("Persisting files", flog.Fields{ Event: "distro.Implementation.consumeCloudConfig", }, ) imp.writeFiles(conf.Files) imp.consumeCommands(conf.Commands) for grpName, _ := range conf.Groups { flog.Info("Creating user group", flog.Fields{ Event: "distro.consumeCloudConfig", }, flog.Details{ "group": grpName, }, ) newGrp := identity.Group{ Name: grpName, } if err := imp.ID.CreateGroup(newGrp); err != nil { flog.Error("Failed to create a user group", flog.Fields{ Event: "identityManager.CreateGroup", Error: err, }, flog.Details{ "group": grpName, }, ) } } for _, usr := range conf.Users { flog.Info("Creating user", flog.Fields{ Event: "distro.consumeCloudConfig", }, flog.Details{ "user": usr.Name, }, ) if err := imp.ID.CreateUser(usr); err != nil { flog.Error("Failed to create a user", flog.Fields{ Event: "identityManager.CreateUser", Error: err, }, flog.Details{ "user": usr.Name, }, ) } } for grpName, usrNames := range conf.Groups { for _, usrName := range usrNames { flog.Info("Adding user to group", flog.Fields{ Event: "distro.consumeCloudConfig", }, flog.Details{ "user": usrName, "group": grpName, }, ) if err := imp.ID.AddUserToGroup(usrName, grpName); err != nil { flog.Error("Failed to add user to group", flog.Fields{ Event: "identityManager.AddUserToGroup", Error: err, }, flog.Details{ "user": usrName, "group": grpName, }, ) } } } imp.consumeSSHKeys(conf.AuthorizedKeys) return err }