// ComposeUserData fills out the provided cloudinit configuration structure // so it is suitable for initialising a machine with the given configuration, // and then renders it and encodes it using the supplied renderer. // When calling ComposeUserData a encoding implementation must be chosen from // the providerinit/encoders package according to the need of the provider. // // If the provided cloudcfg is nil, a new one will be created internally. func ComposeUserData(icfg *instancecfg.InstanceConfig, cloudcfg cloudinit.CloudConfig, renderer renderers.ProviderRenderer) ([]byte, error) { if cloudcfg == nil { var err error cloudcfg, err = cloudinit.New(icfg.Series) if err != nil { return nil, errors.Trace(err) } } _, err := configureCloudinit(icfg, cloudcfg) if err != nil { return nil, errors.Trace(err) } operatingSystem, err := series.GetOSFromSeries(icfg.Series) if err != nil { return nil, errors.Trace(err) } // This might get replaced by a renderer.RenderUserdata which will either // render it as YAML or Bash since some CentOS images might ship without cloudnit udata, err := cloudcfg.RenderYAML() if err != nil { return nil, errors.Trace(err) } udata, err = renderer.EncodeUserdata(udata, operatingSystem) if err != nil { return nil, errors.Trace(err) } logger.Tracef("Generated cloud init:\n%s", string(udata)) return udata, err }
func assertScriptMatches(c *gc.C, cfg cloudinit.CloudConfig, pattern string, match bool) { script, err := cfg.RenderScript() c.Assert(err, jc.ErrorIsNil) checker := gc.Matches if !match { checker = gc.Not(checker) } c.Assert(script, checker, pattern) }
// cloudinitRunCmd returns the shell command that, when run, will create the // "machine info" file containing the hostname of a machine. // That command is destined to be used by cloudinit. func (info *machineInfo) cloudinitRunCmd(cloudcfg cloudinit.CloudConfig) (string, error) { dataDir, err := paths.DataDir(cloudcfg.GetSeries()) if err != nil { return "", errors.Trace(err) } yaml, err := goyaml.Marshal(info) if err != nil { return "", errors.Trace(err) } renderer := cloudcfg.ShellRenderer() fileName := renderer.Join(renderer.FromSlash(dataDir), "MAASmachine.txt") script := renderer.MkdirAll(dataDir) contents := renderer.Quote(string(yaml)) script = append(script, renderer.WriteFile(fileName, []byte(contents))...) script = append(script, renderer.Chmod(fileName, 0755)...) return strings.Join(script, "\n"), nil }
// ComposeUserData fills out the provided cloudinit configuration structure // so it is suitable for initialising a machine with the given configuration, // and then renders it and returns it as a binary (gzipped) blob of user data. // // If the provided cloudcfg is nil, a new one will be created internally. func ComposeUserData(icfg *instancecfg.InstanceConfig, cloudcfg cloudinit.CloudConfig) ([]byte, error) { if cloudcfg == nil { var err error cloudcfg, err = cloudinit.New(icfg.Series) if err != nil { return nil, err } } _, err := configureCloudinit(icfg, cloudcfg) if err != nil { return nil, err } data, err := cloudcfg.RenderYAML() logger.Tracef("Generated cloud init:\n%s", string(data)) if err != nil { return nil, err } return utils.Gzip(data), nil }
func assertUserData(c *gc.C, cloudConf cloudinit.CloudConfig, expected string) { data, err := cloudConf.RenderYAML() c.Assert(err, jc.ErrorIsNil) c.Assert(string(data), gc.Equals, expected) // Make sure it's valid YAML as well. out := make(map[string]interface{}) err = yaml.Unmarshal(data, &out) c.Assert(err, jc.ErrorIsNil) if len(cloudConf.BootCmds()) > 0 { outcmds := out["bootcmd"].([]interface{}) confcmds := cloudConf.BootCmds() c.Assert(len(outcmds), gc.Equals, len(confcmds)) for i, _ := range outcmds { c.Assert(outcmds[i].(string), gc.Equals, confcmds[i]) } } else { c.Assert(out["bootcmd"], gc.IsNil) } }
// SetUbuntuUser creates an "ubuntu" use for unix systems so the juju client // can access the machine using ssh with the configuration we expect. // On precise, the default cloudinit version is too old to support the users // option, so instead rely on the default user being created and adding keys. // It may make sense in the future to add a "juju" user instead across // all distributions. func SetUbuntuUser(conf cloudinit.CloudConfig, authorizedKeys string) { targetSeries := conf.GetSeries() if targetSeries == "precise" { conf.SetSSHAuthorizedKeys(authorizedKeys) } else { var groups []string targetOS, _ := series.GetOSFromSeries(targetSeries) switch targetOS { case os.Ubuntu: groups = UbuntuGroups case os.CentOS: groups = CentOSGroups } conf.AddUser(&cloudinit.User{ Name: "ubuntu", Groups: groups, Shell: "/bin/bash", Sudo: []string{"ALL=(ALL) NOPASSWD:ALL"}, SSHAuthorizedKeys: authorizedKeys, }) } }
// TemplateUserData returns a minimal user data necessary for the template. // This should have the authorized keys, base packages, the cloud archive if // necessary, initial apt proxy config, and it should do the apt-get // update/upgrade initially. func TemplateUserData( series string, authorizedKeys string, aptProxy proxy.Settings, aptMirror string, enablePackageUpdates bool, enableOSUpgrades bool, networkConfig *container.NetworkConfig, ) ([]byte, error) { var config cloudinit.CloudConfig var err error if networkConfig != nil { config, err = newCloudInitConfigWithNetworks(series, networkConfig) if err != nil { return nil, errors.Trace(err) } } else { config, err = cloudinit.New(series) if err != nil { return nil, errors.Trace(err) } } cloudconfig.SetUbuntuUser(config, authorizedKeys) config.AddScripts( "set -xe", // ensure we run all the scripts or abort. ) // For LTS series which need support for the cloud-tools archive, // we need to enable apt-get update regardless of the environ // setting, otherwise provisioning will fail. if series == "precise" && !enablePackageUpdates { logger.Warningf("series %q requires cloud-tools archive: enabling updates", series) enablePackageUpdates = true } if enablePackageUpdates && config.RequiresCloudArchiveCloudTools() { config.AddCloudArchiveCloudTools() } config.AddPackageCommands(aptProxy, aptMirror, enablePackageUpdates, enableOSUpgrades) initSystem, err := service.VersionInitSystem(series) if err != nil { return nil, errors.Trace(err) } cmds, err := shutdownInitCommands(initSystem, series) if err != nil { return nil, errors.Trace(err) } config.AddScripts(strings.Join(cmds, "\n")) data, err := config.RenderYAML() if err != nil { return nil, err } return data, nil }