示例#1
0
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 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)
	}
}
示例#3
0
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
}
示例#4
0
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 (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
}
示例#6
0
//
// 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
}
示例#7
0
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
}
示例#8
0
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
}
示例#9
0
func TestCommunicatorRPC(t *testing.T) {
	// Create the interface to test
	c := new(packer.MockCommunicator)

	// Start the server
	server := rpc.NewServer()
	RegisterCommunicator(server, c)
	address := serveSingleConn(server)

	// Create the client over RPC and run some methods to verify it works
	client, err := rpc.Dial("tcp", address)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	remote := Communicator(client)

	// The remote command we'll use
	stdin_r, stdin_w := io.Pipe()
	stdout_r, stdout_w := io.Pipe()
	stderr_r, stderr_w := io.Pipe()

	var cmd packer.RemoteCmd
	cmd.Command = "foo"
	cmd.Stdin = stdin_r
	cmd.Stdout = stdout_w
	cmd.Stderr = stderr_w

	// Send some data on stdout and stderr from the mock
	c.StartStdout = "outfoo\n"
	c.StartStderr = "errfoo\n"
	c.StartExitStatus = 42

	// Test Start
	err = remote.Start(&cmd)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	// Test that we can read from stdout
	bufOut := bufio.NewReader(stdout_r)
	data, err := bufOut.ReadString('\n')
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if data != "outfoo\n" {
		t.Fatalf("bad data: %s", data)
	}

	// Test that we can read from stderr
	bufErr := bufio.NewReader(stderr_r)
	data, err = bufErr.ReadString('\n')
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if data != "errfoo\n" {
		t.Fatalf("bad data: %s", data)
	}

	// Test that we can write to stdin
	stdin_w.Write([]byte("info\n"))
	stdin_w.Close()
	cmd.Wait()
	if c.StartStdin != "info\n" {
		t.Fatalf("bad data: %s", data)
	}

	// Test that we can get the exit status properly
	if cmd.ExitStatus != 42 {
		t.Fatalf("bad exit: %d", cmd.ExitStatus)
	}

	// Test that we can upload things
	uploadR, uploadW := io.Pipe()
	go func() {
		defer uploadW.Close()
		uploadW.Write([]byte("uploadfoo\n"))
	}()
	err = remote.Upload("foo", uploadR)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if !c.UploadCalled {
		t.Fatal("should have uploaded")
	}

	if c.UploadPath != "foo" {
		t.Fatalf("path: %s", c.UploadPath)
	}

	if c.UploadData != "uploadfoo\n" {
		t.Fatalf("bad: %s", c.UploadData)
	}

	// Test that we can upload directories
	dirDst := "foo"
	dirSrc := "bar"
	dirExcl := []string{"foo"}
	err = remote.UploadDir(dirDst, dirSrc, dirExcl)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if c.UploadDirDst != dirDst {
		t.Fatalf("bad: %s", c.UploadDirDst)
	}

	if c.UploadDirSrc != dirSrc {
		t.Fatalf("bad: %s", c.UploadDirSrc)
	}

	if !reflect.DeepEqual(c.UploadDirExclude, dirExcl) {
		t.Fatalf("bad: %#v", c.UploadDirExclude)
	}

	// Test that we can download things
	downloadR, downloadW := io.Pipe()
	downloadDone := make(chan bool)
	var downloadData string
	var downloadErr error

	go func() {
		bufDownR := bufio.NewReader(downloadR)
		downloadData, downloadErr = bufDownR.ReadString('\n')
		downloadDone <- true
	}()

	c.DownloadData = "download\n"
	err = remote.Download("bar", downloadW)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if !c.DownloadCalled {
		t.Fatal("download should be called")
	}

	if c.DownloadPath != "bar" {
		t.Fatalf("bad: %s", c.DownloadPath)
	}

	<-downloadDone
	if downloadErr != nil {
		t.Fatalf("err: %s", downloadErr)
	}

	if downloadData != "download\n" {
		t.Fatalf("bad: %s", downloadData)
	}
}
示例#10
0
func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {

	var err error
	errorMsg := "Provision error: %s"

	ui.Say("Provision...")

	if len(p.config.DistrSrcPath) != 0 {
		err = comm.UploadDir(p.config.DistrDstPath, p.config.DistrSrcPath, nil)
		if err != nil {
			return err
		}
	}

	if p.config.Inline != nil {

		var blockBuffer bytes.Buffer
		blockBuffer.WriteString("{")
		for _, command := range p.config.Inline {
			blockBuffer.WriteString(command + ";")
		}
		blockBuffer.WriteString("}")

		var stdoutBuff bytes.Buffer
		var stderrBuff bytes.Buffer
		var cmd packer.RemoteCmd
		cmd.Stdout = &stdoutBuff
		cmd.Stderr = &stderrBuff

		cmd.Command = "-ScriptBlock " + blockBuffer.String()

		err = comm.Start(&cmd)
		if err != nil {
			err = fmt.Errorf(errorMsg, err)
		}

		stderrString := stderrBuff.String()
		if len(stderrString) > 0 {
			err = fmt.Errorf(errorMsg, stderrString)
			log.Printf("Provision Inline stderr: %s", stderrString)
		}

		stdoutString := stdoutBuff.String()
		if len(stdoutString) > 0 {
			log.Printf("Provision Inline stdout: %s", stdoutString)
			ui.Message(stdoutString)
		}
	}

	if len(p.config.ScriptPath) != 0 {
		var stdoutBuff bytes.Buffer
		var stderrBuff bytes.Buffer
		var cmd packer.RemoteCmd
		cmd.Stdout = &stdoutBuff
		cmd.Stderr = &stderrBuff
		cmd.Command = "-filepath " + filepath.FromSlash(p.config.ScriptPath)

		err = comm.Start(&cmd)
		if err != nil {
			err = fmt.Errorf(errorMsg, err)
		}

		stderrString := stderrBuff.String()
		if len(stderrString) > 0 {
			err = fmt.Errorf(errorMsg, stderrString)
			log.Printf("Provision from file stderr: %s", stderrString)
		}

		stdoutString := stdoutBuff.String()
		if len(stdoutString) > 0 {
			log.Printf("Provision from file stdout: %s", stdoutString)
			ui.Message(stdoutString)
		}
	}

	return err
}
示例#11
0
func TestCommunicatorRPC(t *testing.T) {
	assert := asserts.NewTestingAsserts(t, true)

	// Create the interface to test
	c := new(testCommunicator)

	// Start the server
	server := rpc.NewServer()
	RegisterCommunicator(server, c)
	address := serveSingleConn(server)

	// Create the client over RPC and run some methods to verify it works
	client, err := rpc.Dial("tcp", address)
	assert.Nil(err, "should be able to connect")
	remote := Communicator(client)

	// The remote command we'll use
	stdin_r, stdin_w := io.Pipe()
	stdout_r, stdout_w := io.Pipe()
	stderr_r, stderr_w := io.Pipe()

	var cmd packer.RemoteCmd
	cmd.Command = "foo"
	cmd.Stdin = stdin_r
	cmd.Stdout = stdout_w
	cmd.Stderr = stderr_w

	// Test Start
	err = remote.Start(&cmd)
	assert.Nil(err, "should not have an error")

	// Test that we can read from stdout
	c.startCmd.Stdout.Write([]byte("outfoo\n"))
	bufOut := bufio.NewReader(stdout_r)
	data, err := bufOut.ReadString('\n')
	assert.Nil(err, "should have no problem reading stdout")
	assert.Equal(data, "outfoo\n", "should be correct stdout")

	// Test that we can read from stderr
	c.startCmd.Stderr.Write([]byte("errfoo\n"))
	bufErr := bufio.NewReader(stderr_r)
	data, err = bufErr.ReadString('\n')
	assert.Nil(err, "should have no problem reading stderr")
	assert.Equal(data, "errfoo\n", "should be correct stderr")

	// Test that we can write to stdin
	stdin_w.Write([]byte("infoo\n"))
	bufIn := bufio.NewReader(c.startCmd.Stdin)
	data, err = bufIn.ReadString('\n')
	assert.Nil(err, "should have no problem reading stdin")
	assert.Equal(data, "infoo\n", "should be correct stdin")

	// Test that we can get the exit status properly
	c.startCmd.ExitStatus = 42
	c.startCmd.Exited = true

	for i := 0; i < 5; i++ {
		if cmd.Exited {
			assert.Equal(cmd.ExitStatus, 42, "should have proper exit status")
			break
		}

		time.Sleep(50 * time.Millisecond)
	}

	assert.True(cmd.Exited, "should have exited")

	// Test that we can upload things
	uploadR, uploadW := io.Pipe()
	go uploadW.Write([]byte("uploadfoo\n"))
	err = remote.Upload("foo", uploadR)
	assert.Nil(err, "should not error")
	assert.True(c.uploadCalled, "should be called")
	assert.Equal(c.uploadPath, "foo", "should be correct path")
	assert.Equal(c.uploadData, "uploadfoo\n", "should have the proper data")

	// Test that we can download things
	downloadR, downloadW := io.Pipe()
	downloadDone := make(chan bool)
	var downloadData string
	var downloadErr error

	go func() {
		bufDownR := bufio.NewReader(downloadR)
		downloadData, downloadErr = bufDownR.ReadString('\n')
		downloadDone <- true
	}()

	err = remote.Download("bar", downloadW)
	assert.Nil(err, "should not error")
	assert.True(c.downloadCalled, "should have called download")
	assert.Equal(c.downloadPath, "bar", "should have correct download path")

	<-downloadDone
	assert.Nil(downloadErr, "should not error reading download data")
	assert.Equal(downloadData, "download\n", "should have the proper data")
}
示例#12
0
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

	toClose := make([]net.Conn, 0)
	if args.StdinAddress != "" {
		stdinC, err := tcpDial(args.StdinAddress)
		if err != nil {
			return err
		}

		toClose = append(toClose, stdinC)
		cmd.Stdin = stdinC
	}

	if args.StdoutAddress != "" {
		stdoutC, err := tcpDial(args.StdoutAddress)
		if err != nil {
			return err
		}

		toClose = append(toClose, stdoutC)
		cmd.Stdout = stdoutC
	}

	if args.StderrAddress != "" {
		stderrC, err := tcpDial(args.StderrAddress)
		if err != nil {
			return err
		}

		toClose = append(toClose, stderrC)
		cmd.Stderr = stderrC
	}

	// Connect to the response address so we can write our result to it
	// when ready.
	responseC, err := tcpDial(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 _, conn := range toClose {
			defer conn.Close()
		}

		cmd.Wait()
		responseWriter.Encode(&CommandFinished{cmd.ExitStatus})
	}()

	return
}
func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {

	var err error
	errorMsg := "Provision error: %s"

	if len(p.config.DistrSrcPath) != 0 {
		err = comm.UploadDir(p.config.DistrDstPath, p.config.DistrSrcPath, nil)
		if err != nil {
			return err
		}
	}

	// check the remote connection is ready
	{
		var cmd packer.RemoteCmd
		stdout := new(bytes.Buffer)
		stderr := new(bytes.Buffer)

		magicWord := "ready"

		var blockBuffer bytes.Buffer
		blockBuffer.WriteString("{ Write-Host '" + magicWord + "' }")

		cmd.Command = "-ScriptBlock " + blockBuffer.String()
		cmd.Stdout = stdout
		cmd.Stderr = stderr

		count := 5
		var duration time.Duration = 1
		sleepTime := time.Minute * duration

		ui.Say("Checking PS remouting is ready...")

		for count > 0 {
			err = comm.Start(&cmd)
			if err != nil {
				return err
			}

			stderrString := strings.TrimSpace(stderr.String())
			stdoutString := strings.TrimSpace(stdout.String())

			log.Printf("stdout: %s", stdoutString)
			log.Printf("stderr: %s", stderrString)

			if stdoutString == magicWord {
				break
			}

			log.Println(fmt.Sprintf("Waiting %v minutes for the remote connection to get ready...", uint(duration)))
			time.Sleep(sleepTime)
			count--
		}

		if count == 0 {
			err := fmt.Errorf(errorMsg, "Remote connection failed")
			return err
		}
	}

	if p.config.Inline != nil {
		var cmd packer.RemoteCmd
		stdout := new(bytes.Buffer)
		stderr := new(bytes.Buffer)

		var blockBuffer bytes.Buffer
		blockBuffer.WriteString("{")
		for _, command := range p.config.Inline {
			blockBuffer.WriteString(command + ";")
		}
		blockBuffer.WriteString("}")

		cmd.Command = "-ScriptBlock " + blockBuffer.String()
		cmd.Stdout = stdout
		cmd.Stderr = stderr

		err = comm.Start(&cmd)

		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("Provision error: %s", stderrString)
		}

		ui.Say(stdoutString)
	}

	if len(p.config.ScriptPath) != 0 {
		var cmd packer.RemoteCmd
		stdout := new(bytes.Buffer)
		stderr := new(bytes.Buffer)

		cmd.Command = "-filepath " + filepath.FromSlash(p.config.ScriptPath)
		cmd.Stdout = stdout
		cmd.Stderr = stderr

		err = comm.Start(&cmd)

		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("Provision error: %s", stderrString)
		}

		ui.Say(stdoutString)
	}

	return err
}
func (s *StepCheckRemoting) Run(state multistep.StateBag) multistep.StepAction {
	ui := state.Get("ui").(packer.Ui)
	comm := state.Get("communicator").(packer.Communicator)

	var err error
	errorMsg := "Error step CheckRemoting: %s"

	// check the remote connection is ready
	{
		var cmd packer.RemoteCmd
		stdout := new(bytes.Buffer)
		stderr := new(bytes.Buffer)

		magicWord := "ready"

		var blockBuffer bytes.Buffer
		blockBuffer.WriteString("{ Write-Host '" + magicWord + "' }")

		cmd.Command = "-ScriptBlock " + blockBuffer.String()
		cmd.Stdout = stdout
		cmd.Stderr = stderr

		count := 5
		var duration time.Duration = 1
		sleepTime := time.Minute * duration

		ui.Say("Checking PS remoting is ready...")

		for count > 0 {
			err = comm.Start(&cmd)
			if err != nil {
				err := fmt.Errorf(errorMsg, "Remote connection failed")
				state.Put("error", err)
				ui.Error(err.Error())
				return multistep.ActionHalt
			}

			stderrString := strings.TrimSpace(stderr.String())
			stdoutString := strings.TrimSpace(stdout.String())

			log.Printf("stdout: %s", stdoutString)
			log.Printf("stderr: %s", stderrString)

			if stdoutString == magicWord {
				break
			}

			log.Println(fmt.Sprintf("Waiting %v minutes for the remote connection to get ready...", uint(duration)))
			time.Sleep(sleepTime)
			count--
		}

		if count == 0 {
			err := fmt.Errorf(errorMsg, "Remote connection failed")
			state.Put("error", err)
			ui.Error(err.Error())
			return multistep.ActionHalt
		}
	}

	return multistep.ActionContinue
}
示例#15
0
func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {

	var err error
	errorMsg := "Error preparing shell script, %s error: %s"

	ui.Say("Provisioning...")

	if len(p.config.DistrSrcPath) != 0 {
		err = comm.UploadDir("skiped param", p.config.DistrSrcPath, nil)
		if err != nil {
			return err
		}
	}

	tempDir := os.TempDir()
	packerTempDir, err := ioutil.TempDir(tempDir, "packer_script")
	if err != nil {
		err := fmt.Errorf("Error creating temporary directory: %s", err.Error())
		return err
	}

	// create a temporary script file and upload it to Azure storage
	ui.Message("Preparing execution script...")
	provisionFileName := fmt.Sprintf("provision-%s.ps1", uuid.New())

	scriptPath := filepath.Join(packerTempDir, provisionFileName)
	tf, err := os.Create(scriptPath)

	if err != nil {
		return fmt.Errorf(errorMsg, "os.Create", err.Error())
	}

	defer os.RemoveAll(packerTempDir)

	writer := bufio.NewWriter(tf)

	if p.config.Inline != nil {
		log.Println("Writing inline commands to execution script...")

		// Write our contents to it
		for _, command := range p.config.Inline {
			log.Println(command)
			if _, err := writer.WriteString(command + ";\n"); err != nil {
				return fmt.Errorf(errorMsg, "writer.WriteString", err.Error())
			}
		}
	}

	// add content to the temp script file
	if len(p.config.ScriptPath) != 0 {
		log.Println("Writing file commands to execution script...")

		f, err := os.Open(p.config.ScriptPath)
		if err != nil {
			return fmt.Errorf(errorMsg, "os.Open", err.Error())
		}
		defer f.Close()

		scanner := bufio.NewScanner(f)
		for scanner.Scan() {
			log.Println(scanner.Text())
			if _, err := writer.WriteString(scanner.Text() + "\n"); err != nil {
				return fmt.Errorf(errorMsg, "writer.WriteString", err.Error())
			}
		}

		if err := scanner.Err(); err != nil {
			return fmt.Errorf(errorMsg, "scanner.Scan", err.Error())
		}
	}

	log.Println("Writing SysPrep to execution script...")
	sysprepPs := []string{
		"Write-Host 'Executing Sysprep from File...'",
		"Start-Process $env:windir\\System32\\Sysprep\\sysprep.exe -NoNewWindow -Wait -Argument '/quiet /generalize /oobe /quit'",
		"Write-Host 'Sysprep is done!'",
	}

	for _, command := range sysprepPs {
		log.Println(command)
		if _, err := writer.WriteString(command + ";\n"); err != nil {
			return fmt.Errorf(errorMsg, "writer.WriteString", err.Error())
		}
	}

	if err := writer.Flush(); err != nil {
		return fmt.Errorf("Error preparing shell script: %s", err.Error())
	}

	tf.Close()

	// upload to Azure storage
	ui.Message("Uploading execution script...")
	err = comm.UploadDir("skiped param", scriptPath, nil)
	if err != nil {
		return err
	}

	// execute script with Custom script extension
	runScript := provisionFileName

	var stdoutBuff bytes.Buffer
	var stderrBuff bytes.Buffer
	var cmd packer.RemoteCmd
	cmd.Stdout = &stdoutBuff
	cmd.Stderr = &stderrBuff

	cmd.Command = runScript

	ui.Message("Starting provisioning. It may take some time...")
	err = comm.Start(&cmd)
	if err != nil {
		err = fmt.Errorf(errorMsg, "comm.Start", err.Error())
		return err
	}

	ui.Message("Provision is Completed")

	stderrString := stderrBuff.String()
	if len(stderrString) > 0 {
		err = fmt.Errorf(errorMsg, "stderrString", stderrString)
		log.Printf("Provision stderr: %s", stderrString)
	}

	ui.Say("Script output")

	stdoutString := stdoutBuff.String()
	if len(stdoutString) > 0 {
		log.Printf("Provision stdout: %s", stdoutString)
		scriptMessages := strings.Split(stdoutString, "\\n")
		for _, m := range scriptMessages {
			ui.Message(m)
		}
	}

	return err
}