func (p *Provisioner) generateElevatedRunner(command string) (uploadedPath string, err error) { log.Printf("Building elevated command wrapper for: %s", command) // generate command var buffer bytes.Buffer base64EncodedCommand, err := powershellEncode(command) if err != nil { return "", fmt.Errorf("Error encoding command: %s", err) } err = elevatedTemplate.Execute(&buffer, elevatedOptions{ User: p.config.ElevatedUser, Password: p.config.ElevatedPassword, TaskDescription: "Packer elevated task", TaskName: fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()), EncodedCommand: base64EncodedCommand, }) if err != nil { fmt.Printf("Error creating elevated template: %s", err) return "", err } tmpFile, err := ioutil.TempFile(os.TempDir(), "packer-elevated-shell.ps1") writer := bufio.NewWriter(tmpFile) if _, err := writer.WriteString(string(buffer.Bytes())); err != nil { return "", fmt.Errorf("Error preparing elevated shell script: %s", err) } if err := writer.Flush(); err != nil { return "", fmt.Errorf("Error preparing elevated shell script: %s", err) } tmpFile.Close() f, err := os.Open(tmpFile.Name()) if err != nil { return "", fmt.Errorf("Error opening temporary elevated shell script: %s", err) } defer f.Close() uuid := uuid.TimeOrderedUUID() path := fmt.Sprintf(`${env:TEMP}\packer-elevated-shell-%s.ps1`, uuid) log.Printf("Uploading elevated shell wrapper for command [%s] to [%s] from [%s]", command, path, tmpFile.Name()) err = p.communicator.Upload(path, f, nil) if err != nil { return "", fmt.Errorf("Error preparing elevated shell script: %s", err) } // CMD formatted Path required for this op path = fmt.Sprintf("%s-%s.ps1", "%TEMP%\\packer-elevated-shell", uuid) return path, err }
func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { nodeName := p.config.NodeName if nodeName == "" { nodeName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()) } remoteValidationKeyPath := "" serverUrl := p.config.ServerUrl if !p.config.SkipInstall { if err := p.installChef(ui, comm); err != nil { return fmt.Errorf("Error installing Chef: %s", err) } } if err := p.createDir(ui, comm, p.config.StagingDir); err != nil { return fmt.Errorf("Error creating staging directory: %s", err) } if p.config.ValidationKeyPath != "" { remoteValidationKeyPath = fmt.Sprintf("%s/validation.pem", p.config.StagingDir) if err := p.copyValidationKey(ui, comm, remoteValidationKeyPath); err != nil { return fmt.Errorf("Error copying validation key: %s", err) } } configPath, err := p.createConfig( ui, comm, nodeName, serverUrl, remoteValidationKeyPath, p.config.ValidationClientName, p.config.ChefEnvironment, p.config.SslVerifyMode) if err != nil { return fmt.Errorf("Error creating Chef config file: %s", err) } jsonPath, err := p.createJson(ui, comm) if err != nil { return fmt.Errorf("Error creating JSON attributes: %s", err) } err = p.executeChef(ui, comm, configPath, jsonPath) if !p.config.SkipCleanNode { if err2 := p.cleanNode(ui, comm, nodeName); err2 != nil { return fmt.Errorf("Error cleaning up chef node: %s", err2) } } if !p.config.SkipCleanClient { if err2 := p.cleanClient(ui, comm, nodeName); err2 != nil { return fmt.Errorf("Error cleaning up chef client: %s", err2) } } if err != nil { return fmt.Errorf("Error executing Chef: %s", err) } if err := p.removeDir(ui, comm, p.config.StagingDir); err != nil { return fmt.Errorf("Error removing /etc/chef directory: %s", err) } return nil }
func doCopy(client *winrm.Client, config *Config, in io.Reader, toPath string) error { tempFile := fmt.Sprintf("winrmcp-%s.tmp", uuid.TimeOrderedUUID()) tempPath := "$env:TEMP\\" + tempFile if os.Getenv("WINRMCP_DEBUG") != "" { log.Printf("Copying file to %s\n", tempPath) } err := uploadContent(client, config.MaxOperationsPerShell, "%TEMP%\\"+tempFile, in) if err != nil { return errors.New(fmt.Sprintf("Error uploading file to %s: %v", tempPath, err)) } if os.Getenv("WINRMCP_DEBUG") != "" { log.Printf("Moving file from %s to %s", tempPath, toPath) } err = restoreContent(client, tempPath, toPath) if err != nil { return errors.New(fmt.Sprintf("Error restoring file from %s to %s: %v", tempPath, toPath, err)) } if os.Getenv("WINRMCP_DEBUG") != "" { log.Printf("Removing temporary file %s", tempPath) } err = cleanupContent(client, tempPath) if err != nil { return errors.New(fmt.Sprintf("Error removing temporary file %s: %v", tempPath, err)) } return nil }
func createCommandText() (command string, err error) { // doesn't take well to the flattened env vars cmd = fmt.Sprintf(`$env:FOO="bar"; %s`, cmd) log.Printf("Building elevated command for: %s", cmd) // generate command var buffer bytes.Buffer err = elevatedTemplate.Execute(&buffer, elevatedOptions{ User: user, Password: pass, TaskDescription: "Packer elevated task", TaskName: fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()), EncodedCommand: powershellEncode([]byte(cmd + "; exit $LASTEXITCODE")), }) if err != nil { return "", err } log.Printf("ELEVATED SCRIPT: %s\n\n", string(buffer.Bytes())) return string(buffer.Bytes()), nil }
func (s *stepCreateDroplet) Run(state multistep.StateBag) multistep.StepAction { client := state.Get("client").(*DigitalOceanClient) ui := state.Get("ui").(packer.Ui) c := state.Get("config").(config) sshKeyId := state.Get("ssh_key_id").(uint) ui.Say("Creating droplet...") // Some random droplet name as it's temporary name := fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()) // Create the droplet based on configuration dropletId, err := client.CreateDroplet(name, c.SizeID, c.ImageID, c.RegionID, sshKeyId) if err != nil { err := fmt.Errorf("Error creating droplet: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } // We use this in cleanup s.dropletId = dropletId // Store the droplet id for later state.Put("droplet_id", dropletId) return multistep.ActionContinue }
func (c *RunConfig) Prepare(ctx *interpolate.Context) []error { // If we are not given an explicit ssh_keypair_name, // then create a temporary one, but only if the // temporary_key_pair_name has not been provided. if c.SSHKeyPairName == "" { if c.TemporaryKeyPairName == "" { c.TemporaryKeyPairName = fmt.Sprintf( "packer_%s", uuid.TimeOrderedUUID()) } } if c.WindowsPasswordTimeout == 0 { c.WindowsPasswordTimeout = 10 * time.Minute } // Validation errs := c.Comm.Prepare(ctx) if c.SourceAmi == "" { errs = append(errs, errors.New("A source_ami must be specified")) } if c.InstanceType == "" { errs = append(errs, errors.New("An instance_type must be specified")) } if c.SpotPrice == "auto" { if c.SpotPriceAutoProduct == "" { errs = append(errs, errors.New( "spot_price_auto_product must be specified when spot_price is auto")) } } if c.UserData != "" && c.UserDataFile != "" { errs = append(errs, fmt.Errorf("Only one of user_data or user_data_file can be specified.")) } else if c.UserDataFile != "" { if _, err := os.Stat(c.UserDataFile); err != nil { errs = append(errs, fmt.Errorf("user_data_file not found: %s", c.UserDataFile)) } } if c.SecurityGroupId != "" { if len(c.SecurityGroupIds) > 0 { errs = append(errs, fmt.Errorf("Only one of security_group_id or security_group_ids can be specified.")) } else { c.SecurityGroupIds = []string{c.SecurityGroupId} c.SecurityGroupId = "" } } if c.InstanceInitiatedShutdownBehavior == "" { c.InstanceInitiatedShutdownBehavior = "stop" } else if !reShutdownBehavior.MatchString(c.InstanceInitiatedShutdownBehavior) { errs = append(errs, fmt.Errorf("shutdown_behaviour only accepts 'stop' or 'terminate' values.")) } return errs }
func (s *StepSecurityGroup) Run(state multistep.StateBag) multistep.StepAction { ec2conn := state.Get("ec2").(*ec2.EC2) ui := state.Get("ui").(packer.Ui) if len(s.SecurityGroupIds) > 0 { log.Printf("Using specified security groups: %v", s.SecurityGroupIds) state.Put("securityGroupIds", s.SecurityGroupIds) return multistep.ActionContinue } if s.SSHPort == 0 { panic("SSHPort must be set to a non-zero value.") } // Create the group ui.Say("Creating temporary security group for this instance...") groupName := fmt.Sprintf("packer %s", uuid.TimeOrderedUUID()) log.Printf("Temporary group name: %s", groupName) group := ec2.SecurityGroup{ Name: groupName, Description: "Temporary group for Packer", VpcId: s.VpcId, } groupResp, err := ec2conn.CreateSecurityGroup(group) if err != nil { ui.Error(err.Error()) return multistep.ActionHalt } // Set the group ID so we can delete it later s.createdGroupId = groupResp.Id // Authorize the SSH access perms := []ec2.IPPerm{ ec2.IPPerm{ Protocol: "tcp", FromPort: s.SSHPort, ToPort: s.SSHPort, SourceIPs: []string{"0.0.0.0/0"}, }, } ui.Say("Authorizing SSH access on the temporary security group...") if _, err := ec2conn.AuthorizeSecurityGroup(groupResp.SecurityGroup, perms); err != nil { err := fmt.Errorf("Error creating temporary security group: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } // Set some state data for use in future steps state.Put("securityGroupIds", []string{s.createdGroupId}) return multistep.ActionContinue }
func (s *StepKeyPair) Run(state multistep.StateBag) multistep.StepAction { csp := state.Get("csp").(gophercloud.CloudServersProvider) ui := state.Get("ui").(packer.Ui) ui.Say("Creating temporary keypair for this instance...") keyName := fmt.Sprintf("packer %s", uuid.TimeOrderedUUID()) log.Printf("temporary keypair name: %s", keyName) keyResp, err := csp.CreateKeyPair(gophercloud.NewKeyPair{Name: keyName}) if err != nil { state.Put("error", fmt.Errorf("Error creating temporary keypair: %s", err)) return multistep.ActionHalt } if keyResp.PrivateKey == "" { state.Put("error", fmt.Errorf("The temporary keypair returned was blank")) return multistep.ActionHalt } // If we're in debug mode, output the private key to the working // directory. if s.Debug { ui.Message(fmt.Sprintf("Saving key for debug purposes: %s", s.DebugKeyPath)) f, err := os.Create(s.DebugKeyPath) if err != nil { state.Put("error", fmt.Errorf("Error saving debug key: %s", err)) return multistep.ActionHalt } defer f.Close() // Write the key out if _, err := f.Write([]byte(keyResp.PrivateKey)); err != nil { state.Put("error", fmt.Errorf("Error saving debug key: %s", err)) return multistep.ActionHalt } // Chmod it so that it is SSH ready if runtime.GOOS != "windows" { if err := f.Chmod(0600); err != nil { state.Put("error", fmt.Errorf("Error setting permissions of debug key: %s", err)) return multistep.ActionHalt } } } // Set the keyname so we know to delete it later s.keyName = keyName // Set some state data for use in future steps state.Put("keyPair", keyName) state.Put("privateKey", keyResp.PrivateKey) return multistep.ActionContinue }
// Run executes the Packer build step that creates a GCE instance. func (s *StepCreateInstance) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*Config) driver := state.Get("driver").(Driver) sshPublicKey := state.Get("ssh_public_key").(string) ui := state.Get("ui").(packer.Ui) ui.Say("Creating instance...") name := fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()) errCh, err := driver.RunInstance(&InstanceConfig{ Description: "New instance created by Packer", Image: config.SourceImage, MachineType: config.MachineType, Metadata: map[string]string{ "sshKeys": fmt.Sprintf("%s:%s", config.SSHUsername, sshPublicKey), }, Name: name, Network: config.Network, Tags: config.Tags, Zone: config.Zone, }) if err == nil { ui.Message("Waiting for creation operation to complete...") select { case err = <-errCh: case <-time.After(config.stateTimeout): err = errors.New("time out while waiting for instance to create") } } if err != nil { err := fmt.Errorf("Error creating instance: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } ui.Message("Instance has been created!") if s.Debug { if name != "" { ui.Message(fmt.Sprintf("Instance: %s started in %s", name, config.Zone)) } } // Things succeeded, store the name so we can remove it later state.Put("instance_name", name) s.instanceName = name return multistep.ActionContinue }
func (s *StepCreateExternalSwitch) Run(state multistep.StateBag) multistep.StepAction { driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) vmName := state.Get("vmName").(string) errorMsg := "Error createing external switch: %s" var err error ui.Say("Creating external switch...") packerExternalSwitchName := "paes_" + uuid.TimeOrderedUUID() err = driver.CreateExternalVirtualSwitch(vmName, packerExternalSwitchName) if err != nil { err := fmt.Errorf("Error creating switch: %s", err) state.Put(errorMsg, err) ui.Error(err.Error()) s.SwitchName = "" return multistep.ActionHalt } switchName, err := driver.GetVirtualMachineSwitchName(vmName) if err != nil { err := fmt.Errorf(errorMsg, err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } if len(switchName) == 0 { err := fmt.Errorf(errorMsg, err) state.Put("error", "Can't get the VM switch name") ui.Error(err.Error()) return multistep.ActionHalt } ui.Say("External switch name is: '" + switchName + "'") if switchName != packerExternalSwitchName { s.SwitchName = "" } else { s.SwitchName = packerExternalSwitchName s.oldSwitchName = state.Get("SwitchName").(string) } // Set the final name in the state bag so others can use it state.Put("SwitchName", switchName) return multistep.ActionContinue }
func (c *RunConfig) Prepare(ctx *interpolate.Context) []error { // if we are not given an explicit keypairname, create a temporary one if c.SSHKeyPairName == "" { c.TemporaryKeyPairName = fmt.Sprintf( "packer %s", uuid.TimeOrderedUUID()) } if c.WindowsPasswordTimeout == 0 { c.WindowsPasswordTimeout = 10 * time.Minute } // Validation errs := c.Comm.Prepare(ctx) if c.SourceAmi == "" { errs = append(errs, errors.New("A source_ami must be specified")) } if c.InstanceType == "" { errs = append(errs, errors.New("An instance_type must be specified")) } if c.SpotPrice == "auto" { if c.SpotPriceAutoProduct == "" { errs = append(errs, errors.New( "spot_price_auto_product must be specified when spot_price is auto")) } } if c.UserData != "" && c.UserDataFile != "" { errs = append(errs, fmt.Errorf("Only one of user_data or user_data_file can be specified.")) } else if c.UserDataFile != "" { if _, err := os.Stat(c.UserDataFile); err != nil { errs = append(errs, fmt.Errorf("user_data_file not found: %s", c.UserDataFile)) } } if c.SecurityGroupId != "" { if len(c.SecurityGroupIds) > 0 { errs = append(errs, fmt.Errorf("Only one of security_group_id or security_group_ids can be specified.")) } else { c.SecurityGroupIds = []string{c.SecurityGroupId} c.SecurityGroupId = "" } } return errs }
func (s *stepCreateServer) Run(state multistep.StateBag) multistep.StepAction { client := state.Get("client").(*vultr.Client) ui := state.Get("ui").(packer.Ui) c := state.Get("config").(config) var keyId string var err error if c.SSHPrivateKey != "" { ui.Say("Uploading SSH key") name := fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()) keyId, err = client.CreateSSHKey(name, c.SSHPrivateKey) if err != nil { err := fmt.Errorf("Error uploading ssh key: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } } ui.Say("Creating server...") // Create the droplet based on configuration opts := client.CreateOpts() opts.Region = c.Region opts.Plan = c.Plan opts.Os = c.Os opts.PrivateNet = c.PrivateNetworking opts.IpV6 = c.IPv6 opts.IpxeUrl = c.IpxeUrl if c.SSHPrivateKey != "" { opts.SSHKeyId = keyId } serverId, err := client.CreateServer(&opts) if err != nil { err := fmt.Errorf("Error creating server: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } // We use this in cleanup s.serverId = serverId // Store the droplet id for later state.Put("server_id", serverId) return multistep.ActionContinue }
func (s *stepCreateSSHKey) Run(state multistep.StateBag) multistep.StepAction { client := state.Get("client").(*DigitalOceanClient) ui := state.Get("ui").(packer.Ui) ui.Say("Creating temporary ssh key for droplet...") priv, err := rsa.GenerateKey(rand.Reader, 2014) // ASN.1 DER encoded form priv_der := x509.MarshalPKCS1PrivateKey(priv) priv_blk := pem.Block{ Type: "RSA PRIVATE KEY", Headers: nil, Bytes: priv_der, } // Set the private key in the statebag for later state.Put("privateKey", string(pem.EncodeToMemory(&priv_blk))) // Marshal the public key into SSH compatible format // TODO properly handle the public key error pub, _ := ssh.NewPublicKey(&priv.PublicKey) pub_sshformat := string(ssh.MarshalAuthorizedKey(pub)) // The name of the public key on DO name := fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()) // Create the key! keyId, err := client.CreateKey(name, pub_sshformat) if err != nil { err := fmt.Errorf("Error creating temporary SSH key: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } // We use this to check cleanup s.keyId = keyId log.Printf("temporary ssh key name: %s", name) // Remember some state for the future state.Put("ssh_key_id", keyId) return multistep.ActionContinue }
func (s *stepDeployVirtualMachine) Run(state multistep.StateBag) multistep.StepAction { client := state.Get("client").(*gopherstack.CloudstackClient) ui := state.Get("ui").(packer.Ui) c := state.Get("config").(config) sshKeyName := state.Get("ssh_key_name").(string) ui.Say("Creating virtual machine...") // Some random virtual machine name as it's temporary displayName := fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()) // Massage any userData that we wish to send to the virtual // machine to help it boot properly. processTemplatedUserdata(state) userData := state.Get("user_data").(string) // Create the virtual machine based on configuration response, err := client.DeployVirtualMachine(c.ServiceOfferingId, c.TemplateId, c.ZoneId, "", c.DiskOfferingId, displayName, c.NetworkIds, sshKeyName, "", userData, c.Hypervisor) if err != nil { err := fmt.Errorf("Error deploying virtual machine: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } // Unpack the async jobid and wait for it vmid := response.Deployvirtualmachineresponse.ID jobid := response.Deployvirtualmachineresponse.Jobid client.WaitForAsyncJob(jobid, c.stateTimeout) // We use this in cleanup s.id = vmid // Store the virtual machine id for later use state.Put("virtual_machine_id", vmid) return multistep.ActionContinue }
func NewConfig(raws ...interface{}) (*Config, []string, error) { c := new(Config) md, err := common.DecodeConfig(c, raws...) if err != nil { return nil, nil, err } c.tpl, err = packer.NewConfigTemplate() if err != nil { return nil, nil, err } c.tpl.UserVars = c.PackerUserVars // Prepare the errors errs := common.CheckUnusedConfig(md) // Set defaults. if c.Network == "" { c.Network = "default" } if c.DiskSizeGb == 0 { c.DiskSizeGb = 10 } if c.ImageDescription == "" { c.ImageDescription = "Created by Packer" } if c.ImageName == "" { c.ImageName = "packer-{{timestamp}}" } if c.InstanceName == "" { c.InstanceName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()) } if c.MachineType == "" { c.MachineType = "n1-standard-1" } if c.RawSSHTimeout == "" { c.RawSSHTimeout = "5m" } if c.RawStateTimeout == "" { c.RawStateTimeout = "5m" } if c.SSHUsername == "" { c.SSHUsername = "******" } if c.SSHPort == 0 { c.SSHPort = 22 } // Process Templates templates := map[string]*string{ "account_file": &c.AccountFile, "client_secrets_file": &c.ClientSecretsFile, "bucket_name": &c.BucketName, "image_name": &c.ImageName, "image_description": &c.ImageDescription, "instance_name": &c.InstanceName, "machine_type": &c.MachineType, "network": &c.Network, "project_id": &c.ProjectId, "source_image": &c.SourceImage, "source_image_project_id": &c.SourceImageProjectId, "ssh_username": &c.SSHUsername, "ssh_timeout": &c.RawSSHTimeout, "state_timeout": &c.RawStateTimeout, "zone": &c.Zone, } for n, ptr := range templates { var err error *ptr, err = c.tpl.Process(*ptr, nil) if err != nil { errs = packer.MultiErrorAppend( errs, fmt.Errorf("Error processing %s: %s", n, err)) } } // Process required parameters. if c.BucketName == "" { errs = packer.MultiErrorAppend( errs, errors.New("a bucket_name must be specified")) } if c.AccountFile == "" { errs = packer.MultiErrorAppend( errs, errors.New("an account_file must be specified")) } if c.ClientSecretsFile == "" { errs = packer.MultiErrorAppend( errs, errors.New("a client_secrets_file must be specified")) } if c.ProjectId == "" { errs = packer.MultiErrorAppend( errs, errors.New("a project_id must be specified")) } if c.SourceImage == "" { errs = packer.MultiErrorAppend( errs, errors.New("a source_image must be specified")) } if c.Zone == "" { errs = packer.MultiErrorAppend( errs, errors.New("a zone must be specified")) } // Process timeout settings. sshTimeout, err := time.ParseDuration(c.RawSSHTimeout) if err != nil { errs = packer.MultiErrorAppend( errs, fmt.Errorf("Failed parsing ssh_timeout: %s", err)) } c.sshTimeout = sshTimeout stateTimeout, err := time.ParseDuration(c.RawStateTimeout) if err != nil { errs = packer.MultiErrorAppend( errs, fmt.Errorf("Failed parsing state_timeout: %s", err)) } c.stateTimeout = stateTimeout if c.AccountFile != "" { if err := loadJSON(&c.account, c.AccountFile); err != nil { errs = packer.MultiErrorAppend( errs, fmt.Errorf("Failed parsing account file: %s", err)) } } if c.ClientSecretsFile != "" { if err := loadJSON(&c.clientSecrets, c.ClientSecretsFile); err != nil { errs = packer.MultiErrorAppend( errs, fmt.Errorf("Failed parsing client secrets file: %s", err)) } } // Check for any errors. if errs != nil && len(errs.Errors) > 0 { return nil, nil, errs } return c, nil, nil }
func (s *StepSecurityGroup) Run(state multistep.StateBag) multistep.StepAction { ec2conn := state.Get("ec2").(*ec2.EC2) ui := state.Get("ui").(packer.Ui) if len(s.SecurityGroupIds) > 0 { log.Printf("Using specified security groups: %v", s.SecurityGroupIds) state.Put("securityGroupIds", s.SecurityGroupIds) return multistep.ActionContinue } port := s.CommConfig.Port() if port == 0 { panic("port must be set to a non-zero value.") } // Create the group ui.Say("Creating temporary security group for this instance...") groupName := fmt.Sprintf("packer %s", uuid.TimeOrderedUUID()) log.Printf("Temporary group name: %s", groupName) group := &ec2.CreateSecurityGroupInput{ GroupName: &groupName, Description: aws.String("Temporary group for Packer"), VpcId: &s.VpcId, } groupResp, err := ec2conn.CreateSecurityGroup(group) if err != nil { ui.Error(err.Error()) state.Put("error", err) return multistep.ActionHalt } // Set the group ID so we can delete it later s.createdGroupId = *groupResp.GroupId // Authorize the SSH access for the security group req := &ec2.AuthorizeSecurityGroupIngressInput{ GroupId: groupResp.GroupId, IpProtocol: aws.String("tcp"), FromPort: aws.Int64(int64(port)), ToPort: aws.Int64(int64(port)), CidrIp: aws.String("0.0.0.0/0"), } // We loop and retry this a few times because sometimes the security // group isn't available immediately because AWS resources are eventaully // consistent. ui.Say(fmt.Sprintf( "Authorizing access to port %d the temporary security group...", port)) for i := 0; i < 5; i++ { _, err = ec2conn.AuthorizeSecurityGroupIngress(req) if err == nil { break } log.Printf("Error authorizing. Will sleep and retry. %s", err) time.Sleep((time.Duration(i) * time.Second) + 1) } if err != nil { err := fmt.Errorf("Error creating temporary security group: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } // Set some state data for use in future steps state.Put("securityGroupIds", []string{s.createdGroupId}) return multistep.ActionContinue }
func (self *stepCreateSshKey) Run(state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) if self.PrivateKeyFile != "" { ui.Say(fmt.Sprintf("Reading private key file (%s)...", self.PrivateKeyFile)) privateKeyBytes, err := ioutil.ReadFile(self.PrivateKeyFile) if err != nil { state.Put("error", fmt.Errorf("Error loading configured private key file: %s", err)) return multistep.ActionHalt } state.Put("ssh_private_key", string(privateKeyBytes)) return multistep.ActionContinue } client := state.Get("client").(*SoftlayerClient) ui.Say("Creating temporary ssh key for the instance...") rsaKey, err := rsa.GenerateKey(rand.Reader, 2014) if err != nil { ui.Error(err.Error()) state.Put("error", err) return multistep.ActionHalt } // ASN.1 DER encoded form privDer := x509.MarshalPKCS1PrivateKey(rsaKey) privBlk := pem.Block{ Type: "RSA PRIVATE KEY", Headers: nil, Bytes: privDer, } // Set the private key in the statebag for later state.Put("ssh_private_key", string(pem.EncodeToMemory(&privBlk))) pub, err := ssh.NewPublicKey(&rsaKey.PublicKey) if err != nil { ui.Error(err.Error()) state.Put("error", err) return multistep.ActionHalt } publicKey := strings.TrimSpace(string(ssh.MarshalAuthorizedKey(pub))) // The name of the public key label := fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()) keyId, err := client.UploadSshKey(label, publicKey) if err != nil { ui.Error(err.Error()) state.Put("error", err) return multistep.ActionHalt } self.keyId = keyId state.Put("ssh_key_id", keyId) ui.Say(fmt.Sprintf("Created SSH key with id '%d'", keyId)) return multistep.ActionContinue }
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { md, err := common.DecodeConfig(&b.config, raws...) if err != nil { return nil, err } b.config.tpl, err = packer.NewConfigTemplate() if err != nil { return nil, err } b.config.tpl.UserVars = b.config.PackerUserVars // Accumulate any errors errs := common.CheckUnusedConfig(md) // Optional configuration with defaults if b.config.APIKey == "" { // Default to environment variable for api_key, if it exists b.config.APIKey = os.Getenv("DIGITALOCEAN_API_KEY") } if b.config.ClientID == "" { // Default to environment variable for client_id, if it exists b.config.ClientID = os.Getenv("DIGITALOCEAN_CLIENT_ID") } if b.config.RegionID == 0 { // Default to Region "New York" b.config.RegionID = 1 } if b.config.SizeID == 0 { // Default to 512mb, the smallest droplet size b.config.SizeID = 66 } if b.config.ImageID == 0 { // Default to base image "Ubuntu 12.04.4 x64 (id: 3101045)" b.config.ImageID = 3101045 } if b.config.SnapshotName == "" { // Default to packer-{{ unix timestamp (utc) }} b.config.SnapshotName = "packer-{{timestamp}}" } if b.config.DropletName == "" { // Default to packer-[time-ordered-uuid] b.config.DropletName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()) } if b.config.SSHUsername == "" { // Default to "root". You can override this if your // SourceImage has a different user account then the DO default b.config.SSHUsername = "******" } if b.config.SSHPort == 0 { // Default to port 22 per DO default b.config.SSHPort = 22 } if b.config.RawSSHTimeout == "" { // Default to 1 minute timeouts b.config.RawSSHTimeout = "1m" } if b.config.RawStateTimeout == "" { // Default to 6 minute timeouts waiting for // desired state. i.e waiting for droplet to become active b.config.RawStateTimeout = "6m" } templates := map[string]*string{ "client_id": &b.config.ClientID, "api_key": &b.config.APIKey, "snapshot_name": &b.config.SnapshotName, "droplet_name": &b.config.DropletName, "ssh_username": &b.config.SSHUsername, "ssh_timeout": &b.config.RawSSHTimeout, "state_timeout": &b.config.RawStateTimeout, } for n, ptr := range templates { var err error *ptr, err = b.config.tpl.Process(*ptr, nil) if err != nil { errs = packer.MultiErrorAppend( errs, fmt.Errorf("Error processing %s: %s", n, err)) } } // Required configurations that will display errors if not set if b.config.ClientID == "" { errs = packer.MultiErrorAppend( errs, errors.New("a client_id must be specified")) } if b.config.APIKey == "" { errs = packer.MultiErrorAppend( errs, errors.New("an api_key must be specified")) } sshTimeout, err := time.ParseDuration(b.config.RawSSHTimeout) if err != nil { errs = packer.MultiErrorAppend( errs, fmt.Errorf("Failed parsing ssh_timeout: %s", err)) } b.config.sshTimeout = sshTimeout stateTimeout, err := time.ParseDuration(b.config.RawStateTimeout) if err != nil { errs = packer.MultiErrorAppend( errs, fmt.Errorf("Failed parsing state_timeout: %s", err)) } b.config.stateTimeout = stateTimeout if errs != nil && len(errs.Errors) > 0 { return nil, errs } common.ScrubConfig(b.config, b.config.ClientID, b.config.APIKey) return nil, nil }
func funcGenUuid(ctx *Context) interface{} { return func() string { return uuid.TimeOrderedUUID() } }
func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { nodeName := p.config.NodeName if nodeName == "" { nodeName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()) } remoteValidationKeyPath := "" serverUrl := p.config.ServerUrl if !p.config.SkipInstall { if err := p.installChef(ui, comm); err != nil { return fmt.Errorf("Error installing Chef: %s", err) } } if err := p.createDir(ui, comm, p.config.StagingDir); err != nil { return fmt.Errorf("Error creating staging directory: %s", err) } if p.config.ClientKey == "" { p.config.ClientKey = fmt.Sprintf("%s/client.pem", p.config.StagingDir) } encryptedDataBagSecretPath := "" if p.config.EncryptedDataBagSecretPath != "" { encryptedDataBagSecretPath = fmt.Sprintf("%s/encrypted_data_bag_secret", p.config.StagingDir) if err := p.uploadFile(ui, comm, encryptedDataBagSecretPath, p.config.EncryptedDataBagSecretPath); err != nil { return fmt.Errorf("Error uploading encrypted data bag secret: %s", err) } } if p.config.ValidationKeyPath != "" { remoteValidationKeyPath = fmt.Sprintf("%s/validation.pem", p.config.StagingDir) if err := p.uploadFile(ui, comm, remoteValidationKeyPath, p.config.ValidationKeyPath); err != nil { return fmt.Errorf("Error copying validation key: %s", err) } } configPath, err := p.createConfig( ui, comm, nodeName, serverUrl, p.config.ClientKey, encryptedDataBagSecretPath, remoteValidationKeyPath, p.config.ValidationClientName, p.config.ChefEnvironment, p.config.SslVerifyMode) if err != nil { return fmt.Errorf("Error creating Chef config file: %s", err) } jsonPath, err := p.createJson(ui, comm) if err != nil { return fmt.Errorf("Error creating JSON attributes: %s", err) } err = p.executeChef(ui, comm, configPath, jsonPath) knifeConfigPath, err2 := p.createKnifeConfig( ui, comm, nodeName, serverUrl, p.config.ClientKey, p.config.SslVerifyMode) if err2 != nil { return fmt.Errorf("Error creating knife config on node: %s", err2) } if !p.config.SkipCleanNode { if err2 := p.cleanNode(ui, comm, nodeName, knifeConfigPath); err2 != nil { return fmt.Errorf("Error cleaning up chef node: %s", err2) } } if !p.config.SkipCleanClient { if err2 := p.cleanClient(ui, comm, nodeName, knifeConfigPath); err2 != nil { return fmt.Errorf("Error cleaning up chef client: %s", err2) } } if err != nil { return fmt.Errorf("Error executing Chef: %s", err) } if err := p.removeDir(ui, comm, p.config.StagingDir); err != nil { return fmt.Errorf("Error removing %s: %s", p.config.StagingDir, err) } return nil }
func (s *StepKeyPair) Run(state multistep.StateBag) multistep.StepAction { if s.PrivateKeyFile != "" { privateKeyBytes, err := ioutil.ReadFile(s.PrivateKeyFile) if err != nil { state.Put("error", fmt.Errorf( "Error loading configured private key file: %s", err)) return multistep.ActionHalt } state.Put("keyPair", s.KeyPairName) state.Put("privateKey", string(privateKeyBytes)) return multistep.ActionContinue } config := state.Get("config").(Config) ui := state.Get("ui").(packer.Ui) // We need the v2 compute client computeClient, err := config.computeV2Client() if err != nil { err = fmt.Errorf("Error initializing compute client: %s", err) state.Put("error", err) return multistep.ActionHalt } ui.Say("Creating temporary keypair for this instance...") keyName := fmt.Sprintf("packer %s", uuid.TimeOrderedUUID()) keypair, err := keypairs.Create(computeClient, keypairs.CreateOpts{ Name: keyName, }).Extract() if err != nil { state.Put("error", fmt.Errorf("Error creating temporary keypair: %s", err)) return multistep.ActionHalt } if keypair.PrivateKey == "" { state.Put("error", fmt.Errorf("The temporary keypair returned was blank")) return multistep.ActionHalt } // If we're in debug mode, output the private key to the working // directory. if s.Debug { ui.Message(fmt.Sprintf("Saving key for debug purposes: %s", s.DebugKeyPath)) f, err := os.Create(s.DebugKeyPath) if err != nil { state.Put("error", fmt.Errorf("Error saving debug key: %s", err)) return multistep.ActionHalt } defer f.Close() // Write the key out if _, err := f.Write([]byte(keypair.PrivateKey)); err != nil { state.Put("error", fmt.Errorf("Error saving debug key: %s", err)) return multistep.ActionHalt } // Chmod it so that it is SSH ready if runtime.GOOS != "windows" { if err := f.Chmod(0600); err != nil { state.Put("error", fmt.Errorf("Error setting permissions of debug key: %s", err)) return multistep.ActionHalt } } } // Set the keyname so we know to delete it later s.keyName = keyName // Set some state data for use in future steps state.Put("keyPair", keyName) state.Put("privateKey", keypair.PrivateKey) return multistep.ActionContinue }
func NewConfig(raws ...interface{}) (*Config, []string, error) { c := new(Config) err := config.Decode(c, &config.DecodeOpts{ Interpolate: true, InterpolateContext: &c.ctx, InterpolateFilter: &interpolate.RenderFilter{ Exclude: []string{ "run_command", }, }, }, raws...) if err != nil { return nil, nil, err } var errs *packer.MultiError // Set defaults. if c.Network == "" { c.Network = "default" } if c.DiskSizeGb == 0 { c.DiskSizeGb = 10 } if c.DiskType == "" { c.DiskType = "pd-standard" } if c.ImageDescription == "" { c.ImageDescription = "Created by Packer" } if c.ImageName == "" { img, err := interpolate.Render("packer-{{timestamp}}", nil) if err != nil { errs = packer.MultiErrorAppend(errs, fmt.Errorf("Unable to parse image name: %s ", err)) } else { c.ImageName = img } } if len(c.ImageFamily) > 63 { errs = packer.MultiErrorAppend(errs, errors.New("Invalid image family: Must not be longer than 63 characters")) } if c.ImageFamily != "" { if !reImageFamily.MatchString(c.ImageFamily) { errs = packer.MultiErrorAppend(errs, errors.New("Invalid image family: The first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash")) } } if c.InstanceName == "" { c.InstanceName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()) } if c.DiskName == "" { c.DiskName = c.InstanceName } if c.MachineType == "" { c.MachineType = "n1-standard-1" } if c.RawStateTimeout == "" { c.RawStateTimeout = "5m" } if c.Comm.SSHUsername == "" { c.Comm.SSHUsername = "******" } if es := c.Comm.Prepare(&c.ctx); len(es) > 0 { errs = packer.MultiErrorAppend(errs, es...) } // Process required parameters. if c.ProjectId == "" { errs = packer.MultiErrorAppend( errs, errors.New("a project_id must be specified")) } if c.Scopes == nil { c.Scopes = []string{ "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/compute", "https://www.googleapis.com/auth/devstorage.full_control", } } if c.SourceImage == "" { errs = packer.MultiErrorAppend( errs, errors.New("a source_image must be specified")) } if c.Zone == "" { errs = packer.MultiErrorAppend( errs, errors.New("a zone must be specified")) } if c.Region == "" && len(c.Zone) > 2 { // get region from Zone region := c.Zone[:len(c.Zone)-2] c.Region = region } err = c.CalcTimeout() if err != nil { errs = packer.MultiErrorAppend(errs, err) } if c.AccountFile != "" { if err := ProcessAccountFile(&c.Account, c.AccountFile); err != nil { errs = packer.MultiErrorAppend(errs, err) } } if c.OmitExternalIP && c.Address != "" { errs = packer.MultiErrorAppend(fmt.Errorf("you can not specify an external address when 'omit_external_ip' is true")) } if c.OmitExternalIP && !c.UseInternalIP { errs = packer.MultiErrorAppend(fmt.Errorf("'use_internal_ip' must be true if 'omit_external_ip' is true")) } // Check for any errors. if errs != nil && len(errs.Errors) > 0 { return nil, nil, errs } return c, nil, nil }
func (s *StepSecurityGroup) Run(state multistep.StateBag) multistep.StepAction { ec2conn := state.Get("ec2").(*ec2.EC2) ui := state.Get("ui").(packer.Ui) if len(s.SecurityGroupIds) > 0 { log.Printf("Using specified security groups: %v", s.SecurityGroupIds) state.Put("securityGroupIds", s.SecurityGroupIds) return multistep.ActionContinue } if s.SSHPort == 0 { panic("SSHPort must be set to a non-zero value.") } // Create the group ui.Say("Creating temporary security group for this instance...") groupName := fmt.Sprintf("packer %s", uuid.TimeOrderedUUID()) log.Printf("Temporary group name: %s", groupName) group := ec2.SecurityGroup{ Name: groupName, Description: "Temporary group for Packer", VpcId: s.VpcId, } groupResp, err := ec2conn.CreateSecurityGroup(group) if err != nil { ui.Error(err.Error()) return multistep.ActionHalt } // Set the group ID so we can delete it later s.createdGroupId = groupResp.Id // Authorize the SSH access perms := []ec2.IPPerm{ ec2.IPPerm{ Protocol: "tcp", FromPort: s.SSHPort, ToPort: s.SSHPort, SourceIPs: []string{"0.0.0.0/0"}, }, } // We loop and retry this a few times because sometimes the security // group isn't available immediately because AWS resources are eventaully // consistent. ui.Say("Authorizing SSH access on the temporary security group...") for i := 0; i < 5; i++ { _, err = ec2conn.AuthorizeSecurityGroup(groupResp.SecurityGroup, perms) if err == nil { break } log.Printf("Error authorizing. Will sleep and retry. %s", err) time.Sleep((time.Duration(i) * time.Second) + 1) } if err != nil { err := fmt.Errorf("Error creating temporary security group: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } // Set some state data for use in future steps state.Put("securityGroupIds", []string{s.createdGroupId}) return multistep.ActionContinue }
func templateUuid() string { return uuid.TimeOrderedUUID() }
func (s *stepCreateSSHKey) Run(state multistep.StateBag) multistep.StepAction { client := state.Get("client").(*godo.Client) ui := state.Get("ui").(packer.Ui) ui.Say("Creating temporary ssh key for droplet...") priv, err := rsa.GenerateKey(rand.Reader, 2014) // ASN.1 DER encoded form priv_der := x509.MarshalPKCS1PrivateKey(priv) priv_blk := pem.Block{ Type: "RSA PRIVATE KEY", Headers: nil, Bytes: priv_der, } // Set the private key in the statebag for later state.Put("privateKey", string(pem.EncodeToMemory(&priv_blk))) // Marshal the public key into SSH compatible format // TODO properly handle the public key error pub, _ := ssh.NewPublicKey(&priv.PublicKey) pub_sshformat := string(ssh.MarshalAuthorizedKey(pub)) // The name of the public key on DO name := fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()) // Create the key! key, _, err := client.Keys.Create(&godo.KeyCreateRequest{ Name: name, PublicKey: pub_sshformat, }) if err != nil { err := fmt.Errorf("Error creating temporary SSH key: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } // We use this to check cleanup s.keyId = key.ID log.Printf("temporary ssh key name: %s", name) // Remember some state for the future state.Put("ssh_key_id", key.ID) // If we're in debug mode, output the private key to the working directory. if s.Debug { ui.Message(fmt.Sprintf("Saving key for debug purposes: %s", s.DebugKeyPath)) f, err := os.Create(s.DebugKeyPath) if err != nil { state.Put("error", fmt.Errorf("Error saving debug key: %s", err)) return multistep.ActionHalt } defer f.Close() // Write the key out if _, err := f.Write(pem.EncodeToMemory(&priv_blk)); err != nil { state.Put("error", fmt.Errorf("Error saving debug key: %s", err)) return multistep.ActionHalt } // Chmod it so that it is SSH ready if runtime.GOOS != "windows" { if err := f.Chmod(0600); err != nil { state.Put("error", fmt.Errorf("Error setting permissions of debug key: %s", err)) return multistep.ActionHalt } } } return multistep.ActionContinue }
func NewConfig(raws ...interface{}) (*Config, []string, error) { c := new(Config) var md mapstructure.Metadata err := config.Decode(c, &config.DecodeOpts{ Metadata: &md, Interpolate: true, InterpolateContext: &c.ctx, InterpolateFilter: &interpolate.RenderFilter{ Exclude: []string{ "run_command", }, }, }, raws...) if err != nil { return nil, nil, err } // Defaults if c.APIToken == "" { // Default to environment variable for api_token, if it exists c.APIToken = os.Getenv("DIGITALOCEAN_API_TOKEN") } if c.SnapshotName == "" { def, err := interpolate.Render("packer-{{timestamp}}", nil) if err != nil { panic(err) } // Default to packer-{{ unix timestamp (utc) }} c.SnapshotName = def } if c.DropletName == "" { // Default to packer-[time-ordered-uuid] c.DropletName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()) } if c.Comm.SSHUsername == "" { // Default to "root". You can override this if your // SourceImage has a different user account then the DO default c.Comm.SSHUsername = "******" } if c.StateTimeout == 0 { // Default to 6 minute timeouts waiting for // desired state. i.e waiting for droplet to become active c.StateTimeout = 6 * time.Minute } var errs *packer.MultiError if es := c.Comm.Prepare(&c.ctx); len(es) > 0 { errs = packer.MultiErrorAppend(errs, es...) } if c.APIToken == "" { // Required configurations that will display errors if not set errs = packer.MultiErrorAppend( errs, errors.New("api_token for auth must be specified")) } if c.Region == "" { errs = packer.MultiErrorAppend( errs, errors.New("region is required")) } if c.Size == "" { errs = packer.MultiErrorAppend( errs, errors.New("size is required")) } if c.Image == "" { errs = packer.MultiErrorAppend( errs, errors.New("image is required")) } if errs != nil && len(errs.Errors) > 0 { return nil, nil, errs } common.ScrubConfig(c, c.APIToken) return c, nil, nil }
func NewConfig(raws ...interface{}) (*Config, []string, error) { c := new(Config) err := config.Decode(c, &config.DecodeOpts{ Interpolate: true, InterpolateContext: &c.ctx, InterpolateFilter: &interpolate.RenderFilter{ Exclude: []string{ "run_command", }, }, }, raws...) if err != nil { return nil, nil, err } var errs *packer.MultiError // Set defaults. if c.Network == "" { c.Network = "default" } if c.DiskSizeGb == 0 { c.DiskSizeGb = 10 } if c.ImageDescription == "" { c.ImageDescription = "Created by Packer" } if c.ImageName == "" { img, err := interpolate.Render("packer-{{timestamp}}", nil) if err != nil { errs = packer.MultiErrorAppend(errs, fmt.Errorf("Unable to parse image name: %s ", err)) c.ImageName = img } } if c.InstanceName == "" { c.InstanceName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()) } if c.DiskName == "" { c.DiskName = c.InstanceName } if c.MachineType == "" { c.MachineType = "n1-standard-1" } if c.RawStateTimeout == "" { c.RawStateTimeout = "5m" } if c.Comm.SSHUsername == "" { c.Comm.SSHUsername = "******" } if es := c.Comm.Prepare(&c.ctx); len(es) > 0 { errs = packer.MultiErrorAppend(errs, es...) } // Process required parameters. if c.ProjectId == "" { errs = packer.MultiErrorAppend( errs, errors.New("a project_id must be specified")) } if c.SourceImage == "" { errs = packer.MultiErrorAppend( errs, errors.New("a source_image must be specified")) } if c.Zone == "" { errs = packer.MultiErrorAppend( errs, errors.New("a zone must be specified")) } stateTimeout, err := time.ParseDuration(c.RawStateTimeout) if err != nil { errs = packer.MultiErrorAppend( errs, fmt.Errorf("Failed parsing state_timeout: %s", err)) } c.stateTimeout = stateTimeout if c.AccountFile != "" { if err := processAccountFile(&c.account, c.AccountFile); err != nil { errs = packer.MultiErrorAppend(errs, err) } } // Check for any errors. if errs != nil && len(errs.Errors) > 0 { return nil, nil, errs } return c, nil, nil }
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { err := config.Decode(&b.config, &config.DecodeOpts{ Interpolate: true, }, raws...) if err != nil { return nil, err } // Optional configuration with defaults if b.config.APIKey == "" { // Default to environment variable for api_key, if it exists b.config.APIKey = os.Getenv("DIGITALOCEAN_API_KEY") } if b.config.ClientID == "" { // Default to environment variable for client_id, if it exists b.config.ClientID = os.Getenv("DIGITALOCEAN_CLIENT_ID") } if b.config.APIURL == "" { // Default to environment variable for api_url, if it exists b.config.APIURL = os.Getenv("DIGITALOCEAN_API_URL") } if b.config.APIToken == "" { // Default to environment variable for api_token, if it exists b.config.APIToken = os.Getenv("DIGITALOCEAN_API_TOKEN") } if b.config.Region == "" { if b.config.RegionID != 0 { b.config.Region = fmt.Sprintf("%v", b.config.RegionID) } else { b.config.Region = DefaultRegion } } if b.config.Size == "" { if b.config.SizeID != 0 { b.config.Size = fmt.Sprintf("%v", b.config.SizeID) } else { b.config.Size = DefaultSize } } if b.config.Image == "" { if b.config.ImageID != 0 { b.config.Image = fmt.Sprintf("%v", b.config.ImageID) } else { b.config.Image = DefaultImage } } if b.config.SnapshotName == "" { // Default to packer-{{ unix timestamp (utc) }} b.config.SnapshotName = "packer-{{timestamp}}" } if b.config.DropletName == "" { // Default to packer-[time-ordered-uuid] b.config.DropletName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()) } if b.config.SSHUsername == "" { // Default to "root". You can override this if your // SourceImage has a different user account then the DO default b.config.SSHUsername = "******" } if b.config.SSHPort == 0 { // Default to port 22 per DO default b.config.SSHPort = 22 } if b.config.RawSSHTimeout == "" { // Default to 1 minute timeouts b.config.RawSSHTimeout = "1m" } if b.config.RawStateTimeout == "" { // Default to 6 minute timeouts waiting for // desired state. i.e waiting for droplet to become active b.config.RawStateTimeout = "6m" } var errs *packer.MultiError if b.config.APIToken == "" { // Required configurations that will display errors if not set if b.config.ClientID == "" { errs = packer.MultiErrorAppend( errs, errors.New("a client_id for v1 auth or api_token for v2 auth must be specified")) } if b.config.APIKey == "" { errs = packer.MultiErrorAppend( errs, errors.New("a api_key for v1 auth or api_token for v2 auth must be specified")) } } if b.config.APIURL == "" { b.config.APIURL = "https://api.digitalocean.com" } sshTimeout, err := time.ParseDuration(b.config.RawSSHTimeout) if err != nil { errs = packer.MultiErrorAppend( errs, fmt.Errorf("Failed parsing ssh_timeout: %s", err)) } b.config.sshTimeout = sshTimeout stateTimeout, err := time.ParseDuration(b.config.RawStateTimeout) if err != nil { errs = packer.MultiErrorAppend( errs, fmt.Errorf("Failed parsing state_timeout: %s", err)) } b.config.stateTimeout = stateTimeout if errs != nil && len(errs.Errors) > 0 { return nil, errs } common.ScrubConfig(b.config, b.config.ClientID, b.config.APIKey) return nil, nil }
func (s *stepCreateSSHKeyPair) Run(state multistep.StateBag) multistep.StepAction { client := state.Get("client").(*gopherstack.CloudstackClient) ui := state.Get("ui").(packer.Ui) c := state.Get("config").(config) // If we have a password specified, just continue instead. if c.SSHPassword != "" { state.Put("ssh_private_key", "") state.Put("ssh_key_name", "") return multistep.ActionContinue } // If we already have a private key for a pre loaded public // key on the base image we load that instead of creating a // SSH key pair. if c.SSHKeyPath != "" { ui.Say("Reading in SSH private key from local disk") f, err := os.Open(c.SSHKeyPath) if err != nil { state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } defer f.Close() keyBytes, err := ioutil.ReadAll(f) if err != nil { state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } state.Put("ssh_private_key", string(keyBytes)) state.Put("ssh_key_name", "") return multistep.ActionContinue } ui.Say("Creating temporary SSH key for virtual machine...") // The name of the public key on Cloudstack name := fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()) // Create the key! response, err := client.CreateSSHKeyPair(name) if err != nil { err := fmt.Errorf("Error creating temporary SSH key: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } s.keyName = name s.privateKey = response.Createsshkeypairresponse.Keypair.Privatekey log.Printf("temporary ssh key name: %s", name) // Remember some state for the future state.Put("ssh_key_name", name) state.Put("ssh_private_key", s.privateKey) return multistep.ActionContinue }
func (c *RunConfig) Prepare(ctx *interpolate.Context) []error { // Defaults if c.SSHPort == 0 { c.SSHPort = 22 } if c.RawSSHTimeout == "" { c.RawSSHTimeout = "5m" } if c.TemporaryKeyPairName == "" { c.TemporaryKeyPairName = fmt.Sprintf( "packer %s", uuid.TimeOrderedUUID()) } // Validation var errs []error if c.SourceAmi == "" { errs = append(errs, errors.New("A source_ami must be specified")) } if c.InstanceType == "" { errs = append(errs, errors.New("An instance_type must be specified")) } if c.SpotPrice == "auto" { if c.SpotPriceAutoProduct == "" { errs = append(errs, errors.New( "spot_price_auto_product must be specified when spot_price is auto")) } } if c.SSHUsername == "" { errs = append(errs, errors.New("An ssh_username must be specified")) } if c.UserData != "" && c.UserDataFile != "" { errs = append(errs, fmt.Errorf("Only one of user_data or user_data_file can be specified.")) } else if c.UserDataFile != "" { if _, err := os.Stat(c.UserDataFile); err != nil { errs = append(errs, fmt.Errorf("user_data_file not found: %s", c.UserDataFile)) } } if c.SecurityGroupId != "" { if len(c.SecurityGroupIds) > 0 { errs = append(errs, fmt.Errorf("Only one of security_group_id or security_group_ids can be specified.")) } else { c.SecurityGroupIds = []string{c.SecurityGroupId} c.SecurityGroupId = "" } } var err error c.sshTimeout, err = time.ParseDuration(c.RawSSHTimeout) if err != nil { errs = append(errs, fmt.Errorf("Failed parsing ssh_timeout: %s", err)) } return errs }