Merge branch 'master' into feature/vgpu-profiles

This commit is contained in:
Thor K. Høgås 2020-04-15 12:02:37 +02:00 committed by GitHub
commit ebfc5bcdcb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
736 changed files with 79127 additions and 118483 deletions

View file

@ -80,9 +80,9 @@ jobs:
check-lint:
executor: golang
resource_class: large
working_directory: /go/src/github.com/hashicorp/packer
steps:
- checkout
- run: git fetch --all
- run:
command: make ci-lint
no_output_timeout: 30m

1
.gitattributes vendored
View file

@ -3,6 +3,7 @@
*.sh text eol=lf
*.json text eol=lf
*.md text eol=lf
*.mdx text eol=lf
*.ps1 text eol=lf
*.hcl text eol=lf
go.mod text eol=lf

View file

@ -3,12 +3,19 @@
**New Builder** azure-dtl allows creation of devtestlabs images in Azure. [GH-8987]
### IMPROVEMENTS:
* builder/azure: Add shared image destination for azure-chroot [GH-9021]
* builder/azure: Data disk names are now randomly generated [GH-8986]
* builder/google: Allow `source_image_project_id` to be a list of several
projects to search. [GH-8679]
* builder/oracle-oci: Allow Instance Principal Auth for Oracle OCI builder
[GH-8893]
* core/hcl2: Set `packer_build_name` and `packer_builder_type` variables for
builder provisioners and post-processors [GH-8956]
* provisioner/ansible: Add option to not use localhost proxy adapter. Removes
need for ansible connection_plugin when using WinRM. [GH-8625]
* provisioner/powershell: Add cleanup step to remove temporarily created
scripts; cleanup can be skipped by setting the `skip_clean` option
[GH-8908]
### Bug Fixes:
* builder/amazon: Fix bug with launch_block_device_mappings in spot instances.
@ -18,6 +25,8 @@
* builder/qemu: Remove `net_device` pre-validation [GH-8979]
* builder/vsphere-iso: disk_size is no longer required if storage is defined
[GH-8975]
* core: Fix crash in wrapperreadline helper when calling `os.NewFile` on
unknown file descriptor [GH-9037]
* core: Make sure CLI variables supersede variables from var files [GH-8964]
* provisioner/powershell: Fix integer decoding issue in the execution policy
parser [GH-8997]

View file

@ -14,8 +14,8 @@
/builder/jdcloud/ @XiaohanLiang @remrain
/website/pages/docs/builders/jdcloud* @XiaohanLiang @remrain
/builder/linode/ @displague @ctreatma @stvnjacobs
/website/pages/docs/builders/linode* @displague @ctreatma @stvnjacobs
/builder/linode/ @displague @ctreatma @stvnjacobs @charliekenney23 @phillc
/website/pages/docs/builders/linode* @displague @ctreatma @stvnjacobs @charliekenney23 @phillc
/builder/lxc/ @ChrisLundquist
/website/pages/docs/builders/lxc* @ChrisLundquist
@ -59,6 +59,10 @@
/builder/osc/ @marinsalinas
/website/pages/docs/builders/osc* @marinsalinas
/builder/tencentcloud/ @likexian
/website/pages/docs/builders/tencentcloud* @likexian
# provisioners

View file

@ -16,7 +16,9 @@ EXECUTABLE_FILES=$(shell find . -type f -executable | egrep -v '^\./(website/[ve
GIT_DIRTY=$(shell test -n "`git status --porcelain`" && echo "+CHANGES" || true)
GIT_COMMIT=$(shell git rev-parse --short HEAD)
GIT_IMPORT=github.com/hashicorp/packer/version
GOLDFLAGS=-X $(GIT_IMPORT).GitCommit=$(GIT_COMMIT)$(GIT_DIRTY)
UNAME_S := $(shell uname -s)
LDFLAGS=-s -w
GOLDFLAGS=-X $(GIT_IMPORT).GitCommit=$(GIT_COMMIT)$(GIT_DIRTY) $(LDFLAGS)
export GOLDFLAGS
@ -84,8 +86,7 @@ lint: install-lint-deps ## Lint Go code
ci-lint: install-lint-deps ## On ci only lint newly added Go source files
@echo "==> Running linter on newly added Go source files..."
GO111MODULE=on golangci-lint run --new-from-rev=`git merge-base master HEAD` ./...
@GO111MODULE=on sh -c "$(CURDIR)/scripts/lint.sh"
fmt: ## Format Go code
@go fmt ./...

View file

@ -1,35 +0,0 @@
# appveyor.yml reference : http://www.appveyor.com/docs/appveyor-yml
version: "{build}"
skip_tags: true
branches:
only:
- master
os: Windows Server 2012 R2
environment:
GOPATH: c:\gopath
clone_folder: c:\gopath\src\github.com\hashicorp\packer
install:
- set GO111MODULE=off
- echo %Path%
- go version
- go env
build_script:
- git rev-parse HEAD
# go test $(go list ./... | grep -v vendor)
- ps: |
go.exe test -timeout=2m (go.exe list ./... `
|? { -not $_.Contains('/vendor/') } `
|? { $_ -ne 'github.com/hashicorp/packer/builder/parallels/common' } `
|? { $_ -ne 'github.com/hashicorp/packer/provisioner/ansible' })
test: off
deploy: off

View file

@ -160,7 +160,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false},
"secret_key": &hcldec.AttrSpec{Name: "secret_key", Type: cty.String, Required: false},
@ -182,7 +182,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"image_force_delete_snapshots": &hcldec.AttrSpec{Name: "image_force_delete_snapshots", Type: cty.Bool, Required: false},
"image_force_delete_instances": &hcldec.AttrSpec{Name: "image_force_delete_instances", Type: cty.Bool, Required: false},
"image_ignore_data_disks": &hcldec.AttrSpec{Name: "image_ignore_data_disks", Type: cty.Bool, Required: false},
"tags": &hcldec.BlockAttrsSpec{TypeName: "tags", ElementType: cty.String, Required: false},
"tags": &hcldec.AttrSpec{Name: "tags", Type: cty.Map(cty.String), Required: false},
"tag": &hcldec.BlockListSpec{TypeName: "tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"system_disk_mapping": &hcldec.BlockSpec{TypeName: "system_disk_mapping", Nested: hcldec.ObjectSpec((*FlatAlicloudDiskDevice)(nil).HCL2Spec())},
"image_disk_mappings": &hcldec.BlockListSpec{TypeName: "image_disk_mappings", Nested: hcldec.ObjectSpec((*FlatAlicloudDiskDevice)(nil).HCL2Spec())},

View file

@ -91,7 +91,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"ami_name": &hcldec.AttrSpec{Name: "ami_name", Type: cty.String, Required: false},
"ami_description": &hcldec.AttrSpec{Name: "ami_description", Type: cty.String, Required: false},
@ -101,7 +101,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"ami_product_codes": &hcldec.AttrSpec{Name: "ami_product_codes", Type: cty.List(cty.String), Required: false},
"ami_regions": &hcldec.AttrSpec{Name: "ami_regions", Type: cty.List(cty.String), Required: false},
"skip_region_validation": &hcldec.AttrSpec{Name: "skip_region_validation", Type: cty.Bool, Required: false},
"tags": &hcldec.BlockAttrsSpec{TypeName: "tags", ElementType: cty.String, Required: false},
"tags": &hcldec.AttrSpec{Name: "tags", Type: cty.Map(cty.String), Required: false},
"tag": &hcldec.BlockListSpec{TypeName: "tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"ena_support": &hcldec.AttrSpec{Name: "ena_support", Type: cty.Bool, Required: false},
"sriov_support": &hcldec.AttrSpec{Name: "sriov_support", Type: cty.Bool, Required: false},
@ -109,9 +109,9 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"force_delete_snapshot": &hcldec.AttrSpec{Name: "force_delete_snapshot", Type: cty.Bool, Required: false},
"encrypt_boot": &hcldec.AttrSpec{Name: "encrypt_boot", Type: cty.Bool, Required: false},
"kms_key_id": &hcldec.AttrSpec{Name: "kms_key_id", Type: cty.String, Required: false},
"region_kms_key_ids": &hcldec.BlockAttrsSpec{TypeName: "region_kms_key_ids", ElementType: cty.String, Required: false},
"region_kms_key_ids": &hcldec.AttrSpec{Name: "region_kms_key_ids", Type: cty.Map(cty.String), Required: false},
"skip_save_build_region": &hcldec.AttrSpec{Name: "skip_save_build_region", Type: cty.Bool, Required: false},
"snapshot_tags": &hcldec.BlockAttrsSpec{TypeName: "snapshot_tags", ElementType: cty.String, Required: false},
"snapshot_tags": &hcldec.AttrSpec{Name: "snapshot_tags", Type: cty.Map(cty.String), Required: false},
"snapshot_tag": &hcldec.BlockListSpec{TypeName: "snapshot_tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"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},
@ -144,7 +144,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"root_volume_type": &hcldec.AttrSpec{Name: "root_volume_type", Type: cty.String, Required: false},
"source_ami": &hcldec.AttrSpec{Name: "source_ami", Type: cty.String, Required: false},
"source_ami_filter": &hcldec.BlockSpec{TypeName: "source_ami_filter", Nested: hcldec.ObjectSpec((*common.FlatAmiFilterOptions)(nil).HCL2Spec())},
"root_volume_tags": &hcldec.BlockAttrsSpec{TypeName: "root_volume_tags", ElementType: cty.String, Required: false},
"root_volume_tags": &hcldec.AttrSpec{Name: "root_volume_tags", Type: cty.Map(cty.String), Required: false},
"root_volume_tag": &hcldec.BlockListSpec{TypeName: "root_volume_tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"ami_architecture": &hcldec.AttrSpec{Name: "ami_architecture", Type: cty.String, Required: false},
}

View file

@ -28,7 +28,7 @@ func (*AmiFilterOptions) FlatMapstructure() interface{ HCL2Spec() map[string]hcl
// The decoded values from this spec will then be applied to a FlatAmiFilterOptions.
func (*FlatAmiFilterOptions) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{
"filters": &hcldec.BlockAttrsSpec{TypeName: "filters", ElementType: cty.String, Required: false},
"filters": &hcldec.AttrSpec{Name: "filters", Type: cty.Map(cty.String), Required: false},
"filter": &hcldec.BlockListSpec{TypeName: "filter", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"owners": &hcldec.AttrSpec{Name: "owners", Type: cty.List(cty.String), Required: false},
"most_recent": &hcldec.AttrSpec{Name: "most_recent", Type: cty.Bool, Required: false},
@ -80,7 +80,7 @@ func (*SecurityGroupFilterOptions) FlatMapstructure() interface{ HCL2Spec() map[
// The decoded values from this spec will then be applied to a FlatSecurityGroupFilterOptions.
func (*FlatSecurityGroupFilterOptions) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{
"filters": &hcldec.BlockAttrsSpec{TypeName: "filters", ElementType: cty.String, Required: false},
"filters": &hcldec.AttrSpec{Name: "filters", Type: cty.Map(cty.String), Required: false},
"filter": &hcldec.BlockListSpec{TypeName: "filter", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
}
return s
@ -134,7 +134,7 @@ func (*SubnetFilterOptions) FlatMapstructure() interface{ HCL2Spec() map[string]
// The decoded values from this spec will then be applied to a FlatSubnetFilterOptions.
func (*FlatSubnetFilterOptions) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{
"filters": &hcldec.BlockAttrsSpec{TypeName: "filters", ElementType: cty.String, Required: false},
"filters": &hcldec.AttrSpec{Name: "filters", Type: cty.Map(cty.String), Required: false},
"filter": &hcldec.BlockListSpec{TypeName: "filter", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"most_free": &hcldec.AttrSpec{Name: "most_free", Type: cty.Bool, Required: false},
"random": &hcldec.AttrSpec{Name: "random", Type: cty.Bool, Required: false},
@ -161,7 +161,7 @@ func (*VpcFilterOptions) FlatMapstructure() interface{ HCL2Spec() map[string]hcl
// The decoded values from this spec will then be applied to a FlatVpcFilterOptions.
func (*FlatVpcFilterOptions) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{
"filters": &hcldec.BlockAttrsSpec{TypeName: "filters", ElementType: cty.String, Required: false},
"filters": &hcldec.AttrSpec{Name: "filters", Type: cty.Map(cty.String), Required: false},
"filter": &hcldec.BlockListSpec{TypeName: "filter", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
}
return s

View file

@ -148,7 +148,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false},
"custom_endpoint_ec2": &hcldec.AttrSpec{Name: "custom_endpoint_ec2", Type: cty.String, Required: false},
@ -170,7 +170,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"ami_groups": &hcldec.AttrSpec{Name: "ami_groups", Type: cty.List(cty.String), Required: false},
"ami_product_codes": &hcldec.AttrSpec{Name: "ami_product_codes", Type: cty.List(cty.String), Required: false},
"ami_regions": &hcldec.AttrSpec{Name: "ami_regions", Type: cty.List(cty.String), Required: false},
"tags": &hcldec.BlockAttrsSpec{TypeName: "tags", ElementType: cty.String, Required: false},
"tags": &hcldec.AttrSpec{Name: "tags", Type: cty.Map(cty.String), Required: false},
"tag": &hcldec.BlockListSpec{TypeName: "tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"ena_support": &hcldec.AttrSpec{Name: "ena_support", Type: cty.Bool, Required: false},
"sriov_support": &hcldec.AttrSpec{Name: "sriov_support", Type: cty.Bool, Required: false},
@ -178,9 +178,9 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"force_delete_snapshot": &hcldec.AttrSpec{Name: "force_delete_snapshot", Type: cty.Bool, Required: false},
"encrypt_boot": &hcldec.AttrSpec{Name: "encrypt_boot", Type: cty.Bool, Required: false},
"kms_key_id": &hcldec.AttrSpec{Name: "kms_key_id", Type: cty.String, Required: false},
"region_kms_key_ids": &hcldec.BlockAttrsSpec{TypeName: "region_kms_key_ids", ElementType: cty.String, Required: false},
"region_kms_key_ids": &hcldec.AttrSpec{Name: "region_kms_key_ids", Type: cty.Map(cty.String), Required: false},
"skip_save_build_region": &hcldec.AttrSpec{Name: "skip_save_build_region", Type: cty.Bool, Required: false},
"snapshot_tags": &hcldec.BlockAttrsSpec{TypeName: "snapshot_tags", ElementType: cty.String, Required: false},
"snapshot_tags": &hcldec.AttrSpec{Name: "snapshot_tags", Type: cty.Map(cty.String), Required: false},
"snapshot_tag": &hcldec.BlockListSpec{TypeName: "snapshot_tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"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},
@ -196,7 +196,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"shutdown_behavior": &hcldec.AttrSpec{Name: "shutdown_behavior", Type: cty.String, Required: false},
"instance_type": &hcldec.AttrSpec{Name: "instance_type", Type: cty.String, Required: false},
"security_group_filter": &hcldec.BlockSpec{TypeName: "security_group_filter", Nested: hcldec.ObjectSpec((*common.FlatSecurityGroupFilterOptions)(nil).HCL2Spec())},
"run_tags": &hcldec.BlockAttrsSpec{TypeName: "run_tags", ElementType: cty.String, Required: false},
"run_tags": &hcldec.AttrSpec{Name: "run_tags", Type: cty.Map(cty.String), Required: false},
"run_tag": &hcldec.BlockListSpec{TypeName: "run_tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"security_group_id": &hcldec.AttrSpec{Name: "security_group_id", Type: cty.String, Required: false},
"security_group_ids": &hcldec.AttrSpec{Name: "security_group_ids", Type: cty.List(cty.String), Required: false},
@ -205,7 +205,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"spot_instance_types": &hcldec.AttrSpec{Name: "spot_instance_types", Type: cty.List(cty.String), Required: false},
"spot_price": &hcldec.AttrSpec{Name: "spot_price", Type: cty.String, Required: false},
"spot_price_auto_product": &hcldec.AttrSpec{Name: "spot_price_auto_product", Type: cty.String, Required: false},
"spot_tags": &hcldec.BlockAttrsSpec{TypeName: "spot_tags", ElementType: cty.String, Required: false},
"spot_tags": &hcldec.AttrSpec{Name: "spot_tags", Type: cty.Map(cty.String), Required: false},
"spot_tag": &hcldec.BlockListSpec{TypeName: "spot_tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"subnet_filter": &hcldec.BlockSpec{TypeName: "subnet_filter", Nested: hcldec.ObjectSpec((*common.FlatSubnetFilterOptions)(nil).HCL2Spec())},
"subnet_id": &hcldec.AttrSpec{Name: "subnet_id", Type: cty.String, Required: false},
@ -259,7 +259,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"ssh_interface": &hcldec.AttrSpec{Name: "ssh_interface", Type: cty.String, Required: false},
"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())},
"run_volume_tags": &hcldec.BlockAttrsSpec{TypeName: "run_volume_tags", ElementType: cty.String, Required: false},
"run_volume_tags": &hcldec.AttrSpec{Name: "run_volume_tags", Type: cty.Map(cty.String), Required: false},
"no_ephemeral": &hcldec.AttrSpec{Name: "no_ephemeral", Type: cty.Bool, Required: false},
}
return s

View file

@ -192,7 +192,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false},
"custom_endpoint_ec2": &hcldec.AttrSpec{Name: "custom_endpoint_ec2", Type: cty.String, Required: false},
@ -219,7 +219,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"shutdown_behavior": &hcldec.AttrSpec{Name: "shutdown_behavior", Type: cty.String, Required: false},
"instance_type": &hcldec.AttrSpec{Name: "instance_type", Type: cty.String, Required: false},
"security_group_filter": &hcldec.BlockSpec{TypeName: "security_group_filter", Nested: hcldec.ObjectSpec((*common.FlatSecurityGroupFilterOptions)(nil).HCL2Spec())},
"run_tags": &hcldec.BlockAttrsSpec{TypeName: "run_tags", ElementType: cty.String, Required: false},
"run_tags": &hcldec.AttrSpec{Name: "run_tags", Type: cty.Map(cty.String), Required: false},
"run_tag": &hcldec.BlockListSpec{TypeName: "run_tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"security_group_id": &hcldec.AttrSpec{Name: "security_group_id", Type: cty.String, Required: false},
"security_group_ids": &hcldec.AttrSpec{Name: "security_group_ids", Type: cty.List(cty.String), Required: false},
@ -228,7 +228,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"spot_instance_types": &hcldec.AttrSpec{Name: "spot_instance_types", Type: cty.List(cty.String), Required: false},
"spot_price": &hcldec.AttrSpec{Name: "spot_price", Type: cty.String, Required: false},
"spot_price_auto_product": &hcldec.AttrSpec{Name: "spot_price_auto_product", Type: cty.String, Required: false},
"spot_tags": &hcldec.BlockAttrsSpec{TypeName: "spot_tags", ElementType: cty.String, Required: false},
"spot_tags": &hcldec.AttrSpec{Name: "spot_tags", Type: cty.Map(cty.String), Required: false},
"spot_tag": &hcldec.BlockListSpec{TypeName: "spot_tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"subnet_filter": &hcldec.BlockSpec{TypeName: "subnet_filter", Nested: hcldec.ObjectSpec((*common.FlatSubnetFilterOptions)(nil).HCL2Spec())},
"subnet_id": &hcldec.AttrSpec{Name: "subnet_id", Type: cty.String, Required: false},
@ -287,7 +287,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"ami_groups": &hcldec.AttrSpec{Name: "ami_groups", Type: cty.List(cty.String), Required: false},
"ami_product_codes": &hcldec.AttrSpec{Name: "ami_product_codes", Type: cty.List(cty.String), Required: false},
"ami_regions": &hcldec.AttrSpec{Name: "ami_regions", Type: cty.List(cty.String), Required: false},
"tags": &hcldec.BlockAttrsSpec{TypeName: "tags", ElementType: cty.String, Required: false},
"tags": &hcldec.AttrSpec{Name: "tags", Type: cty.Map(cty.String), Required: false},
"tag": &hcldec.BlockListSpec{TypeName: "tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"ena_support": &hcldec.AttrSpec{Name: "ena_support", Type: cty.Bool, Required: false},
"sriov_support": &hcldec.AttrSpec{Name: "sriov_support", Type: cty.Bool, Required: false},
@ -295,16 +295,16 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"force_delete_snapshot": &hcldec.AttrSpec{Name: "force_delete_snapshot", Type: cty.Bool, Required: false},
"encrypt_boot": &hcldec.AttrSpec{Name: "encrypt_boot", Type: cty.Bool, Required: false},
"kms_key_id": &hcldec.AttrSpec{Name: "kms_key_id", Type: cty.String, Required: false},
"region_kms_key_ids": &hcldec.BlockAttrsSpec{TypeName: "region_kms_key_ids", ElementType: cty.String, Required: false},
"region_kms_key_ids": &hcldec.AttrSpec{Name: "region_kms_key_ids", Type: cty.Map(cty.String), Required: false},
"skip_save_build_region": &hcldec.AttrSpec{Name: "skip_save_build_region", Type: cty.Bool, Required: false},
"snapshot_tags": &hcldec.BlockAttrsSpec{TypeName: "snapshot_tags", ElementType: cty.String, Required: false},
"snapshot_tags": &hcldec.AttrSpec{Name: "snapshot_tags", Type: cty.Map(cty.String), Required: false},
"snapshot_tag": &hcldec.BlockListSpec{TypeName: "snapshot_tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"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},
"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((*FlatBlockDevice)(nil).HCL2Spec())},
"ami_root_device": &hcldec.BlockSpec{TypeName: "ami_root_device", Nested: hcldec.ObjectSpec((*FlatRootBlockDevice)(nil).HCL2Spec())},
"run_volume_tags": &hcldec.BlockAttrsSpec{TypeName: "run_volume_tags", ElementType: cty.String, Required: false},
"run_volume_tags": &hcldec.AttrSpec{Name: "run_volume_tags", Type: cty.Map(cty.String), Required: false},
"ami_architecture": &hcldec.AttrSpec{Name: "ami_architecture", Type: cty.String, Required: false},
}
return s

View file

@ -47,7 +47,7 @@ func (*FlatBlockDevice) HCL2Spec() map[string]hcldec.Spec {
"volume_type": &hcldec.AttrSpec{Name: "volume_type", Type: cty.String, Required: false},
"volume_size": &hcldec.AttrSpec{Name: "volume_size", Type: cty.Number, Required: false},
"kms_key_id": &hcldec.AttrSpec{Name: "kms_key_id", Type: cty.String, Required: false},
"tags": &hcldec.BlockAttrsSpec{TypeName: "tags", ElementType: cty.String, Required: false},
"tags": &hcldec.AttrSpec{Name: "tags", Type: cty.Map(cty.String), Required: false},
"tag": &hcldec.BlockListSpec{TypeName: "tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
}
return s
@ -173,7 +173,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false},
"custom_endpoint_ec2": &hcldec.AttrSpec{Name: "custom_endpoint_ec2", Type: cty.String, Required: false},
@ -200,7 +200,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"shutdown_behavior": &hcldec.AttrSpec{Name: "shutdown_behavior", Type: cty.String, Required: false},
"instance_type": &hcldec.AttrSpec{Name: "instance_type", Type: cty.String, Required: false},
"security_group_filter": &hcldec.BlockSpec{TypeName: "security_group_filter", Nested: hcldec.ObjectSpec((*common.FlatSecurityGroupFilterOptions)(nil).HCL2Spec())},
"run_tags": &hcldec.BlockAttrsSpec{TypeName: "run_tags", ElementType: cty.String, Required: false},
"run_tags": &hcldec.AttrSpec{Name: "run_tags", Type: cty.Map(cty.String), Required: false},
"run_tag": &hcldec.BlockListSpec{TypeName: "run_tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"security_group_id": &hcldec.AttrSpec{Name: "security_group_id", Type: cty.String, Required: false},
"security_group_ids": &hcldec.AttrSpec{Name: "security_group_ids", Type: cty.List(cty.String), Required: false},
@ -209,7 +209,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"spot_instance_types": &hcldec.AttrSpec{Name: "spot_instance_types", Type: cty.List(cty.String), Required: false},
"spot_price": &hcldec.AttrSpec{Name: "spot_price", Type: cty.String, Required: false},
"spot_price_auto_product": &hcldec.AttrSpec{Name: "spot_price_auto_product", Type: cty.String, Required: false},
"spot_tags": &hcldec.BlockAttrsSpec{TypeName: "spot_tags", ElementType: cty.String, Required: false},
"spot_tags": &hcldec.AttrSpec{Name: "spot_tags", Type: cty.Map(cty.String), Required: false},
"spot_tag": &hcldec.BlockListSpec{TypeName: "spot_tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"subnet_filter": &hcldec.BlockSpec{TypeName: "subnet_filter", Nested: hcldec.ObjectSpec((*common.FlatSubnetFilterOptions)(nil).HCL2Spec())},
"subnet_id": &hcldec.AttrSpec{Name: "subnet_id", Type: cty.String, Required: false},
@ -264,7 +264,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"ena_support": &hcldec.AttrSpec{Name: "ena_support", Type: cty.Bool, Required: false},
"sriov_support": &hcldec.AttrSpec{Name: "sriov_support", Type: cty.Bool, Required: false},
"ebs_volumes": &hcldec.BlockListSpec{TypeName: "ebs_volumes", Nested: hcldec.ObjectSpec((*FlatBlockDevice)(nil).HCL2Spec())},
"run_volume_tags": &hcldec.BlockAttrsSpec{TypeName: "run_volume_tags", ElementType: cty.String, Required: false},
"run_volume_tags": &hcldec.AttrSpec{Name: "run_volume_tags", Type: cty.Map(cty.String), Required: false},
"run_volume_tag": &hcldec.BlockListSpec{TypeName: "run_volume_tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
}
return s

View file

@ -155,7 +155,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false},
"custom_endpoint_ec2": &hcldec.AttrSpec{Name: "custom_endpoint_ec2", Type: cty.String, Required: false},
@ -177,7 +177,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"ami_groups": &hcldec.AttrSpec{Name: "ami_groups", Type: cty.List(cty.String), Required: false},
"ami_product_codes": &hcldec.AttrSpec{Name: "ami_product_codes", Type: cty.List(cty.String), Required: false},
"ami_regions": &hcldec.AttrSpec{Name: "ami_regions", Type: cty.List(cty.String), Required: false},
"tags": &hcldec.BlockAttrsSpec{TypeName: "tags", ElementType: cty.String, Required: false},
"tags": &hcldec.AttrSpec{Name: "tags", Type: cty.Map(cty.String), Required: false},
"tag": &hcldec.BlockListSpec{TypeName: "tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"ena_support": &hcldec.AttrSpec{Name: "ena_support", Type: cty.Bool, Required: false},
"sriov_support": &hcldec.AttrSpec{Name: "sriov_support", Type: cty.Bool, Required: false},
@ -185,9 +185,9 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"force_delete_snapshot": &hcldec.AttrSpec{Name: "force_delete_snapshot", Type: cty.Bool, Required: false},
"encrypt_boot": &hcldec.AttrSpec{Name: "encrypt_boot", Type: cty.Bool, Required: false},
"kms_key_id": &hcldec.AttrSpec{Name: "kms_key_id", Type: cty.String, Required: false},
"region_kms_key_ids": &hcldec.BlockAttrsSpec{TypeName: "region_kms_key_ids", ElementType: cty.String, Required: false},
"region_kms_key_ids": &hcldec.AttrSpec{Name: "region_kms_key_ids", Type: cty.Map(cty.String), Required: false},
"skip_save_build_region": &hcldec.AttrSpec{Name: "skip_save_build_region", Type: cty.Bool, Required: false},
"snapshot_tags": &hcldec.BlockAttrsSpec{TypeName: "snapshot_tags", ElementType: cty.String, Required: false},
"snapshot_tags": &hcldec.AttrSpec{Name: "snapshot_tags", Type: cty.Map(cty.String), Required: false},
"snapshot_tag": &hcldec.BlockListSpec{TypeName: "snapshot_tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"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},
@ -203,7 +203,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"shutdown_behavior": &hcldec.AttrSpec{Name: "shutdown_behavior", Type: cty.String, Required: false},
"instance_type": &hcldec.AttrSpec{Name: "instance_type", Type: cty.String, Required: false},
"security_group_filter": &hcldec.BlockSpec{TypeName: "security_group_filter", Nested: hcldec.ObjectSpec((*common.FlatSecurityGroupFilterOptions)(nil).HCL2Spec())},
"run_tags": &hcldec.BlockAttrsSpec{TypeName: "run_tags", ElementType: cty.String, Required: false},
"run_tags": &hcldec.AttrSpec{Name: "run_tags", Type: cty.Map(cty.String), Required: false},
"run_tag": &hcldec.BlockListSpec{TypeName: "run_tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"security_group_id": &hcldec.AttrSpec{Name: "security_group_id", Type: cty.String, Required: false},
"security_group_ids": &hcldec.AttrSpec{Name: "security_group_ids", Type: cty.List(cty.String), Required: false},
@ -212,7 +212,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"spot_instance_types": &hcldec.AttrSpec{Name: "spot_instance_types", Type: cty.List(cty.String), Required: false},
"spot_price": &hcldec.AttrSpec{Name: "spot_price", Type: cty.String, Required: false},
"spot_price_auto_product": &hcldec.AttrSpec{Name: "spot_price_auto_product", Type: cty.String, Required: false},
"spot_tags": &hcldec.BlockAttrsSpec{TypeName: "spot_tags", ElementType: cty.String, Required: false},
"spot_tags": &hcldec.AttrSpec{Name: "spot_tags", Type: cty.Map(cty.String), Required: false},
"spot_tag": &hcldec.BlockListSpec{TypeName: "spot_tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"subnet_filter": &hcldec.BlockSpec{TypeName: "subnet_filter", Nested: hcldec.ObjectSpec((*common.FlatSubnetFilterOptions)(nil).HCL2Spec())},
"subnet_id": &hcldec.AttrSpec{Name: "subnet_id", Type: cty.String, Required: false},

View file

@ -130,7 +130,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"cloud_environment_name": &hcldec.AttrSpec{Name: "cloud_environment_name", Type: cty.String, Required: false},
"client_id": &hcldec.AttrSpec{Name: "client_id", Type: cty.String, Required: false},
@ -163,7 +163,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"managed_image_os_disk_snapshot_name": &hcldec.AttrSpec{Name: "managed_image_os_disk_snapshot_name", Type: cty.String, Required: false},
"managed_image_data_disk_snapshot_prefix": &hcldec.AttrSpec{Name: "managed_image_data_disk_snapshot_prefix", Type: cty.String, Required: false},
"managed_image_zone_resilient": &hcldec.AttrSpec{Name: "managed_image_zone_resilient", Type: cty.Bool, Required: false},
"azure_tags": &hcldec.BlockAttrsSpec{TypeName: "azure_tags", ElementType: cty.String, Required: false},
"azure_tags": &hcldec.AttrSpec{Name: "azure_tags", Type: cty.Map(cty.String), Required: false},
"azure_tag": &hcldec.BlockListSpec{TypeName: "azure_tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"resource_group_name": &hcldec.AttrSpec{Name: "resource_group_name", Type: cty.String, Required: false},
"storage_account": &hcldec.AttrSpec{Name: "storage_account", Type: cty.String, Required: false},

View file

@ -24,14 +24,14 @@ import (
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
"github.com/mitchellh/mapstructure"
"github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute"
"github.com/Azure/go-autorest/autorest/azure"
"github.com/Azure/go-autorest/autorest/to"
)
// BuilderId is the unique ID for this builder
const BuilderId = "azure.chroot"
// BuilderID is the unique ID for this builder
const BuilderID = "azure.chroot"
// Config is the configuration that is chained through the steps and settable
// from the template.
@ -76,9 +76,6 @@ type Config struct {
// `/etc/resolv.conf`. You may need to do this if you're building an image that uses systemd.
CopyFiles []string `mapstructure:"copy_files"`
// The name of the temporary disk that will be created in the resource group of the VM that Packer is
// running on. Will be generated if not set.
TemporaryOSDiskName string `mapstructure:"temporary_os_disk_name"`
// Try to resize the OS disk to this size on the first copy. Disks can only be englarged. If not specified,
// the disk will keep its original size. Required when using `from_scratch`
OSDiskSizeGB int32 `mapstructure:"os_disk_size_gb"`
@ -88,15 +85,25 @@ type Config struct {
// The [cache type](https://docs.microsoft.com/en-us/rest/api/compute/images/createorupdate#cachingtypes)
// specified in the resulting image and for attaching it to the Packer VM. Defaults to `ReadOnly`
OSDiskCacheType string `mapstructure:"os_disk_cache_type"`
// If set to `true`, leaves the temporary disk behind in the Packer VM resource group. Defaults to `false`
OSDiskSkipCleanup bool `mapstructure:"os_disk_skip_cleanup"`
// The image to create using this build.
ImageResourceID string `mapstructure:"image_resource_id" required:"true"`
// The [Hyper-V generation type](https://docs.microsoft.com/en-us/rest/api/compute/images/createorupdate#hypervgenerationtypes).
// The [Hyper-V generation type](https://docs.microsoft.com/en-us/rest/api/compute/images/createorupdate#hypervgenerationtypes) for Managed Image output.
// Defaults to `V1`.
ImageHyperVGeneration string `mapstructure:"image_hyperv_generation"`
// The id of the temporary disk that will be created. Will be generated if not set.
TemporaryOSDiskID string `mapstructure:"temporary_os_disk_id"`
// The id of the temporary snapshot that will be created. Will be generated if not set.
TemporaryOSDiskSnapshotID string `mapstructure:"temporary_os_disk_snapshot_id"`
// If set to `true`, leaves the temporary disks and snapshots behind in the Packer VM resource group. Defaults to `false`
SkipCleanup bool `mapstructure:"skip_cleanup"`
// The managed image to create using this build.
ImageResourceID string `mapstructure:"image_resource_id"`
// The shared image to create using this build.
SharedImageGalleryDestination SharedImageGalleryDestination `mapstructure:"shared_image_destination"`
ctx interpolate.Context
}
@ -118,11 +125,15 @@ type Builder struct {
runner multistep.Runner
}
// verify interface implementation
var _ packer.Builder = &Builder{}
func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() }
func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
b.config.ctx.Funcs = azcommon.TemplateFuncs
b.config.ctx.Funcs["vm"] = CreateVMMetadataTemplateFunc()
md := &mapstructure.Metadata{}
err := config.Decode(&b.config, &config.DecodeOpts{
Interpolate: true,
InterpolateContext: &b.config.ctx,
@ -136,6 +147,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
"mount_path",
},
},
Metadata: md,
}, raws...)
if err != nil {
return nil, nil, err
@ -183,12 +195,23 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
b.config.MountPartition = "1"
}
if b.config.TemporaryOSDiskName == "" {
if def, err := interpolate.Render("PackerTemp-{{timestamp}}", &b.config.ctx); err == nil {
b.config.TemporaryOSDiskName = def
if b.config.TemporaryOSDiskID == "" {
if def, err := interpolate.Render(
"/subscriptions/{{ vm `subscription_id` }}/resourceGroups/{{ vm `resource_group` }}/providers/Microsoft.Compute/disks/PackerTemp-osdisk-{{timestamp}}",
&b.config.ctx); err == nil {
b.config.TemporaryOSDiskID = def
} else {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("unable to render temporary disk name: %s", err))
errs = packer.MultiErrorAppend(errs, fmt.Errorf("unable to render temporary disk id: %s", err))
}
}
if b.config.TemporaryOSDiskSnapshotID == "" {
if def, err := interpolate.Render(
"/subscriptions/{{ vm `subscription_id` }}/resourceGroups/{{ vm `resource_group` }}/providers/Microsoft.Compute/snapshots/PackerTemp-osdisk-snapshot-{{timestamp}}",
&b.config.ctx); err == nil {
b.config.TemporaryOSDiskSnapshotID = def
} else {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("unable to render temporary snapshot id: %s", err))
}
}
@ -241,9 +264,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("os_disk_storage_account_type: %v", err))
}
if b.config.ImageResourceID == "" {
errs = packer.MultiErrorAppend(errs, errors.New("image_resource_id is required"))
} else {
if b.config.ImageResourceID != "" {
r, err := azure.ParseResourceID(b.config.ImageResourceID)
if err != nil ||
!strings.EqualFold(r.Provider, "Microsoft.Compute") ||
@ -253,6 +274,20 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
}
}
if azcommon.StringsContains(md.Keys, "shared_image_destination") {
e, w := b.config.SharedImageGalleryDestination.Validate("shared_image_destination")
if len(e) > 0 {
errs = packer.MultiErrorAppend(errs, e...)
}
if len(w) > 0 {
warns = append(warns, w...)
}
}
if !azcommon.StringsContains(md.Keys, "shared_image_destination") && b.config.ImageResourceID == "" {
errs = packer.MultiErrorAppend(errs, errors.New("image_resource_id or shared_image_destination is required"))
}
if err := checkHyperVGeneration(b.config.ImageHyperVGeneration); err != nil {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("image_hyperv_generation: %v", err))
}
@ -336,104 +371,8 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
state.Put("instance", info)
// Build the steps
var steps []multistep.Step
if b.config.FromScratch {
steps = append(steps,
&StepCreateNewDisk{
SubscriptionID: info.SubscriptionID,
ResourceGroup: info.ResourceGroupName,
DiskName: b.config.TemporaryOSDiskName,
DiskSizeGB: b.config.OSDiskSizeGB,
DiskStorageAccountType: b.config.OSDiskStorageAccountType,
HyperVGeneration: b.config.ImageHyperVGeneration,
Location: info.Location,
})
} else {
switch b.config.sourceType {
case sourcePlatformImage:
if pi, err := client.ParsePlatformImageURN(b.config.Source); err == nil {
if strings.EqualFold(pi.Version, "latest") {
vmi, err := azcli.VirtualMachineImagesClient().GetLatest(ctx, pi.Publisher, pi.Offer, pi.Sku, info.Location)
if err != nil {
return nil, fmt.Errorf("error retieving latest version of %q: %v", b.config.Source, err)
}
pi.Version = to.String(vmi.Name)
log.Println("Resolved latest version of source image:", pi.Version)
}
steps = append(steps,
&StepCreateNewDisk{
SubscriptionID: info.SubscriptionID,
ResourceGroup: info.ResourceGroupName,
DiskName: b.config.TemporaryOSDiskName,
DiskSizeGB: b.config.OSDiskSizeGB,
DiskStorageAccountType: b.config.OSDiskStorageAccountType,
HyperVGeneration: b.config.ImageHyperVGeneration,
Location: info.Location,
PlatformImage: pi,
SkipCleanup: b.config.OSDiskSkipCleanup,
})
} else {
panic("Unknown image source: " + b.config.Source)
}
case sourceDisk:
steps = append(steps,
&StepVerifySourceDisk{
SourceDiskResourceID: b.config.Source,
SubscriptionID: info.SubscriptionID,
Location: info.Location,
},
&StepCreateNewDisk{
SubscriptionID: info.SubscriptionID,
ResourceGroup: info.ResourceGroupName,
DiskName: b.config.TemporaryOSDiskName,
DiskSizeGB: b.config.OSDiskSizeGB,
DiskStorageAccountType: b.config.OSDiskStorageAccountType,
HyperVGeneration: b.config.ImageHyperVGeneration,
SourceDiskResourceID: b.config.Source,
Location: info.Location,
SkipCleanup: b.config.OSDiskSkipCleanup,
})
default:
panic(fmt.Errorf("Unknown source type: %+q", b.config.sourceType))
}
}
steps = append(steps,
&StepAttachDisk{}, // uses os_disk_resource_id and sets 'device' in stateBag
&chroot.StepPreMountCommands{
Commands: b.config.PreMountCommands,
},
&StepMountDevice{
MountOptions: b.config.MountOptions,
MountPartition: b.config.MountPartition,
MountPath: b.config.MountPath,
},
&chroot.StepPostMountCommands{
Commands: b.config.PostMountCommands,
},
&chroot.StepMountExtra{
ChrootMounts: b.config.ChrootMounts,
},
&chroot.StepCopyFiles{
Files: b.config.CopyFiles,
},
&chroot.StepChrootProvision{},
&chroot.StepEarlyCleanup{},
&StepCreateImage{
ImageResourceID: b.config.ImageResourceID,
ImageOSState: string(compute.Generalized),
OSDiskCacheType: b.config.OSDiskCacheType,
OSDiskStorageAccountType: b.config.OSDiskStorageAccountType,
Location: info.Location,
},
)
// Build the step array from the config
steps := buildsteps(b.config, info)
// Run!
b.runner = common.NewRunner(steps, b.config.PackerConfig, ui)
@ -446,12 +385,149 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
// Build the artifact and return it
artifact := &azcommon.Artifact{
Resources: []string{b.config.ImageResourceID},
BuilderIdValue: BuilderId,
BuilderIdValue: BuilderID,
StateData: map[string]interface{}{"generated_data": state.Get("generated_data")},
AzureClientSet: azcli,
}
if b.config.ImageResourceID != "" {
artifact.Resources = append(artifact.Resources, b.config.ImageResourceID)
}
if e, _ := b.config.SharedImageGalleryDestination.Validate(""); len(e) == 0 {
artifact.Resources = append(artifact.Resources, b.config.SharedImageGalleryDestination.ResourceID(info.SubscriptionID))
}
if b.config.SkipCleanup {
if d, ok := state.GetOk(stateBagKey_OSDiskResourceID); ok {
artifact.Resources = append(artifact.Resources, d.(string))
}
if d, ok := state.GetOk(stateBagKey_OSDiskSnapshotResourceID); ok {
artifact.Resources = append(artifact.Resources, d.(string))
}
}
return artifact, nil
}
var _ packer.Builder = &Builder{}
func buildsteps(config Config, info *client.ComputeInfo) []multistep.Step {
// Build the steps
var steps []multistep.Step
addSteps := func(s ...multistep.Step) { // convenience
steps = append(steps, s...)
}
e, _ := config.SharedImageGalleryDestination.Validate("")
hasValidSharedImage := len(e) == 0
if hasValidSharedImage {
// validate destination early
addSteps(
&StepVerifySharedImageDestination{
Image: config.SharedImageGalleryDestination,
Location: info.Location,
},
)
}
if config.FromScratch {
addSteps(&StepCreateNewDisk{
ResourceID: config.TemporaryOSDiskID,
DiskSizeGB: config.OSDiskSizeGB,
DiskStorageAccountType: config.OSDiskStorageAccountType,
HyperVGeneration: config.ImageHyperVGeneration,
Location: info.Location})
} else {
switch config.sourceType {
case sourcePlatformImage:
if pi, err := client.ParsePlatformImageURN(config.Source); err == nil {
if strings.EqualFold(pi.Version, "latest") {
addSteps(
&StepResolvePlatformImageVersion{
PlatformImage: pi,
Location: info.Location,
})
}
addSteps(
&StepCreateNewDisk{
ResourceID: config.TemporaryOSDiskID,
DiskSizeGB: config.OSDiskSizeGB,
DiskStorageAccountType: config.OSDiskStorageAccountType,
HyperVGeneration: config.ImageHyperVGeneration,
Location: info.Location,
PlatformImage: pi,
SkipCleanup: config.SkipCleanup,
})
} else {
panic("Couldn't parse platfrom image urn: " + config.Source + " err: " + err.Error())
}
case sourceDisk:
addSteps(
&StepVerifySourceDisk{
SourceDiskResourceID: config.Source,
Location: info.Location,
},
&StepCreateNewDisk{
ResourceID: config.TemporaryOSDiskID,
DiskSizeGB: config.OSDiskSizeGB,
DiskStorageAccountType: config.OSDiskStorageAccountType,
HyperVGeneration: config.ImageHyperVGeneration,
SourceDiskResourceID: config.Source,
Location: info.Location,
SkipCleanup: config.SkipCleanup,
})
default:
panic(fmt.Errorf("Unknown source type: %+q", config.sourceType))
}
}
addSteps(
&StepAttachDisk{}, // uses os_disk_resource_id and sets 'device' in stateBag
&chroot.StepPreMountCommands{
Commands: config.PreMountCommands,
},
&StepMountDevice{
MountOptions: config.MountOptions,
MountPartition: config.MountPartition,
MountPath: config.MountPath,
},
&chroot.StepPostMountCommands{
Commands: config.PostMountCommands,
},
&chroot.StepMountExtra{
ChrootMounts: config.ChrootMounts,
},
&chroot.StepCopyFiles{
Files: config.CopyFiles,
},
&chroot.StepChrootProvision{},
&chroot.StepEarlyCleanup{},
)
if config.ImageResourceID != "" {
addSteps(&StepCreateImage{
ImageResourceID: config.ImageResourceID,
ImageOSState: string(compute.Generalized),
OSDiskCacheType: config.OSDiskCacheType,
OSDiskStorageAccountType: config.OSDiskStorageAccountType,
Location: info.Location,
})
}
if hasValidSharedImage {
addSteps(
&StepCreateSnapshot{
ResourceID: config.TemporaryOSDiskSnapshotID,
Location: info.Location,
SkipCleanup: config.SkipCleanup,
},
&StepCreateSharedImageVersion{
Destination: config.SharedImageGalleryDestination,
OSDiskCacheType: config.OSDiskCacheType,
Location: info.Location,
},
)
}
return steps
}

View file

@ -9,38 +9,40 @@ import (
// FlatConfig is an auto-generated flat version of Config.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatConfig struct {
PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name"`
PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type"`
PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug"`
PackerForce *bool `mapstructure:"packer_force" cty:"packer_force"`
PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error"`
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables"`
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables"`
CloudEnvironmentName *string `mapstructure:"cloud_environment_name" required:"false" cty:"cloud_environment_name"`
ClientID *string `mapstructure:"client_id" cty:"client_id"`
ClientSecret *string `mapstructure:"client_secret" cty:"client_secret"`
ClientCertPath *string `mapstructure:"client_cert_path" cty:"client_cert_path"`
ClientJWT *string `mapstructure:"client_jwt" cty:"client_jwt"`
ObjectID *string `mapstructure:"object_id" cty:"object_id"`
TenantID *string `mapstructure:"tenant_id" required:"false" cty:"tenant_id"`
SubscriptionID *string `mapstructure:"subscription_id" cty:"subscription_id"`
FromScratch *bool `mapstructure:"from_scratch" cty:"from_scratch"`
Source *string `mapstructure:"source" required:"true" cty:"source"`
CommandWrapper *string `mapstructure:"command_wrapper" cty:"command_wrapper"`
PreMountCommands []string `mapstructure:"pre_mount_commands" cty:"pre_mount_commands"`
MountOptions []string `mapstructure:"mount_options" cty:"mount_options"`
MountPartition *string `mapstructure:"mount_partition" cty:"mount_partition"`
MountPath *string `mapstructure:"mount_path" cty:"mount_path"`
PostMountCommands []string `mapstructure:"post_mount_commands" cty:"post_mount_commands"`
ChrootMounts [][]string `mapstructure:"chroot_mounts" cty:"chroot_mounts"`
CopyFiles []string `mapstructure:"copy_files" cty:"copy_files"`
TemporaryOSDiskName *string `mapstructure:"temporary_os_disk_name" cty:"temporary_os_disk_name"`
OSDiskSizeGB *int32 `mapstructure:"os_disk_size_gb" cty:"os_disk_size_gb"`
OSDiskStorageAccountType *string `mapstructure:"os_disk_storage_account_type" cty:"os_disk_storage_account_type"`
OSDiskCacheType *string `mapstructure:"os_disk_cache_type" cty:"os_disk_cache_type"`
OSDiskSkipCleanup *bool `mapstructure:"os_disk_skip_cleanup" cty:"os_disk_skip_cleanup"`
ImageResourceID *string `mapstructure:"image_resource_id" required:"true" cty:"image_resource_id"`
ImageHyperVGeneration *string `mapstructure:"image_hyperv_generation" cty:"image_hyperv_generation"`
PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name"`
PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type"`
PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug"`
PackerForce *bool `mapstructure:"packer_force" cty:"packer_force"`
PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error"`
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables"`
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables"`
CloudEnvironmentName *string `mapstructure:"cloud_environment_name" required:"false" cty:"cloud_environment_name"`
ClientID *string `mapstructure:"client_id" cty:"client_id"`
ClientSecret *string `mapstructure:"client_secret" cty:"client_secret"`
ClientCertPath *string `mapstructure:"client_cert_path" cty:"client_cert_path"`
ClientJWT *string `mapstructure:"client_jwt" cty:"client_jwt"`
ObjectID *string `mapstructure:"object_id" cty:"object_id"`
TenantID *string `mapstructure:"tenant_id" required:"false" cty:"tenant_id"`
SubscriptionID *string `mapstructure:"subscription_id" cty:"subscription_id"`
FromScratch *bool `mapstructure:"from_scratch" cty:"from_scratch"`
Source *string `mapstructure:"source" required:"true" cty:"source"`
CommandWrapper *string `mapstructure:"command_wrapper" cty:"command_wrapper"`
PreMountCommands []string `mapstructure:"pre_mount_commands" cty:"pre_mount_commands"`
MountOptions []string `mapstructure:"mount_options" cty:"mount_options"`
MountPartition *string `mapstructure:"mount_partition" cty:"mount_partition"`
MountPath *string `mapstructure:"mount_path" cty:"mount_path"`
PostMountCommands []string `mapstructure:"post_mount_commands" cty:"post_mount_commands"`
ChrootMounts [][]string `mapstructure:"chroot_mounts" cty:"chroot_mounts"`
CopyFiles []string `mapstructure:"copy_files" cty:"copy_files"`
OSDiskSizeGB *int32 `mapstructure:"os_disk_size_gb" cty:"os_disk_size_gb"`
OSDiskStorageAccountType *string `mapstructure:"os_disk_storage_account_type" cty:"os_disk_storage_account_type"`
OSDiskCacheType *string `mapstructure:"os_disk_cache_type" cty:"os_disk_cache_type"`
ImageHyperVGeneration *string `mapstructure:"image_hyperv_generation" cty:"image_hyperv_generation"`
TemporaryOSDiskID *string `mapstructure:"temporary_os_disk_id" cty:"temporary_os_disk_id"`
TemporaryOSDiskSnapshotID *string `mapstructure:"temporary_os_disk_snapshot_id" cty:"temporary_os_disk_snapshot_id"`
SkipCleanup *bool `mapstructure:"skip_cleanup" cty:"skip_cleanup"`
ImageResourceID *string `mapstructure:"image_resource_id" cty:"image_resource_id"`
SharedImageGalleryDestination *FlatSharedImageGalleryDestination `mapstructure:"shared_image_destination" cty:"shared_image_destination"`
}
// FlatMapstructure returns a new FlatConfig.
@ -55,38 +57,40 @@ func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec }
// The decoded values from this spec will then be applied to a FlatConfig.
func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{
"packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false},
"packer_builder_type": &hcldec.AttrSpec{Name: "packer_builder_type", Type: cty.String, Required: false},
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: cty.String, Required: false},
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
"cloud_environment_name": &hcldec.AttrSpec{Name: "cloud_environment_name", Type: cty.String, Required: false},
"client_id": &hcldec.AttrSpec{Name: "client_id", Type: cty.String, Required: false},
"client_secret": &hcldec.AttrSpec{Name: "client_secret", Type: cty.String, Required: false},
"client_cert_path": &hcldec.AttrSpec{Name: "client_cert_path", Type: cty.String, Required: false},
"client_jwt": &hcldec.AttrSpec{Name: "client_jwt", Type: cty.String, Required: false},
"object_id": &hcldec.AttrSpec{Name: "object_id", Type: cty.String, Required: false},
"tenant_id": &hcldec.AttrSpec{Name: "tenant_id", Type: cty.String, Required: false},
"subscription_id": &hcldec.AttrSpec{Name: "subscription_id", Type: cty.String, Required: false},
"from_scratch": &hcldec.AttrSpec{Name: "from_scratch", Type: cty.Bool, Required: false},
"source": &hcldec.AttrSpec{Name: "source", Type: cty.String, Required: false},
"command_wrapper": &hcldec.AttrSpec{Name: "command_wrapper", Type: cty.String, Required: false},
"pre_mount_commands": &hcldec.AttrSpec{Name: "pre_mount_commands", Type: cty.List(cty.String), Required: false},
"mount_options": &hcldec.AttrSpec{Name: "mount_options", Type: cty.List(cty.String), Required: false},
"mount_partition": &hcldec.AttrSpec{Name: "mount_partition", Type: cty.String, Required: false},
"mount_path": &hcldec.AttrSpec{Name: "mount_path", Type: cty.String, Required: false},
"post_mount_commands": &hcldec.AttrSpec{Name: "post_mount_commands", Type: cty.List(cty.String), Required: false},
"chroot_mounts": &hcldec.AttrSpec{Name: "chroot_mounts", Type: cty.List(cty.List(cty.String)), Required: false},
"copy_files": &hcldec.AttrSpec{Name: "copy_files", Type: cty.List(cty.String), Required: false},
"temporary_os_disk_name": &hcldec.AttrSpec{Name: "temporary_os_disk_name", Type: cty.String, Required: false},
"os_disk_size_gb": &hcldec.AttrSpec{Name: "os_disk_size_gb", Type: cty.Number, Required: false},
"os_disk_storage_account_type": &hcldec.AttrSpec{Name: "os_disk_storage_account_type", Type: cty.String, Required: false},
"os_disk_cache_type": &hcldec.AttrSpec{Name: "os_disk_cache_type", Type: cty.String, Required: false},
"os_disk_skip_cleanup": &hcldec.AttrSpec{Name: "os_disk_skip_cleanup", Type: cty.Bool, Required: false},
"image_resource_id": &hcldec.AttrSpec{Name: "image_resource_id", Type: cty.String, Required: false},
"image_hyperv_generation": &hcldec.AttrSpec{Name: "image_hyperv_generation", Type: cty.String, Required: false},
"packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false},
"packer_builder_type": &hcldec.AttrSpec{Name: "packer_builder_type", Type: cty.String, Required: false},
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: 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},
"cloud_environment_name": &hcldec.AttrSpec{Name: "cloud_environment_name", Type: cty.String, Required: false},
"client_id": &hcldec.AttrSpec{Name: "client_id", Type: cty.String, Required: false},
"client_secret": &hcldec.AttrSpec{Name: "client_secret", Type: cty.String, Required: false},
"client_cert_path": &hcldec.AttrSpec{Name: "client_cert_path", Type: cty.String, Required: false},
"client_jwt": &hcldec.AttrSpec{Name: "client_jwt", Type: cty.String, Required: false},
"object_id": &hcldec.AttrSpec{Name: "object_id", Type: cty.String, Required: false},
"tenant_id": &hcldec.AttrSpec{Name: "tenant_id", Type: cty.String, Required: false},
"subscription_id": &hcldec.AttrSpec{Name: "subscription_id", Type: cty.String, Required: false},
"from_scratch": &hcldec.AttrSpec{Name: "from_scratch", Type: cty.Bool, Required: false},
"source": &hcldec.AttrSpec{Name: "source", Type: cty.String, Required: false},
"command_wrapper": &hcldec.AttrSpec{Name: "command_wrapper", Type: cty.String, Required: false},
"pre_mount_commands": &hcldec.AttrSpec{Name: "pre_mount_commands", Type: cty.List(cty.String), Required: false},
"mount_options": &hcldec.AttrSpec{Name: "mount_options", Type: cty.List(cty.String), Required: false},
"mount_partition": &hcldec.AttrSpec{Name: "mount_partition", Type: cty.String, Required: false},
"mount_path": &hcldec.AttrSpec{Name: "mount_path", Type: cty.String, Required: false},
"post_mount_commands": &hcldec.AttrSpec{Name: "post_mount_commands", Type: cty.List(cty.String), Required: false},
"chroot_mounts": &hcldec.AttrSpec{Name: "chroot_mounts", Type: cty.List(cty.List(cty.String)), Required: false},
"copy_files": &hcldec.AttrSpec{Name: "copy_files", Type: cty.List(cty.String), Required: false},
"os_disk_size_gb": &hcldec.AttrSpec{Name: "os_disk_size_gb", Type: cty.Number, Required: false},
"os_disk_storage_account_type": &hcldec.AttrSpec{Name: "os_disk_storage_account_type", Type: cty.String, Required: false},
"os_disk_cache_type": &hcldec.AttrSpec{Name: "os_disk_cache_type", Type: cty.String, Required: false},
"image_hyperv_generation": &hcldec.AttrSpec{Name: "image_hyperv_generation", Type: cty.String, Required: false},
"temporary_os_disk_id": &hcldec.AttrSpec{Name: "temporary_os_disk_id", Type: cty.String, Required: false},
"temporary_os_disk_snapshot_id": &hcldec.AttrSpec{Name: "temporary_os_disk_snapshot_id", Type: cty.String, Required: false},
"skip_cleanup": &hcldec.AttrSpec{Name: "skip_cleanup", Type: cty.Bool, Required: false},
"image_resource_id": &hcldec.AttrSpec{Name: "image_resource_id", Type: cty.String, Required: false},
"shared_image_destination": &hcldec.BlockSpec{TypeName: "shared_image_destination", Nested: hcldec.ObjectSpec((*FlatSharedImageGalleryDestination)(nil).HCL2Spec())},
}
return s
}

View file

@ -1,9 +1,12 @@
package chroot
import (
"strings"
"testing"
"github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute"
"github.com/hashicorp/packer/builder/azure/common/client"
"github.com/hashicorp/packer/helper/multistep"
)
func TestBuilder_Prepare(t *testing.T) {
@ -17,13 +20,13 @@ func TestBuilder_Prepare(t *testing.T) {
wantErr bool
}{
{
name: "HappyPathFromPlatformImage",
name: "platform image to managed disk",
config: config{
"client_id": "123",
"client_secret": "456",
"subscription_id": "789",
"image_resource_id": "/subscriptions/789/resourceGroups/otherrgname/providers/Microsoft.Compute/images/MyDebianOSImage-{{timestamp}}",
"source": "credativ:Debian:9:latest",
"image_resource_id": "/subscriptions/789/resourceGroups/otherrgname/providers/Microsoft.Compute/images/MyDebianOSImage-{{timestamp}}",
},
validate: func(c Config) {
if c.OSDiskSizeGB != 0 {
@ -44,27 +47,168 @@ func TestBuilder_Prepare(t *testing.T) {
},
},
{
name: "HappyPathFromPlatformImage",
name: "disk to managed image, validate temp disk id expansion",
config: config{
"image_resource_id": "/subscriptions/789/resourceGroups/otherrgname/providers/Microsoft.Compute/images/MyDebianOSImage-{{timestamp}}",
"source": "/subscriptions/789/resourceGroups/testrg/providers/Microsoft.Compute/disks/diskname",
"image_resource_id": "/subscriptions/789/resourceGroups/otherrgname/providers/Microsoft.Compute/images/MyDebianOSImage-{{timestamp}}",
},
validate: func(c Config) {
prefix := "/subscriptions/testSubscriptionID/resourceGroups/testResourceGroup/providers/Microsoft.Compute/disks/PackerTemp-osdisk-"
if !strings.HasPrefix(c.TemporaryOSDiskID, prefix) {
t.Errorf("Expected TemporaryOSDiskID to start with %q, but got %q", prefix, c.TemporaryOSDiskID)
}
},
},
{
name: "disk to both managed image and shared image",
config: config{
"source": "/subscriptions/789/resourceGroups/testrg/providers/Microsoft.Compute/disks/diskname",
"image_resource_id": "/subscriptions/789/resourceGroups/otherrgname/providers/Microsoft.Compute/images/MyDebianOSImage-{{timestamp}}",
"shared_image_destination": config{
"resource_group": "rg",
"gallery_name": "galleryName",
"image_name": "imageName",
"image_version": "0.1.0",
},
},
},
{
name: "disk to both managed image and shared image with missing property",
config: config{
"source": "/subscriptions/789/resourceGroups/testrg/providers/Microsoft.Compute/disks/diskname",
"image_resource_id": "/subscriptions/789/resourceGroups/otherrgname/providers/Microsoft.Compute/images/MyDebianOSImage-{{timestamp}}",
"shared_image_destination": config{
"resource_group": "rg",
"gallery_name": "galleryName",
"image_version": "0.1.0",
},
},
wantErr: true,
},
{
name: "err: no output",
config: config{
"source": "/subscriptions/789/resourceGroups/testrg/providers/Microsoft.Compute/disks/diskname",
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b := &Builder{}
withMetadataStub(func() {
b := &Builder{}
_, _, err := b.Prepare(tt.config)
_, _, err := b.Prepare(tt.config)
if (err != nil) != tt.wantErr {
t.Errorf("Builder.Prepare() error = %v, wantErr %v", err, tt.wantErr)
return
}
if (err != nil) != tt.wantErr {
t.Errorf("Builder.Prepare() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.validate != nil {
tt.validate(b.config)
}
if tt.validate != nil {
tt.validate(b.config)
}
})
})
}
}
func Test_buildsteps(t *testing.T) {
info := &client.ComputeInfo{
Location: "northpole",
Name: "unittestVM",
ResourceGroupName: "unittestResourceGroup",
SubscriptionID: "96854241-60c7-426d-9a27-3fdeec8957f4",
}
tests := []struct {
name string
config Config
verify func([]multistep.Step, *testing.T)
}{
{
name: "Source FromScrath creates empty disk",
config: Config{FromScratch: true},
verify: func(steps []multistep.Step, _ *testing.T) {
for _, s := range steps {
if s, ok := s.(*StepCreateNewDisk); ok {
if s.SourceDiskResourceID == "" &&
s.PlatformImage == nil {
return
}
t.Errorf("found misconfigured StepCreateNewDisk: %+v", s)
}
}
t.Error("did not find a StepCreateNewDisk")
}},
{
name: "Source Platform image disk creation",
config: Config{Source: "publisher:offer:sku:version", sourceType: sourcePlatformImage},
verify: func(steps []multistep.Step, _ *testing.T) {
for _, s := range steps {
if s, ok := s.(*StepCreateNewDisk); ok {
if s.SourceDiskResourceID == "" &&
s.PlatformImage != nil &&
s.PlatformImage.Publisher == "publisher" {
return
}
t.Errorf("found misconfigured StepCreateNewDisk: %+v", s)
}
}
t.Error("did not find a StepCreateNewDisk")
}},
{
name: "Source Platform image with version latest adds StepResolvePlatformImageVersion",
config: Config{Source: "publisher:offer:sku:latest", sourceType: sourcePlatformImage},
verify: func(steps []multistep.Step, _ *testing.T) {
for _, s := range steps {
if s, ok := s.(*StepResolvePlatformImageVersion); ok {
if s.PlatformImage != nil &&
s.Location == info.Location {
return
}
t.Errorf("found misconfigured StepResolvePlatformImageVersion: %+v", s)
}
}
t.Error("did not find a StepResolvePlatformImageVersion")
}},
{
name: "Source Disk adds correct disk creation",
config: Config{Source: "diskresourceid", sourceType: sourceDisk},
verify: func(steps []multistep.Step, _ *testing.T) {
for _, s := range steps {
if s, ok := s.(*StepCreateNewDisk); ok {
if s.SourceDiskResourceID == "diskresourceid" &&
s.PlatformImage == nil {
return
}
t.Errorf("found misconfigured StepCreateNewDisk: %+v", s)
}
}
t.Error("did not find a StepCreateNewDisk")
}},
{
name: "Source disk adds StepVerifySourceDisk",
config: Config{Source: "diskresourceid", sourceType: sourceDisk},
verify: func(steps []multistep.Step, _ *testing.T) {
for _, s := range steps {
if s, ok := s.(*StepVerifySourceDisk); ok {
if s.SourceDiskResourceID == "diskresourceid" &&
s.Location == info.Location {
return
}
t.Errorf("found misconfigured StepVerifySourceDisk: %+v", s)
}
}
t.Error("did not find a StepVerifySourceDisk")
}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
withMetadataStub(func() { // ensure that values are taken from info, instead of retrieved again
got := buildsteps(tt.config, info)
tt.verify(got, t)
})
})
}
}

View file

@ -0,0 +1,6 @@
package chroot
const (
stateBagKey_OSDiskResourceID = "os_disk_resource_id"
stateBagKey_OSDiskSnapshotResourceID = "os_disk_snapshot_resource_id"
)

View file

@ -13,7 +13,7 @@ import (
"github.com/hashicorp/packer/builder/azure/common/client"
"github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute"
"github.com/Azure/go-autorest/autorest/azure"
"github.com/Azure/go-autorest/autorest/to"
)

View file

@ -6,7 +6,7 @@ import (
"github.com/Azure/go-autorest/autorest/to"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-03-01/compute"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute"
"github.com/hashicorp/packer/builder/azure/common/client"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

View file

@ -0,0 +1,18 @@
package chroot
import "github.com/hashicorp/packer/builder/azure/common/client"
func withMetadataStub(f func()) {
mdc := client.DefaultMetadataClient
defer func() { client.DefaultMetadataClient = mdc }()
client.DefaultMetadataClient = client.MetadataClientStub{
ComputeInfo: client.ComputeInfo{
SubscriptionID: "testSubscriptionID",
ResourceGroupName: "testResourceGroup",
Name: "testVM",
Location: "testLocation",
},
}
f()
}

View file

@ -0,0 +1,19 @@
package chroot
import (
"io/ioutil"
"strings"
"github.com/hashicorp/packer/packer"
)
// testUI returns a test ui plus a function to retrieve the errors written to the ui
func testUI() (packer.Ui, func() string) {
errorBuffer := &strings.Builder{}
ui := &packer.BasicUi{
Reader: strings.NewReader(""),
Writer: ioutil.Discard,
ErrorWriter: errorBuffer,
}
return ui, errorBuffer.String
}

View file

@ -0,0 +1,65 @@
//go:generate struct-markdown
//go:generate mapstructure-to-hcl2 -type SharedImageGalleryDestination,TargetRegion
package chroot
import (
"fmt"
"regexp"
)
// SharedImageGalleryDestination models an image version in a Shared
// Image Gallery that can be used as a destination.
type SharedImageGalleryDestination struct {
ResourceGroup string `mapstructure:"resource_group" required:"true"`
GalleryName string `mapstructure:"gallery_name" required:"true"`
ImageName string `mapstructure:"image_name" required:"true"`
ImageVersion string `mapstructure:"image_version" required:"true"`
TargetRegions []TargetRegion `mapstructure:"target_regions"`
ExcludeFromLatest bool `mapstructure:"exlude_from_latest"`
}
// TargetRegion describes a region where the shared image should be replicated
type TargetRegion struct {
// Name of the Azure region
Name string `mapstructure:"name" required:"true"`
// Number of replicas in this region. Default: 1
ReplicaCount int32 `mapstructure:"replicas"`
// Storage account type: Standard_LRS or Standard_ZRS. Default: Standard_ZRS
StorageAccountType string `mapstructure:"storage_account_type"`
}
// ResourceID returns the resource ID string
func (sigd SharedImageGalleryDestination) ResourceID(subscriptionID string) string {
return fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/galleries/%s/images/%s/versions/%s",
subscriptionID,
sigd.ResourceGroup,
sigd.GalleryName,
sigd.ImageName,
sigd.ImageVersion)
}
// Validate validates that the values in the shared image are valid (without checking them on the network)
func (sigd *SharedImageGalleryDestination) Validate(prefix string) (errs []error, warns []string) {
if sigd.ResourceGroup == "" {
errs = append(errs, fmt.Errorf("%s.resource_group is required", prefix))
}
if sigd.GalleryName == "" {
errs = append(errs, fmt.Errorf("%s.gallery_name is required", prefix))
}
if sigd.ImageName == "" {
errs = append(errs, fmt.Errorf("%s.image_name is required", prefix))
}
if match, err := regexp.MatchString("^[0-9]+\\.[0-9]+\\.[0-9]+$", sigd.ImageVersion); !match {
if err != nil {
warns = append(warns, fmt.Sprintf("Error matching pattern for %s.image_version: %s (this is probably a bug)", prefix, err))
}
errs = append(errs, fmt.Errorf("%s.image_version should match '^[0-9]+\\.[0-9]+\\.[0-9]+$'", prefix))
}
if len(sigd.TargetRegions) == 0 {
warns = append(warns,
fmt.Sprintf("%s.target_regions is empty; image will only be available in the region of the gallery", prefix))
}
return
}

View file

@ -0,0 +1,67 @@
// Code generated by "mapstructure-to-hcl2 -type SharedImageGalleryDestination,TargetRegion"; DO NOT EDIT.
package chroot
import (
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/zclconf/go-cty/cty"
)
// FlatSharedImageGalleryDestination is an auto-generated flat version of SharedImageGalleryDestination.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatSharedImageGalleryDestination struct {
ResourceGroup *string `mapstructure:"resource_group" required:"true" cty:"resource_group"`
GalleryName *string `mapstructure:"gallery_name" required:"true" cty:"gallery_name"`
ImageName *string `mapstructure:"image_name" required:"true" cty:"image_name"`
ImageVersion *string `mapstructure:"image_version" required:"true" cty:"image_version"`
TargetRegions []FlatTargetRegion `mapstructure:"target_regions" cty:"target_regions"`
ExcludeFromLatest *bool `mapstructure:"exlude_from_latest" cty:"exlude_from_latest"`
}
// FlatMapstructure returns a new FlatSharedImageGalleryDestination.
// FlatSharedImageGalleryDestination is an auto-generated flat version of SharedImageGalleryDestination.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*SharedImageGalleryDestination) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatSharedImageGalleryDestination)
}
// HCL2Spec returns the hcl spec of a SharedImageGalleryDestination.
// This spec is used by HCL to read the fields of SharedImageGalleryDestination.
// The decoded values from this spec will then be applied to a FlatSharedImageGalleryDestination.
func (*FlatSharedImageGalleryDestination) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{
"resource_group": &hcldec.AttrSpec{Name: "resource_group", Type: cty.String, Required: false},
"gallery_name": &hcldec.AttrSpec{Name: "gallery_name", Type: cty.String, Required: false},
"image_name": &hcldec.AttrSpec{Name: "image_name", Type: cty.String, Required: false},
"image_version": &hcldec.AttrSpec{Name: "image_version", Type: cty.String, Required: false},
"target_regions": &hcldec.BlockListSpec{TypeName: "target_regions", Nested: hcldec.ObjectSpec((*FlatTargetRegion)(nil).HCL2Spec())},
"exlude_from_latest": &hcldec.AttrSpec{Name: "exlude_from_latest", Type: cty.Bool, Required: false},
}
return s
}
// FlatTargetRegion is an auto-generated flat version of TargetRegion.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatTargetRegion struct {
Name *string `mapstructure:"name" required:"true" cty:"name"`
ReplicaCount *int32 `mapstructure:"replicas" cty:"replicas"`
StorageAccountType *string `mapstructure:"storage_account_type" cty:"storage_account_type"`
}
// FlatMapstructure returns a new FlatTargetRegion.
// FlatTargetRegion is an auto-generated flat version of TargetRegion.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*TargetRegion) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatTargetRegion)
}
// HCL2Spec returns the hcl spec of a TargetRegion.
// This spec is used by HCL to read the fields of TargetRegion.
// The decoded values from this spec will then be applied to a FlatTargetRegion.
func (*FlatTargetRegion) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{
"name": &hcldec.AttrSpec{Name: "name", Type: cty.String, Required: false},
"replicas": &hcldec.AttrSpec{Name: "replicas", Type: cty.Number, Required: false},
"storage_account_type": &hcldec.AttrSpec{Name: "storage_account_type", Type: cty.String, Required: false},
}
return s
}

View file

@ -0,0 +1,133 @@
package chroot
import (
"reflect"
"strings"
"testing"
)
func TestSharedImageGalleryDestination_ResourceID(t *testing.T) {
sigd := SharedImageGalleryDestination{
ResourceGroup: "ResourceGroup",
GalleryName: "GalleryName",
ImageName: "ImageName",
ImageVersion: "ImageVersion",
}
want := "/subscriptions/SubscriptionID/resourceGroups/ResourceGroup/providers/Microsoft.Compute/galleries/GalleryName/images/ImageName/versions/ImageVersion"
if got := sigd.ResourceID("SubscriptionID"); !strings.EqualFold(got, want) {
t.Errorf("SharedImageGalleryDestination.ResourceID() = %v, want %v", got, want)
}
}
func TestSharedImageGalleryDestination_Validate(t *testing.T) {
type fields struct {
ResourceGroup string
GalleryName string
ImageName string
ImageVersion string
TargetRegions []TargetRegion
ExcludeFromLatest bool
}
tests := []struct {
name string
fields fields
wantErrs []string
wantWarns []string
}{
{
name: "complete",
fields: fields{
ResourceGroup: "ResourceGroup",
GalleryName: "GalleryName",
ImageName: "ImageName",
ImageVersion: "0.1.2",
TargetRegions: []TargetRegion{
TargetRegion{
Name: "region1",
ReplicaCount: 5,
StorageAccountType: "Standard_ZRS",
},
TargetRegion{
Name: "region2",
ReplicaCount: 3,
StorageAccountType: "Standard_LRS",
},
},
ExcludeFromLatest: true,
},
},
{
name: "warn if target regions not specified",
fields: fields{
ResourceGroup: "ResourceGroup",
GalleryName: "GalleryName",
ImageName: "ImageName",
ImageVersion: "0.1.2",
},
wantWarns: []string{"sigdest.target_regions is empty; image will only be available in the region of the gallery"},
},
{
name: "version format",
wantErrs: []string{
"sigdest.image_version should match '^[0-9]+\\.[0-9]+\\.[0-9]+$'",
},
fields: fields{
ResourceGroup: "ResourceGroup",
GalleryName: "GalleryName",
ImageName: "ImageName",
ImageVersion: "0.1.2alpha",
TargetRegions: []TargetRegion{
TargetRegion{
Name: "region1",
ReplicaCount: 5,
StorageAccountType: "Standard_ZRS",
},
TargetRegion{
Name: "region2",
ReplicaCount: 3,
StorageAccountType: "Standard_LRS",
},
},
ExcludeFromLatest: true,
},
},
{
name: "required fields",
wantErrs: []string{
"sigdest.resource_group is required",
"sigdest.gallery_name is required",
"sigdest.image_name is required",
"sigdest.image_version should match '^[0-9]+\\.[0-9]+\\.[0-9]+$'",
},
wantWarns: []string{"sigdest.target_regions is empty; image will only be available in the region of the gallery"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
sigd := &SharedImageGalleryDestination{
ResourceGroup: tt.fields.ResourceGroup,
GalleryName: tt.fields.GalleryName,
ImageName: tt.fields.ImageName,
ImageVersion: tt.fields.ImageVersion,
TargetRegions: tt.fields.TargetRegions,
ExcludeFromLatest: tt.fields.ExcludeFromLatest,
}
gotErrs, gotWarns := sigd.Validate("sigdest")
var gotStrErrs []string
if gotErrs != nil {
gotStrErrs = make([]string, len(gotErrs))
for i, e := range gotErrs {
gotStrErrs[i] = e.Error()
}
}
if !reflect.DeepEqual(gotStrErrs, tt.wantErrs) {
t.Errorf("SharedImageGalleryDestination.Validate() gotErrs = %q, want %q", gotStrErrs, tt.wantErrs)
}
if !reflect.DeepEqual(gotWarns, tt.wantWarns) {
t.Errorf("SharedImageGalleryDestination.Validate() gotWarns = %q, want %q", gotWarns, tt.wantWarns)
}
})
}
}

View file

@ -20,7 +20,7 @@ type StepAttachDisk struct {
func (s *StepAttachDisk) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
azcli := state.Get("azureclient").(client.AzureClientSet)
ui := state.Get("ui").(packer.Ui)
diskResourceID := state.Get("os_disk_resource_id").(string)
diskResourceID := state.Get(stateBagKey_OSDiskResourceID).(string)
ui.Say(fmt.Sprintf("Attaching disk '%s'", diskResourceID))
@ -67,7 +67,7 @@ func (s *StepAttachDisk) CleanupFunc(state multistep.StateBag) error {
if s.attached {
azcli := state.Get("azureclient").(client.AzureClientSet)
ui := state.Get("ui").(packer.Ui)
diskResourceID := state.Get("os_disk_resource_id").(string)
diskResourceID := state.Get(stateBagKey_OSDiskResourceID).(string)
ui.Say(fmt.Sprintf("Detaching disk '%s'", diskResourceID))

View file

@ -9,7 +9,7 @@ import (
"strings"
"testing"
"github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute"
"github.com/Azure/go-autorest/autorest"
"github.com/hashicorp/packer/builder/azure/common/client"
"github.com/hashicorp/packer/helper/multistep"
@ -78,7 +78,7 @@ func TestStepAttachDisk_Run(t *testing.T) {
state := new(multistep.BasicStateBag)
state.Put("azureclient", &client.AzureClientSetMock{})
state.Put("ui", ui)
state.Put("os_disk_resource_id", "/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/disks/disk1")
state.Put(stateBagKey_OSDiskResourceID, "/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/disks/disk1")
got := s.Run(context.TODO(), state)
if !reflect.DeepEqual(got, tt.want) {

View file

@ -5,7 +5,7 @@ import (
"fmt"
"log"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-03-01/compute"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute"
"github.com/Azure/go-autorest/autorest/azure"
"github.com/Azure/go-autorest/autorest/to"
"github.com/hashicorp/packer/builder/azure/common/client"
@ -28,7 +28,7 @@ type StepCreateImage struct {
func (s *StepCreateImage) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
azcli := state.Get("azureclient").(client.AzureClientSet)
ui := state.Get("ui").(packer.Ui)
diskResourceID := state.Get("os_disk_resource_id").(string)
diskResourceID := state.Get(stateBagKey_OSDiskResourceID).(string)
ui.Say(fmt.Sprintf("Creating image %s\n using %s for os disk.",
s.ImageResourceID,

View file

@ -4,8 +4,11 @@ import (
"context"
"fmt"
"log"
"strings"
"time"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-03-01/compute"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute"
"github.com/Azure/go-autorest/autorest/azure"
"github.com/Azure/go-autorest/autorest/to"
"github.com/hashicorp/packer/builder/azure/common/client"
"github.com/hashicorp/packer/helper/multistep"
@ -15,10 +18,12 @@ import (
var _ multistep.Step = &StepCreateNewDisk{}
type StepCreateNewDisk struct {
SubscriptionID, ResourceGroup, DiskName string
DiskSizeGB int32 // optional, ignored if 0
DiskStorageAccountType string // from compute.DiskStorageAccountTypes
HyperVGeneration string
ResourceID string // Disk ID
subscriptionID, resourceGroup, diskName string // split out resource id
DiskSizeGB int32 // optional, ignored if 0
DiskStorageAccountType string // from compute.DiskStorageAccountTypes
HyperVGeneration string
Location string
PlatformImage *client.PlatformImage
@ -28,16 +33,37 @@ type StepCreateNewDisk struct {
SkipCleanup bool
}
func (s StepCreateNewDisk) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
func parseDiskResourceID(resourceID string) (subscriptionID, resourceGroup, diskName string, err error) {
r, err := azure.ParseResourceID(resourceID)
if err != nil {
return "", "", "", err
}
if !strings.EqualFold(r.Provider, "Microsoft.Compute") ||
!strings.EqualFold(r.ResourceType, "disks") {
return "", "", "", fmt.Errorf("Resource %q is not of type Microsoft.Compute/disks", resourceID)
}
return r.SubscriptionID, r.ResourceGroup, r.ResourceName, nil
}
func (s *StepCreateNewDisk) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
azcli := state.Get("azureclient").(client.AzureClientSet)
ui := state.Get("ui").(packer.Ui)
diskResourceID := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/disks/%s",
s.SubscriptionID,
s.ResourceGroup,
s.DiskName)
state.Put("os_disk_resource_id", diskResourceID)
ui.Say(fmt.Sprintf("Creating disk '%s'", diskResourceID))
state.Put(stateBagKey_OSDiskResourceID, s.ResourceID)
ui.Say(fmt.Sprintf("Creating disk '%s'", s.ResourceID))
var err error
s.subscriptionID, s.resourceGroup, s.diskName, err = parseDiskResourceID(s.ResourceID)
if err != nil {
log.Printf("StepCreateNewDisk.Run: error: %+v", err)
err := fmt.Errorf(
"error parsing resource id '%s': %v", s.ResourceID, err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
disk := compute.Disk{
Location: to.StringPtr(s.Location),
@ -67,18 +93,20 @@ func (s StepCreateNewDisk) Run(ctx context.Context, state multistep.StateBag) mu
disk.CreationData.ImageReference = &compute.ImageDiskReference{
ID: to.StringPtr(fmt.Sprintf(
"/subscriptions/%s/providers/Microsoft.Compute/locations/%s/publishers/%s/artifacttypes/vmimage/offers/%s/skus/%s/versions/%s",
s.SubscriptionID, s.Location, s.PlatformImage.Publisher, s.PlatformImage.Offer, s.PlatformImage.Sku, s.PlatformImage.Version)),
s.subscriptionID, s.Location, s.PlatformImage.Publisher, s.PlatformImage.Offer, s.PlatformImage.Sku, s.PlatformImage.Version)),
}
}
f, err := azcli.DisksClient().CreateOrUpdate(ctx, s.ResourceGroup, s.DiskName, disk)
f, err := azcli.DisksClient().CreateOrUpdate(ctx, s.resourceGroup, s.diskName, disk)
if err == nil {
err = f.WaitForCompletionRef(ctx, azcli.PollClient())
cli := azcli.PollClient() // quick polling for quick operations
cli.PollingDelay = time.Second
err = f.WaitForCompletionRef(ctx, cli)
}
if err != nil {
log.Printf("StepCreateNewDisk.Run: error: %+v", err)
err := fmt.Errorf(
"error creating new disk '%s': %v", diskResourceID, err)
"error creating new disk '%s': %v", s.ResourceID, err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
@ -87,27 +115,26 @@ func (s StepCreateNewDisk) Run(ctx context.Context, state multistep.StateBag) mu
return multistep.ActionContinue
}
func (s StepCreateNewDisk) Cleanup(state multistep.StateBag) {
func (s *StepCreateNewDisk) Cleanup(state multistep.StateBag) {
if !s.SkipCleanup {
azcli := state.Get("azureclient").(client.AzureClientSet)
ui := state.Get("ui").(packer.Ui)
diskResourceID := state.Get("os_disk_resource_id").(string)
ui.Say(fmt.Sprintf("Waiting for disk %q detach to complete", diskResourceID))
err := NewDiskAttacher(azcli).WaitForDetach(context.Background(), diskResourceID)
ui.Say(fmt.Sprintf("Waiting for disk %q detach to complete", s.ResourceID))
err := NewDiskAttacher(azcli).WaitForDetach(context.Background(), s.ResourceID)
if err != nil {
ui.Error(fmt.Sprintf("error detaching disk %q: %s", diskResourceID, err))
ui.Error(fmt.Sprintf("error detaching disk %q: %s", s.ResourceID, err))
}
ui.Say(fmt.Sprintf("Deleting disk %q", diskResourceID))
ui.Say(fmt.Sprintf("Deleting disk %q", s.ResourceID))
f, err := azcli.DisksClient().Delete(context.TODO(), s.ResourceGroup, s.DiskName)
f, err := azcli.DisksClient().Delete(context.TODO(), s.resourceGroup, s.diskName)
if err == nil {
err = f.WaitForCompletionRef(context.TODO(), azcli.PollClient())
}
if err != nil {
log.Printf("StepCreateNewDisk.Cleanup: error: %+v", err)
ui.Error(fmt.Sprintf("error deleting new disk '%s': %v.", diskResourceID, err))
ui.Error(fmt.Sprintf("error deleting disk '%s': %v.", s.ResourceID, err))
}
}
}

View file

@ -8,18 +8,17 @@ import (
"regexp"
"testing"
"github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute"
"github.com/Azure/go-autorest/autorest"
"github.com/hashicorp/packer/builder/azure/common/client"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute"
"github.com/Azure/go-autorest/autorest"
)
func TestStepCreateNewDisk_Run(t *testing.T) {
type fields struct {
SubscriptionID string
ResourceGroup string
DiskName string
ResourceID string
DiskSizeGB int32
DiskStorageAccountType string
HyperVGeneration string
@ -35,11 +34,9 @@ func TestStepCreateNewDisk_Run(t *testing.T) {
want multistep.StepAction
}{
{
name: "HappyPathDiskSource",
name: "from disk",
fields: fields{
SubscriptionID: "SubscriptionID",
ResourceGroup: "ResourceGroupName",
DiskName: "TemporaryOSDiskName",
ResourceID: "/subscriptions/SubscriptionID/resourcegroups/ResourceGroupName/providers/Microsoft.Compute/disks/TemporaryOSDiskName",
DiskSizeGB: 42,
DiskStorageAccountType: string(compute.PremiumLRS),
HyperVGeneration: string(compute.V1),
@ -66,11 +63,9 @@ func TestStepCreateNewDisk_Run(t *testing.T) {
want: multistep.ActionContinue,
},
{
name: "HappyPathDiskSource",
name: "from image",
fields: fields{
SubscriptionID: "SubscriptionID",
ResourceGroup: "ResourceGroupName",
DiskName: "TemporaryOSDiskName",
ResourceID: "/subscriptions/SubscriptionID/resourcegroups/ResourceGroupName/providers/Microsoft.Compute/disks/TemporaryOSDiskName",
DiskStorageAccountType: string(compute.StandardLRS),
HyperVGeneration: string(compute.V1),
Location: "westus",
@ -105,9 +100,7 @@ func TestStepCreateNewDisk_Run(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := StepCreateNewDisk{
SubscriptionID: tt.fields.SubscriptionID,
ResourceGroup: tt.fields.ResourceGroup,
DiskName: tt.fields.DiskName,
ResourceID: tt.fields.ResourceID,
DiskSizeGB: tt.fields.DiskSizeGB,
DiskStorageAccountType: tt.fields.DiskStorageAccountType,
HyperVGeneration: tt.fields.HyperVGeneration,

View file

@ -0,0 +1,81 @@
package chroot
import (
"context"
"fmt"
"log"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute"
"github.com/Azure/go-autorest/autorest/to"
"github.com/hashicorp/packer/builder/azure/common/client"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
type StepCreateSharedImageVersion struct {
Destination SharedImageGalleryDestination
OSDiskCacheType string
Location string
}
func (s *StepCreateSharedImageVersion) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
azcli := state.Get("azureclient").(client.AzureClientSet)
ui := state.Get("ui").(packer.Ui)
osDiskSnapshotResourceID := state.Get(stateBagKey_OSDiskSnapshotResourceID).(string)
ui.Say(fmt.Sprintf("Creating image version %s\n using %s for os disk.",
s.Destination.ResourceID(azcli.SubscriptionID()),
osDiskSnapshotResourceID))
var targetRegions []compute.TargetRegion
// transform target regions to API objects
for _, tr := range s.Destination.TargetRegions {
apiObject := compute.TargetRegion{
Name: to.StringPtr(tr.Name),
RegionalReplicaCount: to.Int32Ptr(tr.ReplicaCount),
StorageAccountType: compute.StorageAccountType(tr.StorageAccountType),
}
targetRegions = append(targetRegions, apiObject)
}
imageVersion := compute.GalleryImageVersion{
Location: to.StringPtr(s.Location),
GalleryImageVersionProperties: &compute.GalleryImageVersionProperties{
StorageProfile: &compute.GalleryImageVersionStorageProfile{
OsDiskImage: &compute.GalleryOSDiskImage{
Source: &compute.GalleryArtifactVersionSource{ID: &osDiskSnapshotResourceID},
HostCaching: compute.HostCaching(s.OSDiskCacheType),
},
},
PublishingProfile: &compute.GalleryImageVersionPublishingProfile{
TargetRegions: &targetRegions,
ExcludeFromLatest: to.BoolPtr(s.Destination.ExcludeFromLatest),
},
},
}
f, err := azcli.GalleryImageVersionsClient().CreateOrUpdate(
ctx,
s.Destination.ResourceGroup,
s.Destination.GalleryName,
s.Destination.ImageName,
s.Destination.ImageVersion,
imageVersion)
if err == nil {
log.Println("Shared image version creation in process...")
err = f.WaitForCompletionRef(ctx, azcli.PollClient())
}
if err != nil {
log.Printf("StepCreateSharedImageVersion.Run: error: %+v", err)
err := fmt.Errorf(
"error creating shared image version '%s': %v", s.Destination.ResourceID(azcli.SubscriptionID()), err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
log.Printf("Image creation complete: %s", f.Status())
return multistep.ActionContinue
}
func (*StepCreateSharedImageVersion) Cleanup(multistep.StateBag) {}

View file

@ -0,0 +1,110 @@
package chroot
import (
"context"
"io/ioutil"
"net/http"
"reflect"
"regexp"
"testing"
"github.com/hashicorp/packer/builder/azure/common/client"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute"
"github.com/Azure/go-autorest/autorest"
)
func TestStepCreateSharedImageVersion_Run(t *testing.T) {
type fields struct {
Destination SharedImageGalleryDestination
OSDiskCacheType string
Location string
}
tests := []struct {
name string
fields fields
want multistep.StepAction
expectedPutBody string
}{
{
name: "happy path",
fields: fields{
Destination: SharedImageGalleryDestination{
ResourceGroup: "ResourceGroup",
GalleryName: "GalleryName",
ImageName: "ImageName",
ImageVersion: "0.1.2",
TargetRegions: []TargetRegion{
TargetRegion{
Name: "region1",
ReplicaCount: 5,
StorageAccountType: "Standard_ZRS",
},
},
ExcludeFromLatest: true,
},
Location: "region2",
},
expectedPutBody: `{
"location": "region2",
"properties": {
"publishingProfile": {
"targetRegions": [
{
"name": "region1",
"regionalReplicaCount": 5,
"storageAccountType": "Standard_ZRS"
}
],
"excludeFromLatest": true
},
"storageProfile": {
"osDiskImage": {
"source": {
"id": "osdisksnapshotresourceid"
}
}
}
}
}`,
},
}
for _, tt := range tests {
expectedPutBody := regexp.MustCompile(`[\s\n]`).ReplaceAllString(tt.expectedPutBody, "")
m := compute.NewGalleryImageVersionsClient("subscriptionId")
m.Sender = autorest.SenderFunc(func(r *http.Request) (*http.Response, error) {
if r.Method != "PUT" {
t.Fatal("Expected only a PUT call")
}
b, _ := ioutil.ReadAll(r.Body)
if string(b) != expectedPutBody {
t.Errorf("expected body to be %v, but got %v", expectedPutBody, string(b))
}
return &http.Response{
Request: r,
StatusCode: 200,
}, nil
})
state := new(multistep.BasicStateBag)
state.Put("azureclient", &client.AzureClientSetMock{
GalleryImageVersionsClientMock: m,
})
state.Put("ui", packer.TestUi(t))
state.Put(stateBagKey_OSDiskSnapshotResourceID, "osdisksnapshotresourceid")
t.Run(tt.name, func(t *testing.T) {
s := &StepCreateSharedImageVersion{
Destination: tt.fields.Destination,
OSDiskCacheType: tt.fields.OSDiskCacheType,
Location: tt.fields.Location,
}
if got := s.Run(context.TODO(), state); !reflect.DeepEqual(got, tt.want) {
t.Errorf("StepCreateSharedImageVersion.Run() = %v, want %v", got, tt.want)
}
})
}
}

View file

@ -0,0 +1,123 @@
package chroot
import (
"context"
"fmt"
"log"
"strings"
"time"
"github.com/hashicorp/packer/builder/azure/common/client"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute"
"github.com/Azure/go-autorest/autorest/azure"
"github.com/Azure/go-autorest/autorest/to"
)
var _ multistep.Step = &StepCreateSnapshot{}
type StepCreateSnapshot struct {
ResourceID string
Location string
SkipCleanup bool
subscriptionID, resourceGroup, snapshotName string
}
func parseSnapshotResourceID(resourceID string) (subscriptionID, resourceGroup, snapshotName string, err error) {
r, err := azure.ParseResourceID(resourceID)
if err != nil {
return "", "", "", err
}
if !strings.EqualFold(r.Provider, "Microsoft.Compute") ||
!strings.EqualFold(r.ResourceType, "snapshots") {
return "", "", "", fmt.Errorf("Resource %q is not of type Microsoft.Compute/snapshots", resourceID)
}
return r.SubscriptionID, r.ResourceGroup, r.ResourceName, nil
}
func (s *StepCreateSnapshot) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
azcli := state.Get("azureclient").(client.AzureClientSet)
ui := state.Get("ui").(packer.Ui)
osDiskResourceID := state.Get(stateBagKey_OSDiskResourceID).(string)
state.Put(stateBagKey_OSDiskSnapshotResourceID, s.ResourceID)
ui.Say(fmt.Sprintf("Creating snapshot '%s'", s.ResourceID))
var err error
s.subscriptionID, s.resourceGroup, s.snapshotName, err = parseSnapshotResourceID(s.ResourceID)
if err != nil {
log.Printf("StepCreateSnapshot.Run: error: %+v", err)
err := fmt.Errorf(
"error parsing resource id '%s': %v", s.ResourceID, err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
snapshot := compute.Snapshot{
Location: to.StringPtr(s.Location),
SnapshotProperties: &compute.SnapshotProperties{
CreationData: &compute.CreationData{
CreateOption: compute.Copy,
SourceResourceID: to.StringPtr(osDiskResourceID),
},
Incremental: to.BoolPtr(false),
},
}
f, err := azcli.SnapshotsClient().CreateOrUpdate(ctx, s.resourceGroup, s.snapshotName, snapshot)
if err == nil {
cli := azcli.PollClient() // quick polling for quick operations
cli.PollingDelay = time.Second
err = f.WaitForCompletionRef(ctx, cli)
}
if err != nil {
log.Printf("StepCreateSnapshot.Run: error: %+v", err)
err := fmt.Errorf(
"error creating snapshot '%s': %v", s.ResourceID, err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
return multistep.ActionContinue
}
func (s *StepCreateSnapshot) Cleanup(state multistep.StateBag) {
if !s.SkipCleanup {
azcli := state.Get("azureclient").(client.AzureClientSet)
ui := state.Get("ui").(packer.Ui)
ui.Say(fmt.Sprintf("Removing any active SAS for snapshot %q", s.ResourceID))
{
f, err := azcli.SnapshotsClient().RevokeAccess(context.TODO(), s.resourceGroup, s.snapshotName)
if err == nil {
log.Printf("StepCreateSnapshot.Cleanup: removing SAS...")
err = f.WaitForCompletionRef(context.TODO(), azcli.PollClient())
}
if err != nil {
log.Printf("StepCreateSnapshot.Cleanup: error: %+v", err)
ui.Error(fmt.Sprintf("error deleting snapshot '%s': %v.", s.ResourceID, err))
}
}
ui.Say(fmt.Sprintf("Deleting snapshot %q", s.ResourceID))
{
f, err := azcli.SnapshotsClient().Delete(context.TODO(), s.resourceGroup, s.snapshotName)
if err == nil {
log.Printf("StepCreateSnapshot.Cleanup: deleting snapshot...")
err = f.WaitForCompletionRef(context.TODO(), azcli.PollClient())
}
if err != nil {
log.Printf("StepCreateSnapshot.Cleanup: error: %+v", err)
ui.Error(fmt.Sprintf("error deleting snapshot '%s': %v.", s.ResourceID, err))
}
}
}
}

View file

@ -0,0 +1,215 @@
package chroot
import (
"context"
"io/ioutil"
"net/http"
"reflect"
"regexp"
"strings"
"testing"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute"
"github.com/Azure/go-autorest/autorest"
"github.com/hashicorp/packer/builder/azure/common/client"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
func Test_parseSnapshotResourceID(t *testing.T) {
tests := []struct {
name string
resourceID string
wantSubscriptionID string
wantResourceGroup string
wantSnapshotName string
wantErr bool
}{
{
name: "happy path",
resourceID: "/subscriptions/1234/resourceGroups/rg/providers/microsoft.compute/snapshots/disksnapshot1",
wantErr: false,
wantSubscriptionID: "1234",
wantResourceGroup: "rg",
wantSnapshotName: "disksnapshot1",
},
{
name: "error: nonsense",
resourceID: "nonsense",
wantErr: true,
},
{
name: "error: other resource type",
resourceID: "/subscriptions/1234/resourceGroups/rg/providers/microsoft.compute/disks/disksnapshot1",
wantErr: true,
},
{
name: "error: no name",
resourceID: "/subscriptions/1234/resourceGroups/rg/providers/microsoft.compute/snapshots",
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotSubscriptionID, gotResourceGroup, gotSnapshotName, err := parseSnapshotResourceID(tt.resourceID)
if (err != nil) != tt.wantErr {
t.Errorf("parseSnapshotResourceID() error = %v, wantErr %v", err, tt.wantErr)
return
}
if gotSubscriptionID != tt.wantSubscriptionID {
t.Errorf("parseSnapshotResourceID() gotSubscriptionID = %v, want %v", gotSubscriptionID, tt.wantSubscriptionID)
}
if gotResourceGroup != tt.wantResourceGroup {
t.Errorf("parseSnapshotResourceID() gotResourceGroup = %v, want %v", gotResourceGroup, tt.wantResourceGroup)
}
if gotSnapshotName != tt.wantSnapshotName {
t.Errorf("parseSnapshotResourceID() gotSnapshotName = %v, want %v", gotSnapshotName, tt.wantSnapshotName)
}
})
}
}
func TestStepCreateSnapshot_Run(t *testing.T) {
type fields struct {
ResourceID string
Location string
}
tests := []struct {
name string
fields fields
want multistep.StepAction
wantSnapshotID string
expectedPutBody string
}{
{
name: "happy path",
fields: fields{
ResourceID: "/subscriptions/1234/resourceGroups/rg/providers/Microsoft.Compute/snapshots/snap1",
Location: "region1",
},
expectedPutBody: `{
"location": "region1",
"properties": {
"creationData": {
"createOption": "Copy",
"sourceResourceId": "osdiskresourceid"
},
"incremental": false
}
}`,
},
{
name: "invalid ResourceID",
fields: fields{
ResourceID: "notaresourceid",
Location: "region1",
},
want: multistep.ActionHalt,
},
}
for _, tt := range tests {
expectedPutBody := regexp.MustCompile(`[\s\n]`).ReplaceAllString(tt.expectedPutBody, "")
m := compute.NewSnapshotsClient("subscriptionId")
m.Sender = autorest.SenderFunc(func(r *http.Request) (*http.Response, error) {
if r.Method != "PUT" {
t.Fatal("Expected only a PUT call")
}
b, _ := ioutil.ReadAll(r.Body)
if string(b) != expectedPutBody {
t.Errorf("expected body to be %v, but got %v", expectedPutBody, string(b))
}
return &http.Response{
Request: r,
StatusCode: 200,
}, nil
})
state := new(multistep.BasicStateBag)
state.Put("azureclient", &client.AzureClientSetMock{
SnapshotsClientMock: m,
})
state.Put("ui", packer.TestUi(t))
state.Put(stateBagKey_OSDiskResourceID, "osdiskresourceid")
t.Run(tt.name, func(t *testing.T) {
s := &StepCreateSnapshot{
ResourceID: tt.fields.ResourceID,
Location: tt.fields.Location,
}
if got := s.Run(context.TODO(), state); !reflect.DeepEqual(got, tt.want) {
t.Errorf("StepCreateSnapshot.Run() = %v, want %v", got, tt.want)
}
if tt.wantSnapshotID != "" {
got := state.Get(stateBagKey_OSDiskSnapshotResourceID).(string)
if !strings.EqualFold(got, tt.wantSnapshotID) {
t.Errorf("OSDiskSnapshotResourceID = %v, want %v", got, tt.wantSnapshotID)
}
}
})
}
}
func TestStepCreateSnapshot_Cleanup_skipped(t *testing.T) {
m := compute.NewSnapshotsClient("subscriptionId")
m.Sender = autorest.SenderFunc(func(r *http.Request) (*http.Response, error) {
t.Fatalf("clean up should be skipped, did not expect HTTP calls")
return nil, nil
})
state := new(multistep.BasicStateBag)
state.Put("azureclient", &client.AzureClientSetMock{
SnapshotsClientMock: m,
})
state.Put("ui", packer.TestUi(t))
s := &StepCreateSnapshot{
SkipCleanup: true,
}
s.Cleanup(state)
}
func TestStepCreateSnapshot_Cleanup(t *testing.T) {
m := compute.NewSnapshotsClient("subscriptionId")
{
expectedCalls := []string{
"POST /subscriptions/subscriptionId/resourceGroups/rg/providers/Microsoft.Compute/snapshots/snap1/endGetAccess?api-version=2019-07-01",
"DELETE /subscriptions/subscriptionId/resourceGroups/rg/providers/Microsoft.Compute/snapshots/snap1?api-version=2019-07-01",
}
i := 0
m.Sender = autorest.SenderFunc(func(r *http.Request) (*http.Response, error) {
want := expectedCalls[i]
got := r.Method + " " + r.URL.RequestURI()
if want != got {
t.Errorf("unexpected HTTP call: %v, wanted %v", got, want)
return &http.Response{
Request: r,
StatusCode: 599, // 500 is retried
}, nil
}
i++
return &http.Response{
Request: r,
StatusCode: 200,
}, nil
})
}
state := new(multistep.BasicStateBag)
state.Put("azureclient", &client.AzureClientSetMock{
SnapshotsClientMock: m,
})
state.Put("ui", packer.TestUi(t))
s := &StepCreateSnapshot{
ResourceID: "/subscriptions/1234/resourceGroups/rg/providers/Microsoft.Compute/snapshots/snap1",
Location: "region1",
SkipCleanup: false,
resourceGroup: "rg",
snapshotName: "snap1",
subscriptionID: "1234",
}
s.Cleanup(state)
}

View file

@ -0,0 +1,45 @@
package chroot
import (
"context"
"fmt"
"log"
"strings"
"github.com/Azure/go-autorest/autorest/to"
"github.com/hashicorp/packer/builder/azure/common/client"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
// StepResolvePlatformImageVersion resolves the exact PIR version when the version is 'latest'
type StepResolvePlatformImageVersion struct {
*client.PlatformImage
Location string
}
// Run retrieves all available versions of a PIR image and stores the latest in the PlatformImage
func (pi *StepResolvePlatformImageVersion) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
if strings.EqualFold(pi.Version, "latest") {
azcli := state.Get("azureclient").(client.AzureClientSet)
vmi, err := azcli.VirtualMachineImagesClient().GetLatest(ctx, pi.Publisher, pi.Offer, pi.Sku, pi.Location)
if err != nil {
log.Printf("StepResolvePlatformImageVersion.Run: error: %+v", err)
err := fmt.Errorf("error retieving latest version of %q: %v", pi.URN(), err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
pi.Version = to.String(vmi.Name)
ui.Say("Resolved latest version of source image: " + pi.Version)
} else {
ui.Say("Nothing to do, version is not 'latest'")
}
return multistep.ActionContinue
}
func (*StepResolvePlatformImageVersion) Cleanup(multistep.StateBag) {}

View file

@ -0,0 +1,61 @@
package chroot
import (
"context"
"io/ioutil"
"net/http"
"strings"
"testing"
"time"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute"
"github.com/Azure/go-autorest/autorest"
"github.com/hashicorp/packer/builder/azure/common/client"
"github.com/hashicorp/packer/helper/multistep"
)
func TestStepResolvePlatformImageVersion_Run(t *testing.T) {
pi := &StepResolvePlatformImageVersion{
PlatformImage: &client.PlatformImage{
Version: "latest",
}}
m := compute.NewVirtualMachineImagesClient("subscriptionId")
m.Sender = autorest.SenderFunc(func(r *http.Request) (*http.Response, error) {
if !strings.Contains(r.URL.String(), "%24orderby=name+desc") {
t.Errorf("Expected url to use odata based sorting, but got %q", r.URL.String())
}
return &http.Response{
Request: r,
Body: ioutil.NopCloser(strings.NewReader(
`[
{"name":"1.2.3"},
{"name":"4.5.6"}
]`)),
StatusCode: 200,
}, nil
})
state := new(multistep.BasicStateBag)
state.Put("azureclient", &client.AzureClientSetMock{
VirtualMachineImagesClientMock: client.VirtualMachineImagesClient{
VirtualMachineImagesClientAPI: m}})
ui, getErrs := testUI()
state.Put("ui", ui)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
got := pi.Run(ctx, state)
if got != multistep.ActionContinue {
t.Errorf("Expected 'continue', but got %q", got)
}
if pi.PlatformImage.Version != "1.2.3" {
t.Errorf("Expected version '1.2.3', but got %q", pi.PlatformImage.Version)
}
_ = getErrs
}

View file

@ -0,0 +1,114 @@
package chroot
import (
"context"
"fmt"
"log"
"strings"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute"
"github.com/Azure/go-autorest/autorest/to"
"github.com/hashicorp/packer/builder/azure/common/client"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
var _ multistep.Step = &StepVerifySharedImageDestination{}
// StepVerifySharedImageDestination verifies that the shared image location matches the Location field in the step.
// Also verifies that the OS Type is Linux.
type StepVerifySharedImageDestination struct {
Image SharedImageGalleryDestination
Location string
}
// Run retrieves the image metadata from Azure and compares the location to Location. Verifies the OS Type.
func (s *StepVerifySharedImageDestination) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
azcli := state.Get("azureclient").(client.AzureClientSet)
ui := state.Get("ui").(packer.Ui)
errorMessage := func(message string, parameters ...interface{}) multistep.StepAction {
err := fmt.Errorf(message, parameters...)
log.Printf("StepVerifySharedImageDestination.Run: error: %+v", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
imageURI := fmt.Sprintf("/subscriptions/%s/resourcegroup/%s/providers/Microsoft.Compute/galleries/%s/images/%s",
azcli.SubscriptionID(),
s.Image.ResourceGroup,
s.Image.GalleryName,
s.Image.ImageName,
)
ui.Say(fmt.Sprintf("Validating that shared image %s exists",
imageURI))
image, err := azcli.GalleryImagesClient().Get(ctx,
s.Image.ResourceGroup,
s.Image.GalleryName,
s.Image.ImageName)
if err != nil {
return errorMessage("Error retrieving shared image %q: %+v ", imageURI, err)
}
if image.ID == nil || *image.ID == "" {
return errorMessage("Error retrieving shared image %q: ID field in response is empty", imageURI)
}
if image.GalleryImageProperties == nil {
return errorMessage("Could not retrieve shared image properties for image %q.", to.String(image.ID))
}
location := to.String(image.Location)
log.Printf("StepVerifySharedImageDestination:Run: Image %q, Location: %q, HvGen: %q, osState: %q",
to.String(image.ID),
location,
image.GalleryImageProperties.HyperVGeneration,
image.GalleryImageProperties.OsState)
if !strings.EqualFold(location, s.Location) {
return errorMessage("Destination shared image resource %q is in a different location (%q) than this VM (%q). "+
"Packer does not know how to handle that.",
to.String(image.ID),
location,
s.Location)
}
if image.GalleryImageProperties.OsType != compute.Linux {
return errorMessage("The shared image (%q) is not a Linux image (found %q). Currently only Linux images are supported.",
to.String(image.ID),
image.GalleryImageProperties.OsType)
}
ui.Say(fmt.Sprintf("Found image %s in location %s",
to.String(image.ID),
to.String(image.Location)))
versions, err := azcli.GalleryImageVersionsClient().ListByGalleryImageComplete(ctx,
s.Image.ResourceGroup,
s.Image.GalleryName,
s.Image.ImageName)
for versions.NotDone() {
version := versions.Value()
if version.Name == nil {
return errorMessage("Could not retrieve versions for image %q: unexpected nil name", to.String(image.ID))
}
if *version.Name == s.Image.ImageVersion {
return errorMessage("Shared image version %q already exists for image %q.", s.Image.ImageVersion, to.String(image.ID))
}
err := versions.NextWithContext(ctx)
if err != nil {
return errorMessage("Could not retrieve versions for image %q: %+v", to.String(image.ID), err)
}
}
return multistep.ActionContinue
}
func (*StepVerifySharedImageDestination) Cleanup(multistep.StateBag) {}

View file

@ -0,0 +1,185 @@
package chroot
import (
"context"
"io/ioutil"
"net/http"
"reflect"
"strings"
"testing"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute"
"github.com/Azure/go-autorest/autorest"
"github.com/hashicorp/packer/builder/azure/common/client"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
func TestStepVerifySharedImageDestination_Run(t *testing.T) {
type fields struct {
Image SharedImageGalleryDestination
Location string
}
tests := []struct {
name string
fields fields
want multistep.StepAction
wantErr string
}{
{
name: "happy path",
want: multistep.ActionContinue,
fields: fields{
Image: SharedImageGalleryDestination{
ResourceGroup: "rg",
GalleryName: "gallery",
ImageName: "image",
ImageVersion: "1.2.3",
},
Location: "region1",
},
},
{
name: "not found",
want: multistep.ActionHalt,
wantErr: `Error retrieving shared image "/subscriptions/subscriptionID/resourcegroup/other-rg/providers/Microsoft.Compute/galleries/gallery/images/image": compute.GalleryImagesClient#Get: Failure responding to request: StatusCode=404 -- Original Error: autorest/azure: Service returned an error. Status=404 Code="NotFound" Message="Not found" `,
fields: fields{
Image: SharedImageGalleryDestination{
ResourceGroup: "other-rg",
GalleryName: "gallery",
ImageName: "image",
ImageVersion: "1.2.3",
},
Location: "region1",
},
},
{
name: "wrong region",
want: multistep.ActionHalt,
wantErr: "Destination shared image resource \"image-resourceid-goes-here\" is in a different location (\"region1\") than this VM (\"other-region\"). Packer does not know how to handle that.",
fields: fields{
Image: SharedImageGalleryDestination{
ResourceGroup: "rg",
GalleryName: "gallery",
ImageName: "image",
ImageVersion: "1.2.3",
},
Location: "other-region",
},
},
{
name: "version exists",
want: multistep.ActionHalt,
wantErr: "Shared image version \"2.3.4\" already exists for image \"image-resourceid-goes-here\".",
fields: fields{
Image: SharedImageGalleryDestination{
ResourceGroup: "rg",
GalleryName: "gallery",
ImageName: "image",
ImageVersion: "2.3.4",
},
Location: "region1",
},
},
{
name: "not Linux",
want: multistep.ActionHalt,
wantErr: "The shared image (\"windows-image-resourceid-goes-here\") is not a Linux image (found \"Windows\"). Currently only Linux images are supported.",
fields: fields{
Image: SharedImageGalleryDestination{
ResourceGroup: "rg",
GalleryName: "gallery",
ImageName: "windowsimage",
ImageVersion: "1.2.3",
},
Location: "region1",
},
},
}
for _, tt := range tests {
gi := compute.NewGalleryImagesClient("subscriptionID")
gi.Sender = autorest.SenderFunc(func(r *http.Request) (*http.Response, error) {
switch {
case r.Method == "GET" && strings.HasPrefix(r.URL.RequestURI(),
"/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Compute/galleries/gallery/images/image"):
return &http.Response{
Request: r,
Body: ioutil.NopCloser(strings.NewReader(`{
"id": "image-resourceid-goes-here",
"location": "region1",
"properties": {
"osType": "Linux"
}
}`)),
StatusCode: 200,
}, nil
case r.Method == "GET" && strings.HasPrefix(r.URL.RequestURI(),
"/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Compute/galleries/gallery/images/windowsimage"):
return &http.Response{
Request: r,
Body: ioutil.NopCloser(strings.NewReader(`{
"id": "windows-image-resourceid-goes-here",
"location": "region1",
"properties": {
"osType": "Windows"
}
}`)),
StatusCode: 200,
}, nil
}
return &http.Response{
Request: r,
Body: ioutil.NopCloser(strings.NewReader(`{
"Code": "NotFound",
"Message": "Not found"
}`)),
StatusCode: 404,
}, nil
})
giv := compute.NewGalleryImageVersionsClient("subscriptionID")
giv.Sender = autorest.SenderFunc(func(r *http.Request) (*http.Response, error) {
if !(r.Method == "GET" && strings.HasPrefix(r.URL.RequestURI(),
"/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Compute/galleries/gallery/images/image/versions")) {
t.Errorf("Unexpected HTTP call: %s %s", r.Method, r.URL.RequestURI())
}
return &http.Response{
Request: r,
Body: ioutil.NopCloser(strings.NewReader(`{
"value": [
{
"name": "2.3.4"
}
]
}`)),
StatusCode: 200,
}, nil
})
state := new(multistep.BasicStateBag)
state.Put("azureclient", &client.AzureClientSetMock{
SubscriptionIDMock: "subscriptionID",
GalleryImagesClientMock: gi,
GalleryImageVersionsClientMock: giv,
})
state.Put("ui", packer.TestUi(t))
t.Run(tt.name, func(t *testing.T) {
s := &StepVerifySharedImageDestination{
Image: tt.fields.Image,
Location: tt.fields.Location,
}
if got := s.Run(context.TODO(), state); !reflect.DeepEqual(got, tt.want) {
t.Errorf("StepVerifySharedImageDestination.Run() = %v, want %v", got, tt.want)
}
})
if err, ok := state.GetOk("error"); ok {
if err.(error).Error() != tt.wantErr {
t.Errorf("Unexpected error, got: %q, want: %q", err, tt.wantErr)
}
} else if tt.wantErr != "" {
t.Errorf("Expected error, but didn't get any")
}
}
}

View file

@ -15,7 +15,6 @@ import (
)
type StepVerifySourceDisk struct {
SubscriptionID string
SourceDiskResourceID string
Location string
}
@ -34,10 +33,10 @@ func (s StepVerifySourceDisk) Run(ctx context.Context, state multistep.StateBag)
return multistep.ActionHalt
}
if !strings.EqualFold(resource.SubscriptionID, s.SubscriptionID) {
if !strings.EqualFold(resource.SubscriptionID, azcli.SubscriptionID()) {
err := fmt.Errorf("Source disk resource %q is in a different subscription than this VM (%q). "+
"Packer does not know how to handle that.",
s.SourceDiskResourceID, s.SubscriptionID)
s.SourceDiskResourceID, azcli.SubscriptionID())
log.Printf("StepVerifySourceDisk.Run: error: %+v", err)
state.Put("error", err)
ui.Error(err.Error())

View file

@ -9,7 +9,7 @@ import (
"strings"
"testing"
"github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute"
"github.com/Azure/go-autorest/autorest"
"github.com/hashicorp/packer/builder/azure/common/client"
"github.com/hashicorp/packer/helper/multistep"
@ -18,7 +18,6 @@ import (
func Test_StepVerifySourceDisk_Run(t *testing.T) {
type fields struct {
SubscriptionID string
SourceDiskResourceID string
Location string
@ -38,7 +37,6 @@ func Test_StepVerifySourceDisk_Run(t *testing.T) {
{
name: "HappyPath",
fields: fields{
SubscriptionID: "subid1",
SourceDiskResourceID: "/subscriptions/subid1/resourcegroups/rg1/providers/Microsoft.Compute/disks/disk1",
Location: "westus2",
@ -50,7 +48,6 @@ func Test_StepVerifySourceDisk_Run(t *testing.T) {
{
name: "NotAResourceID",
fields: fields{
SubscriptionID: "subid1",
SourceDiskResourceID: "/other",
Location: "westus2",
@ -63,7 +60,6 @@ func Test_StepVerifySourceDisk_Run(t *testing.T) {
{
name: "DiskNotFound",
fields: fields{
SubscriptionID: "subid1",
SourceDiskResourceID: "/subscriptions/subid1/resourcegroups/rg1/providers/Microsoft.Compute/disks/disk1",
Location: "westus2",
@ -76,7 +72,6 @@ func Test_StepVerifySourceDisk_Run(t *testing.T) {
{
name: "NotADisk",
fields: fields{
SubscriptionID: "subid1",
SourceDiskResourceID: "/subscriptions/subid1/resourcegroups/rg1/providers/Microsoft.Compute/images/image1",
Location: "westus2",
@ -88,7 +83,6 @@ func Test_StepVerifySourceDisk_Run(t *testing.T) {
{
name: "OtherSubscription",
fields: fields{
SubscriptionID: "subid1",
SourceDiskResourceID: "/subscriptions/subid2/resourcegroups/rg1/providers/Microsoft.Compute/disks/disk1",
Location: "westus2",
@ -101,7 +95,6 @@ func Test_StepVerifySourceDisk_Run(t *testing.T) {
{
name: "OtherLocation",
fields: fields{
SubscriptionID: "subid1",
SourceDiskResourceID: "/subscriptions/subid1/resourcegroups/rg1/providers/Microsoft.Compute/disks/disk1",
Location: "eastus",
@ -115,7 +108,6 @@ func Test_StepVerifySourceDisk_Run(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := StepVerifySourceDisk{
SubscriptionID: tt.fields.SubscriptionID,
SourceDiskResourceID: tt.fields.SourceDiskResourceID,
Location: tt.fields.Location,
}
@ -129,16 +121,12 @@ func Test_StepVerifySourceDisk_Run(t *testing.T) {
}, nil
})
errorBuffer := &strings.Builder{}
ui := &packer.BasicUi{
Reader: strings.NewReader(""),
Writer: ioutil.Discard,
ErrorWriter: errorBuffer,
}
ui, getErr := testUI()
state := new(multistep.BasicStateBag)
state.Put("azureclient", &client.AzureClientSetMock{
DisksClientMock: m,
DisksClientMock: m,
SubscriptionIDMock: "subid1",
})
state.Put("ui", ui)
@ -148,8 +136,9 @@ func Test_StepVerifySourceDisk_Run(t *testing.T) {
}
if tt.errormatch != "" {
if !regexp.MustCompile(tt.errormatch).MatchString(errorBuffer.String()) {
t.Errorf("Expected the error output (%q) to match %q", errorBuffer.String(), tt.errormatch)
errs := getErr()
if !regexp.MustCompile(tt.errormatch).MatchString(errs) {
t.Errorf("Expected the error output (%q) to match %q", errs, tt.errormatch)
}
}

View file

@ -0,0 +1,21 @@
package common
import (
"testing"
)
func TestArtifact_String(t *testing.T) {
a := &Artifact{
Resources: []string{
"/subscriptions/4674464f-6024-43ae-903c-f6eed761be04/resourceGroups/rg/providers/Microsoft.Compute/disks/PackerTemp-osdisk-1586461959",
"/subscriptions/4674464f-6024-43ae-903c-f6eed761be04/resourceGroups/images/providers/Microsoft.Compute/galleries/testgallery/images/myUbuntu/versions/1.0.10",
},
}
want := `Azure resources created:
/subscriptions/4674464f-6024-43ae-903c-f6eed761be04/resourcegroups/images/providers/microsoft.compute/galleries/testgallery/images/myubuntu/versions/1.0.10
/subscriptions/4674464f-6024-43ae-903c-f6eed761be04/resourcegroups/rg/providers/microsoft.compute/disks/packertemp-osdisk-1586461959
`
if got := a.String(); got != want {
t.Errorf("Artifact.String() = %v, want %v", got, want)
}
}

View file

@ -5,21 +5,30 @@ import (
"regexp"
"time"
"github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute"
"github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute/computeapi"
"github.com/Azure/go-autorest/autorest"
"github.com/hashicorp/packer/helper/useragent"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute/computeapi"
"github.com/Azure/go-autorest/autorest"
)
type AzureClientSet interface {
MetadataClient() MetadataClientAPI
DisksClient() computeapi.DisksClientAPI
SnapshotsClient() computeapi.SnapshotsClientAPI
ImagesClient() computeapi.ImagesClientAPI
GalleryImagesClient() computeapi.GalleryImagesClientAPI
GalleryImageVersionsClient() computeapi.GalleryImageVersionsClientAPI
VirtualMachinesClient() computeapi.VirtualMachinesClientAPI
VirtualMachineImagesClient() VirtualMachineImagesClientAPI
PollClient() autorest.Client
// SubscriptionID returns the subscription ID that this client set was created for
SubscriptionID() string
}
var subscriptionPathRegex = regexp.MustCompile(`/subscriptions/([[:xdigit:]]{8}(-[[:xdigit:]]{4}){3}-[[:xdigit:]]{12})`)
@ -50,6 +59,10 @@ func new(c Config, say func(string)) (*azureClientSet, error) {
}, nil
}
func (s azureClientSet) SubscriptionID() string {
return s.subscriptionID
}
func (s azureClientSet) configureAutorestClient(c *autorest.Client) {
c.AddToUserAgent(useragent.String())
c.Authorizer = s.authorizer
@ -70,6 +83,13 @@ func (s azureClientSet) DisksClient() computeapi.DisksClientAPI {
return c
}
func (s azureClientSet) SnapshotsClient() computeapi.SnapshotsClientAPI {
c := compute.NewSnapshotsClient(s.subscriptionID)
s.configureAutorestClient(&c.Client)
c.PollingDelay = s.PollingDelay
return c
}
func (s azureClientSet) ImagesClient() computeapi.ImagesClientAPI {
c := compute.NewImagesClient(s.subscriptionID)
s.configureAutorestClient(&c.Client)
@ -88,12 +108,26 @@ func (s azureClientSet) VirtualMachineImagesClient() VirtualMachineImagesClientA
c := compute.NewVirtualMachineImagesClient(s.subscriptionID)
s.configureAutorestClient(&c.Client)
c.PollingDelay = s.PollingDelay
return virtualMachineImagesClientAPI{c}
return VirtualMachineImagesClient{c}
}
func (s azureClientSet) GalleryImagesClient() computeapi.GalleryImagesClientAPI {
c := compute.NewGalleryImagesClient(s.subscriptionID)
s.configureAutorestClient(&c.Client)
c.PollingDelay = s.PollingDelay
return c
}
func (s azureClientSet) GalleryImageVersionsClient() computeapi.GalleryImageVersionsClientAPI {
c := compute.NewGalleryImageVersionsClient(s.subscriptionID)
s.configureAutorestClient(&c.Client)
c.PollingDelay = s.PollingDelay
return c
}
func (s azureClientSet) PollClient() autorest.Client {
c := autorest.NewClientWithUserAgent("Packer-Azure-ClientSet")
s.configureAutorestClient(&c)
c.PollingDelay = time.Second / 3
c.PollingDelay = time.Second * 5
return c
}

View file

@ -1,18 +1,24 @@
package client
import (
"github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute/computeapi"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute/computeapi"
"github.com/Azure/go-autorest/autorest"
)
var _ AzureClientSet = &AzureClientSetMock{}
// AzureClientSetMock provides a generic mock for AzureClientSet
type AzureClientSetMock struct {
DisksClientMock computeapi.DisksClientAPI
SnapshotsClientMock computeapi.SnapshotsClientAPI
ImagesClientMock computeapi.ImagesClientAPI
VirtualMachineImagesClientMock VirtualMachineImagesClientAPI
VirtualMachinesClientMock computeapi.VirtualMachinesClientAPI
GalleryImagesClientMock computeapi.GalleryImagesClientAPI
GalleryImageVersionsClientMock computeapi.GalleryImageVersionsClientAPI
PollClientMock autorest.Client
MetadataClientMock MetadataClientAPI
SubscriptionIDMock string
}
// DisksClient returns a DisksClientAPI
@ -20,6 +26,11 @@ func (m *AzureClientSetMock) DisksClient() computeapi.DisksClientAPI {
return m.DisksClientMock
}
// SnapshotsClient returns a SnapshotsClientAPI
func (m *AzureClientSetMock) SnapshotsClient() computeapi.SnapshotsClientAPI {
return m.SnapshotsClientMock
}
// ImagesClient returns a ImagesClientAPI
func (m *AzureClientSetMock) ImagesClient() computeapi.ImagesClientAPI {
return m.ImagesClientMock
@ -35,6 +46,16 @@ func (m *AzureClientSetMock) VirtualMachinesClient() computeapi.VirtualMachinesC
return m.VirtualMachinesClientMock
}
// GalleryImagesClient returns a GalleryImagesClientAPI
func (m *AzureClientSetMock) GalleryImagesClient() computeapi.GalleryImagesClientAPI {
return m.GalleryImagesClientMock
}
// GalleryImageVersionsClient returns a GalleryImageVersionsClientAPI
func (m *AzureClientSetMock) GalleryImageVersionsClient() computeapi.GalleryImageVersionsClientAPI {
return m.GalleryImageVersionsClientMock
}
// PollClient returns an autorest Client that can be used for polling async requests
func (m *AzureClientSetMock) PollClient() autorest.Client {
return m.PollClientMock
@ -44,3 +65,8 @@ func (m *AzureClientSetMock) PollClient() autorest.Client {
func (m *AzureClientSetMock) MetadataClient() MetadataClientAPI {
return m.MetadataClientMock
}
// SubscriptionID returns SubscriptionIDMock
func (m *AzureClientSetMock) SubscriptionID() string {
return m.SubscriptionIDMock
}

View file

@ -12,11 +12,22 @@ import (
// DefaultMetadataClient is the default instance metadata client for Azure. Replace this variable for testing purposes only
var DefaultMetadataClient = NewMetadataClient()
// MetadataClient holds methods that Packer uses to get information about the current VM
// MetadataClientAPI holds methods that Packer uses to get information about the current VM
type MetadataClientAPI interface {
GetComputeInfo() (*ComputeInfo, error)
}
// MetadataClientStub is an easy way to put a test hook in DefaultMetadataClient
type MetadataClientStub struct {
ComputeInfo
}
//GetComputeInfo implements MetadataClientAPI
func (s MetadataClientStub) GetComputeInfo() (*ComputeInfo, error) {
return &s.ComputeInfo, nil
}
// ComputeInfo defines the Azure VM metadata that is used in Packer
type ComputeInfo struct {
Name string
ResourceGroupName string

View file

@ -6,8 +6,8 @@ import (
"regexp"
"strings"
"github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute"
"github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute/computeapi"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute/computeapi"
"github.com/Azure/go-autorest/autorest/to"
)
@ -19,9 +19,9 @@ type VirtualMachineImagesClientAPI interface {
GetLatest(ctx context.Context, publisher, offer, sku, location string) (*compute.VirtualMachineImageResource, error)
}
var _ VirtualMachineImagesClientAPI = virtualMachineImagesClientAPI{}
var _ VirtualMachineImagesClientAPI = VirtualMachineImagesClient{}
type virtualMachineImagesClientAPI struct {
type VirtualMachineImagesClient struct {
computeapi.VirtualMachineImagesClientAPI
}
@ -33,7 +33,7 @@ func ParsePlatformImageURN(urn string) (image *PlatformImage, err error) {
return &PlatformImage{parts[0], parts[1], parts[2], parts[3]}, nil
}
func (c virtualMachineImagesClientAPI) GetLatest(ctx context.Context, publisher, offer, sku, location string) (*compute.VirtualMachineImageResource, error) {
func (c VirtualMachineImagesClient) GetLatest(ctx context.Context, publisher, offer, sku, location string) (*compute.VirtualMachineImageResource, error) {
result, err := c.List(ctx, location, publisher, offer, sku, "", to.Int32Ptr(1), "name desc")
if err != nil {
return nil, err

View file

@ -0,0 +1,13 @@
package common
import "strings"
// StringsContains returns true if the `haystack` contains the `needle`. Search is case insensitive.
func StringsContains(haystack []string, needle string) bool {
for _, s := range haystack {
if strings.EqualFold(s, needle) {
return true
}
}
return false
}

View file

@ -0,0 +1,39 @@
package common
import "testing"
func TestStringsContains(t *testing.T) {
tests := []struct {
name string
haystack []string
needle string
want bool
}{
{
name: "found",
haystack: []string{"a", "b", "c"},
needle: "b",
want: true,
},
{
name: "missing",
haystack: []string{"a", "b", "c"},
needle: "D",
want: false,
},
{
name: "case insensitive",
haystack: []string{"a", "b", "c"},
needle: "B",
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := StringsContains(tt.haystack, tt.needle); got != tt.want {
t.Errorf("StringsContains() = %v, want %v", got, tt.want)
}
})
}
}

View file

@ -145,7 +145,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"cloud_environment_name": &hcldec.AttrSpec{Name: "cloud_environment_name", Type: cty.String, Required: false},
"client_id": &hcldec.AttrSpec{Name: "client_id", Type: cty.String, Required: false},
@ -172,7 +172,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"managed_image_resource_group_name": &hcldec.AttrSpec{Name: "managed_image_resource_group_name", Type: cty.String, Required: false},
"managed_image_name": &hcldec.AttrSpec{Name: "managed_image_name", Type: cty.String, Required: false},
"managed_image_storage_account_type": &hcldec.AttrSpec{Name: "managed_image_storage_account_type", Type: cty.String, Required: false},
"azure_tags": &hcldec.BlockAttrsSpec{TypeName: "azure_tags", ElementType: cty.String, Required: false},
"azure_tags": &hcldec.AttrSpec{Name: "azure_tags", Type: cty.Map(cty.String), Required: false},
"plan_id": &hcldec.AttrSpec{Name: "plan_id", Type: cty.String, Required: false},
"polling_duration_timeout": &hcldec.AttrSpec{Name: "polling_duration_timeout", Type: cty.String, Required: false},
"os_type": &hcldec.AttrSpec{Name: "os_type", Type: cty.String, Required: false},

View file

@ -119,7 +119,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},
@ -204,7 +204,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"template_requires_hvm": &hcldec.AttrSpec{Name: "template_requires_hvm", Type: cty.Bool, Required: false},
"template_scalable": &hcldec.AttrSpec{Name: "template_scalable", Type: cty.Bool, Required: false},
"template_tag": &hcldec.AttrSpec{Name: "template_tag", Type: cty.String, Required: false},
"tags": &hcldec.BlockAttrsSpec{TypeName: "tags", ElementType: cty.String, Required: false},
"tags": &hcldec.AttrSpec{Name: "tags", Type: cty.Map(cty.String), Required: false},
}
return s
}

View file

@ -92,7 +92,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false},
"pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false},

View file

@ -101,7 +101,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false},
"pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false},
@ -157,7 +157,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"pty": &hcldec.AttrSpec{Name: "pty", Type: cty.Bool, Required: false},
"pull": &hcldec.AttrSpec{Name: "pull", Type: cty.Bool, Required: false},
"run_command": &hcldec.AttrSpec{Name: "run_command", Type: cty.List(cty.String), Required: false},
"volumes": &hcldec.BlockAttrsSpec{TypeName: "volumes", ElementType: cty.String, Required: false},
"volumes": &hcldec.AttrSpec{Name: "volumes", Type: cty.Map(cty.String), Required: false},
"fix_upload_owner": &hcldec.AttrSpec{Name: "fix_upload_owner", Type: cty.Bool, Required: false},
"windows_container": &hcldec.AttrSpec{Name: "windows_container", Type: cty.Bool, Required: false},
"login": &hcldec.AttrSpec{Name: "login", Type: cty.Bool, Required: false},

View file

@ -38,7 +38,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"source": &hcldec.AttrSpec{Name: "source", Type: cty.String, Required: false},
"target": &hcldec.AttrSpec{Name: "target", Type: cty.String, Required: false},

View file

@ -115,7 +115,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false},
"pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false},
@ -171,13 +171,13 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"image_description": &hcldec.AttrSpec{Name: "image_description", Type: cty.String, Required: false},
"image_encryption_key": &hcldec.BlockSpec{TypeName: "image_encryption_key", Nested: hcldec.ObjectSpec((*FlatCustomerEncryptionKey)(nil).HCL2Spec())},
"image_family": &hcldec.AttrSpec{Name: "image_family", Type: cty.String, Required: false},
"image_labels": &hcldec.BlockAttrsSpec{TypeName: "image_labels", ElementType: cty.String, Required: false},
"image_labels": &hcldec.AttrSpec{Name: "image_labels", Type: cty.Map(cty.String), Required: false},
"image_licenses": &hcldec.AttrSpec{Name: "image_licenses", Type: cty.List(cty.String), Required: false},
"instance_name": &hcldec.AttrSpec{Name: "instance_name", Type: cty.String, Required: false},
"labels": &hcldec.BlockAttrsSpec{TypeName: "labels", ElementType: cty.String, Required: false},
"labels": &hcldec.AttrSpec{Name: "labels", Type: cty.Map(cty.String), Required: false},
"machine_type": &hcldec.AttrSpec{Name: "machine_type", Type: cty.String, Required: false},
"metadata": &hcldec.BlockAttrsSpec{TypeName: "metadata", ElementType: cty.String, Required: false},
"metadata_files": &hcldec.BlockAttrsSpec{TypeName: "metadata_files", ElementType: cty.String, Required: false},
"metadata": &hcldec.AttrSpec{Name: "metadata", Type: cty.Map(cty.String), Required: false},
"metadata_files": &hcldec.AttrSpec{Name: "metadata_files", Type: cty.Map(cty.String), Required: false},
"min_cpu_platform": &hcldec.AttrSpec{Name: "min_cpu_platform", Type: cty.String, Required: false},
"network": &hcldec.AttrSpec{Name: "network", Type: cty.String, Required: false},
"network_project_id": &hcldec.AttrSpec{Name: "network_project_id", Type: cty.String, Required: false},

View file

@ -90,7 +90,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false},
"pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false},
@ -142,7 +142,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"image": &hcldec.AttrSpec{Name: "image", Type: cty.String, Required: false},
"image_filter": &hcldec.BlockSpec{TypeName: "image_filter", Nested: hcldec.ObjectSpec((*FlatimageFilter)(nil).HCL2Spec())},
"snapshot_name": &hcldec.AttrSpec{Name: "snapshot_name", Type: cty.String, Required: false},
"snapshot_labels": &hcldec.BlockAttrsSpec{TypeName: "snapshot_labels", ElementType: cty.String, Required: false},
"snapshot_labels": &hcldec.AttrSpec{Name: "snapshot_labels", Type: cty.Map(cty.String), Required: false},
"user_data": &hcldec.AttrSpec{Name: "user_data", Type: cty.String, Required: false},
"user_data_file": &hcldec.AttrSpec{Name: "user_data_file", Type: cty.String, Required: false},
"ssh_keys": &hcldec.AttrSpec{Name: "ssh_keys", Type: cty.List(cty.String), Required: false},

View file

@ -112,7 +112,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false},
"pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false},
@ -163,12 +163,12 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"source_image": &hcldec.AttrSpec{Name: "source_image", Type: cty.String, Required: false},
"image_name": &hcldec.AttrSpec{Name: "image_name", Type: cty.String, Required: false},
"image_description": &hcldec.AttrSpec{Name: "image_description", Type: cty.String, Required: false},
"image_tags": &hcldec.BlockAttrsSpec{TypeName: "image_tags", ElementType: cty.String, Required: false},
"image_tags": &hcldec.AttrSpec{Name: "image_tags", Type: cty.Map(cty.String), Required: false},
"image_tag": &hcldec.BlockListSpec{TypeName: "image_tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"image_service": &hcldec.AttrSpec{Name: "image_service", Type: cty.String, Required: false},
"vm_type": &hcldec.AttrSpec{Name: "vm_type", Type: cty.String, Required: false},
"vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false},
"vm_tags": &hcldec.BlockAttrsSpec{TypeName: "vm_tags", ElementType: cty.String, Required: false},
"vm_tags": &hcldec.AttrSpec{Name: "vm_tags", Type: cty.Map(cty.String), Required: false},
"vm_tag": &hcldec.BlockListSpec{TypeName: "vm_tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"disk_name": &hcldec.AttrSpec{Name: "disk_name", Type: cty.String, Required: false},
"disk_type": &hcldec.AttrSpec{Name: "disk_type", Type: cty.String, Required: false},

View file

@ -124,7 +124,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},

View file

@ -126,7 +126,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},

View file

@ -143,7 +143,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
}
return s

View file

@ -87,7 +87,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false},
"pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false},

View file

@ -47,7 +47,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"config_file": &hcldec.AttrSpec{Name: "config_file", Type: cty.String, Required: false},
"output_directory": &hcldec.AttrSpec{Name: "output_directory", Type: cty.String, Required: false},

View file

@ -43,7 +43,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"output_image": &hcldec.AttrSpec{Name: "output_image", Type: cty.String, Required: false},
"container_name": &hcldec.AttrSpec{Name: "container_name", Type: cty.String, Required: false},
@ -51,8 +51,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"image": &hcldec.AttrSpec{Name: "image", Type: cty.String, Required: false},
"profile": &hcldec.AttrSpec{Name: "profile", Type: cty.String, Required: false},
"init_sleep": &hcldec.AttrSpec{Name: "init_sleep", Type: cty.String, Required: false},
"publish_properties": &hcldec.BlockAttrsSpec{TypeName: "publish_properties", ElementType: cty.String, Required: false},
"launch_config": &hcldec.BlockAttrsSpec{TypeName: "launch_config", ElementType: cty.String, Required: false},
"publish_properties": &hcldec.AttrSpec{Name: "publish_properties", Type: cty.Map(cty.String), Required: false},
"launch_config": &hcldec.AttrSpec{Name: "launch_config", Type: cty.Map(cty.String), Required: false},
}
return s
}

View file

@ -88,7 +88,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false},
"secret_key": &hcldec.AttrSpec{Name: "secret_key", Type: cty.String, Required: false},

View file

@ -76,7 +76,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false},
"pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false},

View file

@ -84,7 +84,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false},
"pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false},

View file

@ -134,7 +134,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"username": &hcldec.AttrSpec{Name: "username", Type: cty.String, Required: false},
"user_id": &hcldec.AttrSpec{Name: "user_id", Type: cty.String, Required: false},
@ -156,7 +156,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"application_credential_secret": &hcldec.AttrSpec{Name: "application_credential_secret", Type: cty.String, Required: false},
"cloud": &hcldec.AttrSpec{Name: "cloud", Type: cty.String, Required: false},
"image_name": &hcldec.AttrSpec{Name: "image_name", Type: cty.String, Required: false},
"metadata": &hcldec.BlockAttrsSpec{TypeName: "metadata", ElementType: cty.String, Required: false},
"metadata": &hcldec.AttrSpec{Name: "metadata", Type: cty.Map(cty.String), Required: false},
"image_visibility": &hcldec.AttrSpec{Name: "image_visibility", Type: cty.String, Required: false},
"image_members": &hcldec.AttrSpec{Name: "image_members", Type: cty.List(cty.String), Required: false},
"image_auto_accept_members": &hcldec.AttrSpec{Name: "image_auto_accept_members", Type: cty.Bool, Required: false},
@ -223,7 +223,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"user_data": &hcldec.AttrSpec{Name: "user_data", Type: cty.String, Required: false},
"user_data_file": &hcldec.AttrSpec{Name: "user_data_file", Type: cty.String, Required: false},
"instance_name": &hcldec.AttrSpec{Name: "instance_name", Type: cty.String, Required: false},
"instance_metadata": &hcldec.BlockAttrsSpec{TypeName: "instance_metadata", ElementType: cty.String, Required: false},
"instance_metadata": &hcldec.AttrSpec{Name: "instance_metadata", Type: cty.Map(cty.String), Required: false},
"force_delete": &hcldec.AttrSpec{Name: "force_delete", Type: cty.Bool, Required: false},
"config_drive": &hcldec.AttrSpec{Name: "config_drive", Type: cty.Bool, Required: false},
"floating_ip_pool": &hcldec.AttrSpec{Name: "floating_ip_pool", Type: cty.String, Required: false},
@ -289,7 +289,7 @@ func (*FlatImageFilterOptions) HCL2Spec() map[string]hcldec.Spec {
"owner": &hcldec.AttrSpec{Name: "owner", Type: cty.String, Required: false},
"tags": &hcldec.AttrSpec{Name: "tags", Type: cty.List(cty.String), Required: false},
"visibility": &hcldec.AttrSpec{Name: "visibility", Type: cty.String, Required: false},
"properties": &hcldec.BlockAttrsSpec{TypeName: "properties", ElementType: cty.String, Required: false},
"properties": &hcldec.AttrSpec{Name: "properties", Type: cty.Map(cty.String), Required: false},
}
return s
}

View file

@ -97,7 +97,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"persistent_volume_size": &hcldec.AttrSpec{Name: "persistent_volume_size", Type: cty.Number, Required: false},
"builder_upload_image_command": &hcldec.AttrSpec{Name: "builder_upload_image_command", Type: cty.String, Required: false},

View file

@ -98,7 +98,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false},
"pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false},
@ -157,12 +157,12 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"shape": &hcldec.AttrSpec{Name: "shape", Type: cty.String, Required: false},
"image_name": &hcldec.AttrSpec{Name: "image_name", Type: cty.String, Required: false},
"instance_name": &hcldec.AttrSpec{Name: "instance_name", Type: cty.String, Required: false},
"metadata": &hcldec.BlockAttrsSpec{TypeName: "metadata", ElementType: cty.String, Required: false},
"metadata": &hcldec.AttrSpec{Name: "metadata", Type: cty.Map(cty.String), Required: false},
"user_data": &hcldec.AttrSpec{Name: "user_data", Type: cty.String, Required: false},
"user_data_file": &hcldec.AttrSpec{Name: "user_data_file", Type: cty.String, Required: false},
"subnet_ocid": &hcldec.AttrSpec{Name: "subnet_ocid", Type: cty.String, Required: false},
"tags": &hcldec.BlockAttrsSpec{TypeName: "tags", ElementType: cty.String, Required: false},
"defined_tags": &hcldec.BlockAttrsSpec{TypeName: "defined_tags", ElementType: cty.String, Required: false},
"tags": &hcldec.AttrSpec{Name: "tags", Type: cty.Map(cty.String), Required: false},
"defined_tags": &hcldec.AttrSpec{Name: "defined_tags", Type: cty.Map(cty.String), Required: false},
}
return s
}

View file

@ -130,7 +130,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false},
"custom_endpoint_oapi": &hcldec.AttrSpec{Name: "custom_endpoint_oapi", Type: cty.String, Required: false},
@ -149,10 +149,10 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"omi_groups": &hcldec.AttrSpec{Name: "omi_groups", Type: cty.List(cty.String), Required: false},
"omi_product_codes": &hcldec.AttrSpec{Name: "omi_product_codes", Type: cty.List(cty.String), Required: false},
"omi_regions": &hcldec.AttrSpec{Name: "omi_regions", Type: cty.List(cty.String), Required: false},
"tags": &hcldec.BlockAttrsSpec{TypeName: "tags", ElementType: cty.String, Required: false},
"tags": &hcldec.AttrSpec{Name: "tags", Type: cty.Map(cty.String), Required: false},
"force_deregister": &hcldec.AttrSpec{Name: "force_deregister", Type: cty.Bool, Required: false},
"force_delete_snapshot": &hcldec.AttrSpec{Name: "force_delete_snapshot", Type: cty.Bool, Required: false},
"snapshot_tags": &hcldec.BlockAttrsSpec{TypeName: "snapshot_tags", ElementType: cty.String, Required: false},
"snapshot_tags": &hcldec.AttrSpec{Name: "snapshot_tags", Type: cty.Map(cty.String), Required: false},
"snapshot_account_ids": &hcldec.AttrSpec{Name: "snapshot_account_ids", Type: cty.List(cty.String), Required: false},
"snapshot_groups": &hcldec.AttrSpec{Name: "snapshot_groups", Type: cty.List(cty.String), Required: false},
"omi_block_device_mappings": &hcldec.BlockListSpec{TypeName: "omi_block_device_mappings", Nested: hcldec.ObjectSpec((*common.FlatBlockDevice)(nil).HCL2Spec())},
@ -167,14 +167,14 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"shutdown_behavior": &hcldec.AttrSpec{Name: "shutdown_behavior", Type: cty.String, Required: false},
"vm_type": &hcldec.AttrSpec{Name: "vm_type", Type: cty.String, Required: false},
"security_group_filter": &hcldec.BlockSpec{TypeName: "security_group_filter", Nested: hcldec.ObjectSpec((*common.FlatSecurityGroupFilterOptions)(nil).HCL2Spec())},
"run_tags": &hcldec.BlockAttrsSpec{TypeName: "run_tags", ElementType: cty.String, Required: false},
"run_tags": &hcldec.AttrSpec{Name: "run_tags", Type: cty.Map(cty.String), Required: false},
"security_group_id": &hcldec.AttrSpec{Name: "security_group_id", Type: cty.String, Required: false},
"security_group_ids": &hcldec.AttrSpec{Name: "security_group_ids", Type: cty.List(cty.String), Required: false},
"source_omi": &hcldec.AttrSpec{Name: "source_omi", Type: cty.String, Required: false},
"source_omi_filter": &hcldec.BlockSpec{TypeName: "source_omi_filter", Nested: hcldec.ObjectSpec((*common.FlatOmiFilterOptions)(nil).HCL2Spec())},
"spot_price": &hcldec.AttrSpec{Name: "spot_price", Type: cty.String, Required: false},
"spot_price_auto_product": &hcldec.AttrSpec{Name: "spot_price_auto_product", Type: cty.String, Required: false},
"spot_tags": &hcldec.BlockAttrsSpec{TypeName: "spot_tags", ElementType: cty.String, Required: false},
"spot_tags": &hcldec.AttrSpec{Name: "spot_tags", Type: cty.Map(cty.String), Required: false},
"subnet_filter": &hcldec.BlockSpec{TypeName: "subnet_filter", Nested: hcldec.ObjectSpec((*common.FlatSubnetFilterOptions)(nil).HCL2Spec())},
"subnet_id": &hcldec.AttrSpec{Name: "subnet_id", Type: cty.String, Required: false},
"temporary_key_pair_name": &hcldec.AttrSpec{Name: "temporary_key_pair_name", Type: cty.String, Required: false},
@ -225,7 +225,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"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},
"ssh_interface": &hcldec.AttrSpec{Name: "ssh_interface", Type: cty.String, Required: false},
"run_volume_tags": &hcldec.BlockAttrsSpec{TypeName: "run_volume_tags", ElementType: cty.String, Required: false},
"run_volume_tags": &hcldec.AttrSpec{Name: "run_volume_tags", Type: cty.Map(cty.String), Required: false},
}
return s
}

View file

@ -131,7 +131,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false},
"custom_endpoint_oapi": &hcldec.AttrSpec{Name: "custom_endpoint_oapi", Type: cty.String, Required: false},
@ -153,14 +153,14 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"shutdown_behavior": &hcldec.AttrSpec{Name: "shutdown_behavior", Type: cty.String, Required: false},
"vm_type": &hcldec.AttrSpec{Name: "vm_type", Type: cty.String, Required: false},
"security_group_filter": &hcldec.BlockSpec{TypeName: "security_group_filter", Nested: hcldec.ObjectSpec((*common.FlatSecurityGroupFilterOptions)(nil).HCL2Spec())},
"run_tags": &hcldec.BlockAttrsSpec{TypeName: "run_tags", ElementType: cty.String, Required: false},
"run_tags": &hcldec.AttrSpec{Name: "run_tags", Type: cty.Map(cty.String), Required: false},
"security_group_id": &hcldec.AttrSpec{Name: "security_group_id", Type: cty.String, Required: false},
"security_group_ids": &hcldec.AttrSpec{Name: "security_group_ids", Type: cty.List(cty.String), Required: false},
"source_omi": &hcldec.AttrSpec{Name: "source_omi", Type: cty.String, Required: false},
"source_omi_filter": &hcldec.BlockSpec{TypeName: "source_omi_filter", Nested: hcldec.ObjectSpec((*common.FlatOmiFilterOptions)(nil).HCL2Spec())},
"spot_price": &hcldec.AttrSpec{Name: "spot_price", Type: cty.String, Required: false},
"spot_price_auto_product": &hcldec.AttrSpec{Name: "spot_price_auto_product", Type: cty.String, Required: false},
"spot_tags": &hcldec.BlockAttrsSpec{TypeName: "spot_tags", ElementType: cty.String, Required: false},
"spot_tags": &hcldec.AttrSpec{Name: "spot_tags", Type: cty.Map(cty.String), Required: false},
"subnet_filter": &hcldec.BlockSpec{TypeName: "subnet_filter", Nested: hcldec.ObjectSpec((*common.FlatSubnetFilterOptions)(nil).HCL2Spec())},
"subnet_id": &hcldec.AttrSpec{Name: "subnet_id", Type: cty.String, Required: false},
"temporary_key_pair_name": &hcldec.AttrSpec{Name: "temporary_key_pair_name", Type: cty.String, Required: false},
@ -220,14 +220,14 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"omi_groups": &hcldec.AttrSpec{Name: "omi_groups", Type: cty.List(cty.String), Required: false},
"omi_product_codes": &hcldec.AttrSpec{Name: "omi_product_codes", Type: cty.List(cty.String), Required: false},
"omi_regions": &hcldec.AttrSpec{Name: "omi_regions", Type: cty.List(cty.String), Required: false},
"tags": &hcldec.BlockAttrsSpec{TypeName: "tags", ElementType: cty.String, Required: false},
"tags": &hcldec.AttrSpec{Name: "tags", Type: cty.Map(cty.String), Required: false},
"force_deregister": &hcldec.AttrSpec{Name: "force_deregister", Type: cty.Bool, Required: false},
"force_delete_snapshot": &hcldec.AttrSpec{Name: "force_delete_snapshot", Type: cty.Bool, Required: false},
"snapshot_tags": &hcldec.BlockAttrsSpec{TypeName: "snapshot_tags", ElementType: cty.String, Required: false},
"snapshot_tags": &hcldec.AttrSpec{Name: "snapshot_tags", Type: cty.Map(cty.String), Required: false},
"snapshot_account_ids": &hcldec.AttrSpec{Name: "snapshot_account_ids", Type: cty.List(cty.String), Required: false},
"snapshot_groups": &hcldec.AttrSpec{Name: "snapshot_groups", Type: cty.List(cty.String), Required: false},
"omi_root_device": &hcldec.BlockSpec{TypeName: "omi_root_device", Nested: hcldec.ObjectSpec((*FlatRootBlockDevice)(nil).HCL2Spec())},
"run_volume_tags": &hcldec.BlockAttrsSpec{TypeName: "run_volume_tags", ElementType: cty.String, Required: false},
"run_volume_tags": &hcldec.AttrSpec{Name: "run_volume_tags", Type: cty.Map(cty.String), Required: false},
}
return s
}

View file

@ -41,7 +41,7 @@ func (*FlatBlockDevice) HCL2Spec() map[string]hcldec.Spec {
"virtual_name": &hcldec.AttrSpec{Name: "virtual_name", Type: cty.String, Required: false},
"volume_type": &hcldec.AttrSpec{Name: "volume_type", Type: cty.String, Required: false},
"volume_size": &hcldec.AttrSpec{Name: "volume_size", Type: cty.Number, Required: false},
"tags": &hcldec.BlockAttrsSpec{TypeName: "tags", ElementType: cty.String, Required: false},
"tags": &hcldec.AttrSpec{Name: "tags", Type: cty.Map(cty.String), Required: false},
}
return s
}
@ -154,7 +154,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false},
"custom_endpoint_oapi": &hcldec.AttrSpec{Name: "custom_endpoint_oapi", Type: cty.String, Required: false},
@ -176,14 +176,14 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"shutdown_behavior": &hcldec.AttrSpec{Name: "shutdown_behavior", Type: cty.String, Required: false},
"vm_type": &hcldec.AttrSpec{Name: "vm_type", Type: cty.String, Required: false},
"security_group_filter": &hcldec.BlockSpec{TypeName: "security_group_filter", Nested: hcldec.ObjectSpec((*common.FlatSecurityGroupFilterOptions)(nil).HCL2Spec())},
"run_tags": &hcldec.BlockAttrsSpec{TypeName: "run_tags", ElementType: cty.String, Required: false},
"run_tags": &hcldec.AttrSpec{Name: "run_tags", Type: cty.Map(cty.String), Required: false},
"security_group_id": &hcldec.AttrSpec{Name: "security_group_id", Type: cty.String, Required: false},
"security_group_ids": &hcldec.AttrSpec{Name: "security_group_ids", Type: cty.List(cty.String), Required: false},
"source_omi": &hcldec.AttrSpec{Name: "source_omi", Type: cty.String, Required: false},
"source_omi_filter": &hcldec.BlockSpec{TypeName: "source_omi_filter", Nested: hcldec.ObjectSpec((*common.FlatOmiFilterOptions)(nil).HCL2Spec())},
"spot_price": &hcldec.AttrSpec{Name: "spot_price", Type: cty.String, Required: false},
"spot_price_auto_product": &hcldec.AttrSpec{Name: "spot_price_auto_product", Type: cty.String, Required: false},
"spot_tags": &hcldec.BlockAttrsSpec{TypeName: "spot_tags", ElementType: cty.String, Required: false},
"spot_tags": &hcldec.AttrSpec{Name: "spot_tags", Type: cty.Map(cty.String), Required: false},
"subnet_filter": &hcldec.BlockSpec{TypeName: "subnet_filter", Nested: hcldec.ObjectSpec((*common.FlatSubnetFilterOptions)(nil).HCL2Spec())},
"subnet_id": &hcldec.AttrSpec{Name: "subnet_id", Type: cty.String, Required: false},
"temporary_key_pair_name": &hcldec.AttrSpec{Name: "temporary_key_pair_name", Type: cty.String, Required: false},

View file

@ -77,7 +77,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"omi_block_device_mappings": &hcldec.BlockListSpec{TypeName: "omi_block_device_mappings", Nested: hcldec.ObjectSpec((*common.FlatBlockDevice)(nil).HCL2Spec())},
"omi_name": &hcldec.AttrSpec{Name: "omi_name", Type: cty.String, Required: false},
@ -88,10 +88,10 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"omi_product_codes": &hcldec.AttrSpec{Name: "omi_product_codes", Type: cty.List(cty.String), Required: false},
"omi_regions": &hcldec.AttrSpec{Name: "omi_regions", Type: cty.List(cty.String), Required: false},
"skip_region_validation": &hcldec.AttrSpec{Name: "skip_region_validation", Type: cty.Bool, Required: false},
"tags": &hcldec.BlockAttrsSpec{TypeName: "tags", ElementType: cty.String, Required: false},
"tags": &hcldec.AttrSpec{Name: "tags", Type: cty.Map(cty.String), Required: false},
"force_deregister": &hcldec.AttrSpec{Name: "force_deregister", Type: cty.Bool, Required: false},
"force_delete_snapshot": &hcldec.AttrSpec{Name: "force_delete_snapshot", Type: cty.Bool, Required: false},
"snapshot_tags": &hcldec.BlockAttrsSpec{TypeName: "snapshot_tags", ElementType: cty.String, Required: false},
"snapshot_tags": &hcldec.AttrSpec{Name: "snapshot_tags", Type: cty.Map(cty.String), Required: false},
"snapshot_account_ids": &hcldec.AttrSpec{Name: "snapshot_account_ids", 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},
@ -119,7 +119,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"root_volume_type": &hcldec.AttrSpec{Name: "root_volume_type", Type: cty.String, Required: false},
"source_omi": &hcldec.AttrSpec{Name: "source_omi", Type: cty.String, Required: false},
"source_omi_filter": &hcldec.BlockSpec{TypeName: "source_omi_filter", Nested: hcldec.ObjectSpec((*common.FlatOmiFilterOptions)(nil).HCL2Spec())},
"root_volume_tags": &hcldec.BlockAttrsSpec{TypeName: "root_volume_tags", ElementType: cty.String, Required: false},
"root_volume_tags": &hcldec.AttrSpec{Name: "root_volume_tags", Type: cty.Map(cty.String), Required: false},
}
return s
}

View file

@ -63,7 +63,7 @@ func (*NetFilterOptions) FlatMapstructure() interface{ HCL2Spec() map[string]hcl
// The decoded values from this spec will then be applied to a FlatNetFilterOptions.
func (*FlatNetFilterOptions) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{
"filters": &hcldec.BlockAttrsSpec{TypeName: "filters", ElementType: cty.String, Required: false},
"filters": &hcldec.AttrSpec{Name: "filters", Type: cty.Map(cty.String), Required: false},
"filter": &hcldec.BlockListSpec{TypeName: "filter", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
}
return s
@ -90,7 +90,7 @@ func (*OmiFilterOptions) FlatMapstructure() interface{ HCL2Spec() map[string]hcl
// The decoded values from this spec will then be applied to a FlatOmiFilterOptions.
func (*FlatOmiFilterOptions) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{
"filters": &hcldec.BlockAttrsSpec{TypeName: "filters", ElementType: cty.String, Required: false},
"filters": &hcldec.AttrSpec{Name: "filters", Type: cty.Map(cty.String), Required: false},
"filter": &hcldec.BlockListSpec{TypeName: "filter", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"owners": &hcldec.AttrSpec{Name: "owners", Type: cty.List(cty.String), Required: false},
"most_recent": &hcldec.AttrSpec{Name: "most_recent", Type: cty.Bool, Required: false},
@ -117,7 +117,7 @@ func (*SecurityGroupFilterOptions) FlatMapstructure() interface{ HCL2Spec() map[
// The decoded values from this spec will then be applied to a FlatSecurityGroupFilterOptions.
func (*FlatSecurityGroupFilterOptions) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{
"filters": &hcldec.BlockAttrsSpec{TypeName: "filters", ElementType: cty.String, Required: false},
"filters": &hcldec.AttrSpec{Name: "filters", Type: cty.Map(cty.String), Required: false},
"filter": &hcldec.BlockListSpec{TypeName: "filter", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
}
return s
@ -144,7 +144,7 @@ func (*SubnetFilterOptions) FlatMapstructure() interface{ HCL2Spec() map[string]
// The decoded values from this spec will then be applied to a FlatSubnetFilterOptions.
func (*FlatSubnetFilterOptions) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{
"filters": &hcldec.BlockAttrsSpec{TypeName: "filters", ElementType: cty.String, Required: false},
"filters": &hcldec.AttrSpec{Name: "filters", Type: cty.Map(cty.String), Required: false},
"filter": &hcldec.BlockListSpec{TypeName: "filter", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"most_free": &hcldec.AttrSpec{Name: "most_free", Type: cty.Bool, Required: false},
"random": &hcldec.AttrSpec{Name: "random", Type: cty.Bool, Required: false},

View file

@ -113,7 +113,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},

View file

@ -96,7 +96,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"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},

View file

@ -88,7 +88,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false},
"pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false},

View file

@ -114,7 +114,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},

View file

@ -130,7 +130,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},

View file

@ -88,7 +88,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false},
"pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false},

View file

@ -114,7 +114,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"secret_id": &hcldec.AttrSpec{Name: "secret_id", Type: cty.String, Required: false},
"secret_key": &hcldec.AttrSpec{Name: "secret_key", Type: cty.String, Required: false},
@ -150,7 +150,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"user_data": &hcldec.AttrSpec{Name: "user_data", Type: cty.String, Required: false},
"user_data_file": &hcldec.AttrSpec{Name: "user_data_file", Type: cty.String, Required: false},
"host_name": &hcldec.AttrSpec{Name: "host_name", Type: cty.String, Required: false},
"run_tags": &hcldec.BlockAttrsSpec{TypeName: "run_tags", ElementType: cty.String, Required: false},
"run_tags": &hcldec.AttrSpec{Name: "run_tags", Type: cty.Map(cty.String), Required: false},
"run_tag": &hcldec.BlockListSpec{TypeName: "run_tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false},
"pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false},

View file

@ -100,7 +100,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"triton_url": &hcldec.AttrSpec{Name: "triton_url", Type: cty.String, Required: false},
"triton_account": &hcldec.AttrSpec{Name: "triton_account", Type: cty.String, Required: false},
@ -112,8 +112,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"source_machine_package": &hcldec.AttrSpec{Name: "source_machine_package", Type: cty.String, Required: false},
"source_machine_image": &hcldec.AttrSpec{Name: "source_machine_image", Type: cty.String, Required: false},
"source_machine_networks": &hcldec.AttrSpec{Name: "source_machine_networks", Type: cty.List(cty.String), Required: false},
"source_machine_metadata": &hcldec.BlockAttrsSpec{TypeName: "source_machine_metadata", ElementType: cty.String, Required: false},
"source_machine_tags": &hcldec.BlockAttrsSpec{TypeName: "source_machine_tags", ElementType: cty.String, Required: false},
"source_machine_metadata": &hcldec.AttrSpec{Name: "source_machine_metadata", Type: cty.Map(cty.String), Required: false},
"source_machine_tags": &hcldec.AttrSpec{Name: "source_machine_tags", Type: cty.Map(cty.String), Required: false},
"source_machine_tag": &hcldec.BlockListSpec{TypeName: "source_machine_tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"source_machine_firewall_enabled": &hcldec.AttrSpec{Name: "source_machine_firewall_enabled", Type: cty.Bool, Required: false},
"source_machine_image_filter": &hcldec.BlockSpec{TypeName: "source_machine_image_filter", Nested: hcldec.ObjectSpec((*FlatMachineImageFilter)(nil).HCL2Spec())},
@ -123,7 +123,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"image_homepage": &hcldec.AttrSpec{Name: "image_homepage", Type: cty.String, Required: false},
"image_eula_url": &hcldec.AttrSpec{Name: "image_eula_url", Type: cty.String, Required: false},
"image_acls": &hcldec.AttrSpec{Name: "image_acls", Type: cty.List(cty.String), Required: false},
"image_tags": &hcldec.BlockAttrsSpec{TypeName: "image_tags", ElementType: cty.String, Required: false},
"image_tags": &hcldec.AttrSpec{Name: "image_tags", Type: cty.Map(cty.String), Required: false},
"image_tag": &hcldec.BlockListSpec{TypeName: "image_tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatNameValue)(nil).HCL2Spec())},
"communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false},
"pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false},

View file

@ -95,7 +95,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"public_key": &hcldec.AttrSpec{Name: "public_key", Type: cty.String, Required: false},
"private_key": &hcldec.AttrSpec{Name: "private_key", Type: cty.String, Required: false},

View file

@ -115,7 +115,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},

View file

@ -135,7 +135,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},

View file

@ -121,7 +121,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},

View file

@ -117,7 +117,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},

View file

@ -144,12 +144,13 @@ func NewDriver(dconfig *DriverConfig, config *SSHConfig, vmName string) (Driver,
errs := ""
for _, driver := range drivers {
err := driver.Verify()
log.Printf("Testing vmware driver %T. Success: %t",
driver, err == nil)
log.Printf("Testing against vmware driver %T, Success: %t", driver, err == nil)
if err == nil {
return driver, nil
}
log.Printf("skipping %T because it failed with the following error %s", driver, err)
errs += "* " + err.Error() + "\n"
}

View file

@ -14,6 +14,11 @@ type RunConfig struct {
// this value is set to true, the machine will start without a console. For
// VMware machines, Packer will output VNC connection information in case you
// need to connect to the console to debug the build process.
// Some users have experienced issues where Packer cannot properly connect
// to a VM if it is headless; this appears to be a result of not ever having
// launched the VMWare GUI and accepting the evaluation license, or
// supplying a real license. If you experience this, launching VMWare and
// accepting the license should resolve your problem.
Headless bool `mapstructure:"headless" required:"false"`
// The IP address that should be
// binded to for VNC. By default packer will use 127.0.0.1 for this. If you

View file

@ -146,7 +146,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},
@ -239,8 +239,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"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_path": &hcldec.AttrSpec{Name: "tools_upload_path", Type: cty.String, Required: false},
"vmx_data": &hcldec.BlockAttrsSpec{TypeName: "vmx_data", ElementType: cty.String, Required: false},
"vmx_data_post": &hcldec.BlockAttrsSpec{TypeName: "vmx_data_post", ElementType: 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_remove_ethernet_interfaces": &hcldec.AttrSpec{Name: "vmx_remove_ethernet_interfaces", Type: cty.Bool, Required: false},
"display_name": &hcldec.AttrSpec{Name: "display_name", Type: cty.String, Required: false},
"format": &hcldec.AttrSpec{Name: "format", Type: cty.String, Required: false},

View file

@ -122,7 +122,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},
@ -199,8 +199,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"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_path": &hcldec.AttrSpec{Name: "tools_upload_path", Type: cty.String, Required: false},
"vmx_data": &hcldec.BlockAttrsSpec{TypeName: "vmx_data", ElementType: cty.String, Required: false},
"vmx_data_post": &hcldec.BlockAttrsSpec{TypeName: "vmx_data_post", ElementType: 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_remove_ethernet_interfaces": &hcldec.AttrSpec{Name: "vmx_remove_ethernet_interfaces", Type: cty.Bool, Required: false},
"display_name": &hcldec.AttrSpec{Name: "display_name", Type: cty.String, Required: false},
"format": &hcldec.AttrSpec{Name: "format", Type: cty.String, Required: false},

View file

@ -45,6 +45,7 @@ type FlatConfig struct {
VideoRAM *int64 `mapstructure:"video_ram" cty:"video_ram"`
VGPUProfile *string `mapstructure:"vgpu_profile" cty:"vgpu_profile"`
NestedHV *bool `mapstructure:"NestedHV" cty:"NestedHV"`
Firmware *string `mapstructure:"firmware" cty:"firmware"`
ConfigParams map[string]string `mapstructure:"configuration_parameters" cty:"configuration_parameters"`
BootOrder *string `mapstructure:"boot_order" cty:"boot_order"`
WaitTimeout *string `mapstructure:"ip_wait_timeout" cty:"ip_wait_timeout"`
@ -114,7 +115,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"vcenter_server": &hcldec.AttrSpec{Name: "vcenter_server", Type: cty.String, Required: false},
"username": &hcldec.AttrSpec{Name: "username", Type: cty.String, Required: false},
@ -144,7 +145,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"video_ram": &hcldec.AttrSpec{Name: "video_ram", Type: cty.Number, Required: false},
"vgpu_profile": &hcldec.AttrSpec{Name: "vgpu_profile", Type: cty.String, Required: false},
"NestedHV": &hcldec.AttrSpec{Name: "NestedHV", Type: cty.Bool, Required: false},
"configuration_parameters": &hcldec.BlockAttrsSpec{TypeName: "configuration_parameters", ElementType: cty.String, Required: false},
"firmware": &hcldec.AttrSpec{Name: "firmware", Type: cty.String, Required: false},
"configuration_parameters": &hcldec.AttrSpec{Name: "configuration_parameters", Type: cty.Map(cty.String), Required: false},
"boot_order": &hcldec.AttrSpec{Name: "boot_order", Type: cty.String, Required: false},
"ip_wait_timeout": &hcldec.AttrSpec{Name: "ip_wait_timeout", Type: cty.String, Required: false},
"ip_settle_timeout": &hcldec.AttrSpec{Name: "ip_settle_timeout", Type: cty.String, Required: false},

View file

@ -24,7 +24,7 @@ func (*ConfigParamsConfig) FlatMapstructure() interface{ HCL2Spec() map[string]h
// The decoded values from this spec will then be applied to a FlatConfigParamsConfig.
func (*FlatConfigParamsConfig) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{
"configuration_parameters": &hcldec.BlockAttrsSpec{TypeName: "configuration_parameters", ElementType: cty.String, Required: false},
"configuration_parameters": &hcldec.AttrSpec{Name: "configuration_parameters", Type: cty.Map(cty.String), Required: false},
}
return s
}

View file

@ -39,6 +39,8 @@ type HardwareConfig struct {
VGPUProfile string `mapstructure:"vgpu_profile"`
// Enable nested hardware virtualization for VM. Defaults to `false`.
NestedHV bool `mapstructure:"NestedHV"`
// Set the Firmware for virtual machine. Supported values: `bios`, `efi`, `efi-secure` or empty string to keep as in template. Defaults to empty string.
Firmware string `mapstructure:"firmware"`
}
func (c *HardwareConfig) Prepare() []error {
@ -48,6 +50,10 @@ func (c *HardwareConfig) Prepare() []error {
errs = append(errs, fmt.Errorf("'RAM_reservation' and 'RAM_reserve_all' cannot be used together"))
}
if c.Firmware != "" && c.Firmware != "bios" && c.Firmware != "efi" && c.Firmware != "efi-secure" {
errs = append(errs, fmt.Errorf("'firmware' must be '', 'bios', 'efi' or 'efi-secure'"))
}
return errs
}
@ -75,6 +81,7 @@ func (s *StepConfigureHardware) Run(_ context.Context, state multistep.StateBag)
MemoryHotAddEnabled: s.Config.MemoryHotAddEnabled,
VideoRAM: s.Config.VideoRAM,
VGPUProfile: s.Config.VGPUProfile,
Firmware: s.Config.Firmware,
})
if err != nil {
state.Put("error", err)

View file

@ -21,6 +21,7 @@ type FlatHardwareConfig struct {
VideoRAM *int64 `mapstructure:"video_ram" cty:"video_ram"`
VGPUProfile *string `mapstructure:"vgpu_profile" cty:"vgpu_profile"`
NestedHV *bool `mapstructure:"NestedHV" cty:"NestedHV"`
Firmware *string `mapstructure:"firmware" cty:"firmware"`
}
// FlatMapstructure returns a new FlatHardwareConfig.
@ -47,6 +48,7 @@ func (*FlatHardwareConfig) HCL2Spec() map[string]hcldec.Spec {
"video_ram": &hcldec.AttrSpec{Name: "video_ram", Type: cty.Number, Required: false},
"vgpu_profile": &hcldec.AttrSpec{Name: "vgpu_profile", Type: cty.String, Required: false},
"NestedHV": &hcldec.AttrSpec{Name: "NestedHV", Type: cty.Bool, Required: false},
"firmware": &hcldec.AttrSpec{Name: "firmware", Type: cty.String, Required: false},
}
return s
}

View file

@ -48,6 +48,7 @@ type HardwareConfig struct {
MemoryHotAddEnabled bool
VideoRAM int64
VGPUProfile string
Firmware string
}
type NIC struct {
@ -71,7 +72,7 @@ type CreateConfig struct {
NICs []NIC
USBController bool
Version uint // example: 10
Firmware string // efi or bios
Firmware string // efi-secure, efi or bios
Storage []Disk
}
@ -108,7 +109,12 @@ func (d *Driver) CreateVM(config *CreateConfig) (*VirtualMachine, error) {
if config.Version != 0 {
createSpec.Version = fmt.Sprintf("%s%d", "vmx-", config.Version)
}
if config.Firmware != "" {
if config.Firmware == "efi-secure" {
createSpec.Firmware = "efi"
createSpec.BootOptions = &types.VirtualMachineBootOptions{
EfiSecureBootEnabled: types.NewBool(true),
}
} else if config.Firmware != "" {
createSpec.Firmware = config.Firmware
}
@ -376,6 +382,15 @@ func (vm *VirtualMachine) Configure(config *HardwareConfig) error {
confSpec.DeviceChange = append(confSpec.DeviceChange, spec)
}
if config.Firmware == "efi-secure" || config.Firmware == "efi" {
confSpec.Firmware = "efi"
confSpec.BootOptions = &types.VirtualMachineBootOptions{
EfiSecureBootEnabled: types.NewBool(config.Firmware == "efi-secure"),
}
} else if config.Firmware != "" {
confSpec.Firmware = config.Firmware
}
task, err := vm.vm.Reconfigure(vm.driver.ctx, confSpec)
if err != nil {
return err

View file

@ -141,7 +141,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},
@ -182,7 +182,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"video_ram": &hcldec.AttrSpec{Name: "video_ram", Type: cty.Number, Required: false},
"vgpu_profile": &hcldec.AttrSpec{Name: "vgpu_profile", Type: cty.String, Required: false},
"NestedHV": &hcldec.AttrSpec{Name: "NestedHV", Type: cty.Bool, Required: false},
"configuration_parameters": &hcldec.BlockAttrsSpec{TypeName: "configuration_parameters", ElementType: cty.String, Required: false},
"configuration_parameters": &hcldec.AttrSpec{Name: "configuration_parameters", Type: cty.Map(cty.String), Required: false},
"iso_checksum": &hcldec.AttrSpec{Name: "iso_checksum", Type: cty.String, Required: false},
"iso_checksum_url": &hcldec.AttrSpec{Name: "iso_checksum_url", Type: cty.String, Required: false},
"iso_checksum_type": &hcldec.AttrSpec{Name: "iso_checksum_type", Type: cty.String, Required: false},

View file

@ -13,6 +13,22 @@ import (
"github.com/hashicorp/packer/packer"
)
// Defines a Network Adapter
//
// Example that creates two network adapters:
//
// ```json
// "network_adapters": [
// {
// "network": "VM Network",
// "network_card": "vmxnet3"
// },
// {
// "network": "OtherNetwork",
// "network_card": "vmxnet3"
// }
// ],
// ```
type NIC struct {
// Set network VM will be connected to.
Network string `mapstructure:"network"`
@ -24,8 +40,23 @@ type NIC struct {
Passthrough *bool `mapstructure:"passthrough"`
}
// Defines the disk storage for a VM.
//
// Example that will create a 15GB and a 20GB disk on the VM. The second disk will be thin provisioned:
//
// ```json
// "storage": [
// {
// "disk_size": 15000,
// },
// {
// "disk_size": 20000,
// "disk_thin_provisioned": true
// }
// ],
// ```
type DiskConfig struct {
// Set the size of the disk
// The size of the disk in MB.
DiskSize int64 `mapstructure:"disk_size" required:"true"`
// Enable VMDK thin provisioning for VM. Defaults to `false`.
DiskThinProvisioned bool `mapstructure:"disk_thin_provisioned"`
@ -43,7 +74,7 @@ type CreateConfig struct {
// here](https://code.vmware.com/apis/358/vsphere/doc/vim.vm.GuestOsDescriptor.GuestOsIdentifier.html)
// for a full list of possible values.
GuestOSType string `mapstructure:"guest_os_type"`
// Set the Firmware at machine creation. Example `efi`. Defaults to `bios`.
// Set the Firmware at machine creation. Supported values: `bios`, `efi` or `efi-secure`. Defaults to `bios`.
Firmware string `mapstructure:"firmware"`
// Set VM disk controller type. Example `pvscsi`.
DiskControllerType string `mapstructure:"disk_controller_type"`
@ -84,8 +115,8 @@ func (c *CreateConfig) Prepare() []error {
c.GuestOSType = "otherGuest"
}
if c.Firmware != "" && c.Firmware != "bios" && c.Firmware != "efi" {
errs = append(errs, fmt.Errorf("'firmware' must be 'bios' or 'efi'"))
if c.Firmware != "" && c.Firmware != "bios" && c.Firmware != "efi" && c.Firmware != "efi-secure" {
errs = append(errs, fmt.Errorf("'firmware' must be 'bios', 'efi' or 'efi-secure'"))
}
return errs

View file

@ -110,7 +110,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.BlockAttrsSpec{TypeName: "packer_user_variables", ElementType: 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},
"communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false},
"pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false},
@ -163,18 +163,18 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"disk_type": &hcldec.AttrSpec{Name: "disk_type", Type: cty.String, Required: false},
"image_description": &hcldec.AttrSpec{Name: "image_description", Type: cty.String, Required: false},
"image_family": &hcldec.AttrSpec{Name: "image_family", Type: cty.String, Required: false},
"image_labels": &hcldec.BlockAttrsSpec{TypeName: "image_labels", ElementType: cty.String, Required: false},
"image_labels": &hcldec.AttrSpec{Name: "image_labels", Type: cty.Map(cty.String), Required: false},
"image_name": &hcldec.AttrSpec{Name: "image_name", Type: cty.String, Required: false},
"image_product_ids": &hcldec.AttrSpec{Name: "image_product_ids", Type: cty.List(cty.String), Required: false},
"instance_cores": &hcldec.AttrSpec{Name: "instance_cores", Type: cty.Number, Required: false},
"instance_gpus": &hcldec.AttrSpec{Name: "instance_gpus", Type: cty.Number, Required: false},
"instance_mem_gb": &hcldec.AttrSpec{Name: "instance_mem_gb", Type: cty.Number, Required: false},
"instance_name": &hcldec.AttrSpec{Name: "instance_name", Type: cty.String, Required: false},
"labels": &hcldec.BlockAttrsSpec{TypeName: "labels", ElementType: cty.String, Required: false},
"labels": &hcldec.AttrSpec{Name: "labels", Type: cty.Map(cty.String), Required: false},
"platform_id": &hcldec.AttrSpec{Name: "platform_id", Type: cty.String, Required: false},
"max_retries": &hcldec.AttrSpec{Name: "max_retries", Type: cty.Number, Required: false},
"metadata": &hcldec.BlockAttrsSpec{TypeName: "metadata", ElementType: cty.String, Required: false},
"metadata_from_file": &hcldec.BlockAttrsSpec{TypeName: "metadata_from_file", ElementType: cty.String, Required: false},
"metadata": &hcldec.AttrSpec{Name: "metadata", Type: cty.Map(cty.String), Required: false},
"metadata_from_file": &hcldec.AttrSpec{Name: "metadata_from_file", Type: cty.Map(cty.String), Required: false},
"preemptible": &hcldec.AttrSpec{Name: "preemptible", Type: cty.Bool, Required: false},
"serial_log_file": &hcldec.AttrSpec{Name: "serial_log_file", Type: cty.String, Required: false},
"source_image_family": &hcldec.AttrSpec{Name: "source_image_family", Type: cty.String, Required: false},

View file

@ -260,10 +260,9 @@ func goFieldToCtyType(accessor string, fieldType types.Type) (interface{}, cty.T
Required: false,
}, ctyType
case *types.Map:
return &hcldec.BlockAttrsSpec{
TypeName: accessor,
ElementType: cty.String, // for now everything can be simplified to a map[string]string
Required: false,
return &hcldec.AttrSpec{
Name: accessor,
Type: cty.Map(cty.String), // for now everything can be simplified to a map[string]string
}, cty.Map(cty.String)
case *types.Named:
// Named is the relative type when of a field with a struct.

View file

@ -3,6 +3,7 @@ package command
import (
"bytes"
"fmt"
"io/ioutil"
"math"
"os"
"path/filepath"
@ -12,12 +13,14 @@ import (
"github.com/hashicorp/packer/builder/file"
"github.com/hashicorp/packer/builder/null"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/post-processor/manifest"
shell_local_pp "github.com/hashicorp/packer/post-processor/shell-local"
filep "github.com/hashicorp/packer/provisioner/file"
"github.com/hashicorp/packer/provisioner/shell"
shell_local "github.com/hashicorp/packer/provisioner/shell-local"
)
func TestBuild_VarArgs(t *testing.T) {
func TestBuild(t *testing.T) {
tc := []struct {
name string
args []string
@ -25,7 +28,7 @@ func TestBuild_VarArgs(t *testing.T) {
fileCheck
}{
{
name: "json - json varfile sets an apple env var",
name: "var-args: json - json varfile sets an apple env var",
args: []string{
"-var-file=" + filepath.Join(testFixture("var-arg"), "apple.json"),
filepath.Join(testFixture("var-arg"), "fruit_builder.json"),
@ -43,7 +46,7 @@ func TestBuild_VarArgs(t *testing.T) {
fileCheck: fileCheck{expected: []string{"banana.txt"}},
},
{
name: "json - arg sets a pear env var",
name: "var-args: json - arg sets a pear env var",
args: []string{
"-var=fruit=pear",
filepath.Join(testFixture("var-arg"), "fruit_builder.json"),
@ -52,7 +55,7 @@ func TestBuild_VarArgs(t *testing.T) {
},
{
name: "json - inexistent var file errs",
name: "var-args: json - inexistent var file errs",
args: []string{
"-var-file=" + filepath.Join(testFixture("var-arg"), "potato.json"),
filepath.Join(testFixture("var-arg"), "fruit_builder.json"),
@ -62,7 +65,7 @@ func TestBuild_VarArgs(t *testing.T) {
},
{
name: "hcl - inexistent json var file errs",
name: "var-args: hcl - inexistent json var file errs",
args: []string{
"-var-file=" + filepath.Join(testFixture("var-arg"), "potato.json"),
testFixture("var-arg"),
@ -72,7 +75,7 @@ func TestBuild_VarArgs(t *testing.T) {
},
{
name: "hcl - inexistent hcl var file errs",
name: "var-args: hcl - inexistent hcl var file errs",
args: []string{
"-var-file=" + filepath.Join(testFixture("var-arg"), "potato.hcl"),
testFixture("var-arg"),
@ -82,7 +85,7 @@ func TestBuild_VarArgs(t *testing.T) {
},
{
name: "hcl - auto varfile sets a chocolate env var",
name: "var-args: hcl - auto varfile sets a chocolate env var",
args: []string{
testFixture("var-arg"),
},
@ -90,7 +93,7 @@ func TestBuild_VarArgs(t *testing.T) {
},
{
name: "hcl - hcl varfile sets a apple env var",
name: "var-args: hcl - hcl varfile sets a apple env var",
args: []string{
"-var-file=" + filepath.Join(testFixture("var-arg"), "apple.hcl"),
testFixture("var-arg"),
@ -99,7 +102,7 @@ func TestBuild_VarArgs(t *testing.T) {
},
{
name: "hcl - json varfile sets a apple env var",
name: "var-args: hcl - json varfile sets a apple env var",
args: []string{
"-var-file=" + filepath.Join(testFixture("var-arg"), "apple.json"),
testFixture("var-arg"),
@ -108,19 +111,108 @@ func TestBuild_VarArgs(t *testing.T) {
},
{
name: "hcl - arg sets a tomato env var",
name: "var-args: hcl - arg sets a tomato env var",
args: []string{
"-var=fruit=tomato",
testFixture("var-arg"),
},
fileCheck: fileCheck{expected: []string{"tomato.txt"}},
},
{
name: "build name: HCL",
args: []string{
"-parallel-builds=1", // to ensure order is kept
testFixture("build-name-and-type"),
},
fileCheck: fileCheck{
expectedContent: map[string]string{
"manifest.json": `{
"builds": [
{
"name": "test",
"builder_type": "null",
"files": null,
"artifact_id": "Null",
"packer_run_uuid": "",
"custom_data": null
},
{
"name": "potato",
"builder_type": "null",
"files": null,
"artifact_id": "Null",
"packer_run_uuid": "",
"custom_data": null
}
],
"last_run_uuid": ""
}`,
},
},
},
{
name: "build name: JSON except potato",
args: []string{
"-except=potato",
"-parallel-builds=1", // to ensure order is kept
filepath.Join(testFixture("build-name-and-type"), "all.json"),
},
fileCheck: fileCheck{
expected: []string{
"null.test.txt",
"null.potato.txt",
},
expectedContent: map[string]string{
"manifest.json": `{
"builds": [
{
"name": "test",
"builder_type": "null",
"files": null,
"artifact_id": "Null",
"packer_run_uuid": "",
"custom_data": null
}
],
"last_run_uuid": ""
}`,
},
},
},
{
name: "build name: JSON only potato",
args: []string{
"-only=potato",
"-parallel-builds=1", // to ensure order is kept
filepath.Join(testFixture("build-name-and-type"), "all.json"),
},
fileCheck: fileCheck{
expectedContent: map[string]string{
"manifest.json": `{
"builds": [
{
"name": "potato",
"builder_type": "null",
"files": null,
"artifact_id": "Null",
"packer_run_uuid": "",
"custom_data": null
}
],
"last_run_uuid": ""
}`,
},
},
},
}
for _, tt := range tc {
t.Run(tt.name, func(t *testing.T) {
defer tt.cleanup(t)
run(t, tt.args, tt.expectedCode)
defer cleanup()
tt.fileCheck.verify(t)
})
}
@ -340,10 +432,28 @@ func run(t *testing.T, args []string, expectedCode int) {
type fileCheck struct {
expected, notExpected []string
expectedContent map[string]string
}
func (fc fileCheck) cleanup(t *testing.T) {
for _, file := range fc.expectedFiles() {
t.Logf("removing %v", file)
if err := os.Remove(file); err != nil {
t.Errorf("failed to remove file %s: %v", file, err)
}
}
}
func (fc fileCheck) expectedFiles() []string {
expected := fc.expected
for file := range fc.expectedContent {
expected = append(expected, file)
}
return expected
}
func (fc fileCheck) verify(t *testing.T) {
for _, f := range fc.expected {
for _, f := range fc.expectedFiles() {
if !fileExists(f) {
t.Errorf("Expected to find %s", f)
}
@ -353,6 +463,15 @@ func (fc fileCheck) verify(t *testing.T) {
t.Errorf("Expected to not find %s", f)
}
}
for file, expectedContent := range fc.expectedContent {
content, err := ioutil.ReadFile(file)
if err != nil {
t.Fatalf("ioutil.ReadFile: %v", err)
}
if diff := cmp.Diff(expectedContent, string(content)); diff != "" {
t.Errorf("content of %s differs: %s", file, diff)
}
}
}
// fileExists returns true if the filename is found
@ -374,9 +493,11 @@ func testCoreConfigBuilder(t *testing.T) *packer.CoreConfig {
ProvisionerStore: packer.MapOfProvisioner{
"shell-local": func() (packer.Provisioner, error) { return &shell_local.Provisioner{}, nil },
"shell": func() (packer.Provisioner, error) { return &shell.Provisioner{}, nil },
"file": func() (packer.Provisioner, error) { return &filep.Provisioner{}, nil },
},
PostProcessorStore: packer.MapOfPostProcessor{
"shell-local": func() (packer.PostProcessor, error) { return &shell_local_pp.PostProcessor{}, nil },
"manifest": func() (packer.PostProcessor, error) { return &manifest.PostProcessor{}, nil },
},
}
return &packer.CoreConfig{

View file

@ -9,6 +9,7 @@ import (
"github.com/chzyer/readline"
"github.com/hashicorp/packer/helper/wrappedreadline"
"github.com/hashicorp/packer/helper/wrappedstreams"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template"
"github.com/hashicorp/packer/template/interpolate"
@ -115,7 +116,7 @@ func (*ConsoleCommand) AutocompleteFlags() complete.Flags {
func (c *ConsoleCommand) modePiped(session *REPLSession) int {
var lastResult string
scanner := bufio.NewScanner(wrappedreadline.Stdin())
scanner := bufio.NewScanner(wrappedstreams.Stdin())
for scanner.Scan() {
result, err := session.Handle(strings.TrimSpace(scanner.Text()))
if err != nil {

Some files were not shown because too many files have changed in this diff Show more