2019-05-31 08:27:41 -04:00
//go:generate struct-markdown
2019-10-23 13:36:10 -04:00
//go:generate mapstructure-to-hcl2 -type AmiFilterOptions,SecurityGroupFilterOptions,SubnetFilterOptions,VpcFilterOptions,PolicyDocument,Statement
2019-05-31 08:27:41 -04:00
2013-07-16 00:23:40 -04:00
package common
import (
"fmt"
2017-10-12 20:05:31 -04:00
"net"
2013-08-12 14:52:43 -04:00
"os"
2016-05-20 05:54:45 -04:00
"regexp"
2018-05-12 11:20:01 -04:00
"strings"
2016-06-14 17:34:01 -04:00
"time"
2014-09-05 19:38:05 -04:00
2017-04-04 16:39:01 -04:00
"github.com/hashicorp/packer/helper/communicator"
2020-11-18 18:46:42 -05:00
"github.com/hashicorp/packer/packer-plugin-sdk/template/config"
2020-11-11 13:21:37 -05:00
"github.com/hashicorp/packer/packer-plugin-sdk/template/interpolate"
2020-11-12 17:44:02 -05:00
"github.com/hashicorp/packer/packer-plugin-sdk/uuid"
2013-07-16 00:23:40 -04:00
)
2016-06-14 17:34:01 -04:00
var reShutdownBehavior = regexp . MustCompile ( "^(stop|terminate)$" )
2016-08-20 19:34:22 -04:00
type AmiFilterOptions struct {
2020-11-18 18:46:42 -05:00
config . KeyValueFilter ` mapstructure:",squash" `
Owners [ ] string
MostRecent bool ` mapstructure:"most_recent" `
2016-08-20 14:58:36 -04:00
}
2019-10-14 09:56:49 -04:00
func ( d * AmiFilterOptions ) GetOwners ( ) [ ] * string {
res := make ( [ ] * string , 0 , len ( d . Owners ) )
for _ , owner := range d . Owners {
2019-11-27 06:28:07 -05:00
i := owner
res = append ( res , & i )
2019-10-14 09:56:49 -04:00
}
return res
}
2016-08-20 19:34:22 -04:00
func ( d * AmiFilterOptions ) Empty ( ) bool {
2020-04-16 09:37:22 -04:00
return len ( d . Owners ) == 0 && d . KeyValueFilter . Empty ( )
2016-08-20 14:58:36 -04:00
}
2018-08-13 20:01:13 -04:00
func ( d * AmiFilterOptions ) NoOwner ( ) bool {
return len ( d . Owners ) == 0
}
2018-06-12 06:05:16 -04:00
type SubnetFilterOptions struct {
2020-11-18 18:46:42 -05:00
config . NameValueFilter ` mapstructure:",squash" `
MostFree bool ` mapstructure:"most_free" `
Random bool ` mapstructure:"random" `
2018-06-12 06:05:16 -04:00
}
type VpcFilterOptions struct {
2020-11-18 18:46:42 -05:00
config . NameValueFilter ` mapstructure:",squash" `
2018-06-12 06:05:16 -04:00
}
2019-10-23 13:36:10 -04:00
type Statement struct {
2020-08-25 04:53:56 -04:00
Effect string ` mapstructure:"Effect" required:"false" `
Action [ ] string ` mapstructure:"Action" required:"false" `
Resource [ ] string ` mapstructure:"Resource" required:"false" `
2019-10-23 13:36:10 -04:00
}
2019-10-19 05:56:18 -04:00
type PolicyDocument struct {
2020-08-25 04:53:56 -04:00
Version string ` mapstructure:"Version" required:"false" `
Statement [ ] Statement ` mapstructure:"Statement" required:"false" `
2019-10-19 05:56:18 -04:00
}
2018-08-14 06:04:13 -04:00
type SecurityGroupFilterOptions struct {
2020-11-18 18:46:42 -05:00
config . NameValueFilter ` mapstructure:",squash" `
2018-08-14 06:04:13 -04:00
}
2013-07-16 00:23:40 -04:00
// RunConfig contains configuration for running an instance from a source
// AMI and details on how to access that launched image.
type RunConfig struct {
2019-05-28 11:50:58 -04:00
// If using a non-default VPC,
2019-06-03 11:55:09 -04:00
// public IP addresses are not provided by default. If this is true, your
// new instance will get a Public IP. default: false
AssociatePublicIpAddress bool ` mapstructure:"associate_public_ip_address" required:"false" `
2019-05-28 11:50:58 -04:00
// Destination availability zone to launch
2019-06-03 11:55:09 -04:00
// instance in. Leave this empty to allow Amazon to auto-assign.
AvailabilityZone string ` mapstructure:"availability_zone" required:"false" `
2019-05-28 11:50:58 -04:00
// Requires spot_price to be set. The
2019-06-03 11:55:09 -04:00
// required duration for the Spot Instances (also known as Spot blocks). This
// value must be a multiple of 60 (60, 120, 180, 240, 300, or 360). You can't
// specify an Availability Zone group or a launch group if you specify a
// duration.
BlockDurationMinutes int64 ` mapstructure:"block_duration_minutes" required:"false" `
// Packer normally stops the build instance after all provisioners have
// run. For Windows instances, it is sometimes desirable to [run
// Sysprep](http://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ami-create-standard.html)
// which will stop the instance for you. If this is set to `true`, Packer
// *will not* stop the instance but will assume that you will send the stop
// signal yourself through your final provisioner. You can do this with a
2020-07-20 10:20:47 -04:00
// [windows-shell provisioner](/docs/provisioners/windows-shell). Note that
// Packer will still wait for the instance to be stopped, and failing to
// send the stop signal yourself, when you have set this flag to `true`,
// will cause a timeout.
2019-06-03 11:55:09 -04:00
//
2020-07-20 10:20:47 -04:00
// An example of a valid windows shutdown command in a `windows-shell`
// provisioner is :
// ```shell-session
// ec2config.exe -sysprep
2020-07-17 18:10:55 -04:00
// ```
2020-07-20 10:20:47 -04:00
// or
// ```sell-session
// "%programfiles%\amazon\ec2configservice\"ec2config.exe -sysprep""
2019-06-03 11:55:09 -04:00
// ```
2020-07-20 10:20:47 -04:00
// -> Note: The double quotation marks in the command are not required if
// your CMD shell is already in the
// `C:\Program Files\Amazon\EC2ConfigService\` directory.
2019-06-03 11:55:09 -04:00
DisableStopInstance bool ` mapstructure:"disable_stop_instance" required:"false" `
// Mark instance as [EBS
// Optimized](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSOptimized.html).
// Default `false`.
EbsOptimized bool ` mapstructure:"ebs_optimized" required:"false" `
// 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/).
EnableT2Unlimited bool ` mapstructure:"enable_t2_unlimited" required:"false" `
2019-06-06 10:29:25 -04:00
// The name of an [IAM instance
// profile](https://docs.aws.amazon.com/IAM/latest/UserGuide/instance-profiles.html)
2019-06-03 11:55:09 -04:00
// to launch the EC2 instance with.
2019-10-19 06:33:58 -04:00
IamInstanceProfile string ` mapstructure:"iam_instance_profile" required:"false" `
2019-12-10 03:17:39 -05:00
// Whether or not to check if the IAM instance profile exists. Defaults to false
SkipProfileValidation bool ` mapstructure:"skip_profile_validation" required:"false" `
2019-10-19 05:56:18 -04:00
// Temporary IAM instance profile policy document
// If IamInstanceProfile is specified it will be used instead. Example:
//
// ```json
//{
// "Version": "2012-10-17",
// "Statement": [
// {
// "Action": [
// "logs:*"
// ],
// "Effect": "Allow",
// "Resource": "*"
// }
// ]
//}
// ```
//
TemporaryIamInstanceProfilePolicyDocument * PolicyDocument ` mapstructure:"temporary_iam_instance_profile_policy_document" required:"false" `
2019-05-28 11:50:58 -04:00
// Automatically terminate instances on
2019-06-03 11:55:09 -04:00
// shutdown in case Packer exits ungracefully. Possible values are stop and
// terminate. Defaults to stop.
InstanceInitiatedShutdownBehavior string ` mapstructure:"shutdown_behavior" required:"false" `
2019-05-28 11:50:58 -04:00
// The EC2 instance type to use while building the
2019-06-03 11:55:09 -04:00
// AMI, such as t2.small.
InstanceType string ` mapstructure:"instance_type" required:"true" `
2020-07-20 10:24:47 -04:00
// Filters used to populate the `security_group_ids` field. JSON Example:
2020-07-17 18:10:55 -04:00
//
2020-03-12 10:05:08 -04:00
// ```json
2019-06-03 11:55:09 -04:00
// {
// "security_group_filter": {
// "filters": {
// "tag:Class": "packer"
// }
// }
// }
// ```
2019-06-06 10:29:25 -04:00
//
2020-07-20 10:24:47 -04:00
// HCL2 Example:
2020-07-17 18:10:55 -04:00
//
// ```hcl
// security_group_filter {
// filters = {
// "tag:Class": "packer"
// }
// }
// ```
//
2019-06-06 10:29:25 -04:00
// This selects the SG's with tag `Class` with the value `packer`.
//
// - `filters` (map of strings) - filters used to select a
// `security_group_ids`. Any filter described in the docs for
// [DescribeSecurityGroups](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSecurityGroups.html)
// is valid.
2019-06-06 10:45:37 -04:00
//
2019-06-06 10:29:25 -04:00
// `security_group_ids` take precedence over this.
2019-06-03 11:55:09 -04:00
SecurityGroupFilter SecurityGroupFilterOptions ` mapstructure:"security_group_filter" required:"false" `
2020-04-16 09:37:22 -04:00
// Key/value pair tags to apply to the instance that is that is *launched*
// to create the EBS volumes. This is a [template
// engine](/docs/templates/engine), see [Build template
// data](#build-template-data) for more information.
2019-06-03 11:55:09 -04:00
RunTags map [ string ] string ` mapstructure:"run_tags" required:"false" `
2020-03-16 09:55:03 -04:00
// Same as [`run_tags`](#run_tags) but defined as a singular repeatable
2020-04-16 09:37:22 -04:00
// block containing a `key` and a `value` field. In HCL2 mode the
2020-04-01 18:54:21 -04:00
// [`dynamic_block`](/docs/configuration/from-1.5/expressions#dynamic-blocks)
2020-03-13 13:04:48 -04:00
// will allow you to create those programatically.
2020-11-18 18:46:42 -05:00
RunTag config . KeyValues ` mapstructure:"run_tag" required:"false" `
2019-05-28 11:50:58 -04:00
// The ID (not the name) of the security
2019-06-03 11:55:09 -04:00
// 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.
SecurityGroupId string ` mapstructure:"security_group_id" required:"false" `
2019-05-28 11:50:58 -04:00
// A list of security groups as
2019-06-03 11:55:09 -04:00
// described above. Note that if this is specified, you must omit the
// security_group_id.
SecurityGroupIds [ ] string ` mapstructure:"security_group_ids" required:"false" `
2019-05-28 11:50:58 -04:00
// The source AMI whose root volume will be copied and
2019-06-03 11:55:09 -04:00
// provisioned on the currently running instance. This must be an EBS-backed
// AMI with a root volume snapshot that you have access to. Note: this is not
// used when from_scratch is set to true.
SourceAmi string ` mapstructure:"source_ami" required:"true" `
2019-06-06 10:45:37 -04:00
// Filters used to populate the `source_ami`
2020-07-20 10:26:45 -04:00
// field. JSON Example:
2020-07-17 18:10:55 -04:00
//
// ```json
// "builders" [
2019-06-06 10:45:37 -04:00
// {
2020-07-17 18:10:55 -04:00
// "type": "amazon-ebs",
2019-06-06 10:45:37 -04:00
// "source_ami_filter": {
2020-07-17 18:10:55 -04:00
// "filters": {
// "virtualization-type": "hvm",
// "name": "ubuntu/images/\*ubuntu-xenial-16.04-amd64-server-\*",
// "root-device-type": "ebs"
// },
// "owners": ["099720109477"],
// "most_recent": true
2019-06-06 10:45:37 -04:00
// }
// }
2020-07-17 18:10:55 -04:00
// ]
// ```
2020-07-20 10:26:45 -04:00
// HCL2 example:
2020-07-17 18:10:55 -04:00
//
// ```hcl
// source "amazon-ebs" "basic-example" {
// source_ami_filter {
// filters = {
// virtualization-type = "hvm"
// name = "ubuntu/images/\*ubuntu-xenial-16.04-amd64-server-\*"
// root-device-type = "ebs"
// }
// owners = ["099720109477"]
// most_recent = true
// }
// }
// ```
//
2019-06-06 10:45:37 -04:00
// 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) - Filters the images by their owner. You
// may specify one or more AWS account IDs, "self" (which will use the
// account whose credentials you are using to run Packer), or an AWS owner
// alias: for example, `amazon`, `aws-marketplace`, or `microsoft`. This
// option is required for security reasons.
//
// - `most_recent` (boolean) - Selects the newest created image when true.
// This is most useful for selecting a daily distro build.
//
// You may set this in place of `source_ami` or in conjunction with it. If you
// set this in conjunction with `source_ami`, the `source_ami` will be added
// to the filter. The provided `source_ami` must meet all of the filtering
// criteria provided in `source_ami_filter`; this pins the AMI returned by the
// filter, but will cause Packer to fail if the `source_ami` does not exist.
2019-06-03 11:55:09 -04:00
SourceAmiFilter AmiFilterOptions ` mapstructure:"source_ami_filter" required:"false" `
2019-05-28 11:50:58 -04:00
// a list of acceptable instance
2019-06-03 11:55:09 -04:00
// types to run your build on. We will request a spot instance using the max
// price of spot_price and the allocation strategy of "lowest price".
// Your instance will be launched on an instance type of the lowest available
// price that you have in your list. This is used in place of instance_type.
// You may only set either spot_instance_types or instance_type, not both.
// This feature exists to help prevent situations where a Packer build fails
// because a particular availability zone does not have capacity for the
// specific instance_type requested in instance_type.
SpotInstanceTypes [ ] string ` mapstructure:"spot_instance_types" required:"false" `
2020-03-09 11:46:30 -04:00
// With Spot Instances, you pay the Spot price that's in effect for the
// time period your instances are running. Spot Instance prices are set by
// Amazon EC2 and adjust gradually based on long-term trends in supply and
// demand for Spot Instance capacity.
//
// When this field is set, it represents the maximum hourly price you are
// willing to pay for a spot instance. If you do not set this value, it
// defaults to a maximum price equal to the on demand price of the
// instance. In the situation where the current Amazon-set spot price
// exceeds the value set in this field, Packer will not launch an instance
// and the build will error. In the situation where the Amazon-set spot
// price is less than the value set in this field, Packer will launch and
// you will pay the Amazon-set spot price, not this maximum value.
// For more information, see the Amazon docs on
// [spot pricing](https://aws.amazon.com/ec2/spot/pricing/).
2019-06-03 11:55:09 -04:00
SpotPrice string ` mapstructure:"spot_price" required:"false" `
2019-05-28 11:50:58 -04:00
// Required if spot_price is set to
2019-06-03 11:55:09 -04:00
// 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)
2020-05-05 20:48:27 -04:00
SpotPriceAutoProduct string ` mapstructure:"spot_price_auto_product" required:"false" undocumented:"true" `
2020-04-16 09:37:22 -04:00
// Requires spot_price to be set. Key/value pair tags to apply tags to the
2020-03-13 13:04:48 -04:00
// spot request that is issued.
2019-06-03 11:55:09 -04:00
SpotTags map [ string ] string ` mapstructure:"spot_tags" required:"false" `
2020-03-16 07:19:34 -04:00
// Same as [`spot_tags`](#spot_tags) but defined as a singular repeatable block
2020-04-16 09:37:22 -04:00
// containing a `key` and a `value` field. In HCL2 mode the
2020-04-01 18:54:21 -04:00
// [`dynamic_block`](/docs/configuration/from-1.5/expressions#dynamic-blocks)
2020-03-13 13:04:48 -04:00
// will allow you to create those programatically.
2020-11-18 18:46:42 -05:00
SpotTag config . KeyValues ` mapstructure:"spot_tag" required:"false" `
2019-06-06 10:45:37 -04:00
// Filters used to populate the `subnet_id` field.
2020-07-20 10:26:45 -04:00
// JSON Example:
2020-07-17 18:10:55 -04:00
//
// ```json
// "builders" [
2019-06-06 10:45:37 -04:00
// {
2020-07-17 18:10:55 -04:00
// "type": "amazon-ebs",
2019-06-06 10:45:37 -04:00
// "subnet_filter": {
// "filters": {
// "tag:Class": "build"
// },
// "most_free": true,
// "random": false
// }
// }
2020-07-17 18:10:55 -04:00
// ]
// ```
2020-07-20 10:26:45 -04:00
// HCL2 example:
2020-07-17 18:10:55 -04:00
//
// ```hcl
// source "amazon-ebs" "basic-example" {
// subnet_filter {
// filters = {
// "tag:Class": "build"
// }
// most_free = true
// random = false
// }
// }
// ```
//
2019-06-06 10:45:37 -04:00
// This selects the Subnet with tag `Class` with the value `build`, which has
// the most free IP addresses. NOTE: This will fail unless *exactly* one
// Subnet is returned. By using `most_free` or `random` one will be selected
// from those matching the filter.
//
// - `filters` (map of strings) - filters used to select a `subnet_id`.
// NOTE: This will fail unless *exactly* one Subnet is returned. Any
// filter described in the docs for
// [DescribeSubnets](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSubnets.html)
// is valid.
//
// - `most_free` (boolean) - The Subnet with the most free IPv4 addresses
// will be used if multiple Subnets matches the filter.
//
// - `random` (boolean) - A random Subnet will be used if multiple Subnets
// matches the filter. `most_free` have precendence over this.
//
// `subnet_id` take precedence over this.
2019-06-03 11:55:09 -04:00
SubnetFilter SubnetFilterOptions ` mapstructure:"subnet_filter" required:"false" `
2019-05-28 11:50:58 -04:00
// If using VPC, the ID of the subnet, such as
2019-06-03 11:55:09 -04:00
// subnet-12345def, where Packer will launch the EC2 instance. This field is
// required if you are using an non-default VPC.
SubnetId string ` mapstructure:"subnet_id" required:"false" `
2020-10-11 01:54:22 -04:00
// [Tenancy](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/dedicated-instance.html) used
// when Packer launches the EC2 instance, allowing it to be launched on dedicated hardware.
2020-10-12 18:05:58 -04:00
//
// The default is "default", meaning shared tenancy. Allowed values are "default",
// "dedicated" and "host".
2020-10-11 01:54:22 -04:00
Tenancy string ` mapstructure:"tenancy" required:"false" `
2019-06-06 10:45:37 -04:00
// A list of IPv4 CIDR blocks to be authorized access to the instance, when
// packer is creating a temporary security group.
//
// The default is [`0.0.0.0/0`] (i.e., allow any IPv4 source). This is only
// used when `security_group_id` or `security_group_ids` is not specified.
2019-06-03 11:55:09 -04:00
TemporarySGSourceCidrs [ ] string ` mapstructure:"temporary_security_group_source_cidrs" required:"false" `
2019-05-28 11:50:58 -04:00
// User data to apply when launching the instance. Note
2019-06-03 11:55:09 -04:00
// 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.
// Packer will not automatically wait for a user script to finish before
// shutting down the instance this must be handled in a provisioner.
UserData string ` mapstructure:"user_data" required:"false" `
2019-05-28 11:50:58 -04:00
// Path to a file that will be used for the user
2019-06-03 11:55:09 -04:00
// data when launching the instance.
UserDataFile string ` mapstructure:"user_data_file" required:"false" `
2019-08-26 10:56:57 -04:00
// Filters used to populate the `vpc_id` field.
2020-07-20 10:26:45 -04:00
// JSON Example:
2020-07-17 18:10:55 -04:00
//
2020-03-12 10:05:08 -04:00
// ```json
2020-07-17 18:10:55 -04:00
// "builders" [
// {
// "type": "amazon-ebs",
// "vpc_filter": {
// "filters": {
// "tag:Class": "build",
// "isDefault": "false",
// "cidr": "/24"
// }
// }
// }
// ]
// ```
2020-07-20 10:26:45 -04:00
// HCL2 example:
2020-07-17 18:10:55 -04:00
//
// ```hcl
// source "amazon-ebs" "basic-example" {
// vpc_filter {
// filters = {
2019-08-26 10:56:57 -04:00
// "tag:Class": "build",
// "isDefault": "false",
// "cidr": "/24"
// }
// }
// }
// ```
//
// This selects the VPC with tag `Class` with the value `build`, which is not
// the default VPC, and have a IPv4 CIDR block of `/24`. NOTE: This will fail
// unless *exactly* one VPC is returned.
//
// - `filters` (map of strings) - filters used to select a `vpc_id`. NOTE:
// This will fail unless *exactly* one VPC is returned. Any filter
// described in the docs for
// [DescribeVpcs](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpcs.html)
// is valid.
//
// `vpc_id` take precedence over this.
2019-06-03 11:55:09 -04:00
VpcFilter VpcFilterOptions ` mapstructure:"vpc_filter" required:"false" `
2019-05-28 11:50:58 -04:00
// If launching into a VPC subnet, Packer needs the VPC ID
2019-06-03 11:55:09 -04:00
// in order to create a temporary security group within the VPC. Requires
// subnet_id to be set. If this field is left blank, Packer will try to get
// the VPC ID from the subnet_id.
VpcId string ` mapstructure:"vpc_id" required:"false" `
2019-05-28 11:50:58 -04:00
// The timeout for waiting for a Windows
2019-06-03 11:55:09 -04:00
// password for Windows instances. Defaults to 20 minutes. Example value:
// 10m
WindowsPasswordTimeout time . Duration ` mapstructure:"windows_password_timeout" required:"false" `
2013-07-16 00:23:40 -04:00
2015-06-13 18:16:12 -04:00
// Communicator settings
2020-01-06 15:01:30 -05:00
Comm communicator . Config ` mapstructure:",squash" `
2020-04-01 07:49:32 -04:00
// One of `public_ip`, `private_ip`, `public_dns`, `private_dns` or `session_manager`.
// If set, either the public IP address, private IP address, public DNS name
2020-01-06 17:12:29 -05:00
// or private DNS name will be used as the host for SSH. The default behaviour
2020-01-06 15:01:30 -05:00
// if inside a VPC is to use the public IP address if available, otherwise
// the private IP address will be used. If not in a VPC the public DNS name
// will be used. Also works for WinRM.
//
// Where Packer is configured for an outbound proxy but WinRM traffic
// should be direct, `ssh_interface` must be set to `private_dns` and
// `<region>.compute.internal` included in the `NO_PROXY` environment
// variable.
2020-04-01 07:49:32 -04:00
//
// When using `session_manager` the machine running Packer must have
2020-06-19 11:47:21 -04:00
// the AWS Session Manager Plugin installed and within the users' system path.
// Connectivity via the `session_manager` interface establishes a secure tunnel
2020-05-06 15:17:38 -04:00
// between the local host and the remote host on an available local port to the specified `ssh_port`.
2020-06-19 11:47:21 -04:00
// See [Session Manager Connections](#session-manager-connections) for more information.
// - Session manager connectivity is currently only implemented for the SSH communicator, not the WinRM communicator.
// - Upon termination the secure tunnel will be terminated automatically, if however there is a failure in
2020-05-06 15:17:38 -04:00
// terminating the tunnel it will automatically terminate itself after 20 minutes of inactivity.
2020-01-06 15:01:30 -05:00
SSHInterface string ` mapstructure:"ssh_interface" `
2020-05-07 14:02:10 -04:00
2020-09-25 04:19:19 -04:00
// The time to wait before establishing the Session Manager session.
// The value of this should be a duration. Examples are
// `5s` and `1m30s` which will cause Packer to wait five seconds and one
// minute 30 seconds, respectively. If no set, defaults to 10 seconds.
// This option is useful when the remote port takes longer to become available.
PauseBeforeSSM time . Duration ` mapstructure:"pause_before_ssm" `
2020-05-07 14:02:10 -04:00
// Which port to connect the local end of the session tunnel to. If
// left blank, Packer will choose a port for you from available ports.
2020-05-08 06:36:41 -04:00
// This option is only used when `ssh_interface` is set `session_manager`.
2020-05-07 14:02:10 -04:00
SessionManagerPort int ` mapstructure:"session_manager_port" `
2013-07-16 00:23:40 -04:00
}
2015-05-27 14:35:56 -04:00
func ( c * RunConfig ) Prepare ( ctx * interpolate . Context ) [ ] error {
2016-10-02 16:20:36 -04:00
// If we are not given an explicit ssh_keypair_name or
// ssh_private_key_file, then create a temporary one, but only if the
// temporary_key_pair_name has not been provided and we are not using
// ssh_password.
2018-08-28 11:47:02 -04:00
if c . Comm . SSHKeyPairName == "" && c . Comm . SSHTemporaryKeyPairName == "" &&
2018-08-23 10:35:07 -04:00
c . Comm . SSHPrivateKeyFile == "" && c . Comm . SSHPassword == "" {
2016-10-02 16:20:36 -04:00
2018-08-28 11:47:02 -04:00
c . Comm . SSHTemporaryKeyPairName = fmt . Sprintf ( "packer_%s" , uuid . TimeOrderedUUID ( ) )
2013-09-05 08:28:31 -04:00
}
2015-06-14 01:35:45 -04:00
if c . WindowsPasswordTimeout == 0 {
2017-02-24 06:08:17 -05:00
c . WindowsPasswordTimeout = 20 * time . Minute
2015-06-14 01:35:45 -04:00
}
2017-01-18 14:34:36 -05:00
if c . RunTags == nil {
c . RunTags = make ( map [ string ] string )
}
2017-11-27 20:26:55 -05:00
// Validation
errs := c . Comm . Prepare ( ctx )
2017-11-21 21:49:38 -05:00
2020-03-16 07:36:20 -04:00
// Copy singular tag maps
2020-03-16 12:47:44 -04:00
errs = append ( errs , c . RunTag . CopyOn ( & c . RunTags ) ... )
errs = append ( errs , c . SpotTag . CopyOn ( & c . SpotTags ) ... )
2020-03-16 07:19:34 -04:00
2020-03-13 13:04:48 -04:00
for _ , preparer := range [ ] interface { Prepare ( ) [ ] error } {
2020-03-13 12:17:46 -04:00
& c . SourceAmiFilter ,
& c . SecurityGroupFilter ,
& c . SubnetFilter ,
& c . VpcFilter ,
} {
2020-03-13 13:04:48 -04:00
errs = append ( errs , preparer . Prepare ( ) ... )
2020-03-13 12:17:46 -04:00
}
2018-03-13 23:28:19 -04:00
// Validating ssh_interface
2019-07-02 13:46:10 -04:00
if c . SSHInterface != "public_ip" &&
c . SSHInterface != "private_ip" &&
c . SSHInterface != "public_dns" &&
c . SSHInterface != "private_dns" &&
2020-03-30 07:47:31 -04:00
c . SSHInterface != "session_manager" &&
2019-07-02 13:46:10 -04:00
c . SSHInterface != "" {
errs = append ( errs , fmt . Errorf ( "Unknown interface type: %s" , c . SSHInterface ) )
2017-11-27 17:46:01 -05:00
}
2020-04-16 14:48:17 -04:00
// Connectivity via Session Manager has a few requirements
if c . SSHInterface == "session_manager" {
if c . Comm . Type == "winrm" {
2020-05-08 06:36:41 -04:00
msg := fmt . Errorf ( ` session_manager connectivity is not supported with the "winrm" communicator; please use "ssh" ` )
2020-04-16 14:48:17 -04:00
errs = append ( errs , msg )
}
2020-04-29 15:15:27 -04:00
if c . IamInstanceProfile == "" && c . TemporaryIamInstanceProfilePolicyDocument == nil {
2020-05-08 06:36:41 -04:00
msg := fmt . Errorf ( ` no iam_instance_profile defined; session_manager connectivity requires a valid instance profile with AmazonSSMManagedInstanceCore permissions. Alternatively a temporary_iam_instance_profile_policy_document can be used. ` )
2020-04-16 14:48:17 -04:00
errs = append ( errs , msg )
}
}
2018-08-28 10:10:39 -04:00
if c . Comm . SSHKeyPairName != "" {
2018-08-23 10:35:07 -04:00
if c . Comm . Type == "winrm" && c . Comm . WinRMPassword == "" && c . Comm . SSHPrivateKeyFile == "" {
2018-05-15 05:07:09 -04:00
errs = append ( errs , fmt . Errorf ( "ssh_private_key_file must be provided to retrieve the winrm password when using ssh_keypair_name." ) )
2018-08-23 10:35:07 -04:00
} else if c . Comm . SSHPrivateKeyFile == "" && ! c . Comm . SSHAgentAuth {
2018-05-15 05:07:09 -04:00
errs = append ( errs , fmt . Errorf ( "ssh_private_key_file must be provided or ssh_agent_auth enabled when ssh_keypair_name is specified." ) )
2017-03-13 16:14:16 -04:00
}
}
2016-08-20 19:34:22 -04:00
if c . SourceAmi == "" && c . SourceAmiFilter . Empty ( ) {
2018-05-15 05:07:09 -04:00
errs = append ( errs , fmt . Errorf ( "A source_ami or source_ami_filter must be specified" ) )
2013-07-16 00:23:40 -04:00
}
2018-08-13 20:01:13 -04:00
if c . SourceAmi == "" && c . SourceAmiFilter . NoOwner ( ) {
errs = append ( errs , fmt . Errorf ( "For security reasons, your source AMI filter must declare an owner." ) )
}
2019-05-22 13:16:42 -04:00
if c . InstanceType == "" && len ( c . SpotInstanceTypes ) == 0 {
errs = append ( errs , fmt . Errorf ( "either instance_type or " +
"spot_instance_types must be specified" ) )
}
if c . InstanceType != "" && len ( c . SpotInstanceTypes ) > 0 {
errs = append ( errs , fmt . Errorf ( "either instance_type or " +
"spot_instance_types must be specified, not both" ) )
2013-07-16 00:23:40 -04:00
}
2018-09-03 02:33:58 -04:00
if c . BlockDurationMinutes % 60 != 0 {
errs = append ( errs , fmt . Errorf (
"block_duration_minutes must be multiple of 60" ) )
}
2017-10-13 02:22:15 -04:00
if c . SpotTags != nil {
if c . SpotPrice == "" || c . SpotPrice == "0" {
errs = append ( errs , fmt . Errorf (
"spot_tags should not be set when not requesting a spot instance" ) )
}
}
2013-08-12 14:52:43 -04:00
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 != "" {
if _ , err := os . Stat ( c . UserDataFile ) ; err != nil {
errs = append ( errs , fmt . Errorf ( "user_data_file not found: %s" , c . UserDataFile ) )
}
}
2013-10-02 13:52:16 -04:00
if c . SecurityGroupId != "" {
if len ( c . SecurityGroupIds ) > 0 {
errs = append ( errs , fmt . Errorf ( "Only one of security_group_id or security_group_ids can be specified." ) )
} else {
c . SecurityGroupIds = [ ] string { c . SecurityGroupId }
c . SecurityGroupId = ""
}
}
2019-03-30 18:47:03 -04:00
if len ( c . TemporarySGSourceCidrs ) == 0 {
c . TemporarySGSourceCidrs = [ ] string { "0.0.0.0/0" }
2017-10-12 20:05:31 -04:00
} else {
2019-03-30 18:47:03 -04:00
for _ , cidr := range c . TemporarySGSourceCidrs {
if _ , _ , err := net . ParseCIDR ( cidr ) ; err != nil {
errs = append ( errs , fmt . Errorf ( "Error parsing CIDR in temporary_security_group_source_cidrs: %s" , err . Error ( ) ) )
}
2017-10-12 20:05:31 -04:00
}
2017-09-25 20:57:56 -04:00
}
2016-05-20 05:54:45 -04:00
if c . InstanceInitiatedShutdownBehavior == "" {
c . InstanceInitiatedShutdownBehavior = "stop"
2016-05-20 16:33:41 -04:00
} else if ! reShutdownBehavior . MatchString ( c . InstanceInitiatedShutdownBehavior ) {
2016-12-14 15:50:26 -05:00
errs = append ( errs , fmt . Errorf ( "shutdown_behavior only accepts 'stop' or 'terminate' values." ) )
2016-05-20 05:54:45 -04:00
}
2018-05-12 11:20:01 -04:00
if c . EnableT2Unlimited {
if c . SpotPrice != "" {
2020-04-29 15:15:27 -04:00
errs = append ( errs , fmt . Errorf ( "Error: T2 Unlimited cannot be used in conjunction with Spot Instances" ) )
2018-05-12 11:20:01 -04:00
}
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 ) )
}
}
2020-10-12 18:05:58 -04:00
if c . Tenancy != "" &&
c . Tenancy != "default" &&
c . Tenancy != "dedicated" &&
c . Tenancy != "host" {
errs = append ( errs , fmt . Errorf ( "Error: Unknown tenancy type %s" , c . Tenancy ) )
2020-10-11 02:06:28 -04:00
}
2013-07-16 00:23:40 -04:00
return errs
}
2017-12-08 17:56:19 -05:00
func ( c * RunConfig ) IsSpotInstance ( ) bool {
return c . SpotPrice != "" && c . SpotPrice != "0"
}
2020-04-16 14:48:17 -04:00
func ( c * RunConfig ) SSMAgentEnabled ( ) bool {
2020-04-29 15:15:27 -04:00
hasIamInstanceProfile := c . IamInstanceProfile != "" || c . TemporaryIamInstanceProfilePolicyDocument != nil
return c . SSHInterface == "session_manager" && hasIamInstanceProfile
2020-04-16 14:48:17 -04:00
}