Merge pull request #6669 from sargun/root_volume_type
Enable setting the volume type
This commit is contained in:
commit
89e43e7747
|
@ -42,6 +42,7 @@ type Config struct {
|
||||||
PreMountCommands []string `mapstructure:"pre_mount_commands"`
|
PreMountCommands []string `mapstructure:"pre_mount_commands"`
|
||||||
RootDeviceName string `mapstructure:"root_device_name"`
|
RootDeviceName string `mapstructure:"root_device_name"`
|
||||||
RootVolumeSize int64 `mapstructure:"root_volume_size"`
|
RootVolumeSize int64 `mapstructure:"root_volume_size"`
|
||||||
|
RootVolumeType string `mapstructure:"root_volume_type"`
|
||||||
SourceAmi string `mapstructure:"source_ami"`
|
SourceAmi string `mapstructure:"source_ami"`
|
||||||
SourceAmiFilter awscommon.AmiFilterOptions `mapstructure:"source_ami_filter"`
|
SourceAmiFilter awscommon.AmiFilterOptions `mapstructure:"source_ami_filter"`
|
||||||
RootVolumeTags awscommon.TagMap `mapstructure:"root_volume_tags"`
|
RootVolumeTags awscommon.TagMap `mapstructure:"root_volume_tags"`
|
||||||
|
@ -233,6 +234,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||||
&StepFlock{},
|
&StepFlock{},
|
||||||
&StepPrepareDevice{},
|
&StepPrepareDevice{},
|
||||||
&StepCreateVolume{
|
&StepCreateVolume{
|
||||||
|
RootVolumeType: b.config.RootVolumeType,
|
||||||
RootVolumeSize: b.config.RootVolumeSize,
|
RootVolumeSize: b.config.RootVolumeSize,
|
||||||
RootVolumeTags: b.config.RootVolumeTags,
|
RootVolumeTags: b.config.RootVolumeTags,
|
||||||
Ctx: b.config.ctx,
|
Ctx: b.config.ctx,
|
||||||
|
|
|
@ -2,6 +2,7 @@ package chroot
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
@ -21,6 +22,7 @@ import (
|
||||||
type StepCreateVolume struct {
|
type StepCreateVolume struct {
|
||||||
volumeId string
|
volumeId string
|
||||||
RootVolumeSize int64
|
RootVolumeSize int64
|
||||||
|
RootVolumeType string
|
||||||
RootVolumeTags awscommon.TagMap
|
RootVolumeTags awscommon.TagMap
|
||||||
Ctx interpolate.Context
|
Ctx interpolate.Context
|
||||||
}
|
}
|
||||||
|
@ -53,11 +55,21 @@ func (s *StepCreateVolume) Run(ctx context.Context, state multistep.StateBag) mu
|
||||||
|
|
||||||
var createVolume *ec2.CreateVolumeInput
|
var createVolume *ec2.CreateVolumeInput
|
||||||
if config.FromScratch {
|
if config.FromScratch {
|
||||||
|
rootVolumeType := ec2.VolumeTypeGp2
|
||||||
|
if s.RootVolumeType == "io1" {
|
||||||
|
err := errors.New("Cannot use io1 volume when building from scratch")
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
} else if s.RootVolumeType != "" {
|
||||||
|
rootVolumeType = s.RootVolumeType
|
||||||
|
}
|
||||||
createVolume = &ec2.CreateVolumeInput{
|
createVolume = &ec2.CreateVolumeInput{
|
||||||
AvailabilityZone: instance.Placement.AvailabilityZone,
|
AvailabilityZone: instance.Placement.AvailabilityZone,
|
||||||
Size: aws.Int64(s.RootVolumeSize),
|
Size: aws.Int64(s.RootVolumeSize),
|
||||||
VolumeType: aws.String(ec2.VolumeTypeGp2),
|
VolumeType: aws.String(rootVolumeType),
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Determine the root device snapshot
|
// Determine the root device snapshot
|
||||||
image := state.Get("source_image").(*ec2.Image)
|
image := state.Get("source_image").(*ec2.Image)
|
||||||
|
@ -70,26 +82,13 @@ func (s *StepCreateVolume) Run(ctx context.Context, state multistep.StateBag) mu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if rootDevice == nil {
|
ui.Say("Creating the root volume...")
|
||||||
err := fmt.Errorf("Couldn't find root device!")
|
createVolume, err = s.buildCreateVolumeInput(*instance.Placement.AvailabilityZone, rootDevice)
|
||||||
|
if err != nil {
|
||||||
state.Put("error", err)
|
state.Put("error", err)
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.Say("Creating the root volume...")
|
|
||||||
vs := *rootDevice.Ebs.VolumeSize
|
|
||||||
if s.RootVolumeSize > *rootDevice.Ebs.VolumeSize {
|
|
||||||
vs = s.RootVolumeSize
|
|
||||||
}
|
|
||||||
|
|
||||||
createVolume = &ec2.CreateVolumeInput{
|
|
||||||
AvailabilityZone: instance.Placement.AvailabilityZone,
|
|
||||||
Size: aws.Int64(vs),
|
|
||||||
SnapshotId: rootDevice.Ebs.SnapshotId,
|
|
||||||
VolumeType: rootDevice.Ebs.VolumeType,
|
|
||||||
Iops: rootDevice.Ebs.Iops,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(tagSpecs) > 0 {
|
if len(tagSpecs) > 0 {
|
||||||
|
@ -137,3 +136,33 @@ func (s *StepCreateVolume) Cleanup(state multistep.StateBag) {
|
||||||
ui.Error(fmt.Sprintf("Error deleting EBS volume: %s", err))
|
ui.Error(fmt.Sprintf("Error deleting EBS volume: %s", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *StepCreateVolume) buildCreateVolumeInput(az string, rootDevice *ec2.BlockDeviceMapping) (*ec2.CreateVolumeInput, error) {
|
||||||
|
if rootDevice == nil {
|
||||||
|
return nil, fmt.Errorf("Couldn't find root device!")
|
||||||
|
}
|
||||||
|
createVolumeInput := &ec2.CreateVolumeInput{
|
||||||
|
AvailabilityZone: aws.String(az),
|
||||||
|
Size: rootDevice.Ebs.VolumeSize,
|
||||||
|
SnapshotId: rootDevice.Ebs.SnapshotId,
|
||||||
|
VolumeType: rootDevice.Ebs.VolumeType,
|
||||||
|
Iops: rootDevice.Ebs.Iops,
|
||||||
|
}
|
||||||
|
if s.RootVolumeSize > *rootDevice.Ebs.VolumeSize {
|
||||||
|
createVolumeInput.Size = aws.Int64(s.RootVolumeSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.RootVolumeType == "" || s.RootVolumeType == *rootDevice.Ebs.VolumeType {
|
||||||
|
return createVolumeInput, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.RootVolumeType == "io1" {
|
||||||
|
return nil, fmt.Errorf("Root volume type cannot be io1, because existing root volume type was %s", *rootDevice.Ebs.VolumeType)
|
||||||
|
}
|
||||||
|
|
||||||
|
createVolumeInput.VolumeType = aws.String(s.RootVolumeType)
|
||||||
|
// non io1 cannot set iops
|
||||||
|
createVolumeInput.Iops = nil
|
||||||
|
|
||||||
|
return createVolumeInput, nil
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
package chroot
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/service/ec2"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func buildTestRootDevice() *ec2.BlockDeviceMapping {
|
||||||
|
return &ec2.BlockDeviceMapping{
|
||||||
|
Ebs: &ec2.EbsBlockDevice{
|
||||||
|
VolumeSize: aws.Int64(10),
|
||||||
|
SnapshotId: aws.String("snap-1234"),
|
||||||
|
VolumeType: aws.String("gp2"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateVolume_Default(t *testing.T) {
|
||||||
|
stepCreateVolume := new(StepCreateVolume)
|
||||||
|
_, err := stepCreateVolume.buildCreateVolumeInput("test-az", buildTestRootDevice())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateVolume_Shrink(t *testing.T) {
|
||||||
|
stepCreateVolume := StepCreateVolume{RootVolumeSize: 1}
|
||||||
|
testRootDevice := buildTestRootDevice()
|
||||||
|
ret, err := stepCreateVolume.buildCreateVolumeInput("test-az", testRootDevice)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
// Ensure that the new value is equal to the size of the old root device
|
||||||
|
assert.Equal(t, *ret.Size, *testRootDevice.Ebs.VolumeSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateVolume_Expand(t *testing.T) {
|
||||||
|
stepCreateVolume := StepCreateVolume{RootVolumeSize: 25}
|
||||||
|
testRootDevice := buildTestRootDevice()
|
||||||
|
ret, err := stepCreateVolume.buildCreateVolumeInput("test-az", testRootDevice)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
// Ensure that the new value is equal to the size of the value passed in
|
||||||
|
assert.Equal(t, *ret.Size, stepCreateVolume.RootVolumeSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateVolume_io1_to_io1(t *testing.T) {
|
||||||
|
stepCreateVolume := StepCreateVolume{RootVolumeType: "io1"}
|
||||||
|
testRootDevice := buildTestRootDevice()
|
||||||
|
testRootDevice.Ebs.VolumeType = aws.String("io1")
|
||||||
|
testRootDevice.Ebs.Iops = aws.Int64(1000)
|
||||||
|
ret, err := stepCreateVolume.buildCreateVolumeInput("test-az", testRootDevice)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, *ret.VolumeType, stepCreateVolume.RootVolumeType)
|
||||||
|
assert.Equal(t, *ret.Iops, *testRootDevice.Ebs.Iops)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateVolume_io1_to_gp2(t *testing.T) {
|
||||||
|
stepCreateVolume := StepCreateVolume{RootVolumeType: "gp2"}
|
||||||
|
testRootDevice := buildTestRootDevice()
|
||||||
|
testRootDevice.Ebs.VolumeType = aws.String("io1")
|
||||||
|
testRootDevice.Ebs.Iops = aws.Int64(1000)
|
||||||
|
|
||||||
|
ret, err := stepCreateVolume.buildCreateVolumeInput("test-az", testRootDevice)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, *ret.VolumeType, stepCreateVolume.RootVolumeType)
|
||||||
|
assert.Nil(t, ret.Iops)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateVolume_gp2_to_io1(t *testing.T) {
|
||||||
|
stepCreateVolume := StepCreateVolume{RootVolumeType: "io1"}
|
||||||
|
testRootDevice := buildTestRootDevice()
|
||||||
|
|
||||||
|
_, err := stepCreateVolume.buildCreateVolumeInput("test-az", testRootDevice)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
|
@ -254,6 +254,11 @@ each category, the available configuration keys are alphabetized.
|
||||||
of the `source_ami` unless `from_scratch` is `true`, in which case
|
of the `source_ami` unless `from_scratch` is `true`, in which case
|
||||||
this field must be defined.
|
this field must be defined.
|
||||||
|
|
||||||
|
- `root_volume_type` (string) - The type of EBS volume for the chroot environment
|
||||||
|
and resulting AMI. The default value is the type of the `source_ami`, unless
|
||||||
|
`from_scratch` is true, in which case the default value is `gp2`. You can only
|
||||||
|
specify `io1` if building based on top of a `source_ami` which is also `io1`.
|
||||||
|
|
||||||
- `root_volume_tags` (object of key/value strings) - Tags to apply to the volumes
|
- `root_volume_tags` (object of key/value strings) - Tags to apply to the volumes
|
||||||
that are *launched*. This is a
|
that are *launched*. This is a
|
||||||
[template engine](/docs/templates/engine.html),
|
[template engine](/docs/templates/engine.html),
|
||||||
|
|
Loading…
Reference in New Issue