From 28712b2648c78086da4f0b8c91139c240124c892 Mon Sep 17 00:00:00 2001 From: Matt Whiteley Date: Wed, 2 Oct 2013 10:52:16 -0700 Subject: [PATCH] builder/amazon: instances can be launched with a list of security groups --- builder/amazon/common/run_config.go | 50 ++++++++++++++----- .../amazon/common/step_run_source_instance.go | 9 +++- builder/amazon/common/step_security_group.go | 14 +++--- builder/amazon/ebs/builder.go | 6 +-- builder/amazon/instance/builder.go | 6 +-- .../docs/builders/amazon-ebs.html.markdown | 4 ++ .../builders/amazon-instance.html.markdown | 4 ++ 7 files changed, 65 insertions(+), 28 deletions(-) diff --git a/builder/amazon/common/run_config.go b/builder/amazon/common/run_config.go index b21999260..60dfbd185 100644 --- a/builder/amazon/common/run_config.go +++ b/builder/amazon/common/run_config.go @@ -11,18 +11,19 @@ import ( // RunConfig contains configuration for running an instance from a source // AMI and details on how to access that launched image. type RunConfig struct { - SourceAmi string `mapstructure:"source_ami"` - IamInstanceProfile string `mapstructure:"iam_instance_profile"` - InstanceType string `mapstructure:"instance_type"` - UserData string `mapstructure:"user_data"` - UserDataFile string `mapstructure:"user_data_file"` - RawSSHTimeout string `mapstructure:"ssh_timeout"` - SSHUsername string `mapstructure:"ssh_username"` - SSHPort int `mapstructure:"ssh_port"` - SecurityGroupId string `mapstructure:"security_group_id"` - SubnetId string `mapstructure:"subnet_id"` - TemporaryKeyPairName string `mapstructure:"temporary_key_pair_name"` - VpcId string `mapstructure:"vpc_id"` + SourceAmi string `mapstructure:"source_ami"` + IamInstanceProfile string `mapstructure:"iam_instance_profile"` + InstanceType string `mapstructure:"instance_type"` + UserData string `mapstructure:"user_data"` + UserDataFile string `mapstructure:"user_data_file"` + RawSSHTimeout string `mapstructure:"ssh_timeout"` + SSHUsername string `mapstructure:"ssh_username"` + SSHPort int `mapstructure:"ssh_port"` + SecurityGroupId string `mapstructure:"security_group_id"` + SecurityGroupIds []string `mapstructure:"security_group_ids"` + SubnetId string `mapstructure:"subnet_id"` + TemporaryKeyPairName string `mapstructure:"temporary_key_pair_name"` + VpcId string `mapstructure:"vpc_id"` // Unexported fields that are calculated from others sshTimeout time.Duration @@ -73,11 +74,19 @@ func (c *RunConfig) Prepare(t *packer.ConfigTemplate) []error { } } + 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 = "" + } + } + templates := map[string]*string{ "iam_instance_profile": &c.IamInstanceProfile, "instance_type": &c.InstanceType, "ssh_timeout": &c.RawSSHTimeout, - "security_group_id": &c.SecurityGroupId, "ssh_username": &c.SSHUsername, "source_ami": &c.SourceAmi, "subnet_id": &c.SubnetId, @@ -94,6 +103,21 @@ func (c *RunConfig) Prepare(t *packer.ConfigTemplate) []error { } } + sliceTemplates := map[string][]string{ + "security_group_ids": c.SecurityGroupIds, + } + + for n, slice := range sliceTemplates { + for i, elem := range slice { + var err error + slice[i], err = t.Process(elem, nil) + if err != nil { + errs = append( + errs, fmt.Errorf("Error processing %s[%d]: %s", n, i, err)) + } + } + } + c.sshTimeout, err = time.ParseDuration(c.RawSSHTimeout) if err != nil { errs = append(errs, fmt.Errorf("Failed parsing ssh_timeout: %s", err)) diff --git a/builder/amazon/common/step_run_source_instance.go b/builder/amazon/common/step_run_source_instance.go index 4aeab217c..b2785a947 100644 --- a/builder/amazon/common/step_run_source_instance.go +++ b/builder/amazon/common/step_run_source_instance.go @@ -26,7 +26,7 @@ type StepRunSourceInstance struct { func (s *StepRunSourceInstance) Run(state multistep.StateBag) multistep.StepAction { ec2conn := state.Get("ec2").(*ec2.EC2) keyName := state.Get("keyPair").(string) - securityGroupId := state.Get("securityGroupId").(string) + securityGroupIds := state.Get("securityGroupIds").([]string) ui := state.Get("ui").(packer.Ui) userData := s.UserData @@ -40,6 +40,11 @@ func (s *StepRunSourceInstance) Run(state multistep.StateBag) multistep.StepActi userData = string(contents) } + securityGroups := make([]ec2.SecurityGroup, len(securityGroupIds)) + for n, securityGroupId := range securityGroupIds { + securityGroups[n] = ec2.SecurityGroup{Id: securityGroupId} + } + runOpts := &ec2.RunInstances{ KeyName: keyName, ImageId: s.SourceAMI, @@ -47,7 +52,7 @@ func (s *StepRunSourceInstance) Run(state multistep.StateBag) multistep.StepActi UserData: []byte(userData), MinCount: 0, MaxCount: 0, - SecurityGroups: []ec2.SecurityGroup{ec2.SecurityGroup{Id: securityGroupId}}, + SecurityGroups: securityGroups, IamInstanceProfile: s.IamInstanceProfile, SubnetId: s.SubnetId, BlockDevices: s.BlockDevices.BuildLaunchDevices(), diff --git a/builder/amazon/common/step_security_group.go b/builder/amazon/common/step_security_group.go index 0f52548df..be05c9915 100644 --- a/builder/amazon/common/step_security_group.go +++ b/builder/amazon/common/step_security_group.go @@ -12,9 +12,9 @@ import ( ) type StepSecurityGroup struct { - SecurityGroupId string - SSHPort int - VpcId string + SecurityGroupIds []string + SSHPort int + VpcId string createdGroupId string } @@ -23,9 +23,9 @@ func (s *StepSecurityGroup) Run(state multistep.StateBag) multistep.StepAction { ec2conn := state.Get("ec2").(*ec2.EC2) ui := state.Get("ui").(packer.Ui) - if s.SecurityGroupId != "" { - log.Printf("Using specified security group: %s", s.SecurityGroupId) - state.Put("securityGroupId", s.SecurityGroupId) + if len(s.SecurityGroupIds) > 0 { + log.Printf("Using specified security groups: %v", s.SecurityGroupIds) + state.Put("securityGroupIds", s.SecurityGroupIds) return multistep.ActionContinue } @@ -70,7 +70,7 @@ func (s *StepSecurityGroup) Run(state multistep.StateBag) multistep.StepAction { } // Set some state data for use in future steps - state.Put("securityGroupId", s.createdGroupId) + state.Put("securityGroupIds", []string{s.createdGroupId}) return multistep.ActionContinue } diff --git a/builder/amazon/ebs/builder.go b/builder/amazon/ebs/builder.go index 194e10bc9..b7d775be9 100644 --- a/builder/amazon/ebs/builder.go +++ b/builder/amazon/ebs/builder.go @@ -88,9 +88,9 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe KeyPairName: b.config.TemporaryKeyPairName, }, &awscommon.StepSecurityGroup{ - SecurityGroupId: b.config.SecurityGroupId, - SSHPort: b.config.SSHPort, - VpcId: b.config.VpcId, + SecurityGroupIds: b.config.SecurityGroupIds, + SSHPort: b.config.SSHPort, + VpcId: b.config.VpcId, }, &awscommon.StepRunSourceInstance{ Debug: b.config.PackerDebug, diff --git a/builder/amazon/instance/builder.go b/builder/amazon/instance/builder.go index 44691ecee..1748097de 100644 --- a/builder/amazon/instance/builder.go +++ b/builder/amazon/instance/builder.go @@ -191,9 +191,9 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe KeyPairName: b.config.TemporaryKeyPairName, }, &awscommon.StepSecurityGroup{ - SecurityGroupId: b.config.SecurityGroupId, - SSHPort: b.config.SSHPort, - VpcId: b.config.VpcId, + SecurityGroupIds: b.config.SecurityGroupIds, + SSHPort: b.config.SSHPort, + VpcId: b.config.VpcId, }, &awscommon.StepRunSourceInstance{ Debug: b.config.PackerDebug, diff --git a/website/source/docs/builders/amazon-ebs.html.markdown b/website/source/docs/builders/amazon-ebs.html.markdown index 7248a2e2d..955b5d186 100644 --- a/website/source/docs/builders/amazon-ebs.html.markdown +++ b/website/source/docs/builders/amazon-ebs.html.markdown @@ -97,6 +97,10 @@ Optional: access. Note that if this is specified, you must be sure the security group allows access to the `ssh_port` given below. +* `security_group_ids` (array of string) - A list of security groups as + described above. Note that if this is specified, you must omit the + security_group_id. + * `ssh_port` (int) - The port that SSH will be available on. This defaults to port 22. diff --git a/website/source/docs/builders/amazon-instance.html.markdown b/website/source/docs/builders/amazon-instance.html.markdown index a2b3b4d1a..d3df44d2c 100644 --- a/website/source/docs/builders/amazon-instance.html.markdown +++ b/website/source/docs/builders/amazon-instance.html.markdown @@ -129,6 +129,10 @@ Optional: access. Note that if this is specified, you must be sure the security group allows access to the `ssh_port` given below. +* `security_group_ids` (array of string) - A list of security groups as + described above. Note that if this is specified, you must omit the + security_group_id. + * `ssh_port` (int) - The port that SSH will be available on. This defaults to port 22.