diff --git a/builder/amazon/common/block_device.go b/builder/amazon/common/block_device.go new file mode 100644 index 000000000..74714f016 --- /dev/null +++ b/builder/amazon/common/block_device.go @@ -0,0 +1,46 @@ +package common + +import ( + "github.com/mitchellh/goamz/ec2" +) + +// BlockDevice +type BlockDevice struct { + DeviceName string `mapstructure:"device_name"` + VirtualName string `mapstructure:"virtual_name"` + SnapshotId string `mapstructure:"snapshot_id"` + VolumeType string `mapstructure:"volume_type"` + VolumeSize int64 `mapstructure:"volume_size"` + DeleteOnTermination bool `mapstructure:"delete_on_termination"` + IOPS int64 `mapstructure:"iops"` +} + +type BlockDevices struct { + AMIMappings []BlockDevice `mapstructure:"ami_block_device_mappings,squash"` + LaunchMappings []BlockDevice `mapstructure:"launch_block_device_mappings,squash"` +} + +func buildBlockDevices(b []BlockDevice) []ec2.BlockDeviceMapping { + var blockDevices []ec2.BlockDeviceMapping + + for _, blockDevice := range b { + blockDevices = append(blockDevices, ec2.BlockDeviceMapping{ + DeviceName: blockDevice.DeviceName, + VirtualName: blockDevice.VirtualName, + SnapshotId: blockDevice.SnapshotId, + VolumeType: blockDevice.VolumeType, + VolumeSize: blockDevice.VolumeSize, + DeleteOnTermination: blockDevice.DeleteOnTermination, + IOPS: blockDevice.IOPS, + }) + } + return blockDevices +} + +func (b *BlockDevices) BuildAMIDevices() []ec2.BlockDeviceMapping { + return buildBlockDevices(b.AMIMappings) +} + +func (b *BlockDevices) BuildLaunchDevices() []ec2.BlockDeviceMapping { + return buildBlockDevices(b.LaunchMappings) +} diff --git a/builder/amazon/common/block_device_test.go b/builder/amazon/common/block_device_test.go new file mode 100644 index 000000000..0981816cf --- /dev/null +++ b/builder/amazon/common/block_device_test.go @@ -0,0 +1,41 @@ +package common + +import ( + "cgl.tideland.biz/asserts" + "github.com/mitchellh/goamz/ec2" + "testing" +) + +func TestBlockDevice(t *testing.T) { + assert := asserts.NewTestingAsserts(t, true) + + ec2Mapping := []ec2.BlockDeviceMapping{ + ec2.BlockDeviceMapping{ + DeviceName: "/dev/sdb", + VirtualName: "ephemeral0", + SnapshotId: "snap-1234", + VolumeType: "standard", + VolumeSize: 8, + DeleteOnTermination: true, + IOPS: 1000, + }, + } + + blockDevice := BlockDevice{ + DeviceName: "/dev/sdb", + VirtualName: "ephemeral0", + SnapshotId: "snap-1234", + VolumeType: "standard", + VolumeSize: 8, + DeleteOnTermination: true, + IOPS: 1000, + } + + blockDevices := BlockDevices{ + AMIMappings: []BlockDevice{blockDevice}, + LaunchMappings: []BlockDevice{blockDevice}, + } + + assert.Equal(ec2Mapping, blockDevices.BuildAMIDevices(), "should match output") + assert.Equal(ec2Mapping, blockDevices.BuildLaunchDevices(), "should match output") +} diff --git a/builder/amazon/common/step_run_source_instance.go b/builder/amazon/common/step_run_source_instance.go index 1f9843a3f..8e1483da0 100644 --- a/builder/amazon/common/step_run_source_instance.go +++ b/builder/amazon/common/step_run_source_instance.go @@ -17,6 +17,7 @@ type StepRunSourceInstance struct { SourceAMI string IamInstanceProfile string SubnetId string + BlockDevices BlockDevices instance *ec2.Instance } @@ -48,6 +49,7 @@ func (s *StepRunSourceInstance) Run(state map[string]interface{}) multistep.Step SecurityGroups: []ec2.SecurityGroup{ec2.SecurityGroup{Id: securityGroupId}}, IamInstanceProfile: s.IamInstanceProfile, SubnetId: s.SubnetId, + BlockDevices: s.BlockDevices.BuildLaunchDevices(), } ui.Say("Launching a source AWS instance...") diff --git a/builder/amazon/ebs/builder.go b/builder/amazon/ebs/builder.go index a8598273c..087afe52a 100644 --- a/builder/amazon/ebs/builder.go +++ b/builder/amazon/ebs/builder.go @@ -22,6 +22,7 @@ type config struct { common.PackerConfig `mapstructure:",squash"` awscommon.AccessConfig `mapstructure:",squash"` awscommon.AMIConfig `mapstructure:",squash"` + awscommon.BlockDevices `mapstructure:",squash"` awscommon.RunConfig `mapstructure:",squash"` // Tags for the AMI @@ -119,6 +120,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe SourceAMI: b.config.SourceAmi, IamInstanceProfile: b.config.IamInstanceProfile, SubnetId: b.config.SubnetId, + BlockDevices: b.config.BlockDevices, }, &common.StepConnectSSH{ SSHAddress: awscommon.SSHAddress(ec2conn, b.config.SSHPort), diff --git a/builder/amazon/ebs/step_create_ami.go b/builder/amazon/ebs/step_create_ami.go index e0dbec002..b6fc70ff1 100644 --- a/builder/amazon/ebs/step_create_ami.go +++ b/builder/amazon/ebs/step_create_ami.go @@ -19,8 +19,9 @@ func (s *stepCreateAMI) Run(state map[string]interface{}) multistep.StepAction { // Create the image ui.Say(fmt.Sprintf("Creating the AMI: %s", config.AMIName)) createOpts := &ec2.CreateImage{ - InstanceId: instance.InstanceId, - Name: config.AMIName, + InstanceId: instance.InstanceId, + Name: config.AMIName, + BlockDevices: config.BlockDevices.BuildAMIDevices(), } createResp, err := ec2conn.CreateImage(createOpts) diff --git a/builder/amazon/instance/builder.go b/builder/amazon/instance/builder.go index 31e4b3f90..bd85be909 100644 --- a/builder/amazon/instance/builder.go +++ b/builder/amazon/instance/builder.go @@ -24,6 +24,7 @@ type Config struct { common.PackerConfig `mapstructure:",squash"` awscommon.AccessConfig `mapstructure:",squash"` awscommon.AMIConfig `mapstructure:",squash"` + awscommon.BlockDevices `mapstructure:",squash"` awscommon.RunConfig `mapstructure:",squash"` AccountId string `mapstructure:"account_id"` @@ -198,6 +199,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe UserDataFile: b.config.UserDataFile, SourceAMI: b.config.SourceAmi, SubnetId: b.config.SubnetId, + BlockDevices: b.config.BlockDevices, }, &common.StepConnectSSH{ SSHAddress: awscommon.SSHAddress(ec2conn, b.config.SSHPort), diff --git a/builder/amazon/instance/step_register_ami.go b/builder/amazon/instance/step_register_ami.go index 38bb319ad..1237e6f81 100644 --- a/builder/amazon/instance/step_register_ami.go +++ b/builder/amazon/instance/step_register_ami.go @@ -20,6 +20,7 @@ func (s *StepRegisterAMI) Run(state map[string]interface{}) multistep.StepAction registerOpts := &ec2.RegisterImage{ ImageLocation: manifestPath, Name: config.AMIName, + BlockDevices: config.BlockDevices.BuildAMIDevices(), } registerResp, err := ec2conn.RegisterImage(registerOpts)