// 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 }
// Run executes the Packer build step that uploads a GCE machine image. func (s *StepUploadImage) Run(state multistep.StateBag) multistep.StepAction { comm := state.Get("communicator").(packer.Communicator) config := state.Get("config").(*Config) imageFilename := state.Get("image_file_name").(string) ui := state.Get("ui").(packer.Ui) sudoPrefix := "" if config.SSHUsername != "root" { sudoPrefix = "sudo " } ui.Say("Uploading image...") cmd := new(packer.RemoteCmd) cmd.Command = fmt.Sprintf("%s/usr/local/bin/gsutil cp %s gs://%s", sudoPrefix, imageFilename, config.BucketName) err := cmd.StartWithUi(comm, ui) if err == nil && cmd.ExitStatus != 0 { err = fmt.Errorf( "gsutil exited with non-zero exit status: %d", cmd.ExitStatus) } if err != nil { err := fmt.Errorf("Error uploading image: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } return multistep.ActionContinue }
func (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) }
// 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 }
func (s *StepBundleVolume) Run(state multistep.StateBag) multistep.StepAction { comm := state.Get("communicator").(packer.Communicator) config := state.Get("config").(*Config) instance := state.Get("instance").(*ec2.Instance) ui := state.Get("ui").(packer.Ui) x509RemoteCertPath := state.Get("x509RemoteCertPath").(string) x509RemoteKeyPath := state.Get("x509RemoteKeyPath").(string) // Bundle the volume var err error config.ctx.Data = bundleCmdData{ AccountId: config.AccountId, Architecture: *instance.Architecture, CertPath: x509RemoteCertPath, Destination: config.BundleDestination, KeyPath: x509RemoteKeyPath, Prefix: config.BundlePrefix, PrivatePath: config.X509UploadPath, } config.BundleVolCommand, err = interpolate.Render(config.BundleVolCommand, &config.ctx) if err != nil { err := fmt.Errorf("Error processing bundle volume command: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } ui.Say("Bundling the volume...") cmd := new(packer.RemoteCmd) cmd.Command = config.BundleVolCommand if s.Debug { ui.Say(fmt.Sprintf("Running: %s", config.BundleVolCommand)) } if err := cmd.StartWithUi(comm, ui); err != nil { state.Put("error", fmt.Errorf("Error bundling volume: %s", err)) ui.Error(state.Get("error").(error).Error()) return multistep.ActionHalt } if cmd.ExitStatus != 0 { state.Put("error", fmt.Errorf( "Volume bundling failed. Please see the output above for more\n"+ "details on what went wrong.\n\n"+ "One common cause for this error is ec2-bundle-vol not being\n"+ "available on the target instance.")) ui.Error(state.Get("error").(error).Error()) return multistep.ActionHalt } // Store the manifest path manifestName := config.BundlePrefix + ".manifest.xml" state.Put("manifest_name", manifestName) state.Put("manifest_path", fmt.Sprintf( "%s/%s", config.BundleDestination, manifestName)) return multistep.ActionContinue }
func (s *StepBundleVolume) Run(state map[string]interface{}) multistep.StepAction { comm := state["communicator"].(packer.Communicator) config := state["config"].(*Config) instance := state["instance"].(*ec2.Instance) ui := state["ui"].(packer.Ui) x509RemoteCertPath := state["x509RemoteCertPath"].(string) x509RemoteKeyPath := state["x509RemoteKeyPath"].(string) // Bundle the volume var err error config.BundleVolCommand, err = config.tpl.Process(config.BundleVolCommand, bundleCmdData{ AccountId: config.AccountId, Architecture: instance.Architecture, CertPath: x509RemoteCertPath, Destination: config.BundleDestination, KeyPath: x509RemoteKeyPath, Prefix: config.BundlePrefix, PrivatePath: config.X509UploadPath, }) if err != nil { err := fmt.Errorf("Error processing bundle volume command: %s", err) state["error"] = err ui.Error(err.Error()) return multistep.ActionHalt } ui.Say("Bundling the volume...") cmd := new(packer.RemoteCmd) cmd.Command = config.BundleVolCommand if err := cmd.StartWithUi(comm, ui); err != nil { state["error"] = fmt.Errorf("Error bundling volume: %s", err) ui.Error(state["error"].(error).Error()) return multistep.ActionHalt } if cmd.ExitStatus != 0 { state["error"] = fmt.Errorf( "Volume bundling failed. Please see the output above for more\n" + "details on what went wrong.") ui.Error(state["error"].(error).Error()) return multistep.ActionHalt } // Store the manifest path manifestName := config.BundlePrefix + ".manifest.xml" state["manifest_name"] = manifestName state["manifest_path"] = fmt.Sprintf( "%s/%s", config.BundleDestination, manifestName) return multistep.ActionContinue }
func (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] = "PACKER_BUILD_NAME=" + p.config.PackerBuildName envVars[1] = "PACKER_BUILDER_TYPE=" + 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 command, err := p.config.tpl.Process(p.config.ExecuteCommand, &ExecuteCommandTemplate{ Vars: flattendVars, Path: p.config.RemotePath, }) 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); err != nil { return fmt.Errorf("Error uploading script: %s", err) } cmd = &packer.RemoteCmd{Command: command} return cmd.StartWithUi(comm, ui) }) if err != nil { return err } // Close the original file since we copied it f.Close() if cmd.ExitStatus != 0 { return fmt.Errorf("Script exited with non-zero exit status: %d", cmd.ExitStatus) } } return nil }
var waitForRestart = func(p *Provisioner, comm packer.Communicator) error { ui := p.ui ui.Say("Waiting for machine to restart...") waitDone := make(chan bool, 1) timeout := time.After(p.config.RestartTimeout) var err error p.comm = comm var cmd *packer.RemoteCmd trycommand := TryCheckReboot abortcommand := AbortReboot // Stolen from Vagrant reboot checker for { log.Printf("Check if machine is rebooting...") cmd = &packer.RemoteCmd{Command: trycommand} err = cmd.StartWithUi(comm, ui) if err != nil { // Couldnt execute, we asume machine is rebooting already break } if cmd.ExitStatus == 1115 || cmd.ExitStatus == 1190 { // Reboot already in progress but not completed log.Printf("Reboot already in progress, waiting...") time.Sleep(10 * time.Second) } if cmd.ExitStatus == 0 { // Cancel reboot we created to test if machine was already rebooting cmd = &packer.RemoteCmd{Command: abortcommand} cmd.StartWithUi(comm, ui) break }
func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { ui.Say(fmt.Sprintf("Provisioning with Powershell...")) p.communicator = comm scripts := make([]string, len(p.config.Scripts)) copy(scripts, p.config.Scripts) // Build our variables up by adding in the build name and builder type envVars := make([]string, len(p.config.Vars)+2) envVars[0] = "PACKER_BUILD_NAME=" + p.config.PackerBuildName envVars[1] = "PACKER_BUILDER_TYPE=" + p.config.PackerBuilderType copy(envVars, p.config.Vars) if p.config.Inline != nil { temp, err := extractScript(p) if err != nil { ui.Error(fmt.Sprintf("Unable to extract inline scripts into a file: %s", err)) } scripts = append(scripts, temp) } 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() command, err := p.createCommandText() 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 } if err := comm.Upload(p.config.RemotePath, f, nil); err != nil { return fmt.Errorf("Error uploading script: %s", err) } cmd = &packer.RemoteCmd{Command: command} return cmd.StartWithUi(comm, ui) }) if err != nil { return err } // Close the original file since we copied it f.Close() // Check exit code against allowed codes (likely just 0) validExitCode := false for _, v := range p.config.ValidExitCodes { if cmd.ExitStatus == v { validExitCode = true } } if !validExitCode { return fmt.Errorf( "Script exited with non-zero exit status: %d. Allowed exit codes are: %v", cmd.ExitStatus, p.config.ValidExitCodes) } } return nil }
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 the exit code indicates a remote disconnect, fail unless // we were expecting it. if cmd.ExitStatus == packer.CmdDisconnect { if !*p.config.ExpectDisconnect { return fmt.Errorf("Script disconnected unexpectedly.") } } else if cmd.ExitStatus != 0 { return fmt.Errorf("Script exited with non-zero exit status: %d", cmd.ExitStatus) } if !p.config.SkipClean { // 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 { ui.Say(fmt.Sprintf("Provisioning with windows-shell...")) scripts := make([]string, len(p.config.Scripts)) copy(scripts, p.config.Scripts) // Build our variables up by adding in the build name and builder type envVars := make([]string, len(p.config.Vars)+2) envVars[0] = "PACKER_BUILD_NAME=" + p.config.PackerBuildName envVars[1] = "PACKER_BUILDER_TYPE=" + p.config.PackerBuilderType copy(envVars, p.config.Vars) if p.config.Inline != nil { temp, err := extractScript(p) if err != nil { ui.Error(fmt.Sprintf("Unable to extract inline scripts into a file: %s", err)) } scripts = append(scripts, temp) } 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() // Create environment variables to set before executing the command flattendVars, err := p.createFlattenedEnvVars() if err != nil { return err } // 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 } if err := comm.Upload(p.config.RemotePath, f, nil); err != nil { return fmt.Errorf("Error uploading script: %s", err) } cmd = &packer.RemoteCmd{Command: command} return cmd.StartWithUi(comm, ui) }) if err != nil { return err } // Close the original file since we copied it f.Close() if cmd.ExitStatus != 0 { return fmt.Errorf("Script exited with non-zero exit status: %d", cmd.ExitStatus) } } return nil }