コード例 #1
0
ファイル: provisioner.go プロジェクト: arizvisa/packer
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
}
コード例 #2
0
ファイル: provisioner.go プロジェクト: dkhenry/packer
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
}
コード例 #3
0
ファイル: cp.go プロジェクト: markpeek/winrmcp
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
}
コード例 #4
0
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

}
コード例 #5
0
ファイル: step_create_droplet.go プロジェクト: reoring/packer
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
}
コード例 #6
0
ファイル: run_config.go プロジェクト: threatstream/packer
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
}
コード例 #7
0
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
}
コード例 #8
0
ファイル: step_key_pair.go プロジェクト: JNPRAutomate/packer
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
}
コード例 #9
0
// 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
}
コード例 #10
0
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
}
コード例 #11
0
ファイル: run_config.go プロジェクト: cewood/packer
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
}
コード例 #12
0
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
}
コード例 #13
0
ファイル: step_create_ssh_key.go プロジェクト: Nitron/packer
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
}
コード例 #14
0
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
}
コード例 #15
0
ファイル: config.go プロジェクト: JNPRAutomate/packer
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
}
コード例 #16
0
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
}
コード例 #17
0
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
}
コード例 #18
0
ファイル: builder.go プロジェクト: johnbellone/packer
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
}
コード例 #19
0
ファイル: funcs.go プロジェクト: henrysher/packer
func funcGenUuid(ctx *Context) interface{} {
	return func() string {
		return uuid.TimeOrderedUUID()
	}
}
コード例 #20
0
ファイル: provisioner.go プロジェクト: monkeylittleinc/packer
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
}
コード例 #21
0
ファイル: step_key_pair.go プロジェクト: rodm/packer
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
}
コード例 #22
0
ファイル: config.go プロジェクト: svanharmelen/packer
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
}
コード例 #23
0
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
}
コード例 #24
0
func templateUuid() string {
	return uuid.TimeOrderedUUID()
}
コード例 #25
0
ファイル: step_create_ssh_key.go プロジェクト: cewood/packer
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
}
コード例 #26
0
ファイル: config.go プロジェクト: c12simple/packer
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
}
コード例 #27
0
ファイル: config.go プロジェクト: c12simple/packer
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
}
コード例 #28
0
ファイル: builder.go プロジェクト: henrysher/packer
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
}
コード例 #29
0
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
}
コード例 #30
0
ファイル: run_config.go プロジェクト: henrysher/packer
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
}