From ee9ea170af5f1ec13979846a0d1320177c56284c Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 12 Dec 2013 16:41:44 -0800 Subject: [PATCH] builder/googlecompute: move config out to seperate file --- builder/googlecompute/builder.go | 158 +-------------- builder/googlecompute/config.go | 187 ++++++++++++++++++ builder/googlecompute/ssh.go | 4 +- builder/googlecompute/step_create_image.go | 2 +- builder/googlecompute/step_create_instance.go | 4 +- builder/googlecompute/step_instance_info.go | 2 +- builder/googlecompute/step_register_image.go | 2 +- builder/googlecompute/step_update_gsutil.go | 2 +- builder/googlecompute/step_upload_image.go | 2 +- 9 files changed, 202 insertions(+), 161 deletions(-) create mode 100644 builder/googlecompute/config.go diff --git a/builder/googlecompute/builder.go b/builder/googlecompute/builder.go index 3e8bf8c9b..ee551dd71 100644 --- a/builder/googlecompute/builder.go +++ b/builder/googlecompute/builder.go @@ -3,8 +3,6 @@ package googlecompute import ( - "errors" - "fmt" "log" "time" @@ -18,163 +16,19 @@ const BuilderId = "packer.googlecompute" // Builder represents a Packer Builder. type Builder struct { - config config + config *Config runner multistep.Runner } -// config holds the googlecompute builder configuration settings. -type config struct { - BucketName string `mapstructure:"bucket_name"` - ClientSecretsFile string `mapstructure:"client_secrets_file"` - ImageName string `mapstructure:"image_name"` - ImageDescription string `mapstructure:"image_description"` - MachineType string `mapstructure:"machine_type"` - Metadata map[string]string `mapstructure:"metadata"` - Network string `mapstructure:"network"` - Passphrase string `mapstructure:"passphrase"` - PrivateKeyFile string `mapstructure:"private_key_file"` - ProjectId string `mapstructure:"project_id"` - SourceImage string `mapstructure:"source_image"` - SSHUsername string `mapstructure:"ssh_username"` - SSHPort uint `mapstructure:"ssh_port"` - RawSSHTimeout string `mapstructure:"ssh_timeout"` - RawStateTimeout string `mapstructure:"state_timeout"` - Tags []string `mapstructure:"tags"` - Zone string `mapstructure:"zone"` - clientSecrets *clientSecrets - common.PackerConfig `mapstructure:",squash"` - instanceName string - privateKeyBytes []byte - sshTimeout time.Duration - stateTimeout time.Duration - tpl *packer.ConfigTemplate -} - // Prepare processes the build configuration parameters. func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { - // Load the packer config. - md, err := common.DecodeConfig(&b.config, raws...) - if err != nil { - return nil, err + c, warnings, errs := NewConfig(raws...) + if errs != nil { + return warnings, errs } - b.config.tpl, err = packer.NewConfigTemplate() - if err != nil { - return nil, err - } - b.config.tpl.UserVars = b.config.PackerUserVars + b.config = c - errs := common.CheckUnusedConfig(md) - // Collect errors if any. - if err := common.CheckUnusedConfig(md); err != nil { - return nil, err - } - // Set defaults. - if b.config.Network == "" { - b.config.Network = "default" - } - if b.config.ImageDescription == "" { - b.config.ImageDescription = "Created by Packer" - } - if b.config.ImageName == "" { - // Default to packer-{{ unix timestamp (utc) }} - b.config.ImageName = "packer-{{timestamp}}" - } - if b.config.MachineType == "" { - b.config.MachineType = "n1-standard-1" - } - if b.config.RawSSHTimeout == "" { - b.config.RawSSHTimeout = "5m" - } - if b.config.RawStateTimeout == "" { - b.config.RawStateTimeout = "5m" - } - if b.config.SSHUsername == "" { - b.config.SSHUsername = "root" - } - if b.config.SSHPort == 0 { - b.config.SSHPort = 22 - } - // Process Templates - templates := map[string]*string{ - "bucket_name": &b.config.BucketName, - "client_secrets_file": &b.config.ClientSecretsFile, - "image_name": &b.config.ImageName, - "image_description": &b.config.ImageDescription, - "machine_type": &b.config.MachineType, - "network": &b.config.Network, - "passphrase": &b.config.Passphrase, - "private_key_file": &b.config.PrivateKeyFile, - "project_id": &b.config.ProjectId, - "source_image": &b.config.SourceImage, - "ssh_username": &b.config.SSHUsername, - "ssh_timeout": &b.config.RawSSHTimeout, - "state_timeout": &b.config.RawStateTimeout, - "zone": &b.config.Zone, - } - 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)) - } - } - // Process required parameters. - if b.config.BucketName == "" { - errs = packer.MultiErrorAppend( - errs, errors.New("a bucket_name must be specified")) - } - if b.config.ClientSecretsFile == "" { - errs = packer.MultiErrorAppend( - errs, errors.New("a client_secrets_file must be specified")) - } - if b.config.PrivateKeyFile == "" { - errs = packer.MultiErrorAppend( - errs, errors.New("a private_key_file must be specified")) - } - if b.config.ProjectId == "" { - errs = packer.MultiErrorAppend( - errs, errors.New("a project_id must be specified")) - } - if b.config.SourceImage == "" { - errs = packer.MultiErrorAppend( - errs, errors.New("a source_image must be specified")) - } - if b.config.Zone == "" { - errs = packer.MultiErrorAppend( - errs, errors.New("a zone must be specified")) - } - // Process timeout settings. - 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 - // Load the client secrets file. - cs, err := loadClientSecrets(b.config.ClientSecretsFile) - if err != nil { - errs = packer.MultiErrorAppend( - errs, fmt.Errorf("Failed parsing client secrets file: %s", err)) - } - b.config.clientSecrets = cs - // Load the private key. - b.config.privateKeyBytes, err = processPrivateKeyFile(b.config.PrivateKeyFile, b.config.Passphrase) - if err != nil { - errs = packer.MultiErrorAppend( - errs, fmt.Errorf("Failed loading private key file: %s", err)) - } - // Check for any errors. - if errs != nil && len(errs.Errors) > 0 { - return nil, errs - } - return nil, nil + return warnings, nil } // Run executes a googlecompute Packer build and returns a packer.Artifact diff --git a/builder/googlecompute/config.go b/builder/googlecompute/config.go new file mode 100644 index 000000000..29d69144d --- /dev/null +++ b/builder/googlecompute/config.go @@ -0,0 +1,187 @@ +package googlecompute + +import ( + "errors" + "fmt" + "time" + + "github.com/mitchellh/packer/common" + "github.com/mitchellh/packer/packer" +) + +// Config is the configuration structure for the GCE builder. It stores +// both the publicly settable state as well as the privately generated +// state of the config object. +type Config struct { + common.PackerConfig `mapstructure:",squash"` + + BucketName string `mapstructure:"bucket_name"` + ClientSecretsFile string `mapstructure:"client_secrets_file"` + ImageName string `mapstructure:"image_name"` + ImageDescription string `mapstructure:"image_description"` + MachineType string `mapstructure:"machine_type"` + Metadata map[string]string `mapstructure:"metadata"` + Network string `mapstructure:"network"` + Passphrase string `mapstructure:"passphrase"` + PrivateKeyFile string `mapstructure:"private_key_file"` + ProjectId string `mapstructure:"project_id"` + SourceImage string `mapstructure:"source_image"` + SSHUsername string `mapstructure:"ssh_username"` + SSHPort uint `mapstructure:"ssh_port"` + RawSSHTimeout string `mapstructure:"ssh_timeout"` + RawStateTimeout string `mapstructure:"state_timeout"` + Tags []string `mapstructure:"tags"` + Zone string `mapstructure:"zone"` + + clientSecrets *clientSecrets + instanceName string + privateKeyBytes []byte + sshTimeout time.Duration + stateTimeout time.Duration + tpl *packer.ConfigTemplate +} + +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.ImageDescription == "" { + c.ImageDescription = "Created by Packer" + } + + if c.ImageName == "" { + c.ImageName = "packer-{{timestamp}}" + } + + 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 = "root" + } + + if c.SSHPort == 0 { + c.SSHPort = 22 + } + + // Process Templates + templates := map[string]*string{ + "bucket_name": &c.BucketName, + "client_secrets_file": &c.ClientSecretsFile, + "image_name": &c.ImageName, + "image_description": &c.ImageDescription, + "machine_type": &c.MachineType, + "network": &c.Network, + "passphrase": &c.Passphrase, + "private_key_file": &c.PrivateKeyFile, + "project_id": &c.ProjectId, + "source_image": &c.SourceImage, + "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.ClientSecretsFile == "" { + errs = packer.MultiErrorAppend( + errs, errors.New("a client_secrets_file must be specified")) + } + + if c.PrivateKeyFile == "" { + errs = packer.MultiErrorAppend( + errs, errors.New("a private_key_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 + + // Load the client secrets file. + cs, err := loadClientSecrets(c.ClientSecretsFile) + if err != nil { + errs = packer.MultiErrorAppend( + errs, fmt.Errorf("Failed parsing client secrets file: %s", err)) + } + c.clientSecrets = cs + + // Load the private key. + c.privateKeyBytes, err = processPrivateKeyFile(c.PrivateKeyFile, c.Passphrase) + if err != nil { + errs = packer.MultiErrorAppend( + errs, fmt.Errorf("Failed loading private key file: %s", err)) + } + + // Check for any errors. + if errs != nil && len(errs.Errors) > 0 { + return nil, nil, errs + } + + return c, nil, nil +} diff --git a/builder/googlecompute/ssh.go b/builder/googlecompute/ssh.go index ddfcab2de..77f226959 100644 --- a/builder/googlecompute/ssh.go +++ b/builder/googlecompute/ssh.go @@ -10,14 +10,14 @@ import ( // sshAddress returns the ssh address. func sshAddress(state multistep.StateBag) (string, error) { - config := state.Get("config").(config) + config := state.Get("config").(*Config) ipAddress := state.Get("instance_ip").(string) return fmt.Sprintf("%s:%d", ipAddress, config.SSHPort), nil } // sshConfig returns the ssh configuration. func sshConfig(state multistep.StateBag) (*gossh.ClientConfig, error) { - config := state.Get("config").(config) + config := state.Get("config").(*Config) privateKey := state.Get("ssh_private_key").(string) keyring := new(ssh.SimpleKeychain) diff --git a/builder/googlecompute/step_create_image.go b/builder/googlecompute/step_create_image.go index c23c7c445..1b964a48e 100644 --- a/builder/googlecompute/step_create_image.go +++ b/builder/googlecompute/step_create_image.go @@ -18,7 +18,7 @@ type stepCreateImage int // command on the running GCE instance. func (s *stepCreateImage) Run(state multistep.StateBag) multistep.StepAction { var ( - config = state.Get("config").(config) + config = state.Get("config").(*Config) comm = state.Get("communicator").(packer.Communicator) sudoPrefix = "" ui = state.Get("ui").(packer.Ui) diff --git a/builder/googlecompute/step_create_instance.go b/builder/googlecompute/step_create_instance.go index b9cb3dbb0..930403f06 100644 --- a/builder/googlecompute/step_create_instance.go +++ b/builder/googlecompute/step_create_instance.go @@ -18,7 +18,7 @@ type stepCreateInstance struct { func (s *stepCreateInstance) Run(state multistep.StateBag) multistep.StepAction { var ( client = state.Get("client").(*GoogleComputeClient) - config = state.Get("config").(config) + config = state.Get("config").(*Config) ui = state.Get("ui").(packer.Ui) ) ui.Say("Creating instance...") @@ -106,7 +106,7 @@ func (s *stepCreateInstance) Run(state multistep.StateBag) multistep.StepAction func (s *stepCreateInstance) Cleanup(state multistep.StateBag) { var ( client = state.Get("client").(*GoogleComputeClient) - config = state.Get("config").(config) + config = state.Get("config").(*Config) ui = state.Get("ui").(packer.Ui) ) if s.instanceName == "" { diff --git a/builder/googlecompute/step_instance_info.go b/builder/googlecompute/step_instance_info.go index b115d97c8..b68b011b2 100644 --- a/builder/googlecompute/step_instance_info.go +++ b/builder/googlecompute/step_instance_info.go @@ -14,7 +14,7 @@ type stepInstanceInfo int func (s *stepInstanceInfo) Run(state multistep.StateBag) multistep.StepAction { var ( client = state.Get("client").(*GoogleComputeClient) - config = state.Get("config").(config) + config = state.Get("config").(*Config) ui = state.Get("ui").(packer.Ui) ) instanceName := state.Get("instance_name").(string) diff --git a/builder/googlecompute/step_register_image.go b/builder/googlecompute/step_register_image.go index 8ff0ce8e8..5e8087921 100644 --- a/builder/googlecompute/step_register_image.go +++ b/builder/googlecompute/step_register_image.go @@ -14,7 +14,7 @@ type stepRegisterImage int func (s *stepRegisterImage) Run(state multistep.StateBag) multistep.StepAction { var ( client = state.Get("client").(*GoogleComputeClient) - config = state.Get("config").(config) + config = state.Get("config").(*Config) ui = state.Get("ui").(packer.Ui) ) ui.Say("Adding image to the project...") diff --git a/builder/googlecompute/step_update_gsutil.go b/builder/googlecompute/step_update_gsutil.go index bc697e0ee..d2e8be741 100644 --- a/builder/googlecompute/step_update_gsutil.go +++ b/builder/googlecompute/step_update_gsutil.go @@ -19,7 +19,7 @@ type stepUpdateGsutil int // prompt to update gsutil if a newer version is available. func (s *stepUpdateGsutil) Run(state multistep.StateBag) multistep.StepAction { var ( - config = state.Get("config").(config) + config = state.Get("config").(*Config) comm = state.Get("communicator").(packer.Communicator) sudoPrefix = "" ui = state.Get("ui").(packer.Ui) diff --git a/builder/googlecompute/step_upload_image.go b/builder/googlecompute/step_upload_image.go index 7cb0c9769..956b981bc 100644 --- a/builder/googlecompute/step_upload_image.go +++ b/builder/googlecompute/step_upload_image.go @@ -13,7 +13,7 @@ type stepUploadImage int // Run executes the Packer build step that uploads a GCE machine image. func (s *stepUploadImage) Run(state multistep.StateBag) multistep.StepAction { var ( - config = state.Get("config").(config) + config = state.Get("config").(*Config) comm = state.Get("communicator").(packer.Communicator) sudoPrefix = "" ui = state.Get("ui").(packer.Ui)