func ConfigureMachine(ctx environs.BootstrapContext, client ssh.Client, host string, machineConfig *cloudinit.MachineConfig) 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 := coreCloudinit.New() cloudcfg.SetAptUpdate(machineConfig.EnableOSRefreshUpdate) cloudcfg.SetAptUpgrade(machineConfig.EnableOSUpgrade) udata, err := cloudinit.NewUserdataConfig(machineConfig, cloudcfg) if err != nil { return err } if err := udata.ConfigureJuju(); err != nil { return err } configScript, err := sshinit.ConfigureScript(cloudcfg) if err != nil { return err } script := shell.DumpFileOnErrorScript(machineConfig.CloudInitOutputLog) + configScript return sshinit.RunConfigureScript(script, sshinit.ConfigureParams{ Host: "ubuntu@" + host, Client: client, Config: cloudcfg, ProgressWriter: ctx.GetStderr(), }) }
func (*scriptSuite) TestDumpFileOnErrorScript(c *gc.C) { tempdir := c.MkDir() filename := filepath.Join(tempdir, "log.txt") err := ioutil.WriteFile(filename, []byte("abc"), 0644) c.Assert(err, gc.IsNil) dumpScript := shell.DumpFileOnErrorScript(filename) c.Logf("%s", dumpScript) run := func(command string) (stdout, stderr string) { var stdoutBuf, stderrBuf bytes.Buffer cmd := exec.Command("/bin/bash", "-s") cmd.Stdin = strings.NewReader(dumpScript + command) cmd.Stdout = &stdoutBuf cmd.Stderr = &stderrBuf cmd.Run() return stdoutBuf.String(), stderrBuf.String() } stdout, stderr := run("exit 0") c.Assert(stdout, gc.Equals, "") c.Assert(stderr, gc.Equals, "") stdout, stderr = run("exit 1") c.Assert(stdout, gc.Equals, "") c.Assert(stderr, gc.Equals, "abc") err = os.Remove(filename) c.Assert(err, gc.IsNil) stdout, stderr = run("exit 1") c.Assert(stdout, gc.Equals, "") c.Assert(stderr, gc.Equals, "") }
// ProvisioningScript generates a bash script that can be // executed on a remote host to carry out the cloud-init // configuration. func ProvisioningScript(mcfg *cloudinit.MachineConfig) (string, error) { cloudcfg := coreCloudinit.New() cloudcfg.SetAptUpdate(mcfg.EnableOSRefreshUpdate) cloudcfg.SetAptUpgrade(mcfg.EnableOSUpgrade) udata, err := cloudinit.NewUserdataConfig(mcfg, 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 := sshinit.ConfigureScript(cloudcfg) 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(mcfg.CloudInitOutputLog)) // If something goes wrong, dump cloud-init-output.log to stderr. buf.WriteString(shell.DumpFileOnErrorScript(mcfg.CloudInitOutputLog)) buf.WriteString(configScript) return buf.String(), nil }
func (s *provisionerSuite) TestProvisioningScript(c *gc.C) { const series = "precise" const arch = "amd64" defer fakeSSH{ Series: series, Arch: arch, InitUbuntuUser: true, }.install(c).Restore() machineId, err := manual.ProvisionMachine(s.getArgs(c)) c.Assert(err, gc.IsNil) mcfg, err := client.MachineConfig(s.State, machineId, agent.BootstrapNonce, "/var/lib/juju") c.Assert(err, gc.IsNil) script, err := manual.ProvisioningScript(mcfg) c.Assert(err, gc.IsNil) cloudcfg := coreCloudinit.New() err = cloudinit.ConfigureJuju(mcfg, cloudcfg) c.Assert(err, gc.IsNil) cloudcfg.SetAptUpgrade(false) sshinitScript, err := sshinit.ConfigureScript(cloudcfg) c.Assert(err, gc.IsNil) removeLogFile := "rm -f '/var/log/cloud-init-output.log'\n" expectedScript := removeLogFile + shell.DumpFileOnErrorScript("/var/log/cloud-init-output.log") + sshinitScript c.Assert(script, gc.Equals, expectedScript) }
func (*scriptSuite) TestDumpFileOnErrorScriptOutput(c *gc.C) { script := shell.DumpFileOnErrorScript("a b c") c.Assert(script, gc.Equals, ` dump_file() { code=$? if [ $code -ne 0 -a -e 'a b c' ]; then cat 'a b c' >&2 fi exit $code } trap dump_file EXIT `[1:]) }
// ProvisioningScript generates a bash script that can be // executed on a remote host to carry out the cloud-init // configuration. func ProvisioningScript(mcfg *cloudinit.MachineConfig) (string, error) { cloudcfg := coreCloudinit.New() if err := cloudinit.ConfigureJuju(mcfg, cloudcfg); err != nil { return "", err } // Explicitly disabling apt_upgrade so as not to trample // the target machine's existing configuration. cloudcfg.SetAptUpgrade(false) configScript, err := sshinit.ConfigureScript(cloudcfg) if err != nil { return "", err } 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(mcfg.CloudInitOutputLog)) // If something goes wrong, dump cloud-init-output.log to stderr. buf.WriteString(shell.DumpFileOnErrorScript(mcfg.CloudInitOutputLog)) buf.WriteString(configScript) return buf.String(), nil }
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 *provisionerSuite) TestProvisioningScript(c *gc.C) { const series = coretesting.FakeDefaultSeries const arch = "amd64" defer fakeSSH{ Series: series, Arch: arch, InitUbuntuUser: true, }.install(c).Restore() machineId, err := manual.ProvisionMachine(s.getArgs(c)) c.Assert(err, gc.IsNil) err = s.State.UpdateEnvironConfig( map[string]interface{}{ "enable-os-upgrade": false, }, nil, nil) c.Assert(err, gc.IsNil) mcfg, err := client.MachineConfig(s.State, machineId, agent.BootstrapNonce, "/var/lib/juju") c.Assert(err, gc.IsNil) script, err := manual.ProvisioningScript(mcfg) c.Assert(err, gc.IsNil) cloudcfg := coreCloudinit.New() udata, err := cloudinit.NewUserdataConfig(mcfg, cloudcfg) c.Assert(err, gc.IsNil) err = udata.ConfigureJuju() c.Assert(err, gc.IsNil) cloudcfg.SetAptUpgrade(false) sshinitScript, err := sshinit.ConfigureScript(cloudcfg) c.Assert(err, gc.IsNil) removeLogFile := "rm -f '/var/log/cloud-init-output.log'\n" expectedScript := removeLogFile + shell.DumpFileOnErrorScript("/var/log/cloud-init-output.log") + sshinitScript c.Assert(script, gc.Equals, expectedScript) }
} // 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 := coreCloudinit.New() if err := cloudinit.ConfigureJuju(machineConfig, cloudcfg); err != nil { return err } configScript, err := sshinit.ConfigureScript(cloudcfg) if err != nil { return err } script := shell.DumpFileOnErrorScript(machineConfig.CloudInitOutputLog) + configScript return sshinit.RunConfigureScript(script, sshinit.ConfigureParams{ Host: "ubuntu@" + addr, Client: client, Config: cloudcfg, ProgressWriter: ctx.GetStderr(), }) } type addresser interface { // Refresh refreshes the addresses for the instance. Refresh() error // Addresses returns the addresses for the instance. // To ensure that the results are up to date, call // Refresh first.
if err != nil { return errors.Trace(err) } if err := udata.ConfigureJuju(); err != nil { return errors.Trace(err) } return executeCloudConfig(ctx, icfg, cloudcfg) } var executeCloudConfig = func(ctx environs.BootstrapContext, icfg *instancecfg.InstanceConfig, cloudcfg cloudinit.CloudConfig) error { // Finally, convert cloud-config to a script and execute it. configScript, err := cloudcfg.RenderScript() if err != nil { return nil } script := shell.DumpFileOnErrorScript(icfg.CloudInitOutputLog) + configScript cmd := exec.Command("sudo", "/bin/bash", "-s") cmd.Stdin = strings.NewReader(script) cmd.Stdout = ctx.GetStdout() cmd.Stderr = ctx.GetStderr() return cmd.Run() } // StateServerInstances is specified in the Environ interface. func (env *localEnviron) StateServerInstances() ([]instance.Id, error) { agentsDir := filepath.Join(env.config.rootDir(), "agents") _, err := os.Stat(agentsDir) if os.IsNotExist(err) { return nil, environs.ErrNotBootstrapped } if err != nil {