// Run executes the Packer build step that uploads a GCE machine image. func (s *StepUploadImage) Run(state multistep.StateBag) multistep.StepAction { comm := state.Get("communicator").(packer.Communicator) config := state.Get("config").(*Config) imageFilename := state.Get("image_file_name").(string) ui := state.Get("ui").(packer.Ui) sudoPrefix := "" if config.SSHUsername != "root" { sudoPrefix = "sudo " } ui.Say("Uploading image...") cmd := new(packer.RemoteCmd) cmd.Command = fmt.Sprintf("%s/usr/local/bin/gsutil cp %s gs://%s", sudoPrefix, imageFilename, config.BucketName) err := cmd.StartWithUi(comm, ui) if err == nil && cmd.ExitStatus != 0 { err = fmt.Errorf( "gsutil exited with non-zero exit status: %d", cmd.ExitStatus) } if err != nil { err := fmt.Errorf("Error uploading image: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } return multistep.ActionContinue }
func (c *comm) Start(cmd *packer.RemoteCmd) (err error) { username := c.config.Username password := c.config.Password remoteHostUrl := c.config.RemoteHostUrl driver := c.config.Driver var blockBuffer bytes.Buffer blockBuffer.WriteString("Invoke-Command -scriptblock { ") blockBuffer.WriteString("$uri = '" + remoteHostUrl + "';") blockBuffer.WriteString("$username = '******';") blockBuffer.WriteString("$password = '******';") blockBuffer.WriteString("$secPassword = ConvertTo-SecureString $password -AsPlainText -Force;") blockBuffer.WriteString("$credential = New-Object -typename System.Management.Automation.PSCredential -argumentlist $username, $secPassword;") blockBuffer.WriteString("$opt = New-PSSessionOption -OperationTimeout 540000;") blockBuffer.WriteString("$sess = New-PSSession -ConnectionUri $uri -Credential $credential -SessionOption $opt;") blockBuffer.WriteString("Invoke-Command -Session $sess ") blockBuffer.WriteString(cmd.Command) blockBuffer.WriteString("; Remove-PSSession -session $sess;") blockBuffer.WriteString("}") var cmdCopy packer.RemoteCmd cmdCopy.Stdout = cmd.Stdout cmdCopy.Stderr = cmd.Stderr cmdCopy.Command = blockBuffer.String() err = driver.ExecRemote(&cmdCopy) return }
func runCommand(shell *winrm.Shell, cmd *winrm.Command, rc *packer.RemoteCmd) { defer shell.Close() var wg sync.WaitGroup copyFunc := func(w io.Writer, r io.Reader) { defer wg.Done() io.Copy(w, r) } if rc.Stdout != nil && cmd.Stdout != nil { wg.Add(1) go copyFunc(rc.Stdout, cmd.Stdout) } else { log.Printf("[WARN] Failed to read stdout for command '%s'", rc.Command) } if rc.Stderr != nil && cmd.Stderr != nil { wg.Add(1) go copyFunc(rc.Stderr, cmd.Stderr) } else { log.Printf("[WARN] Failed to read stderr for command '%s'", rc.Command) } cmd.Wait() wg.Wait() code := cmd.ExitCode() log.Printf("[INFO] command '%s' exited with code: %d", rc.Command, code) rc.SetExited(code) }
func TestStart(t *testing.T) { clientConfig := &ssh.ClientConfig{ User: "******", Auth: []ssh.ClientAuth{ ssh.ClientAuthPassword(password("pass")), }, } conn := func() (net.Conn, error) { conn, err := net.Dial("tcp", newMockLineServer(t)) if err != nil { t.Fatalf("unable to dial to remote side: %s", err) } return conn, err } config := &Config{ Connection: conn, SSHConfig: clientConfig, } client, err := New(config) if err != nil { t.Fatalf("error connecting to SSH: %s", err) } var cmd packer.RemoteCmd stdout := new(bytes.Buffer) cmd.Command = "echo foo" cmd.Stdout = stdout client.Start(&cmd) }
func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { p.cancelLock.Lock() p.cancel = make(chan struct{}) p.cancelLock.Unlock() ui.Say("Restarting Machine") p.comm = comm p.ui = ui var cmd *packer.RemoteCmd command := p.config.RestartCommand err := p.retryable(func() error { cmd = &packer.RemoteCmd{Command: command} return cmd.StartWithUi(comm, ui) }) if err != nil { return err } if cmd.ExitStatus != 0 { return fmt.Errorf("Restart script exited with non-zero exit status: %d", cmd.ExitStatus) } return waitForRestart(p, comm) }
func (c *Communicator) Start(cmd *packer.RemoteCmd) error { localCmd := exec.Command("sh", "-c", cmd.Command) localCmd.Stdin = cmd.Stdin localCmd.Stdout = cmd.Stdout localCmd.Stderr = cmd.Stderr // Start it. If it doesn't work, then error right away. if err := localCmd.Start(); err != nil { return err } // We've started successfully. Start a goroutine to wait for // it to complete and track exit status. go func() { var exitStatus int err := localCmd.Wait() if err != nil { if exitErr, ok := err.(*exec.ExitError); ok { exitStatus = 1 // There is no process-independent way to get the REAL // exit status so we just try to go deeper. if status, ok := exitErr.Sys().(syscall.WaitStatus); ok { exitStatus = status.ExitStatus() } } } cmd.SetExited(exitStatus) }() return nil }
func TestStart(t *testing.T) { wrm := newMockWinRMServer(t) defer wrm.Close() c, err := New(&Config{ Host: wrm.Host, Port: wrm.Port, Username: "******", Password: "******", Timeout: 30 * time.Second, }) if err != nil { t.Fatalf("error creating communicator: %s", err) } var cmd packer.RemoteCmd stdout := new(bytes.Buffer) cmd.Command = "echo foo" cmd.Stdout = stdout err = c.Start(&cmd) if err != nil { t.Fatalf("error executing remote command: %s", err) } cmd.Wait() if stdout.String() != "foo" { t.Fatalf("bad command response: expected %q, got %q", "foo", stdout.String()) } }
// Run executes the Packer build step that creates a GCE machine image. // // Currently the only way to create a GCE image is to run the gcimagebundle // command on the running GCE instance. func (s *StepCreateImage) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*Config) comm := state.Get("communicator").(packer.Communicator) ui := state.Get("ui").(packer.Ui) sudoPrefix := "" if config.SSHUsername != "root" { sudoPrefix = "sudo " } imageFilename := fmt.Sprintf("%s.tar.gz", config.ImageName) imageBundleCmd := "/usr/bin/gcimagebundle -d /dev/sda -o /tmp/" ui.Say("Creating image...") cmd := new(packer.RemoteCmd) cmd.Command = fmt.Sprintf("%s%s --output_file_name %s", sudoPrefix, imageBundleCmd, imageFilename) err := cmd.StartWithUi(comm, ui) if err == nil && cmd.ExitStatus != 0 { err = fmt.Errorf( "gcimagebundle exited with non-zero exit status: %d", cmd.ExitStatus) } if err != nil { err := fmt.Errorf("Error creating image: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } state.Put("image_file_name", filepath.Join("/tmp", imageFilename)) return multistep.ActionContinue }
// Run executes the Packer build step that updates the gsutil utility to the // latest version available. // // This step is required to prevent the image creation process from hanging; // the image creation process utilizes the gcimagebundle cli tool which will // prompt to update gsutil if a newer version is available. func (s *StepUpdateGsutil) Run(state multistep.StateBag) multistep.StepAction { comm := state.Get("communicator").(packer.Communicator) config := state.Get("config").(*Config) ui := state.Get("ui").(packer.Ui) sudoPrefix := "" if config.SSHUsername != "root" { sudoPrefix = "sudo " } gsutilUpdateCmd := "/usr/local/bin/gsutil update -n -f" cmd := new(packer.RemoteCmd) cmd.Command = fmt.Sprintf("%s%s", sudoPrefix, gsutilUpdateCmd) ui.Say("Updating gsutil...") err := cmd.StartWithUi(comm, ui) if err == nil && cmd.ExitStatus != 0 { err = fmt.Errorf( "gsutil update exited with non-zero exit status: %d", cmd.ExitStatus) } if err != nil { err := fmt.Errorf("Error updating gsutil: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } return multistep.ActionContinue }
func (c *CommunicatorServer) Start(args *CommunicatorStartArgs, reply *interface{}) (err error) { // Build the RemoteCmd on this side so that it all pipes over // to the remote side. var cmd packer.RemoteCmd cmd.Command = args.Command if args.StdinAddress != "" { stdinC, err := net.Dial("tcp", args.StdinAddress) if err != nil { return err } cmd.Stdin = stdinC } if args.StdoutAddress != "" { stdoutC, err := net.Dial("tcp", args.StdoutAddress) if err != nil { return err } cmd.Stdout = stdoutC } if args.StderrAddress != "" { stderrC, err := net.Dial("tcp", args.StderrAddress) if err != nil { return err } cmd.Stderr = stderrC } // Connect to the response address so we can write our result to it // when ready. responseC, err := net.Dial("tcp", args.ResponseAddress) if err != nil { return err } responseWriter := gob.NewEncoder(responseC) // Start the actual command err = c.c.Start(&cmd) // Start a goroutine to spin and wait for the process to actual // exit. When it does, report it back to caller... go func() { defer responseC.Close() for !cmd.Exited { time.Sleep(50 * time.Millisecond) } responseWriter.Encode(&CommandFinished{cmd.ExitStatus}) }() return }
func (s *StepBundleVolume) Run(state multistep.StateBag) multistep.StepAction { comm := state.Get("communicator").(packer.Communicator) config := state.Get("config").(*Config) instance := state.Get("instance").(*ec2.Instance) ui := state.Get("ui").(packer.Ui) x509RemoteCertPath := state.Get("x509RemoteCertPath").(string) x509RemoteKeyPath := state.Get("x509RemoteKeyPath").(string) // Bundle the volume var err error config.ctx.Data = bundleCmdData{ AccountId: config.AccountId, Architecture: *instance.Architecture, CertPath: x509RemoteCertPath, Destination: config.BundleDestination, KeyPath: x509RemoteKeyPath, Prefix: config.BundlePrefix, PrivatePath: config.X509UploadPath, } config.BundleVolCommand, err = interpolate.Render(config.BundleVolCommand, &config.ctx) if err != nil { err := fmt.Errorf("Error processing bundle volume command: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } ui.Say("Bundling the volume...") cmd := new(packer.RemoteCmd) cmd.Command = config.BundleVolCommand if s.Debug { ui.Say(fmt.Sprintf("Running: %s", config.BundleVolCommand)) } if err := cmd.StartWithUi(comm, ui); err != nil { state.Put("error", fmt.Errorf("Error bundling volume: %s", err)) ui.Error(state.Get("error").(error).Error()) return multistep.ActionHalt } if cmd.ExitStatus != 0 { state.Put("error", fmt.Errorf( "Volume bundling failed. Please see the output above for more\n"+ "details on what went wrong.\n\n"+ "One common cause for this error is ec2-bundle-vol not being\n"+ "available on the target instance.")) ui.Error(state.Get("error").(error).Error()) return multistep.ActionHalt } // Store the manifest path manifestName := config.BundlePrefix + ".manifest.xml" state.Put("manifest_name", manifestName) state.Put("manifest_path", fmt.Sprintf( "%s/%s", config.BundleDestination, manifestName)) return multistep.ActionContinue }
func runCommand(shell *winrm.Shell, cmd *winrm.Command, rc *packer.RemoteCmd) { defer shell.Close() go io.Copy(rc.Stdout, cmd.Stdout) go io.Copy(rc.Stderr, cmd.Stderr) cmd.Wait() rc.SetExited(cmd.ExitCode()) }
// Runs the given command and blocks until completion func (c *Communicator) run(cmd *exec.Cmd, remote *packer.RemoteCmd, stdin io.WriteCloser, stdout, stderr io.ReadCloser) { // For Docker, remote communication must be serialized since it // only supports single execution. c.lock.Lock() defer c.lock.Unlock() wg := sync.WaitGroup{} repeat := func(w io.Writer, r io.ReadCloser) { io.Copy(w, r) r.Close() wg.Done() } if remote.Stdout != nil { wg.Add(1) go repeat(remote.Stdout, stdout) } if remote.Stderr != nil { wg.Add(1) go repeat(remote.Stderr, stderr) } // Start the command log.Printf("Executing %s:", strings.Join(cmd.Args, " ")) if err := cmd.Start(); err != nil { log.Printf("Error executing: %s", err) remote.SetExited(254) return } var exitStatus int if remote.Stdin != nil { go func() { io.Copy(stdin, remote.Stdin) // close stdin to support commands that wait for stdin to be closed before exiting. stdin.Close() }() } wg.Wait() err := cmd.Wait() if exitErr, ok := err.(*exec.ExitError); ok { exitStatus = 1 // There is no process-independent way to get the REAL // exit status so we just try to go deeper. if status, ok := exitErr.Sys().(syscall.WaitStatus); ok { exitStatus = status.ExitStatus() } } // Set the exit status which triggers waiters remote.SetExited(exitStatus) }
func (c *comm) Start(cmd *packer.RemoteCmd) (err error) { session, err := c.newSession() if err != nil { return } // Setup our session session.Stdin = cmd.Stdin session.Stdout = cmd.Stdout session.Stderr = cmd.Stderr if c.config.Pty { // Request a PTY termModes := ssh.TerminalModes{ ssh.ECHO: 0, // do not echo ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud } if err = session.RequestPty("xterm", 40, 80, termModes); err != nil { return } } log.Printf("starting remote command: %s", cmd.Command) err = session.Start(cmd.Command + "\n") if err != nil { return } // Start a goroutine to wait for the session to end and set the // exit boolean and status. go func() { defer session.Close() err := session.Wait() exitStatus := 0 if err != nil { switch err.(type) { case *ssh.ExitError: exitStatus = err.(*ssh.ExitError).ExitStatus() log.Printf("Remote command exited with '%d': %s", exitStatus, cmd.Command) case *ssh.ExitMissingError: log.Printf("Remote command exited without exit status or exit signal.") exitStatus = -1 default: log.Printf("Error occurred waiting for ssh session: %s", err.Error()) exitStatus = -1 } } cmd.SetExited(exitStatus) }() return }
func runCommand(shell *winrm.Shell, cmd *winrm.Command, rc *packer.RemoteCmd) { defer shell.Close() go io.Copy(rc.Stdout, cmd.Stdout) go io.Copy(rc.Stderr, cmd.Stderr) cmd.Wait() code := cmd.ExitCode() log.Printf("[INFO] command '%s' exited with code: %d", rc.Command, code) rc.SetExited(code) }
func (s *StepBundleVolume) Run(state map[string]interface{}) multistep.StepAction { comm := state["communicator"].(packer.Communicator) config := state["config"].(*Config) instance := state["instance"].(*ec2.Instance) ui := state["ui"].(packer.Ui) x509RemoteCertPath := state["x509RemoteCertPath"].(string) x509RemoteKeyPath := state["x509RemoteKeyPath"].(string) // Bundle the volume var err error config.BundleVolCommand, err = config.tpl.Process(config.BundleVolCommand, bundleCmdData{ AccountId: config.AccountId, Architecture: instance.Architecture, CertPath: x509RemoteCertPath, Destination: config.BundleDestination, KeyPath: x509RemoteKeyPath, Prefix: config.BundlePrefix, PrivatePath: config.X509UploadPath, }) if err != nil { err := fmt.Errorf("Error processing bundle volume command: %s", err) state["error"] = err ui.Error(err.Error()) return multistep.ActionHalt } ui.Say("Bundling the volume...") cmd := new(packer.RemoteCmd) cmd.Command = config.BundleVolCommand if err := cmd.StartWithUi(comm, ui); err != nil { state["error"] = fmt.Errorf("Error bundling volume: %s", err) ui.Error(state["error"].(error).Error()) return multistep.ActionHalt } if cmd.ExitStatus != 0 { state["error"] = fmt.Errorf( "Volume bundling failed. Please see the output above for more\n" + "details on what went wrong.") ui.Error(state["error"].(error).Error()) return multistep.ActionHalt } // Store the manifest path manifestName := config.BundlePrefix + ".manifest.xml" state["manifest_name"] = manifestName state["manifest_path"] = fmt.Sprintf( "%s/%s", config.BundleDestination, manifestName) return multistep.ActionContinue }
func (c *communicator) Start(cmd *packer.RemoteCmd) (err error) { var args CommunicatorStartArgs args.Command = cmd.Command if cmd.Stdin != nil { stdinL := netListenerInRange(portRangeMin, portRangeMax) args.StdinAddress = stdinL.Addr().String() go serveSingleCopy("stdin", stdinL, nil, cmd.Stdin) } if cmd.Stdout != nil { stdoutL := netListenerInRange(portRangeMin, portRangeMax) args.StdoutAddress = stdoutL.Addr().String() go serveSingleCopy("stdout", stdoutL, cmd.Stdout, nil) } if cmd.Stderr != nil { stderrL := netListenerInRange(portRangeMin, portRangeMax) args.StderrAddress = stderrL.Addr().String() go serveSingleCopy("stderr", stderrL, cmd.Stderr, nil) } responseL := netListenerInRange(portRangeMin, portRangeMax) args.ResponseAddress = responseL.Addr().String() go func() { defer responseL.Close() conn, err := responseL.Accept() if err != nil { log.Panic(err) } defer conn.Close() decoder := gob.NewDecoder(conn) var finished CommandFinished if err := decoder.Decode(&finished); err != nil { log.Panic(err) } cmd.ExitStatus = finished.ExitStatus cmd.Exited = true }() err = c.client.Call("Communicator.Start", &args, new(interface{})) return }
func (c *comm) Start(cmd *packer.RemoteCmd) (err error) { session, err := c.newSession() if err != nil { return } // Setup our session session.Stdin = cmd.Stdin session.Stdout = cmd.Stdout session.Stderr = cmd.Stderr // Request a PTY termModes := ssh.TerminalModes{ ssh.ECHO: 0, // do not echo ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud } if err = session.RequestPty("xterm", 80, 40, termModes); err != nil { return } log.Printf("starting remote command: %s", cmd.Command) err = session.Start(cmd.Command + "\n") if err != nil { return } // Start a goroutine to wait for the session to end and set the // exit boolean and status. go func() { defer session.Close() err := session.Wait() exitStatus := 0 if err != nil { exitErr, ok := err.(*ssh.ExitError) if ok { exitStatus = exitErr.ExitStatus() } } log.Printf("remote command exited with '%d': %s", exitStatus, cmd.Command) cmd.SetExited(exitStatus) }() return }
func (c *Communicator) Start(cmd *packer.RemoteCmd) error { // Render the template so that we know how to execute the command c.Ctx.Data = &ExecuteCommandTemplate{ Command: cmd.Command, } for i, field := range c.ExecuteCommand { command, err := interpolate.Render(field, &c.Ctx) if err != nil { return fmt.Errorf("Error processing command: %s", err) } c.ExecuteCommand[i] = command } // Build the local command to execute localCmd := exec.Command(c.ExecuteCommand[0], c.ExecuteCommand[1:]...) localCmd.Stdin = cmd.Stdin localCmd.Stdout = cmd.Stdout localCmd.Stderr = cmd.Stderr // Start it. If it doesn't work, then error right away. if err := localCmd.Start(); err != nil { return err } // We've started successfully. Start a goroutine to wait for // it to complete and track exit status. go func() { var exitStatus int err := localCmd.Wait() if err != nil { if exitErr, ok := err.(*exec.ExitError); ok { exitStatus = 1 // There is no process-independent way to get the REAL // exit status so we just try to go deeper. if status, ok := exitErr.Sys().(syscall.WaitStatus); ok { exitStatus = status.ExitStatus() } } } cmd.SetExited(exitStatus) }() return nil }
func runCommand(shell *winrm.Shell, cmd *winrm.Command, rc *packer.RemoteCmd) { defer shell.Close() if rc.Stdout != nil && cmd.Stdout != nil { go io.Copy(rc.Stdout, cmd.Stdout) } else { log.Printf("[WARN] Failed to read stdout for command '%s'", rc.Command) } if rc.Stderr != nil && cmd.Stderr != nil { go io.Copy(rc.Stderr, cmd.Stderr) } else { log.Printf("[WARN] Failed to read stderr for command '%s'", rc.Command) } cmd.Wait() code := cmd.ExitCode() log.Printf("[INFO] command '%s' exited with code: %d", rc.Command, code) rc.SetExited(code) }
func CreateRemoteDirectory(path string, comm packer.Communicator) (err error) { log.Printf("Creating remote directory: %s ", path) var copyCommand = []string{"mkdir -p", path} var cmd packer.RemoteCmd cmd.Command = strings.Join(copyCommand, " ") var stdout bytes.Buffer cmd.Stdout = &stdout // Start the command if err := comm.Start(&cmd); err != nil { return fmt.Errorf("Unable to create remote directory %s: %d", path, err) } // Wait for it to complete cmd.Wait() return }
func (s *StepExecuteOnlineActivation) Run(state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) comm := state.Get("communicator").(packer.Communicator) errorMsg := "Error Executing Online Activation: %s" var remoteCmd packer.RemoteCmd stdout := new(bytes.Buffer) stderr := new(bytes.Buffer) var err error ui.Say("Executing Online Activation...") var blockBuffer bytes.Buffer blockBuffer.WriteString("{ cscript \"$env:SystemRoot/system32/slmgr.vbs\" -ato //nologo }") remoteCmd.Command = "-ScriptBlock " + blockBuffer.String() remoteCmd.Stdout = stdout remoteCmd.Stderr = stderr err = comm.Start(&remoteCmd) stderrString := strings.TrimSpace(stderr.String()) stdoutString := strings.TrimSpace(stdout.String()) log.Printf("stdout: %s", stdoutString) log.Printf("stderr: %s", stderrString) if len(stderrString) > 0 { err = fmt.Errorf(errorMsg, stderrString) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } ui.Say(stdoutString) return multistep.ActionContinue }
func TestStart(t *testing.T) { // This test hits an already running Windows VM // You can comment this line out temporarily during development t.Skip() comm, err := New(&winrm.Endpoint{"localhost", 5985}, "vagrant", "vagrant", time.Duration(1)*time.Minute) if err != nil { t.Fatalf("error connecting to WinRM: %s", err) } var cmd packer.RemoteCmd var outWriter, errWriter bytes.Buffer cmd.Command = "dir" cmd.Stdout = &outWriter cmd.Stderr = &errWriter err = comm.Start(&cmd) if err != nil { t.Fatalf("error starting cmd: %s", err) } cmd.Wait() fmt.Println(outWriter.String()) fmt.Println(errWriter.String()) if err != nil { t.Fatalf("error running cmd: %s", err) } if cmd.ExitStatus != 0 { t.Fatalf("exit status was non-zero: %d", cmd.ExitStatus) } }
func executeCommand(command string, comm packer.Communicator) (err error) { // Setup the remote command stdout_r, stdout_w := io.Pipe() stderr_r, stderr_w := io.Pipe() var cmd packer.RemoteCmd cmd.Command = command cmd.Stdout = stdout_w cmd.Stderr = stderr_w log.Printf("Executing command: %s", cmd.Command) err = comm.Start(&cmd) if err != nil { return fmt.Errorf("Failed executing command: %s", err) } exitChan := make(chan int, 1) stdoutChan := iochan.DelimReader(stdout_r, '\n') stderrChan := iochan.DelimReader(stderr_r, '\n') go func() { defer stdout_w.Close() defer stderr_w.Close() cmd.Wait() exitChan <- cmd.ExitStatus }() OutputLoop: for { select { case output := <-stderrChan: Ui.Message(strings.TrimSpace(output)) case output := <-stdoutChan: Ui.Message(strings.TrimSpace(output)) case exitStatus := <-exitChan: log.Printf("Puppet provisioner exited with status %d", exitStatus) if exitStatus != 0 { return fmt.Errorf("Command exited with non-zero exit status: %d", exitStatus) } break OutputLoop } } // Make sure we finish off stdout/stderr because we may have gotten // a message from the exit channel first. for output := range stdoutChan { Ui.Message(output) } for output := range stderrChan { Ui.Message(output) } return nil }
func (c *Communicator) Start(cmd *packer.RemoteCmd) error { command, err := c.CmdWrapper( fmt.Sprintf("sudo chroot %s '%s'", c.Chroot, cmd.Command)) if err != nil { return err } localCmd := ShellCommand(command) localCmd.Stdin = cmd.Stdin localCmd.Stdout = cmd.Stdout localCmd.Stderr = cmd.Stderr log.Printf("Executing: %s %#v", localCmd.Path, localCmd.Args) if err := localCmd.Start(); err != nil { return err } go func() { exitStatus := 0 if err := localCmd.Wait(); err != nil { if exitErr, ok := err.(*exec.ExitError); ok { exitStatus = 1 // There is no process-independent way to get the REAL // exit status so we just try to go deeper. if status, ok := exitErr.Sys().(syscall.WaitStatus); ok { exitStatus = status.ExitStatus() } } } log.Printf( "Chroot executation exited with '%d': '%s'", exitStatus, cmd.Command) cmd.SetExited(exitStatus) }() return nil }
func (c *LxcAttachCommunicator) Start(cmd *packer.RemoteCmd) error { localCmd, err := c.Execute(cmd.Command) if err != nil { return err } localCmd.Stdin = cmd.Stdin localCmd.Stdout = cmd.Stdout localCmd.Stderr = cmd.Stderr if err := localCmd.Start(); err != nil { return err } go func() { exitStatus := 0 if err := localCmd.Wait(); err != nil { if exitErr, ok := err.(*exec.ExitError); ok { exitStatus = 1 // There is no process-independent way to get the REAL // exit status so we just try to go deeper. if status, ok := exitErr.Sys().(syscall.WaitStatus); ok { exitStatus = status.ExitStatus() } } } log.Printf( "lxc-attach execution exited with '%d': '%s'", exitStatus, cmd.Command) cmd.SetExited(exitStatus) }() return nil }
func (c *communicator) Start(cmd *packer.RemoteCmd) (err error) { var args CommunicatorStartArgs args.Command = cmd.Command if cmd.Stdin != nil { args.StdinStreamId = c.mux.NextId() go serveSingleCopy("stdin", c.mux, args.StdinStreamId, nil, cmd.Stdin) } if cmd.Stdout != nil { args.StdoutStreamId = c.mux.NextId() go serveSingleCopy("stdout", c.mux, args.StdoutStreamId, cmd.Stdout, nil) } if cmd.Stderr != nil { args.StderrStreamId = c.mux.NextId() go serveSingleCopy("stderr", c.mux, args.StderrStreamId, cmd.Stderr, nil) } responseStreamId := c.mux.NextId() args.ResponseStreamId = responseStreamId go func() { conn, err := c.mux.Accept(responseStreamId) if err != nil { log.Printf("[ERR] Error accepting response stream %d: %s", responseStreamId, err) cmd.SetExited(123) return } defer conn.Close() var finished CommandFinished decoder := gob.NewDecoder(conn) if err := decoder.Decode(&finished); err != nil { log.Printf("[ERR] Error decoding response stream %d: %s", responseStreamId, err) cmd.SetExited(123) return } log.Printf("[INFO] RPC client: Communicator ended with: %d", finished.ExitStatus) cmd.SetExited(finished.ExitStatus) }() err = c.client.Call("Communicator.Start", &args, new(interface{})) return }
// // WinRMRunCmd runs a command on a Windows Server. Uses WinRM, which // should be enabled on the target server // // Parameters: // host: target Windows server host // username: username for the host // password: password for the host // command: command to run // Returns: // string: stdout from command execution // error: errors from establishing connection and copying the file // int: exit status from the command being run // func WinRMRunCmd(host string, username string, password string, command string) (string, error, int) { log.Debug("Connecting to ", username, "@", password, ":", host, " running command ", command) c, err := winrm.New(&winrm.Config{ Host: host, Port: 5985, Username: username, Password: password, Timeout: 30 * time.Second, }) if err != nil { return "", err, 1 } var cmd packer.RemoteCmd stdout := new(bytes.Buffer) stderr := new(bytes.Buffer) cmd.Command = command cmd.Stdout = stdout cmd.Stderr = stderr err = c.Start(&cmd) if err != nil { return "", err, 1 } cmd.Wait() // after waiting for command to complete execition, retrieve exit status exit := cmd.ExitStatus log.Debug("stdout:", stdout, "stderr:", stderr, "exit:", exit) var returnerr error if stderr.String() == "" { returnerr = nil } else { returnerr = errors.New(stderr.String()) } return stdout.String(), returnerr, exit }
func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { scripts := make([]string, len(p.config.Scripts)) copy(scripts, p.config.Scripts) // If we have an inline script, then turn that into a temporary // shell script and use that. if p.config.Inline != nil { tf, err := ioutil.TempFile("", "packer-shell") if err != nil { return fmt.Errorf("Error preparing shell script: %s", err) } defer os.Remove(tf.Name()) // Set the path to the temporary file scripts = append(scripts, tf.Name()) // Write our contents to it writer := bufio.NewWriter(tf) writer.WriteString(fmt.Sprintf("#!%s\n", p.config.InlineShebang)) for _, command := range p.config.Inline { if _, err := writer.WriteString(command + "\n"); err != nil { return fmt.Errorf("Error preparing shell script: %s", err) } } if err := writer.Flush(); err != nil { return fmt.Errorf("Error preparing shell script: %s", err) } tf.Close() } for _, path := range scripts { ui.Say(fmt.Sprintf("Provisioning with shell script: %s", path)) log.Printf("Opening %s for reading", path) f, err := os.Open(path) if err != nil { return fmt.Errorf("Error opening shell script: %s", err) } defer f.Close() log.Printf("Uploading %s => %s", path, p.config.RemotePath) err = comm.Upload(p.config.RemotePath, f) if err != nil { return fmt.Errorf("Error uploading shell script: %s", err) } // Close the original file since we copied it f.Close() // Flatten the environment variables flattendVars := strings.Join(p.config.Vars, " ") // Compile the command var command bytes.Buffer t := template.Must(template.New("command").Parse(p.config.ExecuteCommand)) t.Execute(&command, &ExecuteCommandTemplate{flattendVars, p.config.RemotePath}) // Setup the remote command stdout_r, stdout_w := io.Pipe() stderr_r, stderr_w := io.Pipe() var cmd packer.RemoteCmd cmd.Command = command.String() cmd.Stdout = stdout_w cmd.Stderr = stderr_w log.Printf("Executing command: %s", cmd.Command) err = comm.Start(&cmd) if err != nil { return fmt.Errorf("Failed executing command: %s", err) } exitChan := make(chan int, 1) stdoutChan := iochan.DelimReader(stdout_r, '\n') stderrChan := iochan.DelimReader(stderr_r, '\n') go func() { defer stdout_w.Close() defer stderr_w.Close() cmd.Wait() exitChan <- cmd.ExitStatus }() OutputLoop: for { select { case output := <-stderrChan: ui.Message(strings.TrimSpace(output)) case output := <-stdoutChan: ui.Message(strings.TrimSpace(output)) case exitStatus := <-exitChan: log.Printf("shell provisioner exited with status %d", exitStatus) if exitStatus != 0 { return fmt.Errorf("Script exited with non-zero exit status: %d", exitStatus) } break OutputLoop } } // Make sure we finish off stdout/stderr because we may have gotten // a message from the exit channel first. for output := range stdoutChan { ui.Message(output) } for output := range stderrChan { ui.Message(output) } } return nil }
func (c *CommunicatorServer) Start(args *CommunicatorStartArgs, reply *interface{}) error { // Build the RemoteCmd on this side so that it all pipes over // to the remote side. var cmd packer.RemoteCmd cmd.Command = args.Command // Create a channel to signal we're done so that we can close // our stdin/stdout/stderr streams toClose := make([]io.Closer, 0) doneCh := make(chan struct{}) go func() { <-doneCh for _, conn := range toClose { defer conn.Close() } }() if args.StdinStreamId > 0 { conn, err := c.mux.Dial(args.StdinStreamId) if err != nil { close(doneCh) return NewBasicError(err) } toClose = append(toClose, conn) cmd.Stdin = conn } if args.StdoutStreamId > 0 { conn, err := c.mux.Dial(args.StdoutStreamId) if err != nil { close(doneCh) return NewBasicError(err) } toClose = append(toClose, conn) cmd.Stdout = conn } if args.StderrStreamId > 0 { conn, err := c.mux.Dial(args.StderrStreamId) if err != nil { close(doneCh) return NewBasicError(err) } toClose = append(toClose, conn) cmd.Stderr = conn } // Connect to the response address so we can write our result to it // when ready. responseC, err := c.mux.Dial(args.ResponseStreamId) if err != nil { close(doneCh) return NewBasicError(err) } responseWriter := gob.NewEncoder(responseC) // Start the actual command err = c.c.Start(&cmd) if err != nil { close(doneCh) return NewBasicError(err) } // Start a goroutine to spin and wait for the process to actual // exit. When it does, report it back to caller... go func() { defer close(doneCh) defer responseC.Close() cmd.Wait() log.Printf("[INFO] RPC endpoint: Communicator ended with: %d", cmd.ExitStatus) responseWriter.Encode(&CommandFinished{cmd.ExitStatus}) }() return nil }