Merge branch 'master' of github.com:hashicorp/packer into google-impersonation
This commit is contained in:
commit
b1c74f9df0
|
@ -7,11 +7,11 @@ version: 2.1
|
||||||
executors:
|
executors:
|
||||||
golang:
|
golang:
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/golang:1.13
|
- image: circleci/golang:1.15
|
||||||
resource_class: medium+
|
resource_class: medium+
|
||||||
darwin:
|
darwin:
|
||||||
macos:
|
macos:
|
||||||
xcode: "9.0"
|
xcode: "12.0.0"
|
||||||
|
|
||||||
commands:
|
commands:
|
||||||
install-go-run-tests-unix:
|
install-go-run-tests-unix:
|
||||||
|
@ -67,7 +67,7 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- install-go-run-tests-unix:
|
- install-go-run-tests-unix:
|
||||||
GOOS: darwin
|
GOOS: darwin
|
||||||
GOVERSION: "1.13"
|
GOVERSION: "1.15"
|
||||||
- codecov/upload:
|
- codecov/upload:
|
||||||
file: coverage.txt
|
file: coverage.txt
|
||||||
test-windows:
|
test-windows:
|
||||||
|
@ -76,7 +76,7 @@ jobs:
|
||||||
shell: bash.exe
|
shell: bash.exe
|
||||||
steps:
|
steps:
|
||||||
- install-go-run-tests-windows:
|
- install-go-run-tests-windows:
|
||||||
GOVERSION: "1.13"
|
GOVERSION: "1.15"
|
||||||
- codecov/upload:
|
- codecov/upload:
|
||||||
file: coverage.txt
|
file: coverage.txt
|
||||||
check-lint:
|
check-lint:
|
||||||
|
|
|
@ -13,5 +13,6 @@ coverage:
|
||||||
project: off
|
project: off
|
||||||
patch: off
|
patch: off
|
||||||
|
|
||||||
ignore: # ignore hcl2spec generated code for coverage
|
ignore: # ignore hcl2spec generated code for coverage and mocks
|
||||||
- "**/*.hcl2spec.go"
|
- "**/*.hcl2spec.go"
|
||||||
|
- "**/*_mock.go"
|
46
CHANGELOG.md
46
CHANGELOG.md
|
@ -1,13 +1,37 @@
|
||||||
## 1.6.3 (Upcoming)
|
## 1.6.5 (Upcoming)
|
||||||
|
|
||||||
|
## 1.6.4 (September 30, 2020)
|
||||||
|
|
||||||
|
### BUG FIXES:
|
||||||
|
* builder/amazon: Fix authentication issue when using instance profiles or
|
||||||
|
assumed roles for loading session-derived credentials. [GH-10007]
|
||||||
|
* builder/azure: Fix crash when using `azure_tag` or `azure_tags` configuration
|
||||||
|
options. [GH-10014]
|
||||||
|
* builder/qemu: Ensure `qemu_img_args` are honored during the disk convert
|
||||||
|
step. [GH-10001]
|
||||||
|
|
||||||
|
## 1.6.3 (September 25, 2020)
|
||||||
|
|
||||||
### IMPROVEMENTS:
|
### IMPROVEMENTS:
|
||||||
|
* builder/amazon: Add `pause_before_ssm` option to pause for some time before
|
||||||
|
establishing a Session Manager session; defaults to 10s. [GH-9988]
|
||||||
|
* builder/amazon: Implement assume_role option that matches Terraform behavior.
|
||||||
|
[GH-9981]
|
||||||
* builder/azure: Support publishing to a Shared Image Gallery with a different
|
* builder/azure: Support publishing to a Shared Image Gallery with a different
|
||||||
subscription id [GH-9875]
|
subscription id [GH-9875]
|
||||||
|
* builder/openstack: Add `external_source_image_url` and
|
||||||
|
`external_source_image_format` to support building images from external
|
||||||
|
source URLs. [GH-9992]
|
||||||
|
* builder/openstack: Include API requests and responses as part of the debug
|
||||||
|
log output. [GH-9972]
|
||||||
* builder/oracle-oci: Add `create_vnic_details` option for launch details.
|
* builder/oracle-oci: Add `create_vnic_details` option for launch details.
|
||||||
[GH-9856]
|
[GH-9856]
|
||||||
* builder/oracle-oci: Allow freeform and defined tags to be added instance.
|
* builder/oracle-oci: Allow freeform and defined tags to be added to an instance.
|
||||||
[GH-9802]
|
[GH-9802]
|
||||||
* builder/proxmox: Add ability to specify interfaces for http_directroy and VM.
|
* builder/proxmox: Add `io_thread` option for supporting io threads when using
|
||||||
|
a `virtio-scsi-single` controller with a `scsi` or `virtio` disk type.
|
||||||
|
[GH-9969]
|
||||||
|
* builder/proxmox: Add ability to specify interfaces for http_directory and VM.
|
||||||
[GH-9874]
|
[GH-9874]
|
||||||
* builder/proxmox: Allow the mounting of multiple ISOs via the `cd_drive`
|
* builder/proxmox: Allow the mounting of multiple ISOs via the `cd_drive`
|
||||||
option. [GH-9653]
|
option. [GH-9653]
|
||||||
|
@ -16,17 +40,22 @@
|
||||||
to qemu-img [GH-9956]
|
to qemu-img [GH-9956]
|
||||||
* builder/qemu: Add `skip_resize_disk` option to skip the resizing of QCOW2
|
* builder/qemu: Add `skip_resize_disk` option to skip the resizing of QCOW2
|
||||||
images. [GH-9896] [GH-9860]
|
images. [GH-9896] [GH-9860]
|
||||||
* builder/qemu: Skip qemu-img convert on MacOS to prevent the creation
|
* builder/qemu: Skip qemu-img convert on MacOS to prevent the creation of
|
||||||
of corrupt images [QEMU
|
corrupt images [QEMU
|
||||||
#1776920](https://bugs.launchpad.net/qemu/+bug/1776920) [GH-9949]
|
#1776920](https://bugs.launchpad.net/qemu/+bug/1776920) [GH-9949]
|
||||||
* builder/scaleway: Change default boottype to local. [GH-9853]
|
* builder/scaleway: Change default boottype to local. [GH-9853]
|
||||||
* builder/scaleway: Update scaleway to use non-deprecated sdk. [GH-9902]
|
* builder/scaleway: Update scaleway to use non-deprecated sdk. [GH-9902]
|
||||||
* builder/vmware: Add `vnc_over_websocket` to allow the sending of a
|
* builder/vmware: Add `vnc_over_websocket` to allow the sending of a
|
||||||
`boot_command` to hosts running ESXi 6.7 and above. [GH-9938]
|
`boot_command` to hosts running ESXi 6.7 and above. [GH-9938]
|
||||||
|
* builder/vmware: Allow user to set vmware tools source path. [GH-9983]
|
||||||
* builder/vsphere-clone: Add ability to set `mac_address` [GH-9930]
|
* builder/vsphere-clone: Add ability to set `mac_address` [GH-9930]
|
||||||
|
* builder/vsphere-clone: Add floppy_files, cd_files, and iso_paths options.
|
||||||
|
[GH-9963]
|
||||||
* builder/vsphere-iso: Add NVMe controller support. [GH-9880]
|
* builder/vsphere-iso: Add NVMe controller support. [GH-9880]
|
||||||
* builder/vsphere: Look for a default resource pool when root resource pool is
|
* builder/vsphere: Look for a default resource pool when root resource pool is
|
||||||
not found. [GH-9809]
|
not found. [GH-9809]
|
||||||
|
* core: Add support for running cygwin/msys2 based cd/iso creation tool
|
||||||
|
[GH-9954]
|
||||||
* core: New `cd_files` option to mount iso for modern OSes which don't support
|
* core: New `cd_files` option to mount iso for modern OSes which don't support
|
||||||
floppies. [GH-9796] [GH-9919] [GH-9928] [GH-9932] [GH-9941]
|
floppies. [GH-9796] [GH-9919] [GH-9928] [GH-9932] [GH-9941]
|
||||||
* HCL2: When the type of a variable is not known evaluate setting as a literal
|
* HCL2: When the type of a variable is not known evaluate setting as a literal
|
||||||
|
@ -41,6 +70,9 @@
|
||||||
error was creating multiple spot instances. [GH-9946]
|
error was creating multiple spot instances. [GH-9946]
|
||||||
* builder/amazon-ebssurrogate: Fix issue where builder defaults to AWS managed
|
* builder/amazon-ebssurrogate: Fix issue where builder defaults to AWS managed
|
||||||
key even when custom `kms_key_id` is set. [GH-9959]
|
key even when custom `kms_key_id` is set. [GH-9959]
|
||||||
|
* builder/amazon: Update ssm_driver log polling logic to prevent infinite loops
|
||||||
|
when SSM driver is terminated outside of Packer. [GH-9991]
|
||||||
|
* builder/azure: Fix crash when using HCL2 configs. [GH-9984] [GH-9985]
|
||||||
* builder/qemu: Fix hardcoded lowerbound causing negative ports [GH-9905]
|
* builder/qemu: Fix hardcoded lowerbound causing negative ports [GH-9905]
|
||||||
* builder/qemu: Skip compaction when backing file is used. [GH-9918]
|
* builder/qemu: Skip compaction when backing file is used. [GH-9918]
|
||||||
* builder/scaleway: Add pre validate step to prevent the creation of multiple
|
* builder/scaleway: Add pre validate step to prevent the creation of multiple
|
||||||
|
@ -50,7 +82,9 @@
|
||||||
* builder/vsphere: Fix overly strict iso_path validation regex. [GH-9855]
|
* builder/vsphere: Fix overly strict iso_path validation regex. [GH-9855]
|
||||||
* command/console: Prevent failure when there are unknown vars. [GH-9864]
|
* command/console: Prevent failure when there are unknown vars. [GH-9864]
|
||||||
* command/inspect: Allow unset variables in HCL2 and JSON. [GH-9832]
|
* command/inspect: Allow unset variables in HCL2 and JSON. [GH-9832]
|
||||||
* core: use $APPDATA over $HOME on Windows hosts when determining homedir.
|
* core: Prevent the UI progressbar from hanging and crashing when there is no
|
||||||
|
TTY available. [GH-9974]
|
||||||
|
* core: Use $APPDATA over $HOME on Windows hosts when determining homedir.
|
||||||
[GH-9830]
|
[GH-9830]
|
||||||
* post-processor/digitalocean-import: Fix crash caused by empty artifact.Files
|
* post-processor/digitalocean-import: Fix crash caused by empty artifact.Files
|
||||||
slice. [GH-9857]
|
slice. [GH-9857]
|
||||||
|
|
|
@ -41,7 +41,9 @@ type FlatConfig struct {
|
||||||
SnapshotUsers []string `mapstructure:"snapshot_users" required:"false" cty:"snapshot_users" hcl:"snapshot_users"`
|
SnapshotUsers []string `mapstructure:"snapshot_users" required:"false" cty:"snapshot_users" hcl:"snapshot_users"`
|
||||||
SnapshotGroups []string `mapstructure:"snapshot_groups" required:"false" cty:"snapshot_groups" hcl:"snapshot_groups"`
|
SnapshotGroups []string `mapstructure:"snapshot_groups" required:"false" cty:"snapshot_groups" hcl:"snapshot_groups"`
|
||||||
AccessKey *string `mapstructure:"access_key" required:"true" cty:"access_key" hcl:"access_key"`
|
AccessKey *string `mapstructure:"access_key" required:"true" cty:"access_key" hcl:"access_key"`
|
||||||
|
AssumeRole *common.FlatAssumeRoleConfig `mapstructure:"assume_role" required:"false" cty:"assume_role" hcl:"assume_role"`
|
||||||
CustomEndpointEc2 *string `mapstructure:"custom_endpoint_ec2" required:"false" cty:"custom_endpoint_ec2" hcl:"custom_endpoint_ec2"`
|
CustomEndpointEc2 *string `mapstructure:"custom_endpoint_ec2" required:"false" cty:"custom_endpoint_ec2" hcl:"custom_endpoint_ec2"`
|
||||||
|
CredsFilename *string `mapstructure:"shared_credentials_file" required:"false" cty:"shared_credentials_file" hcl:"shared_credentials_file"`
|
||||||
DecodeAuthZMessages *bool `mapstructure:"decode_authorization_messages" required:"false" cty:"decode_authorization_messages" hcl:"decode_authorization_messages"`
|
DecodeAuthZMessages *bool `mapstructure:"decode_authorization_messages" required:"false" cty:"decode_authorization_messages" hcl:"decode_authorization_messages"`
|
||||||
InsecureSkipTLSVerify *bool `mapstructure:"insecure_skip_tls_verify" required:"false" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"`
|
InsecureSkipTLSVerify *bool `mapstructure:"insecure_skip_tls_verify" required:"false" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"`
|
||||||
MaxRetries *int `mapstructure:"max_retries" required:"false" cty:"max_retries" hcl:"max_retries"`
|
MaxRetries *int `mapstructure:"max_retries" required:"false" cty:"max_retries" hcl:"max_retries"`
|
||||||
|
@ -50,6 +52,7 @@ type FlatConfig struct {
|
||||||
RawRegion *string `mapstructure:"region" required:"true" cty:"region" hcl:"region"`
|
RawRegion *string `mapstructure:"region" required:"true" cty:"region" hcl:"region"`
|
||||||
SecretKey *string `mapstructure:"secret_key" required:"true" cty:"secret_key" hcl:"secret_key"`
|
SecretKey *string `mapstructure:"secret_key" required:"true" cty:"secret_key" hcl:"secret_key"`
|
||||||
SkipMetadataApiCheck *bool `mapstructure:"skip_metadata_api_check" cty:"skip_metadata_api_check" hcl:"skip_metadata_api_check"`
|
SkipMetadataApiCheck *bool `mapstructure:"skip_metadata_api_check" cty:"skip_metadata_api_check" hcl:"skip_metadata_api_check"`
|
||||||
|
SkipCredsValidation *bool `mapstructure:"skip_credential_validation" cty:"skip_credential_validation" hcl:"skip_credential_validation"`
|
||||||
Token *string `mapstructure:"token" required:"false" cty:"token" hcl:"token"`
|
Token *string `mapstructure:"token" required:"false" cty:"token" hcl:"token"`
|
||||||
VaultAWSEngine *common.FlatVaultAWSEngineOptions `mapstructure:"vault_aws_engine" required:"false" cty:"vault_aws_engine" hcl:"vault_aws_engine"`
|
VaultAWSEngine *common.FlatVaultAWSEngineOptions `mapstructure:"vault_aws_engine" required:"false" cty:"vault_aws_engine" hcl:"vault_aws_engine"`
|
||||||
PollingConfig *common.FlatAWSPollingConfig `mapstructure:"aws_polling" required:"false" cty:"aws_polling" hcl:"aws_polling"`
|
PollingConfig *common.FlatAWSPollingConfig `mapstructure:"aws_polling" required:"false" cty:"aws_polling" hcl:"aws_polling"`
|
||||||
|
@ -117,7 +120,9 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
"snapshot_users": &hcldec.AttrSpec{Name: "snapshot_users", Type: cty.List(cty.String), Required: false},
|
"snapshot_users": &hcldec.AttrSpec{Name: "snapshot_users", Type: cty.List(cty.String), Required: false},
|
||||||
"snapshot_groups": &hcldec.AttrSpec{Name: "snapshot_groups", Type: cty.List(cty.String), Required: false},
|
"snapshot_groups": &hcldec.AttrSpec{Name: "snapshot_groups", Type: cty.List(cty.String), Required: false},
|
||||||
"access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false},
|
"access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false},
|
||||||
|
"assume_role": &hcldec.BlockSpec{TypeName: "assume_role", Nested: hcldec.ObjectSpec((*common.FlatAssumeRoleConfig)(nil).HCL2Spec())},
|
||||||
"custom_endpoint_ec2": &hcldec.AttrSpec{Name: "custom_endpoint_ec2", Type: cty.String, Required: false},
|
"custom_endpoint_ec2": &hcldec.AttrSpec{Name: "custom_endpoint_ec2", Type: cty.String, Required: false},
|
||||||
|
"shared_credentials_file": &hcldec.AttrSpec{Name: "shared_credentials_file", Type: cty.String, Required: false},
|
||||||
"decode_authorization_messages": &hcldec.AttrSpec{Name: "decode_authorization_messages", Type: cty.Bool, Required: false},
|
"decode_authorization_messages": &hcldec.AttrSpec{Name: "decode_authorization_messages", Type: cty.Bool, Required: false},
|
||||||
"insecure_skip_tls_verify": &hcldec.AttrSpec{Name: "insecure_skip_tls_verify", Type: cty.Bool, Required: false},
|
"insecure_skip_tls_verify": &hcldec.AttrSpec{Name: "insecure_skip_tls_verify", Type: cty.Bool, Required: false},
|
||||||
"max_retries": &hcldec.AttrSpec{Name: "max_retries", Type: cty.Number, Required: false},
|
"max_retries": &hcldec.AttrSpec{Name: "max_retries", Type: cty.Number, Required: false},
|
||||||
|
@ -126,6 +131,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
"region": &hcldec.AttrSpec{Name: "region", Type: cty.String, Required: false},
|
"region": &hcldec.AttrSpec{Name: "region", Type: cty.String, Required: false},
|
||||||
"secret_key": &hcldec.AttrSpec{Name: "secret_key", Type: cty.String, Required: false},
|
"secret_key": &hcldec.AttrSpec{Name: "secret_key", Type: cty.String, Required: false},
|
||||||
"skip_metadata_api_check": &hcldec.AttrSpec{Name: "skip_metadata_api_check", Type: cty.Bool, Required: false},
|
"skip_metadata_api_check": &hcldec.AttrSpec{Name: "skip_metadata_api_check", Type: cty.Bool, Required: false},
|
||||||
|
"skip_credential_validation": &hcldec.AttrSpec{Name: "skip_credential_validation", Type: cty.Bool, Required: false},
|
||||||
"token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false},
|
"token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false},
|
||||||
"vault_aws_engine": &hcldec.BlockSpec{TypeName: "vault_aws_engine", Nested: hcldec.ObjectSpec((*common.FlatVaultAWSEngineOptions)(nil).HCL2Spec())},
|
"vault_aws_engine": &hcldec.BlockSpec{TypeName: "vault_aws_engine", Nested: hcldec.ObjectSpec((*common.FlatVaultAWSEngineOptions)(nil).HCL2Spec())},
|
||||||
"aws_polling": &hcldec.BlockSpec{TypeName: "aws_polling", Nested: hcldec.ObjectSpec((*common.FlatAWSPollingConfig)(nil).HCL2Spec())},
|
"aws_polling": &hcldec.BlockSpec{TypeName: "aws_polling", Nested: hcldec.ObjectSpec((*common.FlatAWSPollingConfig)(nil).HCL2Spec())},
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//go:generate struct-markdown
|
//go:generate struct-markdown
|
||||||
//go:generate mapstructure-to-hcl2 -type VaultAWSEngineOptions
|
//go:generate mapstructure-to-hcl2 -type VaultAWSEngineOptions,AssumeRoleConfig
|
||||||
|
|
||||||
package common
|
package common
|
||||||
|
|
||||||
|
@ -11,15 +11,67 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
awsCredentials "github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
"github.com/aws/aws-sdk-go/aws/session"
|
"github.com/aws/aws-sdk-go/aws/session"
|
||||||
"github.com/aws/aws-sdk-go/service/ec2"
|
"github.com/aws/aws-sdk-go/service/ec2"
|
||||||
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
|
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
|
||||||
|
awsbase "github.com/hashicorp/aws-sdk-go-base"
|
||||||
cleanhttp "github.com/hashicorp/go-cleanhttp"
|
cleanhttp "github.com/hashicorp/go-cleanhttp"
|
||||||
"github.com/hashicorp/packer/template/interpolate"
|
"github.com/hashicorp/packer/template/interpolate"
|
||||||
vaultapi "github.com/hashicorp/vault/api"
|
vaultapi "github.com/hashicorp/vault/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// AssumeRoleConfig lets users set configuration options for assuming a special
|
||||||
|
// role when executing Packer.
|
||||||
|
//
|
||||||
|
// Usage example:
|
||||||
|
//
|
||||||
|
// HCL config example:
|
||||||
|
//
|
||||||
|
// ```HCL
|
||||||
|
// source "example" "amazon-ebs"{
|
||||||
|
// assume_role {
|
||||||
|
// role_arn = "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME"
|
||||||
|
// session_name = "SESSION_NAME"
|
||||||
|
// external_id = "EXTERNAL_ID"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// JSON config example:
|
||||||
|
//
|
||||||
|
// ```json
|
||||||
|
// builder{
|
||||||
|
// "type": "amazon-ebs",
|
||||||
|
// "assume_role": {
|
||||||
|
// "role_arn" : "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME",
|
||||||
|
// "session_name": "SESSION_NAME",
|
||||||
|
// "external_id" : "EXTERNAL_ID"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
type AssumeRoleConfig struct {
|
||||||
|
// Amazon Resource Name (ARN) of the IAM Role to assume.
|
||||||
|
AssumeRoleARN string `mapstructure:"role_arn" required:"false"`
|
||||||
|
// Number of seconds to restrict the assume role session duration.
|
||||||
|
AssumeRoleDurationSeconds int `mapstructure:"duration_seconds" required:"false"`
|
||||||
|
// The external ID to use when assuming the role. If omitted, no external
|
||||||
|
// ID is passed to the AssumeRole call.
|
||||||
|
AssumeRoleExternalID string `mapstructure:"external_id" required:"false"`
|
||||||
|
// IAM Policy JSON describing further restricting permissions for the IAM
|
||||||
|
// Role being assumed.
|
||||||
|
AssumeRolePolicy string `mapstructure:"policy" required:"false"`
|
||||||
|
// Set of Amazon Resource Names (ARNs) of IAM Policies describing further
|
||||||
|
// restricting permissions for the IAM Role being
|
||||||
|
AssumeRolePolicyARNs []string `mapstructure:"policy_arns" required:"false"`
|
||||||
|
// Session name to use when assuming the role.
|
||||||
|
AssumeRoleSessionName string `mapstructure:"session_name" required:"false"`
|
||||||
|
// Map of assume role session tags.
|
||||||
|
AssumeRoleTags map[string]string `mapstructure:"tags" required:"false"`
|
||||||
|
// Set of assume role session tag keys to pass to any subsequent sessions.
|
||||||
|
AssumeRoleTransitiveTagKeys []string `mapstructure:"transitive_tag_keys" required:"false"`
|
||||||
|
}
|
||||||
|
|
||||||
type VaultAWSEngineOptions struct {
|
type VaultAWSEngineOptions struct {
|
||||||
Name string `mapstructure:"name"`
|
Name string `mapstructure:"name"`
|
||||||
RoleARN string `mapstructure:"role_arn"`
|
RoleARN string `mapstructure:"role_arn"`
|
||||||
|
@ -48,10 +100,17 @@ type AccessConfig struct {
|
||||||
// is not required if you are using `use_vault_aws_engine` for
|
// is not required if you are using `use_vault_aws_engine` for
|
||||||
// authentication instead.
|
// authentication instead.
|
||||||
AccessKey string `mapstructure:"access_key" required:"true"`
|
AccessKey string `mapstructure:"access_key" required:"true"`
|
||||||
|
// If provided with a role ARN, Packer will attempt to assume this role
|
||||||
|
// using the supplied credentials. See
|
||||||
|
// [AssumeRoleConfig](#assume-role-configuration) below for more
|
||||||
|
// details on all of the options available, and for a usage example.
|
||||||
|
AssumeRole AssumeRoleConfig `mapstructure:"assume_role" required:"false"`
|
||||||
// This option is useful if you use a cloud
|
// This option is useful if you use a cloud
|
||||||
// provider whose API is compatible with aws EC2. Specify another endpoint
|
// provider whose API is compatible with aws EC2. Specify another endpoint
|
||||||
// like this https://ec2.custom.endpoint.com.
|
// like this https://ec2.custom.endpoint.com.
|
||||||
CustomEndpointEc2 string `mapstructure:"custom_endpoint_ec2" required:"false"`
|
CustomEndpointEc2 string `mapstructure:"custom_endpoint_ec2" required:"false"`
|
||||||
|
// Path to a credentials file to load credentials from
|
||||||
|
CredsFilename string `mapstructure:"shared_credentials_file" required:"false"`
|
||||||
// Enable automatic decoding of any encoded authorization (error) messages
|
// Enable automatic decoding of any encoded authorization (error) messages
|
||||||
// using the `sts:DecodeAuthorizationMessage` API. Note: requires that the
|
// using the `sts:DecodeAuthorizationMessage` API. Note: requires that the
|
||||||
// effective user/role have permissions to `sts:DecodeAuthorizationMessage`
|
// effective user/role have permissions to `sts:DecodeAuthorizationMessage`
|
||||||
|
@ -86,6 +145,8 @@ type AccessConfig struct {
|
||||||
// validation of the ami_regions configuration option. Default false.
|
// validation of the ami_regions configuration option. Default false.
|
||||||
SkipValidation bool `mapstructure:"skip_region_validation" required:"false"`
|
SkipValidation bool `mapstructure:"skip_region_validation" required:"false"`
|
||||||
SkipMetadataApiCheck bool `mapstructure:"skip_metadata_api_check"`
|
SkipMetadataApiCheck bool `mapstructure:"skip_metadata_api_check"`
|
||||||
|
// Set to true if you want to skip validating AWS credentials before runtime.
|
||||||
|
SkipCredsValidation bool `mapstructure:"skip_credential_validation"`
|
||||||
// The access token to use. This is different from the
|
// 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
|
// 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
|
// probably don't need it. This will also be read from the AWS_SESSION_TOKEN
|
||||||
|
@ -152,16 +213,13 @@ func (c *AccessConfig) Session() (*session.Session, error) {
|
||||||
return c.session, nil
|
return c.session, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create new AWS config
|
||||||
config := aws.NewConfig().WithCredentialsChainVerboseErrors(true)
|
config := aws.NewConfig().WithCredentialsChainVerboseErrors(true)
|
||||||
if c.MaxRetries > 0 {
|
if c.MaxRetries > 0 {
|
||||||
config = config.WithMaxRetries(c.MaxRetries)
|
config = config.WithMaxRetries(c.MaxRetries)
|
||||||
}
|
}
|
||||||
|
|
||||||
staticCreds := credentials.NewStaticCredentials(c.AccessKey, c.SecretKey, c.Token)
|
// Set AWS config defaults.
|
||||||
if _, err := staticCreds.Get(); err != credentials.ErrStaticCredentialsEmpty {
|
|
||||||
config.WithCredentials(staticCreds)
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.RawRegion != "" {
|
if c.RawRegion != "" {
|
||||||
config = config.WithRegion(c.RawRegion)
|
config = config.WithRegion(c.RawRegion)
|
||||||
}
|
}
|
||||||
|
@ -179,6 +237,16 @@ func (c *AccessConfig) Session() (*session.Session, error) {
|
||||||
}
|
}
|
||||||
transport.Proxy = http.ProxyFromEnvironment
|
transport.Proxy = http.ProxyFromEnvironment
|
||||||
|
|
||||||
|
// Figure out which possible credential providers are valid; test that we
|
||||||
|
// can get credentials via the selected providers, and set the providers in
|
||||||
|
// the config.
|
||||||
|
creds, err := c.GetCredentials(config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
config.WithCredentials(creds)
|
||||||
|
|
||||||
|
// Create session options based on our AWS config
|
||||||
opts := session.Options{
|
opts := session.Options{
|
||||||
SharedConfigState: session.SharedConfigEnable,
|
SharedConfigState: session.SharedConfigEnable,
|
||||||
Config: *config,
|
Config: *config,
|
||||||
|
@ -204,9 +272,7 @@ func (c *AccessConfig) Session() (*session.Session, error) {
|
||||||
cp, err := c.session.Config.Credentials.Get()
|
cp, err := c.session.Config.Credentials.Get()
|
||||||
|
|
||||||
if IsAWSErr(err, "NoCredentialProviders", "") {
|
if IsAWSErr(err, "NoCredentialProviders", "") {
|
||||||
return nil, fmt.Errorf("No valid credential sources found for AWS Builder. " +
|
return nil, c.NewNoValidCredentialSourcesError(err)
|
||||||
"Please see https://www.packer.io/docs/builders/amazon#specifying-amazon-credentials " +
|
|
||||||
"for more information on providing credentials for the AWS Builder.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -237,6 +303,42 @@ func (c *AccessConfig) IsChinaCloud() bool {
|
||||||
return strings.HasPrefix(c.SessionRegion(), "cn-")
|
return strings.HasPrefix(c.SessionRegion(), "cn-")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetCredentials gets credentials from the environment, shared credentials,
|
||||||
|
// the session (which may include a credential process), or ECS/EC2 metadata
|
||||||
|
// endpoints. GetCredentials also validates the credentials and the ability to
|
||||||
|
// assume a role or will return an error if unsuccessful.
|
||||||
|
func (c *AccessConfig) GetCredentials(config *aws.Config) (*awsCredentials.Credentials, error) {
|
||||||
|
// Reload values into the config used by the Packer-Terraform shared SDK
|
||||||
|
awsbaseConfig := &awsbase.Config{
|
||||||
|
AccessKey: c.AccessKey,
|
||||||
|
AssumeRoleARN: c.AssumeRole.AssumeRoleARN,
|
||||||
|
AssumeRoleDurationSeconds: c.AssumeRole.AssumeRoleDurationSeconds,
|
||||||
|
AssumeRoleExternalID: c.AssumeRole.AssumeRoleExternalID,
|
||||||
|
AssumeRolePolicy: c.AssumeRole.AssumeRolePolicy,
|
||||||
|
AssumeRolePolicyARNs: c.AssumeRole.AssumeRolePolicyARNs,
|
||||||
|
AssumeRoleSessionName: c.AssumeRole.AssumeRoleSessionName,
|
||||||
|
AssumeRoleTags: c.AssumeRole.AssumeRoleTags,
|
||||||
|
AssumeRoleTransitiveTagKeys: c.AssumeRole.AssumeRoleTransitiveTagKeys,
|
||||||
|
CredsFilename: c.CredsFilename,
|
||||||
|
DebugLogging: false,
|
||||||
|
// TODO: implement for Packer
|
||||||
|
// IamEndpoint: c.Endpoints["iam"],
|
||||||
|
Insecure: c.InsecureSkipTLSVerify,
|
||||||
|
MaxRetries: c.MaxRetries,
|
||||||
|
Profile: c.ProfileName,
|
||||||
|
Region: c.RawRegion,
|
||||||
|
SecretKey: c.SecretKey,
|
||||||
|
SkipCredsValidation: c.SkipCredsValidation,
|
||||||
|
SkipMetadataApiCheck: c.SkipMetadataApiCheck,
|
||||||
|
// TODO: implement for Packer
|
||||||
|
// SkipRequestingAccountId: c.SkipRequestingAccountId,
|
||||||
|
// StsEndpoint: c.Endpoints["sts"],
|
||||||
|
Token: c.Token,
|
||||||
|
}
|
||||||
|
|
||||||
|
return awsbase.GetCredentials(awsbaseConfig)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *AccessConfig) GetCredsFromVault() error {
|
func (c *AccessConfig) GetCredsFromVault() error {
|
||||||
// const EnvVaultAddress = "VAULT_ADDR"
|
// const EnvVaultAddress = "VAULT_ADDR"
|
||||||
// const EnvVaultToken = "VAULT_TOKEN"
|
// const EnvVaultToken = "VAULT_TOKEN"
|
||||||
|
@ -306,6 +408,13 @@ func (c *AccessConfig) Prepare(ctx *interpolate.Context) []error {
|
||||||
return errs
|
return errs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *AccessConfig) NewNoValidCredentialSourcesError(err error) error {
|
||||||
|
return fmt.Errorf("No valid credential sources found for AWS Builder. "+
|
||||||
|
"Please see https://www.packer.io/docs/builders/amazon#authentication "+
|
||||||
|
"for more information on providing credentials for the AWS Builder. "+
|
||||||
|
"Error: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *AccessConfig) NewEC2Connection() (ec2iface.EC2API, error) {
|
func (c *AccessConfig) NewEC2Connection() (ec2iface.EC2API, error) {
|
||||||
if c.getEC2Connection != nil {
|
if c.getEC2Connection != nil {
|
||||||
return c.getEC2Connection(), nil
|
return c.getEC2Connection(), nil
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by "mapstructure-to-hcl2 -type VaultAWSEngineOptions"; DO NOT EDIT.
|
// Code generated by "mapstructure-to-hcl2 -type VaultAWSEngineOptions,AssumeRoleConfig"; DO NOT EDIT.
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -6,6 +6,43 @@ import (
|
||||||
"github.com/zclconf/go-cty/cty"
|
"github.com/zclconf/go-cty/cty"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// FlatAssumeRoleConfig is an auto-generated flat version of AssumeRoleConfig.
|
||||||
|
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
||||||
|
type FlatAssumeRoleConfig struct {
|
||||||
|
AssumeRoleARN *string `mapstructure:"role_arn" required:"false" cty:"role_arn" hcl:"role_arn"`
|
||||||
|
AssumeRoleDurationSeconds *int `mapstructure:"duration_seconds" required:"false" cty:"duration_seconds" hcl:"duration_seconds"`
|
||||||
|
AssumeRoleExternalID *string `mapstructure:"external_id" required:"false" cty:"external_id" hcl:"external_id"`
|
||||||
|
AssumeRolePolicy *string `mapstructure:"policy" required:"false" cty:"policy" hcl:"policy"`
|
||||||
|
AssumeRolePolicyARNs []string `mapstructure:"policy_arns" required:"false" cty:"policy_arns" hcl:"policy_arns"`
|
||||||
|
AssumeRoleSessionName *string `mapstructure:"session_name" required:"false" cty:"session_name" hcl:"session_name"`
|
||||||
|
AssumeRoleTags map[string]string `mapstructure:"tags" required:"false" cty:"tags" hcl:"tags"`
|
||||||
|
AssumeRoleTransitiveTagKeys []string `mapstructure:"transitive_tag_keys" required:"false" cty:"transitive_tag_keys" hcl:"transitive_tag_keys"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FlatMapstructure returns a new FlatAssumeRoleConfig.
|
||||||
|
// FlatAssumeRoleConfig is an auto-generated flat version of AssumeRoleConfig.
|
||||||
|
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
|
||||||
|
func (*AssumeRoleConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
|
||||||
|
return new(FlatAssumeRoleConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HCL2Spec returns the hcl spec of a AssumeRoleConfig.
|
||||||
|
// This spec is used by HCL to read the fields of AssumeRoleConfig.
|
||||||
|
// The decoded values from this spec will then be applied to a FlatAssumeRoleConfig.
|
||||||
|
func (*FlatAssumeRoleConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
|
s := map[string]hcldec.Spec{
|
||||||
|
"role_arn": &hcldec.AttrSpec{Name: "role_arn", Type: cty.String, Required: false},
|
||||||
|
"duration_seconds": &hcldec.AttrSpec{Name: "duration_seconds", Type: cty.Number, Required: false},
|
||||||
|
"external_id": &hcldec.AttrSpec{Name: "external_id", Type: cty.String, Required: false},
|
||||||
|
"policy": &hcldec.AttrSpec{Name: "policy", Type: cty.String, Required: false},
|
||||||
|
"policy_arns": &hcldec.AttrSpec{Name: "policy_arns", Type: cty.List(cty.String), Required: false},
|
||||||
|
"session_name": &hcldec.AttrSpec{Name: "session_name", Type: cty.String, Required: false},
|
||||||
|
"tags": &hcldec.AttrSpec{Name: "tags", Type: cty.Map(cty.String), Required: false},
|
||||||
|
"transitive_tag_keys": &hcldec.AttrSpec{Name: "transitive_tag_keys", Type: cty.List(cty.String), Required: false},
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
// FlatVaultAWSEngineOptions is an auto-generated flat version of VaultAWSEngineOptions.
|
// FlatVaultAWSEngineOptions is an auto-generated flat version of VaultAWSEngineOptions.
|
||||||
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
||||||
type FlatVaultAWSEngineOptions struct {
|
type FlatVaultAWSEngineOptions struct {
|
||||||
|
|
|
@ -473,6 +473,13 @@ type RunConfig struct {
|
||||||
// terminating the tunnel it will automatically terminate itself after 20 minutes of inactivity.
|
// terminating the tunnel it will automatically terminate itself after 20 minutes of inactivity.
|
||||||
SSHInterface string `mapstructure:"ssh_interface"`
|
SSHInterface string `mapstructure:"ssh_interface"`
|
||||||
|
|
||||||
|
// 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"`
|
||||||
|
|
||||||
// Which port to connect the local end of the session tunnel to. If
|
// 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.
|
// left blank, Packer will choose a port for you from available ports.
|
||||||
// This option is only used when `ssh_interface` is set `session_manager`.
|
// This option is only used when `ssh_interface` is set `session_manager`.
|
||||||
|
@ -535,6 +542,10 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
|
||||||
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.`)
|
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.`)
|
||||||
errs = append(errs, msg)
|
errs = append(errs, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.PauseBeforeSSM == 0 {
|
||||||
|
c.PauseBeforeSSM = 10 * time.Second
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Comm.SSHKeyPairName != "" {
|
if c.Comm.SSHKeyPairName != "" {
|
||||||
|
|
|
@ -46,7 +46,7 @@ func NewSSMDriver(config SSMDriverConfig) *SSMDriver {
|
||||||
// not wish to manage the session manually calling StopSession on a instance of this driver will terminate the active session
|
// not wish to manage the session manually calling StopSession on a instance of this driver will terminate the active session
|
||||||
// created from calling StartSession.
|
// created from calling StartSession.
|
||||||
func (d *SSMDriver) StartSession(ctx context.Context, input ssm.StartSessionInput) (*ssm.StartSessionOutput, error) {
|
func (d *SSMDriver) StartSession(ctx context.Context, input ssm.StartSessionInput) (*ssm.StartSessionOutput, error) {
|
||||||
log.Printf("Starting PortForwarding session to instance %q with following params %v", aws.StringValue(input.Target), input.Parameters)
|
log.Printf("Starting PortForwarding session to instance %q", aws.StringValue(input.Target))
|
||||||
|
|
||||||
var output *ssm.StartSessionOutput
|
var output *ssm.StartSessionOutput
|
||||||
err := retry.Config{
|
err := retry.Config{
|
||||||
|
@ -110,15 +110,30 @@ func (d *SSMDriver) openTunnelForSession(ctx context.Context) error {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return
|
return
|
||||||
case output := <-stderrCh:
|
case output, ok := <-stderrCh:
|
||||||
|
if !ok {
|
||||||
|
stderrCh = nil
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
if output != "" {
|
if output != "" {
|
||||||
log.Printf("[ERROR] %s: %s", prefix, output)
|
log.Printf("[ERROR] %s: %s", prefix, output)
|
||||||
}
|
}
|
||||||
case output := <-stdoutCh:
|
case output, ok := <-stdoutCh:
|
||||||
|
if !ok {
|
||||||
|
stdoutCh = nil
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
if output != "" {
|
if output != "" {
|
||||||
log.Printf("[DEBUG] %s: %s", prefix, output)
|
log.Printf("[DEBUG] %s: %s", prefix, output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if stdoutCh == nil && stderrCh == nil {
|
||||||
|
log.Printf("[DEBUG] %s: %s", prefix, "active session has been terminated; stopping all log polling processes.")
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}(ctx, sessionManagerPluginName)
|
}(ctx, sessionManagerPluginName)
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
"github.com/aws/aws-sdk-go/aws/session"
|
"github.com/aws/aws-sdk-go/aws/session"
|
||||||
|
@ -21,6 +22,7 @@ type StepCreateSSMTunnel struct {
|
||||||
RemotePortNumber int
|
RemotePortNumber int
|
||||||
SSMAgentEnabled bool
|
SSMAgentEnabled bool
|
||||||
instanceId string
|
instanceId string
|
||||||
|
PauseBeforeSSM time.Duration
|
||||||
driver *SSMDriver
|
driver *SSMDriver
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +34,17 @@ func (s *StepCreateSSMTunnel) Run(ctx context.Context, state multistep.StateBag)
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait for the remote port to become available
|
||||||
|
if s.PauseBeforeSSM > 0 {
|
||||||
|
ui.Say(fmt.Sprintf("Waiting %s for establishing the SSM session...", s.PauseBeforeSSM))
|
||||||
|
select {
|
||||||
|
case <-time.After(s.PauseBeforeSSM):
|
||||||
|
break
|
||||||
|
case <-ctx.Done():
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Configure local port number
|
// Configure local port number
|
||||||
if err := s.ConfigureLocalHostPort(ctx); err != nil {
|
if err := s.ConfigureLocalHostPort(ctx); err != nil {
|
||||||
err := fmt.Errorf("error finding an available port to initiate a session tunnel: %s", err)
|
err := fmt.Errorf("error finding an available port to initiate a session tunnel: %s", err)
|
||||||
|
|
|
@ -269,6 +269,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||||
&awscommon.StepCreateSSMTunnel{
|
&awscommon.StepCreateSSMTunnel{
|
||||||
AWSSession: session,
|
AWSSession: session,
|
||||||
Region: *ec2conn.Config.Region,
|
Region: *ec2conn.Config.Region,
|
||||||
|
PauseBeforeSSM: b.config.PauseBeforeSSM,
|
||||||
LocalPortNumber: b.config.SessionManagerPort,
|
LocalPortNumber: b.config.SessionManagerPort,
|
||||||
RemotePortNumber: b.config.Comm.Port(),
|
RemotePortNumber: b.config.Comm.Port(),
|
||||||
SSMAgentEnabled: b.config.SSMAgentEnabled(),
|
SSMAgentEnabled: b.config.SSMAgentEnabled(),
|
||||||
|
|
|
@ -19,7 +19,9 @@ type FlatConfig struct {
|
||||||
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
|
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
|
||||||
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
|
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
|
||||||
AccessKey *string `mapstructure:"access_key" required:"true" cty:"access_key" hcl:"access_key"`
|
AccessKey *string `mapstructure:"access_key" required:"true" cty:"access_key" hcl:"access_key"`
|
||||||
|
AssumeRole *common.FlatAssumeRoleConfig `mapstructure:"assume_role" required:"false" cty:"assume_role" hcl:"assume_role"`
|
||||||
CustomEndpointEc2 *string `mapstructure:"custom_endpoint_ec2" required:"false" cty:"custom_endpoint_ec2" hcl:"custom_endpoint_ec2"`
|
CustomEndpointEc2 *string `mapstructure:"custom_endpoint_ec2" required:"false" cty:"custom_endpoint_ec2" hcl:"custom_endpoint_ec2"`
|
||||||
|
CredsFilename *string `mapstructure:"shared_credentials_file" required:"false" cty:"shared_credentials_file" hcl:"shared_credentials_file"`
|
||||||
DecodeAuthZMessages *bool `mapstructure:"decode_authorization_messages" required:"false" cty:"decode_authorization_messages" hcl:"decode_authorization_messages"`
|
DecodeAuthZMessages *bool `mapstructure:"decode_authorization_messages" required:"false" cty:"decode_authorization_messages" hcl:"decode_authorization_messages"`
|
||||||
InsecureSkipTLSVerify *bool `mapstructure:"insecure_skip_tls_verify" required:"false" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"`
|
InsecureSkipTLSVerify *bool `mapstructure:"insecure_skip_tls_verify" required:"false" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"`
|
||||||
MaxRetries *int `mapstructure:"max_retries" required:"false" cty:"max_retries" hcl:"max_retries"`
|
MaxRetries *int `mapstructure:"max_retries" required:"false" cty:"max_retries" hcl:"max_retries"`
|
||||||
|
@ -29,6 +31,7 @@ type FlatConfig struct {
|
||||||
SecretKey *string `mapstructure:"secret_key" required:"true" cty:"secret_key" hcl:"secret_key"`
|
SecretKey *string `mapstructure:"secret_key" required:"true" cty:"secret_key" hcl:"secret_key"`
|
||||||
SkipValidation *bool `mapstructure:"skip_region_validation" required:"false" cty:"skip_region_validation" hcl:"skip_region_validation"`
|
SkipValidation *bool `mapstructure:"skip_region_validation" required:"false" cty:"skip_region_validation" hcl:"skip_region_validation"`
|
||||||
SkipMetadataApiCheck *bool `mapstructure:"skip_metadata_api_check" cty:"skip_metadata_api_check" hcl:"skip_metadata_api_check"`
|
SkipMetadataApiCheck *bool `mapstructure:"skip_metadata_api_check" cty:"skip_metadata_api_check" hcl:"skip_metadata_api_check"`
|
||||||
|
SkipCredsValidation *bool `mapstructure:"skip_credential_validation" cty:"skip_credential_validation" hcl:"skip_credential_validation"`
|
||||||
Token *string `mapstructure:"token" required:"false" cty:"token" hcl:"token"`
|
Token *string `mapstructure:"token" required:"false" cty:"token" hcl:"token"`
|
||||||
VaultAWSEngine *common.FlatVaultAWSEngineOptions `mapstructure:"vault_aws_engine" required:"false" cty:"vault_aws_engine" hcl:"vault_aws_engine"`
|
VaultAWSEngine *common.FlatVaultAWSEngineOptions `mapstructure:"vault_aws_engine" required:"false" cty:"vault_aws_engine" hcl:"vault_aws_engine"`
|
||||||
PollingConfig *common.FlatAWSPollingConfig `mapstructure:"aws_polling" required:"false" cty:"aws_polling" hcl:"aws_polling"`
|
PollingConfig *common.FlatAWSPollingConfig `mapstructure:"aws_polling" required:"false" cty:"aws_polling" hcl:"aws_polling"`
|
||||||
|
@ -132,6 +135,7 @@ type FlatConfig struct {
|
||||||
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"`
|
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"`
|
||||||
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"`
|
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"`
|
||||||
SSHInterface *string `mapstructure:"ssh_interface" cty:"ssh_interface" hcl:"ssh_interface"`
|
SSHInterface *string `mapstructure:"ssh_interface" cty:"ssh_interface" hcl:"ssh_interface"`
|
||||||
|
PauseBeforeSSM *string `mapstructure:"pause_before_ssm" cty:"pause_before_ssm" hcl:"pause_before_ssm"`
|
||||||
SessionManagerPort *int `mapstructure:"session_manager_port" cty:"session_manager_port" hcl:"session_manager_port"`
|
SessionManagerPort *int `mapstructure:"session_manager_port" cty:"session_manager_port" hcl:"session_manager_port"`
|
||||||
AMIMappings []common.FlatBlockDevice `mapstructure:"ami_block_device_mappings" required:"false" cty:"ami_block_device_mappings" hcl:"ami_block_device_mappings"`
|
AMIMappings []common.FlatBlockDevice `mapstructure:"ami_block_device_mappings" required:"false" cty:"ami_block_device_mappings" hcl:"ami_block_device_mappings"`
|
||||||
LaunchMappings []common.FlatBlockDevice `mapstructure:"launch_block_device_mappings" required:"false" cty:"launch_block_device_mappings" hcl:"launch_block_device_mappings"`
|
LaunchMappings []common.FlatBlockDevice `mapstructure:"launch_block_device_mappings" required:"false" cty:"launch_block_device_mappings" hcl:"launch_block_device_mappings"`
|
||||||
|
@ -160,7 +164,9 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
|
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
|
||||||
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
|
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
|
||||||
"access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false},
|
"access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false},
|
||||||
|
"assume_role": &hcldec.BlockSpec{TypeName: "assume_role", Nested: hcldec.ObjectSpec((*common.FlatAssumeRoleConfig)(nil).HCL2Spec())},
|
||||||
"custom_endpoint_ec2": &hcldec.AttrSpec{Name: "custom_endpoint_ec2", Type: cty.String, Required: false},
|
"custom_endpoint_ec2": &hcldec.AttrSpec{Name: "custom_endpoint_ec2", Type: cty.String, Required: false},
|
||||||
|
"shared_credentials_file": &hcldec.AttrSpec{Name: "shared_credentials_file", Type: cty.String, Required: false},
|
||||||
"decode_authorization_messages": &hcldec.AttrSpec{Name: "decode_authorization_messages", Type: cty.Bool, Required: false},
|
"decode_authorization_messages": &hcldec.AttrSpec{Name: "decode_authorization_messages", Type: cty.Bool, Required: false},
|
||||||
"insecure_skip_tls_verify": &hcldec.AttrSpec{Name: "insecure_skip_tls_verify", Type: cty.Bool, Required: false},
|
"insecure_skip_tls_verify": &hcldec.AttrSpec{Name: "insecure_skip_tls_verify", Type: cty.Bool, Required: false},
|
||||||
"max_retries": &hcldec.AttrSpec{Name: "max_retries", Type: cty.Number, Required: false},
|
"max_retries": &hcldec.AttrSpec{Name: "max_retries", Type: cty.Number, Required: false},
|
||||||
|
@ -170,6 +176,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
"secret_key": &hcldec.AttrSpec{Name: "secret_key", Type: cty.String, Required: false},
|
"secret_key": &hcldec.AttrSpec{Name: "secret_key", Type: cty.String, Required: false},
|
||||||
"skip_region_validation": &hcldec.AttrSpec{Name: "skip_region_validation", Type: cty.Bool, Required: false},
|
"skip_region_validation": &hcldec.AttrSpec{Name: "skip_region_validation", Type: cty.Bool, Required: false},
|
||||||
"skip_metadata_api_check": &hcldec.AttrSpec{Name: "skip_metadata_api_check", Type: cty.Bool, Required: false},
|
"skip_metadata_api_check": &hcldec.AttrSpec{Name: "skip_metadata_api_check", Type: cty.Bool, Required: false},
|
||||||
|
"skip_credential_validation": &hcldec.AttrSpec{Name: "skip_credential_validation", Type: cty.Bool, Required: false},
|
||||||
"token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false},
|
"token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false},
|
||||||
"vault_aws_engine": &hcldec.BlockSpec{TypeName: "vault_aws_engine", Nested: hcldec.ObjectSpec((*common.FlatVaultAWSEngineOptions)(nil).HCL2Spec())},
|
"vault_aws_engine": &hcldec.BlockSpec{TypeName: "vault_aws_engine", Nested: hcldec.ObjectSpec((*common.FlatVaultAWSEngineOptions)(nil).HCL2Spec())},
|
||||||
"aws_polling": &hcldec.BlockSpec{TypeName: "aws_polling", Nested: hcldec.ObjectSpec((*common.FlatAWSPollingConfig)(nil).HCL2Spec())},
|
"aws_polling": &hcldec.BlockSpec{TypeName: "aws_polling", Nested: hcldec.ObjectSpec((*common.FlatAWSPollingConfig)(nil).HCL2Spec())},
|
||||||
|
@ -273,6 +280,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
"winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false},
|
"winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false},
|
||||||
"winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false},
|
"winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false},
|
||||||
"ssh_interface": &hcldec.AttrSpec{Name: "ssh_interface", Type: cty.String, Required: false},
|
"ssh_interface": &hcldec.AttrSpec{Name: "ssh_interface", Type: cty.String, Required: false},
|
||||||
|
"pause_before_ssm": &hcldec.AttrSpec{Name: "pause_before_ssm", Type: cty.String, Required: false},
|
||||||
"session_manager_port": &hcldec.AttrSpec{Name: "session_manager_port", Type: cty.Number, Required: false},
|
"session_manager_port": &hcldec.AttrSpec{Name: "session_manager_port", Type: cty.Number, Required: false},
|
||||||
"ami_block_device_mappings": &hcldec.BlockListSpec{TypeName: "ami_block_device_mappings", Nested: hcldec.ObjectSpec((*common.FlatBlockDevice)(nil).HCL2Spec())},
|
"ami_block_device_mappings": &hcldec.BlockListSpec{TypeName: "ami_block_device_mappings", Nested: hcldec.ObjectSpec((*common.FlatBlockDevice)(nil).HCL2Spec())},
|
||||||
"launch_block_device_mappings": &hcldec.BlockListSpec{TypeName: "launch_block_device_mappings", Nested: hcldec.ObjectSpec((*common.FlatBlockDevice)(nil).HCL2Spec())},
|
"launch_block_device_mappings": &hcldec.BlockListSpec{TypeName: "launch_block_device_mappings", Nested: hcldec.ObjectSpec((*common.FlatBlockDevice)(nil).HCL2Spec())},
|
||||||
|
|
|
@ -293,6 +293,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||||
&awscommon.StepCreateSSMTunnel{
|
&awscommon.StepCreateSSMTunnel{
|
||||||
AWSSession: session,
|
AWSSession: session,
|
||||||
Region: *ec2conn.Config.Region,
|
Region: *ec2conn.Config.Region,
|
||||||
|
PauseBeforeSSM: b.config.PauseBeforeSSM,
|
||||||
LocalPortNumber: b.config.SessionManagerPort,
|
LocalPortNumber: b.config.SessionManagerPort,
|
||||||
RemotePortNumber: b.config.Comm.Port(),
|
RemotePortNumber: b.config.Comm.Port(),
|
||||||
SSMAgentEnabled: b.config.SSMAgentEnabled(),
|
SSMAgentEnabled: b.config.SSMAgentEnabled(),
|
||||||
|
|
|
@ -62,7 +62,9 @@ type FlatConfig struct {
|
||||||
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
|
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
|
||||||
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
|
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
|
||||||
AccessKey *string `mapstructure:"access_key" required:"true" cty:"access_key" hcl:"access_key"`
|
AccessKey *string `mapstructure:"access_key" required:"true" cty:"access_key" hcl:"access_key"`
|
||||||
|
AssumeRole *common.FlatAssumeRoleConfig `mapstructure:"assume_role" required:"false" cty:"assume_role" hcl:"assume_role"`
|
||||||
CustomEndpointEc2 *string `mapstructure:"custom_endpoint_ec2" required:"false" cty:"custom_endpoint_ec2" hcl:"custom_endpoint_ec2"`
|
CustomEndpointEc2 *string `mapstructure:"custom_endpoint_ec2" required:"false" cty:"custom_endpoint_ec2" hcl:"custom_endpoint_ec2"`
|
||||||
|
CredsFilename *string `mapstructure:"shared_credentials_file" required:"false" cty:"shared_credentials_file" hcl:"shared_credentials_file"`
|
||||||
DecodeAuthZMessages *bool `mapstructure:"decode_authorization_messages" required:"false" cty:"decode_authorization_messages" hcl:"decode_authorization_messages"`
|
DecodeAuthZMessages *bool `mapstructure:"decode_authorization_messages" required:"false" cty:"decode_authorization_messages" hcl:"decode_authorization_messages"`
|
||||||
InsecureSkipTLSVerify *bool `mapstructure:"insecure_skip_tls_verify" required:"false" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"`
|
InsecureSkipTLSVerify *bool `mapstructure:"insecure_skip_tls_verify" required:"false" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"`
|
||||||
MaxRetries *int `mapstructure:"max_retries" required:"false" cty:"max_retries" hcl:"max_retries"`
|
MaxRetries *int `mapstructure:"max_retries" required:"false" cty:"max_retries" hcl:"max_retries"`
|
||||||
|
@ -72,6 +74,7 @@ type FlatConfig struct {
|
||||||
SecretKey *string `mapstructure:"secret_key" required:"true" cty:"secret_key" hcl:"secret_key"`
|
SecretKey *string `mapstructure:"secret_key" required:"true" cty:"secret_key" hcl:"secret_key"`
|
||||||
SkipValidation *bool `mapstructure:"skip_region_validation" required:"false" cty:"skip_region_validation" hcl:"skip_region_validation"`
|
SkipValidation *bool `mapstructure:"skip_region_validation" required:"false" cty:"skip_region_validation" hcl:"skip_region_validation"`
|
||||||
SkipMetadataApiCheck *bool `mapstructure:"skip_metadata_api_check" cty:"skip_metadata_api_check" hcl:"skip_metadata_api_check"`
|
SkipMetadataApiCheck *bool `mapstructure:"skip_metadata_api_check" cty:"skip_metadata_api_check" hcl:"skip_metadata_api_check"`
|
||||||
|
SkipCredsValidation *bool `mapstructure:"skip_credential_validation" cty:"skip_credential_validation" hcl:"skip_credential_validation"`
|
||||||
Token *string `mapstructure:"token" required:"false" cty:"token" hcl:"token"`
|
Token *string `mapstructure:"token" required:"false" cty:"token" hcl:"token"`
|
||||||
VaultAWSEngine *common.FlatVaultAWSEngineOptions `mapstructure:"vault_aws_engine" required:"false" cty:"vault_aws_engine" hcl:"vault_aws_engine"`
|
VaultAWSEngine *common.FlatVaultAWSEngineOptions `mapstructure:"vault_aws_engine" required:"false" cty:"vault_aws_engine" hcl:"vault_aws_engine"`
|
||||||
PollingConfig *common.FlatAWSPollingConfig `mapstructure:"aws_polling" required:"false" cty:"aws_polling" hcl:"aws_polling"`
|
PollingConfig *common.FlatAWSPollingConfig `mapstructure:"aws_polling" required:"false" cty:"aws_polling" hcl:"aws_polling"`
|
||||||
|
@ -154,6 +157,7 @@ type FlatConfig struct {
|
||||||
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"`
|
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"`
|
||||||
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"`
|
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"`
|
||||||
SSHInterface *string `mapstructure:"ssh_interface" cty:"ssh_interface" hcl:"ssh_interface"`
|
SSHInterface *string `mapstructure:"ssh_interface" cty:"ssh_interface" hcl:"ssh_interface"`
|
||||||
|
PauseBeforeSSM *string `mapstructure:"pause_before_ssm" cty:"pause_before_ssm" hcl:"pause_before_ssm"`
|
||||||
SessionManagerPort *int `mapstructure:"session_manager_port" cty:"session_manager_port" hcl:"session_manager_port"`
|
SessionManagerPort *int `mapstructure:"session_manager_port" cty:"session_manager_port" hcl:"session_manager_port"`
|
||||||
AMIName *string `mapstructure:"ami_name" required:"true" cty:"ami_name" hcl:"ami_name"`
|
AMIName *string `mapstructure:"ami_name" required:"true" cty:"ami_name" hcl:"ami_name"`
|
||||||
AMIDescription *string `mapstructure:"ami_description" required:"false" cty:"ami_description" hcl:"ami_description"`
|
AMIDescription *string `mapstructure:"ami_description" required:"false" cty:"ami_description" hcl:"ami_description"`
|
||||||
|
@ -204,7 +208,9 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
|
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
|
||||||
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
|
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
|
||||||
"access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false},
|
"access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false},
|
||||||
|
"assume_role": &hcldec.BlockSpec{TypeName: "assume_role", Nested: hcldec.ObjectSpec((*common.FlatAssumeRoleConfig)(nil).HCL2Spec())},
|
||||||
"custom_endpoint_ec2": &hcldec.AttrSpec{Name: "custom_endpoint_ec2", Type: cty.String, Required: false},
|
"custom_endpoint_ec2": &hcldec.AttrSpec{Name: "custom_endpoint_ec2", Type: cty.String, Required: false},
|
||||||
|
"shared_credentials_file": &hcldec.AttrSpec{Name: "shared_credentials_file", Type: cty.String, Required: false},
|
||||||
"decode_authorization_messages": &hcldec.AttrSpec{Name: "decode_authorization_messages", Type: cty.Bool, Required: false},
|
"decode_authorization_messages": &hcldec.AttrSpec{Name: "decode_authorization_messages", Type: cty.Bool, Required: false},
|
||||||
"insecure_skip_tls_verify": &hcldec.AttrSpec{Name: "insecure_skip_tls_verify", Type: cty.Bool, Required: false},
|
"insecure_skip_tls_verify": &hcldec.AttrSpec{Name: "insecure_skip_tls_verify", Type: cty.Bool, Required: false},
|
||||||
"max_retries": &hcldec.AttrSpec{Name: "max_retries", Type: cty.Number, Required: false},
|
"max_retries": &hcldec.AttrSpec{Name: "max_retries", Type: cty.Number, Required: false},
|
||||||
|
@ -214,6 +220,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
"secret_key": &hcldec.AttrSpec{Name: "secret_key", Type: cty.String, Required: false},
|
"secret_key": &hcldec.AttrSpec{Name: "secret_key", Type: cty.String, Required: false},
|
||||||
"skip_region_validation": &hcldec.AttrSpec{Name: "skip_region_validation", Type: cty.Bool, Required: false},
|
"skip_region_validation": &hcldec.AttrSpec{Name: "skip_region_validation", Type: cty.Bool, Required: false},
|
||||||
"skip_metadata_api_check": &hcldec.AttrSpec{Name: "skip_metadata_api_check", Type: cty.Bool, Required: false},
|
"skip_metadata_api_check": &hcldec.AttrSpec{Name: "skip_metadata_api_check", Type: cty.Bool, Required: false},
|
||||||
|
"skip_credential_validation": &hcldec.AttrSpec{Name: "skip_credential_validation", Type: cty.Bool, Required: false},
|
||||||
"token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false},
|
"token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false},
|
||||||
"vault_aws_engine": &hcldec.BlockSpec{TypeName: "vault_aws_engine", Nested: hcldec.ObjectSpec((*common.FlatVaultAWSEngineOptions)(nil).HCL2Spec())},
|
"vault_aws_engine": &hcldec.BlockSpec{TypeName: "vault_aws_engine", Nested: hcldec.ObjectSpec((*common.FlatVaultAWSEngineOptions)(nil).HCL2Spec())},
|
||||||
"aws_polling": &hcldec.BlockSpec{TypeName: "aws_polling", Nested: hcldec.ObjectSpec((*common.FlatAWSPollingConfig)(nil).HCL2Spec())},
|
"aws_polling": &hcldec.BlockSpec{TypeName: "aws_polling", Nested: hcldec.ObjectSpec((*common.FlatAWSPollingConfig)(nil).HCL2Spec())},
|
||||||
|
@ -296,6 +303,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
"winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false},
|
"winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false},
|
||||||
"winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false},
|
"winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false},
|
||||||
"ssh_interface": &hcldec.AttrSpec{Name: "ssh_interface", Type: cty.String, Required: false},
|
"ssh_interface": &hcldec.AttrSpec{Name: "ssh_interface", Type: cty.String, Required: false},
|
||||||
|
"pause_before_ssm": &hcldec.AttrSpec{Name: "pause_before_ssm", Type: cty.String, Required: false},
|
||||||
"session_manager_port": &hcldec.AttrSpec{Name: "session_manager_port", Type: cty.Number, Required: false},
|
"session_manager_port": &hcldec.AttrSpec{Name: "session_manager_port", Type: cty.Number, Required: false},
|
||||||
"ami_name": &hcldec.AttrSpec{Name: "ami_name", Type: cty.String, Required: false},
|
"ami_name": &hcldec.AttrSpec{Name: "ami_name", Type: cty.String, Required: false},
|
||||||
"ami_description": &hcldec.AttrSpec{Name: "ami_description", Type: cty.String, Required: false},
|
"ami_description": &hcldec.AttrSpec{Name: "ami_description", Type: cty.String, Required: false},
|
||||||
|
|
|
@ -263,6 +263,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||||
&awscommon.StepCreateSSMTunnel{
|
&awscommon.StepCreateSSMTunnel{
|
||||||
AWSSession: session,
|
AWSSession: session,
|
||||||
Region: *ec2conn.Config.Region,
|
Region: *ec2conn.Config.Region,
|
||||||
|
PauseBeforeSSM: b.config.PauseBeforeSSM,
|
||||||
LocalPortNumber: b.config.SessionManagerPort,
|
LocalPortNumber: b.config.SessionManagerPort,
|
||||||
RemotePortNumber: b.config.Comm.Port(),
|
RemotePortNumber: b.config.Comm.Port(),
|
||||||
SSMAgentEnabled: b.config.SSMAgentEnabled(),
|
SSMAgentEnabled: b.config.SSMAgentEnabled(),
|
||||||
|
|
|
@ -64,7 +64,9 @@ type FlatConfig struct {
|
||||||
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
|
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
|
||||||
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
|
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
|
||||||
AccessKey *string `mapstructure:"access_key" required:"true" cty:"access_key" hcl:"access_key"`
|
AccessKey *string `mapstructure:"access_key" required:"true" cty:"access_key" hcl:"access_key"`
|
||||||
|
AssumeRole *common.FlatAssumeRoleConfig `mapstructure:"assume_role" required:"false" cty:"assume_role" hcl:"assume_role"`
|
||||||
CustomEndpointEc2 *string `mapstructure:"custom_endpoint_ec2" required:"false" cty:"custom_endpoint_ec2" hcl:"custom_endpoint_ec2"`
|
CustomEndpointEc2 *string `mapstructure:"custom_endpoint_ec2" required:"false" cty:"custom_endpoint_ec2" hcl:"custom_endpoint_ec2"`
|
||||||
|
CredsFilename *string `mapstructure:"shared_credentials_file" required:"false" cty:"shared_credentials_file" hcl:"shared_credentials_file"`
|
||||||
DecodeAuthZMessages *bool `mapstructure:"decode_authorization_messages" required:"false" cty:"decode_authorization_messages" hcl:"decode_authorization_messages"`
|
DecodeAuthZMessages *bool `mapstructure:"decode_authorization_messages" required:"false" cty:"decode_authorization_messages" hcl:"decode_authorization_messages"`
|
||||||
InsecureSkipTLSVerify *bool `mapstructure:"insecure_skip_tls_verify" required:"false" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"`
|
InsecureSkipTLSVerify *bool `mapstructure:"insecure_skip_tls_verify" required:"false" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"`
|
||||||
MaxRetries *int `mapstructure:"max_retries" required:"false" cty:"max_retries" hcl:"max_retries"`
|
MaxRetries *int `mapstructure:"max_retries" required:"false" cty:"max_retries" hcl:"max_retries"`
|
||||||
|
@ -74,6 +76,7 @@ type FlatConfig struct {
|
||||||
SecretKey *string `mapstructure:"secret_key" required:"true" cty:"secret_key" hcl:"secret_key"`
|
SecretKey *string `mapstructure:"secret_key" required:"true" cty:"secret_key" hcl:"secret_key"`
|
||||||
SkipValidation *bool `mapstructure:"skip_region_validation" required:"false" cty:"skip_region_validation" hcl:"skip_region_validation"`
|
SkipValidation *bool `mapstructure:"skip_region_validation" required:"false" cty:"skip_region_validation" hcl:"skip_region_validation"`
|
||||||
SkipMetadataApiCheck *bool `mapstructure:"skip_metadata_api_check" cty:"skip_metadata_api_check" hcl:"skip_metadata_api_check"`
|
SkipMetadataApiCheck *bool `mapstructure:"skip_metadata_api_check" cty:"skip_metadata_api_check" hcl:"skip_metadata_api_check"`
|
||||||
|
SkipCredsValidation *bool `mapstructure:"skip_credential_validation" cty:"skip_credential_validation" hcl:"skip_credential_validation"`
|
||||||
Token *string `mapstructure:"token" required:"false" cty:"token" hcl:"token"`
|
Token *string `mapstructure:"token" required:"false" cty:"token" hcl:"token"`
|
||||||
VaultAWSEngine *common.FlatVaultAWSEngineOptions `mapstructure:"vault_aws_engine" required:"false" cty:"vault_aws_engine" hcl:"vault_aws_engine"`
|
VaultAWSEngine *common.FlatVaultAWSEngineOptions `mapstructure:"vault_aws_engine" required:"false" cty:"vault_aws_engine" hcl:"vault_aws_engine"`
|
||||||
PollingConfig *common.FlatAWSPollingConfig `mapstructure:"aws_polling" required:"false" cty:"aws_polling" hcl:"aws_polling"`
|
PollingConfig *common.FlatAWSPollingConfig `mapstructure:"aws_polling" required:"false" cty:"aws_polling" hcl:"aws_polling"`
|
||||||
|
@ -156,6 +159,7 @@ type FlatConfig struct {
|
||||||
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"`
|
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"`
|
||||||
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"`
|
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"`
|
||||||
SSHInterface *string `mapstructure:"ssh_interface" cty:"ssh_interface" hcl:"ssh_interface"`
|
SSHInterface *string `mapstructure:"ssh_interface" cty:"ssh_interface" hcl:"ssh_interface"`
|
||||||
|
PauseBeforeSSM *string `mapstructure:"pause_before_ssm" cty:"pause_before_ssm" hcl:"pause_before_ssm"`
|
||||||
SessionManagerPort *int `mapstructure:"session_manager_port" cty:"session_manager_port" hcl:"session_manager_port"`
|
SessionManagerPort *int `mapstructure:"session_manager_port" cty:"session_manager_port" hcl:"session_manager_port"`
|
||||||
AMIENASupport *bool `mapstructure:"ena_support" required:"false" cty:"ena_support" hcl:"ena_support"`
|
AMIENASupport *bool `mapstructure:"ena_support" required:"false" cty:"ena_support" hcl:"ena_support"`
|
||||||
AMISriovNetSupport *bool `mapstructure:"sriov_support" required:"false" cty:"sriov_support" hcl:"sriov_support"`
|
AMISriovNetSupport *bool `mapstructure:"sriov_support" required:"false" cty:"sriov_support" hcl:"sriov_support"`
|
||||||
|
@ -184,7 +188,9 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
|
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
|
||||||
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
|
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
|
||||||
"access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false},
|
"access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false},
|
||||||
|
"assume_role": &hcldec.BlockSpec{TypeName: "assume_role", Nested: hcldec.ObjectSpec((*common.FlatAssumeRoleConfig)(nil).HCL2Spec())},
|
||||||
"custom_endpoint_ec2": &hcldec.AttrSpec{Name: "custom_endpoint_ec2", Type: cty.String, Required: false},
|
"custom_endpoint_ec2": &hcldec.AttrSpec{Name: "custom_endpoint_ec2", Type: cty.String, Required: false},
|
||||||
|
"shared_credentials_file": &hcldec.AttrSpec{Name: "shared_credentials_file", Type: cty.String, Required: false},
|
||||||
"decode_authorization_messages": &hcldec.AttrSpec{Name: "decode_authorization_messages", Type: cty.Bool, Required: false},
|
"decode_authorization_messages": &hcldec.AttrSpec{Name: "decode_authorization_messages", Type: cty.Bool, Required: false},
|
||||||
"insecure_skip_tls_verify": &hcldec.AttrSpec{Name: "insecure_skip_tls_verify", Type: cty.Bool, Required: false},
|
"insecure_skip_tls_verify": &hcldec.AttrSpec{Name: "insecure_skip_tls_verify", Type: cty.Bool, Required: false},
|
||||||
"max_retries": &hcldec.AttrSpec{Name: "max_retries", Type: cty.Number, Required: false},
|
"max_retries": &hcldec.AttrSpec{Name: "max_retries", Type: cty.Number, Required: false},
|
||||||
|
@ -194,6 +200,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
"secret_key": &hcldec.AttrSpec{Name: "secret_key", Type: cty.String, Required: false},
|
"secret_key": &hcldec.AttrSpec{Name: "secret_key", Type: cty.String, Required: false},
|
||||||
"skip_region_validation": &hcldec.AttrSpec{Name: "skip_region_validation", Type: cty.Bool, Required: false},
|
"skip_region_validation": &hcldec.AttrSpec{Name: "skip_region_validation", Type: cty.Bool, Required: false},
|
||||||
"skip_metadata_api_check": &hcldec.AttrSpec{Name: "skip_metadata_api_check", Type: cty.Bool, Required: false},
|
"skip_metadata_api_check": &hcldec.AttrSpec{Name: "skip_metadata_api_check", Type: cty.Bool, Required: false},
|
||||||
|
"skip_credential_validation": &hcldec.AttrSpec{Name: "skip_credential_validation", Type: cty.Bool, Required: false},
|
||||||
"token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false},
|
"token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false},
|
||||||
"vault_aws_engine": &hcldec.BlockSpec{TypeName: "vault_aws_engine", Nested: hcldec.ObjectSpec((*common.FlatVaultAWSEngineOptions)(nil).HCL2Spec())},
|
"vault_aws_engine": &hcldec.BlockSpec{TypeName: "vault_aws_engine", Nested: hcldec.ObjectSpec((*common.FlatVaultAWSEngineOptions)(nil).HCL2Spec())},
|
||||||
"aws_polling": &hcldec.BlockSpec{TypeName: "aws_polling", Nested: hcldec.ObjectSpec((*common.FlatAWSPollingConfig)(nil).HCL2Spec())},
|
"aws_polling": &hcldec.BlockSpec{TypeName: "aws_polling", Nested: hcldec.ObjectSpec((*common.FlatAWSPollingConfig)(nil).HCL2Spec())},
|
||||||
|
@ -276,6 +283,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
"winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false},
|
"winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false},
|
||||||
"winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false},
|
"winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false},
|
||||||
"ssh_interface": &hcldec.AttrSpec{Name: "ssh_interface", Type: cty.String, Required: false},
|
"ssh_interface": &hcldec.AttrSpec{Name: "ssh_interface", Type: cty.String, Required: false},
|
||||||
|
"pause_before_ssm": &hcldec.AttrSpec{Name: "pause_before_ssm", Type: cty.String, Required: false},
|
||||||
"session_manager_port": &hcldec.AttrSpec{Name: "session_manager_port", Type: cty.Number, Required: false},
|
"session_manager_port": &hcldec.AttrSpec{Name: "session_manager_port", Type: cty.Number, Required: false},
|
||||||
"ena_support": &hcldec.AttrSpec{Name: "ena_support", Type: cty.Bool, Required: false},
|
"ena_support": &hcldec.AttrSpec{Name: "ena_support", Type: cty.Bool, Required: false},
|
||||||
"sriov_support": &hcldec.AttrSpec{Name: "sriov_support", Type: cty.Bool, Required: false},
|
"sriov_support": &hcldec.AttrSpec{Name: "sriov_support", Type: cty.Bool, Required: false},
|
||||||
|
|
|
@ -343,6 +343,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||||
&awscommon.StepCreateSSMTunnel{
|
&awscommon.StepCreateSSMTunnel{
|
||||||
AWSSession: session,
|
AWSSession: session,
|
||||||
Region: *ec2conn.Config.Region,
|
Region: *ec2conn.Config.Region,
|
||||||
|
PauseBeforeSSM: b.config.PauseBeforeSSM,
|
||||||
LocalPortNumber: b.config.SessionManagerPort,
|
LocalPortNumber: b.config.SessionManagerPort,
|
||||||
RemotePortNumber: b.config.Comm.Port(),
|
RemotePortNumber: b.config.Comm.Port(),
|
||||||
SSMAgentEnabled: b.config.SSMAgentEnabled(),
|
SSMAgentEnabled: b.config.SSMAgentEnabled(),
|
||||||
|
|
|
@ -19,7 +19,9 @@ type FlatConfig struct {
|
||||||
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
|
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
|
||||||
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
|
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
|
||||||
AccessKey *string `mapstructure:"access_key" required:"true" cty:"access_key" hcl:"access_key"`
|
AccessKey *string `mapstructure:"access_key" required:"true" cty:"access_key" hcl:"access_key"`
|
||||||
|
AssumeRole *common.FlatAssumeRoleConfig `mapstructure:"assume_role" required:"false" cty:"assume_role" hcl:"assume_role"`
|
||||||
CustomEndpointEc2 *string `mapstructure:"custom_endpoint_ec2" required:"false" cty:"custom_endpoint_ec2" hcl:"custom_endpoint_ec2"`
|
CustomEndpointEc2 *string `mapstructure:"custom_endpoint_ec2" required:"false" cty:"custom_endpoint_ec2" hcl:"custom_endpoint_ec2"`
|
||||||
|
CredsFilename *string `mapstructure:"shared_credentials_file" required:"false" cty:"shared_credentials_file" hcl:"shared_credentials_file"`
|
||||||
DecodeAuthZMessages *bool `mapstructure:"decode_authorization_messages" required:"false" cty:"decode_authorization_messages" hcl:"decode_authorization_messages"`
|
DecodeAuthZMessages *bool `mapstructure:"decode_authorization_messages" required:"false" cty:"decode_authorization_messages" hcl:"decode_authorization_messages"`
|
||||||
InsecureSkipTLSVerify *bool `mapstructure:"insecure_skip_tls_verify" required:"false" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"`
|
InsecureSkipTLSVerify *bool `mapstructure:"insecure_skip_tls_verify" required:"false" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"`
|
||||||
MaxRetries *int `mapstructure:"max_retries" required:"false" cty:"max_retries" hcl:"max_retries"`
|
MaxRetries *int `mapstructure:"max_retries" required:"false" cty:"max_retries" hcl:"max_retries"`
|
||||||
|
@ -29,6 +31,7 @@ type FlatConfig struct {
|
||||||
SecretKey *string `mapstructure:"secret_key" required:"true" cty:"secret_key" hcl:"secret_key"`
|
SecretKey *string `mapstructure:"secret_key" required:"true" cty:"secret_key" hcl:"secret_key"`
|
||||||
SkipValidation *bool `mapstructure:"skip_region_validation" required:"false" cty:"skip_region_validation" hcl:"skip_region_validation"`
|
SkipValidation *bool `mapstructure:"skip_region_validation" required:"false" cty:"skip_region_validation" hcl:"skip_region_validation"`
|
||||||
SkipMetadataApiCheck *bool `mapstructure:"skip_metadata_api_check" cty:"skip_metadata_api_check" hcl:"skip_metadata_api_check"`
|
SkipMetadataApiCheck *bool `mapstructure:"skip_metadata_api_check" cty:"skip_metadata_api_check" hcl:"skip_metadata_api_check"`
|
||||||
|
SkipCredsValidation *bool `mapstructure:"skip_credential_validation" cty:"skip_credential_validation" hcl:"skip_credential_validation"`
|
||||||
Token *string `mapstructure:"token" required:"false" cty:"token" hcl:"token"`
|
Token *string `mapstructure:"token" required:"false" cty:"token" hcl:"token"`
|
||||||
VaultAWSEngine *common.FlatVaultAWSEngineOptions `mapstructure:"vault_aws_engine" required:"false" cty:"vault_aws_engine" hcl:"vault_aws_engine"`
|
VaultAWSEngine *common.FlatVaultAWSEngineOptions `mapstructure:"vault_aws_engine" required:"false" cty:"vault_aws_engine" hcl:"vault_aws_engine"`
|
||||||
PollingConfig *common.FlatAWSPollingConfig `mapstructure:"aws_polling" required:"false" cty:"aws_polling" hcl:"aws_polling"`
|
PollingConfig *common.FlatAWSPollingConfig `mapstructure:"aws_polling" required:"false" cty:"aws_polling" hcl:"aws_polling"`
|
||||||
|
@ -132,6 +135,7 @@ type FlatConfig struct {
|
||||||
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"`
|
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"`
|
||||||
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"`
|
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"`
|
||||||
SSHInterface *string `mapstructure:"ssh_interface" cty:"ssh_interface" hcl:"ssh_interface"`
|
SSHInterface *string `mapstructure:"ssh_interface" cty:"ssh_interface" hcl:"ssh_interface"`
|
||||||
|
PauseBeforeSSM *string `mapstructure:"pause_before_ssm" cty:"pause_before_ssm" hcl:"pause_before_ssm"`
|
||||||
SessionManagerPort *int `mapstructure:"session_manager_port" cty:"session_manager_port" hcl:"session_manager_port"`
|
SessionManagerPort *int `mapstructure:"session_manager_port" cty:"session_manager_port" hcl:"session_manager_port"`
|
||||||
AMIMappings []common.FlatBlockDevice `mapstructure:"ami_block_device_mappings" required:"false" cty:"ami_block_device_mappings" hcl:"ami_block_device_mappings"`
|
AMIMappings []common.FlatBlockDevice `mapstructure:"ami_block_device_mappings" required:"false" cty:"ami_block_device_mappings" hcl:"ami_block_device_mappings"`
|
||||||
LaunchMappings []common.FlatBlockDevice `mapstructure:"launch_block_device_mappings" required:"false" cty:"launch_block_device_mappings" hcl:"launch_block_device_mappings"`
|
LaunchMappings []common.FlatBlockDevice `mapstructure:"launch_block_device_mappings" required:"false" cty:"launch_block_device_mappings" hcl:"launch_block_device_mappings"`
|
||||||
|
@ -166,7 +170,9 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
|
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
|
||||||
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
|
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
|
||||||
"access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false},
|
"access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false},
|
||||||
|
"assume_role": &hcldec.BlockSpec{TypeName: "assume_role", Nested: hcldec.ObjectSpec((*common.FlatAssumeRoleConfig)(nil).HCL2Spec())},
|
||||||
"custom_endpoint_ec2": &hcldec.AttrSpec{Name: "custom_endpoint_ec2", Type: cty.String, Required: false},
|
"custom_endpoint_ec2": &hcldec.AttrSpec{Name: "custom_endpoint_ec2", Type: cty.String, Required: false},
|
||||||
|
"shared_credentials_file": &hcldec.AttrSpec{Name: "shared_credentials_file", Type: cty.String, Required: false},
|
||||||
"decode_authorization_messages": &hcldec.AttrSpec{Name: "decode_authorization_messages", Type: cty.Bool, Required: false},
|
"decode_authorization_messages": &hcldec.AttrSpec{Name: "decode_authorization_messages", Type: cty.Bool, Required: false},
|
||||||
"insecure_skip_tls_verify": &hcldec.AttrSpec{Name: "insecure_skip_tls_verify", Type: cty.Bool, Required: false},
|
"insecure_skip_tls_verify": &hcldec.AttrSpec{Name: "insecure_skip_tls_verify", Type: cty.Bool, Required: false},
|
||||||
"max_retries": &hcldec.AttrSpec{Name: "max_retries", Type: cty.Number, Required: false},
|
"max_retries": &hcldec.AttrSpec{Name: "max_retries", Type: cty.Number, Required: false},
|
||||||
|
@ -176,6 +182,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
"secret_key": &hcldec.AttrSpec{Name: "secret_key", Type: cty.String, Required: false},
|
"secret_key": &hcldec.AttrSpec{Name: "secret_key", Type: cty.String, Required: false},
|
||||||
"skip_region_validation": &hcldec.AttrSpec{Name: "skip_region_validation", Type: cty.Bool, Required: false},
|
"skip_region_validation": &hcldec.AttrSpec{Name: "skip_region_validation", Type: cty.Bool, Required: false},
|
||||||
"skip_metadata_api_check": &hcldec.AttrSpec{Name: "skip_metadata_api_check", Type: cty.Bool, Required: false},
|
"skip_metadata_api_check": &hcldec.AttrSpec{Name: "skip_metadata_api_check", Type: cty.Bool, Required: false},
|
||||||
|
"skip_credential_validation": &hcldec.AttrSpec{Name: "skip_credential_validation", Type: cty.Bool, Required: false},
|
||||||
"token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false},
|
"token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false},
|
||||||
"vault_aws_engine": &hcldec.BlockSpec{TypeName: "vault_aws_engine", Nested: hcldec.ObjectSpec((*common.FlatVaultAWSEngineOptions)(nil).HCL2Spec())},
|
"vault_aws_engine": &hcldec.BlockSpec{TypeName: "vault_aws_engine", Nested: hcldec.ObjectSpec((*common.FlatVaultAWSEngineOptions)(nil).HCL2Spec())},
|
||||||
"aws_polling": &hcldec.BlockSpec{TypeName: "aws_polling", Nested: hcldec.ObjectSpec((*common.FlatAWSPollingConfig)(nil).HCL2Spec())},
|
"aws_polling": &hcldec.BlockSpec{TypeName: "aws_polling", Nested: hcldec.ObjectSpec((*common.FlatAWSPollingConfig)(nil).HCL2Spec())},
|
||||||
|
@ -279,6 +286,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
"winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false},
|
"winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false},
|
||||||
"winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false},
|
"winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false},
|
||||||
"ssh_interface": &hcldec.AttrSpec{Name: "ssh_interface", Type: cty.String, Required: false},
|
"ssh_interface": &hcldec.AttrSpec{Name: "ssh_interface", Type: cty.String, Required: false},
|
||||||
|
"pause_before_ssm": &hcldec.AttrSpec{Name: "pause_before_ssm", Type: cty.String, Required: false},
|
||||||
"session_manager_port": &hcldec.AttrSpec{Name: "session_manager_port", Type: cty.Number, Required: false},
|
"session_manager_port": &hcldec.AttrSpec{Name: "session_manager_port", Type: cty.Number, Required: false},
|
||||||
"ami_block_device_mappings": &hcldec.BlockListSpec{TypeName: "ami_block_device_mappings", Nested: hcldec.ObjectSpec((*common.FlatBlockDevice)(nil).HCL2Spec())},
|
"ami_block_device_mappings": &hcldec.BlockListSpec{TypeName: "ami_block_device_mappings", Nested: hcldec.ObjectSpec((*common.FlatBlockDevice)(nil).HCL2Spec())},
|
||||||
"launch_block_device_mappings": &hcldec.BlockListSpec{TypeName: "launch_block_device_mappings", Nested: hcldec.ObjectSpec((*common.FlatBlockDevice)(nil).HCL2Spec())},
|
"launch_block_device_mappings": &hcldec.BlockListSpec{TypeName: "launch_block_device_mappings", Nested: hcldec.ObjectSpec((*common.FlatBlockDevice)(nil).HCL2Spec())},
|
||||||
|
|
|
@ -390,7 +390,7 @@ func (b *Builder) getBlobAccount(ctx context.Context, client *AzureClient, resou
|
||||||
func (b *Builder) configureStateBag(stateBag multistep.StateBag) {
|
func (b *Builder) configureStateBag(stateBag multistep.StateBag) {
|
||||||
stateBag.Put(constants.AuthorizedKey, b.config.sshAuthorizedKey)
|
stateBag.Put(constants.AuthorizedKey, b.config.sshAuthorizedKey)
|
||||||
|
|
||||||
stateBag.Put(constants.ArmTags, b.config.AzureTags)
|
stateBag.Put(constants.ArmTags, packerAzureCommon.MapToAzureTags(b.config.AzureTags))
|
||||||
stateBag.Put(constants.ArmComputeName, b.config.tmpComputeName)
|
stateBag.Put(constants.ArmComputeName, b.config.tmpComputeName)
|
||||||
stateBag.Put(constants.ArmDeploymentName, b.config.tmpDeploymentName)
|
stateBag.Put(constants.ArmDeploymentName, b.config.tmpDeploymentName)
|
||||||
|
|
||||||
|
|
|
@ -223,7 +223,11 @@ const testBuilderAccManagedDiskLinux = `
|
||||||
"image_sku": "16.04-LTS",
|
"image_sku": "16.04-LTS",
|
||||||
|
|
||||||
"location": "South Central US",
|
"location": "South Central US",
|
||||||
"vm_size": "Standard_DS2_v2"
|
"vm_size": "Standard_DS2_v2",
|
||||||
|
"azure_tags": {
|
||||||
|
"env": "testing",
|
||||||
|
"builder": "packer"
|
||||||
|
}
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
|
@ -33,3 +33,35 @@ func TestStateBagShouldBePopulatedExpectedValues(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStateBagShouldPoluateExpectedTags(t *testing.T) {
|
||||||
|
var testSubject Builder
|
||||||
|
|
||||||
|
expectedTags := map[string]string{
|
||||||
|
"env": "test",
|
||||||
|
"builder": "packer",
|
||||||
|
}
|
||||||
|
armConfig := getArmBuilderConfiguration()
|
||||||
|
armConfig["azure_tags"] = expectedTags
|
||||||
|
|
||||||
|
_, _, err := testSubject.Prepare(armConfig, getPackerConfiguration())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to prepare: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tags, ok := testSubject.stateBag.Get(constants.ArmTags).(map[string]*string)
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("Expected the builder's state bag to contain tags of type %T, but didn't.", testSubject.config.AzureTags)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(tags) != len(expectedTags) {
|
||||||
|
t.Errorf("expect tags from state to be the same length as tags from config")
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range tags {
|
||||||
|
if expectedTags[k] != *v {
|
||||||
|
t.Errorf("expect tag value of %s to be %s, but got %s", k, expectedTags[k], *v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -288,7 +288,7 @@ type Config struct {
|
||||||
// Group, VM, NIC, VNET, Public IP, KeyVault, etc. The user can define up
|
// Group, VM, NIC, VNET, Public IP, KeyVault, etc. The user can define up
|
||||||
// to 15 tags. Tag names cannot exceed 512 characters, and tag values
|
// to 15 tags. Tag names cannot exceed 512 characters, and tag values
|
||||||
// cannot exceed 256 characters.
|
// cannot exceed 256 characters.
|
||||||
AzureTags map[string]*string `mapstructure:"azure_tags" required:"false"`
|
AzureTags map[string]string `mapstructure:"azure_tags" required:"false"`
|
||||||
// Same as [`azure_tags`](#azure_tags) but defined as a singular repeatable block
|
// Same as [`azure_tags`](#azure_tags) but defined as a singular repeatable block
|
||||||
// containing a `name` and a `value` field. In HCL2 mode the
|
// containing a `name` and a `value` field. In HCL2 mode the
|
||||||
// [`dynamic_block`](/docs/configuration/from-1.5/expressions#dynamic-blocks)
|
// [`dynamic_block`](/docs/configuration/from-1.5/expressions#dynamic-blocks)
|
||||||
|
@ -513,7 +513,7 @@ func (c *Config) toImageParameters() *compute.Image {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Location: to.StringPtr(c.Location),
|
Location: to.StringPtr(c.Location),
|
||||||
Tags: c.AzureTags,
|
Tags: azcommon.MapToAzureTags(c.AzureTags),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -596,10 +596,7 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy singular blocks
|
// copy singular blocks
|
||||||
for _, kv := range c.AzureTag {
|
c.AzureTag.CopyOn(&c.AzureTags)
|
||||||
v := kv.Value
|
|
||||||
c.AzureTags[kv.Name] = &v
|
|
||||||
}
|
|
||||||
|
|
||||||
err = c.ClientConfig.SetDefaultValues()
|
err = c.ClientConfig.SetDefaultValues()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -807,8 +804,8 @@ func assertTagProperties(c *Config, errs *packer.MultiError) {
|
||||||
if len(k) > 512 {
|
if len(k) > 512 {
|
||||||
errs = packer.MultiErrorAppend(errs, fmt.Errorf("the tag name %q exceeds (%d) the 512 character limit", k, len(k)))
|
errs = packer.MultiErrorAppend(errs, fmt.Errorf("the tag name %q exceeds (%d) the 512 character limit", k, len(k)))
|
||||||
}
|
}
|
||||||
if len(*v) > 256 {
|
if len(v) > 256 {
|
||||||
errs = packer.MultiErrorAppend(errs, fmt.Errorf("the tag name %q exceeds (%d) the 256 character limit", *v, len(*v)))
|
errs = packer.MultiErrorAppend(errs, fmt.Errorf("the tag name %q exceeds (%d) the 256 character limit", v, len(v)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1063,13 +1060,13 @@ func assertRequiredParametersSet(c *Config, errs *packer.MultiError) {
|
||||||
errs = packer.MultiErrorAppend(errs, fmt.Errorf("if either plan_name, plan_product, plan_publisher, or plan_promotion_code are defined then plan_name, plan_product, and plan_publisher must be defined"))
|
errs = packer.MultiErrorAppend(errs, fmt.Errorf("if either plan_name, plan_product, plan_publisher, or plan_promotion_code are defined then plan_name, plan_product, and plan_publisher must be defined"))
|
||||||
} else {
|
} else {
|
||||||
if c.AzureTags == nil {
|
if c.AzureTags == nil {
|
||||||
c.AzureTags = make(map[string]*string)
|
c.AzureTags = make(map[string]string)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.AzureTags["PlanInfo"] = &c.PlanInfo.PlanName
|
c.AzureTags["PlanInfo"] = c.PlanInfo.PlanName
|
||||||
c.AzureTags["PlanProduct"] = &c.PlanInfo.PlanProduct
|
c.AzureTags["PlanProduct"] = c.PlanInfo.PlanProduct
|
||||||
c.AzureTags["PlanPublisher"] = &c.PlanInfo.PlanPublisher
|
c.AzureTags["PlanPublisher"] = c.PlanInfo.PlanPublisher
|
||||||
c.AzureTags["PlanPromotionCode"] = &c.PlanInfo.PlanPromotionCode
|
c.AzureTags["PlanPromotionCode"] = c.PlanInfo.PlanPromotionCode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ type FlatConfig struct {
|
||||||
ManagedImageOSDiskSnapshotName *string `mapstructure:"managed_image_os_disk_snapshot_name" required:"false" cty:"managed_image_os_disk_snapshot_name" hcl:"managed_image_os_disk_snapshot_name"`
|
ManagedImageOSDiskSnapshotName *string `mapstructure:"managed_image_os_disk_snapshot_name" required:"false" cty:"managed_image_os_disk_snapshot_name" hcl:"managed_image_os_disk_snapshot_name"`
|
||||||
ManagedImageDataDiskSnapshotPrefix *string `mapstructure:"managed_image_data_disk_snapshot_prefix" required:"false" cty:"managed_image_data_disk_snapshot_prefix" hcl:"managed_image_data_disk_snapshot_prefix"`
|
ManagedImageDataDiskSnapshotPrefix *string `mapstructure:"managed_image_data_disk_snapshot_prefix" required:"false" cty:"managed_image_data_disk_snapshot_prefix" hcl:"managed_image_data_disk_snapshot_prefix"`
|
||||||
ManagedImageZoneResilient *bool `mapstructure:"managed_image_zone_resilient" required:"false" cty:"managed_image_zone_resilient" hcl:"managed_image_zone_resilient"`
|
ManagedImageZoneResilient *bool `mapstructure:"managed_image_zone_resilient" required:"false" cty:"managed_image_zone_resilient" hcl:"managed_image_zone_resilient"`
|
||||||
AzureTags map[string]*string `mapstructure:"azure_tags" required:"false" cty:"azure_tags" hcl:"azure_tags"`
|
AzureTags map[string]string `mapstructure:"azure_tags" required:"false" cty:"azure_tags" hcl:"azure_tags"`
|
||||||
AzureTag []hcl2template.FlatNameValue `mapstructure:"azure_tag" required:"false" cty:"azure_tag" hcl:"azure_tag"`
|
AzureTag []hcl2template.FlatNameValue `mapstructure:"azure_tag" required:"false" cty:"azure_tag" hcl:"azure_tag"`
|
||||||
ResourceGroupName *string `mapstructure:"resource_group_name" cty:"resource_group_name" hcl:"resource_group_name"`
|
ResourceGroupName *string `mapstructure:"resource_group_name" cty:"resource_group_name" hcl:"resource_group_name"`
|
||||||
StorageAccount *string `mapstructure:"storage_account" cty:"storage_account" hcl:"storage_account"`
|
StorageAccount *string `mapstructure:"storage_account" cty:"storage_account" hcl:"storage_account"`
|
||||||
|
|
|
@ -6,7 +6,9 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute"
|
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute"
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/hashicorp/packer/builder/azure/common/constants"
|
"github.com/hashicorp/packer/builder/azure/common/constants"
|
||||||
|
"github.com/hashicorp/packer/hcl2template"
|
||||||
)
|
)
|
||||||
|
|
||||||
// List of configuration parameters that are required by the ARM builder.
|
// List of configuration parameters that are required by the ARM builder.
|
||||||
|
@ -910,32 +912,55 @@ func TestConfigShouldAcceptTags(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var c Config
|
c := Config{
|
||||||
|
AzureTag: hcl2template.NameValues{
|
||||||
|
{Name: "tag03", Value: "value03"},
|
||||||
|
},
|
||||||
|
}
|
||||||
_, err := c.Prepare(config, getPackerConfiguration())
|
_, err := c.Prepare(config, getPackerConfiguration())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(c.AzureTags) != 2 {
|
if diff := cmp.Diff(c.AzureTags, map[string]string{
|
||||||
t.Fatalf("expected to find 2 tags, but got %d", len(c.AzureTags))
|
"tag01": "value01",
|
||||||
|
"tag02": "value02",
|
||||||
|
"tag03": "value03",
|
||||||
|
}); diff != "" {
|
||||||
|
t.Fatalf("unexpected azure tags: %s", diff)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := c.AzureTags["tag01"]; !ok {
|
func TestConfigShouldAcceptTag(t *testing.T) {
|
||||||
t.Error("expected to find key=\"tag01\", but did not")
|
config := map[string]interface{}{
|
||||||
}
|
"capture_name_prefix": "ignore",
|
||||||
if _, ok := c.AzureTags["tag02"]; !ok {
|
"capture_container_name": "ignore",
|
||||||
t.Error("expected to find key=\"tag02\", but did not")
|
"image_offer": "ignore",
|
||||||
|
"image_publisher": "ignore",
|
||||||
|
"image_sku": "ignore",
|
||||||
|
"location": "ignore",
|
||||||
|
"storage_account": "ignore",
|
||||||
|
"resource_group_name": "ignore",
|
||||||
|
"subscription_id": "ignore",
|
||||||
|
"communicator": "none",
|
||||||
|
// Does not matter for this test case, just pick one.
|
||||||
|
"os_type": constants.Target_Linux,
|
||||||
}
|
}
|
||||||
|
|
||||||
value := c.AzureTags["tag01"]
|
c := Config{
|
||||||
if *value != "value01" {
|
AzureTag: hcl2template.NameValues{
|
||||||
t.Errorf("expected AzureTags[\"tag01\"] to have value \"value01\", but got %q", *value)
|
{Name: "tag03", Value: "value03"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, err := c.Prepare(config, getPackerConfiguration())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
value = c.AzureTags["tag02"]
|
if diff := cmp.Diff(c.AzureTags, map[string]string{
|
||||||
if *value != "value02" {
|
"tag03": "value03",
|
||||||
t.Errorf("expected AzureTags[\"tag02\"] to have value \"value02\", but got %q", *value)
|
}); diff != "" {
|
||||||
|
t.Fatalf("unexpected azure tags: %s", diff)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2047,8 +2072,8 @@ func TestConfig_PrepareProvidedWinRMPassword(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getArmBuilderConfiguration() map[string]string {
|
func getArmBuilderConfiguration() map[string]interface{} {
|
||||||
m := make(map[string]string)
|
m := make(map[string]interface{})
|
||||||
for _, v := range requiredConfigValues {
|
for _, v := range requiredConfigValues {
|
||||||
m[v] = "ignored00"
|
m[v] = "ignored00"
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,13 @@ func (s *StepCreateResourceGroup) Run(ctx context.Context, state multistep.State
|
||||||
|
|
||||||
var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string)
|
var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string)
|
||||||
var location = state.Get(constants.ArmLocation).(string)
|
var location = state.Get(constants.ArmLocation).(string)
|
||||||
var tags = state.Get(constants.ArmTags).(map[string]*string)
|
tags, ok := state.Get(constants.ArmTags).(map[string]*string)
|
||||||
|
if !ok {
|
||||||
|
err := fmt.Errorf("failed to extract tags from state bag")
|
||||||
|
state.Put(constants.Error, err)
|
||||||
|
s.error(err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
exists, err := s.exists(ctx, resourceGroupName)
|
exists, err := s.exists(ctx, resourceGroupName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -220,3 +220,32 @@ func createTestExistingStateBagStepCreateResourceGroup() multistep.StateBag {
|
||||||
stateBag.Put(constants.ArmTags, tags)
|
stateBag.Put(constants.ArmTags, tags)
|
||||||
return stateBag
|
return stateBag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStepCreateResourceGroupShouldFailIfTagsFailCast(t *testing.T) {
|
||||||
|
stateBag := new(multistep.BasicStateBag)
|
||||||
|
|
||||||
|
stateBag.Put(constants.ArmLocation, "Unit Test: Location")
|
||||||
|
stateBag.Put(constants.ArmResourceGroupName, "Unit Test: ResourceGroupName")
|
||||||
|
stateBag.Put(constants.ArmIsExistingResourceGroup, true)
|
||||||
|
|
||||||
|
value := "Unit Test: Tags"
|
||||||
|
tags := map[string]string{
|
||||||
|
"tag01": value,
|
||||||
|
}
|
||||||
|
|
||||||
|
stateBag.Put(constants.ArmTags, tags)
|
||||||
|
var testSubject = &StepCreateResourceGroup{
|
||||||
|
create: func(context.Context, string, string, map[string]*string) error { return nil },
|
||||||
|
say: func(message string) {},
|
||||||
|
error: func(e error) {},
|
||||||
|
exists: func(context.Context, string) (bool, error) { return false, nil },
|
||||||
|
}
|
||||||
|
var result = testSubject.Run(context.Background(), stateBag)
|
||||||
|
if result != multistep.ActionHalt {
|
||||||
|
t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := stateBag.GetOk(constants.Error); ok == false {
|
||||||
|
t.Fatalf("Expected the step to set stateBag['%s'], but it was not.", constants.Error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
func MapToAzureTags(in map[string]string) map[string]*string {
|
||||||
|
res := map[string]*string{}
|
||||||
|
for k := range in {
|
||||||
|
v := in[k]
|
||||||
|
res[k] = &v
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
|
@ -32,7 +32,7 @@ type Resource struct {
|
||||||
DependsOn *[]string `json:"dependsOn,omitempty"`
|
DependsOn *[]string `json:"dependsOn,omitempty"`
|
||||||
Plan *Plan `json:"plan,omitempty"`
|
Plan *Plan `json:"plan,omitempty"`
|
||||||
Properties *Properties `json:"properties,omitempty"`
|
Properties *Properties `json:"properties,omitempty"`
|
||||||
Tags *map[string]*string `json:"tags,omitempty"`
|
Tags *map[string]string `json:"tags,omitempty"`
|
||||||
Resources *[]Resource `json:"resources,omitempty"`
|
Resources *[]Resource `json:"resources,omitempty"`
|
||||||
Identity *Identity `json:"identity,omitempty"`
|
Identity *Identity `json:"identity,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -374,7 +374,7 @@ func (s *TemplateBuilder) SetNetworkSecurityGroup(ipAddresses []string, port int
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TemplateBuilder) SetTags(tags *map[string]*string) error {
|
func (s *TemplateBuilder) SetTags(tags *map[string]string) error {
|
||||||
if tags == nil || len(*tags) == 0 {
|
if tags == nil || len(*tags) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,16 +3,20 @@
|
||||||
package openstack
|
package openstack
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/gophercloud/gophercloud"
|
"github.com/gophercloud/gophercloud"
|
||||||
"github.com/gophercloud/gophercloud/openstack"
|
"github.com/gophercloud/gophercloud/openstack"
|
||||||
"github.com/gophercloud/utils/openstack/clientconfig"
|
"github.com/gophercloud/utils/openstack/clientconfig"
|
||||||
"github.com/hashicorp/go-cleanhttp"
|
"github.com/hashicorp/go-cleanhttp"
|
||||||
|
"github.com/hashicorp/packer/packer"
|
||||||
"github.com/hashicorp/packer/template/interpolate"
|
"github.com/hashicorp/packer/template/interpolate"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -236,6 +240,15 @@ func (c *AccessConfig) Prepare(ctx *interpolate.Context) []error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *AccessConfig) enableDebug(ui packer.Ui) {
|
||||||
|
c.osClient.HTTPClient = http.Client{
|
||||||
|
Transport: &DebugRoundTripper{
|
||||||
|
ui: ui,
|
||||||
|
rt: c.osClient.HTTPClient.Transport,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *AccessConfig) computeV2Client() (*gophercloud.ServiceClient, error) {
|
func (c *AccessConfig) computeV2Client() (*gophercloud.ServiceClient, error) {
|
||||||
return openstack.NewComputeV2(c.osClient, gophercloud.EndpointOpts{
|
return openstack.NewComputeV2(c.osClient, gophercloud.EndpointOpts{
|
||||||
Region: c.Region,
|
Region: c.Region,
|
||||||
|
@ -273,3 +286,49 @@ func (c *AccessConfig) getEndpointType() gophercloud.Availability {
|
||||||
}
|
}
|
||||||
return gophercloud.AvailabilityPublic
|
return gophercloud.AvailabilityPublic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DebugRoundTripper struct {
|
||||||
|
ui packer.Ui
|
||||||
|
rt http.RoundTripper
|
||||||
|
numReauthAttempts int
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoundTrip performs a round-trip HTTP request and logs relevant information about it.
|
||||||
|
func (drt *DebugRoundTripper) RoundTrip(request *http.Request) (*http.Response, error) {
|
||||||
|
defer func() {
|
||||||
|
if request.Body != nil {
|
||||||
|
request.Body.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
var response *http.Response
|
||||||
|
var err error
|
||||||
|
|
||||||
|
response, err = drt.rt.RoundTrip(request)
|
||||||
|
if response == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if response.StatusCode == http.StatusUnauthorized {
|
||||||
|
if drt.numReauthAttempts == 3 {
|
||||||
|
return response, fmt.Errorf("Tried to re-authenticate 3 times with no success.")
|
||||||
|
}
|
||||||
|
drt.numReauthAttempts++
|
||||||
|
}
|
||||||
|
|
||||||
|
drt.DebugMessage(fmt.Sprintf("Request %s %s %d", request.Method, request.URL, response.StatusCode))
|
||||||
|
|
||||||
|
if response.StatusCode >= 400 {
|
||||||
|
buf := bytes.NewBuffer([]byte{})
|
||||||
|
body, _ := ioutil.ReadAll(io.TeeReader(response.Body, buf))
|
||||||
|
drt.DebugMessage(fmt.Sprintf("Response Error: %+v\n", string(body)))
|
||||||
|
bufWithClose := ioutil.NopCloser(buf)
|
||||||
|
response.Body = bufWithClose
|
||||||
|
}
|
||||||
|
|
||||||
|
return response, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (drt *DebugRoundTripper) DebugMessage(message string) {
|
||||||
|
drt.ui.Message(fmt.Sprintf("[DEBUG] %s", message))
|
||||||
|
}
|
||||||
|
|
|
@ -71,6 +71,10 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) {
|
func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) {
|
||||||
|
if b.config.PackerDebug {
|
||||||
|
b.config.enableDebug(ui)
|
||||||
|
}
|
||||||
|
|
||||||
computeClient, err := b.config.computeV2Client()
|
computeClient, err := b.config.computeV2Client()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Error initializing compute client: %s", err)
|
return nil, fmt.Errorf("Error initializing compute client: %s", err)
|
||||||
|
@ -100,6 +104,8 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||||
&StepSourceImageInfo{
|
&StepSourceImageInfo{
|
||||||
SourceImage: b.config.RunConfig.SourceImage,
|
SourceImage: b.config.RunConfig.SourceImage,
|
||||||
SourceImageName: b.config.RunConfig.SourceImageName,
|
SourceImageName: b.config.RunConfig.SourceImageName,
|
||||||
|
ExternalSourceImageURL: b.config.RunConfig.ExternalSourceImageURL,
|
||||||
|
ExternalSourceImageFormat: b.config.RunConfig.ExternalSourceImageFormat,
|
||||||
SourceImageOpts: b.config.RunConfig.sourceImageOpts,
|
SourceImageOpts: b.config.RunConfig.sourceImageOpts,
|
||||||
SourceMostRecent: b.config.SourceImageFilters.MostRecent,
|
SourceMostRecent: b.config.SourceImageFilters.MostRecent,
|
||||||
SourceProperties: b.config.SourceImageFilters.Filters.Properties,
|
SourceProperties: b.config.SourceImageFilters.Filters.Properties,
|
||||||
|
|
|
@ -95,6 +95,8 @@ type FlatConfig struct {
|
||||||
SSHIPVersion *string `mapstructure:"ssh_ip_version" required:"false" cty:"ssh_ip_version" hcl:"ssh_ip_version"`
|
SSHIPVersion *string `mapstructure:"ssh_ip_version" required:"false" cty:"ssh_ip_version" hcl:"ssh_ip_version"`
|
||||||
SourceImage *string `mapstructure:"source_image" required:"true" cty:"source_image" hcl:"source_image"`
|
SourceImage *string `mapstructure:"source_image" required:"true" cty:"source_image" hcl:"source_image"`
|
||||||
SourceImageName *string `mapstructure:"source_image_name" required:"true" cty:"source_image_name" hcl:"source_image_name"`
|
SourceImageName *string `mapstructure:"source_image_name" required:"true" cty:"source_image_name" hcl:"source_image_name"`
|
||||||
|
ExternalSourceImageURL *string `mapstructure:"external_source_image_url" required:"true" cty:"external_source_image_url" hcl:"external_source_image_url"`
|
||||||
|
ExternalSourceImageFormat *string `mapstructure:"external_source_image_format" required:"false" cty:"external_source_image_format" hcl:"external_source_image_format"`
|
||||||
SourceImageFilters *FlatImageFilter `mapstructure:"source_image_filter" required:"true" cty:"source_image_filter" hcl:"source_image_filter"`
|
SourceImageFilters *FlatImageFilter `mapstructure:"source_image_filter" required:"true" cty:"source_image_filter" hcl:"source_image_filter"`
|
||||||
Flavor *string `mapstructure:"flavor" required:"true" cty:"flavor" hcl:"flavor"`
|
Flavor *string `mapstructure:"flavor" required:"true" cty:"flavor" hcl:"flavor"`
|
||||||
AvailabilityZone *string `mapstructure:"availability_zone" required:"false" cty:"availability_zone" hcl:"availability_zone"`
|
AvailabilityZone *string `mapstructure:"availability_zone" required:"false" cty:"availability_zone" hcl:"availability_zone"`
|
||||||
|
@ -220,6 +222,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
"ssh_ip_version": &hcldec.AttrSpec{Name: "ssh_ip_version", Type: cty.String, Required: false},
|
"ssh_ip_version": &hcldec.AttrSpec{Name: "ssh_ip_version", Type: cty.String, Required: false},
|
||||||
"source_image": &hcldec.AttrSpec{Name: "source_image", Type: cty.String, Required: false},
|
"source_image": &hcldec.AttrSpec{Name: "source_image", Type: cty.String, Required: false},
|
||||||
"source_image_name": &hcldec.AttrSpec{Name: "source_image_name", Type: cty.String, Required: false},
|
"source_image_name": &hcldec.AttrSpec{Name: "source_image_name", Type: cty.String, Required: false},
|
||||||
|
"external_source_image_url": &hcldec.AttrSpec{Name: "external_source_image_url", Type: cty.String, Required: false},
|
||||||
|
"external_source_image_format": &hcldec.AttrSpec{Name: "external_source_image_format", Type: cty.String, Required: false},
|
||||||
"source_image_filter": &hcldec.BlockSpec{TypeName: "source_image_filter", Nested: hcldec.ObjectSpec((*FlatImageFilter)(nil).HCL2Spec())},
|
"source_image_filter": &hcldec.BlockSpec{TypeName: "source_image_filter", Nested: hcldec.ObjectSpec((*FlatImageFilter)(nil).HCL2Spec())},
|
||||||
"flavor": &hcldec.AttrSpec{Name: "flavor", Type: cty.String, Required: false},
|
"flavor": &hcldec.AttrSpec{Name: "flavor", Type: cty.String, Required: false},
|
||||||
"availability_zone": &hcldec.AttrSpec{Name: "availability_zone", Type: cty.String, Required: false},
|
"availability_zone": &hcldec.AttrSpec{Name: "availability_zone", Type: cty.String, Required: false},
|
||||||
|
|
|
@ -33,6 +33,11 @@ type RunConfig struct {
|
||||||
// The name of the base image to use. This is an alternative way of
|
// The name of the base image to use. This is an alternative way of
|
||||||
// providing source_image and only either of them can be specified.
|
// providing source_image and only either of them can be specified.
|
||||||
SourceImageName string `mapstructure:"source_image_name" required:"true"`
|
SourceImageName string `mapstructure:"source_image_name" required:"true"`
|
||||||
|
// The URL of an external base image to use. This is an alternative way of
|
||||||
|
// providing source_image and only either of them can be specified.
|
||||||
|
ExternalSourceImageURL string `mapstructure:"external_source_image_url" required:"true"`
|
||||||
|
// The format of the external source image to use, e.g. qcow2, raw.
|
||||||
|
ExternalSourceImageFormat string `mapstructure:"external_source_image_format" required:"false"`
|
||||||
// Filters used to populate filter options. Example:
|
// Filters used to populate filter options. Example:
|
||||||
//
|
//
|
||||||
// ```json
|
// ```json
|
||||||
|
@ -247,10 +252,19 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.SourceImage == "" && c.SourceImageName == "" && c.SourceImageFilters.Filters.Empty() {
|
hasOnlySourceImage := len(c.SourceImage) > 0 && len(c.SourceImageName) == 0 && len(c.ExternalSourceImageURL) == 0
|
||||||
errs = append(errs, errors.New("Either a source_image, a source_image_name, or source_image_filter must be specified"))
|
hasOnlySourceImageName := len(c.SourceImageName) > 0 && len(c.SourceImage) == 0 && len(c.ExternalSourceImageURL) == 0
|
||||||
} else if len(c.SourceImage) > 0 && len(c.SourceImageName) > 0 {
|
hasOnlyExternalSourceImageURL := len(c.ExternalSourceImageURL) > 0 && len(c.SourceImage) == 0 && len(c.SourceImageName) == 0
|
||||||
errs = append(errs, errors.New("Only a source_image or a source_image_name can be specified, not both."))
|
|
||||||
|
if c.SourceImage == "" && c.SourceImageName == "" && c.ExternalSourceImageURL == "" && c.SourceImageFilters.Filters.Empty() {
|
||||||
|
errs = append(errs, errors.New("Either a source_image, a source_image_name, an external_source_image_url or source_image_filter must be specified"))
|
||||||
|
} else if !(hasOnlySourceImage || hasOnlySourceImageName || hasOnlyExternalSourceImageURL) {
|
||||||
|
errs = append(errs, errors.New("Only a source_image, a source_image_name or an external_source_image_url can be specified, not multiple."))
|
||||||
|
}
|
||||||
|
|
||||||
|
// if external_source_image_format is not set use qcow2 as default
|
||||||
|
if c.ExternalSourceImageFormat == "" {
|
||||||
|
c.ExternalSourceImageFormat = "qcow2"
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Flavor == "" {
|
if c.Flavor == "" {
|
||||||
|
@ -283,9 +297,9 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if neither ID or image name is provided outside the filter, build the
|
// if neither ID, image name or external image URL is provided outside the filter,
|
||||||
// filter
|
// build the filter
|
||||||
if len(c.SourceImage) == 0 && len(c.SourceImageName) == 0 {
|
if len(c.SourceImage) == 0 && len(c.SourceImageName) == 0 && len(c.ExternalSourceImageURL) == 0 {
|
||||||
|
|
||||||
listOpts, filterErr := c.SourceImageFilters.Filters.Build()
|
listOpts, filterErr := c.SourceImageFilters.Filters.Build()
|
||||||
|
|
||||||
|
@ -295,6 +309,11 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
|
||||||
c.sourceImageOpts = *listOpts
|
c.sourceImageOpts = *listOpts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if c.ExternalSourceImageURL is set use a generated source image name
|
||||||
|
if c.ExternalSourceImageURL != "" {
|
||||||
|
c.SourceImageName = fmt.Sprintf("packer_%s", uuid.TimeOrderedUUID())
|
||||||
|
}
|
||||||
|
|
||||||
return errs
|
return errs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package openstack
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/gophercloud/gophercloud/openstack/imageservice/v2/images"
|
"github.com/gophercloud/gophercloud/openstack/imageservice/v2/images"
|
||||||
|
@ -132,6 +133,49 @@ func TestRunConfigPrepare_FloatingIPPoolCompat(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRunConfigPrepare_ExternalSourceImageURL(t *testing.T) {
|
||||||
|
c := testRunConfig()
|
||||||
|
// test setting both ExternalSourceImageURL and SourceImage causes an error
|
||||||
|
c.ExternalSourceImageURL = "http://example.com/image.qcow2"
|
||||||
|
if err := c.Prepare(nil); len(err) != 1 {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// test setting both ExternalSourceImageURL and SourceImageName causes an error
|
||||||
|
c.SourceImage = ""
|
||||||
|
c.SourceImageName = "abcd"
|
||||||
|
c.ExternalSourceImageURL = "http://example.com/image.qcow2"
|
||||||
|
if err := c.Prepare(nil); len(err) != 1 {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// test neither setting SourceImage, SourceImageName or ExternalSourceImageURL causes an error
|
||||||
|
c.SourceImage = ""
|
||||||
|
c.SourceImageName = ""
|
||||||
|
c.ExternalSourceImageURL = ""
|
||||||
|
if err := c.Prepare(nil); len(err) != 1 {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// test setting only ExternalSourceImageURL passes
|
||||||
|
c.SourceImage = ""
|
||||||
|
c.SourceImageName = ""
|
||||||
|
c.ExternalSourceImageURL = "http://example.com/image.qcow2"
|
||||||
|
if err := c.Prepare(nil); len(err) != 0 {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// test default values
|
||||||
|
if c.ExternalSourceImageFormat != "qcow2" {
|
||||||
|
t.Fatalf("ExternalSourceImageFormat should have been set to default: qcow2")
|
||||||
|
}
|
||||||
|
|
||||||
|
p := `packer_[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}`
|
||||||
|
if matches, _ := regexp.MatchString(p, c.SourceImageName); !matches {
|
||||||
|
t.Fatalf("invalid format for SourceImageName: %s", c.SourceImageName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This test case confirms that only allowed fields will be set to values
|
// This test case confirms that only allowed fields will be set to values
|
||||||
// The checked values are non-nil for their target type
|
// The checked values are non-nil for their target type
|
||||||
func TestBuildImageFilter(t *testing.T) {
|
func TestBuildImageFilter(t *testing.T) {
|
||||||
|
|
|
@ -4,7 +4,9 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/imageservice/v2/imageimport"
|
||||||
"github.com/gophercloud/gophercloud/openstack/imageservice/v2/images"
|
"github.com/gophercloud/gophercloud/openstack/imageservice/v2/images"
|
||||||
"github.com/gophercloud/gophercloud/pagination"
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
"github.com/hashicorp/packer/helper/multistep"
|
"github.com/hashicorp/packer/helper/multistep"
|
||||||
|
@ -14,6 +16,8 @@ import (
|
||||||
type StepSourceImageInfo struct {
|
type StepSourceImageInfo struct {
|
||||||
SourceImage string
|
SourceImage string
|
||||||
SourceImageName string
|
SourceImageName string
|
||||||
|
ExternalSourceImageURL string
|
||||||
|
ExternalSourceImageFormat string
|
||||||
SourceImageOpts images.ListOpts
|
SourceImageOpts images.ListOpts
|
||||||
SourceMostRecent bool
|
SourceMostRecent bool
|
||||||
SourceProperties map[string]string
|
SourceProperties map[string]string
|
||||||
|
@ -33,12 +37,6 @@ func (s *StepSourceImageInfo) Run(ctx context.Context, state multistep.StateBag)
|
||||||
config := state.Get("config").(*Config)
|
config := state.Get("config").(*Config)
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
|
||||||
if s.SourceImage != "" {
|
|
||||||
state.Put("source_image", s.SourceImage)
|
|
||||||
|
|
||||||
return multistep.ActionContinue
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := config.imageV2Client()
|
client, err := config.imageV2Client()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("error creating image client: %s", err)
|
err := fmt.Errorf("error creating image client: %s", err)
|
||||||
|
@ -47,6 +45,70 @@ func (s *StepSourceImageInfo) Run(ctx context.Context, state multistep.StateBag)
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.ExternalSourceImageURL != "" {
|
||||||
|
createOpts := images.CreateOpts{
|
||||||
|
Name: s.SourceImageName,
|
||||||
|
ContainerFormat: "bare",
|
||||||
|
DiskFormat: s.ExternalSourceImageFormat,
|
||||||
|
Properties: map[string]string{
|
||||||
|
"packer_external_source_image_url": s.ExternalSourceImageURL,
|
||||||
|
"packer_external_source_image_format": s.ExternalSourceImageFormat,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say("Creating image using external source image with name " + s.SourceImageName)
|
||||||
|
ui.Say("Using disk format " + s.ExternalSourceImageFormat)
|
||||||
|
image, err := images.Create(client, createOpts).Extract()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error creating source image: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say("Created image with ID " + image.ID)
|
||||||
|
|
||||||
|
importOpts := imageimport.CreateOpts{
|
||||||
|
Name: imageimport.WebDownloadMethod,
|
||||||
|
URI: s.ExternalSourceImageURL,
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say("Importing External Source Image from URL " + s.ExternalSourceImageURL)
|
||||||
|
err = imageimport.Create(client, image.ID, importOpts).ExtractErr()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error importing source image: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
for image.Status != images.ImageStatusActive {
|
||||||
|
ui.Message("Image not Active, retrying in 10 seconds")
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
|
||||||
|
img, err := images.Get(client, image.ID).Extract()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error querying image: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
image = img
|
||||||
|
}
|
||||||
|
|
||||||
|
s.SourceImage = image.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.SourceImage != "" {
|
||||||
|
state.Put("source_image", s.SourceImage)
|
||||||
|
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
if s.SourceImageName != "" {
|
if s.SourceImageName != "" {
|
||||||
s.SourceImageOpts = images.ListOpts{
|
s.SourceImageOpts = images.ListOpts{
|
||||||
Name: s.SourceImageName,
|
Name: s.SourceImageName,
|
||||||
|
@ -117,5 +179,25 @@ func (s *StepSourceImageInfo) Run(ctx context.Context, state multistep.StateBag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StepSourceImageInfo) Cleanup(state multistep.StateBag) {
|
func (s *StepSourceImageInfo) Cleanup(state multistep.StateBag) {
|
||||||
// No cleanup required for backout
|
if s.ExternalSourceImageURL != "" {
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
|
||||||
|
client, err := config.imageV2Client()
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("error creating image client: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say(fmt.Sprintf("Deleting temporary external source image: %s ...", s.SourceImageName))
|
||||||
|
err = images.Delete(client, s.SourceImage).ExtractErr()
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("error cleaning up external source image: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,7 @@ type diskConfig struct {
|
||||||
Size string `mapstructure:"disk_size"`
|
Size string `mapstructure:"disk_size"`
|
||||||
CacheMode string `mapstructure:"cache_mode"`
|
CacheMode string `mapstructure:"cache_mode"`
|
||||||
DiskFormat string `mapstructure:"format"`
|
DiskFormat string `mapstructure:"format"`
|
||||||
|
IOThread bool `mapstructure:"io_thread"`
|
||||||
}
|
}
|
||||||
type vgaConfig struct {
|
type vgaConfig struct {
|
||||||
Type string `mapstructure:"type"`
|
Type string `mapstructure:"type"`
|
||||||
|
@ -189,6 +190,17 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
|
||||||
log.Printf("Disk %d cache mode not set, using default 'none'", idx)
|
log.Printf("Disk %d cache mode not set, using default 'none'", idx)
|
||||||
c.Disks[idx].CacheMode = "none"
|
c.Disks[idx].CacheMode = "none"
|
||||||
}
|
}
|
||||||
|
if c.Disks[idx].IOThread {
|
||||||
|
// io thread is only supported by virtio-scsi-single controller
|
||||||
|
if c.SCSIController != "virtio-scsi-single" {
|
||||||
|
errs = packer.MultiErrorAppend(errs, fmt.Errorf("io thread option requires virtio-scsi-single controller"))
|
||||||
|
} else {
|
||||||
|
// ... and only for virtio and scsi disks
|
||||||
|
if !(c.Disks[idx].Type == "scsi" || c.Disks[idx].Type == "virtio") {
|
||||||
|
errs = packer.MultiErrorAppend(errs, fmt.Errorf("io thread option requires scsi or a virtio disk"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// For any storage pool types which aren't in rxStorageTypes in proxmox-api/proxmox/config_qemu.go:890
|
// For any storage pool types which aren't in rxStorageTypes in proxmox-api/proxmox/config_qemu.go:890
|
||||||
// (currently zfspool|lvm|rbd|cephfs), the format parameter is mandatory. Make sure this is still up to date
|
// (currently zfspool|lvm|rbd|cephfs), the format parameter is mandatory. Make sure this is still up to date
|
||||||
// when updating the vendored code!
|
// when updating the vendored code!
|
||||||
|
|
|
@ -230,6 +230,7 @@ type FlatdiskConfig struct {
|
||||||
Size *string `mapstructure:"disk_size" cty:"disk_size" hcl:"disk_size"`
|
Size *string `mapstructure:"disk_size" cty:"disk_size" hcl:"disk_size"`
|
||||||
CacheMode *string `mapstructure:"cache_mode" cty:"cache_mode" hcl:"cache_mode"`
|
CacheMode *string `mapstructure:"cache_mode" cty:"cache_mode" hcl:"cache_mode"`
|
||||||
DiskFormat *string `mapstructure:"format" cty:"format" hcl:"format"`
|
DiskFormat *string `mapstructure:"format" cty:"format" hcl:"format"`
|
||||||
|
IOThread *bool `mapstructure:"io_thread" cty:"io_thread" hcl:"io_thread"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// FlatMapstructure returns a new FlatdiskConfig.
|
// FlatMapstructure returns a new FlatdiskConfig.
|
||||||
|
@ -250,6 +251,7 @@ func (*FlatdiskConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
"disk_size": &hcldec.AttrSpec{Name: "disk_size", Type: cty.String, Required: false},
|
"disk_size": &hcldec.AttrSpec{Name: "disk_size", Type: cty.String, Required: false},
|
||||||
"cache_mode": &hcldec.AttrSpec{Name: "cache_mode", Type: cty.String, Required: false},
|
"cache_mode": &hcldec.AttrSpec{Name: "cache_mode", Type: cty.String, Required: false},
|
||||||
"format": &hcldec.AttrSpec{Name: "format", Type: cty.String, Required: false},
|
"format": &hcldec.AttrSpec{Name: "format", Type: cty.String, Required: false},
|
||||||
|
"io_thread": &hcldec.AttrSpec{Name: "io_thread", Type: cty.Bool, Required: false},
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
|
@ -208,3 +208,52 @@ func TestPacketQueueSupportForNetworkAdapters(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHardDiskControllerIOThreadSupport(t *testing.T) {
|
||||||
|
drivertests := []struct {
|
||||||
|
expectedToFail bool
|
||||||
|
controller string
|
||||||
|
disk_type string
|
||||||
|
}{
|
||||||
|
// io thread is only supported by virtio-scsi-single controller
|
||||||
|
// and only for virtio and scsi disks
|
||||||
|
{expectedToFail: false, controller: "virtio-scsi-single", disk_type: "scsi"},
|
||||||
|
{expectedToFail: false, controller: "virtio-scsi-single", disk_type: "virtio"},
|
||||||
|
{expectedToFail: true, controller: "virtio-scsi-single", disk_type: "sata"},
|
||||||
|
{expectedToFail: true, controller: "lsi", disk_type: "scsi"},
|
||||||
|
{expectedToFail: true, controller: "lsi53c810", disk_type: "virtio"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range drivertests {
|
||||||
|
nic := make(map[string]interface{})
|
||||||
|
nic["bridge"] = "vmbr0"
|
||||||
|
|
||||||
|
nics := make([]map[string]interface{}, 0)
|
||||||
|
nics = append(nics, nic)
|
||||||
|
|
||||||
|
disk := make(map[string]interface{})
|
||||||
|
disk["type"] = tt.disk_type
|
||||||
|
disk["io_thread"] = true
|
||||||
|
disk["storage_pool"] = "local-lvm"
|
||||||
|
disk["storage_pool_type"] = "lvm"
|
||||||
|
|
||||||
|
disks := make([]map[string]interface{}, 0)
|
||||||
|
disks = append(disks, disk)
|
||||||
|
|
||||||
|
cfg := mandatoryConfig(t)
|
||||||
|
cfg["network_adapters"] = nics
|
||||||
|
cfg["disks"] = disks
|
||||||
|
cfg["scsi_controller"] = tt.controller
|
||||||
|
|
||||||
|
var c Config
|
||||||
|
_, err := c.Prepare(cfg)
|
||||||
|
|
||||||
|
if tt.expectedToFail == true && err == nil {
|
||||||
|
t.Error("expected config preparation to fail, but no error occured")
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.expectedToFail == false && err != nil {
|
||||||
|
t.Errorf("expected config preparation to succeed, but %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -142,6 +142,10 @@ func generateProxmoxDisks(disks []diskConfig) proxmox.QemuDevices {
|
||||||
setDeviceParamIfDefined(devs[idx], "storage_type", disks[idx].StoragePoolType)
|
setDeviceParamIfDefined(devs[idx], "storage_type", disks[idx].StoragePoolType)
|
||||||
setDeviceParamIfDefined(devs[idx], "cache", disks[idx].CacheMode)
|
setDeviceParamIfDefined(devs[idx], "cache", disks[idx].CacheMode)
|
||||||
setDeviceParamIfDefined(devs[idx], "format", disks[idx].DiskFormat)
|
setDeviceParamIfDefined(devs[idx], "format", disks[idx].DiskFormat)
|
||||||
|
|
||||||
|
if devs[idx]["type"] == "scsi" || devs[idx]["type"] == "virtio" {
|
||||||
|
setDeviceParamIfDefined(devs[idx], "iothread", strconv.FormatBool(disks[idx].IOThread))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return devs
|
return devs
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,6 +137,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||||
OutputDir: b.config.OutputDir,
|
OutputDir: b.config.OutputDir,
|
||||||
SkipCompaction: b.config.SkipCompaction,
|
SkipCompaction: b.config.SkipCompaction,
|
||||||
VMName: b.config.VMName,
|
VMName: b.config.VMName,
|
||||||
|
QemuImgArgs: b.config.QemuImgArgs,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
type StepPrepareTools struct {
|
type StepPrepareTools struct {
|
||||||
RemoteType string
|
RemoteType string
|
||||||
ToolsUploadFlavor string
|
ToolsUploadFlavor string
|
||||||
|
ToolsSourcePath string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StepPrepareTools) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
func (c *StepPrepareTools) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
|
@ -20,11 +21,15 @@ func (c *StepPrepareTools) Run(ctx context.Context, state multistep.StateBag) mu
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.ToolsUploadFlavor == "" {
|
if c.ToolsUploadFlavor == "" && c.ToolsSourcePath == "" {
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
path := driver.ToolsIsoPath(c.ToolsUploadFlavor)
|
path := c.ToolsSourcePath
|
||||||
|
if path == "" {
|
||||||
|
path = driver.ToolsIsoPath(c.ToolsUploadFlavor)
|
||||||
|
}
|
||||||
|
|
||||||
if _, err := os.Stat(path); err != nil {
|
if _, err := os.Stat(path); err != nil {
|
||||||
state.Put("error", fmt.Errorf(
|
state.Put("error", fmt.Errorf(
|
||||||
"Couldn't find VMware tools for '%s'! VMware often downloads these\n"+
|
"Couldn't find VMware tools for '%s'! VMware often downloads these\n"+
|
||||||
|
|
|
@ -114,3 +114,65 @@ func TestStepPrepareTools_nonExist(t *testing.T) {
|
||||||
t.Fatal("should NOT have tools_upload_source")
|
t.Fatal("should NOT have tools_upload_source")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStepPrepareTools_SourcePath(t *testing.T) {
|
||||||
|
state := testState(t)
|
||||||
|
step := &StepPrepareTools{
|
||||||
|
RemoteType: "",
|
||||||
|
ToolsSourcePath: "/path/to/tool.iso",
|
||||||
|
}
|
||||||
|
|
||||||
|
driver := state.Get("driver").(*DriverMock)
|
||||||
|
|
||||||
|
// Mock results
|
||||||
|
driver.ToolsIsoPathResult = "foo"
|
||||||
|
|
||||||
|
// Test the run
|
||||||
|
if action := step.Run(context.Background(), state); action != multistep.ActionHalt {
|
||||||
|
t.Fatalf("Should have failed when stat failed %#v", action)
|
||||||
|
}
|
||||||
|
if _, ok := state.GetOk("error"); !ok {
|
||||||
|
t.Fatal("should have error")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test the driver
|
||||||
|
if driver.ToolsIsoPathCalled {
|
||||||
|
t.Fatal("tools iso path should not be called when ToolsSourcePath is set")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test the resulting state
|
||||||
|
if _, ok := state.GetOk("tools_upload_source"); ok {
|
||||||
|
t.Fatal("should NOT have tools_upload_source")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStepPrepareTools_SourcePath_exists(t *testing.T) {
|
||||||
|
state := testState(t)
|
||||||
|
step := &StepPrepareTools{
|
||||||
|
RemoteType: "",
|
||||||
|
ToolsSourcePath: "./step_prepare_tools.go",
|
||||||
|
}
|
||||||
|
|
||||||
|
driver := state.Get("driver").(*DriverMock)
|
||||||
|
|
||||||
|
// Mock results
|
||||||
|
driver.ToolsIsoPathResult = "foo"
|
||||||
|
|
||||||
|
// Test the run
|
||||||
|
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
|
||||||
|
t.Fatalf("Step should succeed when stat succeeds: %#v", action)
|
||||||
|
}
|
||||||
|
if _, ok := state.GetOk("error"); ok {
|
||||||
|
t.Fatal("should NOT have error")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test the driver
|
||||||
|
if driver.ToolsIsoPathCalled {
|
||||||
|
t.Fatal("tools iso path should not be called when ToolsSourcePath is set")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test the resulting state
|
||||||
|
if _, ok := state.GetOk("tools_upload_source"); !ok {
|
||||||
|
t.Fatal("should have tools_upload_source")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/hashicorp/packer/template/interpolate"
|
"github.com/hashicorp/packer/template/interpolate"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -18,12 +20,22 @@ type ToolsConfig struct {
|
||||||
// the upload path is set to `{{.Flavor}}.iso`. This setting is not used
|
// the upload path is set to `{{.Flavor}}.iso`. This setting is not used
|
||||||
// when `remote_type` is `esx5`.
|
// when `remote_type` is `esx5`.
|
||||||
ToolsUploadPath string `mapstructure:"tools_upload_path" required:"false"`
|
ToolsUploadPath string `mapstructure:"tools_upload_path" required:"false"`
|
||||||
|
// The path on your local machine to fetch the vmware tools from. If this
|
||||||
|
// is not set but the tools_upload_flavor is set, then Packer will try to
|
||||||
|
// load the VMWare tools from the VMWare installation directory.
|
||||||
|
ToolsSourcePath string `mapstructure:"tools_source_path" required:"false"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ToolsConfig) Prepare(ctx *interpolate.Context) []error {
|
func (c *ToolsConfig) Prepare(ctx *interpolate.Context) []error {
|
||||||
|
errs := []error{}
|
||||||
if c.ToolsUploadPath == "" {
|
if c.ToolsUploadPath == "" {
|
||||||
|
if c.ToolsSourcePath != "" && c.ToolsUploadFlavor == "" {
|
||||||
|
errs = append(errs, fmt.Errorf("If you provide a "+
|
||||||
|
"tools_source_path, you must also provide either a "+
|
||||||
|
"tools_upload_flavor or a tools_upload_path."))
|
||||||
|
}
|
||||||
c.ToolsUploadPath = "{{ .Flavor }}.iso"
|
c.ToolsUploadPath = "{{ .Flavor }}.iso"
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return errs
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/packer/template/interpolate"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestToolsConfigPrepare_Empty(t *testing.T) {
|
||||||
|
c := &ToolsConfig{}
|
||||||
|
|
||||||
|
errs := c.Prepare(interpolate.NewContext())
|
||||||
|
if len(errs) > 0 {
|
||||||
|
t.Fatalf("err: %#v", errs)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.ToolsUploadPath != "{{ .Flavor }}.iso" {
|
||||||
|
t.Fatal("should have defaulted tools upload path")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToolsConfigPrepare_SetUploadPath(t *testing.T) {
|
||||||
|
c := &ToolsConfig{
|
||||||
|
ToolsUploadPath: "path/to/tools.iso",
|
||||||
|
}
|
||||||
|
|
||||||
|
errs := c.Prepare(interpolate.NewContext())
|
||||||
|
if len(errs) > 0 {
|
||||||
|
t.Fatalf("err: %#v", errs)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.ToolsUploadPath != "path/to/tools.iso" {
|
||||||
|
t.Fatal("should have used given tools upload path")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToolsConfigPrepare_ErrorIfOnlySource(t *testing.T) {
|
||||||
|
c := &ToolsConfig{
|
||||||
|
ToolsSourcePath: "path/to/tools.iso",
|
||||||
|
}
|
||||||
|
|
||||||
|
errs := c.Prepare(interpolate.NewContext())
|
||||||
|
if len(errs) != 1 {
|
||||||
|
t.Fatalf("Should have received an error because the flavor and " +
|
||||||
|
"upload path aren't set")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToolsConfigPrepare_SourceSuccess(t *testing.T) {
|
||||||
|
for _, c := range []*ToolsConfig{
|
||||||
|
&ToolsConfig{
|
||||||
|
ToolsSourcePath: "path/to/tools.iso",
|
||||||
|
ToolsUploadPath: "partypath.iso",
|
||||||
|
},
|
||||||
|
&ToolsConfig{
|
||||||
|
ToolsSourcePath: "path/to/tools.iso",
|
||||||
|
ToolsUploadFlavor: "linux",
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
errs := c.Prepare(interpolate.NewContext())
|
||||||
|
if len(errs) != 0 {
|
||||||
|
t.Fatalf("Should not have received an error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -119,6 +119,7 @@ type FlatConfig struct {
|
||||||
SSHSkipRequestPty *bool `mapstructure:"ssh_skip_request_pty" cty:"ssh_skip_request_pty" hcl:"ssh_skip_request_pty"`
|
SSHSkipRequestPty *bool `mapstructure:"ssh_skip_request_pty" cty:"ssh_skip_request_pty" hcl:"ssh_skip_request_pty"`
|
||||||
ToolsUploadFlavor *string `mapstructure:"tools_upload_flavor" required:"false" cty:"tools_upload_flavor" hcl:"tools_upload_flavor"`
|
ToolsUploadFlavor *string `mapstructure:"tools_upload_flavor" required:"false" cty:"tools_upload_flavor" hcl:"tools_upload_flavor"`
|
||||||
ToolsUploadPath *string `mapstructure:"tools_upload_path" required:"false" cty:"tools_upload_path" hcl:"tools_upload_path"`
|
ToolsUploadPath *string `mapstructure:"tools_upload_path" required:"false" cty:"tools_upload_path" hcl:"tools_upload_path"`
|
||||||
|
ToolsSourcePath *string `mapstructure:"tools_source_path" required:"false" cty:"tools_source_path" hcl:"tools_source_path"`
|
||||||
VMXData map[string]string `mapstructure:"vmx_data" required:"false" cty:"vmx_data" hcl:"vmx_data"`
|
VMXData map[string]string `mapstructure:"vmx_data" required:"false" cty:"vmx_data" hcl:"vmx_data"`
|
||||||
VMXDataPost map[string]string `mapstructure:"vmx_data_post" required:"false" cty:"vmx_data_post" hcl:"vmx_data_post"`
|
VMXDataPost map[string]string `mapstructure:"vmx_data_post" required:"false" cty:"vmx_data_post" hcl:"vmx_data_post"`
|
||||||
VMXRemoveEthernet *bool `mapstructure:"vmx_remove_ethernet_interfaces" required:"false" cty:"vmx_remove_ethernet_interfaces" hcl:"vmx_remove_ethernet_interfaces"`
|
VMXRemoveEthernet *bool `mapstructure:"vmx_remove_ethernet_interfaces" required:"false" cty:"vmx_remove_ethernet_interfaces" hcl:"vmx_remove_ethernet_interfaces"`
|
||||||
|
@ -263,6 +264,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
"ssh_skip_request_pty": &hcldec.AttrSpec{Name: "ssh_skip_request_pty", Type: cty.Bool, Required: false},
|
"ssh_skip_request_pty": &hcldec.AttrSpec{Name: "ssh_skip_request_pty", Type: cty.Bool, Required: false},
|
||||||
"tools_upload_flavor": &hcldec.AttrSpec{Name: "tools_upload_flavor", Type: cty.String, Required: false},
|
"tools_upload_flavor": &hcldec.AttrSpec{Name: "tools_upload_flavor", Type: cty.String, Required: false},
|
||||||
"tools_upload_path": &hcldec.AttrSpec{Name: "tools_upload_path", Type: cty.String, Required: false},
|
"tools_upload_path": &hcldec.AttrSpec{Name: "tools_upload_path", Type: cty.String, Required: false},
|
||||||
|
"tools_source_path": &hcldec.AttrSpec{Name: "tools_source_path", Type: cty.String, Required: false},
|
||||||
"vmx_data": &hcldec.AttrSpec{Name: "vmx_data", Type: cty.Map(cty.String), Required: false},
|
"vmx_data": &hcldec.AttrSpec{Name: "vmx_data", Type: cty.Map(cty.String), Required: false},
|
||||||
"vmx_data_post": &hcldec.AttrSpec{Name: "vmx_data_post", Type: cty.Map(cty.String), Required: false},
|
"vmx_data_post": &hcldec.AttrSpec{Name: "vmx_data_post", Type: cty.Map(cty.String), Required: false},
|
||||||
"vmx_remove_ethernet_interfaces": &hcldec.AttrSpec{Name: "vmx_remove_ethernet_interfaces", Type: cty.Bool, Required: false},
|
"vmx_remove_ethernet_interfaces": &hcldec.AttrSpec{Name: "vmx_remove_ethernet_interfaces", Type: cty.Bool, Required: false},
|
||||||
|
|
|
@ -104,6 +104,7 @@ type FlatConfig struct {
|
||||||
SSHSkipRequestPty *bool `mapstructure:"ssh_skip_request_pty" cty:"ssh_skip_request_pty" hcl:"ssh_skip_request_pty"`
|
SSHSkipRequestPty *bool `mapstructure:"ssh_skip_request_pty" cty:"ssh_skip_request_pty" hcl:"ssh_skip_request_pty"`
|
||||||
ToolsUploadFlavor *string `mapstructure:"tools_upload_flavor" required:"false" cty:"tools_upload_flavor" hcl:"tools_upload_flavor"`
|
ToolsUploadFlavor *string `mapstructure:"tools_upload_flavor" required:"false" cty:"tools_upload_flavor" hcl:"tools_upload_flavor"`
|
||||||
ToolsUploadPath *string `mapstructure:"tools_upload_path" required:"false" cty:"tools_upload_path" hcl:"tools_upload_path"`
|
ToolsUploadPath *string `mapstructure:"tools_upload_path" required:"false" cty:"tools_upload_path" hcl:"tools_upload_path"`
|
||||||
|
ToolsSourcePath *string `mapstructure:"tools_source_path" required:"false" cty:"tools_source_path" hcl:"tools_source_path"`
|
||||||
VMXData map[string]string `mapstructure:"vmx_data" required:"false" cty:"vmx_data" hcl:"vmx_data"`
|
VMXData map[string]string `mapstructure:"vmx_data" required:"false" cty:"vmx_data" hcl:"vmx_data"`
|
||||||
VMXDataPost map[string]string `mapstructure:"vmx_data_post" required:"false" cty:"vmx_data_post" hcl:"vmx_data_post"`
|
VMXDataPost map[string]string `mapstructure:"vmx_data_post" required:"false" cty:"vmx_data_post" hcl:"vmx_data_post"`
|
||||||
VMXRemoveEthernet *bool `mapstructure:"vmx_remove_ethernet_interfaces" required:"false" cty:"vmx_remove_ethernet_interfaces" hcl:"vmx_remove_ethernet_interfaces"`
|
VMXRemoveEthernet *bool `mapstructure:"vmx_remove_ethernet_interfaces" required:"false" cty:"vmx_remove_ethernet_interfaces" hcl:"vmx_remove_ethernet_interfaces"`
|
||||||
|
@ -229,6 +230,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
"ssh_skip_request_pty": &hcldec.AttrSpec{Name: "ssh_skip_request_pty", Type: cty.Bool, Required: false},
|
"ssh_skip_request_pty": &hcldec.AttrSpec{Name: "ssh_skip_request_pty", Type: cty.Bool, Required: false},
|
||||||
"tools_upload_flavor": &hcldec.AttrSpec{Name: "tools_upload_flavor", Type: cty.String, Required: false},
|
"tools_upload_flavor": &hcldec.AttrSpec{Name: "tools_upload_flavor", Type: cty.String, Required: false},
|
||||||
"tools_upload_path": &hcldec.AttrSpec{Name: "tools_upload_path", Type: cty.String, Required: false},
|
"tools_upload_path": &hcldec.AttrSpec{Name: "tools_upload_path", Type: cty.String, Required: false},
|
||||||
|
"tools_source_path": &hcldec.AttrSpec{Name: "tools_source_path", Type: cty.String, Required: false},
|
||||||
"vmx_data": &hcldec.AttrSpec{Name: "vmx_data", Type: cty.Map(cty.String), Required: false},
|
"vmx_data": &hcldec.AttrSpec{Name: "vmx_data", Type: cty.Map(cty.String), Required: false},
|
||||||
"vmx_data_post": &hcldec.AttrSpec{Name: "vmx_data_post", Type: cty.Map(cty.String), Required: false},
|
"vmx_data_post": &hcldec.AttrSpec{Name: "vmx_data_post", Type: cty.Map(cty.String), Required: false},
|
||||||
"vmx_remove_ethernet_interfaces": &hcldec.AttrSpec{Name: "vmx_remove_ethernet_interfaces", Type: cty.Bool, Required: false},
|
"vmx_remove_ethernet_interfaces": &hcldec.AttrSpec{Name: "vmx_remove_ethernet_interfaces", Type: cty.Bool, Required: false},
|
||||||
|
|
|
@ -41,6 +41,15 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||||
&common.StepConnect{
|
&common.StepConnect{
|
||||||
Config: &b.config.ConnectConfig,
|
Config: &b.config.ConnectConfig,
|
||||||
},
|
},
|
||||||
|
&packerCommon.StepCreateCD{
|
||||||
|
Files: b.config.CDConfig.CDFiles,
|
||||||
|
Label: b.config.CDConfig.CDLabel,
|
||||||
|
},
|
||||||
|
&common.StepRemoteUpload{
|
||||||
|
Datastore: b.config.Datastore,
|
||||||
|
Host: b.config.Host,
|
||||||
|
SetHostForDatastoreUploads: b.config.SetHostForDatastoreUploads,
|
||||||
|
},
|
||||||
&StepCloneVM{
|
&StepCloneVM{
|
||||||
Config: &b.config.CloneConfig,
|
Config: &b.config.CloneConfig,
|
||||||
Location: &b.config.LocationConfig,
|
Location: &b.config.LocationConfig,
|
||||||
|
@ -49,6 +58,9 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||||
&common.StepConfigureHardware{
|
&common.StepConfigureHardware{
|
||||||
Config: &b.config.HardwareConfig,
|
Config: &b.config.HardwareConfig,
|
||||||
},
|
},
|
||||||
|
&common.StepAddCDRom{
|
||||||
|
Config: &b.config.CDRomConfig,
|
||||||
|
},
|
||||||
&common.StepConfigParams{
|
&common.StepConfigParams{
|
||||||
Config: &b.config.ConfigParamsConfig,
|
Config: &b.config.ConfigParamsConfig,
|
||||||
},
|
},
|
||||||
|
@ -62,6 +74,17 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||||
|
|
||||||
if b.config.Comm.Type != "none" {
|
if b.config.Comm.Type != "none" {
|
||||||
steps = append(steps,
|
steps = append(steps,
|
||||||
|
&packerCommon.StepCreateFloppy{
|
||||||
|
Files: b.config.FloppyFiles,
|
||||||
|
Directories: b.config.FloppyDirectories,
|
||||||
|
Label: b.config.FloppyLabel,
|
||||||
|
},
|
||||||
|
&common.StepAddFloppy{
|
||||||
|
Config: &b.config.FloppyConfig,
|
||||||
|
Datastore: b.config.Datastore,
|
||||||
|
Host: b.config.Host,
|
||||||
|
SetHostForDatastoreUploads: b.config.SetHostForDatastoreUploads,
|
||||||
|
},
|
||||||
&common.StepHTTPIPDiscover{
|
&common.StepHTTPIPDiscover{
|
||||||
HTTPIP: b.config.BootConfig.HTTPIP,
|
HTTPIP: b.config.BootConfig.HTTPIP,
|
||||||
Network: b.config.WaitIpConfig.GetIPNet(),
|
Network: b.config.WaitIpConfig.GetIPNet(),
|
||||||
|
@ -98,10 +121,17 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||||
&common.StepShutdown{
|
&common.StepShutdown{
|
||||||
Config: &b.config.ShutdownConfig,
|
Config: &b.config.ShutdownConfig,
|
||||||
},
|
},
|
||||||
|
&common.StepRemoveFloppy{
|
||||||
|
Datastore: b.config.Datastore,
|
||||||
|
Host: b.config.Host,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
steps = append(steps,
|
steps = append(steps,
|
||||||
|
&common.StepRemoveCDRom{
|
||||||
|
Config: &b.config.RemoveCDRomConfig,
|
||||||
|
},
|
||||||
&common.StepCreateSnapshot{
|
&common.StepCreateSnapshot{
|
||||||
CreateSnapshot: b.config.CreateSnapshot,
|
CreateSnapshot: b.config.CreateSnapshot,
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
type Config struct {
|
type Config struct {
|
||||||
packerCommon.PackerConfig `mapstructure:",squash"`
|
packerCommon.PackerConfig `mapstructure:",squash"`
|
||||||
packerCommon.HTTPConfig `mapstructure:",squash"`
|
packerCommon.HTTPConfig `mapstructure:",squash"`
|
||||||
|
packerCommon.CDConfig `mapstructure:",squash"`
|
||||||
|
|
||||||
common.ConnectConfig `mapstructure:",squash"`
|
common.ConnectConfig `mapstructure:",squash"`
|
||||||
CloneConfig `mapstructure:",squash"`
|
CloneConfig `mapstructure:",squash"`
|
||||||
|
@ -22,6 +23,9 @@ type Config struct {
|
||||||
common.HardwareConfig `mapstructure:",squash"`
|
common.HardwareConfig `mapstructure:",squash"`
|
||||||
common.ConfigParamsConfig `mapstructure:",squash"`
|
common.ConfigParamsConfig `mapstructure:",squash"`
|
||||||
|
|
||||||
|
common.CDRomConfig `mapstructure:",squash"`
|
||||||
|
common.RemoveCDRomConfig `mapstructure:",squash"`
|
||||||
|
common.FloppyConfig `mapstructure:",squash"`
|
||||||
common.RunConfig `mapstructure:",squash"`
|
common.RunConfig `mapstructure:",squash"`
|
||||||
common.BootConfig `mapstructure:",squash"`
|
common.BootConfig `mapstructure:",squash"`
|
||||||
common.WaitIpConfig `mapstructure:",squash"`
|
common.WaitIpConfig `mapstructure:",squash"`
|
||||||
|
@ -67,6 +71,8 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
|
||||||
errs = packer.MultiErrorAppend(errs, c.HardwareConfig.Prepare()...)
|
errs = packer.MultiErrorAppend(errs, c.HardwareConfig.Prepare()...)
|
||||||
errs = packer.MultiErrorAppend(errs, c.HTTPConfig.Prepare(&c.ctx)...)
|
errs = packer.MultiErrorAppend(errs, c.HTTPConfig.Prepare(&c.ctx)...)
|
||||||
|
|
||||||
|
errs = packer.MultiErrorAppend(errs, c.CDRomConfig.Prepare()...)
|
||||||
|
errs = packer.MultiErrorAppend(errs, c.CDConfig.Prepare(&c.ctx)...)
|
||||||
errs = packer.MultiErrorAppend(errs, c.BootConfig.Prepare(&c.ctx)...)
|
errs = packer.MultiErrorAppend(errs, c.BootConfig.Prepare(&c.ctx)...)
|
||||||
errs = packer.MultiErrorAppend(errs, c.WaitIpConfig.Prepare()...)
|
errs = packer.MultiErrorAppend(errs, c.WaitIpConfig.Prepare()...)
|
||||||
errs = packer.MultiErrorAppend(errs, c.Comm.Prepare(&c.ctx)...)
|
errs = packer.MultiErrorAppend(errs, c.Comm.Prepare(&c.ctx)...)
|
||||||
|
|
|
@ -22,6 +22,8 @@ type FlatConfig struct {
|
||||||
HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"`
|
HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"`
|
||||||
HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"`
|
HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"`
|
||||||
HTTPInterface *string `mapstructure:"http_interface" undocumented:"true" cty:"http_interface" hcl:"http_interface"`
|
HTTPInterface *string `mapstructure:"http_interface" undocumented:"true" cty:"http_interface" hcl:"http_interface"`
|
||||||
|
CDFiles []string `mapstructure:"cd_files" cty:"cd_files" hcl:"cd_files"`
|
||||||
|
CDLabel *string `mapstructure:"cd_label" cty:"cd_label" hcl:"cd_label"`
|
||||||
VCenterServer *string `mapstructure:"vcenter_server" cty:"vcenter_server" hcl:"vcenter_server"`
|
VCenterServer *string `mapstructure:"vcenter_server" cty:"vcenter_server" hcl:"vcenter_server"`
|
||||||
Username *string `mapstructure:"username" cty:"username" hcl:"username"`
|
Username *string `mapstructure:"username" cty:"username" hcl:"username"`
|
||||||
Password *string `mapstructure:"password" cty:"password" hcl:"password"`
|
Password *string `mapstructure:"password" cty:"password" hcl:"password"`
|
||||||
|
@ -58,6 +60,13 @@ type FlatConfig struct {
|
||||||
ConfigParams map[string]string `mapstructure:"configuration_parameters" cty:"configuration_parameters" hcl:"configuration_parameters"`
|
ConfigParams map[string]string `mapstructure:"configuration_parameters" cty:"configuration_parameters" hcl:"configuration_parameters"`
|
||||||
ToolsSyncTime *bool `mapstructure:"tools_sync_time" cty:"tools_sync_time" hcl:"tools_sync_time"`
|
ToolsSyncTime *bool `mapstructure:"tools_sync_time" cty:"tools_sync_time" hcl:"tools_sync_time"`
|
||||||
ToolsUpgradePolicy *bool `mapstructure:"tools_upgrade_policy" cty:"tools_upgrade_policy" hcl:"tools_upgrade_policy"`
|
ToolsUpgradePolicy *bool `mapstructure:"tools_upgrade_policy" cty:"tools_upgrade_policy" hcl:"tools_upgrade_policy"`
|
||||||
|
CdromType *string `mapstructure:"cdrom_type" cty:"cdrom_type" hcl:"cdrom_type"`
|
||||||
|
ISOPaths []string `mapstructure:"iso_paths" cty:"iso_paths" hcl:"iso_paths"`
|
||||||
|
RemoveCdrom *bool `mapstructure:"remove_cdrom" cty:"remove_cdrom" hcl:"remove_cdrom"`
|
||||||
|
FloppyIMGPath *string `mapstructure:"floppy_img_path" cty:"floppy_img_path" hcl:"floppy_img_path"`
|
||||||
|
FloppyFiles []string `mapstructure:"floppy_files" cty:"floppy_files" hcl:"floppy_files"`
|
||||||
|
FloppyDirectories []string `mapstructure:"floppy_dirs" cty:"floppy_dirs" hcl:"floppy_dirs"`
|
||||||
|
FloppyLabel *string `mapstructure:"floppy_label" cty:"floppy_label" hcl:"floppy_label"`
|
||||||
BootOrder *string `mapstructure:"boot_order" cty:"boot_order" hcl:"boot_order"`
|
BootOrder *string `mapstructure:"boot_order" cty:"boot_order" hcl:"boot_order"`
|
||||||
BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval" hcl:"boot_keygroup_interval"`
|
BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval" hcl:"boot_keygroup_interval"`
|
||||||
BootWait *string `mapstructure:"boot_wait" cty:"boot_wait" hcl:"boot_wait"`
|
BootWait *string `mapstructure:"boot_wait" cty:"boot_wait" hcl:"boot_wait"`
|
||||||
|
@ -147,6 +156,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
"http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false},
|
"http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false},
|
||||||
"http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false},
|
"http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false},
|
||||||
"http_interface": &hcldec.AttrSpec{Name: "http_interface", Type: cty.String, Required: false},
|
"http_interface": &hcldec.AttrSpec{Name: "http_interface", Type: cty.String, Required: false},
|
||||||
|
"cd_files": &hcldec.AttrSpec{Name: "cd_files", Type: cty.List(cty.String), Required: false},
|
||||||
|
"cd_label": &hcldec.AttrSpec{Name: "cd_label", Type: cty.String, Required: false},
|
||||||
"vcenter_server": &hcldec.AttrSpec{Name: "vcenter_server", Type: cty.String, Required: false},
|
"vcenter_server": &hcldec.AttrSpec{Name: "vcenter_server", Type: cty.String, Required: false},
|
||||||
"username": &hcldec.AttrSpec{Name: "username", Type: cty.String, Required: false},
|
"username": &hcldec.AttrSpec{Name: "username", Type: cty.String, Required: false},
|
||||||
"password": &hcldec.AttrSpec{Name: "password", Type: cty.String, Required: false},
|
"password": &hcldec.AttrSpec{Name: "password", Type: cty.String, Required: false},
|
||||||
|
@ -183,6 +194,13 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
"configuration_parameters": &hcldec.AttrSpec{Name: "configuration_parameters", Type: cty.Map(cty.String), Required: false},
|
"configuration_parameters": &hcldec.AttrSpec{Name: "configuration_parameters", Type: cty.Map(cty.String), Required: false},
|
||||||
"tools_sync_time": &hcldec.AttrSpec{Name: "tools_sync_time", Type: cty.Bool, Required: false},
|
"tools_sync_time": &hcldec.AttrSpec{Name: "tools_sync_time", Type: cty.Bool, Required: false},
|
||||||
"tools_upgrade_policy": &hcldec.AttrSpec{Name: "tools_upgrade_policy", Type: cty.Bool, Required: false},
|
"tools_upgrade_policy": &hcldec.AttrSpec{Name: "tools_upgrade_policy", Type: cty.Bool, Required: false},
|
||||||
|
"cdrom_type": &hcldec.AttrSpec{Name: "cdrom_type", Type: cty.String, Required: false},
|
||||||
|
"iso_paths": &hcldec.AttrSpec{Name: "iso_paths", Type: cty.List(cty.String), Required: false},
|
||||||
|
"remove_cdrom": &hcldec.AttrSpec{Name: "remove_cdrom", Type: cty.Bool, Required: false},
|
||||||
|
"floppy_img_path": &hcldec.AttrSpec{Name: "floppy_img_path", Type: cty.String, Required: false},
|
||||||
|
"floppy_files": &hcldec.AttrSpec{Name: "floppy_files", Type: cty.List(cty.String), Required: false},
|
||||||
|
"floppy_dirs": &hcldec.AttrSpec{Name: "floppy_dirs", Type: cty.List(cty.String), Required: false},
|
||||||
|
"floppy_label": &hcldec.AttrSpec{Name: "floppy_label", Type: cty.String, Required: false},
|
||||||
"boot_order": &hcldec.AttrSpec{Name: "boot_order", Type: cty.String, Required: false},
|
"boot_order": &hcldec.AttrSpec{Name: "boot_order", Type: cty.String, Required: false},
|
||||||
"boot_keygroup_interval": &hcldec.AttrSpec{Name: "boot_keygroup_interval", Type: cty.String, Required: false},
|
"boot_keygroup_interval": &hcldec.AttrSpec{Name: "boot_keygroup_interval", Type: cty.String, Required: false},
|
||||||
"boot_wait": &hcldec.AttrSpec{Name: "boot_wait", Type: cty.String, Required: false},
|
"boot_wait": &hcldec.AttrSpec{Name: "boot_wait", Type: cty.String, Required: false},
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//go:generate struct-markdown
|
//go:generate struct-markdown
|
||||||
//go:generate mapstructure-to-hcl2 -type CDRomConfig
|
//go:generate mapstructure-to-hcl2 -type CDRomConfig
|
||||||
|
|
||||||
package iso
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
|
@ -1,5 +1,5 @@
|
||||||
// Code generated by "mapstructure-to-hcl2 -type CDRomConfig"; DO NOT EDIT.
|
// Code generated by "mapstructure-to-hcl2 -type CDRomConfig"; DO NOT EDIT.
|
||||||
package iso
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/hashicorp/hcl/v2/hcldec"
|
"github.com/hashicorp/hcl/v2/hcldec"
|
|
@ -1,4 +1,4 @@
|
||||||
package iso
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -96,7 +96,7 @@ func TestStepAddCDRom_Run(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Add SATA Controller",
|
name: "Add SATA Controller",
|
||||||
state: basicStateBag(),
|
state: basicStateBag(nil),
|
||||||
step: &StepAddCDRom{
|
step: &StepAddCDRom{
|
||||||
Config: &CDRomConfig{
|
Config: &CDRomConfig{
|
||||||
CdromType: "sata",
|
CdromType: "sata",
|
||||||
|
@ -116,7 +116,7 @@ func TestStepAddCDRom_Run(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Fail to add SATA Controller",
|
name: "Fail to add SATA Controller",
|
||||||
state: basicStateBag(),
|
state: basicStateBag(nil),
|
||||||
step: &StepAddCDRom{
|
step: &StepAddCDRom{
|
||||||
Config: &CDRomConfig{
|
Config: &CDRomConfig{
|
||||||
CdromType: "sata",
|
CdromType: "sata",
|
||||||
|
@ -136,7 +136,7 @@ func TestStepAddCDRom_Run(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "IDE CDRom Type and Iso Path set",
|
name: "IDE CDRom Type and Iso Path set",
|
||||||
state: basicStateBag(),
|
state: basicStateBag(nil),
|
||||||
step: &StepAddCDRom{
|
step: &StepAddCDRom{
|
||||||
Config: &CDRomConfig{
|
Config: &CDRomConfig{
|
||||||
CdromType: "ide",
|
CdromType: "ide",
|
||||||
|
@ -156,7 +156,7 @@ func TestStepAddCDRom_Run(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Fail to add cdrom from ISOPaths",
|
name: "Fail to add cdrom from ISOPaths",
|
||||||
state: basicStateBag(),
|
state: basicStateBag(nil),
|
||||||
step: &StepAddCDRom{
|
step: &StepAddCDRom{
|
||||||
Config: &CDRomConfig{
|
Config: &CDRomConfig{
|
||||||
ISOPaths: []string{"iso/path"},
|
ISOPaths: []string{"iso/path"},
|
||||||
|
@ -222,14 +222,14 @@ func TestStepAddCDRom_Run(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func cdAndIsoRemotePathStateBag() *multistep.BasicStateBag {
|
func cdAndIsoRemotePathStateBag() *multistep.BasicStateBag {
|
||||||
state := basicStateBag()
|
state := basicStateBag(nil)
|
||||||
state.Put("iso_remote_path", "remote/path")
|
state.Put("iso_remote_path", "remote/path")
|
||||||
state.Put("cd_path", "cd/path")
|
state.Put("cd_path", "cd/path")
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
func isoRemotePathStateBag() *multistep.BasicStateBag {
|
func isoRemotePathStateBag() *multistep.BasicStateBag {
|
||||||
state := basicStateBag()
|
state := basicStateBag(nil)
|
||||||
state.Put("iso_remote_path", "remote/path")
|
state.Put("iso_remote_path", "remote/path")
|
||||||
return state
|
return state
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
//go:generate struct-markdown
|
//go:generate struct-markdown
|
||||||
//go:generate mapstructure-to-hcl2 -type FloppyConfig
|
//go:generate mapstructure-to-hcl2 -type FloppyConfig
|
||||||
|
|
||||||
package iso
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -37,8 +37,8 @@ type StepAddFloppy struct {
|
||||||
|
|
||||||
func (s *StepAddFloppy) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
func (s *StepAddFloppy) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
vm := state.Get("vm").(*driver.VirtualMachineDriver)
|
vm := state.Get("vm").(driver.VirtualMachine)
|
||||||
d := state.Get("driver").(*driver.VCenterDriver)
|
d := state.Get("driver").(driver.Driver)
|
||||||
|
|
||||||
if floppyPath, ok := state.GetOk("floppy_path"); ok {
|
if floppyPath, ok := state.GetOk("floppy_path"); ok {
|
||||||
ui.Say("Uploading created floppy image")
|
ui.Say("Uploading created floppy image")
|
||||||
|
@ -90,7 +90,7 @@ func (s *StepAddFloppy) Cleanup(state multistep.StateBag) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
d := state.Get("driver").(*driver.VCenterDriver)
|
d := state.Get("driver").(driver.Driver)
|
||||||
|
|
||||||
if UploadedFloppyPath, ok := state.GetOk("uploaded_floppy_path"); ok {
|
if UploadedFloppyPath, ok := state.GetOk("uploaded_floppy_path"); ok {
|
||||||
ui.Say("Deleting Floppy image ...")
|
ui.Say("Deleting Floppy image ...")
|
|
@ -1,5 +1,5 @@
|
||||||
// Code generated by "mapstructure-to-hcl2 -type FloppyConfig"; DO NOT EDIT.
|
// Code generated by "mapstructure-to-hcl2 -type FloppyConfig"; DO NOT EDIT.
|
||||||
package iso
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/hashicorp/hcl/v2/hcldec"
|
"github.com/hashicorp/hcl/v2/hcldec"
|
|
@ -0,0 +1,453 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"github.com/google/go-cmp/cmp/cmpopts"
|
||||||
|
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||||
|
"github.com/hashicorp/packer/helper/multistep"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStepAddFloppy_Run(t *testing.T) {
|
||||||
|
tc := []struct {
|
||||||
|
name string
|
||||||
|
floppyPath string
|
||||||
|
uploadedPath string
|
||||||
|
step *StepAddFloppy
|
||||||
|
expectedAction multistep.StepAction
|
||||||
|
vmMock *driver.VirtualMachineMock
|
||||||
|
expectedVmMock *driver.VirtualMachineMock
|
||||||
|
driverMock *driver.DriverMock
|
||||||
|
expectedDriverMock *driver.DriverMock
|
||||||
|
dsMock *driver.DatastoreMock
|
||||||
|
expectedDsMock *driver.DatastoreMock
|
||||||
|
fail bool
|
||||||
|
errMessage string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Add floppy from state floppy path",
|
||||||
|
floppyPath: "floppy/path",
|
||||||
|
uploadedPath: "vm/dir/packer-tmp-created-floppy.flp",
|
||||||
|
step: &StepAddFloppy{
|
||||||
|
Config: new(FloppyConfig),
|
||||||
|
Datastore: "datastore",
|
||||||
|
Host: "host",
|
||||||
|
SetHostForDatastoreUploads: true,
|
||||||
|
},
|
||||||
|
expectedAction: multistep.ActionContinue,
|
||||||
|
vmMock: &driver.VirtualMachineMock{
|
||||||
|
GetDirResponse: "vm/dir",
|
||||||
|
},
|
||||||
|
expectedVmMock: &driver.VirtualMachineMock{
|
||||||
|
GetDirResponse: "vm/dir",
|
||||||
|
GetDirCalled: true,
|
||||||
|
AddFloppyCalled: true,
|
||||||
|
AddFloppyImagePath: "resolved/path",
|
||||||
|
},
|
||||||
|
driverMock: new(driver.DriverMock),
|
||||||
|
expectedDriverMock: &driver.DriverMock{
|
||||||
|
FindDatastoreCalled: true,
|
||||||
|
FindDatastoreName: "datastore",
|
||||||
|
FindDatastoreHost: "host",
|
||||||
|
},
|
||||||
|
dsMock: &driver.DatastoreMock{
|
||||||
|
ResolvePathReturn: "resolved/path",
|
||||||
|
},
|
||||||
|
expectedDsMock: &driver.DatastoreMock{
|
||||||
|
UploadFileCalled: true,
|
||||||
|
UploadFileSrc: "floppy/path",
|
||||||
|
UploadFileDst: "vm/dir/packer-tmp-created-floppy.flp",
|
||||||
|
UploadFileHost: "host",
|
||||||
|
UploadFileSetHost: true,
|
||||||
|
ResolvePathCalled: true,
|
||||||
|
ResolvePathReturn: "resolved/path",
|
||||||
|
},
|
||||||
|
fail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "State floppy path - find datastore fail",
|
||||||
|
floppyPath: "floppy/path",
|
||||||
|
step: &StepAddFloppy{
|
||||||
|
Config: new(FloppyConfig),
|
||||||
|
Datastore: "datastore",
|
||||||
|
Host: "host",
|
||||||
|
SetHostForDatastoreUploads: true,
|
||||||
|
},
|
||||||
|
expectedAction: multistep.ActionHalt,
|
||||||
|
vmMock: new(driver.VirtualMachineMock),
|
||||||
|
expectedVmMock: new(driver.VirtualMachineMock),
|
||||||
|
driverMock: &driver.DriverMock{
|
||||||
|
FindDatastoreErr: fmt.Errorf("error finding datastore"),
|
||||||
|
},
|
||||||
|
expectedDriverMock: &driver.DriverMock{
|
||||||
|
FindDatastoreCalled: true,
|
||||||
|
FindDatastoreName: "datastore",
|
||||||
|
FindDatastoreHost: "host",
|
||||||
|
},
|
||||||
|
dsMock: new(driver.DatastoreMock),
|
||||||
|
expectedDsMock: new(driver.DatastoreMock),
|
||||||
|
fail: true,
|
||||||
|
errMessage: "error finding datastore",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "State floppy path - vm get dir fail",
|
||||||
|
floppyPath: "floppy/path",
|
||||||
|
step: &StepAddFloppy{
|
||||||
|
Config: new(FloppyConfig),
|
||||||
|
Datastore: "datastore",
|
||||||
|
Host: "host",
|
||||||
|
SetHostForDatastoreUploads: true,
|
||||||
|
},
|
||||||
|
expectedAction: multistep.ActionHalt,
|
||||||
|
vmMock: &driver.VirtualMachineMock{
|
||||||
|
GetDirErr: fmt.Errorf("fail to get vm dir"),
|
||||||
|
},
|
||||||
|
expectedVmMock: &driver.VirtualMachineMock{
|
||||||
|
GetDirCalled: true,
|
||||||
|
},
|
||||||
|
driverMock: new(driver.DriverMock),
|
||||||
|
expectedDriverMock: &driver.DriverMock{
|
||||||
|
FindDatastoreCalled: true,
|
||||||
|
FindDatastoreName: "datastore",
|
||||||
|
FindDatastoreHost: "host",
|
||||||
|
},
|
||||||
|
dsMock: new(driver.DatastoreMock),
|
||||||
|
expectedDsMock: new(driver.DatastoreMock),
|
||||||
|
fail: true,
|
||||||
|
errMessage: "fail to get vm dir",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "State floppy path - datastore upload file fail",
|
||||||
|
floppyPath: "floppy/path",
|
||||||
|
step: &StepAddFloppy{
|
||||||
|
Config: new(FloppyConfig),
|
||||||
|
Datastore: "datastore",
|
||||||
|
Host: "host",
|
||||||
|
SetHostForDatastoreUploads: true,
|
||||||
|
},
|
||||||
|
expectedAction: multistep.ActionHalt,
|
||||||
|
vmMock: &driver.VirtualMachineMock{
|
||||||
|
GetDirResponse: "vm/dir",
|
||||||
|
},
|
||||||
|
expectedVmMock: &driver.VirtualMachineMock{
|
||||||
|
GetDirResponse: "vm/dir",
|
||||||
|
GetDirCalled: true,
|
||||||
|
},
|
||||||
|
driverMock: new(driver.DriverMock),
|
||||||
|
expectedDriverMock: &driver.DriverMock{
|
||||||
|
FindDatastoreCalled: true,
|
||||||
|
FindDatastoreName: "datastore",
|
||||||
|
FindDatastoreHost: "host",
|
||||||
|
},
|
||||||
|
dsMock: &driver.DatastoreMock{
|
||||||
|
UploadFileErr: fmt.Errorf("failed to upload file"),
|
||||||
|
},
|
||||||
|
expectedDsMock: &driver.DatastoreMock{
|
||||||
|
UploadFileCalled: true,
|
||||||
|
UploadFileSrc: "floppy/path",
|
||||||
|
UploadFileDst: "vm/dir/packer-tmp-created-floppy.flp",
|
||||||
|
UploadFileHost: "host",
|
||||||
|
UploadFileSetHost: true,
|
||||||
|
},
|
||||||
|
fail: true,
|
||||||
|
errMessage: "failed to upload file",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "State floppy path - vm fail to add floppy",
|
||||||
|
floppyPath: "floppy/path",
|
||||||
|
uploadedPath: "vm/dir/packer-tmp-created-floppy.flp",
|
||||||
|
step: &StepAddFloppy{
|
||||||
|
Config: new(FloppyConfig),
|
||||||
|
Datastore: "datastore",
|
||||||
|
Host: "host",
|
||||||
|
SetHostForDatastoreUploads: true,
|
||||||
|
},
|
||||||
|
expectedAction: multistep.ActionHalt,
|
||||||
|
vmMock: &driver.VirtualMachineMock{
|
||||||
|
GetDirResponse: "vm/dir",
|
||||||
|
AddFloppyErr: fmt.Errorf("failed to add floppy"),
|
||||||
|
},
|
||||||
|
expectedVmMock: &driver.VirtualMachineMock{
|
||||||
|
GetDirResponse: "vm/dir",
|
||||||
|
GetDirCalled: true,
|
||||||
|
AddFloppyCalled: true,
|
||||||
|
AddFloppyImagePath: "resolved/path",
|
||||||
|
},
|
||||||
|
driverMock: new(driver.DriverMock),
|
||||||
|
expectedDriverMock: &driver.DriverMock{
|
||||||
|
FindDatastoreCalled: true,
|
||||||
|
FindDatastoreName: "datastore",
|
||||||
|
FindDatastoreHost: "host",
|
||||||
|
},
|
||||||
|
dsMock: &driver.DatastoreMock{
|
||||||
|
ResolvePathReturn: "resolved/path",
|
||||||
|
},
|
||||||
|
expectedDsMock: &driver.DatastoreMock{
|
||||||
|
UploadFileCalled: true,
|
||||||
|
UploadFileSrc: "floppy/path",
|
||||||
|
UploadFileDst: "vm/dir/packer-tmp-created-floppy.flp",
|
||||||
|
UploadFileHost: "host",
|
||||||
|
UploadFileSetHost: true,
|
||||||
|
ResolvePathCalled: true,
|
||||||
|
ResolvePathReturn: "resolved/path",
|
||||||
|
},
|
||||||
|
fail: true,
|
||||||
|
errMessage: "failed to add floppy",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Add floppy from FloppyIMGPath config",
|
||||||
|
step: &StepAddFloppy{
|
||||||
|
Config: &FloppyConfig{
|
||||||
|
FloppyIMGPath: "floppy/image/path",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedAction: multistep.ActionContinue,
|
||||||
|
vmMock: new(driver.VirtualMachineMock),
|
||||||
|
expectedVmMock: &driver.VirtualMachineMock{
|
||||||
|
AddFloppyCalled: true,
|
||||||
|
AddFloppyImagePath: "floppy/image/path",
|
||||||
|
},
|
||||||
|
driverMock: new(driver.DriverMock),
|
||||||
|
expectedDriverMock: new(driver.DriverMock),
|
||||||
|
dsMock: new(driver.DatastoreMock),
|
||||||
|
expectedDsMock: new(driver.DatastoreMock),
|
||||||
|
fail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Fail to add floppy from FloppyIMGPath config",
|
||||||
|
step: &StepAddFloppy{
|
||||||
|
Config: &FloppyConfig{
|
||||||
|
FloppyIMGPath: "floppy/image/path",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedAction: multistep.ActionHalt,
|
||||||
|
vmMock: &driver.VirtualMachineMock{
|
||||||
|
AddFloppyErr: fmt.Errorf("fail to add floppy"),
|
||||||
|
},
|
||||||
|
expectedVmMock: &driver.VirtualMachineMock{
|
||||||
|
AddFloppyCalled: true,
|
||||||
|
AddFloppyImagePath: "floppy/image/path",
|
||||||
|
},
|
||||||
|
driverMock: new(driver.DriverMock),
|
||||||
|
expectedDriverMock: new(driver.DriverMock),
|
||||||
|
dsMock: new(driver.DatastoreMock),
|
||||||
|
expectedDsMock: new(driver.DatastoreMock),
|
||||||
|
fail: true,
|
||||||
|
errMessage: "fail to add floppy",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range tc {
|
||||||
|
t.Run(c.name, func(t *testing.T) {
|
||||||
|
state := basicStateBag(nil)
|
||||||
|
state.Put("vm", c.vmMock)
|
||||||
|
c.driverMock.DatastoreMock = c.dsMock
|
||||||
|
state.Put("driver", c.driverMock)
|
||||||
|
|
||||||
|
if c.floppyPath != "" {
|
||||||
|
state.Put("floppy_path", c.floppyPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
if action := c.step.Run(context.TODO(), state); action != c.expectedAction {
|
||||||
|
t.Fatalf("unexpected action %v", action)
|
||||||
|
}
|
||||||
|
err, ok := state.Get("error").(error)
|
||||||
|
if ok {
|
||||||
|
if err.Error() != c.errMessage {
|
||||||
|
t.Fatalf("unexpected error %s", err.Error())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if c.fail {
|
||||||
|
t.Fatalf("expected to fail but it didn't")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadedPath, _ := state.Get("uploaded_floppy_path").(string)
|
||||||
|
if uploadedPath != c.uploadedPath {
|
||||||
|
t.Fatalf("Unexpected uploaded path state %s", uploadedPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmp.Diff(c.vmMock, c.expectedVmMock,
|
||||||
|
cmpopts.IgnoreInterfaces(struct{ error }{})); diff != "" {
|
||||||
|
t.Fatalf("unexpected VirtualMachine calls: %s", diff)
|
||||||
|
}
|
||||||
|
c.expectedDriverMock.DatastoreMock = c.expectedDsMock
|
||||||
|
if diff := cmp.Diff(c.driverMock, c.expectedDriverMock,
|
||||||
|
cmpopts.IgnoreInterfaces(struct{ error }{})); diff != "" {
|
||||||
|
t.Fatalf("unexpected Driver calls: %s", diff)
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(c.dsMock, c.expectedDsMock,
|
||||||
|
cmpopts.IgnoreInterfaces(struct{ error }{})); diff != "" {
|
||||||
|
t.Fatalf("unexpected Datastore calls: %s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStepAddFloppy_Cleanup(t *testing.T) {
|
||||||
|
tc := []struct {
|
||||||
|
name string
|
||||||
|
uploadedPath string
|
||||||
|
multistepState string
|
||||||
|
step *StepAddFloppy
|
||||||
|
driverMock *driver.DriverMock
|
||||||
|
expectedDriverMock *driver.DriverMock
|
||||||
|
dsMock *driver.DatastoreMock
|
||||||
|
expectedDsMock *driver.DatastoreMock
|
||||||
|
fail bool
|
||||||
|
errMessage string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "State cancelled clean up",
|
||||||
|
uploadedPath: "uploaded/path",
|
||||||
|
multistepState: multistep.StateCancelled,
|
||||||
|
step: &StepAddFloppy{
|
||||||
|
Datastore: "datastore",
|
||||||
|
Host: "host",
|
||||||
|
},
|
||||||
|
driverMock: new(driver.DriverMock),
|
||||||
|
expectedDriverMock: &driver.DriverMock{
|
||||||
|
FindDatastoreCalled: true,
|
||||||
|
FindDatastoreName: "datastore",
|
||||||
|
FindDatastoreHost: "host",
|
||||||
|
},
|
||||||
|
dsMock: &driver.DatastoreMock{
|
||||||
|
DeleteCalled: true,
|
||||||
|
},
|
||||||
|
expectedDsMock: &driver.DatastoreMock{
|
||||||
|
DeleteCalled: true,
|
||||||
|
DeletePath: "uploaded/path",
|
||||||
|
},
|
||||||
|
fail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "State halted clean up",
|
||||||
|
uploadedPath: "uploaded/path",
|
||||||
|
multistepState: multistep.StateHalted,
|
||||||
|
step: &StepAddFloppy{
|
||||||
|
Datastore: "datastore",
|
||||||
|
Host: "host",
|
||||||
|
},
|
||||||
|
driverMock: new(driver.DriverMock),
|
||||||
|
expectedDriverMock: &driver.DriverMock{
|
||||||
|
FindDatastoreCalled: true,
|
||||||
|
FindDatastoreName: "datastore",
|
||||||
|
FindDatastoreHost: "host",
|
||||||
|
},
|
||||||
|
dsMock: &driver.DatastoreMock{
|
||||||
|
DeleteCalled: true,
|
||||||
|
},
|
||||||
|
expectedDsMock: &driver.DatastoreMock{
|
||||||
|
DeleteCalled: true,
|
||||||
|
DeletePath: "uploaded/path",
|
||||||
|
},
|
||||||
|
fail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Don't clean up without uploaded path",
|
||||||
|
multistepState: multistep.StateHalted,
|
||||||
|
step: new(StepAddFloppy),
|
||||||
|
driverMock: new(driver.DriverMock),
|
||||||
|
expectedDriverMock: new(driver.DriverMock),
|
||||||
|
dsMock: new(driver.DatastoreMock),
|
||||||
|
expectedDsMock: new(driver.DatastoreMock),
|
||||||
|
fail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Don't clean up if state is not halted or canceled",
|
||||||
|
multistepState: "",
|
||||||
|
step: new(StepAddFloppy),
|
||||||
|
driverMock: new(driver.DriverMock),
|
||||||
|
expectedDriverMock: new(driver.DriverMock),
|
||||||
|
dsMock: new(driver.DatastoreMock),
|
||||||
|
expectedDsMock: new(driver.DatastoreMock),
|
||||||
|
fail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Fail because datastore is not found",
|
||||||
|
uploadedPath: "uploaded/path",
|
||||||
|
multistepState: multistep.StateHalted,
|
||||||
|
step: &StepAddFloppy{
|
||||||
|
Datastore: "datastore",
|
||||||
|
Host: "host",
|
||||||
|
},
|
||||||
|
driverMock: &driver.DriverMock{
|
||||||
|
FindDatastoreErr: fmt.Errorf("fail to find datastore"),
|
||||||
|
},
|
||||||
|
expectedDriverMock: &driver.DriverMock{
|
||||||
|
FindDatastoreCalled: true,
|
||||||
|
FindDatastoreName: "datastore",
|
||||||
|
FindDatastoreHost: "host",
|
||||||
|
},
|
||||||
|
dsMock: new(driver.DatastoreMock),
|
||||||
|
expectedDsMock: new(driver.DatastoreMock),
|
||||||
|
fail: true,
|
||||||
|
errMessage: "fail to find datastore",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Fail to delete floppy",
|
||||||
|
uploadedPath: "uploaded/path",
|
||||||
|
multistepState: multistep.StateHalted,
|
||||||
|
step: &StepAddFloppy{
|
||||||
|
Datastore: "datastore",
|
||||||
|
Host: "host",
|
||||||
|
},
|
||||||
|
driverMock: new(driver.DriverMock),
|
||||||
|
expectedDriverMock: &driver.DriverMock{
|
||||||
|
FindDatastoreCalled: true,
|
||||||
|
FindDatastoreName: "datastore",
|
||||||
|
FindDatastoreHost: "host",
|
||||||
|
},
|
||||||
|
dsMock: &driver.DatastoreMock{
|
||||||
|
DeleteCalled: true,
|
||||||
|
DeleteErr: fmt.Errorf("failed to delete floppy"),
|
||||||
|
},
|
||||||
|
expectedDsMock: &driver.DatastoreMock{
|
||||||
|
DeleteCalled: true,
|
||||||
|
DeletePath: "uploaded/path",
|
||||||
|
},
|
||||||
|
fail: true,
|
||||||
|
errMessage: "failed to delete floppy",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range tc {
|
||||||
|
t.Run(c.name, func(t *testing.T) {
|
||||||
|
state := basicStateBag(nil)
|
||||||
|
c.driverMock.DatastoreMock = c.dsMock
|
||||||
|
state.Put("driver", c.driverMock)
|
||||||
|
if c.uploadedPath != "" {
|
||||||
|
state.Put("uploaded_floppy_path", c.uploadedPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.multistepState != "" {
|
||||||
|
state.Put(c.multistepState, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.step.Cleanup(state)
|
||||||
|
err, ok := state.Get("error").(error)
|
||||||
|
if ok {
|
||||||
|
if err.Error() != c.errMessage {
|
||||||
|
t.Fatalf("unexpected error %s", err.Error())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if c.fail {
|
||||||
|
t.Fatalf("expected to fail but it didn't")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.expectedDriverMock.DatastoreMock = c.expectedDsMock
|
||||||
|
if diff := cmp.Diff(c.driverMock, c.expectedDriverMock,
|
||||||
|
cmpopts.IgnoreInterfaces(struct{ error }{})); diff != "" {
|
||||||
|
t.Fatalf("unexpected Driver calls: %s", diff)
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(c.dsMock, c.expectedDsMock,
|
||||||
|
cmpopts.IgnoreInterfaces(struct{ error }{})); diff != "" {
|
||||||
|
t.Fatalf("unexpected Datastore calls: %s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package iso
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
|
@ -1,4 +1,4 @@
|
||||||
package iso
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -10,7 +10,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestStepRemoteUpload_Run(t *testing.T) {
|
func TestStepRemoteUpload_Run(t *testing.T) {
|
||||||
state := basicStateBag()
|
state := basicStateBag(nil)
|
||||||
driverMock := driver.NewDriverMock()
|
driverMock := driver.NewDriverMock()
|
||||||
state.Put("driver", driverMock)
|
state.Put("driver", driverMock)
|
||||||
state.Put("iso_path", "[datastore] iso/path")
|
state.Put("iso_path", "[datastore] iso/path")
|
||||||
|
@ -48,7 +48,7 @@ func TestStepRemoteUpload_Run(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStepRemoteUpload_SkipRun(t *testing.T) {
|
func TestStepRemoteUpload_SkipRun(t *testing.T) {
|
||||||
state := basicStateBag()
|
state := basicStateBag(nil)
|
||||||
driverMock := driver.NewDriverMock()
|
driverMock := driver.NewDriverMock()
|
||||||
state.Put("driver", driverMock)
|
state.Put("driver", driverMock)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//go:generate struct-markdown
|
//go:generate struct-markdown
|
||||||
//go:generate mapstructure-to-hcl2 -type RemoveCDRomConfig
|
//go:generate mapstructure-to-hcl2 -type RemoveCDRomConfig
|
||||||
|
|
||||||
package iso
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -22,7 +22,7 @@ type StepRemoveCDRom struct {
|
||||||
|
|
||||||
func (s *StepRemoveCDRom) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
func (s *StepRemoveCDRom) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
vm := state.Get("vm").(*driver.VirtualMachineDriver)
|
vm := state.Get("vm").(driver.VirtualMachine)
|
||||||
|
|
||||||
ui.Say("Eject CD-ROM drives...")
|
ui.Say("Eject CD-ROM drives...")
|
||||||
err := vm.EjectCdroms()
|
err := vm.EjectCdroms()
|
|
@ -1,5 +1,5 @@
|
||||||
// Code generated by "mapstructure-to-hcl2 -type RemoveCDRomConfig"; DO NOT EDIT.
|
// Code generated by "mapstructure-to-hcl2 -type RemoveCDRomConfig"; DO NOT EDIT.
|
||||||
package iso
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/hashicorp/hcl/v2/hcldec"
|
"github.com/hashicorp/hcl/v2/hcldec"
|
|
@ -0,0 +1,111 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"github.com/google/go-cmp/cmp/cmpopts"
|
||||||
|
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||||
|
"github.com/hashicorp/packer/helper/multistep"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStepRemoveCDRom_Run(t *testing.T) {
|
||||||
|
tc := []struct {
|
||||||
|
name string
|
||||||
|
step *StepRemoveCDRom
|
||||||
|
expectedAction multistep.StepAction
|
||||||
|
vmMock *driver.VirtualMachineMock
|
||||||
|
expectedVmMock *driver.VirtualMachineMock
|
||||||
|
fail bool
|
||||||
|
errMessage string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Eject CD-ROM drives",
|
||||||
|
step: &StepRemoveCDRom{
|
||||||
|
Config: &RemoveCDRomConfig{},
|
||||||
|
},
|
||||||
|
expectedAction: multistep.ActionContinue,
|
||||||
|
vmMock: new(driver.VirtualMachineMock),
|
||||||
|
expectedVmMock: &driver.VirtualMachineMock{
|
||||||
|
EjectCdromsCalled: true,
|
||||||
|
},
|
||||||
|
fail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Failed to eject CD-ROM drives",
|
||||||
|
step: &StepRemoveCDRom{
|
||||||
|
Config: &RemoveCDRomConfig{},
|
||||||
|
},
|
||||||
|
expectedAction: multistep.ActionHalt,
|
||||||
|
vmMock: &driver.VirtualMachineMock{
|
||||||
|
EjectCdromsErr: fmt.Errorf("failed to eject cd-rom drives"),
|
||||||
|
},
|
||||||
|
expectedVmMock: &driver.VirtualMachineMock{
|
||||||
|
EjectCdromsCalled: true,
|
||||||
|
},
|
||||||
|
fail: true,
|
||||||
|
errMessage: "failed to eject cd-rom drives",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Eject and delete CD-ROM drives",
|
||||||
|
step: &StepRemoveCDRom{
|
||||||
|
Config: &RemoveCDRomConfig{
|
||||||
|
RemoveCdrom: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedAction: multistep.ActionContinue,
|
||||||
|
vmMock: new(driver.VirtualMachineMock),
|
||||||
|
expectedVmMock: &driver.VirtualMachineMock{
|
||||||
|
EjectCdromsCalled: true,
|
||||||
|
RemoveCdromsCalled: true,
|
||||||
|
},
|
||||||
|
fail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Fail to delete CD-ROM drives",
|
||||||
|
step: &StepRemoveCDRom{
|
||||||
|
Config: &RemoveCDRomConfig{
|
||||||
|
RemoveCdrom: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedAction: multistep.ActionHalt,
|
||||||
|
vmMock: &driver.VirtualMachineMock{
|
||||||
|
RemoveCdromsErr: fmt.Errorf("failed to delete cd-rom devices"),
|
||||||
|
},
|
||||||
|
expectedVmMock: &driver.VirtualMachineMock{
|
||||||
|
EjectCdromsCalled: true,
|
||||||
|
RemoveCdromsCalled: true,
|
||||||
|
},
|
||||||
|
fail: true,
|
||||||
|
errMessage: "failed to delete cd-rom devices",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range tc {
|
||||||
|
t.Run(c.name, func(t *testing.T) {
|
||||||
|
state := basicStateBag(nil)
|
||||||
|
state.Put("vm", c.vmMock)
|
||||||
|
|
||||||
|
if action := c.step.Run(context.TODO(), state); action != c.expectedAction {
|
||||||
|
t.Fatalf("unexpected action %v", action)
|
||||||
|
}
|
||||||
|
err, ok := state.Get("error").(error)
|
||||||
|
if ok {
|
||||||
|
if err.Error() != c.errMessage {
|
||||||
|
t.Fatalf("unexpected error %s", err.Error())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if c.fail {
|
||||||
|
t.Fatalf("expected to fail but it didn't")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmp.Diff(c.vmMock, c.expectedVmMock,
|
||||||
|
cmpopts.IgnoreInterfaces(struct{ error }{})); diff != "" {
|
||||||
|
t.Fatalf("unexpected VirtualMachine calls: %s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package iso
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -6,7 +6,6 @@ import (
|
||||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||||
"github.com/hashicorp/packer/helper/multistep"
|
"github.com/hashicorp/packer/helper/multistep"
|
||||||
"github.com/hashicorp/packer/packer"
|
"github.com/hashicorp/packer/packer"
|
||||||
"github.com/vmware/govmomi/vim25/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type StepRemoveFloppy struct {
|
type StepRemoveFloppy struct {
|
||||||
|
@ -16,16 +15,15 @@ type StepRemoveFloppy struct {
|
||||||
|
|
||||||
func (s *StepRemoveFloppy) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
func (s *StepRemoveFloppy) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
vm := state.Get("vm").(*driver.VirtualMachineDriver)
|
vm := state.Get("vm").(driver.VirtualMachine)
|
||||||
d := state.Get("driver").(*driver.VCenterDriver)
|
d := state.Get("driver").(driver.Driver)
|
||||||
|
|
||||||
ui.Say("Deleting Floppy drives...")
|
ui.Say("Deleting Floppy drives...")
|
||||||
devices, err := vm.Devices()
|
floppies, err := vm.FloppyDevices()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
state.Put("error", err)
|
state.Put("error", err)
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
floppies := devices.SelectByType((*types.VirtualFloppy)(nil))
|
|
||||||
if err = vm.RemoveDevice(true, floppies...); err != nil {
|
if err = vm.RemoveDevice(true, floppies...); err != nil {
|
||||||
state.Put("error", err)
|
state.Put("error", err)
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
|
@ -0,0 +1,213 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"github.com/google/go-cmp/cmp/cmpopts"
|
||||||
|
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||||
|
"github.com/hashicorp/packer/helper/multistep"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStepRemoveFloppy_Run(t *testing.T) {
|
||||||
|
tc := []struct {
|
||||||
|
name string
|
||||||
|
uploadedPath string
|
||||||
|
step *StepRemoveFloppy
|
||||||
|
expectedAction multistep.StepAction
|
||||||
|
vmMock *driver.VirtualMachineMock
|
||||||
|
expectedVmMock *driver.VirtualMachineMock
|
||||||
|
driverMock *driver.DriverMock
|
||||||
|
expectedDriverMock *driver.DriverMock
|
||||||
|
dsMock *driver.DatastoreMock
|
||||||
|
expectedDsMock *driver.DatastoreMock
|
||||||
|
fail bool
|
||||||
|
errMessage string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Remove floppy drives and images",
|
||||||
|
uploadedPath: "vm/dir/packer-tmp-created-floppy.flp",
|
||||||
|
step: &StepRemoveFloppy{
|
||||||
|
Datastore: "datastore",
|
||||||
|
Host: "host",
|
||||||
|
},
|
||||||
|
expectedAction: multistep.ActionContinue,
|
||||||
|
vmMock: new(driver.VirtualMachineMock),
|
||||||
|
expectedVmMock: &driver.VirtualMachineMock{
|
||||||
|
FloppyDevicesCalled: true,
|
||||||
|
RemoveDeviceCalled: true,
|
||||||
|
RemoveDeviceKeepFiles: true,
|
||||||
|
},
|
||||||
|
driverMock: new(driver.DriverMock),
|
||||||
|
expectedDriverMock: &driver.DriverMock{
|
||||||
|
FindDatastoreCalled: true,
|
||||||
|
FindDatastoreName: "datastore",
|
||||||
|
FindDatastoreHost: "host",
|
||||||
|
},
|
||||||
|
dsMock: new(driver.DatastoreMock),
|
||||||
|
expectedDsMock: &driver.DatastoreMock{
|
||||||
|
DeleteCalled: true,
|
||||||
|
DeletePath: "vm/dir/packer-tmp-created-floppy.flp",
|
||||||
|
},
|
||||||
|
fail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "No floppy image to remove",
|
||||||
|
step: &StepRemoveFloppy{},
|
||||||
|
expectedAction: multistep.ActionContinue,
|
||||||
|
vmMock: new(driver.VirtualMachineMock),
|
||||||
|
expectedVmMock: &driver.VirtualMachineMock{
|
||||||
|
FloppyDevicesCalled: true,
|
||||||
|
RemoveDeviceCalled: true,
|
||||||
|
RemoveDeviceKeepFiles: true,
|
||||||
|
},
|
||||||
|
driverMock: new(driver.DriverMock),
|
||||||
|
expectedDriverMock: new(driver.DriverMock),
|
||||||
|
dsMock: new(driver.DatastoreMock),
|
||||||
|
expectedDsMock: new(driver.DatastoreMock),
|
||||||
|
fail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Fail to find floppy devices",
|
||||||
|
step: &StepRemoveFloppy{},
|
||||||
|
expectedAction: multistep.ActionHalt,
|
||||||
|
vmMock: &driver.VirtualMachineMock{
|
||||||
|
FloppyDevicesErr: fmt.Errorf("failed to find floppy devices"),
|
||||||
|
},
|
||||||
|
expectedVmMock: &driver.VirtualMachineMock{
|
||||||
|
FloppyDevicesCalled: true,
|
||||||
|
},
|
||||||
|
driverMock: new(driver.DriverMock),
|
||||||
|
expectedDriverMock: new(driver.DriverMock),
|
||||||
|
dsMock: new(driver.DatastoreMock),
|
||||||
|
expectedDsMock: new(driver.DatastoreMock),
|
||||||
|
fail: true,
|
||||||
|
errMessage: "failed to find floppy devices",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Fail to remove floppy devices",
|
||||||
|
step: &StepRemoveFloppy{},
|
||||||
|
expectedAction: multistep.ActionHalt,
|
||||||
|
vmMock: &driver.VirtualMachineMock{
|
||||||
|
RemoveDeviceErr: fmt.Errorf("failed to remove device"),
|
||||||
|
},
|
||||||
|
expectedVmMock: &driver.VirtualMachineMock{
|
||||||
|
FloppyDevicesCalled: true,
|
||||||
|
RemoveDeviceCalled: true,
|
||||||
|
RemoveDeviceKeepFiles: true,
|
||||||
|
},
|
||||||
|
driverMock: new(driver.DriverMock),
|
||||||
|
expectedDriverMock: new(driver.DriverMock),
|
||||||
|
dsMock: new(driver.DatastoreMock),
|
||||||
|
expectedDsMock: new(driver.DatastoreMock),
|
||||||
|
fail: true,
|
||||||
|
errMessage: "failed to remove device",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Fail to find datastore",
|
||||||
|
uploadedPath: "vm/dir/packer-tmp-created-floppy.flp",
|
||||||
|
step: &StepRemoveFloppy{
|
||||||
|
Datastore: "datastore",
|
||||||
|
Host: "host",
|
||||||
|
},
|
||||||
|
expectedAction: multistep.ActionHalt,
|
||||||
|
vmMock: new(driver.VirtualMachineMock),
|
||||||
|
expectedVmMock: &driver.VirtualMachineMock{
|
||||||
|
FloppyDevicesCalled: true,
|
||||||
|
RemoveDeviceCalled: true,
|
||||||
|
RemoveDeviceKeepFiles: true,
|
||||||
|
},
|
||||||
|
driverMock: &driver.DriverMock{
|
||||||
|
FindDatastoreErr: fmt.Errorf("failed to find datastore"),
|
||||||
|
},
|
||||||
|
expectedDriverMock: &driver.DriverMock{
|
||||||
|
FindDatastoreCalled: true,
|
||||||
|
FindDatastoreName: "datastore",
|
||||||
|
FindDatastoreHost: "host",
|
||||||
|
},
|
||||||
|
dsMock: new(driver.DatastoreMock),
|
||||||
|
expectedDsMock: new(driver.DatastoreMock),
|
||||||
|
fail: true,
|
||||||
|
errMessage: "failed to find datastore",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Fail to delete floppy image",
|
||||||
|
uploadedPath: "vm/dir/packer-tmp-created-floppy.flp",
|
||||||
|
step: &StepRemoveFloppy{
|
||||||
|
Datastore: "datastore",
|
||||||
|
Host: "host",
|
||||||
|
},
|
||||||
|
expectedAction: multistep.ActionHalt,
|
||||||
|
vmMock: new(driver.VirtualMachineMock),
|
||||||
|
expectedVmMock: &driver.VirtualMachineMock{
|
||||||
|
FloppyDevicesCalled: true,
|
||||||
|
RemoveDeviceCalled: true,
|
||||||
|
RemoveDeviceKeepFiles: true,
|
||||||
|
},
|
||||||
|
driverMock: new(driver.DriverMock),
|
||||||
|
expectedDriverMock: &driver.DriverMock{
|
||||||
|
FindDatastoreCalled: true,
|
||||||
|
FindDatastoreName: "datastore",
|
||||||
|
FindDatastoreHost: "host",
|
||||||
|
},
|
||||||
|
dsMock: &driver.DatastoreMock{
|
||||||
|
DeleteErr: fmt.Errorf("failed to delete floppy"),
|
||||||
|
},
|
||||||
|
expectedDsMock: &driver.DatastoreMock{
|
||||||
|
DeleteCalled: true,
|
||||||
|
DeletePath: "vm/dir/packer-tmp-created-floppy.flp",
|
||||||
|
},
|
||||||
|
fail: true,
|
||||||
|
errMessage: "failed to delete floppy",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range tc {
|
||||||
|
t.Run(c.name, func(t *testing.T) {
|
||||||
|
state := basicStateBag(nil)
|
||||||
|
state.Put("vm", c.vmMock)
|
||||||
|
c.driverMock.DatastoreMock = c.dsMock
|
||||||
|
state.Put("driver", c.driverMock)
|
||||||
|
|
||||||
|
if c.uploadedPath != "" {
|
||||||
|
state.Put("uploaded_floppy_path", c.uploadedPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
if action := c.step.Run(context.TODO(), state); action != c.expectedAction {
|
||||||
|
t.Fatalf("unexpected action %v", action)
|
||||||
|
}
|
||||||
|
err, ok := state.Get("error").(error)
|
||||||
|
if ok {
|
||||||
|
if err.Error() != c.errMessage {
|
||||||
|
t.Fatalf("unexpected error %s", err.Error())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if c.fail {
|
||||||
|
t.Fatalf("expected to fail but it didn't")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.fail {
|
||||||
|
if _, ok := state.GetOk("uploaded_floppy_path"); ok {
|
||||||
|
t.Fatalf("uploaded_floppy_path should not be in state")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmp.Diff(c.vmMock, c.expectedVmMock,
|
||||||
|
cmpopts.IgnoreInterfaces(struct{ error }{})); diff != "" {
|
||||||
|
t.Fatalf("unexpected VirtualMachine calls: %s", diff)
|
||||||
|
}
|
||||||
|
c.expectedDriverMock.DatastoreMock = c.expectedDsMock
|
||||||
|
if diff := cmp.Diff(c.driverMock, c.expectedDriverMock,
|
||||||
|
cmpopts.IgnoreInterfaces(struct{ error }{})); diff != "" {
|
||||||
|
t.Fatalf("unexpected Driver calls: %s", diff)
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(c.dsMock, c.expectedDsMock,
|
||||||
|
cmpopts.IgnoreInterfaces(struct{ error }{})); diff != "" {
|
||||||
|
t.Fatalf("unexpected Datastore calls: %s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,7 +8,20 @@ import (
|
||||||
type DatastoreMock struct {
|
type DatastoreMock struct {
|
||||||
FileExistsCalled bool
|
FileExistsCalled bool
|
||||||
MakeDirectoryCalled bool
|
MakeDirectoryCalled bool
|
||||||
|
|
||||||
|
ResolvePathCalled bool
|
||||||
|
ResolvePathReturn string
|
||||||
|
|
||||||
|
DeleteCalled bool
|
||||||
|
DeletePath string
|
||||||
|
DeleteErr error
|
||||||
|
|
||||||
UploadFileCalled bool
|
UploadFileCalled bool
|
||||||
|
UploadFileSrc string
|
||||||
|
UploadFileDst string
|
||||||
|
UploadFileHost string
|
||||||
|
UploadFileSetHost bool
|
||||||
|
UploadFileErr error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ds *DatastoreMock) Info(params ...string) (*mo.Datastore, error) {
|
func (ds *DatastoreMock) Info(params ...string) (*mo.Datastore, error) {
|
||||||
|
@ -29,16 +42,23 @@ func (ds *DatastoreMock) Reference() types.ManagedObjectReference {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ds *DatastoreMock) ResolvePath(path string) string {
|
func (ds *DatastoreMock) ResolvePath(path string) string {
|
||||||
return ""
|
ds.ResolvePathCalled = true
|
||||||
|
return ds.ResolvePathReturn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ds *DatastoreMock) UploadFile(src, dst, host string, setHost bool) error {
|
func (ds *DatastoreMock) UploadFile(src, dst, host string, setHost bool) error {
|
||||||
ds.UploadFileCalled = true
|
ds.UploadFileCalled = true
|
||||||
return nil
|
ds.UploadFileSrc = src
|
||||||
|
ds.UploadFileDst = dst
|
||||||
|
ds.UploadFileHost = host
|
||||||
|
ds.UploadFileSetHost = setHost
|
||||||
|
return ds.UploadFileErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ds *DatastoreMock) Delete(path string) error {
|
func (ds *DatastoreMock) Delete(path string) error {
|
||||||
return nil
|
ds.DeleteCalled = true
|
||||||
|
ds.DeletePath = path
|
||||||
|
return ds.DeleteErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ds *DatastoreMock) MakeDirectory(path string) error {
|
func (ds *DatastoreMock) MakeDirectory(path string) error {
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
package driver
|
package driver
|
||||||
|
|
||||||
import "testing"
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/vmware/govmomi/simulator"
|
||||||
|
)
|
||||||
|
|
||||||
func TestDatastoreIsoPath(t *testing.T) {
|
func TestDatastoreIsoPath(t *testing.T) {
|
||||||
tc := []struct {
|
tc := []struct {
|
||||||
|
@ -87,3 +91,84 @@ func TestDatastoreIsoPath(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVCenterDriver_FindDatastore(t *testing.T) {
|
||||||
|
sim, err := NewVCenterSimulator()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("should not fail: %s", err.Error())
|
||||||
|
}
|
||||||
|
defer sim.Close()
|
||||||
|
|
||||||
|
_, datastore := sim.ChooseSimulatorPreCreatedDatastore()
|
||||||
|
_, host := sim.ChooseSimulatorPreCreatedHost()
|
||||||
|
|
||||||
|
tc := []struct {
|
||||||
|
name string
|
||||||
|
datastore string
|
||||||
|
host string
|
||||||
|
fail bool
|
||||||
|
errMessage string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "should find datastore when name is provided",
|
||||||
|
datastore: datastore.Name,
|
||||||
|
fail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "should find datastore when only host is provided",
|
||||||
|
host: host.Name,
|
||||||
|
fail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "should not find invalid datastore",
|
||||||
|
datastore: "invalid",
|
||||||
|
fail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "should not find invalid host",
|
||||||
|
host: "invalid",
|
||||||
|
fail: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range tc {
|
||||||
|
t.Run(c.name, func(t *testing.T) {
|
||||||
|
ds, err := sim.driver.FindDatastore(c.datastore, c.host)
|
||||||
|
if c.fail {
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected to fail")
|
||||||
|
}
|
||||||
|
if c.errMessage != "" && err.Error() != c.errMessage {
|
||||||
|
t.Fatalf("unexpected error message %s", err.Error())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("should not fail: %s", err.Error())
|
||||||
|
}
|
||||||
|
if ds == nil {
|
||||||
|
t.Fatalf("expected to find datastore")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVCenterDriver_MultipleDatastoreError(t *testing.T) {
|
||||||
|
model := simulator.ESX()
|
||||||
|
model.Datastore = 2
|
||||||
|
sim, err := NewCustomVCenterSimulator(model)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("should not fail: %s", err.Error())
|
||||||
|
}
|
||||||
|
defer sim.Close()
|
||||||
|
|
||||||
|
_, host := sim.ChooseSimulatorPreCreatedHost()
|
||||||
|
|
||||||
|
_, err = sim.driver.FindDatastore("", host.Name)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected to fail")
|
||||||
|
}
|
||||||
|
if err.Error() != "Host has multiple datastores. Specify it explicitly" {
|
||||||
|
t.Fatalf("unexpected error message %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,9 @@ import (
|
||||||
type DriverMock struct {
|
type DriverMock struct {
|
||||||
FindDatastoreCalled bool
|
FindDatastoreCalled bool
|
||||||
DatastoreMock *DatastoreMock
|
DatastoreMock *DatastoreMock
|
||||||
|
FindDatastoreName string
|
||||||
|
FindDatastoreHost string
|
||||||
|
FindDatastoreErr error
|
||||||
|
|
||||||
PreCleanShouldFail bool
|
PreCleanShouldFail bool
|
||||||
PreCleanVMCalled bool
|
PreCleanVMCalled bool
|
||||||
|
@ -32,7 +35,9 @@ func (d *DriverMock) FindDatastore(name string, host string) (Datastore, error)
|
||||||
if d.DatastoreMock == nil {
|
if d.DatastoreMock == nil {
|
||||||
d.DatastoreMock = new(DatastoreMock)
|
d.DatastoreMock = new(DatastoreMock)
|
||||||
}
|
}
|
||||||
return d.DatastoreMock, nil
|
d.FindDatastoreName = name
|
||||||
|
d.FindDatastoreHost = host
|
||||||
|
return d.DatastoreMock, d.FindDatastoreErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DriverMock) NewVM(ref *types.ManagedObjectReference) VirtualMachine {
|
func (d *DriverMock) NewVM(ref *types.ManagedObjectReference) VirtualMachine {
|
||||||
|
|
|
@ -50,24 +50,89 @@ func newVMName() string {
|
||||||
return fmt.Sprintf("test-%v", rand.Intn(1000))
|
return fmt.Sprintf("test-%v", rand.Intn(1000))
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSimulatorServer(model *simulator.Model) (*simulator.Server, error) {
|
type VCenterSimulator struct {
|
||||||
err := model.Create()
|
model *simulator.Model
|
||||||
|
server *simulator.Server
|
||||||
|
driver *VCenterDriver
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCustomVCenterSimulator(model *simulator.Model) (*VCenterSimulator, error) {
|
||||||
|
sim := new(VCenterSimulator)
|
||||||
|
sim.model = model
|
||||||
|
|
||||||
|
server, err := sim.NewSimulatorServer()
|
||||||
|
if err != nil {
|
||||||
|
sim.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sim.server = server
|
||||||
|
|
||||||
|
driver, err := sim.NewSimulatorDriver()
|
||||||
|
if err != nil {
|
||||||
|
sim.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sim.driver = driver
|
||||||
|
return sim, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewVCenterSimulator() (*VCenterSimulator, error) {
|
||||||
|
model := simulator.VPX()
|
||||||
|
model.Machine = 1
|
||||||
|
return NewCustomVCenterSimulator(model)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *VCenterSimulator) Close() {
|
||||||
|
if s.model != nil {
|
||||||
|
s.model.Remove()
|
||||||
|
}
|
||||||
|
if s.server != nil {
|
||||||
|
s.server.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Simulator shortcut to choose any pre created VM.
|
||||||
|
func (s *VCenterSimulator) ChooseSimulatorPreCreatedVM() (VirtualMachine, *simulator.VirtualMachine) {
|
||||||
|
machine := simulator.Map.Any("VirtualMachine").(*simulator.VirtualMachine)
|
||||||
|
ref := machine.Reference()
|
||||||
|
vm := s.driver.NewVM(&ref)
|
||||||
|
return vm, machine
|
||||||
|
}
|
||||||
|
|
||||||
|
//Simulator shortcut to choose any pre created Datastore.
|
||||||
|
func (s *VCenterSimulator) ChooseSimulatorPreCreatedDatastore() (Datastore, *simulator.Datastore) {
|
||||||
|
ds := simulator.Map.Any("Datastore").(*simulator.Datastore)
|
||||||
|
ref := ds.Reference()
|
||||||
|
datastore := s.driver.NewDatastore(&ref)
|
||||||
|
return datastore, ds
|
||||||
|
}
|
||||||
|
|
||||||
|
//Simulator shortcut to choose any pre created Host.
|
||||||
|
func (s *VCenterSimulator) ChooseSimulatorPreCreatedHost() (*Host, *simulator.HostSystem) {
|
||||||
|
h := simulator.Map.Any("HostSystem").(*simulator.HostSystem)
|
||||||
|
ref := h.Reference()
|
||||||
|
host := s.driver.NewHost(&ref)
|
||||||
|
return host, h
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *VCenterSimulator) NewSimulatorServer() (*simulator.Server, error) {
|
||||||
|
err := s.model.Create()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
model.Service.RegisterEndpoints = true
|
s.model.Service.RegisterEndpoints = true
|
||||||
model.Service.TLS = new(tls.Config)
|
s.model.Service.TLS = new(tls.Config)
|
||||||
model.Service.ServeMux = http.NewServeMux()
|
s.model.Service.ServeMux = http.NewServeMux()
|
||||||
return model.Service.NewServer(), nil
|
return s.model.Service.NewServer(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSimulatorDriver(s *simulator.Server) (*VCenterDriver, error) {
|
func (s *VCenterSimulator) NewSimulatorDriver() (*VCenterDriver, error) {
|
||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
user := &url.Userinfo{}
|
user := &url.Userinfo{}
|
||||||
s.URL.User = user
|
s.server.URL.User = user
|
||||||
|
|
||||||
soapClient := soap.NewClient(s.URL, true)
|
soapClient := soap.NewClient(s.server.URL, true)
|
||||||
vimClient, err := vim25.NewClient(ctx, soapClient)
|
vimClient, err := vim25.NewClient(ctx, soapClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -104,11 +169,3 @@ func NewSimulatorDriver(s *simulator.Server) (*VCenterDriver, error) {
|
||||||
}
|
}
|
||||||
return d, nil
|
return d, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//Simulator shortcut to choose any pre created VM.
|
|
||||||
func ChooseSimulatorPreCreatedVM(driverSim *VCenterDriver) VirtualMachine {
|
|
||||||
machine := simulator.Map.Any("VirtualMachine").(*simulator.VirtualMachine)
|
|
||||||
ref := machine.Reference()
|
|
||||||
vm := driverSim.NewVM(&ref)
|
|
||||||
return vm
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,21 +7,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestVCenterDriver_FindResourcePool(t *testing.T) {
|
func TestVCenterDriver_FindResourcePool(t *testing.T) {
|
||||||
model := simulator.VPX()
|
sim, err := NewVCenterSimulator()
|
||||||
defer model.Remove()
|
|
||||||
|
|
||||||
s, err := NewSimulatorServer(model)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("should not fail: %s", err.Error())
|
t.Fatalf("should not fail: %s", err.Error())
|
||||||
}
|
}
|
||||||
defer s.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
driverSim, err := NewSimulatorDriver(s)
|
res, err := sim.driver.FindResourcePool("", "DC0_H0", "")
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("should not fail: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := driverSim.FindResourcePool("", "DC0_H0", "")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("should not fail: %s", err.Error())
|
t.Fatalf("should not fail: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
@ -47,19 +39,13 @@ func TestVCenterDriver_FindResourcePoolStandaloneESX(t *testing.T) {
|
||||||
model.DelayConfig.MethodDelay = opts.DelayConfig.MethodDelay
|
model.DelayConfig.MethodDelay = opts.DelayConfig.MethodDelay
|
||||||
model.DelayConfig.DelayJitter = opts.DelayConfig.DelayJitter
|
model.DelayConfig.DelayJitter = opts.DelayConfig.DelayJitter
|
||||||
|
|
||||||
s, err := NewSimulatorServer(model)
|
sim, err := NewCustomVCenterSimulator(model)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("should not fail: %s", err.Error())
|
t.Fatalf("should not fail: %s", err.Error())
|
||||||
}
|
}
|
||||||
defer s.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
driverSim, err := NewSimulatorDriver(s)
|
res, err := sim.driver.FindResourcePool("", "localhost.localdomain", "")
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("should not fail: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
res, err := driverSim.FindResourcePool("", "localhost.localdomain", "")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("should not fail: %s", err.Error())
|
t.Fatalf("should not fail: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
@ -72,7 +58,7 @@ func TestVCenterDriver_FindResourcePoolStandaloneESX(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invalid resource name should look for default resource pool
|
// Invalid resource name should look for default resource pool
|
||||||
res, err = driverSim.FindResourcePool("", "localhost.localdomain", "invalid")
|
res, err = sim.driver.FindResourcePool("", "localhost.localdomain", "invalid")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("should not fail: %s", err.Error())
|
t.Fatalf("should not fail: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import (
|
||||||
type VirtualMachine interface {
|
type VirtualMachine interface {
|
||||||
Info(params ...string) (*mo.VirtualMachine, error)
|
Info(params ...string) (*mo.VirtualMachine, error)
|
||||||
Devices() (object.VirtualDeviceList, error)
|
Devices() (object.VirtualDeviceList, error)
|
||||||
|
FloppyDevices() (object.VirtualDeviceList, error)
|
||||||
Clone(ctx context.Context, config *CloneConfig) (VirtualMachine, error)
|
Clone(ctx context.Context, config *CloneConfig) (VirtualMachine, error)
|
||||||
updateVAppConfig(ctx context.Context, newProps map[string]string) (*types.VmConfigSpec, error)
|
updateVAppConfig(ctx context.Context, newProps map[string]string) (*types.VmConfigSpec, error)
|
||||||
AddPublicKeys(ctx context.Context, publicKeys string) error
|
AddPublicKeys(ctx context.Context, publicKeys string) error
|
||||||
|
@ -284,6 +285,15 @@ func (vm *VirtualMachineDriver) Devices() (object.VirtualDeviceList, error) {
|
||||||
return vmInfo.Config.Hardware.Device, nil
|
return vmInfo.Config.Hardware.Device, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (vm *VirtualMachineDriver) FloppyDevices() (object.VirtualDeviceList, error) {
|
||||||
|
device, err := vm.Devices()
|
||||||
|
if err != nil {
|
||||||
|
return device, err
|
||||||
|
}
|
||||||
|
floppies := device.SelectByType((*types.VirtualFloppy)(nil))
|
||||||
|
return floppies, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (vm *VirtualMachineDriver) Clone(ctx context.Context, config *CloneConfig) (VirtualMachine, error) {
|
func (vm *VirtualMachineDriver) Clone(ctx context.Context, config *CloneConfig) (VirtualMachine, error) {
|
||||||
folder, err := vm.driver.FindFolder(config.Folder)
|
folder, err := vm.driver.FindFolder(config.Folder)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -5,27 +5,17 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/vmware/govmomi/simulator"
|
|
||||||
"github.com/vmware/govmomi/vim25/types"
|
"github.com/vmware/govmomi/vim25/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestVirtualMachineDriver_FindAndAddSATAController(t *testing.T) {
|
func TestVirtualMachineDriver_FindAndAddSATAController(t *testing.T) {
|
||||||
model := simulator.VPX()
|
sim, err := NewVCenterSimulator()
|
||||||
model.Machine = 1
|
|
||||||
defer model.Remove()
|
|
||||||
|
|
||||||
s, err := NewSimulatorServer(model)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("should not fail: %s", err.Error())
|
t.Fatalf("should not fail: %s", err.Error())
|
||||||
}
|
}
|
||||||
defer s.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
driverSim, err := NewSimulatorDriver(s)
|
vm, _ := sim.ChooseSimulatorPreCreatedVM()
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("should not fail: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
vm := ChooseSimulatorPreCreatedVM(driverSim)
|
|
||||||
|
|
||||||
_, err = vm.FindSATAController()
|
_, err = vm.FindSATAController()
|
||||||
if err != nil && !strings.Contains(err.Error(), "no available SATA controller") {
|
if err != nil && !strings.Contains(err.Error(), "no available SATA controller") {
|
||||||
|
@ -49,23 +39,13 @@ func TestVirtualMachineDriver_FindAndAddSATAController(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVirtualMachineDriver_CreateAndRemoveCdrom(t *testing.T) {
|
func TestVirtualMachineDriver_CreateAndRemoveCdrom(t *testing.T) {
|
||||||
model := simulator.VPX()
|
sim, err := NewVCenterSimulator()
|
||||||
model.Machine = 1
|
|
||||||
defer model.Remove()
|
|
||||||
|
|
||||||
s, err := NewSimulatorServer(model)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("should not fail: %s", err.Error())
|
t.Fatalf("should not fail: %s", err.Error())
|
||||||
}
|
}
|
||||||
defer s.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
driverSim, err := NewSimulatorDriver(s)
|
vm, _ := sim.ChooseSimulatorPreCreatedVM()
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("should not fail: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
//Simulator shortcut to choose any pre created VM.
|
|
||||||
vm := ChooseSimulatorPreCreatedVM(driverSim)
|
|
||||||
|
|
||||||
// Add SATA Controller
|
// Add SATA Controller
|
||||||
if err := vm.AddSATAController(); err != nil {
|
if err := vm.AddSATAController(); err != nil {
|
||||||
|
@ -118,23 +98,13 @@ func TestVirtualMachineDriver_CreateAndRemoveCdrom(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVirtualMachineDriver_EjectCdrom(t *testing.T) {
|
func TestVirtualMachineDriver_EjectCdrom(t *testing.T) {
|
||||||
model := simulator.VPX()
|
sim, err := NewVCenterSimulator()
|
||||||
model.Machine = 1
|
|
||||||
defer model.Remove()
|
|
||||||
|
|
||||||
s, err := NewSimulatorServer(model)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("should not fail: %s", err.Error())
|
t.Fatalf("should not fail: %s", err.Error())
|
||||||
}
|
}
|
||||||
defer s.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
driverSim, err := NewSimulatorDriver(s)
|
vm, _ := sim.ChooseSimulatorPreCreatedVM()
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("should not fail: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
//Simulator shortcut to choose any pre created VM.
|
|
||||||
vm := ChooseSimulatorPreCreatedVM(driverSim)
|
|
||||||
|
|
||||||
// Add SATA Controller
|
// Add SATA Controller
|
||||||
if err := vm.AddSATAController(); err != nil {
|
if err := vm.AddSATAController(); err != nil {
|
||||||
|
|
|
@ -32,6 +32,29 @@ type VirtualMachineMock struct {
|
||||||
AddCdromErr error
|
AddCdromErr error
|
||||||
AddCdromTypes []string
|
AddCdromTypes []string
|
||||||
AddCdromPaths []string
|
AddCdromPaths []string
|
||||||
|
|
||||||
|
GetDirCalled bool
|
||||||
|
GetDirResponse string
|
||||||
|
GetDirErr error
|
||||||
|
|
||||||
|
AddFloppyCalled bool
|
||||||
|
AddFloppyImagePath string
|
||||||
|
AddFloppyErr error
|
||||||
|
|
||||||
|
FloppyDevicesErr error
|
||||||
|
FloppyDevicesReturn object.VirtualDeviceList
|
||||||
|
FloppyDevicesCalled bool
|
||||||
|
|
||||||
|
RemoveDeviceErr error
|
||||||
|
RemoveDeviceCalled bool
|
||||||
|
RemoveDeviceKeepFiles bool
|
||||||
|
RemoveDeviceDevices []types.BaseVirtualDevice
|
||||||
|
|
||||||
|
EjectCdromsCalled bool
|
||||||
|
EjectCdromsErr error
|
||||||
|
|
||||||
|
RemoveCdromsCalled bool
|
||||||
|
RemoveCdromsErr error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vm *VirtualMachineMock) Info(params ...string) (*mo.VirtualMachine, error) {
|
func (vm *VirtualMachineMock) Info(params ...string) (*mo.VirtualMachine, error) {
|
||||||
|
@ -42,6 +65,11 @@ func (vm *VirtualMachineMock) Devices() (object.VirtualDeviceList, error) {
|
||||||
return object.VirtualDeviceList{}, nil
|
return object.VirtualDeviceList{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (vm *VirtualMachineMock) FloppyDevices() (object.VirtualDeviceList, error) {
|
||||||
|
vm.FloppyDevicesCalled = true
|
||||||
|
return vm.FloppyDevicesReturn, vm.FloppyDevicesErr
|
||||||
|
}
|
||||||
|
|
||||||
func (vm *VirtualMachineMock) Clone(ctx context.Context, config *CloneConfig) (VirtualMachine, error) {
|
func (vm *VirtualMachineMock) Clone(ctx context.Context, config *CloneConfig) (VirtualMachine, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -124,7 +152,8 @@ func (vm *VirtualMachineMock) ImportToContentLibrary(template vcenter.Template)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vm *VirtualMachineMock) GetDir() (string, error) {
|
func (vm *VirtualMachineMock) GetDir() (string, error) {
|
||||||
return "", nil
|
vm.GetDirCalled = true
|
||||||
|
return vm.GetDirResponse, vm.GetDirErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vm *VirtualMachineMock) AddCdrom(cdromType string, isoPath string) error {
|
func (vm *VirtualMachineMock) AddCdrom(cdromType string, isoPath string) error {
|
||||||
|
@ -136,7 +165,9 @@ func (vm *VirtualMachineMock) AddCdrom(cdromType string, isoPath string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vm *VirtualMachineMock) AddFloppy(imgPath string) error {
|
func (vm *VirtualMachineMock) AddFloppy(imgPath string) error {
|
||||||
return nil
|
vm.AddFloppyCalled = true
|
||||||
|
vm.AddFloppyImagePath = imgPath
|
||||||
|
return vm.AddFloppyErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vm *VirtualMachineMock) SetBootOrder(order []string) error {
|
func (vm *VirtualMachineMock) SetBootOrder(order []string) error {
|
||||||
|
@ -144,7 +175,10 @@ func (vm *VirtualMachineMock) SetBootOrder(order []string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vm *VirtualMachineMock) RemoveDevice(keepFiles bool, device ...types.BaseVirtualDevice) error {
|
func (vm *VirtualMachineMock) RemoveDevice(keepFiles bool, device ...types.BaseVirtualDevice) error {
|
||||||
return nil
|
vm.RemoveDeviceCalled = true
|
||||||
|
vm.RemoveDeviceKeepFiles = keepFiles
|
||||||
|
vm.RemoveDeviceDevices = device
|
||||||
|
return vm.RemoveDeviceErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vm *VirtualMachineMock) addDevice(device types.BaseVirtualDevice) error {
|
func (vm *VirtualMachineMock) addDevice(device types.BaseVirtualDevice) error {
|
||||||
|
@ -186,9 +220,11 @@ func (vm *VirtualMachineMock) CreateCdrom(c *types.VirtualController) (*types.Vi
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vm *VirtualMachineMock) RemoveCdroms() error {
|
func (vm *VirtualMachineMock) RemoveCdroms() error {
|
||||||
return nil
|
vm.RemoveCdromsCalled = true
|
||||||
|
return vm.RemoveCdromsErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vm *VirtualMachineMock) EjectCdroms() error {
|
func (vm *VirtualMachineMock) EjectCdroms() error {
|
||||||
return nil
|
vm.EjectCdromsCalled = true
|
||||||
|
return vm.EjectCdromsErr
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,25 +28,13 @@ func (vm *ReconfigureFail) ReconfigVMTask(req *types.ReconfigVM_Task) soap.HasFa
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVirtualMachineDriver_Configure(t *testing.T) {
|
func TestVirtualMachineDriver_Configure(t *testing.T) {
|
||||||
model := simulator.VPX()
|
sim, err := NewVCenterSimulator()
|
||||||
model.Machine = 1
|
|
||||||
defer model.Remove()
|
|
||||||
|
|
||||||
s, err := NewSimulatorServer(model)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("should not fail: %s", err.Error())
|
t.Fatalf("should not fail: %s", err.Error())
|
||||||
}
|
}
|
||||||
defer s.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
driverSim, err := NewSimulatorDriver(s)
|
vm, machine := sim.ChooseSimulatorPreCreatedVM()
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("should not fail: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
//Simulator shortcut to choose any pre created VM.
|
|
||||||
machine := simulator.Map.Any("VirtualMachine").(*simulator.VirtualMachine)
|
|
||||||
ref := machine.Reference()
|
|
||||||
vm := driverSim.NewVM(&ref)
|
|
||||||
|
|
||||||
// Happy test
|
// Happy test
|
||||||
hardwareConfig := &HardwareConfig{
|
hardwareConfig := &HardwareConfig{
|
||||||
|
|
|
@ -52,7 +52,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||||
Files: b.config.CDConfig.CDFiles,
|
Files: b.config.CDConfig.CDFiles,
|
||||||
Label: b.config.CDConfig.CDLabel,
|
Label: b.config.CDConfig.CDLabel,
|
||||||
},
|
},
|
||||||
&StepRemoteUpload{
|
&common.StepRemoteUpload{
|
||||||
Datastore: b.config.Datastore,
|
Datastore: b.config.Datastore,
|
||||||
Host: b.config.Host,
|
Host: b.config.Host,
|
||||||
SetHostForDatastoreUploads: b.config.SetHostForDatastoreUploads,
|
SetHostForDatastoreUploads: b.config.SetHostForDatastoreUploads,
|
||||||
|
@ -65,7 +65,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||||
&common.StepConfigureHardware{
|
&common.StepConfigureHardware{
|
||||||
Config: &b.config.HardwareConfig,
|
Config: &b.config.HardwareConfig,
|
||||||
},
|
},
|
||||||
&StepAddCDRom{
|
&common.StepAddCDRom{
|
||||||
Config: &b.config.CDRomConfig,
|
Config: &b.config.CDRomConfig,
|
||||||
},
|
},
|
||||||
&common.StepConfigParams{
|
&common.StepConfigParams{
|
||||||
|
@ -80,7 +80,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||||
Directories: b.config.FloppyDirectories,
|
Directories: b.config.FloppyDirectories,
|
||||||
Label: b.config.FloppyLabel,
|
Label: b.config.FloppyLabel,
|
||||||
},
|
},
|
||||||
&StepAddFloppy{
|
&common.StepAddFloppy{
|
||||||
Config: &b.config.FloppyConfig,
|
Config: &b.config.FloppyConfig,
|
||||||
Datastore: b.config.Datastore,
|
Datastore: b.config.Datastore,
|
||||||
Host: b.config.Host,
|
Host: b.config.Host,
|
||||||
|
@ -117,7 +117,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||||
&common.StepShutdown{
|
&common.StepShutdown{
|
||||||
Config: &b.config.ShutdownConfig,
|
Config: &b.config.ShutdownConfig,
|
||||||
},
|
},
|
||||||
&StepRemoveFloppy{
|
&common.StepRemoveFloppy{
|
||||||
Datastore: b.config.Datastore,
|
Datastore: b.config.Datastore,
|
||||||
Host: b.config.Host,
|
Host: b.config.Host,
|
||||||
},
|
},
|
||||||
|
@ -125,7 +125,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||||
}
|
}
|
||||||
|
|
||||||
steps = append(steps,
|
steps = append(steps,
|
||||||
&StepRemoveCDRom{
|
&common.StepRemoveCDRom{
|
||||||
Config: &b.config.RemoveCDRomConfig,
|
Config: &b.config.RemoveCDRomConfig,
|
||||||
},
|
},
|
||||||
&common.StepCreateSnapshot{
|
&common.StepCreateSnapshot{
|
||||||
|
|
|
@ -25,9 +25,9 @@ type Config struct {
|
||||||
|
|
||||||
packerCommon.ISOConfig `mapstructure:",squash"`
|
packerCommon.ISOConfig `mapstructure:",squash"`
|
||||||
|
|
||||||
CDRomConfig `mapstructure:",squash"`
|
common.CDRomConfig `mapstructure:",squash"`
|
||||||
RemoveCDRomConfig `mapstructure:",squash"`
|
common.RemoveCDRomConfig `mapstructure:",squash"`
|
||||||
FloppyConfig `mapstructure:",squash"`
|
common.FloppyConfig `mapstructure:",squash"`
|
||||||
common.RunConfig `mapstructure:",squash"`
|
common.RunConfig `mapstructure:",squash"`
|
||||||
common.BootConfig `mapstructure:",squash"`
|
common.BootConfig `mapstructure:",squash"`
|
||||||
common.WaitIpConfig `mapstructure:",squash"`
|
common.WaitIpConfig `mapstructure:",squash"`
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/packer/helper/builder/localexec"
|
"github.com/hashicorp/packer/helper/builder/localexec"
|
||||||
|
@ -167,12 +168,34 @@ var supportedCDISOCreationCommands []cdISOCreationCommand = []cdISOCreationComma
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isCygwinExecutable(path string) bool {
|
||||||
|
return runtime.GOOS == "windows" && strings.Contains(path, "\\usr\\bin\\")
|
||||||
|
}
|
||||||
|
|
||||||
|
func toCygwinPath(path string) (string, error) {
|
||||||
|
c := exec.Command("cygpath", path)
|
||||||
|
cygwinPath, err := c.Output()
|
||||||
|
return strings.TrimSpace(string(cygwinPath)), err
|
||||||
|
}
|
||||||
|
|
||||||
func retrieveCDISOCreationCommand(label string, source string, dest string) (*exec.Cmd, error) {
|
func retrieveCDISOCreationCommand(label string, source string, dest string) (*exec.Cmd, error) {
|
||||||
for _, c := range supportedCDISOCreationCommands {
|
for _, c := range supportedCDISOCreationCommands {
|
||||||
path, err := exec.LookPath(c.Name)
|
path, err := exec.LookPath(c.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
// if we are running a cygwin/msys2 executable we must convert the
|
||||||
|
// native win32 path to a cygwin/msys2/unix style path.
|
||||||
|
if isCygwinExecutable(path) {
|
||||||
|
source, err = toCygwinPath(source)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dest, err = toCygwinPath(dest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
return c.Command(path, label, source, dest), nil
|
return c.Command(path, label, source, dest), nil
|
||||||
}
|
}
|
||||||
var commands = make([]string, 0, len(supportedCDISOCreationCommands))
|
var commands = make([]string, 0, len(supportedCDISOCreationCommands))
|
||||||
|
|
|
@ -245,6 +245,7 @@ func TestStepDownload_download(t *testing.T) {
|
||||||
ui := &packer.BasicUi{
|
ui := &packer.BasicUi{
|
||||||
Reader: new(bytes.Buffer),
|
Reader: new(bytes.Buffer),
|
||||||
Writer: new(bytes.Buffer),
|
Writer: new(bytes.Buffer),
|
||||||
|
PB: &packer.NoopProgressTracker{},
|
||||||
}
|
}
|
||||||
|
|
||||||
dir := createTempDir(t)
|
dir := createTempDir(t)
|
||||||
|
|
|
@ -16,6 +16,7 @@ func testState(t *testing.T) multistep.StateBag {
|
||||||
state.Put("ui", &packer.BasicUi{
|
state.Put("ui", &packer.BasicUi{
|
||||||
Reader: new(bytes.Buffer),
|
Reader: new(bytes.Buffer),
|
||||||
Writer: new(bytes.Buffer),
|
Writer: new(bytes.Buffer),
|
||||||
|
PB: &packer.NoopProgressTracker{},
|
||||||
})
|
})
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
9
go.mod
9
go.mod
|
@ -22,7 +22,7 @@ require (
|
||||||
github.com/antchfx/xquery v0.0.0-20170730121040-eb8c3c172607 // indirect
|
github.com/antchfx/xquery v0.0.0-20170730121040-eb8c3c172607 // indirect
|
||||||
github.com/approvals/go-approval-tests v0.0.0-20160714161514-ad96e53bea43
|
github.com/approvals/go-approval-tests v0.0.0-20160714161514-ad96e53bea43
|
||||||
github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 // indirect
|
github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 // indirect
|
||||||
github.com/aws/aws-sdk-go v1.30.8
|
github.com/aws/aws-sdk-go v1.34.26
|
||||||
github.com/biogo/hts v0.0.0-20160420073057-50da7d4131a3
|
github.com/biogo/hts v0.0.0-20160420073057-50da7d4131a3
|
||||||
github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee
|
github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee
|
||||||
github.com/cheggaaa/pb v1.0.27
|
github.com/cheggaaa/pb v1.0.27
|
||||||
|
@ -40,9 +40,6 @@ require (
|
||||||
github.com/go-ole/go-ole v1.2.4 // indirect
|
github.com/go-ole/go-ole v1.2.4 // indirect
|
||||||
github.com/go-resty/resty/v2 v2.3.0
|
github.com/go-resty/resty/v2 v2.3.0
|
||||||
github.com/gobwas/glob v0.2.3
|
github.com/gobwas/glob v0.2.3
|
||||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee // indirect
|
|
||||||
github.com/gobwas/pool v0.2.1 // indirect
|
|
||||||
github.com/gobwas/ws v1.0.4 // indirect
|
|
||||||
github.com/gofrs/flock v0.7.3
|
github.com/gofrs/flock v0.7.3
|
||||||
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3
|
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3
|
||||||
github.com/golang/protobuf v1.4.2 // indirect
|
github.com/golang/protobuf v1.4.2 // indirect
|
||||||
|
@ -53,14 +50,14 @@ require (
|
||||||
github.com/gophercloud/gophercloud v0.12.0
|
github.com/gophercloud/gophercloud v0.12.0
|
||||||
github.com/gophercloud/utils v0.0.0-20200508015959-b0167b94122c
|
github.com/gophercloud/utils v0.0.0-20200508015959-b0167b94122c
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect
|
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect
|
||||||
github.com/gorilla/websocket v0.0.0-20170319172727-a91eba7f9777 // indirect
|
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0
|
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0
|
||||||
github.com/hako/durafmt v0.0.0-20200710122514-c0fb7b4da026
|
github.com/hako/durafmt v0.0.0-20200710122514-c0fb7b4da026
|
||||||
|
github.com/hashicorp/aws-sdk-go-base v0.6.0
|
||||||
github.com/hashicorp/consul/api v1.4.0
|
github.com/hashicorp/consul/api v1.4.0
|
||||||
github.com/hashicorp/errwrap v1.0.0
|
github.com/hashicorp/errwrap v1.0.0
|
||||||
github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de
|
github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.1
|
github.com/hashicorp/go-cleanhttp v0.5.1
|
||||||
github.com/hashicorp/go-cty-funcs v0.0.0-20200520133146-0d04eb807361
|
github.com/hashicorp/go-cty-funcs v0.0.0-20200930094925-2721b1e36840
|
||||||
github.com/hashicorp/go-getter/gcs/v2 v2.0.0-20200604122502-a6995fa1edad
|
github.com/hashicorp/go-getter/gcs/v2 v2.0.0-20200604122502-a6995fa1edad
|
||||||
github.com/hashicorp/go-getter/s3/v2 v2.0.0-20200604122502-a6995fa1edad
|
github.com/hashicorp/go-getter/s3/v2 v2.0.0-20200604122502-a6995fa1edad
|
||||||
github.com/hashicorp/go-getter/v2 v2.0.0-20200604122502-a6995fa1edad
|
github.com/hashicorp/go-getter/v2 v2.0.0-20200604122502-a6995fa1edad
|
||||||
|
|
52
go.sum
52
go.sum
|
@ -129,6 +129,9 @@ github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3A
|
||||||
github.com/aws/aws-sdk-go v1.16.22/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
github.com/aws/aws-sdk-go v1.16.22/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||||
github.com/aws/aws-sdk-go v1.30.8 h1:4BHbh8K3qKmcnAgToZ2LShldRF9inoqIBccpCLNCy3I=
|
github.com/aws/aws-sdk-go v1.30.8 h1:4BHbh8K3qKmcnAgToZ2LShldRF9inoqIBccpCLNCy3I=
|
||||||
github.com/aws/aws-sdk-go v1.30.8/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
github.com/aws/aws-sdk-go v1.30.8/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||||
|
github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||||
|
github.com/aws/aws-sdk-go v1.34.26 h1:tw4nsSfGvCDnXt2xPe8NkxIrDui+asAWinMknPLEf80=
|
||||||
|
github.com/aws/aws-sdk-go v1.34.26/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
|
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
|
||||||
|
@ -172,8 +175,6 @@ github.com/digitalocean/godo v1.11.1 h1:OsTh37YFKk+g6DnAOrkXJ9oDArTkRx5UTkBJ2EWA
|
||||||
github.com/digitalocean/godo v1.11.1/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU=
|
github.com/digitalocean/godo v1.11.1/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU=
|
||||||
github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4=
|
github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4=
|
||||||
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
|
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
|
||||||
github.com/diskfs/go-diskfs v1.1.1 h1:rMjLpaydtXGVZb7mdkRGK1+//30i76nKAit89zUzeaI=
|
|
||||||
github.com/diskfs/go-diskfs v1.1.1/go.mod h1:afUPxxu+x1snp4aCY2bKR0CoZ/YFJewV3X2UEr2nPZE=
|
|
||||||
github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY=
|
github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY=
|
||||||
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
||||||
github.com/dylanmei/iso8601 v0.1.0 h1:812NGQDBcqquTfH5Yeo7lwR0nzx/cKdsmf3qMjPURUI=
|
github.com/dylanmei/iso8601 v0.1.0 h1:812NGQDBcqquTfH5Yeo7lwR0nzx/cKdsmf3qMjPURUI=
|
||||||
|
@ -217,12 +218,6 @@ github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
|
||||||
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
|
|
||||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
|
||||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
|
||||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
|
||||||
github.com/gobwas/ws v1.0.4 h1:5eXU1CZhpQdq5kXbKb+sECH5Ia5KiO6CYzIzdlVx6Bs=
|
|
||||||
github.com/gobwas/ws v1.0.4/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
|
||||||
github.com/gofrs/flock v0.7.3 h1:I0EKY9l8HZCXTMYC4F80vwT6KNypV9uYKP3Alm/hjmQ=
|
github.com/gofrs/flock v0.7.3 h1:I0EKY9l8HZCXTMYC4F80vwT6KNypV9uYKP3Alm/hjmQ=
|
||||||
github.com/gofrs/flock v0.7.3/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
github.com/gofrs/flock v0.7.3/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||||
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
|
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
|
||||||
|
@ -288,6 +283,7 @@ github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASu
|
||||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
|
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
|
github.com/google/martian/v3 v3.0.0 h1:pMen7vLs8nvgEYhywH3KDWJIJTeEr2ULsVWHWYHQyBs=
|
||||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
@ -313,12 +309,12 @@ github.com/gophercloud/utils v0.0.0-20200508015959-b0167b94122c h1:iawx2ojEQA7c+
|
||||||
github.com/gophercloud/utils v0.0.0-20200508015959-b0167b94122c/go.mod h1:ehWUbLQJPqS0Ep+CxeD559hsm9pthPXadJNKwZkp43w=
|
github.com/gophercloud/utils v0.0.0-20200508015959-b0167b94122c/go.mod h1:ehWUbLQJPqS0Ep+CxeD559hsm9pthPXadJNKwZkp43w=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg=
|
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gorilla/websocket v0.0.0-20170319172727-a91eba7f9777 h1:JIM+OacoOJRU30xpjMf8sulYqjr0ViA3WDrTX6j/yDI=
|
|
||||||
github.com/gorilla/websocket v0.0.0-20170319172727-a91eba7f9777/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 h1:THDBEeQ9xZ8JEaCLyLQqXMMdRqNr0QAUJTIkQAUtFjg=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 h1:THDBEeQ9xZ8JEaCLyLQqXMMdRqNr0QAUJTIkQAUtFjg=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE=
|
||||||
github.com/hako/durafmt v0.0.0-20200710122514-c0fb7b4da026 h1:BpJ2o0OR5FV7vrkDYfXYVJQeMNWa8RhklZOpW2ITAIQ=
|
github.com/hako/durafmt v0.0.0-20200710122514-c0fb7b4da026 h1:BpJ2o0OR5FV7vrkDYfXYVJQeMNWa8RhklZOpW2ITAIQ=
|
||||||
github.com/hako/durafmt v0.0.0-20200710122514-c0fb7b4da026/go.mod h1:5Scbynm8dF1XAPwIwkGPqzkM/shndPm79Jd1003hTjE=
|
github.com/hako/durafmt v0.0.0-20200710122514-c0fb7b4da026/go.mod h1:5Scbynm8dF1XAPwIwkGPqzkM/shndPm79Jd1003hTjE=
|
||||||
|
github.com/hashicorp/aws-sdk-go-base v0.6.0 h1:qmUbzM36msbBF59YctwuO5w0M2oNXjlilgKpnEhx1uw=
|
||||||
|
github.com/hashicorp/aws-sdk-go-base v0.6.0/go.mod h1:2fRjWDv3jJBeN6mVWFHV6hFTNeFBx2gpDLQaZNxUVAY=
|
||||||
github.com/hashicorp/consul/api v1.4.0 h1:jfESivXnO5uLdH650JU/6AnjRoHrLhULq0FnC3Kp9EY=
|
github.com/hashicorp/consul/api v1.4.0 h1:jfESivXnO5uLdH650JU/6AnjRoHrLhULq0FnC3Kp9EY=
|
||||||
github.com/hashicorp/consul/api v1.4.0/go.mod h1:xc8u05kyMa3Wjr9eEAsIAo3dg8+LywT5E/Cl7cNS5nU=
|
github.com/hashicorp/consul/api v1.4.0/go.mod h1:xc8u05kyMa3Wjr9eEAsIAo3dg8+LywT5E/Cl7cNS5nU=
|
||||||
github.com/hashicorp/consul/sdk v0.4.0 h1:zBtCfKJZcJDBvSCkQJch4ulp59m1rATFLKwNo/LYY30=
|
github.com/hashicorp/consul/sdk v0.4.0 h1:zBtCfKJZcJDBvSCkQJch4ulp59m1rATFLKwNo/LYY30=
|
||||||
|
@ -331,8 +327,8 @@ github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6K
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
|
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||||
github.com/hashicorp/go-cty-funcs v0.0.0-20200520133146-0d04eb807361 h1:qFuR7ZaMDC5xelTZeNwsJ90I4+4km7ACDdAP+2w84xI=
|
github.com/hashicorp/go-cty-funcs v0.0.0-20200930094925-2721b1e36840 h1:kgvybwEeu0SXktbB2y3uLHX9lklLo+nzUwh59A3jzQc=
|
||||||
github.com/hashicorp/go-cty-funcs v0.0.0-20200520133146-0d04eb807361/go.mod h1:Abjk0jbRkDaNCzsRhOv2iDCofYpX1eVsjozoiK63qLA=
|
github.com/hashicorp/go-cty-funcs v0.0.0-20200930094925-2721b1e36840/go.mod h1:Abjk0jbRkDaNCzsRhOv2iDCofYpX1eVsjozoiK63qLA=
|
||||||
github.com/hashicorp/go-getter v1.4.1 h1:3A2Mh8smGFcf5M+gmcv898mZdrxpseik45IpcyISLsA=
|
github.com/hashicorp/go-getter v1.4.1 h1:3A2Mh8smGFcf5M+gmcv898mZdrxpseik45IpcyISLsA=
|
||||||
github.com/hashicorp/go-getter v1.4.1/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY=
|
github.com/hashicorp/go-getter v1.4.1/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY=
|
||||||
github.com/hashicorp/go-getter/gcs/v2 v2.0.0-20200604122502-a6995fa1edad h1:QPLyAkuTS5Uf9uqJQxCTDDFgmD+gVAzSvqkGb3h+7oQ=
|
github.com/hashicorp/go-getter/gcs/v2 v2.0.0-20200604122502-a6995fa1edad h1:QPLyAkuTS5Uf9uqJQxCTDDFgmD+gVAzSvqkGb3h+7oQ=
|
||||||
|
@ -380,7 +376,6 @@ github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1
|
||||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
|
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
|
||||||
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
|
||||||
github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0=
|
github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0=
|
||||||
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E=
|
github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E=
|
||||||
|
@ -517,8 +512,6 @@ github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZX
|
||||||
github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
|
github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
|
||||||
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||||
github.com/mitchellh/gox v1.0.1 h1:x0jD3dcHk9a9xPSDN6YEL4xL6Qz0dvNYm8yZqui5chI=
|
|
||||||
github.com/mitchellh/gox v1.0.1/go.mod h1:ED6BioOGXMswlXa2zxfh/xdd5QhwYliBFn9V18Ap4z4=
|
|
||||||
github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY=
|
github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY=
|
||||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
@ -619,14 +612,6 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/sylviamoss/go-vnc v0.0.0-20200908143403-27ce26f2bed9 h1:uEIT4Mi8C8O+S44150F3lug+WaZ01aJ0sLHvN4npMsc=
|
|
||||||
github.com/sylviamoss/go-vnc v0.0.0-20200908143403-27ce26f2bed9/go.mod h1:+I9wdVxvb9OqA4vpPvYoLvAeSx+Ew5PF6SiOWekjkGE=
|
|
||||||
github.com/sylviamoss/go-vnc v0.0.0-20200908143844-452d6786ec66 h1:4pQ2Ex/3Fxn7WDvpa85XqHLkc+cSoceIefX/8mD518o=
|
|
||||||
github.com/sylviamoss/go-vnc v0.0.0-20200908143844-452d6786ec66/go.mod h1:+I9wdVxvb9OqA4vpPvYoLvAeSx+Ew5PF6SiOWekjkGE=
|
|
||||||
github.com/sylviamoss/go-vnc v0.0.0-20200908144818-694f171108bf h1:HUHmcnxuPAJktJM1acw5AckmPvOWz/BoenBLB+IMuo0=
|
|
||||||
github.com/sylviamoss/go-vnc v0.0.0-20200908144818-694f171108bf/go.mod h1:+I9wdVxvb9OqA4vpPvYoLvAeSx+Ew5PF6SiOWekjkGE=
|
|
||||||
github.com/sylviamoss/go-vnc v0.0.0-20200908145922-2061e37ffa00 h1:mURYI59JxRHmjEKY4ZZING6qm6e/R91tUqdwFmHoAjY=
|
|
||||||
github.com/sylviamoss/go-vnc v0.0.0-20200908145922-2061e37ffa00/go.mod h1:+I9wdVxvb9OqA4vpPvYoLvAeSx+Ew5PF6SiOWekjkGE=
|
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go v3.0.222+incompatible h1:bs+0lcG4RELNbE8PsBC9oaPP0/qExr0DuEGnZyocm84=
|
github.com/tencentcloud/tencentcloud-sdk-go v3.0.222+incompatible h1:bs+0lcG4RELNbE8PsBC9oaPP0/qExr0DuEGnZyocm84=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go v3.0.222+incompatible/go.mod h1:0PfYow01SHPMhKY31xa+EFz2RStxIqj6JFAJS+IkCi4=
|
github.com/tencentcloud/tencentcloud-sdk-go v3.0.222+incompatible/go.mod h1:0PfYow01SHPMhKY31xa+EFz2RStxIqj6JFAJS+IkCi4=
|
||||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 h1:G3dpKMzFDjgEh2q1Z7zUUtKa8ViPtH+ocF0bE0g00O8=
|
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 h1:G3dpKMzFDjgEh2q1Z7zUUtKa8ViPtH+ocF0bE0g00O8=
|
||||||
|
@ -764,8 +749,6 @@ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/
|
||||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM=
|
|
||||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
|
||||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
|
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
|
||||||
|
@ -829,11 +812,8 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80=
|
|
||||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200828194041-157a740278f4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200828194041-157a740278f4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f h1:Fqb3ao1hUmOR3GkUOg/Y+BadLwykBIzs5q8Ez2SbHyc=
|
|
||||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200918174421-af09f7315aff h1:1CPUrky56AcgSpxz/KfgzQWzfG09u5YOL8MvPYBlrL8=
|
golang.org/x/sys v0.0.0-20200918174421-af09f7315aff h1:1CPUrky56AcgSpxz/KfgzQWzfG09u5YOL8MvPYBlrL8=
|
||||||
golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
@ -880,7 +860,6 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK
|
||||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2 h1:L/G4KZvrQn7FWLN/LlulBtBzrLUhqjiGfTWWDmrh+IQ=
|
|
||||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||||
|
@ -894,16 +873,12 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc
|
||||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
golang.org/x/tools v0.0.0-20200828161849-5deb26317202/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
golang.org/x/tools v0.0.0-20200828161849-5deb26317202/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858 h1:xLt+iB5ksWcZVxqc+g9K41ZHy+6MKWfXCDsjSThnsPA=
|
|
||||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||||
golang.org/x/tools v0.0.0-20200915173823-2db8f0ff891c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
golang.org/x/tools v0.0.0-20200915173823-2db8f0ff891c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||||
golang.org/x/tools v0.0.0-20200918201133-e94ab7288189 h1:7E/geNtekOV4N/07EhKz7zyXs0hZhoZZ19R2O2mMHoI=
|
|
||||||
golang.org/x/tools v0.0.0-20200918201133-e94ab7288189/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
|
||||||
golang.org/x/tools v0.0.0-20200918232735-d647fc253266 h1:k7tVuG0g1JwmD3Jh8oAl1vQ1C3jb4Hi/dUl1wWDBJpQ=
|
golang.org/x/tools v0.0.0-20200918232735-d647fc253266 h1:k7tVuG0g1JwmD3Jh8oAl1vQ1C3jb4Hi/dUl1wWDBJpQ=
|
||||||
golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
@ -918,7 +893,6 @@ google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/
|
||||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
google.golang.org/api v0.21.0 h1:zS+Q/CJJnVlXpXQVIz+lH0ZT2lBuT2ac7XD8Y/3w6hY=
|
|
||||||
google.golang.org/api v0.21.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
google.golang.org/api v0.21.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||||
|
@ -932,7 +906,6 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||||
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
|
|
||||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
|
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
|
||||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
|
@ -963,14 +936,11 @@ google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfG
|
||||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
google.golang.org/genproto v0.0.0-20200617032506-f1bdc9086088 h1:XXo4PvhJkaWYIkwn7bX7mcdB8RdcOvn12HbaUUAwX3E=
|
|
||||||
google.golang.org/genproto v0.0.0-20200617032506-f1bdc9086088/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
|
||||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20200831141814-d751682dd103/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200831141814-d751682dd103/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d h1:92D1fum1bJLKSdr11OJ+54YeCMCGYIygTA7R/YZxH5M=
|
|
||||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20200914193844-75d14daec038/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200914193844-75d14daec038/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20200918140846-d0d605568037 h1:ujwz1DPMeHwCvo36rK5shXhAzc4GMRecrqQFaMZJBKQ=
|
google.golang.org/genproto v0.0.0-20200918140846-d0d605568037 h1:ujwz1DPMeHwCvo36rK5shXhAzc4GMRecrqQFaMZJBKQ=
|
||||||
|
@ -986,11 +956,9 @@ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
|
||||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||||
google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=
|
|
||||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
google.golang.org/grpc v1.31.1 h1:SfXqXS5hkufcdZ/mHtYCh53P2b+92WQq/DZcKLgsFRs=
|
|
||||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0=
|
google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0=
|
||||||
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
|
@ -1002,7 +970,6 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
|
||||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
|
|
||||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
|
@ -1013,8 +980,6 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogR
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/cheggaaa/pb.v1 v1.0.27 h1:kJdccidYzt3CaHD1crCFTS1hxyhSi059NhOFUf03YFo=
|
gopkg.in/cheggaaa/pb.v1 v1.0.27 h1:kJdccidYzt3CaHD1crCFTS1hxyhSi059NhOFUf03YFo=
|
||||||
gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||||
gopkg.in/djherbis/times.v1 v1.2.0 h1:UCvDKl1L/fmBygl2Y7hubXCnY7t4Yj46ZrBFNUipFbM=
|
|
||||||
gopkg.in/djherbis/times.v1 v1.2.0/go.mod h1:AQlg6unIsrsCEdQYhTzERy542dz6SFdQFZFv6mUY0P8=
|
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk=
|
gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk=
|
||||||
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
@ -1034,7 +999,6 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U=
|
|
||||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/hashicorp/go-cty-funcs/cidr"
|
"github.com/hashicorp/go-cty-funcs/cidr"
|
||||||
|
"github.com/hashicorp/go-cty-funcs/collection"
|
||||||
"github.com/hashicorp/go-cty-funcs/crypto"
|
"github.com/hashicorp/go-cty-funcs/crypto"
|
||||||
"github.com/hashicorp/go-cty-funcs/encoding"
|
"github.com/hashicorp/go-cty-funcs/encoding"
|
||||||
"github.com/hashicorp/go-cty-funcs/filesystem"
|
"github.com/hashicorp/go-cty-funcs/filesystem"
|
||||||
|
@ -41,7 +42,7 @@ func Functions(basedir string) map[string]function.Function {
|
||||||
"cidrnetmask": cidr.NetmaskFunc,
|
"cidrnetmask": cidr.NetmaskFunc,
|
||||||
"cidrsubnet": cidr.SubnetFunc,
|
"cidrsubnet": cidr.SubnetFunc,
|
||||||
"cidrsubnets": cidr.SubnetsFunc,
|
"cidrsubnets": cidr.SubnetsFunc,
|
||||||
"coalesce": stdlib.CoalesceFunc,
|
"coalesce": collection.CoalesceFunc,
|
||||||
"coalescelist": stdlib.CoalesceListFunc,
|
"coalescelist": stdlib.CoalesceListFunc,
|
||||||
"compact": stdlib.CompactFunc,
|
"compact": stdlib.CompactFunc,
|
||||||
"concat": stdlib.ConcatFunc,
|
"concat": stdlib.ConcatFunc,
|
||||||
|
|
|
@ -7,7 +7,7 @@ build {
|
||||||
]
|
]
|
||||||
|
|
||||||
provisioner "shell" {
|
provisioner "shell" {
|
||||||
string = "string"
|
string = coalesce(null, "", "string")
|
||||||
int = "${41 + 1}"
|
int = "${41 + 1}"
|
||||||
int64 = "${42 + 1}"
|
int64 = "${42 + 1}"
|
||||||
bool = "true"
|
bool = "true"
|
||||||
|
|
2
main.go
2
main.go
|
@ -196,6 +196,7 @@ func wrappedMain() int {
|
||||||
Reader: os.Stdin,
|
Reader: os.Stdin,
|
||||||
Writer: os.Stdout,
|
Writer: os.Stdout,
|
||||||
ErrorWriter: os.Stdout,
|
ErrorWriter: os.Stdout,
|
||||||
|
PB: &packer.NoopProgressTracker{},
|
||||||
}
|
}
|
||||||
ui = basicUi
|
ui = basicUi
|
||||||
if !inPlugin {
|
if !inPlugin {
|
||||||
|
@ -211,6 +212,7 @@ func wrappedMain() int {
|
||||||
fmt.Fprintf(os.Stderr, "No tty available: %s\n", err)
|
fmt.Fprintf(os.Stderr, "No tty available: %s\n", err)
|
||||||
} else {
|
} else {
|
||||||
basicUi.TTY = TTY
|
basicUi.TTY = TTY
|
||||||
|
basicUi.PB = &packer.UiProgressBar{}
|
||||||
defer TTY.Close()
|
defer TTY.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,25 +15,17 @@ func ProgressBarConfig(bar *pb.ProgressBar, prefix string) {
|
||||||
bar.Prefix(prefix)
|
bar.Prefix(prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
var defaultUiProgressBar = &uiProgressBar{}
|
// UiProgressBar is a progress bar compatible with go-getter used in our
|
||||||
|
// UI structs.
|
||||||
// uiProgressBar is a self managed progress bar singleton.
|
type UiProgressBar struct {
|
||||||
// decorate your struct with a *uiProgressBar to
|
|
||||||
// give it TrackProgress capabilities.
|
|
||||||
// In TrackProgress if uiProgressBar is nil
|
|
||||||
// defaultUiProgressBar will be used as
|
|
||||||
// the progress bar.
|
|
||||||
type uiProgressBar struct {
|
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
|
|
||||||
pool *pb.Pool
|
pool *pb.Pool
|
||||||
|
|
||||||
pbs int
|
pbs int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *uiProgressBar) TrackProgress(src string, currentSize, totalSize int64, stream io.ReadCloser) io.ReadCloser {
|
func (p *UiProgressBar) TrackProgress(src string, currentSize, totalSize int64, stream io.ReadCloser) io.ReadCloser {
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return defaultUiProgressBar.TrackProgress(src, currentSize, totalSize, stream)
|
return stream
|
||||||
}
|
}
|
||||||
p.lock.Lock()
|
p.lock.Lock()
|
||||||
defer p.lock.Unlock()
|
defer p.lock.Unlock()
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
package packer
|
package packer
|
||||||
|
|
||||||
type uiProgressBar = NoopProgressTracker
|
type UiProgressBar = NoopProgressTracker
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
// The following tests rarelly just happen. So we run them 100 times.
|
// The following tests rarelly just happen. So we run them 100 times.
|
||||||
|
|
||||||
func TestProgressTracking_open_close(t *testing.T) {
|
func TestProgressTracking_open_close(t *testing.T) {
|
||||||
var bar *uiProgressBar
|
var bar *UiProgressBar
|
||||||
|
|
||||||
tracker := bar.TrackProgress("1,", 1, 42, ioutil.NopCloser(nil))
|
tracker := bar.TrackProgress("1,", 1, 42, ioutil.NopCloser(nil))
|
||||||
tracker.Close()
|
tracker.Close()
|
||||||
|
@ -21,7 +21,7 @@ func TestProgressTracking_open_close(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProgressTracking_multi_open_close(t *testing.T) {
|
func TestProgressTracking_multi_open_close(t *testing.T) {
|
||||||
var bar *uiProgressBar
|
var bar *UiProgressBar
|
||||||
g := errgroup.Group{}
|
g := errgroup.Group{}
|
||||||
|
|
||||||
for i := 0; i < 100; i++ {
|
for i := 0; i < 100; i++ {
|
||||||
|
@ -36,7 +36,7 @@ func TestProgressTracking_multi_open_close(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProgressTracking_races(t *testing.T) {
|
func TestProgressTracking_races(t *testing.T) {
|
||||||
var bar *uiProgressBar
|
var bar *UiProgressBar
|
||||||
g := errgroup.Group{}
|
g := errgroup.Group{}
|
||||||
|
|
||||||
for i := 0; i < 100; i++ {
|
for i := 0; i < 100; i++ {
|
||||||
|
|
36
packer/ui.go
36
packer/ui.go
|
@ -40,11 +40,12 @@ type Ui interface {
|
||||||
Message(string)
|
Message(string)
|
||||||
Error(string)
|
Error(string)
|
||||||
Machine(string, ...string)
|
Machine(string, ...string)
|
||||||
|
// TrackProgress(src string, currentSize, totalSize int64, stream io.ReadCloser) (body io.ReadCloser)
|
||||||
getter.ProgressTracker
|
getter.ProgressTracker
|
||||||
}
|
}
|
||||||
|
|
||||||
type NoopUi struct {
|
type NoopUi struct {
|
||||||
NoopProgressTracker
|
PB NoopProgressTracker
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Ui = new(NoopUi)
|
var _ Ui = new(NoopUi)
|
||||||
|
@ -54,13 +55,16 @@ func (*NoopUi) Say(string) { return }
|
||||||
func (*NoopUi) Message(string) { return }
|
func (*NoopUi) Message(string) { return }
|
||||||
func (*NoopUi) Error(string) { return }
|
func (*NoopUi) Error(string) { return }
|
||||||
func (*NoopUi) Machine(string, ...string) { return }
|
func (*NoopUi) Machine(string, ...string) { return }
|
||||||
|
func (u *NoopUi) TrackProgress(src string, currentSize, totalSize int64, stream io.ReadCloser) io.ReadCloser {
|
||||||
|
return u.PB.TrackProgress(src, currentSize, totalSize, stream)
|
||||||
|
}
|
||||||
|
|
||||||
// ColoredUi is a UI that is colored using terminal colors.
|
// ColoredUi is a UI that is colored using terminal colors.
|
||||||
type ColoredUi struct {
|
type ColoredUi struct {
|
||||||
Color UiColor
|
Color UiColor
|
||||||
ErrorColor UiColor
|
ErrorColor UiColor
|
||||||
Ui Ui
|
Ui Ui
|
||||||
*uiProgressBar
|
PB getter.ProgressTracker
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Ui = new(ColoredUi)
|
var _ Ui = new(ColoredUi)
|
||||||
|
@ -189,7 +193,7 @@ type BasicUi struct {
|
||||||
l sync.Mutex
|
l sync.Mutex
|
||||||
interrupted bool
|
interrupted bool
|
||||||
TTY TTY
|
TTY TTY
|
||||||
*uiProgressBar
|
PB getter.ProgressTracker
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Ui = new(BasicUi)
|
var _ Ui = new(BasicUi)
|
||||||
|
@ -304,11 +308,15 @@ func (rw *BasicUi) Machine(t string, args ...string) {
|
||||||
log.Printf("machine readable: %s %#v", t, args)
|
log.Printf("machine readable: %s %#v", t, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rw *BasicUi) TrackProgress(src string, currentSize, totalSize int64, stream io.ReadCloser) (body io.ReadCloser) {
|
||||||
|
return rw.PB.TrackProgress(src, currentSize, totalSize, stream)
|
||||||
|
}
|
||||||
|
|
||||||
// MachineReadableUi is a UI that only outputs machine-readable output
|
// MachineReadableUi is a UI that only outputs machine-readable output
|
||||||
// to the given Writer.
|
// to the given Writer.
|
||||||
type MachineReadableUi struct {
|
type MachineReadableUi struct {
|
||||||
Writer io.Writer
|
Writer io.Writer
|
||||||
NoopProgressTracker
|
PB NoopProgressTracker
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Ui = new(MachineReadableUi)
|
var _ Ui = new(MachineReadableUi)
|
||||||
|
@ -366,11 +374,15 @@ func (u *MachineReadableUi) Machine(category string, args ...string) {
|
||||||
log.Printf("%d,%s,%s,%s\n", now.Unix(), target, category, argsString)
|
log.Printf("%d,%s,%s,%s\n", now.Unix(), target, category, argsString)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *MachineReadableUi) TrackProgress(src string, currentSize, totalSize int64, stream io.ReadCloser) (body io.ReadCloser) {
|
||||||
|
return u.PB.TrackProgress(src, currentSize, totalSize, stream)
|
||||||
|
}
|
||||||
|
|
||||||
// TimestampedUi is a UI that wraps another UI implementation and
|
// TimestampedUi is a UI that wraps another UI implementation and
|
||||||
// prefixes each message with an RFC3339 timestamp
|
// prefixes each message with an RFC3339 timestamp
|
||||||
type TimestampedUi struct {
|
type TimestampedUi struct {
|
||||||
Ui Ui
|
Ui Ui
|
||||||
*uiProgressBar
|
PB getter.ProgressTracker
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Ui = new(TimestampedUi)
|
var _ Ui = new(TimestampedUi)
|
||||||
|
@ -395,6 +407,10 @@ func (u *TimestampedUi) Machine(message string, args ...string) {
|
||||||
u.Ui.Machine(message, args...)
|
u.Ui.Machine(message, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *TimestampedUi) TrackProgress(src string, currentSize, totalSize int64, stream io.ReadCloser) (body io.ReadCloser) {
|
||||||
|
return u.Ui.TrackProgress(src, currentSize, totalSize, stream)
|
||||||
|
}
|
||||||
|
|
||||||
func (u *TimestampedUi) timestampLine(string string) string {
|
func (u *TimestampedUi) timestampLine(string string) string {
|
||||||
return fmt.Sprintf("%v: %v", time.Now().Format(time.RFC3339), string)
|
return fmt.Sprintf("%v: %v", time.Now().Format(time.RFC3339), string)
|
||||||
}
|
}
|
||||||
|
@ -404,7 +420,7 @@ func (u *TimestampedUi) timestampLine(string string) string {
|
||||||
type SafeUi struct {
|
type SafeUi struct {
|
||||||
Sem chan int
|
Sem chan int
|
||||||
Ui Ui
|
Ui Ui
|
||||||
*uiProgressBar
|
PB getter.ProgressTracker
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Ui = new(SafeUi)
|
var _ Ui = new(SafeUi)
|
||||||
|
@ -440,3 +456,11 @@ func (u *SafeUi) Machine(t string, args ...string) {
|
||||||
u.Ui.Machine(t, args...)
|
u.Ui.Machine(t, args...)
|
||||||
<-u.Sem
|
<-u.Sem
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *SafeUi) TrackProgress(src string, currentSize, totalSize int64, stream io.ReadCloser) (body io.ReadCloser) {
|
||||||
|
u.Sem <- 1
|
||||||
|
ret := u.Ui.TrackProgress(src, currentSize, totalSize, stream)
|
||||||
|
<-u.Sem
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ func (tty *testTTY) ReadString() (string, error) {
|
||||||
|
|
||||||
func TestColoredUi(t *testing.T) {
|
func TestColoredUi(t *testing.T) {
|
||||||
bufferUi := testUi()
|
bufferUi := testUi()
|
||||||
ui := &ColoredUi{UiColorYellow, UiColorRed, bufferUi, defaultUiProgressBar}
|
ui := &ColoredUi{UiColorYellow, UiColorRed, bufferUi, &UiProgressBar{}}
|
||||||
|
|
||||||
if !ui.supportsColors() {
|
if !ui.supportsColors() {
|
||||||
t.Skip("skipping for ui without color support")
|
t.Skip("skipping for ui without color support")
|
||||||
|
@ -81,7 +81,7 @@ func TestColoredUi(t *testing.T) {
|
||||||
|
|
||||||
func TestColoredUi_noColorEnv(t *testing.T) {
|
func TestColoredUi_noColorEnv(t *testing.T) {
|
||||||
bufferUi := testUi()
|
bufferUi := testUi()
|
||||||
ui := &ColoredUi{UiColorYellow, UiColorRed, bufferUi, defaultUiProgressBar}
|
ui := &ColoredUi{UiColorYellow, UiColorRed, bufferUi, &UiProgressBar{}}
|
||||||
|
|
||||||
// Set the env var to get rid of the color
|
// Set the env var to get rid of the color
|
||||||
oldenv := os.Getenv("PACKER_NO_COLOR")
|
oldenv := os.Getenv("PACKER_NO_COLOR")
|
||||||
|
|
|
@ -18,7 +18,9 @@ type FlatConfig struct {
|
||||||
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
|
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
|
||||||
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
|
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
|
||||||
AccessKey *string `mapstructure:"access_key" required:"true" cty:"access_key" hcl:"access_key"`
|
AccessKey *string `mapstructure:"access_key" required:"true" cty:"access_key" hcl:"access_key"`
|
||||||
|
AssumeRole *common.FlatAssumeRoleConfig `mapstructure:"assume_role" required:"false" cty:"assume_role" hcl:"assume_role"`
|
||||||
CustomEndpointEc2 *string `mapstructure:"custom_endpoint_ec2" required:"false" cty:"custom_endpoint_ec2" hcl:"custom_endpoint_ec2"`
|
CustomEndpointEc2 *string `mapstructure:"custom_endpoint_ec2" required:"false" cty:"custom_endpoint_ec2" hcl:"custom_endpoint_ec2"`
|
||||||
|
CredsFilename *string `mapstructure:"shared_credentials_file" required:"false" cty:"shared_credentials_file" hcl:"shared_credentials_file"`
|
||||||
DecodeAuthZMessages *bool `mapstructure:"decode_authorization_messages" required:"false" cty:"decode_authorization_messages" hcl:"decode_authorization_messages"`
|
DecodeAuthZMessages *bool `mapstructure:"decode_authorization_messages" required:"false" cty:"decode_authorization_messages" hcl:"decode_authorization_messages"`
|
||||||
InsecureSkipTLSVerify *bool `mapstructure:"insecure_skip_tls_verify" required:"false" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"`
|
InsecureSkipTLSVerify *bool `mapstructure:"insecure_skip_tls_verify" required:"false" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"`
|
||||||
MaxRetries *int `mapstructure:"max_retries" required:"false" cty:"max_retries" hcl:"max_retries"`
|
MaxRetries *int `mapstructure:"max_retries" required:"false" cty:"max_retries" hcl:"max_retries"`
|
||||||
|
@ -28,6 +30,7 @@ type FlatConfig struct {
|
||||||
SecretKey *string `mapstructure:"secret_key" required:"true" cty:"secret_key" hcl:"secret_key"`
|
SecretKey *string `mapstructure:"secret_key" required:"true" cty:"secret_key" hcl:"secret_key"`
|
||||||
SkipValidation *bool `mapstructure:"skip_region_validation" required:"false" cty:"skip_region_validation" hcl:"skip_region_validation"`
|
SkipValidation *bool `mapstructure:"skip_region_validation" required:"false" cty:"skip_region_validation" hcl:"skip_region_validation"`
|
||||||
SkipMetadataApiCheck *bool `mapstructure:"skip_metadata_api_check" cty:"skip_metadata_api_check" hcl:"skip_metadata_api_check"`
|
SkipMetadataApiCheck *bool `mapstructure:"skip_metadata_api_check" cty:"skip_metadata_api_check" hcl:"skip_metadata_api_check"`
|
||||||
|
SkipCredsValidation *bool `mapstructure:"skip_credential_validation" cty:"skip_credential_validation" hcl:"skip_credential_validation"`
|
||||||
Token *string `mapstructure:"token" required:"false" cty:"token" hcl:"token"`
|
Token *string `mapstructure:"token" required:"false" cty:"token" hcl:"token"`
|
||||||
VaultAWSEngine *common.FlatVaultAWSEngineOptions `mapstructure:"vault_aws_engine" required:"false" cty:"vault_aws_engine" hcl:"vault_aws_engine"`
|
VaultAWSEngine *common.FlatVaultAWSEngineOptions `mapstructure:"vault_aws_engine" required:"false" cty:"vault_aws_engine" hcl:"vault_aws_engine"`
|
||||||
PollingConfig *common.FlatAWSPollingConfig `mapstructure:"aws_polling" required:"false" cty:"aws_polling" hcl:"aws_polling"`
|
PollingConfig *common.FlatAWSPollingConfig `mapstructure:"aws_polling" required:"false" cty:"aws_polling" hcl:"aws_polling"`
|
||||||
|
@ -68,7 +71,9 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
|
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
|
||||||
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
|
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
|
||||||
"access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false},
|
"access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false},
|
||||||
|
"assume_role": &hcldec.BlockSpec{TypeName: "assume_role", Nested: hcldec.ObjectSpec((*common.FlatAssumeRoleConfig)(nil).HCL2Spec())},
|
||||||
"custom_endpoint_ec2": &hcldec.AttrSpec{Name: "custom_endpoint_ec2", Type: cty.String, Required: false},
|
"custom_endpoint_ec2": &hcldec.AttrSpec{Name: "custom_endpoint_ec2", Type: cty.String, Required: false},
|
||||||
|
"shared_credentials_file": &hcldec.AttrSpec{Name: "shared_credentials_file", Type: cty.String, Required: false},
|
||||||
"decode_authorization_messages": &hcldec.AttrSpec{Name: "decode_authorization_messages", Type: cty.Bool, Required: false},
|
"decode_authorization_messages": &hcldec.AttrSpec{Name: "decode_authorization_messages", Type: cty.Bool, Required: false},
|
||||||
"insecure_skip_tls_verify": &hcldec.AttrSpec{Name: "insecure_skip_tls_verify", Type: cty.Bool, Required: false},
|
"insecure_skip_tls_verify": &hcldec.AttrSpec{Name: "insecure_skip_tls_verify", Type: cty.Bool, Required: false},
|
||||||
"max_retries": &hcldec.AttrSpec{Name: "max_retries", Type: cty.Number, Required: false},
|
"max_retries": &hcldec.AttrSpec{Name: "max_retries", Type: cty.Number, Required: false},
|
||||||
|
@ -78,6 +83,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
"secret_key": &hcldec.AttrSpec{Name: "secret_key", Type: cty.String, Required: false},
|
"secret_key": &hcldec.AttrSpec{Name: "secret_key", Type: cty.String, Required: false},
|
||||||
"skip_region_validation": &hcldec.AttrSpec{Name: "skip_region_validation", Type: cty.Bool, Required: false},
|
"skip_region_validation": &hcldec.AttrSpec{Name: "skip_region_validation", Type: cty.Bool, Required: false},
|
||||||
"skip_metadata_api_check": &hcldec.AttrSpec{Name: "skip_metadata_api_check", Type: cty.Bool, Required: false},
|
"skip_metadata_api_check": &hcldec.AttrSpec{Name: "skip_metadata_api_check", Type: cty.Bool, Required: false},
|
||||||
|
"skip_credential_validation": &hcldec.AttrSpec{Name: "skip_credential_validation", Type: cty.Bool, Required: false},
|
||||||
"token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false},
|
"token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false},
|
||||||
"vault_aws_engine": &hcldec.BlockSpec{TypeName: "vault_aws_engine", Nested: hcldec.ObjectSpec((*common.FlatVaultAWSEngineOptions)(nil).HCL2Spec())},
|
"vault_aws_engine": &hcldec.BlockSpec{TypeName: "vault_aws_engine", Nested: hcldec.ObjectSpec((*common.FlatVaultAWSEngineOptions)(nil).HCL2Spec())},
|
||||||
"aws_polling": &hcldec.BlockSpec{TypeName: "aws_polling", Nested: hcldec.ObjectSpec((*common.FlatAWSPollingConfig)(nil).HCL2Spec())},
|
"aws_polling": &hcldec.BlockSpec{TypeName: "aws_polling", Nested: hcldec.ObjectSpec((*common.FlatAWSPollingConfig)(nil).HCL2Spec())},
|
||||||
|
|
|
@ -375,7 +375,7 @@ func (p *Provisioner) setupAdapter(ui packer.Ui, comm packer.Communicator) (stri
|
||||||
keyChecker := ssh.CertChecker{
|
keyChecker := ssh.CertChecker{
|
||||||
UserKeyFallback: func(conn ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) {
|
UserKeyFallback: func(conn ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) {
|
||||||
if user := conn.User(); user != p.config.User {
|
if user := conn.User(); user != p.config.User {
|
||||||
return nil, errors.New(fmt.Sprintf("authentication failed: %s is not a valid user", user))
|
return nil, fmt.Errorf("authentication failed: %s is not a valid user", user)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !bytes.Equal(k.Marshal(), pubKey.Marshal()) {
|
if !bytes.Equal(k.Marshal(), pubKey.Marshal()) {
|
||||||
|
@ -648,16 +648,30 @@ func (p *Provisioner) executeGalaxy(ui packer.Ui, comm packer.Communicator) erro
|
||||||
collectionArgs = append(collectionArgs, "-p", filepath.ToSlash(p.config.CollectionsPath))
|
collectionArgs = append(collectionArgs, "-p", filepath.ToSlash(p.config.CollectionsPath))
|
||||||
}
|
}
|
||||||
|
|
||||||
roleInstallError := p.invokeGalaxyCommand(roleArgs, ui, comm)
|
// Search galaxy_file for roles and collections keywords
|
||||||
// Return the error if the role installation failed before attempting the collection install
|
f, err := ioutil.ReadFile(galaxyFile)
|
||||||
if roleInstallError != nil {
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
hasRoles, _ := regexp.Match(`(?m)^roles:`, f)
|
||||||
|
hasCollections, _ := regexp.Match(`(?m)^collections:`, f)
|
||||||
|
|
||||||
|
// If if roles keyword present (v2 format), or no collections keywork present (v1), install roles
|
||||||
|
if hasRoles || !hasCollections {
|
||||||
|
if roleInstallError := p.invokeGalaxyCommand(roleArgs, ui, comm); roleInstallError != nil {
|
||||||
return roleInstallError
|
return roleInstallError
|
||||||
}
|
}
|
||||||
// If all is well, proceed with collection install
|
}
|
||||||
// This variable isn't strictly necessary but including for readability to match the role installation
|
|
||||||
collectionInstallError := p.invokeGalaxyCommand(collectionArgs, ui, comm)
|
// If collections keyword present (v2 format), install collections
|
||||||
|
if hasCollections {
|
||||||
|
if collectionInstallError := p.invokeGalaxyCommand(collectionArgs, ui, comm); collectionInstallError != nil {
|
||||||
return collectionInstallError
|
return collectionInstallError
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Intended to be invoked from p.executeGalaxy depending on the Ansible Galaxy parameters passed to Packer
|
// Intended to be invoked from p.executeGalaxy depending on the Ansible Galaxy parameters passed to Packer
|
||||||
func (p *Provisioner) invokeGalaxyCommand(args []string, ui packer.Ui, comm packer.Communicator) error {
|
func (p *Provisioner) invokeGalaxyCommand(args []string, ui packer.Ui, comm packer.Communicator) error {
|
||||||
|
|
|
@ -70,7 +70,7 @@ $xml = [xml]@'
|
||||||
<Hidden>false</Hidden>
|
<Hidden>false</Hidden>
|
||||||
<RunOnlyIfIdle>false</RunOnlyIfIdle>
|
<RunOnlyIfIdle>false</RunOnlyIfIdle>
|
||||||
<WakeToRun>false</WakeToRun>
|
<WakeToRun>false</WakeToRun>
|
||||||
<ExecutionTimeLimit>PT24H</ExecutionTimeLimit>
|
<ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
|
||||||
<Priority>4</Priority>
|
<Priority>4</Priority>
|
||||||
</Settings>
|
</Settings>
|
||||||
<Actions Context="Author">
|
<Actions Context="Author">
|
||||||
|
|
|
@ -126,6 +126,7 @@ func TestProvisionerProvision_SendsFile(t *testing.T) {
|
||||||
b := bytes.NewBuffer(nil)
|
b := bytes.NewBuffer(nil)
|
||||||
ui := &packer.BasicUi{
|
ui := &packer.BasicUi{
|
||||||
Writer: b,
|
Writer: b,
|
||||||
|
PB: &packer.NoopProgressTracker{},
|
||||||
}
|
}
|
||||||
comm := &packer.MockCommunicator{}
|
comm := &packer.MockCommunicator{}
|
||||||
err = p.Provision(context.Background(), ui, comm, make(map[string]interface{}))
|
err = p.Provision(context.Background(), ui, comm, make(map[string]interface{}))
|
||||||
|
@ -184,6 +185,7 @@ func TestProvisionerProvision_SendsFileMultipleFiles(t *testing.T) {
|
||||||
b := bytes.NewBuffer(nil)
|
b := bytes.NewBuffer(nil)
|
||||||
ui := &packer.BasicUi{
|
ui := &packer.BasicUi{
|
||||||
Writer: b,
|
Writer: b,
|
||||||
|
PB: &packer.NoopProgressTracker{},
|
||||||
}
|
}
|
||||||
comm := &packer.MockCommunicator{}
|
comm := &packer.MockCommunicator{}
|
||||||
err = p.Provision(context.Background(), ui, comm, make(map[string]interface{}))
|
err = p.Provision(context.Background(), ui, comm, make(map[string]interface{}))
|
||||||
|
@ -253,6 +255,7 @@ func TestProvisionerProvision_SendsFileMultipleDirs(t *testing.T) {
|
||||||
b := bytes.NewBuffer(nil)
|
b := bytes.NewBuffer(nil)
|
||||||
ui := &packer.BasicUi{
|
ui := &packer.BasicUi{
|
||||||
Writer: b,
|
Writer: b,
|
||||||
|
PB: &packer.NoopProgressTracker{},
|
||||||
}
|
}
|
||||||
comm := &packer.MockCommunicator{}
|
comm := &packer.MockCommunicator{}
|
||||||
err = p.Provision(context.Background(), ui, comm, make(map[string]interface{}))
|
err = p.Provision(context.Background(), ui, comm, make(map[string]interface{}))
|
||||||
|
@ -304,6 +307,7 @@ func TestProvisionerProvision_SendsFileMultipleFilesToFolder(t *testing.T) {
|
||||||
b := bytes.NewBuffer(nil)
|
b := bytes.NewBuffer(nil)
|
||||||
ui := &packer.BasicUi{
|
ui := &packer.BasicUi{
|
||||||
Writer: b,
|
Writer: b,
|
||||||
|
PB: &packer.NoopProgressTracker{},
|
||||||
}
|
}
|
||||||
comm := &packer.MockCommunicator{}
|
comm := &packer.MockCommunicator{}
|
||||||
err = p.Provision(context.Background(), ui, comm, make(map[string]interface{}))
|
err = p.Provision(context.Background(), ui, comm, make(map[string]interface{}))
|
||||||
|
@ -361,6 +365,7 @@ func TestProvisionDownloadMkdirAll(t *testing.T) {
|
||||||
b := bytes.NewBuffer(nil)
|
b := bytes.NewBuffer(nil)
|
||||||
ui := &packer.BasicUi{
|
ui := &packer.BasicUi{
|
||||||
Writer: b,
|
Writer: b,
|
||||||
|
PB: &packer.NoopProgressTracker{},
|
||||||
}
|
}
|
||||||
comm := &packer.MockCommunicator{}
|
comm := &packer.MockCommunicator{}
|
||||||
err = p.ProvisionDownload(ui, comm)
|
err = p.ProvisionDownload(ui, comm)
|
||||||
|
|
|
@ -43,7 +43,7 @@ type Config struct {
|
||||||
|
|
||||||
// An optional endpoint URL (hostname only or fully qualified URI)
|
// An optional endpoint URL (hostname only or fully qualified URI)
|
||||||
// that overrides the default generated endpoint for a client. Set this
|
// that overrides the default generated endpoint for a client. Set this
|
||||||
// to `""` to use the default generated endpoint.
|
// to `nil` or the value to `""` to use the default generated endpoint.
|
||||||
//
|
//
|
||||||
// Note: You must still provide a `Region` value when specifying an
|
// Note: You must still provide a `Region` value when specifying an
|
||||||
// endpoint for a client.
|
// endpoint for a client.
|
||||||
|
@ -138,7 +138,7 @@ type Config struct {
|
||||||
// `ExpectContinueTimeout` for information on adjusting the continue wait
|
// `ExpectContinueTimeout` for information on adjusting the continue wait
|
||||||
// timeout. https://golang.org/pkg/net/http/#Transport
|
// timeout. https://golang.org/pkg/net/http/#Transport
|
||||||
//
|
//
|
||||||
// You should use this flag to disble 100-Continue if you experience issues
|
// You should use this flag to disable 100-Continue if you experience issues
|
||||||
// with proxies or third party S3 compatible services.
|
// with proxies or third party S3 compatible services.
|
||||||
S3Disable100Continue *bool
|
S3Disable100Continue *bool
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ type Config struct {
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
// sess := session.Must(session.NewSession(aws.NewConfig()
|
// sess := session.Must(session.NewSession(aws.NewConfig()
|
||||||
// .WithEC2MetadataDiableTimeoutOverride(true)))
|
// .WithEC2MetadataDisableTimeoutOverride(true)))
|
||||||
//
|
//
|
||||||
// svc := s3.New(sess)
|
// svc := s3.New(sess)
|
||||||
//
|
//
|
||||||
|
@ -194,7 +194,7 @@ type Config struct {
|
||||||
// both IPv4 and IPv6 addressing.
|
// both IPv4 and IPv6 addressing.
|
||||||
//
|
//
|
||||||
// Setting this for a service which does not support dual stack will fail
|
// Setting this for a service which does not support dual stack will fail
|
||||||
// to make requets. It is not recommended to set this value on the session
|
// to make requests. It is not recommended to set this value on the session
|
||||||
// as it will apply to all service clients created with the session. Even
|
// as it will apply to all service clients created with the session. Even
|
||||||
// services which don't support dual stack endpoints.
|
// services which don't support dual stack endpoints.
|
||||||
//
|
//
|
||||||
|
@ -238,6 +238,7 @@ type Config struct {
|
||||||
|
|
||||||
// EnableEndpointDiscovery will allow for endpoint discovery on operations that
|
// EnableEndpointDiscovery will allow for endpoint discovery on operations that
|
||||||
// have the definition in its model. By default, endpoint discovery is off.
|
// have the definition in its model. By default, endpoint discovery is off.
|
||||||
|
// To use EndpointDiscovery, Endpoint should be unset or set to an empty string.
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
// sess := session.Must(session.NewSession(&aws.Config{
|
// sess := session.Must(session.NewSession(&aws.Config{
|
||||||
|
|
|
@ -225,6 +225,8 @@ var ValidateEndpointHandler = request.NamedHandler{Name: "core.ValidateEndpointH
|
||||||
if r.ClientInfo.SigningRegion == "" && aws.StringValue(r.Config.Region) == "" {
|
if r.ClientInfo.SigningRegion == "" && aws.StringValue(r.Config.Region) == "" {
|
||||||
r.Error = aws.ErrMissingRegion
|
r.Error = aws.ErrMissingRegion
|
||||||
} else if r.ClientInfo.Endpoint == "" {
|
} else if r.ClientInfo.Endpoint == "" {
|
||||||
|
// Was any endpoint provided by the user, or one was derived by the
|
||||||
|
// SDK's endpoint resolver?
|
||||||
r.Error = aws.ErrMissingEndpoint
|
r.Error = aws.ErrMissingEndpoint
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
5
vendor/github.com/aws/aws-sdk-go/aws/credentials/shared_credentials_provider.go
generated
vendored
5
vendor/github.com/aws/aws-sdk-go/aws/credentials/shared_credentials_provider.go
generated
vendored
|
@ -17,8 +17,9 @@ var (
|
||||||
ErrSharedCredentialsHomeNotFound = awserr.New("UserHomeNotFound", "user home directory not found.", nil)
|
ErrSharedCredentialsHomeNotFound = awserr.New("UserHomeNotFound", "user home directory not found.", nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// A SharedCredentialsProvider retrieves credentials from the current user's home
|
// A SharedCredentialsProvider retrieves access key pair (access key ID,
|
||||||
// directory, and keeps track if those credentials are expired.
|
// secret access key, and session token if present) credentials from the current
|
||||||
|
// user's home directory, and keeps track if those credentials are expired.
|
||||||
//
|
//
|
||||||
// Profile ini file example: $HOME/.aws/credentials
|
// Profile ini file example: $HOME/.aws/credentials
|
||||||
type SharedCredentialsProvider struct {
|
type SharedCredentialsProvider struct {
|
||||||
|
|
24
vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/assume_role_provider.go
generated
vendored
24
vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/assume_role_provider.go
generated
vendored
|
@ -169,6 +169,29 @@ type AssumeRoleProvider struct {
|
||||||
// size.
|
// size.
|
||||||
Policy *string
|
Policy *string
|
||||||
|
|
||||||
|
// The ARNs of IAM managed policies you want to use as managed session policies.
|
||||||
|
// The policies must exist in the same account as the role.
|
||||||
|
//
|
||||||
|
// This parameter is optional. You can provide up to 10 managed policy ARNs.
|
||||||
|
// However, the plain text that you use for both inline and managed session
|
||||||
|
// policies can't exceed 2,048 characters.
|
||||||
|
//
|
||||||
|
// An AWS conversion compresses the passed session policies and session tags
|
||||||
|
// into a packed binary format that has a separate limit. Your request can fail
|
||||||
|
// for this limit even if your plain text meets the other requirements. The
|
||||||
|
// PackedPolicySize response element indicates by percentage how close the policies
|
||||||
|
// and tags for your request are to the upper size limit.
|
||||||
|
//
|
||||||
|
// Passing policies to this operation returns new temporary credentials. The
|
||||||
|
// resulting session's permissions are the intersection of the role's identity-based
|
||||||
|
// policy and the session policies. You can use the role's temporary credentials
|
||||||
|
// in subsequent AWS API calls to access resources in the account that owns
|
||||||
|
// the role. You cannot use session policies to grant more permissions than
|
||||||
|
// those allowed by the identity-based policy of the role that is being assumed.
|
||||||
|
// For more information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
PolicyArns []*sts.PolicyDescriptorType
|
||||||
|
|
||||||
// The identification number of the MFA device that is associated with the user
|
// The identification number of the MFA device that is associated with the user
|
||||||
// who is making the AssumeRole call. Specify this value if the trust policy
|
// who is making the AssumeRole call. Specify this value if the trust policy
|
||||||
// of the role being assumed includes a condition that requires MFA authentication.
|
// of the role being assumed includes a condition that requires MFA authentication.
|
||||||
|
@ -291,6 +314,7 @@ func (p *AssumeRoleProvider) RetrieveWithContext(ctx credentials.Context) (crede
|
||||||
RoleSessionName: aws.String(p.RoleSessionName),
|
RoleSessionName: aws.String(p.RoleSessionName),
|
||||||
ExternalId: p.ExternalID,
|
ExternalId: p.ExternalID,
|
||||||
Tags: p.Tags,
|
Tags: p.Tags,
|
||||||
|
PolicyArns: p.PolicyArns,
|
||||||
TransitiveTagKeys: p.TransitiveTagKeys,
|
TransitiveTagKeys: p.TransitiveTagKeys,
|
||||||
}
|
}
|
||||||
if p.Policy != nil {
|
if p.Policy != nil {
|
||||||
|
|
56
vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/web_identity_provider.go
generated
vendored
56
vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/web_identity_provider.go
generated
vendored
|
@ -28,15 +28,46 @@ const (
|
||||||
// compare test values.
|
// compare test values.
|
||||||
var now = time.Now
|
var now = time.Now
|
||||||
|
|
||||||
|
// TokenFetcher shuold return WebIdentity token bytes or an error
|
||||||
|
type TokenFetcher interface {
|
||||||
|
FetchToken(credentials.Context) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchTokenPath is a path to a WebIdentity token file
|
||||||
|
type FetchTokenPath string
|
||||||
|
|
||||||
|
// FetchToken returns a token by reading from the filesystem
|
||||||
|
func (f FetchTokenPath) FetchToken(ctx credentials.Context) ([]byte, error) {
|
||||||
|
data, err := ioutil.ReadFile(string(f))
|
||||||
|
if err != nil {
|
||||||
|
errMsg := fmt.Sprintf("unable to read file at %s", f)
|
||||||
|
return nil, awserr.New(ErrCodeWebIdentity, errMsg, err)
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
// WebIdentityRoleProvider is used to retrieve credentials using
|
// WebIdentityRoleProvider is used to retrieve credentials using
|
||||||
// an OIDC token.
|
// an OIDC token.
|
||||||
type WebIdentityRoleProvider struct {
|
type WebIdentityRoleProvider struct {
|
||||||
credentials.Expiry
|
credentials.Expiry
|
||||||
|
PolicyArns []*sts.PolicyDescriptorType
|
||||||
|
|
||||||
client stsiface.STSAPI
|
// Duration the STS credentials will be valid for. Truncated to seconds.
|
||||||
|
// If unset, the assumed role will use AssumeRoleWithWebIdentity's default
|
||||||
|
// expiry duration. See
|
||||||
|
// https://docs.aws.amazon.com/sdk-for-go/api/service/sts/#STS.AssumeRoleWithWebIdentity
|
||||||
|
// for more information.
|
||||||
|
Duration time.Duration
|
||||||
|
|
||||||
|
// The amount of time the credentials will be refreshed before they expire.
|
||||||
|
// This is useful refresh credentials before they expire to reduce risk of
|
||||||
|
// using credentials as they expire. If unset, will default to no expiry
|
||||||
|
// window.
|
||||||
ExpiryWindow time.Duration
|
ExpiryWindow time.Duration
|
||||||
|
|
||||||
tokenFilePath string
|
client stsiface.STSAPI
|
||||||
|
|
||||||
|
tokenFetcher TokenFetcher
|
||||||
roleARN string
|
roleARN string
|
||||||
roleSessionName string
|
roleSessionName string
|
||||||
}
|
}
|
||||||
|
@ -52,9 +83,15 @@ func NewWebIdentityCredentials(c client.ConfigProvider, roleARN, roleSessionName
|
||||||
// NewWebIdentityRoleProvider will return a new WebIdentityRoleProvider with the
|
// NewWebIdentityRoleProvider will return a new WebIdentityRoleProvider with the
|
||||||
// provided stsiface.STSAPI
|
// provided stsiface.STSAPI
|
||||||
func NewWebIdentityRoleProvider(svc stsiface.STSAPI, roleARN, roleSessionName, path string) *WebIdentityRoleProvider {
|
func NewWebIdentityRoleProvider(svc stsiface.STSAPI, roleARN, roleSessionName, path string) *WebIdentityRoleProvider {
|
||||||
|
return NewWebIdentityRoleProviderWithToken(svc, roleARN, roleSessionName, FetchTokenPath(path))
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWebIdentityRoleProviderWithToken will return a new WebIdentityRoleProvider with the
|
||||||
|
// provided stsiface.STSAPI and a TokenFetcher
|
||||||
|
func NewWebIdentityRoleProviderWithToken(svc stsiface.STSAPI, roleARN, roleSessionName string, tokenFetcher TokenFetcher) *WebIdentityRoleProvider {
|
||||||
return &WebIdentityRoleProvider{
|
return &WebIdentityRoleProvider{
|
||||||
client: svc,
|
client: svc,
|
||||||
tokenFilePath: path,
|
tokenFetcher: tokenFetcher,
|
||||||
roleARN: roleARN,
|
roleARN: roleARN,
|
||||||
roleSessionName: roleSessionName,
|
roleSessionName: roleSessionName,
|
||||||
}
|
}
|
||||||
|
@ -71,10 +108,9 @@ func (p *WebIdentityRoleProvider) Retrieve() (credentials.Value, error) {
|
||||||
// 'WebIdentityTokenFilePath' specified destination and if that is empty an
|
// 'WebIdentityTokenFilePath' specified destination and if that is empty an
|
||||||
// error will be returned.
|
// error will be returned.
|
||||||
func (p *WebIdentityRoleProvider) RetrieveWithContext(ctx credentials.Context) (credentials.Value, error) {
|
func (p *WebIdentityRoleProvider) RetrieveWithContext(ctx credentials.Context) (credentials.Value, error) {
|
||||||
b, err := ioutil.ReadFile(p.tokenFilePath)
|
b, err := p.tokenFetcher.FetchToken(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errMsg := fmt.Sprintf("unable to read file at %s", p.tokenFilePath)
|
return credentials.Value{}, awserr.New(ErrCodeWebIdentity, "failed fetching WebIdentity token: ", err)
|
||||||
return credentials.Value{}, awserr.New(ErrCodeWebIdentity, errMsg, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionName := p.roleSessionName
|
sessionName := p.roleSessionName
|
||||||
|
@ -83,10 +119,18 @@ func (p *WebIdentityRoleProvider) RetrieveWithContext(ctx credentials.Context) (
|
||||||
// uses unix time in nanoseconds to uniquely identify sessions.
|
// uses unix time in nanoseconds to uniquely identify sessions.
|
||||||
sessionName = strconv.FormatInt(now().UnixNano(), 10)
|
sessionName = strconv.FormatInt(now().UnixNano(), 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var duration *int64
|
||||||
|
if p.Duration != 0 {
|
||||||
|
duration = aws.Int64(int64(p.Duration / time.Second))
|
||||||
|
}
|
||||||
|
|
||||||
req, resp := p.client.AssumeRoleWithWebIdentityRequest(&sts.AssumeRoleWithWebIdentityInput{
|
req, resp := p.client.AssumeRoleWithWebIdentityRequest(&sts.AssumeRoleWithWebIdentityInput{
|
||||||
|
PolicyArns: p.PolicyArns,
|
||||||
RoleArn: &p.roleARN,
|
RoleArn: &p.roleARN,
|
||||||
RoleSessionName: &sessionName,
|
RoleSessionName: &sessionName,
|
||||||
WebIdentityToken: aws.String(string(b)),
|
WebIdentityToken: aws.String(string(b)),
|
||||||
|
DurationSeconds: duration,
|
||||||
})
|
})
|
||||||
|
|
||||||
req.SetContext(ctx)
|
req.SetContext(ctx)
|
||||||
|
|
|
@ -20,7 +20,7 @@ func (c *EC2Metadata) getToken(ctx aws.Context, duration time.Duration) (tokenOu
|
||||||
op := &request.Operation{
|
op := &request.Operation{
|
||||||
Name: "GetToken",
|
Name: "GetToken",
|
||||||
HTTPMethod: "PUT",
|
HTTPMethod: "PUT",
|
||||||
HTTPPath: "/api/token",
|
HTTPPath: "/latest/api/token",
|
||||||
}
|
}
|
||||||
|
|
||||||
var output tokenOutput
|
var output tokenOutput
|
||||||
|
@ -62,7 +62,7 @@ func (c *EC2Metadata) GetMetadataWithContext(ctx aws.Context, p string) (string,
|
||||||
op := &request.Operation{
|
op := &request.Operation{
|
||||||
Name: "GetMetadata",
|
Name: "GetMetadata",
|
||||||
HTTPMethod: "GET",
|
HTTPMethod: "GET",
|
||||||
HTTPPath: sdkuri.PathJoin("/meta-data", p),
|
HTTPPath: sdkuri.PathJoin("/latest/meta-data", p),
|
||||||
}
|
}
|
||||||
output := &metadataOutput{}
|
output := &metadataOutput{}
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ func (c *EC2Metadata) GetUserDataWithContext(ctx aws.Context) (string, error) {
|
||||||
op := &request.Operation{
|
op := &request.Operation{
|
||||||
Name: "GetUserData",
|
Name: "GetUserData",
|
||||||
HTTPMethod: "GET",
|
HTTPMethod: "GET",
|
||||||
HTTPPath: "/user-data",
|
HTTPPath: "/latest/user-data",
|
||||||
}
|
}
|
||||||
|
|
||||||
output := &metadataOutput{}
|
output := &metadataOutput{}
|
||||||
|
@ -113,7 +113,7 @@ func (c *EC2Metadata) GetDynamicDataWithContext(ctx aws.Context, p string) (stri
|
||||||
op := &request.Operation{
|
op := &request.Operation{
|
||||||
Name: "GetDynamicData",
|
Name: "GetDynamicData",
|
||||||
HTTPMethod: "GET",
|
HTTPMethod: "GET",
|
||||||
HTTPPath: sdkuri.PathJoin("/dynamic", p),
|
HTTPPath: sdkuri.PathJoin("/latest/dynamic", p),
|
||||||
}
|
}
|
||||||
|
|
||||||
output := &metadataOutput{}
|
output := &metadataOutput{}
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
// variable "AWS_EC2_METADATA_DISABLED=true". This environment variable set to
|
// variable "AWS_EC2_METADATA_DISABLED=true". This environment variable set to
|
||||||
// true instructs the SDK to disable the EC2 Metadata client. The client cannot
|
// true instructs the SDK to disable the EC2 Metadata client. The client cannot
|
||||||
// be used while the environment variable is set to true, (case insensitive).
|
// be used while the environment variable is set to true, (case insensitive).
|
||||||
|
//
|
||||||
|
// The endpoint of the EC2 IMDS client can be configured via the environment
|
||||||
|
// variable, AWS_EC2_METADATA_SERVICE_ENDPOINT when creating the client with a
|
||||||
|
// Session. See aws/session#Options.EC2IMDSEndpoint for more details.
|
||||||
package ec2metadata
|
package ec2metadata
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -12,6 +16,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -69,6 +74,9 @@ func New(p client.ConfigProvider, cfgs ...*aws.Config) *EC2Metadata {
|
||||||
// a client when not using a session. Generally using just New with a session
|
// a client when not using a session. Generally using just New with a session
|
||||||
// is preferred.
|
// is preferred.
|
||||||
//
|
//
|
||||||
|
// Will remove the URL path from the endpoint provided to ensure the EC2 IMDS
|
||||||
|
// client is able to communicate with the EC2 IMDS API.
|
||||||
|
//
|
||||||
// If an unmodified HTTP client is provided from the stdlib default, or no client
|
// If an unmodified HTTP client is provided from the stdlib default, or no client
|
||||||
// the EC2RoleProvider's EC2Metadata HTTP client's timeout will be shortened.
|
// the EC2RoleProvider's EC2Metadata HTTP client's timeout will be shortened.
|
||||||
// To disable this set Config.EC2MetadataDisableTimeoutOverride to false. Enabled by default.
|
// To disable this set Config.EC2MetadataDisableTimeoutOverride to false. Enabled by default.
|
||||||
|
@ -86,6 +94,15 @@ func NewClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegio
|
||||||
cfg.MaxRetries = aws.Int(2)
|
cfg.MaxRetries = aws.Int(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if u, err := url.Parse(endpoint); err == nil {
|
||||||
|
// Remove path from the endpoint since it will be added by requests.
|
||||||
|
// This is an artifact of the SDK adding `/latest` to the endpoint for
|
||||||
|
// EC2 IMDS, but this is now moved to the operation definition.
|
||||||
|
u.Path = ""
|
||||||
|
u.RawPath = ""
|
||||||
|
endpoint = u.String()
|
||||||
|
}
|
||||||
|
|
||||||
svc := &EC2Metadata{
|
svc := &EC2Metadata{
|
||||||
Client: client.New(
|
Client: client.New(
|
||||||
cfg,
|
cfg,
|
||||||
|
|
|
@ -93,7 +93,7 @@ func decodeV3Endpoints(modelDef modelDefinition, opts DecodeModelOptions) (Resol
|
||||||
}
|
}
|
||||||
|
|
||||||
func custAddS3DualStack(p *partition) {
|
func custAddS3DualStack(p *partition) {
|
||||||
if p.ID != "aws" {
|
if !(p.ID == "aws" || p.ID == "aws-cn" || p.ID == "aws-us-gov") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -7,6 +7,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var regionValidationRegex = regexp.MustCompile(`^[[:alnum:]]([[:alnum:]\-]*[[:alnum:]])?$`)
|
||||||
|
|
||||||
type partitions []partition
|
type partitions []partition
|
||||||
|
|
||||||
func (ps partitions) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
|
func (ps partitions) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
|
||||||
|
@ -124,7 +126,7 @@ func (p partition) EndpointFor(service, region string, opts ...func(*Options)) (
|
||||||
|
|
||||||
defs := []endpoint{p.Defaults, s.Defaults}
|
defs := []endpoint{p.Defaults, s.Defaults}
|
||||||
|
|
||||||
return e.resolve(service, p.ID, region, p.DNSSuffix, defs, opt), nil
|
return e.resolve(service, p.ID, region, p.DNSSuffix, defs, opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func serviceList(ss services) []string {
|
func serviceList(ss services) []string {
|
||||||
|
@ -233,7 +235,7 @@ func getByPriority(s []string, p []string, def string) string {
|
||||||
return s[0]
|
return s[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e endpoint) resolve(service, partitionID, region, dnsSuffix string, defs []endpoint, opts Options) ResolvedEndpoint {
|
func (e endpoint) resolve(service, partitionID, region, dnsSuffix string, defs []endpoint, opts Options) (ResolvedEndpoint, error) {
|
||||||
var merged endpoint
|
var merged endpoint
|
||||||
for _, def := range defs {
|
for _, def := range defs {
|
||||||
merged.mergeIn(def)
|
merged.mergeIn(def)
|
||||||
|
@ -260,6 +262,10 @@ func (e endpoint) resolve(service, partitionID, region, dnsSuffix string, defs [
|
||||||
region = signingRegion
|
region = signingRegion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !validateInputRegion(region) {
|
||||||
|
return ResolvedEndpoint{}, fmt.Errorf("invalid region identifier format provided")
|
||||||
|
}
|
||||||
|
|
||||||
u := strings.Replace(hostname, "{service}", service, 1)
|
u := strings.Replace(hostname, "{service}", service, 1)
|
||||||
u = strings.Replace(u, "{region}", region, 1)
|
u = strings.Replace(u, "{region}", region, 1)
|
||||||
u = strings.Replace(u, "{dnsSuffix}", dnsSuffix, 1)
|
u = strings.Replace(u, "{dnsSuffix}", dnsSuffix, 1)
|
||||||
|
@ -274,7 +280,7 @@ func (e endpoint) resolve(service, partitionID, region, dnsSuffix string, defs [
|
||||||
SigningName: signingName,
|
SigningName: signingName,
|
||||||
SigningNameDerived: signingNameDerived,
|
SigningNameDerived: signingNameDerived,
|
||||||
SigningMethod: getByPriority(e.SignatureVersions, signerPriority, defaultSigner),
|
SigningMethod: getByPriority(e.SignatureVersions, signerPriority, defaultSigner),
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getEndpointScheme(protocols []string, disableSSL bool) string {
|
func getEndpointScheme(protocols []string, disableSSL bool) string {
|
||||||
|
@ -339,3 +345,7 @@ const (
|
||||||
boxedFalse
|
boxedFalse
|
||||||
boxedTrue
|
boxedTrue
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func validateInputRegion(region string) bool {
|
||||||
|
return regionValidationRegex.MatchString(region)
|
||||||
|
}
|
||||||
|
|
|
@ -9,7 +9,8 @@ func isErrConnectionReset(err error) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.Contains(err.Error(), "connection reset") ||
|
if strings.Contains(err.Error(), "use of closed network connection") ||
|
||||||
|
strings.Contains(err.Error(), "connection reset") ||
|
||||||
strings.Contains(err.Error(), "broken pipe") {
|
strings.Contains(err.Error(), "broken pipe") {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue