// ConsumeMetadata uses the given userdata to contextualize the distribution implementation. func (imp *Implementation) ConsumeMetadata(m *metadata.Digest) error { flog.Info("Consuming meta-data", flog.Fields{ Event: "distro.Implementation.ConsumeMetadata", }, ) if err := imp.setHostname(m.Hostname); err != nil { flog.Error("Failed to set hostname", flog.Fields{ Event: "distro.Implementation.setHostname", }, flog.Details{ "name": m.Hostname, }, ) return err } imp.consumeSSHKeys(m.SSHKeys) flog.Info("Finished consuming meta-data", flog.Fields{ Event: "distro.Implementation.ConsumeUserdata", }, ) return nil }
// consumeScripts executes the given name/script content pairs. func (imp *Implementation) consumeScripts(scripts map[string]string) { for name, content := range scripts { flog.Info("Executing script", flog.Fields{ Event: "distro.consumeScripts", }, flog.Details{ "name": name, }, ) if err := imp.executeScript(content); err != nil { flog.Error("Failed to execute script", flog.Fields{ Event: "distro.executeScript", }, flog.Details{ "name": name, }, flog.DebugFields{ "content": content, }, ) } } }
func FinalizeContextualization() error { // TODO(tmrts): Add plug-in hooks flog.Info("Finalizing contextualization", flog.Fields{ Event: "main.FinalizeContextualization", }, ) return nil }
// consumeSSHKeys authorizes the given SSH keys for the user. func (imp *Implementation) consumeSSHKeys(userKeys map[string][]ssh.Key) { for userName, sshKeys := range userKeys { flog.Info("Authorizing SSH keys", flog.Fields{ Event: "distro.consumeSSHKeys", }, flog.Details{ "user": userName, }, ) usr, err := nss.GetUser(userName) if err != nil { flog.Error("Failed to retrieve user NSS entry", flog.Fields{ Event: "nss.GetUser", Error: err, }, flog.Details{ "user": userName, }, ) continue } if err := ssh.AuthorizeKeysFor(usr, sshKeys); err != nil { flog.Error("Failed to authorize SSH keys for user", flog.Fields{ Event: "ssh.AuthorizeKeysFor", Error: err, }, flog.Details{ "user": userName, }, flog.DebugFields{ "SSHKeys": sshKeys, }, ) } } }
// 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 }
// ConsumeUserdata uses the given userdata to contextualize the distribution implementation. func (imp *Implementation) ConsumeUserdata(u userdata.Map) error { // TODO(tmrts): Store unused user-data in files? // TODO(tmrts): Execute scripts in rc.local or a similar level flog.Info("Consuming user-data", flog.Fields{ Event: "distro.ConsumeUserdata", }, ) // TODO(tmrts): Use only scripts with 'startup', 'shutdown', 'user-data'. scripts := u.Scripts() flog.Info("Searched for script files", flog.Fields{ Event: "userdata.Map.Scripts", }, flog.Details{ "count": len(scripts), }, ) imp.consumeScripts(scripts) confs := u.CloudConfigs() flog.Info("Searched for cloud-config files", flog.Fields{ Event: "userdata.Map.CloudConfigs", }, flog.Details{ "count": len(confs), }, ) for name, content := range confs { flog.Info("Consuming user-data file", flog.Fields{ Event: "distro.ConsumeUserdata", }, flog.Details{ "name": name, }, ) err := imp.consumeCloudConfig(content) if err != nil { flog.Error("Failed to consume cloud-config file", flog.Fields{ Event: "distro.consumeCloudConfig", }, flog.Details{ "name": name, }, flog.DebugFields{ "content": content, }, ) return err } } flog.Info("Finished consuming user-data", flog.Fields{ Event: "distro.Implementation.ConsumeUserdata", }, ) return nil }