From 72a7123a0bbdd1faf88b35ab307626061d15704b Mon Sep 17 00:00:00 2001 From: Chris Chalfant Date: Mon, 14 Mar 2016 12:54:03 -0400 Subject: [PATCH 1/3] Add option to tell packer not to stop the instance It is sometimes desirable to sysprep a windows machine before creating an EC2 image. The AWS-approved way to do this is to run ec2configservice.exe -sysprep and let ec2configservice shut down the instance. This change adds an option to disable the stop instance call issued by packer so that the user can control when the machine is stopped. --- builder/amazon/common/run_config.go | 3 ++- builder/amazon/ebs/builder.go | 5 ++++- builder/amazon/ebs/step_stop_instance.go | 27 ++++++++++++++---------- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/builder/amazon/common/run_config.go b/builder/amazon/common/run_config.go index 307a177ed..f5e237257 100644 --- a/builder/amazon/common/run_config.go +++ b/builder/amazon/common/run_config.go @@ -23,7 +23,8 @@ type RunConfig struct { SourceAmi string `mapstructure:"source_ami"` SpotPrice string `mapstructure:"spot_price"` SpotPriceAutoProduct string `mapstructure:"spot_price_auto_product"` - SecurityGroupId string `mapstructure:"security_group_id"` + DisableStopInstance bool `mapstructure:"disable_stop_instance"` + SecurityGroupId string `mapstructure:"security_group_id"` SecurityGroupIds []string `mapstructure:"security_group_ids"` SubnetId string `mapstructure:"subnet_id"` TemporaryKeyPairName string `mapstructure:"temporary_key_pair_name"` diff --git a/builder/amazon/ebs/builder.go b/builder/amazon/ebs/builder.go index d8e8cea28..ebf496f34 100644 --- a/builder/amazon/ebs/builder.go +++ b/builder/amazon/ebs/builder.go @@ -150,7 +150,10 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe b.config.RunConfig.Comm.SSHUsername), }, &common.StepProvision{}, - &stepStopInstance{SpotPrice: b.config.SpotPrice}, + &stepStopInstance{ + SpotPrice: b.config.SpotPrice, + DisableStopInstance: b.config.DisableStopInstance, + }, // TODO(mitchellh): verify works with spots &stepModifyInstance{}, &awscommon.StepDeregisterAMI{ diff --git a/builder/amazon/ebs/step_stop_instance.go b/builder/amazon/ebs/step_stop_instance.go index d6f135368..b536aaf1b 100644 --- a/builder/amazon/ebs/step_stop_instance.go +++ b/builder/amazon/ebs/step_stop_instance.go @@ -11,6 +11,7 @@ import ( type stepStopInstance struct { SpotPrice string + DisableStopInstance bool } func (s *stepStopInstance) Run(state multistep.StateBag) multistep.StepAction { @@ -23,17 +24,21 @@ func (s *stepStopInstance) Run(state multistep.StateBag) multistep.StepAction { return multistep.ActionContinue } - // Stop the instance so we can create an AMI from it - ui.Say("Stopping the source instance...") - _, err := ec2conn.StopInstances(&ec2.StopInstancesInput{ - InstanceIds: []*string{instance.InstanceId}, - }) - if err != nil { - err := fmt.Errorf("Error stopping instance: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } + var err error + + if s.DisableStopInstance == false { + // Stop the instance so we can create an AMI from it + ui.Say("Stopping the source instance...") + _, err = ec2conn.StopInstances(&ec2.StopInstancesInput{ + InstanceIds: []*string{instance.InstanceId}, + }) + if err != nil { + err := fmt.Errorf("Error stopping instance: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + } // Wait for the instance to actual stop ui.Say("Waiting for the instance to stop...") From 8163e16e0237d429b6b9ef109f75bf6884e53f85 Mon Sep 17 00:00:00 2001 From: Chris Chalfant Date: Mon, 14 Mar 2016 13:49:42 -0400 Subject: [PATCH 2/3] gofmt code --- builder/amazon/common/run_config.go | 4 +-- builder/amazon/ebs/builder.go | 6 ++--- builder/amazon/ebs/step_stop_instance.go | 32 ++++++++++++------------ 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/builder/amazon/common/run_config.go b/builder/amazon/common/run_config.go index f5e237257..1dbe3fca0 100644 --- a/builder/amazon/common/run_config.go +++ b/builder/amazon/common/run_config.go @@ -23,8 +23,8 @@ type RunConfig struct { SourceAmi string `mapstructure:"source_ami"` SpotPrice string `mapstructure:"spot_price"` SpotPriceAutoProduct string `mapstructure:"spot_price_auto_product"` - DisableStopInstance bool `mapstructure:"disable_stop_instance"` - SecurityGroupId string `mapstructure:"security_group_id"` + DisableStopInstance bool `mapstructure:"disable_stop_instance"` + SecurityGroupId string `mapstructure:"security_group_id"` SecurityGroupIds []string `mapstructure:"security_group_ids"` SubnetId string `mapstructure:"subnet_id"` TemporaryKeyPairName string `mapstructure:"temporary_key_pair_name"` diff --git a/builder/amazon/ebs/builder.go b/builder/amazon/ebs/builder.go index ebf496f34..a4e9ebc5e 100644 --- a/builder/amazon/ebs/builder.go +++ b/builder/amazon/ebs/builder.go @@ -151,9 +151,9 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe }, &common.StepProvision{}, &stepStopInstance{ - SpotPrice: b.config.SpotPrice, - DisableStopInstance: b.config.DisableStopInstance, - }, + SpotPrice: b.config.SpotPrice, + DisableStopInstance: b.config.DisableStopInstance, + }, // TODO(mitchellh): verify works with spots &stepModifyInstance{}, &awscommon.StepDeregisterAMI{ diff --git a/builder/amazon/ebs/step_stop_instance.go b/builder/amazon/ebs/step_stop_instance.go index b536aaf1b..58153f8d8 100644 --- a/builder/amazon/ebs/step_stop_instance.go +++ b/builder/amazon/ebs/step_stop_instance.go @@ -10,8 +10,8 @@ import ( ) type stepStopInstance struct { - SpotPrice string - DisableStopInstance bool + SpotPrice string + DisableStopInstance bool } func (s *stepStopInstance) Run(state multistep.StateBag) multistep.StepAction { @@ -24,21 +24,21 @@ func (s *stepStopInstance) Run(state multistep.StateBag) multistep.StepAction { return multistep.ActionContinue } - var err error + var err error - if s.DisableStopInstance == false { - // Stop the instance so we can create an AMI from it - ui.Say("Stopping the source instance...") - _, err = ec2conn.StopInstances(&ec2.StopInstancesInput{ - InstanceIds: []*string{instance.InstanceId}, - }) - if err != nil { - err := fmt.Errorf("Error stopping instance: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } + if s.DisableStopInstance == false { + // Stop the instance so we can create an AMI from it + ui.Say("Stopping the source instance...") + _, err = ec2conn.StopInstances(&ec2.StopInstancesInput{ + InstanceIds: []*string{instance.InstanceId}, + }) + if err != nil { + err := fmt.Errorf("Error stopping instance: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + } // Wait for the instance to actual stop ui.Say("Waiting for the instance to stop...") From 601b833aaa0056155b596ce5bae67adad1142073 Mon Sep 17 00:00:00 2001 From: Chris Chalfant Date: Tue, 15 Mar 2016 08:01:20 -0400 Subject: [PATCH 3/3] style and documentation changes per PR review comments --- builder/amazon/ebs/step_stop_instance.go | 4 +++- website/source/docs/builders/amazon-ebs.html.md | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/builder/amazon/ebs/step_stop_instance.go b/builder/amazon/ebs/step_stop_instance.go index 58153f8d8..a704406f8 100644 --- a/builder/amazon/ebs/step_stop_instance.go +++ b/builder/amazon/ebs/step_stop_instance.go @@ -26,7 +26,7 @@ func (s *stepStopInstance) Run(state multistep.StateBag) multistep.StepAction { var err error - if s.DisableStopInstance == false { + if !s.DisableStopInstance { // Stop the instance so we can create an AMI from it ui.Say("Stopping the source instance...") _, err = ec2conn.StopInstances(&ec2.StopInstancesInput{ @@ -38,6 +38,8 @@ func (s *stepStopInstance) Run(state multistep.StateBag) multistep.StepAction { ui.Error(err.Error()) return multistep.ActionHalt } + } else { + ui.Say("Automatic instance stop disabled. Please stop instance manually.") } // Wait for the instance to actual stop diff --git a/website/source/docs/builders/amazon-ebs.html.md b/website/source/docs/builders/amazon-ebs.html.md index 863d2791b..539e1b5b8 100644 --- a/website/source/docs/builders/amazon-ebs.html.md +++ b/website/source/docs/builders/amazon-ebs.html.md @@ -116,6 +116,19 @@ builder. - `availability_zone` (string) - Destination availability zone to launch instance in. Leave this empty to allow Amazon to auto-assign. +- `disable_stop_instance` (boolean) - Packer normally stops the build instance + after all provisioners have run. For Windows instances, it is sometimes + desirable to [run Sysprep](http://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ami-create-standard.html) + which will stop the instance for you. If this is set to true, Packer *will not* + stop the instance and will wait for you to stop it manually. You can do this + with a [windows-shell provisioner](https://www.packer.io/docs/provisioners/windows-shell.html). + + ``` {.javascript} + { + "type": "windows-shell", + "inline": ["\"c:\\Program Files\\Amazon\\Ec2ConfigService\\ec2config.exe\" -sysprep"] + }``` + - `ebs_optimized` (boolean) - Mark instance as [EBS Optimized](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSOptimized.html). Default `false`. @@ -224,7 +237,7 @@ Here is a basic example. You will need to provide access keys, and may need to c environmental variables. See the configuration reference in the section above for more information on what environmental variables Packer will look for. -Further information on locating AMI IDs and their relationship to instance types and regions can be found in the AWS EC2 Documentation [for Linux](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/finding-an-ami.html) or [for Windows](http://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/finding-an-ami.html). +Further information on locating AMI IDs and their relationship to instance types and regions can be found in the AWS EC2 Documentation [for Linux](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/finding-an-ami.html) or [for Windows](http://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/finding-an-ami.html). ## Accessing the Instance to Debug