コード例 #1
0
// 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
}
コード例 #2
0
ファイル: communicator.go プロジェクト: paulmey/packer-azure
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
}
コード例 #3
0
ファイル: communicator.go プロジェクト: boumenot/packer
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)
}
コード例 #4
0
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)
}
コード例 #5
0
ファイル: provisioner.go プロジェクト: c12simple/packer
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)
}
コード例 #6
0
ファイル: communicator.go プロジェクト: eticzon/packer
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
}
コード例 #7
0
ファイル: communicator_test.go プロジェクト: c12simple/packer
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())
	}
}
コード例 #8
0
ファイル: step_create_image.go プロジェクト: Nitron/packer
// 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
}
コード例 #9
0
ファイル: step_update_gsutil.go プロジェクト: Nitron/packer
// 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
}
コード例 #10
0
ファイル: communicator.go プロジェクト: kyleconroy/packer
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
}
コード例 #11
0
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
}
コード例 #12
0
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())
}
コード例 #13
0
ファイル: communicator.go プロジェクト: rnaveiras/packer
// 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)
}
コード例 #14
0
ファイル: communicator.go プロジェクト: jtopper/packer
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
}
コード例 #15
0
ファイル: communicator.go プロジェクト: cewood/packer
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)
}
コード例 #16
0
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
}
コード例 #17
0
ファイル: communicator.go プロジェクト: kyleconroy/packer
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
}
コード例 #18
0
ファイル: communicator.go プロジェクト: phobos182/packer
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
}
コード例 #19
0
ファイル: communicator.go プロジェクト: metalmolly/packer
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
}
コード例 #20
0
ファイル: communicator.go プロジェクト: blairham/packer
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)
}
コード例 #21
0
ファイル: provisioner.go プロジェクト: jamtur01/packer
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
}
コード例 #23
0
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)
	}
}
コード例 #24
0
ファイル: provisioner.go プロジェクト: jamtur01/packer
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
}
コード例 #25
0
ファイル: communicator.go プロジェクト: rhass/packer
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
}
コード例 #26
0
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
}
コード例 #27
0
ファイル: communicator.go プロジェクト: c12simple/packer
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
}
コード例 #28
0
ファイル: utils.go プロジェクト: containerx/machine
//
// 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
}
コード例 #29
0
ファイル: provisioner.go プロジェクト: svenne/packer
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
}
コード例 #30
0
ファイル: communicator.go プロジェクト: c12simple/packer
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
}