Merge pull request #4088 from mitchellh/f-ebsinit-builder
[WIP] builder/amazon: Add `ebs-init` builder
This commit is contained in:
commit
ffd76f1194
|
@ -1,4 +1,4 @@
|
|||
package ebs
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -8,16 +8,17 @@ import (
|
|||
"github.com/mitchellh/packer/packer"
|
||||
)
|
||||
|
||||
type stepModifyInstance struct{}
|
||||
type StepModifyEBSBackedInstance struct {
|
||||
EnableEnhancedNetworking bool
|
||||
}
|
||||
|
||||
func (s *stepModifyInstance) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(Config)
|
||||
func (s *StepModifyEBSBackedInstance) Run(state multistep.StateBag) multistep.StepAction {
|
||||
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 {
|
||||
if s.EnableEnhancedNetworking {
|
||||
ui.Say("Enabling Enhanced Networking...")
|
||||
simple := "simple"
|
||||
_, err := ec2conn.ModifyInstanceAttribute(&ec2.ModifyInstanceAttributeInput{
|
||||
|
@ -35,6 +36,6 @@ func (s *stepModifyInstance) Run(state multistep.StateBag) multistep.StepAction
|
|||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepModifyInstance) Cleanup(state multistep.StateBag) {
|
||||
func (s *StepModifyEBSBackedInstance) Cleanup(state multistep.StateBag) {
|
||||
// No cleanup...
|
||||
}
|
|
@ -1,20 +1,19 @@
|
|||
package ebs
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/mitchellh/multistep"
|
||||
awscommon "github.com/mitchellh/packer/builder/amazon/common"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
)
|
||||
|
||||
type stepStopInstance struct {
|
||||
type StepStopEBSBackedInstance struct {
|
||||
SpotPrice string
|
||||
DisableStopInstance bool
|
||||
}
|
||||
|
||||
func (s *stepStopInstance) Run(state multistep.StateBag) multistep.StepAction {
|
||||
func (s *StepStopEBSBackedInstance) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
instance := state.Get("instance").(*ec2.Instance)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
@ -44,13 +43,13 @@ func (s *stepStopInstance) Run(state multistep.StateBag) multistep.StepAction {
|
|||
|
||||
// Wait for the instance to actual stop
|
||||
ui.Say("Waiting for the instance to stop...")
|
||||
stateChange := awscommon.StateChangeConf{
|
||||
stateChange := StateChangeConf{
|
||||
Pending: []string{"running", "stopping"},
|
||||
Target: "stopped",
|
||||
Refresh: awscommon.InstanceStateRefreshFunc(ec2conn, *instance.InstanceId),
|
||||
Refresh: InstanceStateRefreshFunc(ec2conn, *instance.InstanceId),
|
||||
StepState: state,
|
||||
}
|
||||
_, err = awscommon.WaitForState(&stateChange)
|
||||
_, err = WaitForState(&stateChange)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error waiting for instance to stop: %s", err)
|
||||
state.Put("error", err)
|
||||
|
@ -61,6 +60,6 @@ func (s *stepStopInstance) Run(state multistep.StateBag) multistep.StepAction {
|
|||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepStopInstance) Cleanup(multistep.StateBag) {
|
||||
func (s *StepStopEBSBackedInstance) Cleanup(multistep.StateBag) {
|
||||
// No cleanup...
|
||||
}
|
|
@ -154,12 +154,13 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
b.config.RunConfig.Comm.SSHPassword),
|
||||
},
|
||||
&common.StepProvision{},
|
||||
&stepStopInstance{
|
||||
&awscommon.StepStopEBSBackedInstance{
|
||||
SpotPrice: b.config.SpotPrice,
|
||||
DisableStopInstance: b.config.DisableStopInstance,
|
||||
},
|
||||
// TODO(mitchellh): verify works with spots
|
||||
&stepModifyInstance{},
|
||||
&awscommon.StepModifyEBSBackedInstance{
|
||||
EnableEnhancedNetworking: b.config.AMIEnhancedNetworking,
|
||||
},
|
||||
&awscommon.StepDeregisterAMI{
|
||||
ForceDeregister: b.config.AMIForceDeregister,
|
||||
AMIName: b.config.AMIName,
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package ebsvolume
|
||||
|
||||
import (
|
||||
awscommon "github.com/mitchellh/packer/builder/amazon/common"
|
||||
)
|
||||
|
||||
type BlockDevice struct {
|
||||
awscommon.BlockDevice `mapstructure:"-,squash"`
|
||||
Tags map[string]string `mapstructure:"tags"`
|
||||
}
|
||||
|
||||
func commonBlockDevices(mappings []BlockDevice) awscommon.BlockDevices {
|
||||
result := make([]awscommon.BlockDevice, len(mappings))
|
||||
for i, mapping := range mappings {
|
||||
result[i] = mapping.BlockDevice
|
||||
}
|
||||
|
||||
return awscommon.BlockDevices{
|
||||
LaunchBlockDevices: awscommon.LaunchBlockDevices{
|
||||
LaunchMappings: result,
|
||||
},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
// The ebsvolume package contains a packer.Builder implementation that
|
||||
// builds EBS volumes for Amazon EC2 using an ephemeral instance,
|
||||
package ebsvolume
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/hashicorp/errwrap"
|
||||
"github.com/mitchellh/multistep"
|
||||
awscommon "github.com/mitchellh/packer/builder/amazon/common"
|
||||
"github.com/mitchellh/packer/common"
|
||||
"github.com/mitchellh/packer/helper/communicator"
|
||||
"github.com/mitchellh/packer/helper/config"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"github.com/mitchellh/packer/template/interpolate"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
common.PackerConfig `mapstructure:",squash"`
|
||||
awscommon.AccessConfig `mapstructure:",squash"`
|
||||
awscommon.RunConfig `mapstructure:",squash"`
|
||||
|
||||
VolumeMappings []BlockDevice `mapstructure:"ebs_volumes"`
|
||||
AMIEnhancedNetworking bool `mapstructure:"enhanced_networking"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
||||
type Builder struct {
|
||||
config Config
|
||||
runner multistep.Runner
|
||||
}
|
||||
|
||||
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
b.config.ctx.Funcs = awscommon.TemplateFuncs
|
||||
err := config.Decode(&b.config, &config.DecodeOpts{
|
||||
Interpolate: true,
|
||||
InterpolateContext: &b.config.ctx,
|
||||
}, raws...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Accumulate any errors
|
||||
var errs *packer.MultiError
|
||||
errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(&b.config.ctx)...)
|
||||
errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...)
|
||||
|
||||
if errs != nil && len(errs.Errors) > 0 {
|
||||
return nil, errs
|
||||
}
|
||||
|
||||
log.Println(common.ScrubConfig(b.config, b.config.AccessKey, b.config.SecretKey))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
|
||||
config, err := b.config.Config()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
session, err := session.NewSession(config)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error creating AWS Session: {{err}}", err)
|
||||
}
|
||||
|
||||
ec2conn := ec2.New(session)
|
||||
|
||||
// If the subnet is specified but not the AZ, try to determine the AZ automatically
|
||||
if b.config.SubnetId != "" && b.config.AvailabilityZone == "" {
|
||||
log.Printf("[INFO] Finding AZ for the given subnet '%s'", b.config.SubnetId)
|
||||
resp, err := ec2conn.DescribeSubnets(&ec2.DescribeSubnetsInput{SubnetIds: []*string{&b.config.SubnetId}})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b.config.AvailabilityZone = *resp.Subnets[0].AvailabilityZone
|
||||
log.Printf("[INFO] AZ found: '%s'", b.config.AvailabilityZone)
|
||||
}
|
||||
|
||||
// Setup the state bag and initial state for the steps
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("config", b.config)
|
||||
state.Put("ec2", ec2conn)
|
||||
state.Put("hook", hook)
|
||||
state.Put("ui", ui)
|
||||
|
||||
launchBlockDevices := commonBlockDevices(b.config.VolumeMappings)
|
||||
|
||||
var volumeIds *[]string
|
||||
|
||||
// Build the steps
|
||||
steps := []multistep.Step{
|
||||
&awscommon.StepSourceAMIInfo{
|
||||
SourceAmi: b.config.SourceAmi,
|
||||
EnhancedNetworking: b.config.AMIEnhancedNetworking,
|
||||
AmiFilters: b.config.SourceAmiFilter,
|
||||
},
|
||||
&awscommon.StepKeyPair{
|
||||
Debug: b.config.PackerDebug,
|
||||
DebugKeyPath: fmt.Sprintf("ec2_%s.pem", b.config.PackerBuildName),
|
||||
KeyPairName: b.config.SSHKeyPairName,
|
||||
TemporaryKeyPairName: b.config.TemporaryKeyPairName,
|
||||
PrivateKeyFile: b.config.RunConfig.Comm.SSHPrivateKey,
|
||||
},
|
||||
&awscommon.StepSecurityGroup{
|
||||
SecurityGroupIds: b.config.SecurityGroupIds,
|
||||
CommConfig: &b.config.RunConfig.Comm,
|
||||
VpcId: b.config.VpcId,
|
||||
},
|
||||
&awscommon.StepRunSourceInstance{
|
||||
Debug: b.config.PackerDebug,
|
||||
ExpectedRootDevice: "ebs",
|
||||
SpotPrice: b.config.SpotPrice,
|
||||
SpotPriceProduct: b.config.SpotPriceAutoProduct,
|
||||
InstanceType: b.config.InstanceType,
|
||||
UserData: b.config.UserData,
|
||||
UserDataFile: b.config.UserDataFile,
|
||||
SourceAMI: b.config.SourceAmi,
|
||||
IamInstanceProfile: b.config.IamInstanceProfile,
|
||||
SubnetId: b.config.SubnetId,
|
||||
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
|
||||
EbsOptimized: b.config.EbsOptimized,
|
||||
AvailabilityZone: b.config.AvailabilityZone,
|
||||
BlockDevices: launchBlockDevices,
|
||||
Tags: b.config.RunTags,
|
||||
InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior,
|
||||
},
|
||||
&stepTagEBSVolumes{
|
||||
VolumeMapping: b.config.VolumeMappings,
|
||||
VolumeIDs: &volumeIds,
|
||||
},
|
||||
&awscommon.StepGetPassword{
|
||||
Debug: b.config.PackerDebug,
|
||||
Comm: &b.config.RunConfig.Comm,
|
||||
Timeout: b.config.WindowsPasswordTimeout,
|
||||
},
|
||||
&communicator.StepConnect{
|
||||
Config: &b.config.RunConfig.Comm,
|
||||
Host: awscommon.SSHHost(
|
||||
ec2conn,
|
||||
b.config.SSHPrivateIp),
|
||||
SSHConfig: awscommon.SSHConfig(
|
||||
b.config.RunConfig.Comm.SSHAgentAuth,
|
||||
b.config.RunConfig.Comm.SSHUsername,
|
||||
b.config.RunConfig.Comm.SSHPassword),
|
||||
},
|
||||
&common.StepProvision{},
|
||||
&awscommon.StepStopEBSBackedInstance{
|
||||
SpotPrice: b.config.SpotPrice,
|
||||
DisableStopInstance: b.config.DisableStopInstance,
|
||||
},
|
||||
&awscommon.StepModifyEBSBackedInstance{
|
||||
EnableEnhancedNetworking: b.config.AMIEnhancedNetworking,
|
||||
},
|
||||
}
|
||||
|
||||
// Run!
|
||||
b.runner = common.NewRunner(steps, b.config.PackerConfig, ui)
|
||||
b.runner.Run(state)
|
||||
|
||||
// If there was an error, return that
|
||||
if rawErr, ok := state.GetOk("error"); ok {
|
||||
return nil, rawErr.(error)
|
||||
}
|
||||
|
||||
ui.Say(fmt.Sprintf("Created Volumes: %s", strings.Join(*volumeIds, ", ")))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (b *Builder) Cancel() {
|
||||
if b.runner != nil {
|
||||
log.Println("Cancelling the step runner...")
|
||||
b.runner.Cancel()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package ebsvolume
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mitchellh/packer/packer"
|
||||
)
|
||||
|
||||
func testConfig() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"access_key": "foo",
|
||||
"secret_key": "bar",
|
||||
"source_ami": "foo",
|
||||
"instance_type": "foo",
|
||||
"region": "us-east-1",
|
||||
"ssh_username": "root",
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilder_ImplementsBuilder(t *testing.T) {
|
||||
var raw interface{}
|
||||
raw = &Builder{}
|
||||
if _, ok := raw.(packer.Builder); !ok {
|
||||
t.Fatalf("Builder should be a builder")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilder_Prepare_BadType(t *testing.T) {
|
||||
b := &Builder{}
|
||||
c := map[string]interface{}{
|
||||
"access_key": []string{},
|
||||
}
|
||||
|
||||
warnings, err := b.Prepare(c)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatalf("prepare should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_InvalidKey(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
// Add a random key
|
||||
config["i_should_not_be_valid"] = true
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_InvalidShutdownBehaviour(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
// Test good
|
||||
config["shutdown_behaviour"] = "terminate"
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
// Test good
|
||||
config["shutdown_behaviour"] = "stop"
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
// Test bad
|
||||
config["shutdown_behaviour"] = "foobar"
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package ebsvolume
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
)
|
||||
|
||||
type stepTagEBSVolumes struct {
|
||||
VolumeMapping []BlockDevice
|
||||
VolumeIDs **[]string
|
||||
}
|
||||
|
||||
func (s *stepTagEBSVolumes) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
instance := state.Get("instance").(*ec2.Instance)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
volumeIds := make([]string, 0, len(s.VolumeMapping))
|
||||
for _, instanceBlockDevices := range instance.BlockDeviceMappings {
|
||||
for _, configVolumeMapping := range s.VolumeMapping {
|
||||
if configVolumeMapping.DeviceName == *instanceBlockDevices.DeviceName {
|
||||
volumeIds = append(volumeIds, *instanceBlockDevices.Ebs.VolumeId)
|
||||
}
|
||||
}
|
||||
}
|
||||
*s.VolumeIDs = &volumeIds
|
||||
|
||||
if len(s.VolumeMapping) > 0 {
|
||||
ui.Say("Tagging EBS volumes...")
|
||||
|
||||
toTag := map[string][]*ec2.Tag{}
|
||||
for _, mapping := range s.VolumeMapping {
|
||||
if len(mapping.Tags) == 0 {
|
||||
ui.Say(fmt.Sprintf("No tags specified for volume on %s...", mapping.DeviceName))
|
||||
continue
|
||||
}
|
||||
|
||||
tags := make([]*ec2.Tag, 0, len(mapping.Tags))
|
||||
for key, value := range mapping.Tags {
|
||||
tags = append(tags, &ec2.Tag{
|
||||
Key: aws.String(fmt.Sprintf("%s", key)),
|
||||
Value: aws.String(fmt.Sprintf("%s", value)),
|
||||
})
|
||||
}
|
||||
|
||||
for _, v := range instance.BlockDeviceMappings {
|
||||
if *v.DeviceName == mapping.DeviceName {
|
||||
toTag[*v.Ebs.VolumeId] = tags
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for volumeId, tags := range toTag {
|
||||
_, err := ec2conn.CreateTags(&ec2.CreateTagsInput{
|
||||
Resources: []*string{&volumeId},
|
||||
Tags: tags,
|
||||
})
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error tagging EBS Volume %s on %s: %s", volumeId, *instance.InstanceId, err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepTagEBSVolumes) Cleanup(state multistep.StateBag) {
|
||||
// No cleanup...
|
||||
}
|
|
@ -15,6 +15,7 @@ import (
|
|||
|
||||
amazonchrootbuilder "github.com/mitchellh/packer/builder/amazon/chroot"
|
||||
amazonebsbuilder "github.com/mitchellh/packer/builder/amazon/ebs"
|
||||
amazonebsvolumebuilder "github.com/mitchellh/packer/builder/amazon/ebsvolume"
|
||||
amazoninstancebuilder "github.com/mitchellh/packer/builder/amazon/instance"
|
||||
azurearmbuilder "github.com/mitchellh/packer/builder/azure/arm"
|
||||
cloudstackbuilder "github.com/mitchellh/packer/builder/cloudstack"
|
||||
|
@ -69,6 +70,7 @@ type PluginCommand struct {
|
|||
var Builders = map[string]packer.Builder{
|
||||
"amazon-chroot": new(amazonchrootbuilder.Builder),
|
||||
"amazon-ebs": new(amazonebsbuilder.Builder),
|
||||
"amazon-ebsvolume": new(amazonebsvolumebuilder.Builder),
|
||||
"amazon-instance": new(amazoninstancebuilder.Builder),
|
||||
"azure-arm": new(azurearmbuilder.Builder),
|
||||
"cloudstack": new(cloudstackbuilder.Builder),
|
||||
|
|
|
@ -0,0 +1,267 @@
|
|||
---
|
||||
description: |
|
||||
The `amazon-ebs-volume` Packer builder is like the EBS builder, but is
|
||||
intended to create EBS volumes rather than a machine image.
|
||||
layout: docs
|
||||
page_title: 'Amazon EBS Volume Builder'
|
||||
...
|
||||
|
||||
# EBS Volume Builder
|
||||
|
||||
Type: `amazon-ebs-volume`
|
||||
|
||||
The `amazon-ebs-volume` Packer builder is able to create Amazon Elastic Block
|
||||
Store volumes which are prepopulated with filesystems or data.
|
||||
|
||||
This builder builds EBS volumes by launching an EC2 instance from a source AMI,
|
||||
provisioning that running machine, and then destroying the source machine, keeping
|
||||
the volumes intact.
|
||||
|
||||
This is all done in your own AWS account. The builder will create temporary
|
||||
keypairs, security group rules, etc. that provide it temporary access to the
|
||||
instance while the image is being created.
|
||||
|
||||
The builder does *not* manage EBS Volumes. Once it creates volumes and stores
|
||||
it in your account, it is up to you to use, delete, etc. the volumes.
|
||||
|
||||
## Configuration Reference
|
||||
|
||||
There are many configuration options available for the builder. They are
|
||||
segmented below into two categories: required and optional parameters. Within
|
||||
each category, the available configuration keys are alphabetized.
|
||||
|
||||
In addition to the options listed here, a
|
||||
[communicator](/docs/templates/communicator.html) can be configured for this
|
||||
builder.
|
||||
|
||||
### Required:
|
||||
|
||||
- `access_key` (string) - The access key used to communicate with AWS. [Learn
|
||||
how to set this.](/docs/builders/amazon.html#specifying-amazon-credentials)
|
||||
|
||||
- `instance_type` (string) - The EC2 instance type to use while building the
|
||||
AMI, such as "m1.small".
|
||||
|
||||
- `region` (string) - The name of the region, such as "us-east-1", in which to
|
||||
launch the EC2 instance to create the AMI.
|
||||
|
||||
- `secret_key` (string) - The secret key used to communicate with AWS. [Learn
|
||||
how to set this.](/docs/builders/amazon.html#specifying-amazon-credentials)
|
||||
|
||||
- `source_ami` (string) - The initial AMI used as a base for the newly
|
||||
created machine. `source_ami_filter` may be used instead to populate this
|
||||
automatically.
|
||||
|
||||
### Optional:
|
||||
|
||||
- `ebs_volumes` (array of block device mappings) - Add the block
|
||||
device mappings to the AMI. The block device mappings allow for keys:
|
||||
|
||||
- `device_name` (string) - The device name exposed to the instance (for
|
||||
example, "/dev/sdh" or "xvdh"). Required when specifying `volume_size`.
|
||||
- `delete_on_termination` (boolean) - Indicates whether the EBS volume is
|
||||
deleted on instance termination
|
||||
- `encrypted` (boolean) - Indicates whether to encrypt the volume or not
|
||||
- `iops` (integer) - The number of I/O operations per second (IOPS) that the
|
||||
volume supports. See the documentation on
|
||||
[IOPs](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_EbsBlockDevice.html)
|
||||
for more information
|
||||
- `no_device` (boolean) - Suppresses the specified device included in the
|
||||
block device mapping of the AMI
|
||||
- `snapshot_id` (string) - The ID of the snapshot
|
||||
- `virtual_name` (string) - The virtual device name. See the documentation on
|
||||
[Block Device
|
||||
Mapping](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_BlockDeviceMapping.html)
|
||||
for more information
|
||||
- `volume_size` (integer) - The size of the volume, in GiB. Required if not
|
||||
specifying a `snapshot_id`
|
||||
- `volume_type` (string) - The volume type. gp2 for General Purpose (SSD)
|
||||
volumes, io1 for Provisioned IOPS (SSD) volumes, and standard for Magnetic
|
||||
volumes
|
||||
- `tags` (map) - Tags to apply to the volume. These are retained after the
|
||||
builder completes.
|
||||
|
||||
- `associate_public_ip_address` (boolean) - If using a non-default VPC, public
|
||||
IP addresses are not provided by default. If this is toggled, your new
|
||||
instance will get a Public IP.
|
||||
|
||||
- `availability_zone` (string) - Destination availability zone to launch
|
||||
instance in. Leave this empty to allow Amazon to auto-assign.
|
||||
|
||||
- `ebs_optimized` (boolean) - Mark instance as [EBS
|
||||
Optimized](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSOptimized.html).
|
||||
Default `false`.
|
||||
|
||||
- `enhanced_networking` (boolean) - Enable enhanced
|
||||
networking (SriovNetSupport) on HVM-compatible AMIs. If true, add
|
||||
`ec2:ModifyInstanceAttribute` to your AWS IAM policy.
|
||||
|
||||
- `iam_instance_profile` (string) - The name of an [IAM instance
|
||||
profile](https://docs.aws.amazon.com/IAM/latest/UserGuide/instance-profiles.html)
|
||||
to launch the EC2 instance with.
|
||||
|
||||
- `run_tags` (object of key/value strings) - Tags to apply to the instance
|
||||
that is *launched* to create the AMI. These tags are *not* applied to the
|
||||
resulting AMI unless they're duplicated in `tags`.
|
||||
|
||||
- `security_group_id` (string) - The ID (*not* the name) of the security group
|
||||
to assign to the instance. By default this is not set and Packer will
|
||||
automatically create a new temporary security group to allow SSH 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 strings) - A list of security groups as
|
||||
described above. Note that if this is specified, you must omit the
|
||||
`security_group_id`.
|
||||
|
||||
- `skip_region_validation` (boolean) - Set to true if you want to skip
|
||||
validation of the region configuration option. Defaults to false.
|
||||
|
||||
- `source_ami_filter` (object) - Filters used to populate the `source_ami` field.
|
||||
Example:
|
||||
``` {.javascript}
|
||||
"source_ami_filter": {
|
||||
"filters": {
|
||||
"virtualization-type": "hvm",
|
||||
"name": "*ubuntu-xenial-16.04-amd64-server-*",
|
||||
"root-device-type": "ebs"
|
||||
},
|
||||
"owners": ["099720109477"],
|
||||
"most_recent": true
|
||||
}
|
||||
```
|
||||
This selects the most recent Ubuntu 16.04 HVM EBS AMI from Canonical.
|
||||
NOTE: This will fail unless *exactly* one AMI is returned. In the above
|
||||
example, `most_recent` will cause this to succeed by selecting the newest image.
|
||||
|
||||
- `filters` (map of strings) - filters used to select a `source_ami`.
|
||||
NOTE: This will fail unless *exactly* one AMI is returned.
|
||||
Any filter described in the docs for [DescribeImages](http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeImages.html)
|
||||
is valid.
|
||||
|
||||
- `owners` (array of strings) - This scopes the AMIs to certain Amazon account IDs.
|
||||
This is helpful to limit the AMIs to a trusted third party, or to your own account.
|
||||
|
||||
- `most_recent` (bool) - Selects the newest created image when true.
|
||||
This is most useful for selecting a daily distro build.
|
||||
|
||||
- `spot_price` (string) - The maximum hourly price to pay for a spot instance
|
||||
to create the AMI. Spot instances are a type of instance that EC2 starts
|
||||
when the current spot price is less than the maximum price you specify. Spot
|
||||
price will be updated based on available spot instance capacity and current
|
||||
spot instance requests. It may save you some costs. You can set this to
|
||||
"auto" for Packer to automatically discover the best spot price or to "0"
|
||||
to use an on demand instance (default).
|
||||
|
||||
- `spot_price_auto_product` (string) - Required if `spot_price` is set
|
||||
to "auto". This tells Packer what sort of AMI you're launching to find the
|
||||
best spot price. This must be one of: `Linux/UNIX`, `SUSE Linux`, `Windows`,
|
||||
`Linux/UNIX (Amazon VPC)`, `SUSE Linux (Amazon VPC)`, `Windows (Amazon VPC)`
|
||||
|
||||
- `ssh_keypair_name` (string) - If specified, this is the key that will be
|
||||
used for SSH with the machine. By default, this is blank, and Packer will
|
||||
generate a temporary keypair unless
|
||||
[`ssh_password`](/docs/templates/communicator.html#ssh_password) is used.
|
||||
[`ssh_private_key_file`](/docs/templates/communicator.html#ssh_private_key_file)
|
||||
must be specified with this.
|
||||
|
||||
- `ssh_private_ip` (boolean) - If true, then SSH will always use the private
|
||||
IP if available.
|
||||
|
||||
- `subnet_id` (string) - If using VPC, the ID of the subnet, such as
|
||||
"subnet-12345def", where Packer will launch the EC2 instance. This field is
|
||||
required if you are using an non-default VPC.
|
||||
|
||||
- `temporary_key_pair_name` (string) - The name of the temporary keypair
|
||||
to generate. By default, Packer generates a name with a UUID.
|
||||
|
||||
- `token` (string) - The access token to use. This is different from the
|
||||
access key and secret key. If you're not sure what this is, then you
|
||||
probably don't need it. This will also be read from the `AWS_SESSION_TOKEN`
|
||||
environmental variable.
|
||||
|
||||
- `user_data` (string) - User data to apply when launching the instance. Note
|
||||
that you need to be careful about escaping characters due to the templates
|
||||
being JSON. It is often more convenient to use `user_data_file`, instead.
|
||||
|
||||
- `user_data_file` (string) - Path to a file that will be used for the user
|
||||
data when launching the instance.
|
||||
|
||||
- `vpc_id` (string) - If launching into a VPC subnet, Packer needs the VPC ID
|
||||
in order to create a temporary security group within the VPC. Requires `subnet_id`
|
||||
to be set.
|
||||
|
||||
- `windows_password_timeout` (string) - The timeout for waiting for a Windows
|
||||
password for Windows instances. Defaults to 20 minutes. Example value: "10m"
|
||||
|
||||
- `shutdown_behaviour` (string) - Automatically terminate instances on shutdown
|
||||
incase packer exits ungracefully. Possible values are "stop" and "terminate",
|
||||
default is stop.
|
||||
|
||||
## Basic Example
|
||||
|
||||
```
|
||||
{
|
||||
"type" : "amazon-ebsinit",
|
||||
"secret_key" : "YOUR SECRET KEY HERE",
|
||||
"access_key" : "YOUR KEY HERE",
|
||||
"region" : "us-east-1",
|
||||
"ssh_username" : "ubuntu",
|
||||
"instance_type" : "t2.medium",
|
||||
"source_ami" : "ami-40d28157",
|
||||
"ebs_volumes" : [
|
||||
{
|
||||
"volume_type" : "gp2",
|
||||
"device_name" : "/dev/xvdf",
|
||||
"delete_on_termination" : false,
|
||||
"tags" : {
|
||||
"zpool" : "data",
|
||||
"Name" : "Data1"
|
||||
},
|
||||
"volume_size" : 10
|
||||
},
|
||||
{
|
||||
"volume_type" : "gp2",
|
||||
"device_name" : "/dev/xvdg",
|
||||
"tags" : {
|
||||
"zpool" : "data",
|
||||
"Name" : "Data2"
|
||||
},
|
||||
"delete_on_termination" : false,
|
||||
"volume_size" : 10
|
||||
},
|
||||
{
|
||||
"volume_size" : 10,
|
||||
"tags" : {
|
||||
"Name" : "Data3",
|
||||
"zpool" : "data"
|
||||
},
|
||||
"delete_on_termination" : false,
|
||||
"device_name" : "/dev/xvdh",
|
||||
"volume_type" : "gp2"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
-> **Note:** Packer can also read the access key and secret access key from
|
||||
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).
|
||||
|
||||
## Accessing the Instance to Debug
|
||||
|
||||
If you need to access the instance to debug for some reason, run the builder
|
||||
with the `-debug` flag. In debug mode, the Amazon builder will save the private
|
||||
key in the current directory and will output the DNS or IP information as well.
|
||||
You can use this information to access the instance as it is running.
|
||||
|
||||
-> **Note:** Packer uses pre-built AMIs as the source for building images.
|
||||
These source AMIs may include volumes that are not flagged to be destroyed on
|
||||
termination of the instance building the new image. In addition to those volumes
|
||||
created by this builder, any volumes inn the source AMI which are not marked for
|
||||
deletion on termination will remain in your account.
|
|
@ -32,6 +32,15 @@ Packer supports the following builders at the moment:
|
|||
builder](/docs/builders/amazon-ebs.html). It is much easier to use and Amazon
|
||||
generally recommends EBS-backed images nowadays.
|
||||
|
||||
# Amazon EBS Volume Builder
|
||||
|
||||
Packer is able to create Amazon EBS Volumes which are preinitialized with a
|
||||
filesystem and data.
|
||||
|
||||
- [amazon-ebs](/docs/builders/amazon-ebsv-volume.html) - Create EBS volumes
|
||||
by launching a source AMI with block devices mapped. Provision the instance,
|
||||
then destroy it, retaining the EBS volumes.
|
||||
|
||||
<span id="specifying-amazon-credentials"></span>
|
||||
|
||||
## Specifying Amazon Credentials
|
||||
|
|
Loading…
Reference in New Issue