// RunConfigureScript connects to the specified host over // SSH, and executes the provided script which is expected // to have been returned by cloudinit ConfigureScript. func RunConfigureScript(script string, params ConfigureParams) error { logger.Tracef("Running script on %s: %s", params.Host, script) encoded := base64.StdEncoding.EncodeToString([]byte(` set -e tmpfile=$(mktemp) trap "rm -f $tmpfile" EXIT cat > $tmpfile /bin/bash $tmpfile `)) // bash will read a byte at a time when consuming commands // from stdin. We avoid sending the entire script -- which // will be very large when uploading tools -- directly to // bash for this reason. Instead, run cat which will write // the script to disk, and then execute it from there. cmd := ssh.Command(params.Host, []string{ "sudo", "/bin/bash", "-c", // The outer bash interprets the $(...), and executes // the decoded script in the nested bash. This avoids // linebreaks in the commandline, which the go.crypto- // based client has trouble with. fmt.Sprintf( `/bin/bash -c "$(echo %s | base64 -d)"`, utils.ShQuote(encoded), ), }, nil) cmd.Stdin = strings.NewReader(script) cmd.Stderr = params.ProgressWriter return cmd.Run() }
// Run resolves c.Target to a machine, to the address of a i // machine or unit forks ssh passing any arguments provided. func (c *sshCommand) Run(ctx *cmd.Context) error { if c.apiClient == nil { // If the apClient is not already opened and it is opened // by ensureAPIClient, then close it when we're done. defer func() { if c.apiClient != nil { c.apiClient.Close() c.apiClient = nil } }() } options, err := c.getSSHOptions(c.pty) if err != nil { return err } user, host, err := c.userHostFromTarget(c.Target) if err != nil { return err } cmd := ssh.Command(user+"@"+host, c.Args, options) cmd.Stdin = ctx.Stdin cmd.Stdout = ctx.Stdout cmd.Stderr = ctx.Stderr return cmd.Run() }
// RunConfigureScript connects to the specified host over // SSH, and executes the provided script which is expected // to have been returned by cloudinit ConfigureScript. func RunConfigureScript(script string, params ConfigureParams) error { logger.Tracef("Running script on %s: %s", params.Host, script) cmd := ssh.Command(params.Host, []string{"sudo", "/bin/bash"}, nil) cmd.Stdin = strings.NewReader(script) cmd.Stderr = params.ProgressWriter return cmd.Run() }
func checkProvisioned(host string) (bool, error) { logger.Infof("Checking if %s is already provisioned", host) script := service.ListServicesScript() cmd := ssh.Command("ubuntu@"+host, []string{"/bin/bash"}, nil) var stdout, stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr cmd.Stdin = strings.NewReader(script) if err := cmd.Run(); err != nil { if stderr.Len() != 0 { err = fmt.Errorf("%v (%v)", err, strings.TrimSpace(stderr.String())) } return false, err } output := strings.TrimSpace(stdout.String()) provisioned := strings.Contains(output, "juju") if provisioned { logger.Infof("%s is already provisioned [%q]", host, output) } else { logger.Infof("%s is not provisioned", host) } return provisioned, nil }
func detectSeriesAndHardwareCharacteristics(host string) (hc instance.HardwareCharacteristics, series string, err error) { logger.Infof("Detecting series and characteristics on %s", host) cmd := ssh.Command("ubuntu@"+host, []string{"/bin/bash"}, nil) var stdout, stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr cmd.Stdin = bytes.NewBufferString(detectionScript) if err := cmd.Run(); err != nil { if stderr.Len() != 0 { err = fmt.Errorf("%v (%v)", err, strings.TrimSpace(stderr.String())) } return hc, "", err } lines := strings.Split(stdout.String(), "\n") series = strings.TrimSpace(lines[0]) arch := arch.NormaliseArch(lines[1]) hc.Arch = &arch // HardwareCharacteristics wants memory in megabytes, // meminfo reports it in kilobytes. memkB := strings.Fields(lines[2])[1] // "MemTotal: NNN kB" hc.Mem = new(uint64) *hc.Mem, err = strconv.ParseUint(memkB, 10, 0) *hc.Mem /= 1024 // For each "physical id", count the number of cores. // This way we only count physical cores, not additional // logical cores due to hyperthreading. recorded := make(map[string]bool) var physicalId string hc.CpuCores = new(uint64) for _, line := range lines[3:] { if strings.HasPrefix(line, "physical id") { physicalId = strings.TrimSpace(strings.SplitN(line, ":", 2)[1]) } else if strings.HasPrefix(line, "cpu cores") { var cores uint64 value := strings.TrimSpace(strings.SplitN(line, ":", 2)[1]) if cores, err = strconv.ParseUint(value, 10, 0); err != nil { return hc, "", err } if !recorded[physicalId] { *hc.CpuCores += cores recorded[physicalId] = true } } } if *hc.CpuCores == 0 { // In the case of a single-core, non-HT CPU, we'll see no // "physical id" or "cpu cores" lines. *hc.CpuCores = 1 } // TODO(axw) calculate CpuPower. What algorithm do we use? logger.Infof("series: %s, characteristics: %s", series, hc) return hc, series, nil }
// InitUbuntuUser adds the ubuntu user if it doesn't // already exist, updates its ~/.ssh/authorized_keys, // and enables passwordless sudo for it. // // InitUbuntuUser will initially attempt to login as // the ubuntu user, and verify that passwordless sudo // is enabled; only if this is false will there be an // attempt with the specified login. // // authorizedKeys may be empty, in which case the file // will be created and left empty. // // stdin and stdout will be used for remote sudo prompts, // if the ubuntu user must be created/updated. func InitUbuntuUser(host, login, authorizedKeys string, stdin io.Reader, stdout io.Writer) error { logger.Infof("initialising %q, user %q", host, login) // To avoid unnecessary prompting for the specified login, // initUbuntuUser will first attempt to ssh to the machine // as "ubuntu" with password authentication disabled, and // ensure that it can use sudo without a password. // // Note that we explicitly do not allocate a PTY, so we // get a failure if sudo prompts. cmd := ssh.Command("ubuntu@"+host, []string{"sudo", "-n", "true"}, nil) if cmd.Run() == nil { logger.Infof("ubuntu user is already initialised") return nil } // Failed to login as ubuntu (or passwordless sudo is not enabled). // Use specified login, and execute the initUbuntuScript below. if login != "" { host = login + "@" + host } script := fmt.Sprintf(initUbuntuScript, utils.ShQuote(authorizedKeys)) var options ssh.Options options.AllowPasswordAuthentication() options.EnablePTY() cmd = ssh.Command(host, []string{"sudo", "/bin/bash -c " + utils.ShQuote(script)}, &options) var stderr bytes.Buffer cmd.Stdin = stdin cmd.Stdout = stdout // for sudo prompt cmd.Stderr = &stderr if err := cmd.Run(); err != nil { if stderr.Len() != 0 { err = fmt.Errorf("%v (%v)", err, strings.TrimSpace(stderr.String())) } return err } return nil }
func (r *RestoreSuite) TestRunViaSSH(c *gc.C) { var ( passedAddress string passedArgs []string ) fakeSSHCommand := func(address string, args []string, options *ssh.Options) *ssh.Cmd { passedAddress = address passedArgs = args return ssh.Command("", []string{"ls"}, &ssh.Options{}) } r.PatchValue(&sshCommand, fakeSSHCommand) runViaSSH("invalidAddress", "invalidScript") c.Assert(passedAddress, gc.Equals, "ubuntu@invalidAddress") c.Assert(passedArgs, gc.DeepEquals, []string{"sudo", "-n", "bash", "-c 'invalidScript'"}) }
// Run resolves c.Target to a machine, to the address of a i // machine or unit forks ssh passing any arguments provided. func (c *sshCommand) Run(ctx *cmd.Context) error { err := c.initRun() if err != nil { return errors.Trace(err) } defer c.cleanupRun() target, err := c.resolveTarget(c.Target) if err != nil { return err } options, err := c.getSSHOptions(c.pty, target) if err != nil { return err } cmd := ssh.Command(target.userHost(), c.Args, options) cmd.Stdin = ctx.Stdin cmd.Stdout = ctx.Stdout cmd.Stderr = ctx.Stderr return cmd.Run() }
for i, id := range ids { if id == BootstrapInstanceId { instances[i] = manualBootstrapInstance{e.host} found = true } else { err = environs.ErrPartialInstances } } if !found { err = environs.ErrNoInstances } return instances, err } var runSSHCommand = func(host string, command []string, stdin string) (stdout, stderr string, err error) { cmd := ssh.Command(host, command, nil) cmd.Stdin = strings.NewReader(stdin) var stdoutBuf, stderrBuf bytes.Buffer cmd.Stdout = &stdoutBuf cmd.Stderr = &stderrBuf if err := cmd.Run(); err != nil { if stderr := strings.TrimSpace(stderrBuf.String()); len(stderr) > 0 { err = errors.Annotate(err, stderr) } return "", "", err } return stdoutBuf.String(), stderrBuf.String(), nil } // Destroy implements the Environ interface. func (e *manualEnviron) Destroy() error {