// TestCloudInitVerify checks that required fields are appropriately // checked for by NewCloudInit. func (*cloudinitSuite) TestCloudInitVerify(c *gc.C) { cfg := &instancecfg.InstanceConfig{ Bootstrap: true, StateServingInfo: stateServingInfo, MachineId: "99", Tools: newSimpleTools("9.9.9-quantal-arble"), AuthorizedKeys: "sshkey1", Series: "quantal", AgentEnvironment: map[string]string{agent.ProviderType: "dummy"}, MongoInfo: &mongo.MongoInfo{ Info: mongo.Info{ Addrs: []string{"host:98765"}, CACert: testing.CACert, }, Password: "******", }, APIInfo: &api.Info{ Addrs: []string{"host:9999"}, CACert: testing.CACert, ModelTag: testing.ModelTag, }, Config: minimalModelConfig(c), HostedModelConfig: map[string]interface{}{"name": "hosted-model"}, DataDir: jujuDataDir("quantal"), LogDir: jujuLogDir("quantal"), MetricsSpoolDir: metricsSpoolDir("quantal"), Jobs: normalMachineJobs, CloudInitOutputLog: cloudInitOutputLog("quantal"), InstanceId: "i-bootstrap", MachineNonce: "FAKE_NONCE", MachineAgentServiceName: "jujud-machine-99", } // check that the base configuration does not give an error ci, err := cloudinit.New("quantal") c.Assert(err, jc.ErrorIsNil) for i, test := range verifyTests { // check that the base configuration does not give an error // and that a previous test hasn't mutated it accidentially. udata, err := cloudconfig.NewUserdataConfig(cfg, ci) c.Assert(err, jc.ErrorIsNil) err = udata.Configure() c.Assert(err, jc.ErrorIsNil) c.Logf("test %d. %s", i, test.err) cfg1 := *cfg test.mutate(&cfg1) udata, err = cloudconfig.NewUserdataConfig(&cfg1, ci) c.Assert(err, jc.ErrorIsNil) err = udata.Configure() c.Check(err, gc.ErrorMatches, "invalid machine configuration: "+test.err) } }
// ProvisioningScript generates a bash script that can be // executed on a remote host to carry out the cloud-init // configuration. func ProvisioningScript(icfg *instancecfg.InstanceConfig) (string, error) { cloudcfg, err := cloudinit.New(icfg.Series) if err != nil { return "", errors.Annotate(err, "error generating cloud-config") } cloudcfg.SetSystemUpdate(icfg.EnableOSRefreshUpdate) cloudcfg.SetSystemUpgrade(icfg.EnableOSUpgrade) udata, err := cloudconfig.NewUserdataConfig(icfg, cloudcfg) if err != nil { return "", errors.Annotate(err, "error generating cloud-config") } if err := udata.ConfigureJuju(); err != nil { return "", errors.Annotate(err, "error generating cloud-config") } configScript, err := cloudcfg.RenderScript() if err != nil { return "", errors.Annotate(err, "error converting cloud-config to script") } var buf bytes.Buffer // Always remove the cloud-init-output.log file first, if it exists. fmt.Fprintf(&buf, "rm -f %s\n", utils.ShQuote(icfg.CloudInitOutputLog)) // If something goes wrong, dump cloud-init-output.log to stderr. buf.WriteString(shell.DumpFileOnErrorScript(icfg.CloudInitOutputLog)) buf.WriteString(configScript) return buf.String(), nil }
func CloudInitUserData( instanceConfig *instancecfg.InstanceConfig, networkConfig *container.NetworkConfig, ) ([]byte, error) { cloudConfig, err := newCloudInitConfigWithNetworks(instanceConfig.Series, networkConfig) if err != nil { return nil, errors.Trace(err) } udata, err := cloudconfig.NewUserdataConfig(instanceConfig, cloudConfig) if err != nil { return nil, errors.Trace(err) } if err = udata.Configure(); err != nil { return nil, errors.Trace(err) } // Run ifconfig to get the addresses of the internal container at least // logged in the host. cloudConfig.AddRunCmd("ifconfig") if instanceConfig.MachineContainerHostname != "" { cloudConfig.SetAttr("hostname", instanceConfig.MachineContainerHostname) } data, err := cloudConfig.RenderYAML() if err != nil { return nil, errors.Trace(err) } return data, nil }
func (s *CloudInitSuite) TestWindowsUserdataEncoding(c *gc.C) { series := "win8" metricsSpoolDir := must(paths.MetricsSpoolDir("win8")) toolsList := tools.List{ &tools.Tools{ URL: "http://foo.com/tools/released/juju1.2.3-win8-amd64.tgz", Version: version.MustParseBinary("1.2.3-win8-amd64"), Size: 10, SHA256: "1234", }, } dataDir, err := paths.DataDir(series) c.Assert(err, jc.ErrorIsNil) logDir, err := paths.LogDir(series) c.Assert(err, jc.ErrorIsNil) cfg := instancecfg.InstanceConfig{ ControllerTag: testing.ControllerTag, MachineId: "10", AgentEnvironment: map[string]string{agent.ProviderType: "dummy"}, Series: series, Jobs: []multiwatcher.MachineJob{multiwatcher.JobHostUnits}, MachineNonce: "FAKE_NONCE", APIInfo: &api.Info{ Addrs: []string{"state-addr.testing.invalid:54321"}, Password: "******", CACert: "CA CERT\n" + testing.CACert, Tag: names.NewMachineTag("10"), ModelTag: testing.ModelTag, }, MachineAgentServiceName: "jujud-machine-10", DataDir: dataDir, LogDir: path.Join(logDir, "juju"), MetricsSpoolDir: metricsSpoolDir, CloudInitOutputLog: path.Join(logDir, "cloud-init-output.log"), } err = cfg.SetTools(toolsList) c.Assert(err, jc.ErrorIsNil) ci, err := cloudinit.New("win8") c.Assert(err, jc.ErrorIsNil) udata, err := cloudconfig.NewUserdataConfig(&cfg, ci) c.Assert(err, jc.ErrorIsNil) err = udata.Configure() c.Assert(err, jc.ErrorIsNil) data, err := ci.RenderYAML() c.Assert(err, jc.ErrorIsNil) cicompose, err := cloudinit.New("win8") c.Assert(err, jc.ErrorIsNil) base64Data := base64.StdEncoding.EncodeToString(utils.Gzip(data)) got := []byte(fmt.Sprintf(cloudconfig.UserDataScript, base64Data)) expected, err := providerinit.ComposeUserData(&cfg, cicompose, openstack.OpenstackRenderer{}) c.Assert(err, jc.ErrorIsNil) c.Assert(string(got), gc.Equals, string(expected)) }
func (s *configureSuite) getCloudConfig(c *gc.C, stateServer bool, vers version.Binary) cloudinit.CloudConfig { var icfg *instancecfg.InstanceConfig var err error if stateServer { icfg, err = instancecfg.NewBootstrapInstanceConfig(constraints.Value{}, vers.Series) c.Assert(err, jc.ErrorIsNil) icfg.InstanceId = "instance-id" icfg.Jobs = []multiwatcher.MachineJob{multiwatcher.JobManageEnviron, multiwatcher.JobHostUnits} } else { icfg, err = instancecfg.NewInstanceConfig("0", "ya", imagemetadata.ReleasedStream, vers.Series, true, nil, nil, nil) c.Assert(err, jc.ErrorIsNil) icfg.Jobs = []multiwatcher.MachineJob{multiwatcher.JobHostUnits} } icfg.Tools = &tools.Tools{ Version: vers, URL: "http://testing.invalid/tools.tar.gz", } environConfig := testConfig(c, stateServer, vers) err = instancecfg.FinishInstanceConfig(icfg, environConfig) c.Assert(err, jc.ErrorIsNil) cloudcfg, err := cloudinit.New(icfg.Series) c.Assert(err, jc.ErrorIsNil) udata, err := cloudconfig.NewUserdataConfig(icfg, cloudcfg) c.Assert(err, jc.ErrorIsNil) err = udata.Configure() c.Assert(err, jc.ErrorIsNil) return cloudcfg }
func (*cloudinitSuite) TestWindowsCloudInit(c *gc.C) { for i, test := range windowsCloudinitTests { testConfig := test.cfg.render() c.Logf("test %d", i) ci, err := cloudinit.New("win8") c.Assert(err, jc.ErrorIsNil) udata, err := cloudconfig.NewUserdataConfig(&testConfig, ci) c.Assert(err, jc.ErrorIsNil) err = udata.Configure() c.Assert(err, jc.ErrorIsNil) c.Check(ci, gc.NotNil) data, err := ci.RenderYAML() c.Assert(err, jc.ErrorIsNil) stringData := strings.Replace(string(data), "\r\n", "\n", -1) stringData = strings.Replace(stringData, "\t", " ", -1) stringData = strings.TrimSpace(stringData) compareString := strings.Replace(string(test.expectScripts), "\r\n", "\n", -1) compareString = strings.Replace(compareString, "\t", " ", -1) compareString = strings.TrimSpace(compareString) testing.CheckString(c, stringData, compareString) } }
func (s *configureSuite) getCloudConfig(c *gc.C, controller bool, vers version.Binary) cloudinit.CloudConfig { var icfg *instancecfg.InstanceConfig var err error modelConfig := testConfig(c, controller, vers) if controller { icfg, err = instancecfg.NewBootstrapInstanceConfig( coretesting.FakeControllerConfig(), constraints.Value{}, constraints.Value{}, vers.Series, "", ) c.Assert(err, jc.ErrorIsNil) icfg.APIInfo = &api.Info{ Password: "******", CACert: coretesting.CACert, ModelTag: coretesting.ModelTag, } icfg.Controller.MongoInfo = &mongo.MongoInfo{ Password: "******", Info: mongo.Info{CACert: coretesting.CACert}, } icfg.Bootstrap.ControllerModelConfig = modelConfig icfg.Bootstrap.BootstrapMachineInstanceId = "instance-id" icfg.Bootstrap.HostedModelConfig = map[string]interface{}{ "name": "hosted-model", } icfg.Bootstrap.StateServingInfo = params.StateServingInfo{ Cert: coretesting.ServerCert, PrivateKey: coretesting.ServerKey, CAPrivateKey: coretesting.CAKey, StatePort: 123, APIPort: 456, } icfg.Jobs = []multiwatcher.MachineJob{multiwatcher.JobManageModel, multiwatcher.JobHostUnits} icfg.Bootstrap.StateServingInfo = params.StateServingInfo{ Cert: coretesting.ServerCert, PrivateKey: coretesting.ServerKey, CAPrivateKey: coretesting.CAKey, StatePort: 123, APIPort: 456, } } else { icfg, err = instancecfg.NewInstanceConfig(coretesting.ControllerTag, "0", "ya", imagemetadata.ReleasedStream, vers.Series, nil) c.Assert(err, jc.ErrorIsNil) icfg.Jobs = []multiwatcher.MachineJob{multiwatcher.JobHostUnits} } err = icfg.SetTools(tools.List{ &tools.Tools{ Version: vers, URL: "http://testing.invalid/tools.tar.gz", }, }) err = instancecfg.FinishInstanceConfig(icfg, modelConfig) c.Assert(err, jc.ErrorIsNil) cloudcfg, err := cloudinit.New(icfg.Series) c.Assert(err, jc.ErrorIsNil) udata, err := cloudconfig.NewUserdataConfig(icfg, cloudcfg) c.Assert(err, jc.ErrorIsNil) err = udata.Configure() c.Assert(err, jc.ErrorIsNil) return cloudcfg }
func (*cloudinitSuite) TestCloudInitConfigureBootstrapLogging(c *gc.C) { loggo.GetLogger("").SetLogLevel(loggo.INFO) envConfig := minimalEnvironConfig(c) instConfig := makeBootstrapConfig("quantal").maybeSetEnvironConfig(envConfig) rendered := instConfig.render() cloudcfg, err := cloudinit.New(rendered.Series) c.Assert(err, jc.ErrorIsNil) udata, err := cloudconfig.NewUserdataConfig(&rendered, cloudcfg) c.Assert(err, jc.ErrorIsNil) err = udata.Configure() c.Assert(err, jc.ErrorIsNil) data, err := cloudcfg.RenderYAML() c.Assert(err, jc.ErrorIsNil) configKeyValues := make(map[interface{}]interface{}) err = goyaml.Unmarshal(data, &configKeyValues) c.Assert(err, jc.ErrorIsNil) scripts := getScripts(configKeyValues) for i, script := range scripts { if strings.Contains(script, "bootstrap") { c.Logf("scripts[%d]: %q", i, script) } } expected := "jujud bootstrap-state --data-dir '.*' --env-config '.*'" + " --instance-id '.*' --bootstrap-constraints 'mem=4096M'" + " --environ-constraints 'mem=2048M' --show-log" assertScriptMatch(c, scripts, expected, false) }
// TestCloudInit checks that the output from the various tests // in cloudinitTests is well formed. func (*cloudinitSuite) TestCloudInit(c *gc.C) { for i, test := range cloudinitTests { c.Logf("test %d", i) var envConfig *config.Config if test.setEnvConfig { envConfig = minimalEnvironConfig(c) } testConfig := test.cfg.maybeSetEnvironConfig(envConfig).render() ci, err := cloudinit.New(testConfig.Series) c.Assert(err, jc.ErrorIsNil) udata, err := cloudconfig.NewUserdataConfig(&testConfig, ci) c.Assert(err, jc.ErrorIsNil) err = udata.Configure() c.Assert(err, jc.ErrorIsNil) c.Check(ci, gc.NotNil) // render the cloudinit config to bytes, and then // back to a map so we can introspect it without // worrying about internal details of the cloudinit // package. data, err := ci.RenderYAML() c.Assert(err, jc.ErrorIsNil) configKeyValues := make(map[interface{}]interface{}) err = goyaml.Unmarshal(data, &configKeyValues) c.Assert(err, jc.ErrorIsNil) if testConfig.EnableOSRefreshUpdate { c.Check(configKeyValues["package_update"], jc.IsTrue) } else { c.Check(configKeyValues["package_update"], jc.IsFalse) } if testConfig.EnableOSUpgrade { c.Check(configKeyValues["package_upgrade"], jc.IsTrue) } else { c.Check(configKeyValues["package_upgrade"], jc.IsFalse) } scripts := getScripts(configKeyValues) assertScriptMatch(c, scripts, test.expectScripts, !test.inexactMatch) if testConfig.Config != nil { checkEnvConfig(c, testConfig.Config, configKeyValues, scripts) } // curl should always be installed, since it's required by jujud. checkPackage(c, configKeyValues, "curl", true) tag := names.NewMachineTag(testConfig.MachineId).String() acfg := getAgentConfig(c, tag, scripts) c.Assert(acfg, jc.Contains, "AGENT_SERVICE_NAME: jujud-"+tag) c.Assert(acfg, jc.Contains, "upgradedToVersion: 1.2.3\n") source := "deb http://ubuntu-cloud.archive.canonical.com/ubuntu precise-updates/cloud-tools main" needCloudArchive := testConfig.Series == "precise" checkAptSource(c, configKeyValues, source, pacconf.UbuntuCloudArchiveSigningKey, needCloudArchive) } }
func (*cloudinitSuite) TestCloudInitConfigure(c *gc.C) { for i, test := range cloudinitTests { testConfig := test.cfg.maybeSetEnvironConfig(minimalEnvironConfig(c)).render() c.Logf("test %d (Configure)", i) cloudcfg, err := cloudinit.New(testConfig.Series) c.Assert(err, jc.ErrorIsNil) udata, err := cloudconfig.NewUserdataConfig(&testConfig, cloudcfg) c.Assert(err, jc.ErrorIsNil) err = udata.Configure() c.Assert(err, jc.ErrorIsNil) } }
func (s *cloudinitSuite) testAptMirror(c *gc.C, cfg *config.Config, expect string) { instanceCfg := s.createInstanceConfig(c, cfg) cloudcfg, err := cloudinit.New("quantal") c.Assert(err, jc.ErrorIsNil) udata, err := cloudconfig.NewUserdataConfig(instanceCfg, cloudcfg) c.Assert(err, jc.ErrorIsNil) err = udata.Configure() c.Assert(err, jc.ErrorIsNil) //mirror, ok := cloudcfg.AptMirror() mirror := cloudcfg.PackageMirror() c.Assert(mirror, gc.Equals, expect) //c.Assert(ok, gc.Equals, expect != "") }
func (s *cloudinitSuite) TestAptProxyNotWrittenIfNotSet(c *gc.C) { environConfig := minimalEnvironConfig(c) instanceCfg := s.createInstanceConfig(c, environConfig) cloudcfg, err := cloudinit.New("quantal") c.Assert(err, jc.ErrorIsNil) udata, err := cloudconfig.NewUserdataConfig(instanceCfg, cloudcfg) c.Assert(err, jc.ErrorIsNil) err = udata.Configure() c.Assert(err, jc.ErrorIsNil) cmds := cloudcfg.BootCmds() c.Assert(cmds, gc.IsNil) }
func (s *cloudinitSuite) TestAptProxyWritten(c *gc.C) { environConfig := minimalEnvironConfig(c) environConfig, err := environConfig.Apply(map[string]interface{}{ "apt-http-proxy": "http://[email protected]", }) c.Assert(err, jc.ErrorIsNil) instanceCfg := s.createInstanceConfig(c, environConfig) cloudcfg, err := cloudinit.New("quantal") c.Assert(err, jc.ErrorIsNil) udata, err := cloudconfig.NewUserdataConfig(instanceCfg, cloudcfg) c.Assert(err, jc.ErrorIsNil) err = udata.Configure() c.Assert(err, jc.ErrorIsNil) cmds := cloudcfg.BootCmds() expected := "printf '%s\\n' 'Acquire::http::Proxy \"http://[email protected]\";' > /etc/apt/apt.conf.d/42-juju-proxy-settings" c.Assert(cmds, jc.DeepEquals, []string{expected}) }
func configureCloudinit(icfg *instancecfg.InstanceConfig, cloudcfg cloudinit.CloudConfig) (cloudconfig.UserdataConfig, error) { // When bootstrapping, we only want to apt-get update/upgrade // and setup the SSH keys. The rest we leave to cloudinit/sshinit. udata, err := cloudconfig.NewUserdataConfig(icfg, cloudcfg) if err != nil { return nil, err } if icfg.Bootstrap != nil { err = udata.ConfigureBasic() if err != nil { return nil, err } return udata, nil } err = udata.Configure() if err != nil { return nil, err } return udata, nil }
func (*cloudinitSuite) TestCloudInitConfigureUsesGivenConfig(c *gc.C) { // Create a simple cloudinit config with a 'runcmd' statement. cloudcfg, err := cloudinit.New("quantal") c.Assert(err, jc.ErrorIsNil) script := "test script" cloudcfg.AddRunCmd(script) cloudinitTests[0].cfg.Config = minimalConfig(c) udata, err := cloudconfig.NewUserdataConfig(&cloudinitTests[0].cfg, cloudcfg) c.Assert(err, jc.ErrorIsNil) err = udata.Configure() c.Assert(err, jc.ErrorIsNil) data, err := cloudcfg.RenderYAML() c.Assert(err, jc.ErrorIsNil) ciContent := make(map[interface{}]interface{}) err = goyaml.Unmarshal(data, &ciContent) c.Assert(err, jc.ErrorIsNil) // The 'runcmd' statement is at the beginning of the list // of 'runcmd' statements. runCmd := ciContent["runcmd"].([]interface{}) c.Check(runCmd[0], gc.Equals, script) }
func (s *provisionerSuite) TestProvisioningScript(c *gc.C) { var series = series.LatestLts() const arch = "amd64" defer fakeSSH{ Series: series, Arch: arch, InitUbuntuUser: true, }.install(c).Restore() machineId, err := manual.ProvisionMachine(s.getArgs(c)) c.Assert(err, jc.ErrorIsNil) err = s.State.UpdateModelConfig( map[string]interface{}{ "enable-os-upgrade": false, }, nil, nil) c.Assert(err, jc.ErrorIsNil) icfg, err := client.InstanceConfig(s.State, machineId, agent.BootstrapNonce, "/var/lib/juju") c.Assert(err, jc.ErrorIsNil) script, err := manual.ProvisioningScript(icfg) c.Assert(err, jc.ErrorIsNil) cloudcfg, err := cloudinit.New(series) c.Assert(err, jc.ErrorIsNil) udata, err := cloudconfig.NewUserdataConfig(icfg, cloudcfg) c.Assert(err, jc.ErrorIsNil) err = udata.ConfigureJuju() c.Assert(err, jc.ErrorIsNil) cloudcfg.SetSystemUpgrade(false) provisioningScript, err := cloudcfg.RenderScript() c.Assert(err, jc.ErrorIsNil) removeLogFile := "rm -f '/var/log/cloud-init-output.log'\n" expectedScript := removeLogFile + shell.DumpFileOnErrorScript("/var/log/cloud-init-output.log") + provisioningScript c.Assert(script, gc.Equals, expectedScript) }
func (s *cloudinitSuite) TestProxyWritten(c *gc.C) { environConfig := minimalEnvironConfig(c) environConfig, err := environConfig.Apply(map[string]interface{}{ "http-proxy": "http://[email protected]", "no-proxy": "localhost,10.0.3.1", }) c.Assert(err, jc.ErrorIsNil) instanceCfg := s.createInstanceConfig(c, environConfig) cloudcfg, err := cloudinit.New("quantal") c.Assert(err, jc.ErrorIsNil) udata, err := cloudconfig.NewUserdataConfig(instanceCfg, cloudcfg) c.Assert(err, jc.ErrorIsNil) err = udata.Configure() c.Assert(err, jc.ErrorIsNil) cmds := cloudcfg.RunCmds() first := `([ ! -e /home/ubuntu/.profile ] || grep -q '.juju-proxy' /home/ubuntu/.profile) || printf '\n# Added by juju\n[ -f "$HOME/.juju-proxy" ] && . "$HOME/.juju-proxy"\n' >> /home/ubuntu/.profile` expected := []string{ `export http_proxy=http://[email protected]`, `export HTTP_PROXY=http://[email protected]`, `export no_proxy=localhost,10.0.3.1`, `export NO_PROXY=localhost,10.0.3.1`, `(id ubuntu &> /dev/null) && (printf '%s\n' 'export http_proxy=http://[email protected] export HTTP_PROXY=http://[email protected] export no_proxy=localhost,10.0.3.1 export NO_PROXY=localhost,10.0.3.1' > /home/ubuntu/.juju-proxy && chown ubuntu:ubuntu /home/ubuntu/.juju-proxy)`, } found := false for i, cmd := range cmds { if cmd == first { c.Assert(cmds[i+1:i+6], jc.DeepEquals, expected) found = true break } } c.Assert(found, jc.IsTrue) }
func ConfigureMachine(ctx environs.BootstrapContext, client ssh.Client, host string, instanceConfig *instancecfg.InstanceConfig) error { // Bootstrap is synchronous, and will spawn a subprocess // to complete the procedure. If the user hits Ctrl-C, // SIGINT is sent to the foreground process attached to // the terminal, which will be the ssh subprocess at this // point. For that reason, we do not call StopInterruptNotify // until this function completes. cloudcfg, err := cloudinit.New(instanceConfig.Series) if err != nil { return errors.Trace(err) } // Set packaging update here cloudcfg.SetSystemUpdate(instanceConfig.EnableOSRefreshUpdate) cloudcfg.SetSystemUpgrade(instanceConfig.EnableOSUpgrade) udata, err := cloudconfig.NewUserdataConfig(instanceConfig, cloudcfg) if err != nil { return err } if err := udata.ConfigureJuju(); err != nil { return err } configScript, err := cloudcfg.RenderScript() if err != nil { return err } script := shell.DumpFileOnErrorScript(instanceConfig.CloudInitOutputLog) + configScript return sshinit.RunConfigureScript(script, sshinit.ConfigureParams{ Host: "[email protected]" + host, Client: client, Config: cloudcfg, ProgressWriter: ctx.GetStderr(), Series: instanceConfig.Series, }) }
func checkCloudInitWithGUI(c *gc.C, cfg *testInstanceConfig, expectedScripts string, expectedError string) { envConfig := minimalModelConfig(c) testConfig := cfg.maybeSetModelConfig(envConfig).render() ci, err := cloudinit.New(testConfig.Series) c.Assert(err, jc.ErrorIsNil) udata, err := cloudconfig.NewUserdataConfig(&testConfig, ci) c.Assert(err, jc.ErrorIsNil) err = udata.Configure() if expectedError != "" { c.Assert(err, gc.ErrorMatches, expectedError) return } c.Assert(err, jc.ErrorIsNil) c.Check(ci, gc.NotNil) data, err := ci.RenderYAML() c.Assert(err, jc.ErrorIsNil) configKeyValues := make(map[interface{}]interface{}) err = goyaml.Unmarshal(data, &configKeyValues) c.Assert(err, jc.ErrorIsNil) scripts := getScripts(configKeyValues) assertScriptMatch(c, scripts, expectedScripts, false) }
// finishBootstrap converts the machine config to cloud-config, // converts that to a script, and then executes it locally. func (env *localEnviron) finishBootstrap(ctx environs.BootstrapContext, icfg *instancecfg.InstanceConfig) error { icfg.InstanceId = bootstrapInstanceId icfg.DataDir = env.config.rootDir() icfg.LogDir = fmt.Sprintf("/var/log/juju-%s", env.config.namespace()) icfg.CloudInitOutputLog = filepath.Join(icfg.DataDir, "cloud-init-output.log") // No JobManageNetworking added in order not to change the network // configuration of the user's machine. icfg.Jobs = []multiwatcher.MachineJob{multiwatcher.JobManageEnviron} icfg.MachineAgentServiceName = env.machineAgentServiceName() icfg.AgentEnvironment = map[string]string{ agent.Namespace: env.config.namespace(), agent.LxcBridge: env.config.networkBridge(), // The local provider only supports a single state server, // so we make the oplog size to a small value. This makes // the preallocation faster with no disadvantage. agent.MongoOplogSize: "1", // 1MB } if err := instancecfg.FinishInstanceConfig(icfg, env.Config()); err != nil { return errors.Trace(err) } // Since Juju's state machine is currently the host machine // for local providers, don't stomp on it. cfgAttrs := env.config.AllAttrs() if val, ok := cfgAttrs["enable-os-refresh-update"].(bool); !ok { logger.Infof("local provider; disabling refreshing OS updates.") icfg.EnableOSRefreshUpdate = false } else { icfg.EnableOSRefreshUpdate = val } if val, ok := cfgAttrs["enable-os-upgrade"].(bool); !ok { logger.Infof("local provider; disabling OS upgrades.") icfg.EnableOSUpgrade = false } else { icfg.EnableOSUpgrade = val } // don't write proxy or mirror settings for local machine icfg.AptProxySettings = proxy.Settings{} icfg.ProxySettings = proxy.Settings{} icfg.AptMirror = "" cloudcfg, err := cloudinit.New(icfg.Series) if err != nil { return errors.Trace(err) } cloudcfg.SetSystemUpdate(icfg.EnableOSRefreshUpdate) cloudcfg.SetSystemUpgrade(icfg.EnableOSUpgrade) localLogDir := filepath.Join(icfg.DataDir, "log") if err := os.RemoveAll(localLogDir); err != nil { return errors.Trace(err) } if err := symlink.New(icfg.LogDir, localLogDir); err != nil { return errors.Trace(err) } if err := os.Remove(icfg.CloudInitOutputLog); err != nil && !os.IsNotExist(err) { return errors.Trace(err) } cloudcfg.AddScripts( fmt.Sprintf("rm -fr %s", icfg.LogDir), ) udata, err := cloudconfig.NewUserdataConfig(icfg, cloudcfg) if err != nil { return errors.Trace(err) } if err := udata.ConfigureJuju(); err != nil { return errors.Trace(err) } return executeCloudConfig(ctx, icfg, cloudcfg) }