diff --git a/builder/amazon/chroot/builder.go b/builder/amazon/chroot/builder.go index 33c5bc586..832a26022 100644 --- a/builder/amazon/chroot/builder.go +++ b/builder/amazon/chroot/builder.go @@ -7,13 +7,14 @@ package chroot import ( "errors" "fmt" + "log" + "runtime" + "github.com/mitchellh/goamz/ec2" "github.com/mitchellh/multistep" awscommon "github.com/mitchellh/packer/builder/amazon/common" "github.com/mitchellh/packer/common" "github.com/mitchellh/packer/packer" - "log" - "runtime" ) // The unique ID for this builder @@ -182,7 +183,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe // Build the steps steps := []multistep.Step{ &StepInstanceInfo{}, - &StepSourceAMIInfo{}, + &awscommon.StepSourceAMIInfo{ + SourceAmi: b.config.SourceAmi, + EnhancedNetworking: b.config.AMIEnhancedNetworking, + }, + &StepCheckRootDevice{}, &StepFlock{}, &StepPrepareDevice{}, &StepCreateVolume{}, diff --git a/builder/amazon/chroot/step_check_root_device.go b/builder/amazon/chroot/step_check_root_device.go new file mode 100644 index 000000000..d4d202f25 --- /dev/null +++ b/builder/amazon/chroot/step_check_root_device.go @@ -0,0 +1,31 @@ +package chroot + +import ( + "fmt" + + "github.com/mitchellh/goamz/ec2" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" +) + +// StepCheckRootDevice makes sure the root device on the AMI is EBS-backed. +type StepCheckRootDevice struct{} + +func (s *StepCheckRootDevice) Run(state multistep.StateBag) multistep.StepAction { + image := state.Get("ec2").(*ec2.Image) + ui := state.Get("ui").(packer.Ui) + + ui.Say("Checking the root device on source AMI...") + + // It must be EBS-backed otherwise the build won't work + if image.RootDeviceType != "ebs" { + err := fmt.Errorf("The root device of the source AMI must be EBS-backed.") + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + return multistep.ActionContinue +} + +func (s *StepCheckRootDevice) Cleanup(multistep.StateBag) {} diff --git a/builder/amazon/chroot/step_register_ami.go b/builder/amazon/chroot/step_register_ami.go index 173d88d6d..69ec6dbb6 100644 --- a/builder/amazon/chroot/step_register_ami.go +++ b/builder/amazon/chroot/step_register_ami.go @@ -2,6 +2,7 @@ package chroot import ( "fmt" + "github.com/mitchellh/goamz/ec2" "github.com/mitchellh/multistep" awscommon "github.com/mitchellh/packer/builder/amazon/common" @@ -38,6 +39,11 @@ func (s *StepRegisterAMI) Run(state multistep.StateBag) multistep.StepAction { BlockDevices: blockDevices, } + // Set SriovNetSupport to "simple". See http://goo.gl/icuXh5 + if config.AMIEnhancedNetworking { + registerOpts.SriovNetSupport = "simple" + } + registerResp, err := ec2conn.RegisterImage(registerOpts) if err != nil { state.Put("error", fmt.Errorf("Error registering AMI: %s", err)) diff --git a/builder/amazon/common/ami_config.go b/builder/amazon/common/ami_config.go index 53ef7f8e2..91c2d12d0 100644 --- a/builder/amazon/common/ami_config.go +++ b/builder/amazon/common/ami_config.go @@ -2,20 +2,22 @@ package common import ( "fmt" + "github.com/mitchellh/goamz/aws" "github.com/mitchellh/packer/packer" ) // AMIConfig is for common configuration related to creating AMIs. type AMIConfig struct { - AMIName string `mapstructure:"ami_name"` - AMIDescription string `mapstructure:"ami_description"` - AMIVirtType string `mapstructure:"ami_virtualization_type"` - AMIUsers []string `mapstructure:"ami_users"` - AMIGroups []string `mapstructure:"ami_groups"` - AMIProductCodes []string `mapstructure:"ami_product_codes"` - AMIRegions []string `mapstructure:"ami_regions"` - AMITags map[string]string `mapstructure:"tags"` + AMIName string `mapstructure:"ami_name"` + AMIDescription string `mapstructure:"ami_description"` + AMIVirtType string `mapstructure:"ami_virtualization_type"` + AMIUsers []string `mapstructure:"ami_users"` + AMIGroups []string `mapstructure:"ami_groups"` + AMIProductCodes []string `mapstructure:"ami_product_codes"` + AMIRegions []string `mapstructure:"ami_regions"` + AMITags map[string]string `mapstructure:"tags"` + AMIEnhancedNetworking bool `mapstructure:"enhanced_networking"` } func (c *AMIConfig) Prepare(t *packer.ConfigTemplate) []error { diff --git a/builder/amazon/chroot/step_source_ami_info.go b/builder/amazon/common/step_source_ami_info.go similarity index 66% rename from builder/amazon/chroot/step_source_ami_info.go rename to builder/amazon/common/step_source_ami_info.go index 32ca5fd9c..c9f72123d 100644 --- a/builder/amazon/chroot/step_source_ami_info.go +++ b/builder/amazon/common/step_source_ami_info.go @@ -1,7 +1,8 @@ -package chroot +package common import ( "fmt" + "github.com/mitchellh/goamz/ec2" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" @@ -12,15 +13,17 @@ import ( // // Produces: // source_image *ec2.Image - the source AMI info -type StepSourceAMIInfo struct{} +type StepSourceAMIInfo struct { + SourceAmi string + EnhancedNetworking bool +} func (s *StepSourceAMIInfo) Run(state multistep.StateBag) multistep.StepAction { - config := state.Get("config").(*Config) ec2conn := state.Get("ec2").(*ec2.EC2) ui := state.Get("ui").(packer.Ui) ui.Say("Inspecting the source AMI...") - imageResp, err := ec2conn.Images([]string{config.SourceAmi}, ec2.NewFilter()) + imageResp, err := ec2conn.Images([]string{s.SourceAmi}, ec2.NewFilter()) if err != nil { err := fmt.Errorf("Error querying AMI: %s", err) state.Put("error", err) @@ -29,7 +32,7 @@ func (s *StepSourceAMIInfo) Run(state multistep.StateBag) multistep.StepAction { } if len(imageResp.Images) == 0 { - err := fmt.Errorf("Source AMI '%s' was not found!", config.SourceAmi) + err := fmt.Errorf("Source AMI '%s' was not found!", s.SourceAmi) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt @@ -37,9 +40,10 @@ func (s *StepSourceAMIInfo) Run(state multistep.StateBag) multistep.StepAction { image := &imageResp.Images[0] - // It must be EBS-backed otherwise the build won't work - if image.RootDeviceType != "ebs" { - err := fmt.Errorf("The root device of the source AMI must be EBS-backed.") + // Enhanced Networking (SriovNetSupport) can only be enabled on HVM AMIs. + // See http://goo.gl/icuXh5 + if s.EnhancedNetworking && image.VirtualizationType != "hvm" { + err := fmt.Errorf("Cannot enable enhanced networking, source AMI '%s' is not HVM", s.SourceAmi) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt diff --git a/builder/amazon/ebs/builder.go b/builder/amazon/ebs/builder.go index 2e898671e..b5d2ce750 100644 --- a/builder/amazon/ebs/builder.go +++ b/builder/amazon/ebs/builder.go @@ -7,12 +7,13 @@ package ebs import ( "fmt" + "log" + "github.com/mitchellh/goamz/ec2" "github.com/mitchellh/multistep" awscommon "github.com/mitchellh/packer/builder/amazon/common" "github.com/mitchellh/packer/common" "github.com/mitchellh/packer/packer" - "log" ) // The unique ID for this builder @@ -82,6 +83,10 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe // Build the steps steps := []multistep.Step{ + &awscommon.StepSourceAMIInfo{ + SourceAmi: b.config.SourceAmi, + EnhancedNetworking: b.config.AMIEnhancedNetworking, + }, &awscommon.StepKeyPair{ Debug: b.config.PackerDebug, DebugKeyPath: fmt.Sprintf("ec2_%s.pem", b.config.PackerBuildName), @@ -114,6 +119,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe }, &common.StepProvision{}, &stepStopInstance{}, + &stepModifyInstance{}, &stepCreateAMI{}, &awscommon.StepAMIRegionCopy{ Regions: b.config.AMIRegions, diff --git a/builder/amazon/ebs/step_modify_instance.go b/builder/amazon/ebs/step_modify_instance.go new file mode 100644 index 000000000..21c5e7de9 --- /dev/null +++ b/builder/amazon/ebs/step_modify_instance.go @@ -0,0 +1,39 @@ +package ebs + +import ( + "fmt" + + "github.com/mitchellh/goamz/ec2" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" +) + +type stepModifyInstance struct{} + +func (s *stepModifyInstance) Run(state multistep.StateBag) multistep.StepAction { + config := state.Get("config").(config) + ec2conn := state.Get("ec2").(*ec2.EC2) + instance := state.Get("instance").(*ec2.Instance) + ui := state.Get("ui").(packer.Ui) + + // Set SriovNetSupport to "simple". See http://goo.gl/icuXh5 + if config.AMIEnhancedNetworking { + ui.Say("Enabling Enhanced Networking...") + _, err := ec2conn.ModifyInstance( + instance.InstanceId, + &ec2.ModifyInstance{SriovNetSupport: true}, + ) + if err != nil { + err := fmt.Errorf("Error enabling Enhanced Networking on %s: %s", instance.InstanceId, err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + } + + return multistep.ActionContinue +} + +func (s *stepModifyInstance) Cleanup(state multistep.StateBag) { + // No cleanup... +} diff --git a/builder/amazon/instance/builder.go b/builder/amazon/instance/builder.go index 81be72f72..7edd027de 100644 --- a/builder/amazon/instance/builder.go +++ b/builder/amazon/instance/builder.go @@ -5,14 +5,15 @@ package instance import ( "errors" "fmt" + "log" + "os" + "strings" + "github.com/mitchellh/goamz/ec2" "github.com/mitchellh/multistep" awscommon "github.com/mitchellh/packer/builder/amazon/common" "github.com/mitchellh/packer/common" "github.com/mitchellh/packer/packer" - "log" - "os" - "strings" ) // The unique ID for this builder @@ -186,6 +187,10 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe // Build the steps steps := []multistep.Step{ + &awscommon.StepSourceAMIInfo{ + SourceAmi: b.config.SourceAmi, + EnhancedNetworking: b.config.AMIEnhancedNetworking, + }, &awscommon.StepKeyPair{ Debug: b.config.PackerDebug, DebugKeyPath: fmt.Sprintf("ec2_%s.pem", b.config.PackerBuildName), diff --git a/builder/amazon/instance/step_register_ami.go b/builder/amazon/instance/step_register_ami.go index cadde6464..07040f417 100644 --- a/builder/amazon/instance/step_register_ami.go +++ b/builder/amazon/instance/step_register_ami.go @@ -2,6 +2,7 @@ package instance import ( "fmt" + "github.com/mitchellh/goamz/ec2" "github.com/mitchellh/multistep" awscommon "github.com/mitchellh/packer/builder/amazon/common" @@ -24,6 +25,11 @@ func (s *StepRegisterAMI) Run(state multistep.StateBag) multistep.StepAction { VirtType: config.AMIVirtType, } + // Set SriovNetSupport to "simple". See http://goo.gl/icuXh5 + if config.AMIEnhancedNetworking { + registerOpts.SriovNetSupport = "simple" + } + registerResp, err := ec2conn.RegisterImage(registerOpts) if err != nil { state.Put("error", fmt.Errorf("Error registering AMI: %s", err))