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 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 (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 (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 (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() } // Build our variables up by adding in the build name and builder type envVars := make([]string, len(p.config.Vars)+2) envVars[0] = fmt.Sprintf("PACKER_BUILD_NAME='%s'", p.config.PackerBuildName) envVars[1] = fmt.Sprintf("PACKER_BUILDER_TYPE='%s'", p.config.PackerBuilderType) copy(envVars[2:], p.config.Vars) 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() // Flatten the environment variables flattendVars := strings.Join(envVars, " ") // Compile the command p.config.ctx.Data = &ExecuteCommandTemplate{ Vars: flattendVars, Path: p.config.RemotePath, } command, err := interpolate.Render(p.config.ExecuteCommand, &p.config.ctx) if err != nil { return fmt.Errorf("Error processing command: %s", err) } // Upload the file and run the command. Do this in the context of // a single retryable function so that we don't end up with // the case that the upload succeeded, a restart is initiated, // and then the command is executed but the file doesn't exist // any longer. var cmd *packer.RemoteCmd err = p.retryable(func() error { if _, err := f.Seek(0, 0); err != nil { return err } var r io.Reader = f if !p.config.Binary { r = &UnixReader{Reader: r} } if err := comm.Upload(p.config.RemotePath, r, nil); err != nil { return fmt.Errorf("Error uploading script: %s", err) } cmd = &packer.RemoteCmd{ Command: fmt.Sprintf("chmod 0755 %s", p.config.RemotePath), } if err := comm.Start(cmd); err != nil { return fmt.Errorf( "Error chmodding script file to 0755 in remote "+ "machine: %s", err) } cmd.Wait() cmd = &packer.RemoteCmd{Command: command} return cmd.StartWithUi(comm, ui) }) if err != nil { return err } if cmd.ExitStatus != 0 { return fmt.Errorf("Script exited with non-zero exit status: %d", cmd.ExitStatus) } // Delete the temporary file we created. We retry this a few times // since if the above rebooted we have to wait until the reboot // completes. err = p.retryable(func() error { cmd = &packer.RemoteCmd{ Command: fmt.Sprintf("rm -f %s", p.config.RemotePath), } if err := comm.Start(cmd); err != nil { return fmt.Errorf( "Error removing temporary script at %s: %s", p.config.RemotePath, err) } cmd.Wait() return nil }) if err != nil { return err } if cmd.ExitStatus != 0 { return fmt.Errorf( "Error removing temporary script at %s!", p.config.RemotePath) } } return nil }
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 (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 }