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) } }
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 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 }
// // 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 }
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) } }
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 }
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") }
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 }
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 }