Merge pull request #6265 from DanHam/enable-t2-unlimited

Add support for T2 Unlimited for Amazon builders
This commit is contained in:
James Nugent 2018-05-25 00:26:17 +04:00 committed by GitHub
commit b97475b647
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 186 additions and 19 deletions

View File

@ -1,11 +1,11 @@
package common
import (
"errors"
"fmt"
"net"
"os"
"regexp"
"strings"
"time"
"github.com/hashicorp/packer/common/uuid"
@ -30,25 +30,26 @@ func (d *AmiFilterOptions) Empty() bool {
type RunConfig struct {
AssociatePublicIpAddress bool `mapstructure:"associate_public_ip_address"`
AvailabilityZone string `mapstructure:"availability_zone"`
DisableStopInstance bool `mapstructure:"disable_stop_instance"`
EbsOptimized bool `mapstructure:"ebs_optimized"`
EnableT2Unlimited bool `mapstructure:"enable_t2_unlimited"`
IamInstanceProfile string `mapstructure:"iam_instance_profile"`
InstanceInitiatedShutdownBehavior string `mapstructure:"shutdown_behavior"`
InstanceType string `mapstructure:"instance_type"`
RunTags map[string]string `mapstructure:"run_tags"`
SecurityGroupId string `mapstructure:"security_group_id"`
SecurityGroupIds []string `mapstructure:"security_group_ids"`
SourceAmi string `mapstructure:"source_ami"`
SourceAmiFilter AmiFilterOptions `mapstructure:"source_ami_filter"`
SpotPrice string `mapstructure:"spot_price"`
SpotPriceAutoProduct string `mapstructure:"spot_price_auto_product"`
DisableStopInstance bool `mapstructure:"disable_stop_instance"`
SecurityGroupId string `mapstructure:"security_group_id"`
SecurityGroupIds []string `mapstructure:"security_group_ids"`
TemporarySGSourceCidr string `mapstructure:"temporary_security_group_source_cidr"`
SubnetId string `mapstructure:"subnet_id"`
TemporaryKeyPairName string `mapstructure:"temporary_key_pair_name"`
TemporarySGSourceCidr string `mapstructure:"temporary_security_group_source_cidr"`
UserData string `mapstructure:"user_data"`
UserDataFile string `mapstructure:"user_data_file"`
WindowsPasswordTimeout time.Duration `mapstructure:"windows_password_timeout"`
VpcId string `mapstructure:"vpc_id"`
InstanceInitiatedShutdownBehavior string `mapstructure:"shutdown_behavior"`
WindowsPasswordTimeout time.Duration `mapstructure:"windows_password_timeout"`
// Communicator settings
Comm communicator.Config `mapstructure:",squash"`
@ -84,32 +85,39 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
c.SSHInterface != "public_dns" &&
c.SSHInterface != "private_dns" &&
c.SSHInterface != "" {
errs = append(errs, errors.New(fmt.Sprintf("Unknown interface type: %s", c.SSHInterface)))
errs = append(errs, fmt.Errorf("Unknown interface type: %s", c.SSHInterface))
}
if c.SSHKeyPairName != "" {
if c.Comm.Type == "winrm" && c.Comm.WinRMPassword == "" && c.Comm.SSHPrivateKey == "" {
errs = append(errs, errors.New("ssh_private_key_file must be provided to retrieve the winrm password when using ssh_keypair_name."))
errs = append(errs, fmt.Errorf("ssh_private_key_file must be provided to retrieve the winrm password when using ssh_keypair_name."))
} else if c.Comm.SSHPrivateKey == "" && !c.Comm.SSHAgentAuth {
errs = append(errs, errors.New("ssh_private_key_file must be provided or ssh_agent_auth enabled when ssh_keypair_name is specified."))
errs = append(errs, fmt.Errorf("ssh_private_key_file must be provided or ssh_agent_auth enabled when ssh_keypair_name is specified."))
}
}
if c.SourceAmi == "" && c.SourceAmiFilter.Empty() {
errs = append(errs, errors.New("A source_ami or source_ami_filter must be specified"))
errs = append(errs, fmt.Errorf("A source_ami or source_ami_filter must be specified"))
}
if c.InstanceType == "" {
errs = append(errs, errors.New("An instance_type must be specified"))
errs = append(errs, fmt.Errorf("An instance_type must be specified"))
}
if c.SpotPrice == "auto" {
if c.SpotPriceAutoProduct == "" {
errs = append(errs, errors.New(
errs = append(errs, fmt.Errorf(
"spot_price_auto_product must be specified when spot_price is auto"))
}
}
if c.SpotPriceAutoProduct != "" {
if c.SpotPrice != "auto" {
errs = append(errs, fmt.Errorf(
"spot_price should be set to auto when spot_price_auto_product is specified"))
}
}
if c.UserData != "" && c.UserDataFile != "" {
errs = append(errs, fmt.Errorf("Only one of user_data or user_data_file can be specified."))
} else if c.UserDataFile != "" {
@ -141,6 +149,18 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
errs = append(errs, fmt.Errorf("shutdown_behavior only accepts 'stop' or 'terminate' values."))
}
if c.EnableT2Unlimited {
if c.SpotPrice != "" {
errs = append(errs, fmt.Errorf("Error: T2 Unlimited cannot be used in conjuction with Spot Instances"))
}
firstDotIndex := strings.Index(c.InstanceType, ".")
if firstDotIndex == -1 {
errs = append(errs, fmt.Errorf("Error determining main Instance Type from: %s", c.InstanceType))
} else if c.InstanceType[0:firstDotIndex] != "t2" {
errs = append(errs, fmt.Errorf("Error: T2 Unlimited enabled with a non-T2 Instance Type: %s", c.InstanceType))
}
}
return errs
}

View File

@ -48,7 +48,7 @@ func TestRunConfigPrepare_InstanceType(t *testing.T) {
c := testConfig()
c.InstanceType = ""
if err := c.Prepare(nil); len(err) != 1 {
t.Fatalf("err: %s", err)
t.Fatalf("Should error if an instance_type is not specified")
}
}
@ -56,14 +56,14 @@ func TestRunConfigPrepare_SourceAmi(t *testing.T) {
c := testConfig()
c.SourceAmi = ""
if err := c.Prepare(nil); len(err) != 1 {
t.Fatalf("err: %s", err)
t.Fatalf("Should error if a source_ami (or source_ami_filter) is not specified")
}
}
func TestRunConfigPrepare_SourceAmiFilterBlank(t *testing.T) {
c := testConfigFilter()
if err := c.Prepare(nil); len(err) != 1 {
t.Fatalf("err: %s", err)
t.Fatalf("Should error if source_ami_filter is empty or not specified (and source_ami is not specified)")
}
}
@ -79,17 +79,58 @@ func TestRunConfigPrepare_SourceAmiFilterGood(t *testing.T) {
}
}
func TestRunConfigPrepare_EnableT2UnlimitedGood(t *testing.T) {
c := testConfig()
// Must have a T2 instance type if T2 Unlimited is enabled
c.InstanceType = "t2.micro"
c.EnableT2Unlimited = true
err := c.Prepare(nil)
if len(err) > 0 {
t.Fatalf("err: %s", err)
}
}
func TestRunConfigPrepare_EnableT2UnlimitedBadInstanceType(t *testing.T) {
c := testConfig()
// T2 Unlimited cannot be used with instance types other than T2
c.InstanceType = "m5.large"
c.EnableT2Unlimited = true
err := c.Prepare(nil)
if len(err) != 1 {
t.Fatalf("Should error if T2 Unlimited is enabled with non-T2 instance_type")
}
}
func TestRunConfigPrepare_EnableT2UnlimitedBadWithSpotInstanceRequest(t *testing.T) {
c := testConfig()
// T2 Unlimited cannot be used with Spot Instances
c.InstanceType = "t2.micro"
c.EnableT2Unlimited = true
c.SpotPrice = "auto"
c.SpotPriceAutoProduct = "Linux/UNIX"
err := c.Prepare(nil)
if len(err) != 1 {
t.Fatalf("Should error if T2 Unlimited has been used in conjuntion with a Spot Price request")
}
}
func TestRunConfigPrepare_SpotAuto(t *testing.T) {
c := testConfig()
c.SpotPrice = "auto"
if err := c.Prepare(nil); len(err) != 1 {
t.Fatalf("err: %s", err)
t.Fatalf("Should error if spot_price_auto_product is not set and spot_price is set to auto")
}
// Good - SpotPrice and SpotPriceAutoProduct are correctly set
c.SpotPriceAutoProduct = "foo"
if err := c.Prepare(nil); len(err) != 0 {
t.Fatalf("err: %s", err)
}
c.SpotPrice = ""
if err := c.Prepare(nil); len(err) != 1 {
t.Fatalf("Should error if spot_price is not set to auto and spot_price_auto_product is set")
}
}
func TestRunConfigPrepare_SSHPort(t *testing.T) {
@ -125,7 +166,7 @@ func TestRunConfigPrepare_UserData(t *testing.T) {
c.UserData = "foo"
c.UserDataFile = tf.Name()
if err := c.Prepare(nil); len(err) != 1 {
t.Fatalf("err: %s", err)
t.Fatalf("Should error if user_data string and user_data_file have both been specified")
}
}
@ -137,7 +178,7 @@ func TestRunConfigPrepare_UserDataFile(t *testing.T) {
c.UserDataFile = "idontexistidontthink"
if err := c.Prepare(nil); len(err) != 1 {
t.Fatalf("err: %s", err)
t.Fatalf("Should error if the file specified by user_data_file does not exist")
}
tf, err := ioutil.TempFile("", "packer")

View File

@ -24,6 +24,7 @@ type StepRunSourceInstance struct {
Ctx interpolate.Context
Debug bool
EbsOptimized bool
EnableT2Unlimited bool
ExpectedRootDevice string
IamInstanceProfile string
InstanceInitiatedShutdownBehavior string
@ -116,6 +117,11 @@ func (s *StepRunSourceInstance) Run(ctx context.Context, state multistep.StateBa
EbsOptimized: &s.EbsOptimized,
}
if s.EnableT2Unlimited {
creditOption := "unlimited"
runOpts.CreditSpecification = &ec2.CreditSpecificationRequest{CpuCredits: &creditOption}
}
// Collect tags for tagging on resource creation
var tagSpecs []*ec2.TagSpecification

View File

@ -148,6 +148,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
Ctx: b.config.ctx,
Debug: b.config.PackerDebug,
EbsOptimized: b.config.EbsOptimized,
EnableT2Unlimited: b.config.EnableT2Unlimited,
ExpectedRootDevice: "ebs",
IamInstanceProfile: b.config.IamInstanceProfile,
InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior,

View File

@ -162,6 +162,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
Ctx: b.config.ctx,
Debug: b.config.PackerDebug,
EbsOptimized: b.config.EbsOptimized,
EnableT2Unlimited: b.config.EnableT2Unlimited,
ExpectedRootDevice: "ebs",
IamInstanceProfile: b.config.IamInstanceProfile,
InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior,

View File

@ -145,6 +145,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
Ctx: b.config.ctx,
Debug: b.config.PackerDebug,
EbsOptimized: b.config.EbsOptimized,
EnableT2Unlimited: b.config.EnableT2Unlimited,
ExpectedRootDevice: "ebs",
IamInstanceProfile: b.config.IamInstanceProfile,
InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior,

View File

@ -230,6 +230,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
Ctx: b.config.ctx,
Debug: b.config.PackerDebug,
EbsOptimized: b.config.EbsOptimized,
EnableT2Unlimited: b.config.EnableT2Unlimited,
IamInstanceProfile: b.config.IamInstanceProfile,
InstanceType: b.config.InstanceType,
IsRestricted: b.config.IsChinaCloud() || b.config.IsGovCloud(),

View File

@ -169,6 +169,30 @@ builder.
Note: you must make sure enhanced networking is enabled on your instance. See [Amazon's
documentation on enabling enhanced networking](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking.html#enabling_enhanced_networking). Default `false`.
- `enable_t2_unlimited` (boolean) - Enabling T2 Unlimited allows the source
instance to burst additional CPU beyond its available [CPU Credits]
(https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-credits-baseline-concepts.html)
for as long as the demand exists.
This is in contrast to the standard configuration that only allows an
instance to consume up to its available CPU Credits.
See the AWS documentation for [T2 Unlimited]
(https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-unlimited.html)
and the 'T2 Unlimited Pricing' section of the [Amazon EC2 On-Demand
Pricing](https://aws.amazon.com/ec2/pricing/on-demand/) document for more
information.
By default this option is disabled and Packer will set up a [T2
Standard](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-std.html)
instance instead.
To use T2 Unlimited you must use a T2 instance type e.g. t2.micro.
Additionally, T2 Unlimited cannot be used in conjunction with Spot
Instances e.g. when the `spot_price` option has been configured.
Attempting to do so will cause an error.
!> **Warning!** Additional costs may be incurred by enabling T2
Unlimited - even for instances that would usually qualify for the
[AWS Free Tier](https://aws.amazon.com/free/).
- `force_deregister` (boolean) - Force Packer to first deregister an existing
AMI if one with the same name already exists. Default `false`.

View File

@ -162,6 +162,30 @@ builder.
Note: you must make sure enhanced networking is enabled on your instance. See [Amazon's
documentation on enabling enhanced networking](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking.html#enabling_enhanced_networking). Default `false`.
- `enable_t2_unlimited` (boolean) - Enabling T2 Unlimited allows the source
instance to burst additional CPU beyond its available [CPU Credits]
(https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-credits-baseline-concepts.html)
for as long as the demand exists.
This is in contrast to the standard configuration that only allows an
instance to consume up to its available CPU Credits.
See the AWS documentation for [T2 Unlimited]
(https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-unlimited.html)
and the 'T2 Unlimited Pricing' section of the [Amazon EC2 On-Demand
Pricing](https://aws.amazon.com/ec2/pricing/on-demand/) document for more
information.
By default this option is disabled and Packer will set up a [T2
Standard](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-std.html)
instance instead.
To use T2 Unlimited you must use a T2 instance type e.g. t2.micro.
Additionally, T2 Unlimited cannot be used in conjunction with Spot
Instances e.g. when the `spot_price` option has been configured.
Attempting to do so will cause an error.
!> **Warning!** Additional costs may be incurred by enabling T2
Unlimited - even for instances that would usually qualify for the
[AWS Free Tier](https://aws.amazon.com/free/).
- `force_deregister` (boolean) - Force Packer to first deregister an existing
AMI if one with the same name already exists. Default `false`.

View File

@ -120,6 +120,30 @@ builder.
Note: you must make sure enhanced networking is enabled on your instance. See [Amazon's
documentation on enabling enhanced networking](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking.html#enabling_enhanced_networking). Default `false`.
- `enable_t2_unlimited` (boolean) - Enabling T2 Unlimited allows the source
instance to burst additional CPU beyond its available [CPU Credits]
(https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-credits-baseline-concepts.html)
for as long as the demand exists.
This is in contrast to the standard configuration that only allows an
instance to consume up to its available CPU Credits.
See the AWS documentation for [T2 Unlimited]
(https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-unlimited.html)
and the 'T2 Unlimited Pricing' section of the [Amazon EC2 On-Demand
Pricing](https://aws.amazon.com/ec2/pricing/on-demand/) document for more
information.
By default this option is disabled and Packer will set up a [T2
Standard](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-std.html)
instance instead.
To use T2 Unlimited you must use a T2 instance type e.g. t2.micro.
Additionally, T2 Unlimited cannot be used in conjunction with Spot
Instances e.g. when the `spot_price` option has been configured.
Attempting to do so will cause an error.
!> **Warning!** Additional costs may be incurred by enabling T2
Unlimited - even for instances that would usually qualify for the
[AWS Free Tier](https://aws.amazon.com/free/).
- `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.

View File

@ -193,6 +193,30 @@ builder.
Note: you must make sure enhanced networking is enabled on your instance. See [Amazon's
documentation on enabling enhanced networking](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking.html#enabling_enhanced_networking). Default `false`.
- `enable_t2_unlimited` (boolean) - Enabling T2 Unlimited allows the source
instance to burst additional CPU beyond its available [CPU Credits]
(https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-credits-baseline-concepts.html)
for as long as the demand exists.
This is in contrast to the standard configuration that only allows an
instance to consume up to its available CPU Credits.
See the AWS documentation for [T2 Unlimited]
(https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-unlimited.html)
and the 'T2 Unlimited Pricing' section of the [Amazon EC2 On-Demand
Pricing](https://aws.amazon.com/ec2/pricing/on-demand/) document for more
information.
By default this option is disabled and Packer will set up a [T2
Standard](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-std.html)
instance instead.
To use T2 Unlimited you must use a T2 instance type e.g. t2.micro.
Additionally, T2 Unlimited cannot be used in conjunction with Spot
Instances e.g. when the `spot_price` option has been configured.
Attempting to do so will cause an error.
!> **Warning!** Additional costs may be incurred by enabling T2
Unlimited - even for instances that would usually qualify for the
[AWS Free Tier](https://aws.amazon.com/free/).
- `force_deregister` (boolean) - Force Packer to first deregister an existing
AMI if one with the same name already exists. Defaults to `false`.