Merge branch 'master' into merge-vsphere-builder

This commit is contained in:
Megan Marsh 2020-01-07 14:23:38 -08:00
commit 8cb1f7b1c1
504 changed files with 9578 additions and 4630 deletions

View File

@ -1,49 +1,115 @@
## 1.5.0 (Upcoming) ## 1.5.2 (Upcoming)
### IMPROVEMENTS:
* builder/amazon: Add source AMI owner ID/name to template engines [GH-8550]
* builder/azure: Set expiry for image versions in SIG [GH-8561]
* core: clean up messy log line in plugin execution. [GH-8542]
### Bug Fixes:
* builder/virtualbox-ovf: Remove config dependency from StepImport [GH-8509]
* builder/virtualbox-vm: use config as a non pointer to avoid a panic [GH-8576]
* core: Fix crash when build.sources is set to an invalid name [GH-8569]
* core: Fix loading of external plugins. GH-8543]
* post-processor/vagrant: correctly handle the diskSize property as a qemu size
string [GH-8567]
* provisioner/ansible: Fix password sanitization to account for empty string
values. [GH-8570]
## 1.5.1 (December 20, 2019)
This was a fast-follow release to fix a number of panics that we introduced when
making changes for HCL2.
### IMPROVEMENTS:
* builder/alicloud: Add show_expired option for describing images [GH-8425]
### Bug Fixes:
* builder/cloudstack: Fix panics associated with loading config [GH-8513]
* builder/hyperv/iso: Fix panics associated with loading config [GH-8513]
* builder/hyperv/vmcx: Fix panics associated with loading config [GH-8513]
* builder/jdcloud: Update jdcloud statebag to use pointers for config [GH-8518]
* builder/linode: Fix panics associated with loading config [GH-8513]
* builder/lxc: Fix panics associated with loading config [GH-8513]
* builder/lxd: Fix panics associated with loading config [GH-8513]
* builder/oneandone: Fix panics associated with loading config [GH-8513]
* builder/oracle/classic: Fix panics associated with loading config [GH-8513]
* builder/oracle/oci: Fix panics associated with loading config [GH-8513]
* builder/osc/bsuvolume: Fix panics associated with loading config [GH-8513]
* builder/parallels/pvm: Fix panics associated with loading config [GH-8513]
* builder/profitbricks: Fix panics associated with loading config [GH-8513]
* builder/scaleway: Fix panics associated with loading config [GH-8513]
* builder/vagrant: Fix panics associated with loading config [GH-8513]
* builder/virtualbox/ovf: Fix panics associated with loading config [GH-8513]
* builder/virtualbox: Configure NAT interface before forwarded port mapping
#8514
* post-processor/vagrant-cloud: Configure NAT interface before forwarded port
mapping [GH-8514]
## 1.5.0 (December 18, 2019)
### IMPROVEMENTS: ### IMPROVEMENTS:
* builder/amazon: Add no_ephemeral template option to remove ephemeral drives * builder/amazon: Add no_ephemeral template option to remove ephemeral drives
from launch mappings. [GH-8393] from launch mappings. [GH-8393]
* builder/amazon: Add validation for `subnet_id` when specifying `vpc_id` * builder/amazon: Add validation for "subnet_id" when specifying "vpc_id"
[GH-8360] [GH-8387] [GH-8391] [GH-8360] [GH-8387] [GH-8391]
* builder/amazon: allow enabling ena/sr-iov on ebssurrogate spot instances * builder/amazon: allow enabling ena/sr-iov on ebssurrogate spot instances
[GH-8397] [GH-8397]
* builder/amazon: Retry runinstances aws api call to mitigate throttling * builder/amazon: Retry runinstances aws api call to mitigate throttling
[GH-8342] [GH-8342]
* builder/hyperone: Update builder schema and tags [GH-8444]
* builder/qemu: Add display template option for qemu. [GH-7676] * builder/qemu: Add display template option for qemu. [GH-7676]
* builder/qemu: Disk Size is now read as a string to support units. [GH-8320]
[GH-7546]
* builder/qemu: Add fixer to convert disk size from int to string [GH-8390]
* builder/qemu: Disk Size is now read as a string to support units. [GH-8320]
[GH-7546]
* builder/qemu: When a user adds a new drive in qemuargs, process it to make * builder/qemu: When a user adds a new drive in qemuargs, process it to make
sure that necessary settings are applied to that drive. [GH-8380] sure that necessary settings are applied to that drive. [GH-8380]
* builder/vmware: Fix error message when ovftool is missing [GH-8371] * builder/vmware: Fix error message when ovftool is missing [GH-8371]
* core: Cleanup logging for external plugins [GH-8471]
* core: HCL2 template support is now in beta. [GH-8423]
* core: Interpolation within provisioners can now access build-specific values
like Host IP, communicator password, and more. [GH-7866]
* core: Various fixes to error handling. [GH-8343] [GH-8333] [GH-8316] * core: Various fixes to error handling. [GH-8343] [GH-8333] [GH-8316]
[GH-8354] [GH-8361] [GH-8363] [GH-8370] [GH-8354] [GH-8361] [GH-8363] [GH-8370]
* post-processor/docker-tag: Add support for multiple tags. [GH-8392]
* post-processor/shell-local: Add "valid_exit_codes" option to shell-local. * post-processor/shell-local: Add "valid_exit_codes" option to shell-local.
[GH-8401] [GH-8401]
* provisioner/chef-client: Add version selection option. [GH-8468]
* provisioner/shell-local: Add "valid_exit_codes" option to shell-local. * provisioner/shell-local: Add "valid_exit_codes" option to shell-local.
[GH-8401] [GH-8401]
* provisioner/shell: Add support for the `env_var_format` parameter [GH-8319] * provisioner/shell: Add support for the "env_var_format" parameter [GH-8319]
### BUG FIXES: ### BUG FIXES:
* builder/amazon: Fix request retry mechanism to launch aws instance [GH-8430]
* builder/azure: Fix PollDuration option which was overriden in some clients.
[GH-8490]
* builder/hyperv: Fix bug in checking VM name that could cause flakiness if * builder/hyperv: Fix bug in checking VM name that could cause flakiness if
many VMs are defined. [GH-8357] many VMs are defined. [GH-8357]
* builder/vagrant: Use absolute path for Vagrantfile [GH-8321] * builder/vagrant: Use absolute path for Vagrantfile [GH-8321]
* builder/virtualbox: Fix panic in snapshot builder. [GH-8336] [GH-8329] * builder/virtualbox: Fix panic in snapshot builder. [GH-8336] [GH-8329]
* communicator/winrm: Resolve ntlm nil pointer bug by bumping go-ntlmssp * communicator/winrm: Resolve ntlm nil pointer bug by bumping go-ntlmssp
dependency [GH-8369] dependency [GH-8369]
* communicator: Fix proxy connection settings to use `SSHProxyUsername` and * communicator: Fix proxy connection settings to use "SSHProxyUsername" and
`SSHProxyPassword` where relevant instead of bastion username and password. "SSHProxyPassword" where relevant instead of bastion username and password.
[GH-8375] [GH-8375]
* core: Fix bug where Packer froze if asked to log an extremely long line * core: Fix bug where Packer froze if asked to log an extremely long line
[GH-8356] [GH-8356]
* core: Fix iso_target_path option; don't cache when target path is non-nil * core: Fix iso_target_path option; don't cache when target path is non-nil
[GH-8394] [GH-8394]
* core: Return exit code 1 when builder type is not found [GH-8474]
* core: Return exit code 1 when builder type is not found [GH-8475]
* core: Update to newest version of go-tty to re-enable CTRL-S and CTRL-Q usage * core: Update to newest version of go-tty to re-enable CTRL-S and CTRL-Q usage
[GH-8364] [GH-8364]
### BACKWARDS INCOMPATIBILITIES: ### BACKWARDS INCOMPATIBILITIES:
* builder/amazon: Complete deprecation of clean_ami_name template func * builder/amazon: Complete deprecation of clean_ami_name template func
[GH-8320] [GH-8193] [GH-8320] [GH-8193]
* builder/qemu: Disk Size is now read as a string to support units. [GH-8320] * core: Changes have been made to both the Prepare() method signature on the
[GH-7546] builder interface and on the Provision() method signature on the
provisioner interface. [GH-7866]
* provisioner/ansible-local: The "galaxycommand" option has been renamed to
"galaxy_command". A fixer has been written for this, which can be invoked
with `packer fix`. [GH-8411]
## 1.4.5 (November 4, 2019) ## 1.4.5 (November 4, 2019)

View File

@ -2,8 +2,8 @@
# builders # builders
/builder/alicloud/ @chhaj5236 /builder/alicloud/ @chhaj5236 @alexyueer
/website/source/docs/builders/alicloud* @chhaj5236 /website/source/docs/builders/alicloud* @chhaj5236 @alexyueer
/builder/azure/ @paulmey /builder/azure/ @paulmey
/website/source/docs/builders/azure* @paulmey /website/source/docs/builders/azure* @paulmey

View File

@ -3,29 +3,42 @@
package ecs package ecs
import ( import (
"encoding/json"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"runtime"
"time" "time"
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
"github.com/hashicorp/packer/template/interpolate" "github.com/hashicorp/packer/template/interpolate"
"github.com/hashicorp/packer/version" "github.com/hashicorp/packer/version"
"github.com/mitchellh/go-homedir"
) )
// Config of alicloud // Config of alicloud
type AlicloudAccessConfig struct { type AlicloudAccessConfig struct {
// This is the Alicloud access key. It must be provided, but it can also be // This is the Alicloud access key. It must be provided when profile not exist, but it can also be
// sourced from the ALICLOUD_ACCESS_KEY environment variable. // sourced from the ALICLOUD_ACCESS_KEY environment variable.
AlicloudAccessKey string `mapstructure:"access_key" required:"true"` AlicloudAccessKey string `mapstructure:"access_key" required:"false"`
// This is the Alicloud secret key. It must be provided, but it can also be // This is the Alicloud secret key. It must be provided when profile not exist, but it can also be
// sourced from the ALICLOUD_SECRET_KEY environment variable. // sourced from the ALICLOUD_SECRET_KEY environment variable.
AlicloudSecretKey string `mapstructure:"secret_key" required:"true"` AlicloudSecretKey string `mapstructure:"secret_key" required:"false"`
// This is the Alicloud region. It must be provided, but it can also be // This is the Alicloud region. It must be provided when profile not exist, but it can also be
// sourced from the ALICLOUD_REGION environment variables. // sourced from the ALICLOUD_REGION environment variables.
AlicloudRegion string `mapstructure:"region" required:"true"` AlicloudRegion string `mapstructure:"region" required:"false"`
// The region validation can be skipped if this value is true, the default // The region validation can be skipped if this value is true, the default
// value is false. // value is false.
AlicloudSkipValidation bool `mapstructure:"skip_region_validation" required:"false"` AlicloudSkipValidation bool `mapstructure:"skip_region_validation" required:"false"`
// The image validation can be skipped if this value is true, the default
// value is false.
AlicloudSkipImageValidation bool `mapstructure:"skip_image_validation" required:"false"`
// This is th Alicloud profile. If access_key not exist, is must be provided, but it can also be
// sourced from the ALICLOUD_PROFILE environment variables.
AlicloudProfile string `mapstructure:"profile" required:"false"`
// This is the Alicloud shared credentials file path. If this file path exist, os will read access key
// and secret key from this file.
AlicloudSharedCredentialsFile string `mapstructure:"shared_credentials_file" required:"false"`
// STS access token, can be set through template or by exporting as // STS access token, can be set through template or by exporting as
// environment variable such as `export SECURITY_TOKEN=value`. // environment variable such as `export SECURITY_TOKEN=value`.
SecurityToken string `mapstructure:"security_token" required:"false"` SecurityToken string `mapstructure:"security_token" required:"false"`
@ -45,8 +58,22 @@ func (c *AlicloudAccessConfig) Client() (*ClientWrapper, error) {
c.SecurityToken = os.Getenv("SECURITY_TOKEN") c.SecurityToken = os.Getenv("SECURITY_TOKEN")
} }
client, err := ecs.NewClientWithStsToken(c.AlicloudRegion, c.AlicloudAccessKey, var getProviderConfig = func(str string, key string) string {
c.AlicloudSecretKey, c.SecurityToken) value, err := getConfigFromProfile(c, key)
if err == nil && value != nil {
str = value.(string)
}
return str
}
if c.AlicloudAccessKey == "" || c.AlicloudSecretKey == "" {
c.AlicloudAccessKey = getProviderConfig(c.AlicloudAccessKey, "access_key_id")
c.AlicloudSecretKey = getProviderConfig(c.AlicloudSecretKey, "access_key_secret")
c.AlicloudRegion = getProviderConfig(c.AlicloudRegion, "region_id")
c.SecurityToken = getProviderConfig(c.SecurityToken, "sts_token")
}
client, err := ecs.NewClientWithStsToken(c.AlicloudRegion, c.AlicloudAccessKey, c.AlicloudSecretKey, c.SecurityToken)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -86,7 +113,13 @@ func (c *AlicloudAccessConfig) Config() error {
if c.AlicloudSecretKey == "" { if c.AlicloudSecretKey == "" {
c.AlicloudSecretKey = os.Getenv("ALICLOUD_SECRET_KEY") c.AlicloudSecretKey = os.Getenv("ALICLOUD_SECRET_KEY")
} }
if c.AlicloudAccessKey == "" || c.AlicloudSecretKey == "" { if c.AlicloudProfile == "" {
c.AlicloudProfile = os.Getenv("ALICLOUD_PROFILE")
}
if c.AlicloudSharedCredentialsFile == "" {
c.AlicloudSharedCredentialsFile = os.Getenv("ALICLOUD_SHARED_CREDENTIALS_FILE")
}
if (c.AlicloudAccessKey == "" || c.AlicloudSecretKey == "") && c.AlicloudProfile == "" {
return fmt.Errorf("ALICLOUD_ACCESS_KEY and ALICLOUD_SECRET_KEY must be set in template file or environment variables.") return fmt.Errorf("ALICLOUD_ACCESS_KEY and ALICLOUD_SECRET_KEY must be set in template file or environment variables.")
} }
return nil return nil
@ -128,3 +161,66 @@ func (c *AlicloudAccessConfig) getSupportedRegions() ([]string, error) {
return validRegions, nil return validRegions, nil
} }
func getConfigFromProfile(c *AlicloudAccessConfig, ProfileKey string) (interface{}, error) {
providerConfig := make(map[string]interface{})
current := c.AlicloudProfile
if current != "" {
profilePath, err := homedir.Expand(c.AlicloudSharedCredentialsFile)
if err != nil {
return nil, err
}
if profilePath == "" {
profilePath = fmt.Sprintf("%s/.aliyun/config.json", os.Getenv("HOME"))
if runtime.GOOS == "windows" {
profilePath = fmt.Sprintf("%s/.aliyun/config.json", os.Getenv("USERPROFILE"))
}
}
_, err = os.Stat(profilePath)
if !os.IsNotExist(err) {
data, err := ioutil.ReadFile(profilePath)
if err != nil {
return nil, err
}
config := map[string]interface{}{}
err = json.Unmarshal(data, &config)
if err != nil {
return nil, err
}
for _, v := range config["profiles"].([]interface{}) {
if current == v.(map[string]interface{})["name"] {
providerConfig = v.(map[string]interface{})
}
}
}
}
mode := ""
if v, ok := providerConfig["mode"]; ok {
mode = v.(string)
} else {
return v, nil
}
switch ProfileKey {
case "access_key_id", "access_key_secret":
if mode == "EcsRamRole" {
return "", nil
}
case "ram_role_name":
if mode != "EcsRamRole" {
return "", nil
}
case "sts_token":
if mode != "StsToken" {
return "", nil
}
case "ram_role_arn", "ram_session_name":
if mode != "RamRoleArn" {
return "", nil
}
case "expired_seconds":
if mode != "RamRoleArn" {
return float64(0), nil
}
}
return providerConfig[ProfileKey], nil
}

View File

@ -32,5 +32,21 @@ func TestAlicloudAccessConfigPrepareRegion(t *testing.T) {
t.Fatalf("shouldn't have err: %s", err) t.Fatalf("shouldn't have err: %s", err)
} }
c.AlicloudAccessKey = ""
if err := c.Prepare(nil); err == nil {
t.Fatalf("should have err")
}
c.AlicloudProfile = "default"
if err := c.Prepare(nil); err != nil {
t.Fatalf("shouldn't have err: %s", err)
}
c.AlicloudProfile = ""
os.Setenv("ALICLOUD_PROFILE", "default")
if err := c.Prepare(nil); err != nil {
t.Fatalf("shouldn't have err: %s", err)
}
c.AlicloudSkipValidation = false c.AlicloudSkipValidation = false
} }

View File

@ -8,6 +8,7 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/communicator" "github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/config" "github.com/hashicorp/packer/helper/config"
@ -41,7 +42,9 @@ const (
ALICLOUD_DEFAULT_LONG_TIMEOUT = 3600 ALICLOUD_DEFAULT_LONG_TIMEOUT = 3600
) )
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() }
func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
err := config.Decode(&b.config, &config.DecodeOpts{ err := config.Decode(&b.config, &config.DecodeOpts{
Interpolate: true, Interpolate: true,
InterpolateContext: &b.config.ctx, InterpolateContext: &b.config.ctx,
@ -53,7 +56,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
}, raws...) }, raws...)
b.config.ctx.EnableEnv = true b.config.ctx.EnableEnv = true
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
if b.config.PackerConfig.PackerForce { if b.config.PackerConfig.PackerForce {
@ -68,11 +71,11 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...) errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...)
if errs != nil && len(errs.Errors) > 0 { if errs != nil && len(errs.Errors) > 0 {
return nil, errs return nil, nil, errs
} }
packer.LogSecretFilter.Set(b.config.AlicloudAccessKey, b.config.AlicloudSecretKey) packer.LogSecretFilter.Set(b.config.AlicloudAccessKey, b.config.AlicloudSecretKey)
return nil, nil return nil, nil, nil
} }
func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) { func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) {

View File

@ -22,10 +22,13 @@ type FlatAlicloudDiskDevice struct {
// FlatMapstructure returns a new FlatAlicloudDiskDevice. // FlatMapstructure returns a new FlatAlicloudDiskDevice.
// FlatAlicloudDiskDevice is an auto-generated flat version of AlicloudDiskDevice. // FlatAlicloudDiskDevice is an auto-generated flat version of AlicloudDiskDevice.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*AlicloudDiskDevice) FlatMapstructure() interface{} { return new(FlatAlicloudDiskDevice) } func (*AlicloudDiskDevice) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatAlicloudDiskDevice)
}
// HCL2Spec returns the hcldec.Spec of a FlatAlicloudDiskDevice. // HCL2Spec returns the hcl spec of a AlicloudDiskDevice.
// This spec is used by HCL to read the fields of FlatAlicloudDiskDevice. // This spec is used by HCL to read the fields of AlicloudDiskDevice.
// The decoded values from this spec will then be applied to a FlatAlicloudDiskDevice.
func (*FlatAlicloudDiskDevice) HCL2Spec() map[string]hcldec.Spec { func (*FlatAlicloudDiskDevice) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"disk_name": &hcldec.AttrSpec{Name: "disk_name", Type: cty.String, Required: false}, "disk_name": &hcldec.AttrSpec{Name: "disk_name", Type: cty.String, Required: false},
@ -50,10 +53,13 @@ type FlatConfig struct {
PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error"` PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error"`
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables"` PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables"`
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables"` PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables"`
AlicloudAccessKey *string `mapstructure:"access_key" required:"true" cty:"access_key"` AlicloudAccessKey *string `mapstructure:"access_key" required:"false" cty:"access_key"`
AlicloudSecretKey *string `mapstructure:"secret_key" required:"true" cty:"secret_key"` AlicloudSecretKey *string `mapstructure:"secret_key" required:"false" cty:"secret_key"`
AlicloudRegion *string `mapstructure:"region" required:"true" cty:"region"` AlicloudRegion *string `mapstructure:"region" required:"false" cty:"region"`
AlicloudSkipValidation *bool `mapstructure:"skip_region_validation" required:"false" cty:"skip_region_validation"` AlicloudSkipValidation *bool `mapstructure:"skip_region_validation" required:"false" cty:"skip_region_validation"`
AlicloudSkipImageValidation *bool `mapstructure:"skip_image_validation" required:"false" cty:"skip_image_validation"`
AlicloudProfile *string `mapstructure:"profile" required:"false" cty:"profile"`
AlicloudSharedCredentialsFile *string `mapstructure:"shared_credentials_file" required:"false" cty:"shared_credentials_file"`
SecurityToken *string `mapstructure:"security_token" required:"false" cty:"security_token"` SecurityToken *string `mapstructure:"security_token" required:"false" cty:"security_token"`
AlicloudImageName *string `mapstructure:"image_name" required:"true" cty:"image_name"` AlicloudImageName *string `mapstructure:"image_name" required:"true" cty:"image_name"`
AlicloudImageVersion *string `mapstructure:"image_version" required:"false" cty:"image_version"` AlicloudImageVersion *string `mapstructure:"image_version" required:"false" cty:"image_version"`
@ -121,8 +127,8 @@ type FlatConfig struct {
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"` SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"`
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"` SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"`
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"` SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"`
SSHPublicKey []byte `cty:"ssh_public_key"` SSHPublicKey []byte `mapstructure:"ssh_public_key" cty:"ssh_public_key"`
SSHPrivateKey []byte `cty:"ssh_private_key"` SSHPrivateKey []byte `mapstructure:"ssh_private_key" cty:"ssh_private_key"`
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"` WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"`
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"` WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"`
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"` WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"`
@ -137,10 +143,13 @@ type FlatConfig struct {
// FlatMapstructure returns a new FlatConfig. // FlatMapstructure returns a new FlatConfig.
// FlatConfig is an auto-generated flat version of Config. // FlatConfig is an auto-generated flat version of Config.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*Config) FlatMapstructure() interface{} { return new(FlatConfig) } func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatConfig)
}
// HCL2Spec returns the hcldec.Spec of a FlatConfig. // HCL2Spec returns the hcl spec of a Config.
// This spec is used by HCL to read the fields of FlatConfig. // This spec is used by HCL to read the fields of Config.
// The decoded values from this spec will then be applied to a FlatConfig.
func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false},
@ -154,6 +163,9 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"secret_key": &hcldec.AttrSpec{Name: "secret_key", Type: cty.String, Required: false}, "secret_key": &hcldec.AttrSpec{Name: "secret_key", Type: cty.String, Required: false},
"region": &hcldec.AttrSpec{Name: "region", Type: cty.String, Required: false}, "region": &hcldec.AttrSpec{Name: "region", Type: cty.String, Required: false},
"skip_region_validation": &hcldec.AttrSpec{Name: "skip_region_validation", Type: cty.Bool, Required: false}, "skip_region_validation": &hcldec.AttrSpec{Name: "skip_region_validation", Type: cty.Bool, Required: false},
"skip_image_validation": &hcldec.AttrSpec{Name: "skip_image_validation", Type: cty.Bool, Required: false},
"profile": &hcldec.AttrSpec{Name: "profile", Type: cty.String, Required: false},
"shared_credentials_file": &hcldec.AttrSpec{Name: "shared_credentials_file", Type: cty.String, Required: false},
"security_token": &hcldec.AttrSpec{Name: "security_token", Type: cty.String, Required: false}, "security_token": &hcldec.AttrSpec{Name: "security_token", Type: cty.String, Required: false},
"image_name": &hcldec.AttrSpec{Name: "image_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}, "image_version": &hcldec.AttrSpec{Name: "image_version", Type: cty.String, Required: false},
@ -169,7 +181,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"image_ignore_data_disks": &hcldec.AttrSpec{Name: "image_ignore_data_disks", 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.BlockAttrsSpec{TypeName: "tags", ElementType: cty.String, Required: false},
"system_disk_mapping": &hcldec.BlockSpec{TypeName: "system_disk_mapping", Nested: hcldec.ObjectSpec((*FlatAlicloudDiskDevice)(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.BlockSpec{TypeName: "image_disk_mappings", Nested: hcldec.ObjectSpec((*FlatAlicloudDiskDevice)(nil).HCL2Spec())}}, "image_disk_mappings": &hcldec.BlockListSpec{TypeName: "image_disk_mappings", Nested: hcldec.ObjectSpec((*FlatAlicloudDiskDevice)(nil).HCL2Spec())},
"associate_public_ip_address": &hcldec.AttrSpec{Name: "associate_public_ip_address", Type: cty.Bool, Required: false}, "associate_public_ip_address": &hcldec.AttrSpec{Name: "associate_public_ip_address", Type: cty.Bool, Required: false},
"zone_id": &hcldec.AttrSpec{Name: "zone_id", Type: cty.String, Required: false}, "zone_id": &hcldec.AttrSpec{Name: "zone_id", Type: cty.String, Required: false},
"io_optimized": &hcldec.AttrSpec{Name: "io_optimized", Type: cty.Bool, Required: false}, "io_optimized": &hcldec.AttrSpec{Name: "io_optimized", Type: cty.Bool, Required: false},

View File

@ -35,7 +35,7 @@ func TestBuilder_Prepare_BadType(t *testing.T) {
"access_key": []string{}, "access_key": []string{},
} }
warnings, err := b.Prepare(c) _, warnings, err := b.Prepare(c)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -50,7 +50,7 @@ func TestBuilderPrepare_ECSImageName(t *testing.T) {
// Test good // Test good
config["image_name"] = "ecs.n1.tiny" config["image_name"] = "ecs.n1.tiny"
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -61,7 +61,7 @@ func TestBuilderPrepare_ECSImageName(t *testing.T) {
// Test bad // Test bad
config["ecs_image_name"] = "foo {{" config["ecs_image_name"] = "foo {{"
b = Builder{} b = Builder{}
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -72,7 +72,7 @@ func TestBuilderPrepare_ECSImageName(t *testing.T) {
// Test bad // Test bad
delete(config, "image_name") delete(config, "image_name")
b = Builder{} b = Builder{}
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -87,7 +87,7 @@ func TestBuilderPrepare_InvalidKey(t *testing.T) {
// Add a random key // Add a random key
config["i_should_not_be_valid"] = true config["i_should_not_be_valid"] = true
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -120,7 +120,7 @@ func TestBuilderPrepare_Devices(t *testing.T) {
"disk_device": "/dev/xvdc", "disk_device": "/dev/xvdc",
}, },
} }
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -160,7 +160,7 @@ func TestBuilderPrepare_IgnoreDataDisks(t *testing.T) {
var b Builder var b Builder
config := testBuilderConfig() config := testBuilderConfig()
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -173,7 +173,7 @@ func TestBuilderPrepare_IgnoreDataDisks(t *testing.T) {
} }
config["image_ignore_data_disks"] = "false" config["image_ignore_data_disks"] = "false"
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -186,7 +186,7 @@ func TestBuilderPrepare_IgnoreDataDisks(t *testing.T) {
} }
config["image_ignore_data_disks"] = "true" config["image_ignore_data_disks"] = "true"
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -203,7 +203,7 @@ func TestBuilderPrepare_WaitSnapshotReadyTimeout(t *testing.T) {
var b Builder var b Builder
config := testBuilderConfig() config := testBuilderConfig()
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -219,7 +219,7 @@ func TestBuilderPrepare_WaitSnapshotReadyTimeout(t *testing.T) {
} }
config["wait_snapshot_ready_timeout"] = ALICLOUD_DEFAULT_TIMEOUT config["wait_snapshot_ready_timeout"] = ALICLOUD_DEFAULT_TIMEOUT
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }

View File

@ -33,14 +33,11 @@ func TestWaitForExpectedExceedRetryTimes(t *testing.T) {
waitDone <- true waitDone <- true
}() }()
timeTolerance := 1 * time.Second
select { select {
case <-waitDone: case <-waitDone:
if iter != defaultRetryTimes { if iter != defaultRetryTimes {
t.Fatalf("WaitForExpected should terminate at the %d iterations", defaultRetryTimes) t.Fatalf("WaitForExpected should terminate at the %d iterations", defaultRetryTimes)
} }
case <-time.After(defaultRetryTimes*defaultRetryInterval + timeTolerance):
t.Fatalf("WaitForExpected should terminate within %f seconds", (defaultRetryTimes*defaultRetryInterval + timeTolerance).Seconds())
} }
} }

View File

@ -21,6 +21,9 @@ func (s *stepCheckAlicloudSourceImage) Run(ctx context.Context, state multistep.
describeImagesRequest := ecs.CreateDescribeImagesRequest() describeImagesRequest := ecs.CreateDescribeImagesRequest()
describeImagesRequest.RegionId = config.AlicloudRegion describeImagesRequest.RegionId = config.AlicloudRegion
describeImagesRequest.ImageId = config.AlicloudSourceImage describeImagesRequest.ImageId = config.AlicloudSourceImage
if config.AlicloudSkipImageValidation {
describeImagesRequest.ShowExpired = "true"
}
imagesResponse, err := client.DescribeImages(describeImagesRequest) imagesResponse, err := client.DescribeImages(describeImagesRequest)
if err != nil { if err != nil {
return halt(state, err, "Error querying alicloud image") return halt(state, err, "Error querying alicloud image")

View File

@ -36,7 +36,7 @@ func (s *stepConfigAlicloudSecurityGroup) Run(ctx context.Context, state multist
if len(s.SecurityGroupId) != 0 { if len(s.SecurityGroupId) != 0 {
describeSecurityGroupsRequest := ecs.CreateDescribeSecurityGroupsRequest() describeSecurityGroupsRequest := ecs.CreateDescribeSecurityGroupsRequest()
describeSecurityGroupsRequest.RegionId = s.RegionId describeSecurityGroupsRequest.RegionId = s.RegionId
describeSecurityGroupsRequest.SecurityGroupId = s.SecurityGroupId
if networkType == InstanceNetworkVpc { if networkType == InstanceNetworkVpc {
vpcId := state.Get("vpcid").(string) vpcId := state.Get("vpcid").(string)
describeSecurityGroupsRequest.VpcId = vpcId describeSecurityGroupsRequest.VpcId = vpcId

View File

@ -77,6 +77,9 @@ func (s *stepCreateAlicloudInstance) Run(ctx context.Context, state multistep.St
ui.Message(fmt.Sprintf("Created instance: %s", instanceId)) ui.Message(fmt.Sprintf("Created instance: %s", instanceId))
s.instance = &instances.Instances.Instance[0] s.instance = &instances.Instances.Instance[0]
state.Put("instance", s.instance) state.Put("instance", s.instance)
// instance_id is the generic term used so that users can have access to the
// instance id inside of the provisioners, used in step_provision.
state.Put("instance_id", instanceId)
return multistep.ActionContinue return multistep.ActionContinue
} }

View File

@ -3,9 +3,9 @@ package ecs
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
"time" "time"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
"github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"

View File

@ -13,6 +13,7 @@ import (
"runtime" "runtime"
"github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/hcl/v2/hcldec"
awscommon "github.com/hashicorp/packer/builder/amazon/common" awscommon "github.com/hashicorp/packer/builder/amazon/common"
"github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/common/chroot" "github.com/hashicorp/packer/common/chroot"
@ -182,7 +183,9 @@ type Builder struct {
runner multistep.Runner runner multistep.Runner
} }
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() }
func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
b.config.ctx.Funcs = awscommon.TemplateFuncs b.config.ctx.Funcs = awscommon.TemplateFuncs
err := config.Decode(&b.config, &config.DecodeOpts{ err := config.Decode(&b.config, &config.DecodeOpts{
Interpolate: true, Interpolate: true,
@ -201,7 +204,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
}, },
}, raws...) }, raws...)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
if b.config.Architecture == "" { if b.config.Architecture == "" {
@ -319,11 +322,11 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
} }
if errs != nil && len(errs.Errors) > 0 { if errs != nil && len(errs.Errors) > 0 {
return warns, errs return nil, warns, errs
} }
packer.LogSecretFilter.Set(b.config.AccessKey, b.config.SecretKey, b.config.Token) packer.LogSecretFilter.Set(b.config.AccessKey, b.config.SecretKey, b.config.Token)
return warns, nil return nil, warns, nil
} }
func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) { func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) {

View File

@ -72,10 +72,13 @@ type FlatConfig struct {
// FlatMapstructure returns a new FlatConfig. // FlatMapstructure returns a new FlatConfig.
// FlatConfig is an auto-generated flat version of Config. // FlatConfig is an auto-generated flat version of Config.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*Config) FlatMapstructure() interface{} { return new(FlatConfig) } func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatConfig)
}
// HCL2Spec returns the hcldec.Spec of a FlatConfig. // HCL2Spec returns the hcl spec of a Config.
// This spec is used by HCL to read the fields of FlatConfig. // This spec is used by HCL to read the fields of Config.
// The decoded values from this spec will then be applied to a FlatConfig.
func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false},
@ -93,7 +96,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_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}, "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}, "skip_region_validation": &hcldec.AttrSpec{Name: "skip_region_validation", Type: cty.Bool, Required: false},
"tags": &hcldec.BlockAttrsSpec{TypeName: "common.TagMap", ElementType: cty.String, Required: false}, "tags": &hcldec.BlockAttrsSpec{TypeName: "tags", ElementType: cty.String, Required: false},
"ena_support": &hcldec.AttrSpec{Name: "ena_support", Type: cty.Bool, Required: false}, "ena_support": &hcldec.AttrSpec{Name: "ena_support", Type: cty.Bool, Required: false},
"sriov_support": &hcldec.AttrSpec{Name: "sriov_support", Type: cty.Bool, Required: false}, "sriov_support": &hcldec.AttrSpec{Name: "sriov_support", Type: cty.Bool, Required: false},
"force_deregister": &hcldec.AttrSpec{Name: "force_deregister", Type: cty.Bool, Required: false}, "force_deregister": &hcldec.AttrSpec{Name: "force_deregister", Type: cty.Bool, Required: false},
@ -102,7 +105,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"kms_key_id": &hcldec.AttrSpec{Name: "kms_key_id", Type: cty.String, 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.BlockAttrsSpec{TypeName: "region_kms_key_ids", ElementType: cty.String, Required: false},
"skip_save_build_region": &hcldec.AttrSpec{Name: "skip_save_build_region", Type: cty.Bool, Required: false}, "skip_save_build_region": &hcldec.AttrSpec{Name: "skip_save_build_region", Type: cty.Bool, Required: false},
"snapshot_tags": &hcldec.BlockAttrsSpec{TypeName: "common.TagMap", ElementType: cty.String, Required: false}, "snapshot_tags": &hcldec.BlockAttrsSpec{TypeName: "snapshot_tags", ElementType: cty.String, Required: false},
"snapshot_users": &hcldec.AttrSpec{Name: "snapshot_users", Type: cty.List(cty.String), Required: false}, "snapshot_users": &hcldec.AttrSpec{Name: "snapshot_users", Type: cty.List(cty.String), Required: false},
"snapshot_groups": &hcldec.AttrSpec{Name: "snapshot_groups", Type: cty.List(cty.String), Required: false}, "snapshot_groups": &hcldec.AttrSpec{Name: "snapshot_groups", Type: cty.List(cty.String), Required: false},
"access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false}, "access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false},
@ -116,7 +119,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"skip_metadata_api_check": &hcldec.AttrSpec{Name: "skip_metadata_api_check", Type: cty.Bool, Required: false}, "skip_metadata_api_check": &hcldec.AttrSpec{Name: "skip_metadata_api_check", Type: cty.Bool, Required: false},
"token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false}, "token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false},
"vault_aws_engine": &hcldec.BlockSpec{TypeName: "vault_aws_engine", Nested: hcldec.ObjectSpec((*common.FlatVaultAWSEngineOptions)(nil).HCL2Spec())}, "vault_aws_engine": &hcldec.BlockSpec{TypeName: "vault_aws_engine", Nested: hcldec.ObjectSpec((*common.FlatVaultAWSEngineOptions)(nil).HCL2Spec())},
"ami_block_device_mappings": &hcldec.BlockListSpec{TypeName: "ami_block_device_mappings", Nested: &hcldec.BlockSpec{TypeName: "ami_block_device_mappings", Nested: hcldec.ObjectSpec((*common.FlatBlockDevice)(nil).HCL2Spec())}}, "ami_block_device_mappings": &hcldec.BlockListSpec{TypeName: "ami_block_device_mappings", Nested: hcldec.ObjectSpec((*common.FlatBlockDevice)(nil).HCL2Spec())},
"chroot_mounts": &hcldec.BlockListSpec{TypeName: "chroot_mounts", Nested: &hcldec.AttrSpec{Name: "chroot_mounts", Type: cty.List(cty.String), Required: false}}, "chroot_mounts": &hcldec.BlockListSpec{TypeName: "chroot_mounts", Nested: &hcldec.AttrSpec{Name: "chroot_mounts", Type: cty.List(cty.String), Required: false}},
"command_wrapper": &hcldec.AttrSpec{Name: "command_wrapper", Type: cty.String, Required: false}, "command_wrapper": &hcldec.AttrSpec{Name: "command_wrapper", Type: cty.String, Required: false},
"copy_files": &hcldec.AttrSpec{Name: "copy_files", Type: cty.List(cty.String), Required: false}, "copy_files": &hcldec.AttrSpec{Name: "copy_files", Type: cty.List(cty.String), Required: false},
@ -133,7 +136,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"root_volume_type": &hcldec.AttrSpec{Name: "root_volume_type", Type: cty.String, Required: false}, "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": &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())}, "source_ami_filter": &hcldec.BlockSpec{TypeName: "source_ami_filter", Nested: hcldec.ObjectSpec((*common.FlatAmiFilterOptions)(nil).HCL2Spec())},
"root_volume_tags": &hcldec.BlockAttrsSpec{TypeName: "common.TagMap", ElementType: cty.String, Required: false}, "root_volume_tags": &hcldec.BlockAttrsSpec{TypeName: "root_volume_tags", ElementType: cty.String, Required: false},
"ami_architecture": &hcldec.AttrSpec{Name: "ami_architecture", Type: cty.String, Required: false}, "ami_architecture": &hcldec.AttrSpec{Name: "ami_architecture", Type: cty.String, Required: false},
} }
return s return s

View File

@ -31,7 +31,7 @@ func TestBuilderPrepare_AMIName(t *testing.T) {
// Test good // Test good
config["ami_name"] = "foo" config["ami_name"] = "foo"
config["skip_region_validation"] = true config["skip_region_validation"] = true
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -42,7 +42,7 @@ func TestBuilderPrepare_AMIName(t *testing.T) {
// Test bad // Test bad
config["ami_name"] = "foo {{" config["ami_name"] = "foo {{"
b = Builder{} b = Builder{}
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -53,7 +53,7 @@ func TestBuilderPrepare_AMIName(t *testing.T) {
// Test bad // Test bad
delete(config, "ami_name") delete(config, "ami_name")
b = Builder{} b = Builder{}
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -67,7 +67,7 @@ func TestBuilderPrepare_ChrootMounts(t *testing.T) {
config := testConfig() config := testConfig()
config["chroot_mounts"] = nil config["chroot_mounts"] = nil
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -83,7 +83,7 @@ func TestBuilderPrepare_ChrootMountsBadDefaults(t *testing.T) {
config["chroot_mounts"] = [][]string{ config["chroot_mounts"] = [][]string{
{"bad"}, {"bad"},
} }
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -96,7 +96,7 @@ func TestBuilderPrepare_SourceAmi(t *testing.T) {
config := testConfig() config := testConfig()
config["source_ami"] = "" config["source_ami"] = ""
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -105,7 +105,7 @@ func TestBuilderPrepare_SourceAmi(t *testing.T) {
} }
config["source_ami"] = "foo" config["source_ami"] = "foo"
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -119,7 +119,7 @@ func TestBuilderPrepare_CommandWrapper(t *testing.T) {
config := testConfig() config := testConfig()
config["command_wrapper"] = "echo hi; {{.Command}}" config["command_wrapper"] = "echo hi; {{.Command}}"
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -132,7 +132,7 @@ func TestBuilderPrepare_CopyFiles(t *testing.T) {
b := &Builder{} b := &Builder{}
config := testConfig() config := testConfig()
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -150,7 +150,7 @@ func TestBuilderPrepare_CopyFilesNoDefault(t *testing.T) {
config := testConfig() config := testConfig()
config["copy_files"] = []string{} config["copy_files"] = []string{}
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -171,7 +171,7 @@ func TestBuilderPrepare_RootDeviceNameAndAMIMappings(t *testing.T) {
config["root_device_name"] = "/dev/sda" config["root_device_name"] = "/dev/sda"
config["ami_block_device_mappings"] = []interface{}{map[string]string{}} config["ami_block_device_mappings"] = []interface{}{map[string]string{}}
config["root_volume_size"] = 15 config["root_volume_size"] = 15
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) == 0 { if len(warnings) == 0 {
t.Fatal("Missing warning, stating block device mappings will be overwritten") t.Fatal("Missing warning, stating block device mappings will be overwritten")
} else if len(warnings) > 1 { } else if len(warnings) > 1 {
@ -187,7 +187,7 @@ func TestBuilderPrepare_AMIMappingsNoRootDeviceName(t *testing.T) {
config := testConfig() config := testConfig()
config["ami_block_device_mappings"] = []interface{}{map[string]string{}} config["ami_block_device_mappings"] = []interface{}{map[string]string{}}
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -201,7 +201,7 @@ func TestBuilderPrepare_RootDeviceNameNoAMIMappings(t *testing.T) {
config := testConfig() config := testConfig()
config["root_device_name"] = "/dev/sda" config["root_device_name"] = "/dev/sda"
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }

View File

@ -18,10 +18,13 @@ type FlatVaultAWSEngineOptions struct {
// FlatMapstructure returns a new FlatVaultAWSEngineOptions. // FlatMapstructure returns a new FlatVaultAWSEngineOptions.
// FlatVaultAWSEngineOptions is an auto-generated flat version of VaultAWSEngineOptions. // FlatVaultAWSEngineOptions is an auto-generated flat version of VaultAWSEngineOptions.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*VaultAWSEngineOptions) FlatMapstructure() interface{} { return new(FlatVaultAWSEngineOptions) } func (*VaultAWSEngineOptions) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatVaultAWSEngineOptions)
}
// HCL2Spec returns the hcldec.Spec of a FlatVaultAWSEngineOptions. // HCL2Spec returns the hcl spec of a VaultAWSEngineOptions.
// This spec is used by HCL to read the fields of FlatVaultAWSEngineOptions. // This spec is used by HCL to read the fields of VaultAWSEngineOptions.
// The decoded values from this spec will then be applied to a FlatVaultAWSEngineOptions.
func (*FlatVaultAWSEngineOptions) HCL2Spec() map[string]hcldec.Spec { func (*FlatVaultAWSEngineOptions) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"name": &hcldec.AttrSpec{Name: "name", Type: cty.String, Required: false}, "name": &hcldec.AttrSpec{Name: "name", Type: cty.String, Required: false},

View File

@ -24,10 +24,13 @@ type FlatBlockDevice struct {
// FlatMapstructure returns a new FlatBlockDevice. // FlatMapstructure returns a new FlatBlockDevice.
// FlatBlockDevice is an auto-generated flat version of BlockDevice. // FlatBlockDevice is an auto-generated flat version of BlockDevice.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*BlockDevice) FlatMapstructure() interface{} { return new(FlatBlockDevice) } func (*BlockDevice) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatBlockDevice)
}
// HCL2Spec returns the hcldec.Spec of a FlatBlockDevice. // HCL2Spec returns the hcl spec of a BlockDevice.
// This spec is used by HCL to read the fields of FlatBlockDevice. // This spec is used by HCL to read the fields of BlockDevice.
// The decoded values from this spec will then be applied to a FlatBlockDevice.
func (*FlatBlockDevice) HCL2Spec() map[string]hcldec.Spec { func (*FlatBlockDevice) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"delete_on_termination": &hcldec.AttrSpec{Name: "delete_on_termination", Type: cty.Bool, Required: false}, "delete_on_termination": &hcldec.AttrSpec{Name: "delete_on_termination", Type: cty.Bool, Required: false},

View File

@ -7,10 +7,12 @@ import (
) )
type BuildInfoTemplate struct { type BuildInfoTemplate struct {
BuildRegion string BuildRegion string
SourceAMI string SourceAMI string
SourceAMIName string SourceAMIName string
SourceAMITags map[string]string SourceAMIOwner string
SourceAMIOwnerName string
SourceAMITags map[string]string
} }
func extractBuildInfo(region string, state multistep.StateBag) *BuildInfoTemplate { func extractBuildInfo(region string, state multistep.StateBag) *BuildInfoTemplate {
@ -28,9 +30,11 @@ func extractBuildInfo(region string, state multistep.StateBag) *BuildInfoTemplat
} }
return &BuildInfoTemplate{ return &BuildInfoTemplate{
BuildRegion: region, BuildRegion: region,
SourceAMI: aws.StringValue(sourceAMI.ImageId), SourceAMI: aws.StringValue(sourceAMI.ImageId),
SourceAMIName: aws.StringValue(sourceAMI.Name), SourceAMIName: aws.StringValue(sourceAMI.Name),
SourceAMITags: sourceAMITags, SourceAMIOwner: aws.StringValue(sourceAMI.OwnerId),
SourceAMIOwnerName: aws.StringValue(sourceAMI.ImageOwnerAlias),
SourceAMITags: sourceAMITags,
} }
} }

View File

@ -11,8 +11,10 @@ import (
func testImage() *ec2.Image { func testImage() *ec2.Image {
return &ec2.Image{ return &ec2.Image{
ImageId: aws.String("ami-abcd1234"), ImageId: aws.String("ami-abcd1234"),
Name: aws.String("ami_test_name"), Name: aws.String("ami_test_name"),
OwnerId: aws.String("ami_test_owner_id"),
ImageOwnerAlias: aws.String("ami_test_owner_alias"),
Tags: []*ec2.Tag{ Tags: []*ec2.Tag{
{ {
Key: aws.String("key-1"), Key: aws.String("key-1"),
@ -49,9 +51,11 @@ func TestInterpolateBuildInfo_extractBuildInfo_withSourceImage(t *testing.T) {
buildInfo := extractBuildInfo("foo", state) buildInfo := extractBuildInfo("foo", state)
expected := BuildInfoTemplate{ expected := BuildInfoTemplate{
BuildRegion: "foo", BuildRegion: "foo",
SourceAMI: "ami-abcd1234", SourceAMI: "ami-abcd1234",
SourceAMIName: "ami_test_name", SourceAMIName: "ami_test_name",
SourceAMIOwner: "ami_test_owner_id",
SourceAMIOwnerName: "ami_test_owner_alias",
SourceAMITags: map[string]string{ SourceAMITags: map[string]string{
"key-1": "value-1", "key-1": "value-1",
"key-2": "value-2", "key-2": "value-2",

View File

@ -145,6 +145,8 @@ type RunConfig struct {
// profile](https://docs.aws.amazon.com/IAM/latest/UserGuide/instance-profiles.html) // profile](https://docs.aws.amazon.com/IAM/latest/UserGuide/instance-profiles.html)
// to launch the EC2 instance with. // to launch the EC2 instance with.
IamInstanceProfile string `mapstructure:"iam_instance_profile" required:"false"` IamInstanceProfile string `mapstructure:"iam_instance_profile" required:"false"`
// Whether or not to check if the IAM instance profile exists. Defaults to false
SkipProfileValidation bool `mapstructure:"skip_profile_validation" required:"false"`
// Temporary IAM instance profile policy document // Temporary IAM instance profile policy document
// If IamInstanceProfile is specified it will be used instead. Example: // If IamInstanceProfile is specified it will be used instead. Example:
// //
@ -375,8 +377,20 @@ type RunConfig struct {
WindowsPasswordTimeout time.Duration `mapstructure:"windows_password_timeout" required:"false"` WindowsPasswordTimeout time.Duration `mapstructure:"windows_password_timeout" required:"false"`
// Communicator settings // Communicator settings
Comm communicator.Config `mapstructure:",squash"` Comm communicator.Config `mapstructure:",squash"`
SSHInterface string `mapstructure:"ssh_interface"`
// One of `public_ip`, `private_ip`, `public_dns`, or `private_dns`. If
// set, either the public IP address, private IP address, public DNS name
// or private DNS name will be used as the host for SSH. The default behaviour
// if inside a VPC is to use the public IP address if available, otherwise
// the private IP address will be used. If not in a VPC the public DNS name
// will be used. Also works for WinRM.
//
// Where Packer is configured for an outbound proxy but WinRM traffic
// should be direct, `ssh_interface` must be set to `private_dns` and
// `<region>.compute.internal` included in the `NO_PROXY` environment
// variable.
SSHInterface string `mapstructure:"ssh_interface"`
} }
func (c *RunConfig) Prepare(ctx *interpolate.Context) []error { func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {

View File

@ -17,10 +17,13 @@ type FlatAmiFilterOptions struct {
// FlatMapstructure returns a new FlatAmiFilterOptions. // FlatMapstructure returns a new FlatAmiFilterOptions.
// FlatAmiFilterOptions is an auto-generated flat version of AmiFilterOptions. // FlatAmiFilterOptions is an auto-generated flat version of AmiFilterOptions.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*AmiFilterOptions) FlatMapstructure() interface{} { return new(FlatAmiFilterOptions) } func (*AmiFilterOptions) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatAmiFilterOptions)
}
// HCL2Spec returns the hcldec.Spec of a FlatAmiFilterOptions. // HCL2Spec returns the hcl spec of a AmiFilterOptions.
// This spec is used by HCL to read the fields of FlatAmiFilterOptions. // This spec is used by HCL to read the fields of AmiFilterOptions.
// The decoded values from this spec will then be applied to a FlatAmiFilterOptions.
func (*FlatAmiFilterOptions) HCL2Spec() map[string]hcldec.Spec { func (*FlatAmiFilterOptions) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"filters": &hcldec.BlockAttrsSpec{TypeName: "filters", ElementType: cty.String, Required: false}, "filters": &hcldec.BlockAttrsSpec{TypeName: "filters", ElementType: cty.String, Required: false},
@ -40,14 +43,17 @@ type FlatPolicyDocument struct {
// FlatMapstructure returns a new FlatPolicyDocument. // FlatMapstructure returns a new FlatPolicyDocument.
// FlatPolicyDocument is an auto-generated flat version of PolicyDocument. // FlatPolicyDocument is an auto-generated flat version of PolicyDocument.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*PolicyDocument) FlatMapstructure() interface{} { return new(FlatPolicyDocument) } func (*PolicyDocument) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatPolicyDocument)
}
// HCL2Spec returns the hcldec.Spec of a FlatPolicyDocument. // HCL2Spec returns the hcl spec of a PolicyDocument.
// This spec is used by HCL to read the fields of FlatPolicyDocument. // This spec is used by HCL to read the fields of PolicyDocument.
// The decoded values from this spec will then be applied to a FlatPolicyDocument.
func (*FlatPolicyDocument) HCL2Spec() map[string]hcldec.Spec { func (*FlatPolicyDocument) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"version": &hcldec.AttrSpec{Name: "version", Type: cty.String, Required: false}, "version": &hcldec.AttrSpec{Name: "version", Type: cty.String, Required: false},
"statement": &hcldec.BlockListSpec{TypeName: "statement", Nested: &hcldec.BlockSpec{TypeName: "statement", Nested: hcldec.ObjectSpec((*FlatStatement)(nil).HCL2Spec())}}, "statement": &hcldec.BlockListSpec{TypeName: "statement", Nested: hcldec.ObjectSpec((*FlatStatement)(nil).HCL2Spec())},
} }
return s return s
} }
@ -61,12 +67,13 @@ type FlatSecurityGroupFilterOptions struct {
// FlatMapstructure returns a new FlatSecurityGroupFilterOptions. // FlatMapstructure returns a new FlatSecurityGroupFilterOptions.
// FlatSecurityGroupFilterOptions is an auto-generated flat version of SecurityGroupFilterOptions. // FlatSecurityGroupFilterOptions is an auto-generated flat version of SecurityGroupFilterOptions.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*SecurityGroupFilterOptions) FlatMapstructure() interface{} { func (*SecurityGroupFilterOptions) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatSecurityGroupFilterOptions) return new(FlatSecurityGroupFilterOptions)
} }
// HCL2Spec returns the hcldec.Spec of a FlatSecurityGroupFilterOptions. // HCL2Spec returns the hcl spec of a SecurityGroupFilterOptions.
// This spec is used by HCL to read the fields of FlatSecurityGroupFilterOptions. // This spec is used by HCL to read the fields of SecurityGroupFilterOptions.
// The decoded values from this spec will then be applied to a FlatSecurityGroupFilterOptions.
func (*FlatSecurityGroupFilterOptions) HCL2Spec() map[string]hcldec.Spec { func (*FlatSecurityGroupFilterOptions) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"filters": &hcldec.BlockAttrsSpec{TypeName: "filters", ElementType: cty.String, Required: false}, "filters": &hcldec.BlockAttrsSpec{TypeName: "filters", ElementType: cty.String, Required: false},
@ -85,10 +92,13 @@ type FlatStatement struct {
// FlatMapstructure returns a new FlatStatement. // FlatMapstructure returns a new FlatStatement.
// FlatStatement is an auto-generated flat version of Statement. // FlatStatement is an auto-generated flat version of Statement.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*Statement) FlatMapstructure() interface{} { return new(FlatStatement) } func (*Statement) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatStatement)
}
// HCL2Spec returns the hcldec.Spec of a FlatStatement. // HCL2Spec returns the hcl spec of a Statement.
// This spec is used by HCL to read the fields of FlatStatement. // This spec is used by HCL to read the fields of Statement.
// The decoded values from this spec will then be applied to a FlatStatement.
func (*FlatStatement) HCL2Spec() map[string]hcldec.Spec { func (*FlatStatement) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"effect": &hcldec.AttrSpec{Name: "effect", Type: cty.String, Required: false}, "effect": &hcldec.AttrSpec{Name: "effect", Type: cty.String, Required: false},
@ -109,10 +119,13 @@ type FlatSubnetFilterOptions struct {
// FlatMapstructure returns a new FlatSubnetFilterOptions. // FlatMapstructure returns a new FlatSubnetFilterOptions.
// FlatSubnetFilterOptions is an auto-generated flat version of SubnetFilterOptions. // FlatSubnetFilterOptions is an auto-generated flat version of SubnetFilterOptions.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*SubnetFilterOptions) FlatMapstructure() interface{} { return new(FlatSubnetFilterOptions) } func (*SubnetFilterOptions) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatSubnetFilterOptions)
}
// HCL2Spec returns the hcldec.Spec of a FlatSubnetFilterOptions. // HCL2Spec returns the hcl spec of a SubnetFilterOptions.
// This spec is used by HCL to read the fields of FlatSubnetFilterOptions. // This spec is used by HCL to read the fields of SubnetFilterOptions.
// The decoded values from this spec will then be applied to a FlatSubnetFilterOptions.
func (*FlatSubnetFilterOptions) HCL2Spec() map[string]hcldec.Spec { func (*FlatSubnetFilterOptions) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"filters": &hcldec.BlockAttrsSpec{TypeName: "filters", ElementType: cty.String, Required: false}, "filters": &hcldec.BlockAttrsSpec{TypeName: "filters", ElementType: cty.String, Required: false},
@ -131,10 +144,13 @@ type FlatVpcFilterOptions struct {
// FlatMapstructure returns a new FlatVpcFilterOptions. // FlatMapstructure returns a new FlatVpcFilterOptions.
// FlatVpcFilterOptions is an auto-generated flat version of VpcFilterOptions. // FlatVpcFilterOptions is an auto-generated flat version of VpcFilterOptions.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*VpcFilterOptions) FlatMapstructure() interface{} { return new(FlatVpcFilterOptions) } func (*VpcFilterOptions) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatVpcFilterOptions)
}
// HCL2Spec returns the hcldec.Spec of a FlatVpcFilterOptions. // HCL2Spec returns the hcl spec of a VpcFilterOptions.
// This spec is used by HCL to read the fields of FlatVpcFilterOptions. // This spec is used by HCL to read the fields of VpcFilterOptions.
// The decoded values from this spec will then be applied to a FlatVpcFilterOptions.
func (*FlatVpcFilterOptions) HCL2Spec() map[string]hcldec.Spec { func (*FlatVpcFilterOptions) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"filters": &hcldec.BlockAttrsSpec{TypeName: "filters", ElementType: cty.String, Required: false}, "filters": &hcldec.BlockAttrsSpec{TypeName: "filters", ElementType: cty.String, Required: false},

View File

@ -13,7 +13,6 @@ import (
"github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/packer/common/retry" "github.com/hashicorp/packer/common/retry"
commonhelper "github.com/hashicorp/packer/helper/common"
"github.com/hashicorp/packer/helper/communicator" "github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"
@ -91,16 +90,13 @@ WaitLoop:
"Password (since debug is enabled): %s", s.Comm.WinRMPassword)) "Password (since debug is enabled): %s", s.Comm.WinRMPassword))
} }
// store so that we can access this later during provisioning // store so that we can access this later during provisioning
state.Put("winrm_password", s.Comm.WinRMPassword)
commonhelper.SetSharedState("winrm_password", s.Comm.WinRMPassword, s.BuildName)
packer.LogSecretFilter.Set(s.Comm.WinRMPassword) packer.LogSecretFilter.Set(s.Comm.WinRMPassword)
return multistep.ActionContinue return multistep.ActionContinue
} }
func (s *StepGetPassword) Cleanup(multistep.StateBag) { func (s *StepGetPassword) Cleanup(multistep.StateBag) {}
commonhelper.RemoveSharedStateFile("winrm_password", s.BuildName)
}
func (s *StepGetPassword) waitForPassword(ctx context.Context, state multistep.StateBag) (string, error) { func (s *StepGetPassword) waitForPassword(ctx context.Context, state multistep.StateBag) (string, error) {
ec2conn := state.Get("ec2").(*ec2.EC2) ec2conn := state.Get("ec2").(*ec2.EC2)

View File

@ -2,11 +2,10 @@ package common
import ( import (
"context" "context"
"encoding/json"
"fmt" "fmt"
"log" "log"
"encoding/json"
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/iam" "github.com/aws/aws-sdk-go/service/iam"
"github.com/hashicorp/packer/common/uuid" "github.com/hashicorp/packer/common/uuid"
@ -16,6 +15,7 @@ import (
type StepIamInstanceProfile struct { type StepIamInstanceProfile struct {
IamInstanceProfile string IamInstanceProfile string
SkipProfileValidation bool
TemporaryIamInstanceProfilePolicyDocument *PolicyDocument TemporaryIamInstanceProfilePolicyDocument *PolicyDocument
createdInstanceProfileName string createdInstanceProfileName string
createdRoleName string createdRoleName string
@ -30,16 +30,18 @@ func (s *StepIamInstanceProfile) Run(ctx context.Context, state multistep.StateB
state.Put("iamInstanceProfile", "") state.Put("iamInstanceProfile", "")
if len(s.IamInstanceProfile) > 0 { if len(s.IamInstanceProfile) > 0 {
_, err := iamsvc.GetInstanceProfile( if !s.SkipProfileValidation {
&iam.GetInstanceProfileInput{ _, err := iamsvc.GetInstanceProfile(
InstanceProfileName: aws.String(s.IamInstanceProfile), &iam.GetInstanceProfileInput{
}, InstanceProfileName: aws.String(s.IamInstanceProfile),
) },
if err != nil { )
err := fmt.Errorf("Couldn't find specified instance profile: %s", err) if err != nil {
log.Printf("[DEBUG] %s", err.Error()) err := fmt.Errorf("Couldn't find specified instance profile: %s", err)
state.Put("error", err) log.Printf("[DEBUG] %s", err.Error())
return multistep.ActionHalt state.Put("error", err)
return multistep.ActionHalt
}
} }
log.Printf("Using specified instance profile: %v", s.IamInstanceProfile) log.Printf("Using specified instance profile: %v", s.IamInstanceProfile)
state.Put("iamInstanceProfile", s.IamInstanceProfile) state.Put("iamInstanceProfile", s.IamInstanceProfile)

View File

@ -280,6 +280,9 @@ func (s *StepRunSourceInstance) Run(ctx context.Context, state multistep.StateBa
} }
state.Put("instance", instance) state.Put("instance", instance)
// instance_id is the generic term used so that users can have access to the
// instance id inside of the provisioners, used in step_provision.
state.Put("instance_id", instance.InstanceId)
// If we're in a region that doesn't support tagging on instance creation, // If we're in a region that doesn't support tagging on instance creation,
// do that now. // do that now.

View File

@ -441,6 +441,9 @@ func (s *StepRunSpotInstance) Run(ctx context.Context, state multistep.StateBag)
} }
state.Put("instance", instance) state.Put("instance", instance)
// instance_id is the generic term used so that users can have access to the
// instance id inside of the provisioners, used in step_provision.
state.Put("instance_id", instance.InstanceId)
return multistep.ActionContinue return multistep.ActionContinue
} }

View File

@ -14,6 +14,7 @@ import (
"github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/iam" "github.com/aws/aws-sdk-go/service/iam"
"github.com/hashicorp/hcl/v2/hcldec"
awscommon "github.com/hashicorp/packer/builder/amazon/common" awscommon "github.com/hashicorp/packer/builder/amazon/common"
"github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/communicator" "github.com/hashicorp/packer/helper/communicator"
@ -72,7 +73,9 @@ type Builder struct {
runner multistep.Runner runner multistep.Runner
} }
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() }
func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
b.config.ctx.Funcs = awscommon.TemplateFuncs b.config.ctx.Funcs = awscommon.TemplateFuncs
err := config.Decode(&b.config, &config.DecodeOpts{ err := config.Decode(&b.config, &config.DecodeOpts{
Interpolate: true, Interpolate: true,
@ -89,7 +92,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
}, },
}, raws...) }, raws...)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
if b.config.PackerConfig.PackerForce { if b.config.PackerConfig.PackerForce {
@ -123,11 +126,11 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
} }
if errs != nil && len(errs.Errors) > 0 { if errs != nil && len(errs.Errors) > 0 {
return warns, errs return nil, warns, errs
} }
packer.LogSecretFilter.Set(b.config.AccessKey, b.config.SecretKey, b.config.Token) packer.LogSecretFilter.Set(b.config.AccessKey, b.config.SecretKey, b.config.Token)
return warns, nil return nil, warns, nil
} }
func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) { func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) {
@ -234,6 +237,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
}, },
&awscommon.StepIamInstanceProfile{ &awscommon.StepIamInstanceProfile{
IamInstanceProfile: b.config.IamInstanceProfile, IamInstanceProfile: b.config.IamInstanceProfile,
SkipProfileValidation: b.config.SkipProfileValidation,
TemporaryIamInstanceProfilePolicyDocument: b.config.TemporaryIamInstanceProfilePolicyDocument, TemporaryIamInstanceProfilePolicyDocument: b.config.TemporaryIamInstanceProfilePolicyDocument,
}, },
&awscommon.StepCleanupVolumes{ &awscommon.StepCleanupVolumes{

View File

@ -55,6 +55,7 @@ type FlatConfig struct {
EbsOptimized *bool `mapstructure:"ebs_optimized" required:"false" cty:"ebs_optimized"` EbsOptimized *bool `mapstructure:"ebs_optimized" required:"false" cty:"ebs_optimized"`
EnableT2Unlimited *bool `mapstructure:"enable_t2_unlimited" required:"false" cty:"enable_t2_unlimited"` EnableT2Unlimited *bool `mapstructure:"enable_t2_unlimited" required:"false" cty:"enable_t2_unlimited"`
IamInstanceProfile *string `mapstructure:"iam_instance_profile" required:"false" cty:"iam_instance_profile"` IamInstanceProfile *string `mapstructure:"iam_instance_profile" required:"false" cty:"iam_instance_profile"`
SkipProfileValidation *bool `mapstructure:"skip_profile_validation" required:"false" cty:"skip_profile_validation"`
TemporaryIamInstanceProfilePolicyDocument *common.FlatPolicyDocument `mapstructure:"temporary_iam_instance_profile_policy_document" required:"false" cty:"temporary_iam_instance_profile_policy_document"` TemporaryIamInstanceProfilePolicyDocument *common.FlatPolicyDocument `mapstructure:"temporary_iam_instance_profile_policy_document" required:"false" cty:"temporary_iam_instance_profile_policy_document"`
InstanceInitiatedShutdownBehavior *string `mapstructure:"shutdown_behavior" required:"false" cty:"shutdown_behavior"` InstanceInitiatedShutdownBehavior *string `mapstructure:"shutdown_behavior" required:"false" cty:"shutdown_behavior"`
InstanceType *string `mapstructure:"instance_type" required:"true" cty:"instance_type"` InstanceType *string `mapstructure:"instance_type" required:"true" cty:"instance_type"`
@ -106,8 +107,8 @@ type FlatConfig struct {
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"` SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"`
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"` SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"`
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"` SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"`
SSHPublicKey []byte `cty:"ssh_public_key"` SSHPublicKey []byte `mapstructure:"ssh_public_key" cty:"ssh_public_key"`
SSHPrivateKey []byte `cty:"ssh_private_key"` SSHPrivateKey []byte `mapstructure:"ssh_private_key" cty:"ssh_private_key"`
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"` WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"`
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"` WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"`
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"` WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"`
@ -126,10 +127,13 @@ type FlatConfig struct {
// FlatMapstructure returns a new FlatConfig. // FlatMapstructure returns a new FlatConfig.
// FlatConfig is an auto-generated flat version of Config. // FlatConfig is an auto-generated flat version of Config.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*Config) FlatMapstructure() interface{} { return new(FlatConfig) } func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatConfig)
}
// HCL2Spec returns the hcldec.Spec of a FlatConfig. // HCL2Spec returns the hcl spec of a Config.
// This spec is used by HCL to read the fields of FlatConfig. // This spec is used by HCL to read the fields of Config.
// The decoded values from this spec will then be applied to a FlatConfig.
func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false},
@ -158,7 +162,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"ami_groups": &hcldec.AttrSpec{Name: "ami_groups", Type: cty.List(cty.String), Required: false}, "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_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}, "ami_regions": &hcldec.AttrSpec{Name: "ami_regions", Type: cty.List(cty.String), Required: false},
"tags": &hcldec.BlockAttrsSpec{TypeName: "common.TagMap", ElementType: cty.String, Required: false}, "tags": &hcldec.BlockAttrsSpec{TypeName: "tags", ElementType: cty.String, Required: false},
"ena_support": &hcldec.AttrSpec{Name: "ena_support", Type: cty.Bool, Required: false}, "ena_support": &hcldec.AttrSpec{Name: "ena_support", Type: cty.Bool, Required: false},
"sriov_support": &hcldec.AttrSpec{Name: "sriov_support", Type: cty.Bool, Required: false}, "sriov_support": &hcldec.AttrSpec{Name: "sriov_support", Type: cty.Bool, Required: false},
"force_deregister": &hcldec.AttrSpec{Name: "force_deregister", Type: cty.Bool, Required: false}, "force_deregister": &hcldec.AttrSpec{Name: "force_deregister", Type: cty.Bool, Required: false},
@ -167,7 +171,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"kms_key_id": &hcldec.AttrSpec{Name: "kms_key_id", Type: cty.String, 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.BlockAttrsSpec{TypeName: "region_kms_key_ids", ElementType: cty.String, Required: false},
"skip_save_build_region": &hcldec.AttrSpec{Name: "skip_save_build_region", Type: cty.Bool, Required: false}, "skip_save_build_region": &hcldec.AttrSpec{Name: "skip_save_build_region", Type: cty.Bool, Required: false},
"snapshot_tags": &hcldec.BlockAttrsSpec{TypeName: "common.TagMap", ElementType: cty.String, Required: false}, "snapshot_tags": &hcldec.BlockAttrsSpec{TypeName: "snapshot_tags", ElementType: cty.String, Required: false},
"snapshot_users": &hcldec.AttrSpec{Name: "snapshot_users", Type: cty.List(cty.String), Required: false}, "snapshot_users": &hcldec.AttrSpec{Name: "snapshot_users", Type: cty.List(cty.String), Required: false},
"snapshot_groups": &hcldec.AttrSpec{Name: "snapshot_groups", Type: cty.List(cty.String), Required: false}, "snapshot_groups": &hcldec.AttrSpec{Name: "snapshot_groups", Type: cty.List(cty.String), Required: false},
"associate_public_ip_address": &hcldec.AttrSpec{Name: "associate_public_ip_address", Type: cty.Bool, Required: false}, "associate_public_ip_address": &hcldec.AttrSpec{Name: "associate_public_ip_address", Type: cty.Bool, Required: false},
@ -177,6 +181,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"ebs_optimized": &hcldec.AttrSpec{Name: "ebs_optimized", Type: cty.Bool, Required: false}, "ebs_optimized": &hcldec.AttrSpec{Name: "ebs_optimized", Type: cty.Bool, Required: false},
"enable_t2_unlimited": &hcldec.AttrSpec{Name: "enable_t2_unlimited", Type: cty.Bool, Required: false}, "enable_t2_unlimited": &hcldec.AttrSpec{Name: "enable_t2_unlimited", Type: cty.Bool, Required: false},
"iam_instance_profile": &hcldec.AttrSpec{Name: "iam_instance_profile", Type: cty.String, Required: false}, "iam_instance_profile": &hcldec.AttrSpec{Name: "iam_instance_profile", Type: cty.String, Required: false},
"skip_profile_validation": &hcldec.AttrSpec{Name: "skip_profile_validation", Type: cty.Bool, Required: false},
"temporary_iam_instance_profile_policy_document": &hcldec.BlockSpec{TypeName: "temporary_iam_instance_profile_policy_document", Nested: hcldec.ObjectSpec((*common.FlatPolicyDocument)(nil).HCL2Spec())}, "temporary_iam_instance_profile_policy_document": &hcldec.BlockSpec{TypeName: "temporary_iam_instance_profile_policy_document", Nested: hcldec.ObjectSpec((*common.FlatPolicyDocument)(nil).HCL2Spec())},
"shutdown_behavior": &hcldec.AttrSpec{Name: "shutdown_behavior", Type: cty.String, Required: false}, "shutdown_behavior": &hcldec.AttrSpec{Name: "shutdown_behavior", Type: cty.String, Required: false},
"instance_type": &hcldec.AttrSpec{Name: "instance_type", Type: cty.String, Required: false}, "instance_type": &hcldec.AttrSpec{Name: "instance_type", Type: cty.String, Required: false},
@ -239,9 +244,9 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false}, "winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false},
"winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false}, "winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false},
"ssh_interface": &hcldec.AttrSpec{Name: "ssh_interface", Type: cty.String, Required: false}, "ssh_interface": &hcldec.AttrSpec{Name: "ssh_interface", Type: cty.String, Required: false},
"ami_block_device_mappings": &hcldec.BlockListSpec{TypeName: "ami_block_device_mappings", Nested: &hcldec.BlockSpec{TypeName: "ami_block_device_mappings", Nested: hcldec.ObjectSpec((*common.FlatBlockDevice)(nil).HCL2Spec())}}, "ami_block_device_mappings": &hcldec.BlockListSpec{TypeName: "ami_block_device_mappings", Nested: hcldec.ObjectSpec((*common.FlatBlockDevice)(nil).HCL2Spec())},
"launch_block_device_mappings": &hcldec.BlockListSpec{TypeName: "launch_block_device_mappings", Nested: &hcldec.BlockSpec{TypeName: "launch_block_device_mappings", Nested: hcldec.ObjectSpec((*common.FlatBlockDevice)(nil).HCL2Spec())}}, "launch_block_device_mappings": &hcldec.BlockListSpec{TypeName: "launch_block_device_mappings", Nested: hcldec.ObjectSpec((*common.FlatBlockDevice)(nil).HCL2Spec())},
"run_volume_tags": &hcldec.BlockAttrsSpec{TypeName: "common.TagMap", ElementType: cty.String, Required: false}, "run_volume_tags": &hcldec.BlockAttrsSpec{TypeName: "run_volume_tags", ElementType: cty.String, Required: false},
"no_ephemeral": &hcldec.AttrSpec{Name: "no_ephemeral", Type: cty.Bool, Required: false}, "no_ephemeral": &hcldec.AttrSpec{Name: "no_ephemeral", Type: cty.Bool, Required: false},
} }
return s return s

View File

@ -32,7 +32,7 @@ func TestBuilder_Prepare_BadType(t *testing.T) {
"access_key": []string{}, "access_key": []string{},
} }
warnings, err := b.Prepare(c) _, warnings, err := b.Prepare(c)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -48,7 +48,7 @@ func TestBuilderPrepare_AMIName(t *testing.T) {
// Test good // Test good
config["ami_name"] = "foo" config["ami_name"] = "foo"
config["skip_region_validation"] = true config["skip_region_validation"] = true
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -59,7 +59,7 @@ func TestBuilderPrepare_AMIName(t *testing.T) {
// Test bad // Test bad
config["ami_name"] = "foo {{" config["ami_name"] = "foo {{"
b = Builder{} b = Builder{}
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -70,7 +70,7 @@ func TestBuilderPrepare_AMIName(t *testing.T) {
// Test bad // Test bad
delete(config, "ami_name") delete(config, "ami_name")
b = Builder{} b = Builder{}
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -85,7 +85,7 @@ func TestBuilderPrepare_InvalidKey(t *testing.T) {
// Add a random key // Add a random key
config["i_should_not_be_valid"] = true config["i_should_not_be_valid"] = true
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -101,7 +101,7 @@ func TestBuilderPrepare_InvalidShutdownBehavior(t *testing.T) {
// Test good // Test good
config["shutdown_behavior"] = "terminate" config["shutdown_behavior"] = "terminate"
config["skip_region_validation"] = true config["skip_region_validation"] = true
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -111,7 +111,7 @@ func TestBuilderPrepare_InvalidShutdownBehavior(t *testing.T) {
// Test good // Test good
config["shutdown_behavior"] = "stop" config["shutdown_behavior"] = "stop"
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -121,7 +121,7 @@ func TestBuilderPrepare_InvalidShutdownBehavior(t *testing.T) {
// Test bad // Test bad
config["shutdown_behavior"] = "foobar" config["shutdown_behavior"] = "foobar"
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }

View File

@ -1,4 +1,5 @@
//go:generate struct-markdown //go:generate struct-markdown
//go:generate mapstructure-to-hcl2 -type Config,RootBlockDevice,BlockDevice
// The ebssurrogate package contains a packer.Builder implementation that // The ebssurrogate package contains a packer.Builder implementation that
// builds a new EBS-backed AMI using an ephemeral instance. // builds a new EBS-backed AMI using an ephemeral instance.
@ -11,6 +12,7 @@ import (
"github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/iam" "github.com/aws/aws-sdk-go/service/iam"
"github.com/hashicorp/hcl/v2/hcldec"
awscommon "github.com/hashicorp/packer/builder/amazon/common" awscommon "github.com/hashicorp/packer/builder/amazon/common"
"github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/communicator" "github.com/hashicorp/packer/helper/communicator"
@ -70,7 +72,9 @@ type Builder struct {
runner multistep.Runner runner multistep.Runner
} }
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() }
func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
b.config.ctx.Funcs = awscommon.TemplateFuncs b.config.ctx.Funcs = awscommon.TemplateFuncs
err := config.Decode(&b.config, &config.DecodeOpts{ err := config.Decode(&b.config, &config.DecodeOpts{
Interpolate: true, Interpolate: true,
@ -87,7 +91,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
}, },
}, raws...) }, raws...)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
if b.config.PackerConfig.PackerForce { if b.config.PackerConfig.PackerForce {
@ -145,12 +149,12 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
errs = packer.MultiErrorAppend(errs, errors.New(`The only valid ami_architecture values are "x86_64" and "arm64"`)) errs = packer.MultiErrorAppend(errs, errors.New(`The only valid ami_architecture values are "x86_64" and "arm64"`))
} }
if errs != nil && len(errs.Errors) > 0 { if errs != nil && len(errs.Errors) > 0 {
return warns, errs return nil, warns, errs
} }
packer.LogSecretFilter.Set(b.config.AccessKey, b.config.SecretKey, b.config.Token) packer.LogSecretFilter.Set(b.config.AccessKey, b.config.SecretKey, b.config.Token)
return warns, nil return nil, warns, nil
} }
func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) { func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) {
@ -257,6 +261,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
}, },
&awscommon.StepIamInstanceProfile{ &awscommon.StepIamInstanceProfile{
IamInstanceProfile: b.config.IamInstanceProfile, IamInstanceProfile: b.config.IamInstanceProfile,
SkipProfileValidation: b.config.SkipProfileValidation,
TemporaryIamInstanceProfilePolicyDocument: b.config.TemporaryIamInstanceProfilePolicyDocument, TemporaryIamInstanceProfilePolicyDocument: b.config.TemporaryIamInstanceProfilePolicyDocument,
}, },
&awscommon.StepCleanupVolumes{ &awscommon.StepCleanupVolumes{

View File

@ -0,0 +1,331 @@
// Code generated by "mapstructure-to-hcl2 -type Config,RootBlockDevice,BlockDevice"; DO NOT EDIT.
package ebssurrogate
import (
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/packer/builder/amazon/common"
"github.com/zclconf/go-cty/cty"
)
// FlatBlockDevice is an auto-generated flat version of BlockDevice.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatBlockDevice struct {
DeleteOnTermination *bool `mapstructure:"delete_on_termination" required:"false" cty:"delete_on_termination"`
DeviceName *string `mapstructure:"device_name" required:"false" cty:"device_name"`
Encrypted *bool `mapstructure:"encrypted" required:"false" cty:"encrypted"`
IOPS *int64 `mapstructure:"iops" required:"false" cty:"iops"`
NoDevice *bool `mapstructure:"no_device" required:"false" cty:"no_device"`
SnapshotId *string `mapstructure:"snapshot_id" required:"false" cty:"snapshot_id"`
VirtualName *string `mapstructure:"virtual_name" required:"false" cty:"virtual_name"`
VolumeType *string `mapstructure:"volume_type" required:"false" cty:"volume_type"`
VolumeSize *int64 `mapstructure:"volume_size" required:"false" cty:"volume_size"`
KmsKeyId *string `mapstructure:"kms_key_id" required:"false" cty:"kms_key_id"`
OmitFromArtifact *bool `mapstructure:"omit_from_artifact" cty:"omit_from_artifact"`
}
// FlatMapstructure returns a new FlatBlockDevice.
// FlatBlockDevice is an auto-generated flat version of BlockDevice.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*BlockDevice) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatBlockDevice)
}
// HCL2Spec returns the hcl spec of a BlockDevice.
// This spec is used by HCL to read the fields of BlockDevice.
// The decoded values from this spec will then be applied to a FlatBlockDevice.
func (*FlatBlockDevice) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{
"delete_on_termination": &hcldec.AttrSpec{Name: "delete_on_termination", Type: cty.Bool, Required: false},
"device_name": &hcldec.AttrSpec{Name: "device_name", Type: cty.String, Required: false},
"encrypted": &hcldec.AttrSpec{Name: "encrypted", Type: cty.Bool, Required: false},
"iops": &hcldec.AttrSpec{Name: "iops", Type: cty.Number, Required: false},
"no_device": &hcldec.AttrSpec{Name: "no_device", Type: cty.Bool, Required: false},
"snapshot_id": &hcldec.AttrSpec{Name: "snapshot_id", Type: cty.String, Required: false},
"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},
"kms_key_id": &hcldec.AttrSpec{Name: "kms_key_id", Type: cty.String, Required: false},
"omit_from_artifact": &hcldec.AttrSpec{Name: "omit_from_artifact", Type: cty.Bool, Required: false},
}
return s
}
// 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"`
AccessKey *string `mapstructure:"access_key" required:"true" cty:"access_key"`
CustomEndpointEc2 *string `mapstructure:"custom_endpoint_ec2" required:"false" cty:"custom_endpoint_ec2"`
DecodeAuthZMessages *bool `mapstructure:"decode_authorization_messages" required:"false" cty:"decode_authorization_messages"`
InsecureSkipTLSVerify *bool `mapstructure:"insecure_skip_tls_verify" required:"false" cty:"insecure_skip_tls_verify"`
MFACode *string `mapstructure:"mfa_code" required:"false" cty:"mfa_code"`
ProfileName *string `mapstructure:"profile" required:"false" cty:"profile"`
RawRegion *string `mapstructure:"region" required:"true" cty:"region"`
SecretKey *string `mapstructure:"secret_key" required:"true" cty:"secret_key"`
SkipValidation *bool `mapstructure:"skip_region_validation" required:"false" cty:"skip_region_validation"`
SkipMetadataApiCheck *bool `mapstructure:"skip_metadata_api_check" cty:"skip_metadata_api_check"`
Token *string `mapstructure:"token" required:"false" cty:"token"`
VaultAWSEngine *common.FlatVaultAWSEngineOptions `mapstructure:"vault_aws_engine" required:"false" cty:"vault_aws_engine"`
AssociatePublicIpAddress *bool `mapstructure:"associate_public_ip_address" required:"false" cty:"associate_public_ip_address"`
AvailabilityZone *string `mapstructure:"availability_zone" required:"false" cty:"availability_zone"`
BlockDurationMinutes *int64 `mapstructure:"block_duration_minutes" required:"false" cty:"block_duration_minutes"`
DisableStopInstance *bool `mapstructure:"disable_stop_instance" required:"false" cty:"disable_stop_instance"`
EbsOptimized *bool `mapstructure:"ebs_optimized" required:"false" cty:"ebs_optimized"`
EnableT2Unlimited *bool `mapstructure:"enable_t2_unlimited" required:"false" cty:"enable_t2_unlimited"`
IamInstanceProfile *string `mapstructure:"iam_instance_profile" required:"false" cty:"iam_instance_profile"`
SkipProfileValidation *bool `mapstructure:"skip_profile_validation" required:"false" cty:"skip_profile_validation"`
TemporaryIamInstanceProfilePolicyDocument *common.FlatPolicyDocument `mapstructure:"temporary_iam_instance_profile_policy_document" required:"false" cty:"temporary_iam_instance_profile_policy_document"`
InstanceInitiatedShutdownBehavior *string `mapstructure:"shutdown_behavior" required:"false" cty:"shutdown_behavior"`
InstanceType *string `mapstructure:"instance_type" required:"true" cty:"instance_type"`
SecurityGroupFilter *common.FlatSecurityGroupFilterOptions `mapstructure:"security_group_filter" required:"false" cty:"security_group_filter"`
RunTags map[string]string `mapstructure:"run_tags" required:"false" cty:"run_tags"`
SecurityGroupId *string `mapstructure:"security_group_id" required:"false" cty:"security_group_id"`
SecurityGroupIds []string `mapstructure:"security_group_ids" required:"false" cty:"security_group_ids"`
SourceAmi *string `mapstructure:"source_ami" required:"true" cty:"source_ami"`
SourceAmiFilter *common.FlatAmiFilterOptions `mapstructure:"source_ami_filter" required:"false" cty:"source_ami_filter"`
SpotInstanceTypes []string `mapstructure:"spot_instance_types" required:"false" cty:"spot_instance_types"`
SpotPrice *string `mapstructure:"spot_price" required:"false" cty:"spot_price"`
SpotPriceAutoProduct *string `mapstructure:"spot_price_auto_product" required:"false" cty:"spot_price_auto_product"`
SpotTags map[string]string `mapstructure:"spot_tags" required:"false" cty:"spot_tags"`
SubnetFilter *common.FlatSubnetFilterOptions `mapstructure:"subnet_filter" required:"false" cty:"subnet_filter"`
SubnetId *string `mapstructure:"subnet_id" required:"false" cty:"subnet_id"`
TemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" required:"false" cty:"temporary_key_pair_name"`
TemporarySGSourceCidrs []string `mapstructure:"temporary_security_group_source_cidrs" required:"false" cty:"temporary_security_group_source_cidrs"`
UserData *string `mapstructure:"user_data" required:"false" cty:"user_data"`
UserDataFile *string `mapstructure:"user_data_file" required:"false" cty:"user_data_file"`
VpcFilter *common.FlatVpcFilterOptions `mapstructure:"vpc_filter" required:"false" cty:"vpc_filter"`
VpcId *string `mapstructure:"vpc_id" required:"false" cty:"vpc_id"`
WindowsPasswordTimeout *string `mapstructure:"windows_password_timeout" required:"false" cty:"windows_password_timeout"`
Type *string `mapstructure:"communicator" cty:"communicator"`
PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting"`
SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host"`
SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port"`
SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username"`
SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password"`
SSHKeyPairName *string `mapstructure:"ssh_keypair_name" cty:"ssh_keypair_name"`
SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys"`
SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" cty:"ssh_private_key_file"`
SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty"`
SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout"`
SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" cty:"ssh_agent_auth"`
SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding"`
SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts"`
SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host"`
SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port"`
SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth"`
SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username"`
SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password"`
SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file"`
SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method"`
SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host"`
SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port"`
SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username"`
SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password"`
SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval"`
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"`
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"`
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"`
SSHPublicKey []byte `mapstructure:"ssh_public_key" cty:"ssh_public_key"`
SSHPrivateKey []byte `mapstructure:"ssh_private_key" cty:"ssh_private_key"`
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"`
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"`
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"`
WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port"`
WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout"`
WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl"`
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure"`
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm"`
SSHInterface *string `mapstructure:"ssh_interface" cty:"ssh_interface"`
AMIName *string `mapstructure:"ami_name" required:"true" cty:"ami_name"`
AMIDescription *string `mapstructure:"ami_description" required:"false" cty:"ami_description"`
AMIVirtType *string `mapstructure:"ami_virtualization_type" required:"false" cty:"ami_virtualization_type"`
AMIUsers []string `mapstructure:"ami_users" required:"false" cty:"ami_users"`
AMIGroups []string `mapstructure:"ami_groups" required:"false" cty:"ami_groups"`
AMIProductCodes []string `mapstructure:"ami_product_codes" required:"false" cty:"ami_product_codes"`
AMIRegions []string `mapstructure:"ami_regions" required:"false" cty:"ami_regions"`
AMITags common.TagMap `mapstructure:"tags" required:"false" cty:"tags"`
AMIENASupport *bool `mapstructure:"ena_support" required:"false" cty:"ena_support"`
AMISriovNetSupport *bool `mapstructure:"sriov_support" required:"false" cty:"sriov_support"`
AMIForceDeregister *bool `mapstructure:"force_deregister" required:"false" cty:"force_deregister"`
AMIForceDeleteSnapshot *bool `mapstructure:"force_delete_snapshot" required:"false" cty:"force_delete_snapshot"`
AMIEncryptBootVolume *bool `mapstructure:"encrypt_boot" required:"false" cty:"encrypt_boot"`
AMIKmsKeyId *string `mapstructure:"kms_key_id" required:"false" cty:"kms_key_id"`
AMIRegionKMSKeyIDs map[string]string `mapstructure:"region_kms_key_ids" required:"false" cty:"region_kms_key_ids"`
AMISkipBuildRegion *bool `mapstructure:"skip_save_build_region" cty:"skip_save_build_region"`
SnapshotTags common.TagMap `mapstructure:"snapshot_tags" required:"false" cty:"snapshot_tags"`
SnapshotUsers []string `mapstructure:"snapshot_users" required:"false" cty:"snapshot_users"`
SnapshotGroups []string `mapstructure:"snapshot_groups" required:"false" cty:"snapshot_groups"`
AMIMappings []common.FlatBlockDevice `mapstructure:"ami_block_device_mappings" required:"false" cty:"ami_block_device_mappings"`
LaunchMappings []FlatBlockDevice `mapstructure:"launch_block_device_mappings" required:"false" cty:"launch_block_device_mappings"`
RootDevice *FlatRootBlockDevice `mapstructure:"ami_root_device" required:"true" cty:"ami_root_device"`
VolumeRunTags common.TagMap `mapstructure:"run_volume_tags" cty:"run_volume_tags"`
Architecture *string `mapstructure:"ami_architecture" required:"false" cty:"ami_architecture"`
}
// FlatMapstructure returns a new FlatConfig.
// FlatConfig is an auto-generated flat version of Config.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatConfig)
}
// HCL2Spec returns the hcl spec of a Config.
// This spec is used by HCL to read the fields of Config.
// 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},
"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},
"decode_authorization_messages": &hcldec.AttrSpec{Name: "decode_authorization_messages", Type: cty.Bool, Required: false},
"insecure_skip_tls_verify": &hcldec.AttrSpec{Name: "insecure_skip_tls_verify", Type: cty.Bool, Required: false},
"mfa_code": &hcldec.AttrSpec{Name: "mfa_code", Type: cty.String, Required: false},
"profile": &hcldec.AttrSpec{Name: "profile", Type: cty.String, Required: false},
"region": &hcldec.AttrSpec{Name: "region", Type: cty.String, Required: false},
"secret_key": &hcldec.AttrSpec{Name: "secret_key", Type: cty.String, Required: false},
"skip_region_validation": &hcldec.AttrSpec{Name: "skip_region_validation", Type: cty.Bool, Required: false},
"skip_metadata_api_check": &hcldec.AttrSpec{Name: "skip_metadata_api_check", Type: cty.Bool, Required: false},
"token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false},
"vault_aws_engine": &hcldec.BlockSpec{TypeName: "vault_aws_engine", Nested: hcldec.ObjectSpec((*common.FlatVaultAWSEngineOptions)(nil).HCL2Spec())},
"associate_public_ip_address": &hcldec.AttrSpec{Name: "associate_public_ip_address", Type: cty.Bool, Required: false},
"availability_zone": &hcldec.AttrSpec{Name: "availability_zone", Type: cty.String, Required: false},
"block_duration_minutes": &hcldec.AttrSpec{Name: "block_duration_minutes", Type: cty.Number, Required: false},
"disable_stop_instance": &hcldec.AttrSpec{Name: "disable_stop_instance", Type: cty.Bool, Required: false},
"ebs_optimized": &hcldec.AttrSpec{Name: "ebs_optimized", Type: cty.Bool, Required: false},
"enable_t2_unlimited": &hcldec.AttrSpec{Name: "enable_t2_unlimited", Type: cty.Bool, Required: false},
"iam_instance_profile": &hcldec.AttrSpec{Name: "iam_instance_profile", Type: cty.String, Required: false},
"skip_profile_validation": &hcldec.AttrSpec{Name: "skip_profile_validation", Type: cty.Bool, Required: false},
"temporary_iam_instance_profile_policy_document": &hcldec.BlockSpec{TypeName: "temporary_iam_instance_profile_policy_document", Nested: hcldec.ObjectSpec((*common.FlatPolicyDocument)(nil).HCL2Spec())},
"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},
"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_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())},
"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},
"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},
"temporary_security_group_source_cidrs": &hcldec.AttrSpec{Name: "temporary_security_group_source_cidrs", Type: cty.List(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},
"vpc_filter": &hcldec.BlockSpec{TypeName: "vpc_filter", Nested: hcldec.ObjectSpec((*common.FlatVpcFilterOptions)(nil).HCL2Spec())},
"vpc_id": &hcldec.AttrSpec{Name: "vpc_id", Type: cty.String, Required: false},
"windows_password_timeout": &hcldec.AttrSpec{Name: "windows_password_timeout", Type: 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},
"ssh_host": &hcldec.AttrSpec{Name: "ssh_host", Type: cty.String, Required: false},
"ssh_port": &hcldec.AttrSpec{Name: "ssh_port", Type: cty.Number, Required: false},
"ssh_username": &hcldec.AttrSpec{Name: "ssh_username", Type: cty.String, Required: false},
"ssh_password": &hcldec.AttrSpec{Name: "ssh_password", Type: cty.String, Required: false},
"ssh_keypair_name": &hcldec.AttrSpec{Name: "ssh_keypair_name", Type: cty.String, Required: false},
"ssh_clear_authorized_keys": &hcldec.AttrSpec{Name: "ssh_clear_authorized_keys", Type: cty.Bool, Required: false},
"ssh_private_key_file": &hcldec.AttrSpec{Name: "ssh_private_key_file", Type: cty.String, Required: false},
"ssh_pty": &hcldec.AttrSpec{Name: "ssh_pty", Type: cty.Bool, Required: false},
"ssh_timeout": &hcldec.AttrSpec{Name: "ssh_timeout", Type: cty.String, Required: false},
"ssh_agent_auth": &hcldec.AttrSpec{Name: "ssh_agent_auth", Type: cty.Bool, Required: false},
"ssh_disable_agent_forwarding": &hcldec.AttrSpec{Name: "ssh_disable_agent_forwarding", Type: cty.Bool, Required: false},
"ssh_handshake_attempts": &hcldec.AttrSpec{Name: "ssh_handshake_attempts", Type: cty.Number, Required: false},
"ssh_bastion_host": &hcldec.AttrSpec{Name: "ssh_bastion_host", Type: cty.String, Required: false},
"ssh_bastion_port": &hcldec.AttrSpec{Name: "ssh_bastion_port", Type: cty.Number, Required: false},
"ssh_bastion_agent_auth": &hcldec.AttrSpec{Name: "ssh_bastion_agent_auth", Type: cty.Bool, Required: false},
"ssh_bastion_username": &hcldec.AttrSpec{Name: "ssh_bastion_username", Type: cty.String, Required: false},
"ssh_bastion_password": &hcldec.AttrSpec{Name: "ssh_bastion_password", Type: cty.String, Required: false},
"ssh_bastion_private_key_file": &hcldec.AttrSpec{Name: "ssh_bastion_private_key_file", Type: cty.String, Required: false},
"ssh_file_transfer_method": &hcldec.AttrSpec{Name: "ssh_file_transfer_method", Type: cty.String, Required: false},
"ssh_proxy_host": &hcldec.AttrSpec{Name: "ssh_proxy_host", Type: cty.String, Required: false},
"ssh_proxy_port": &hcldec.AttrSpec{Name: "ssh_proxy_port", Type: cty.Number, Required: false},
"ssh_proxy_username": &hcldec.AttrSpec{Name: "ssh_proxy_username", Type: cty.String, Required: false},
"ssh_proxy_password": &hcldec.AttrSpec{Name: "ssh_proxy_password", Type: cty.String, Required: false},
"ssh_keep_alive_interval": &hcldec.AttrSpec{Name: "ssh_keep_alive_interval", Type: cty.String, Required: false},
"ssh_read_write_timeout": &hcldec.AttrSpec{Name: "ssh_read_write_timeout", Type: cty.String, Required: false},
"ssh_remote_tunnels": &hcldec.AttrSpec{Name: "ssh_remote_tunnels", Type: cty.List(cty.String), Required: false},
"ssh_local_tunnels": &hcldec.AttrSpec{Name: "ssh_local_tunnels", Type: cty.List(cty.String), Required: false},
"ssh_public_key": &hcldec.AttrSpec{Name: "ssh_public_key", Type: cty.List(cty.Number), Required: false},
"ssh_private_key": &hcldec.AttrSpec{Name: "ssh_private_key", Type: cty.List(cty.Number), Required: false},
"winrm_username": &hcldec.AttrSpec{Name: "winrm_username", Type: cty.String, Required: false},
"winrm_password": &hcldec.AttrSpec{Name: "winrm_password", Type: cty.String, Required: false},
"winrm_host": &hcldec.AttrSpec{Name: "winrm_host", Type: cty.String, Required: false},
"winrm_port": &hcldec.AttrSpec{Name: "winrm_port", Type: cty.Number, Required: false},
"winrm_timeout": &hcldec.AttrSpec{Name: "winrm_timeout", Type: cty.String, Required: false},
"winrm_use_ssl": &hcldec.AttrSpec{Name: "winrm_use_ssl", Type: cty.Bool, Required: false},
"winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false},
"winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false},
"ssh_interface": &hcldec.AttrSpec{Name: "ssh_interface", Type: cty.String, Required: false},
"ami_name": &hcldec.AttrSpec{Name: "ami_name", Type: cty.String, Required: false},
"ami_description": &hcldec.AttrSpec{Name: "ami_description", Type: cty.String, Required: false},
"ami_virtualization_type": &hcldec.AttrSpec{Name: "ami_virtualization_type", Type: cty.String, Required: false},
"ami_users": &hcldec.AttrSpec{Name: "ami_users", Type: cty.List(cty.String), Required: false},
"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},
"ena_support": &hcldec.AttrSpec{Name: "ena_support", Type: cty.Bool, Required: false},
"sriov_support": &hcldec.AttrSpec{Name: "sriov_support", Type: cty.Bool, 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},
"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},
"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_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},
"ami_architecture": &hcldec.AttrSpec{Name: "ami_architecture", Type: cty.String, Required: false},
}
return s
}
// FlatRootBlockDevice is an auto-generated flat version of RootBlockDevice.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatRootBlockDevice struct {
SourceDeviceName *string `mapstructure:"source_device_name" cty:"source_device_name"`
DeviceName *string `mapstructure:"device_name" required:"false" cty:"device_name"`
DeleteOnTermination *bool `mapstructure:"delete_on_termination" required:"false" cty:"delete_on_termination"`
IOPS *int64 `mapstructure:"iops" required:"false" cty:"iops"`
VolumeType *string `mapstructure:"volume_type" required:"false" cty:"volume_type"`
VolumeSize *int64 `mapstructure:"volume_size" required:"false" cty:"volume_size"`
}
// FlatMapstructure returns a new FlatRootBlockDevice.
// FlatRootBlockDevice is an auto-generated flat version of RootBlockDevice.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*RootBlockDevice) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatRootBlockDevice)
}
// HCL2Spec returns the hcl spec of a RootBlockDevice.
// This spec is used by HCL to read the fields of RootBlockDevice.
// The decoded values from this spec will then be applied to a FlatRootBlockDevice.
func (*FlatRootBlockDevice) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{
"source_device_name": &hcldec.AttrSpec{Name: "source_device_name", Type: cty.String, Required: false},
"device_name": &hcldec.AttrSpec{Name: "device_name", Type: cty.String, Required: false},
"delete_on_termination": &hcldec.AttrSpec{Name: "delete_on_termination", Type: cty.Bool, Required: false},
"iops": &hcldec.AttrSpec{Name: "iops", Type: cty.Number, 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},
}
return s
}

View File

@ -31,7 +31,7 @@ func TestBuilder_Prepare_BadType(t *testing.T) {
"access_key": []string{}, "access_key": []string{},
} }
warnings, err := b.Prepare(c) _, warnings, err := b.Prepare(c)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -46,7 +46,7 @@ func TestBuilderPrepare_InvalidKey(t *testing.T) {
// Add a random key // Add a random key
config["i_should_not_be_valid"] = true config["i_should_not_be_valid"] = true
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }

View File

@ -1,4 +1,5 @@
//go:generate struct-markdown //go:generate struct-markdown
//go:generate mapstructure-to-hcl2 -type Config,BlockDevice
// The ebsvolume package contains a packer.Builder implementation that builds // The ebsvolume package contains a packer.Builder implementation that builds
// EBS volumes for Amazon EC2 using an ephemeral instance, // EBS volumes for Amazon EC2 using an ephemeral instance,
@ -10,6 +11,7 @@ import (
"github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/iam" "github.com/aws/aws-sdk-go/service/iam"
"github.com/hashicorp/hcl/v2/hcldec"
awscommon "github.com/hashicorp/packer/builder/amazon/common" awscommon "github.com/hashicorp/packer/builder/amazon/common"
"github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/communicator" "github.com/hashicorp/packer/helper/communicator"
@ -79,7 +81,9 @@ type EngineVarsTemplate struct {
SourceAMI string SourceAMI string
} }
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() }
func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
b.config.ctx.Funcs = awscommon.TemplateFuncs b.config.ctx.Funcs = awscommon.TemplateFuncs
// Create passthrough for {{ .BuildRegion }} and {{ .SourceAMI }} variables // Create passthrough for {{ .BuildRegion }} and {{ .SourceAMI }} variables
// so we can fill them in later // so we can fill them in later
@ -92,7 +96,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
InterpolateContext: &b.config.ctx, InterpolateContext: &b.config.ctx,
}, raws...) }, raws...)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
// Accumulate any errors // Accumulate any errors
@ -129,11 +133,11 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
} }
if errs != nil && len(errs.Errors) > 0 { if errs != nil && len(errs.Errors) > 0 {
return warns, errs return nil, warns, errs
} }
packer.LogSecretFilter.Set(b.config.AccessKey, b.config.SecretKey, b.config.Token) packer.LogSecretFilter.Set(b.config.AccessKey, b.config.SecretKey, b.config.Token)
return warns, nil return nil, warns, nil
} }
func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) { func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) {
@ -227,6 +231,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
}, },
&awscommon.StepIamInstanceProfile{ &awscommon.StepIamInstanceProfile{
IamInstanceProfile: b.config.IamInstanceProfile, IamInstanceProfile: b.config.IamInstanceProfile,
SkipProfileValidation: b.config.SkipProfileValidation,
TemporaryIamInstanceProfilePolicyDocument: b.config.TemporaryIamInstanceProfilePolicyDocument, TemporaryIamInstanceProfilePolicyDocument: b.config.TemporaryIamInstanceProfilePolicyDocument,
}, },
instanceStep, instanceStep,

View File

@ -0,0 +1,258 @@
// Code generated by "mapstructure-to-hcl2 -type Config,BlockDevice"; DO NOT EDIT.
package ebsvolume
import (
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/packer/builder/amazon/common"
"github.com/zclconf/go-cty/cty"
)
// FlatBlockDevice is an auto-generated flat version of BlockDevice.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatBlockDevice struct {
DeleteOnTermination *bool `mapstructure:"delete_on_termination" required:"false" cty:"delete_on_termination"`
DeviceName *string `mapstructure:"device_name" required:"false" cty:"device_name"`
Encrypted *bool `mapstructure:"encrypted" required:"false" cty:"encrypted"`
IOPS *int64 `mapstructure:"iops" required:"false" cty:"iops"`
NoDevice *bool `mapstructure:"no_device" required:"false" cty:"no_device"`
SnapshotId *string `mapstructure:"snapshot_id" required:"false" cty:"snapshot_id"`
VirtualName *string `mapstructure:"virtual_name" required:"false" cty:"virtual_name"`
VolumeType *string `mapstructure:"volume_type" required:"false" cty:"volume_type"`
VolumeSize *int64 `mapstructure:"volume_size" required:"false" cty:"volume_size"`
KmsKeyId *string `mapstructure:"kms_key_id" required:"false" cty:"kms_key_id"`
Tags common.TagMap `mapstructure:"tags" required:"false" cty:"tags"`
}
// FlatMapstructure returns a new FlatBlockDevice.
// FlatBlockDevice is an auto-generated flat version of BlockDevice.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*BlockDevice) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatBlockDevice)
}
// HCL2Spec returns the hcl spec of a BlockDevice.
// This spec is used by HCL to read the fields of BlockDevice.
// The decoded values from this spec will then be applied to a FlatBlockDevice.
func (*FlatBlockDevice) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{
"delete_on_termination": &hcldec.AttrSpec{Name: "delete_on_termination", Type: cty.Bool, Required: false},
"device_name": &hcldec.AttrSpec{Name: "device_name", Type: cty.String, Required: false},
"encrypted": &hcldec.AttrSpec{Name: "encrypted", Type: cty.Bool, Required: false},
"iops": &hcldec.AttrSpec{Name: "iops", Type: cty.Number, Required: false},
"no_device": &hcldec.AttrSpec{Name: "no_device", Type: cty.Bool, Required: false},
"snapshot_id": &hcldec.AttrSpec{Name: "snapshot_id", Type: cty.String, Required: false},
"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},
"kms_key_id": &hcldec.AttrSpec{Name: "kms_key_id", Type: cty.String, Required: false},
"tags": &hcldec.BlockAttrsSpec{TypeName: "tags", ElementType: cty.String, Required: false},
}
return s
}
// 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"`
AccessKey *string `mapstructure:"access_key" required:"true" cty:"access_key"`
CustomEndpointEc2 *string `mapstructure:"custom_endpoint_ec2" required:"false" cty:"custom_endpoint_ec2"`
DecodeAuthZMessages *bool `mapstructure:"decode_authorization_messages" required:"false" cty:"decode_authorization_messages"`
InsecureSkipTLSVerify *bool `mapstructure:"insecure_skip_tls_verify" required:"false" cty:"insecure_skip_tls_verify"`
MFACode *string `mapstructure:"mfa_code" required:"false" cty:"mfa_code"`
ProfileName *string `mapstructure:"profile" required:"false" cty:"profile"`
RawRegion *string `mapstructure:"region" required:"true" cty:"region"`
SecretKey *string `mapstructure:"secret_key" required:"true" cty:"secret_key"`
SkipValidation *bool `mapstructure:"skip_region_validation" required:"false" cty:"skip_region_validation"`
SkipMetadataApiCheck *bool `mapstructure:"skip_metadata_api_check" cty:"skip_metadata_api_check"`
Token *string `mapstructure:"token" required:"false" cty:"token"`
VaultAWSEngine *common.FlatVaultAWSEngineOptions `mapstructure:"vault_aws_engine" required:"false" cty:"vault_aws_engine"`
AssociatePublicIpAddress *bool `mapstructure:"associate_public_ip_address" required:"false" cty:"associate_public_ip_address"`
AvailabilityZone *string `mapstructure:"availability_zone" required:"false" cty:"availability_zone"`
BlockDurationMinutes *int64 `mapstructure:"block_duration_minutes" required:"false" cty:"block_duration_minutes"`
DisableStopInstance *bool `mapstructure:"disable_stop_instance" required:"false" cty:"disable_stop_instance"`
EbsOptimized *bool `mapstructure:"ebs_optimized" required:"false" cty:"ebs_optimized"`
EnableT2Unlimited *bool `mapstructure:"enable_t2_unlimited" required:"false" cty:"enable_t2_unlimited"`
IamInstanceProfile *string `mapstructure:"iam_instance_profile" required:"false" cty:"iam_instance_profile"`
SkipProfileValidation *bool `mapstructure:"skip_profile_validation" required:"false" cty:"skip_profile_validation"`
TemporaryIamInstanceProfilePolicyDocument *common.FlatPolicyDocument `mapstructure:"temporary_iam_instance_profile_policy_document" required:"false" cty:"temporary_iam_instance_profile_policy_document"`
InstanceInitiatedShutdownBehavior *string `mapstructure:"shutdown_behavior" required:"false" cty:"shutdown_behavior"`
InstanceType *string `mapstructure:"instance_type" required:"true" cty:"instance_type"`
SecurityGroupFilter *common.FlatSecurityGroupFilterOptions `mapstructure:"security_group_filter" required:"false" cty:"security_group_filter"`
RunTags map[string]string `mapstructure:"run_tags" required:"false" cty:"run_tags"`
SecurityGroupId *string `mapstructure:"security_group_id" required:"false" cty:"security_group_id"`
SecurityGroupIds []string `mapstructure:"security_group_ids" required:"false" cty:"security_group_ids"`
SourceAmi *string `mapstructure:"source_ami" required:"true" cty:"source_ami"`
SourceAmiFilter *common.FlatAmiFilterOptions `mapstructure:"source_ami_filter" required:"false" cty:"source_ami_filter"`
SpotInstanceTypes []string `mapstructure:"spot_instance_types" required:"false" cty:"spot_instance_types"`
SpotPrice *string `mapstructure:"spot_price" required:"false" cty:"spot_price"`
SpotPriceAutoProduct *string `mapstructure:"spot_price_auto_product" required:"false" cty:"spot_price_auto_product"`
SpotTags map[string]string `mapstructure:"spot_tags" required:"false" cty:"spot_tags"`
SubnetFilter *common.FlatSubnetFilterOptions `mapstructure:"subnet_filter" required:"false" cty:"subnet_filter"`
SubnetId *string `mapstructure:"subnet_id" required:"false" cty:"subnet_id"`
TemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" required:"false" cty:"temporary_key_pair_name"`
TemporarySGSourceCidrs []string `mapstructure:"temporary_security_group_source_cidrs" required:"false" cty:"temporary_security_group_source_cidrs"`
UserData *string `mapstructure:"user_data" required:"false" cty:"user_data"`
UserDataFile *string `mapstructure:"user_data_file" required:"false" cty:"user_data_file"`
VpcFilter *common.FlatVpcFilterOptions `mapstructure:"vpc_filter" required:"false" cty:"vpc_filter"`
VpcId *string `mapstructure:"vpc_id" required:"false" cty:"vpc_id"`
WindowsPasswordTimeout *string `mapstructure:"windows_password_timeout" required:"false" cty:"windows_password_timeout"`
Type *string `mapstructure:"communicator" cty:"communicator"`
PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting"`
SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host"`
SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port"`
SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username"`
SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password"`
SSHKeyPairName *string `mapstructure:"ssh_keypair_name" cty:"ssh_keypair_name"`
SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys"`
SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" cty:"ssh_private_key_file"`
SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty"`
SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout"`
SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" cty:"ssh_agent_auth"`
SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding"`
SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts"`
SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host"`
SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port"`
SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth"`
SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username"`
SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password"`
SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file"`
SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method"`
SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host"`
SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port"`
SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username"`
SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password"`
SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval"`
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"`
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"`
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"`
SSHPublicKey []byte `mapstructure:"ssh_public_key" cty:"ssh_public_key"`
SSHPrivateKey []byte `mapstructure:"ssh_private_key" cty:"ssh_private_key"`
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"`
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"`
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"`
WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port"`
WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout"`
WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl"`
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure"`
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm"`
SSHInterface *string `mapstructure:"ssh_interface" cty:"ssh_interface"`
AMIENASupport *bool `mapstructure:"ena_support" required:"false" cty:"ena_support"`
AMISriovNetSupport *bool `mapstructure:"sriov_support" required:"false" cty:"sriov_support"`
VolumeMappings []FlatBlockDevice `mapstructure:"ebs_volumes" required:"false" cty:"ebs_volumes"`
VolumeRunTags common.TagMap `mapstructure:"run_volume_tags" cty:"run_volume_tags"`
}
// FlatMapstructure returns a new FlatConfig.
// FlatConfig is an auto-generated flat version of Config.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatConfig)
}
// HCL2Spec returns the hcl spec of a Config.
// This spec is used by HCL to read the fields of Config.
// 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},
"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},
"decode_authorization_messages": &hcldec.AttrSpec{Name: "decode_authorization_messages", Type: cty.Bool, Required: false},
"insecure_skip_tls_verify": &hcldec.AttrSpec{Name: "insecure_skip_tls_verify", Type: cty.Bool, Required: false},
"mfa_code": &hcldec.AttrSpec{Name: "mfa_code", Type: cty.String, Required: false},
"profile": &hcldec.AttrSpec{Name: "profile", Type: cty.String, Required: false},
"region": &hcldec.AttrSpec{Name: "region", Type: cty.String, Required: false},
"secret_key": &hcldec.AttrSpec{Name: "secret_key", Type: cty.String, Required: false},
"skip_region_validation": &hcldec.AttrSpec{Name: "skip_region_validation", Type: cty.Bool, Required: false},
"skip_metadata_api_check": &hcldec.AttrSpec{Name: "skip_metadata_api_check", Type: cty.Bool, Required: false},
"token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false},
"vault_aws_engine": &hcldec.BlockSpec{TypeName: "vault_aws_engine", Nested: hcldec.ObjectSpec((*common.FlatVaultAWSEngineOptions)(nil).HCL2Spec())},
"associate_public_ip_address": &hcldec.AttrSpec{Name: "associate_public_ip_address", Type: cty.Bool, Required: false},
"availability_zone": &hcldec.AttrSpec{Name: "availability_zone", Type: cty.String, Required: false},
"block_duration_minutes": &hcldec.AttrSpec{Name: "block_duration_minutes", Type: cty.Number, Required: false},
"disable_stop_instance": &hcldec.AttrSpec{Name: "disable_stop_instance", Type: cty.Bool, Required: false},
"ebs_optimized": &hcldec.AttrSpec{Name: "ebs_optimized", Type: cty.Bool, Required: false},
"enable_t2_unlimited": &hcldec.AttrSpec{Name: "enable_t2_unlimited", Type: cty.Bool, Required: false},
"iam_instance_profile": &hcldec.AttrSpec{Name: "iam_instance_profile", Type: cty.String, Required: false},
"skip_profile_validation": &hcldec.AttrSpec{Name: "skip_profile_validation", Type: cty.Bool, Required: false},
"temporary_iam_instance_profile_policy_document": &hcldec.BlockSpec{TypeName: "temporary_iam_instance_profile_policy_document", Nested: hcldec.ObjectSpec((*common.FlatPolicyDocument)(nil).HCL2Spec())},
"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},
"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_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())},
"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},
"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},
"temporary_security_group_source_cidrs": &hcldec.AttrSpec{Name: "temporary_security_group_source_cidrs", Type: cty.List(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},
"vpc_filter": &hcldec.BlockSpec{TypeName: "vpc_filter", Nested: hcldec.ObjectSpec((*common.FlatVpcFilterOptions)(nil).HCL2Spec())},
"vpc_id": &hcldec.AttrSpec{Name: "vpc_id", Type: cty.String, Required: false},
"windows_password_timeout": &hcldec.AttrSpec{Name: "windows_password_timeout", Type: 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},
"ssh_host": &hcldec.AttrSpec{Name: "ssh_host", Type: cty.String, Required: false},
"ssh_port": &hcldec.AttrSpec{Name: "ssh_port", Type: cty.Number, Required: false},
"ssh_username": &hcldec.AttrSpec{Name: "ssh_username", Type: cty.String, Required: false},
"ssh_password": &hcldec.AttrSpec{Name: "ssh_password", Type: cty.String, Required: false},
"ssh_keypair_name": &hcldec.AttrSpec{Name: "ssh_keypair_name", Type: cty.String, Required: false},
"ssh_clear_authorized_keys": &hcldec.AttrSpec{Name: "ssh_clear_authorized_keys", Type: cty.Bool, Required: false},
"ssh_private_key_file": &hcldec.AttrSpec{Name: "ssh_private_key_file", Type: cty.String, Required: false},
"ssh_pty": &hcldec.AttrSpec{Name: "ssh_pty", Type: cty.Bool, Required: false},
"ssh_timeout": &hcldec.AttrSpec{Name: "ssh_timeout", Type: cty.String, Required: false},
"ssh_agent_auth": &hcldec.AttrSpec{Name: "ssh_agent_auth", Type: cty.Bool, Required: false},
"ssh_disable_agent_forwarding": &hcldec.AttrSpec{Name: "ssh_disable_agent_forwarding", Type: cty.Bool, Required: false},
"ssh_handshake_attempts": &hcldec.AttrSpec{Name: "ssh_handshake_attempts", Type: cty.Number, Required: false},
"ssh_bastion_host": &hcldec.AttrSpec{Name: "ssh_bastion_host", Type: cty.String, Required: false},
"ssh_bastion_port": &hcldec.AttrSpec{Name: "ssh_bastion_port", Type: cty.Number, Required: false},
"ssh_bastion_agent_auth": &hcldec.AttrSpec{Name: "ssh_bastion_agent_auth", Type: cty.Bool, Required: false},
"ssh_bastion_username": &hcldec.AttrSpec{Name: "ssh_bastion_username", Type: cty.String, Required: false},
"ssh_bastion_password": &hcldec.AttrSpec{Name: "ssh_bastion_password", Type: cty.String, Required: false},
"ssh_bastion_private_key_file": &hcldec.AttrSpec{Name: "ssh_bastion_private_key_file", Type: cty.String, Required: false},
"ssh_file_transfer_method": &hcldec.AttrSpec{Name: "ssh_file_transfer_method", Type: cty.String, Required: false},
"ssh_proxy_host": &hcldec.AttrSpec{Name: "ssh_proxy_host", Type: cty.String, Required: false},
"ssh_proxy_port": &hcldec.AttrSpec{Name: "ssh_proxy_port", Type: cty.Number, Required: false},
"ssh_proxy_username": &hcldec.AttrSpec{Name: "ssh_proxy_username", Type: cty.String, Required: false},
"ssh_proxy_password": &hcldec.AttrSpec{Name: "ssh_proxy_password", Type: cty.String, Required: false},
"ssh_keep_alive_interval": &hcldec.AttrSpec{Name: "ssh_keep_alive_interval", Type: cty.String, Required: false},
"ssh_read_write_timeout": &hcldec.AttrSpec{Name: "ssh_read_write_timeout", Type: cty.String, Required: false},
"ssh_remote_tunnels": &hcldec.AttrSpec{Name: "ssh_remote_tunnels", Type: cty.List(cty.String), Required: false},
"ssh_local_tunnels": &hcldec.AttrSpec{Name: "ssh_local_tunnels", Type: cty.List(cty.String), Required: false},
"ssh_public_key": &hcldec.AttrSpec{Name: "ssh_public_key", Type: cty.List(cty.Number), Required: false},
"ssh_private_key": &hcldec.AttrSpec{Name: "ssh_private_key", Type: cty.List(cty.Number), Required: false},
"winrm_username": &hcldec.AttrSpec{Name: "winrm_username", Type: cty.String, Required: false},
"winrm_password": &hcldec.AttrSpec{Name: "winrm_password", Type: cty.String, Required: false},
"winrm_host": &hcldec.AttrSpec{Name: "winrm_host", Type: cty.String, Required: false},
"winrm_port": &hcldec.AttrSpec{Name: "winrm_port", Type: cty.Number, Required: false},
"winrm_timeout": &hcldec.AttrSpec{Name: "winrm_timeout", Type: cty.String, Required: false},
"winrm_use_ssl": &hcldec.AttrSpec{Name: "winrm_use_ssl", Type: cty.Bool, Required: false},
"winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false},
"winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false},
"ssh_interface": &hcldec.AttrSpec{Name: "ssh_interface", Type: cty.String, Required: false},
"ena_support": &hcldec.AttrSpec{Name: "ena_support", Type: cty.Bool, Required: false},
"sriov_support": &hcldec.AttrSpec{Name: "sriov_support", Type: cty.Bool, Required: false},
"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},
}
return s
}

View File

@ -31,7 +31,7 @@ func TestBuilder_Prepare_BadType(t *testing.T) {
"access_key": []string{}, "access_key": []string{},
} }
warnings, err := b.Prepare(c) _, warnings, err := b.Prepare(c)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -46,7 +46,7 @@ func TestBuilderPrepare_InvalidKey(t *testing.T) {
// Add a random key // Add a random key
config["i_should_not_be_valid"] = true config["i_should_not_be_valid"] = true
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -62,7 +62,7 @@ func TestBuilderPrepare_InvalidShutdownBehavior(t *testing.T) {
// Test good // Test good
config["shutdown_behavior"] = "terminate" config["shutdown_behavior"] = "terminate"
config["skip_region_validation"] = true config["skip_region_validation"] = true
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -72,7 +72,7 @@ func TestBuilderPrepare_InvalidShutdownBehavior(t *testing.T) {
// Test good // Test good
config["shutdown_behavior"] = "stop" config["shutdown_behavior"] = "stop"
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -82,7 +82,7 @@ func TestBuilderPrepare_InvalidShutdownBehavior(t *testing.T) {
// Test bad // Test bad
config["shutdown_behavior"] = "foobar" config["shutdown_behavior"] = "foobar"
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }

View File

@ -1,4 +1,5 @@
//go:generate struct-markdown //go:generate struct-markdown
//go:generate mapstructure-to-hcl2 -type Config
// The instance package contains a packer.Builder implementation that builds // The instance package contains a packer.Builder implementation that builds
// AMIs for Amazon EC2 backed by instance storage, as opposed to EBS storage. // AMIs for Amazon EC2 backed by instance storage, as opposed to EBS storage.
@ -13,6 +14,7 @@ import (
"github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/iam" "github.com/aws/aws-sdk-go/service/iam"
"github.com/hashicorp/hcl/v2/hcldec"
awscommon "github.com/hashicorp/packer/builder/amazon/common" awscommon "github.com/hashicorp/packer/builder/amazon/common"
"github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/communicator" "github.com/hashicorp/packer/helper/communicator"
@ -93,7 +95,9 @@ type Builder struct {
runner multistep.Runner runner multistep.Runner
} }
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() }
func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
configs := make([]interface{}, len(raws)+1) configs := make([]interface{}, len(raws)+1)
configs[0] = map[string]interface{}{ configs[0] = map[string]interface{}{
"bundle_prefix": "image-{{timestamp}}", "bundle_prefix": "image-{{timestamp}}",
@ -118,7 +122,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
}, },
}, configs...) }, configs...)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
if b.config.PackerConfig.PackerForce { if b.config.PackerConfig.PackerForce {
@ -218,10 +222,10 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
} }
if errs != nil && len(errs.Errors) > 0 { if errs != nil && len(errs.Errors) > 0 {
return warns, errs return nil, warns, errs
} }
packer.LogSecretFilter.Set(b.config.AccessKey, b.config.SecretKey, b.config.Token) packer.LogSecretFilter.Set(b.config.AccessKey, b.config.SecretKey, b.config.Token)
return warns, nil return nil, warns, nil
} }
func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) { func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) {
@ -318,6 +322,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
}, },
&awscommon.StepIamInstanceProfile{ &awscommon.StepIamInstanceProfile{
IamInstanceProfile: b.config.IamInstanceProfile, IamInstanceProfile: b.config.IamInstanceProfile,
SkipProfileValidation: b.config.SkipProfileValidation,
TemporaryIamInstanceProfilePolicyDocument: b.config.TemporaryIamInstanceProfilePolicyDocument, TemporaryIamInstanceProfilePolicyDocument: b.config.TemporaryIamInstanceProfilePolicyDocument,
}, },
instanceStep, instanceStep,

View File

@ -0,0 +1,267 @@
// Code generated by "mapstructure-to-hcl2 -type Config"; DO NOT EDIT.
package instance
import (
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/packer/builder/amazon/common"
"github.com/zclconf/go-cty/cty"
)
// 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"`
AccessKey *string `mapstructure:"access_key" required:"true" cty:"access_key"`
CustomEndpointEc2 *string `mapstructure:"custom_endpoint_ec2" required:"false" cty:"custom_endpoint_ec2"`
DecodeAuthZMessages *bool `mapstructure:"decode_authorization_messages" required:"false" cty:"decode_authorization_messages"`
InsecureSkipTLSVerify *bool `mapstructure:"insecure_skip_tls_verify" required:"false" cty:"insecure_skip_tls_verify"`
MFACode *string `mapstructure:"mfa_code" required:"false" cty:"mfa_code"`
ProfileName *string `mapstructure:"profile" required:"false" cty:"profile"`
RawRegion *string `mapstructure:"region" required:"true" cty:"region"`
SecretKey *string `mapstructure:"secret_key" required:"true" cty:"secret_key"`
SkipValidation *bool `mapstructure:"skip_region_validation" required:"false" cty:"skip_region_validation"`
SkipMetadataApiCheck *bool `mapstructure:"skip_metadata_api_check" cty:"skip_metadata_api_check"`
Token *string `mapstructure:"token" required:"false" cty:"token"`
VaultAWSEngine *common.FlatVaultAWSEngineOptions `mapstructure:"vault_aws_engine" required:"false" cty:"vault_aws_engine"`
AMIName *string `mapstructure:"ami_name" required:"true" cty:"ami_name"`
AMIDescription *string `mapstructure:"ami_description" required:"false" cty:"ami_description"`
AMIVirtType *string `mapstructure:"ami_virtualization_type" required:"false" cty:"ami_virtualization_type"`
AMIUsers []string `mapstructure:"ami_users" required:"false" cty:"ami_users"`
AMIGroups []string `mapstructure:"ami_groups" required:"false" cty:"ami_groups"`
AMIProductCodes []string `mapstructure:"ami_product_codes" required:"false" cty:"ami_product_codes"`
AMIRegions []string `mapstructure:"ami_regions" required:"false" cty:"ami_regions"`
AMITags common.TagMap `mapstructure:"tags" required:"false" cty:"tags"`
AMIENASupport *bool `mapstructure:"ena_support" required:"false" cty:"ena_support"`
AMISriovNetSupport *bool `mapstructure:"sriov_support" required:"false" cty:"sriov_support"`
AMIForceDeregister *bool `mapstructure:"force_deregister" required:"false" cty:"force_deregister"`
AMIForceDeleteSnapshot *bool `mapstructure:"force_delete_snapshot" required:"false" cty:"force_delete_snapshot"`
AMIEncryptBootVolume *bool `mapstructure:"encrypt_boot" required:"false" cty:"encrypt_boot"`
AMIKmsKeyId *string `mapstructure:"kms_key_id" required:"false" cty:"kms_key_id"`
AMIRegionKMSKeyIDs map[string]string `mapstructure:"region_kms_key_ids" required:"false" cty:"region_kms_key_ids"`
AMISkipBuildRegion *bool `mapstructure:"skip_save_build_region" cty:"skip_save_build_region"`
SnapshotTags common.TagMap `mapstructure:"snapshot_tags" required:"false" cty:"snapshot_tags"`
SnapshotUsers []string `mapstructure:"snapshot_users" required:"false" cty:"snapshot_users"`
SnapshotGroups []string `mapstructure:"snapshot_groups" required:"false" cty:"snapshot_groups"`
AssociatePublicIpAddress *bool `mapstructure:"associate_public_ip_address" required:"false" cty:"associate_public_ip_address"`
AvailabilityZone *string `mapstructure:"availability_zone" required:"false" cty:"availability_zone"`
BlockDurationMinutes *int64 `mapstructure:"block_duration_minutes" required:"false" cty:"block_duration_minutes"`
DisableStopInstance *bool `mapstructure:"disable_stop_instance" required:"false" cty:"disable_stop_instance"`
EbsOptimized *bool `mapstructure:"ebs_optimized" required:"false" cty:"ebs_optimized"`
EnableT2Unlimited *bool `mapstructure:"enable_t2_unlimited" required:"false" cty:"enable_t2_unlimited"`
IamInstanceProfile *string `mapstructure:"iam_instance_profile" required:"false" cty:"iam_instance_profile"`
SkipProfileValidation *bool `mapstructure:"skip_profile_validation" required:"false" cty:"skip_profile_validation"`
TemporaryIamInstanceProfilePolicyDocument *common.FlatPolicyDocument `mapstructure:"temporary_iam_instance_profile_policy_document" required:"false" cty:"temporary_iam_instance_profile_policy_document"`
InstanceInitiatedShutdownBehavior *string `mapstructure:"shutdown_behavior" required:"false" cty:"shutdown_behavior"`
InstanceType *string `mapstructure:"instance_type" required:"true" cty:"instance_type"`
SecurityGroupFilter *common.FlatSecurityGroupFilterOptions `mapstructure:"security_group_filter" required:"false" cty:"security_group_filter"`
RunTags map[string]string `mapstructure:"run_tags" required:"false" cty:"run_tags"`
SecurityGroupId *string `mapstructure:"security_group_id" required:"false" cty:"security_group_id"`
SecurityGroupIds []string `mapstructure:"security_group_ids" required:"false" cty:"security_group_ids"`
SourceAmi *string `mapstructure:"source_ami" required:"true" cty:"source_ami"`
SourceAmiFilter *common.FlatAmiFilterOptions `mapstructure:"source_ami_filter" required:"false" cty:"source_ami_filter"`
SpotInstanceTypes []string `mapstructure:"spot_instance_types" required:"false" cty:"spot_instance_types"`
SpotPrice *string `mapstructure:"spot_price" required:"false" cty:"spot_price"`
SpotPriceAutoProduct *string `mapstructure:"spot_price_auto_product" required:"false" cty:"spot_price_auto_product"`
SpotTags map[string]string `mapstructure:"spot_tags" required:"false" cty:"spot_tags"`
SubnetFilter *common.FlatSubnetFilterOptions `mapstructure:"subnet_filter" required:"false" cty:"subnet_filter"`
SubnetId *string `mapstructure:"subnet_id" required:"false" cty:"subnet_id"`
TemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" required:"false" cty:"temporary_key_pair_name"`
TemporarySGSourceCidrs []string `mapstructure:"temporary_security_group_source_cidrs" required:"false" cty:"temporary_security_group_source_cidrs"`
UserData *string `mapstructure:"user_data" required:"false" cty:"user_data"`
UserDataFile *string `mapstructure:"user_data_file" required:"false" cty:"user_data_file"`
VpcFilter *common.FlatVpcFilterOptions `mapstructure:"vpc_filter" required:"false" cty:"vpc_filter"`
VpcId *string `mapstructure:"vpc_id" required:"false" cty:"vpc_id"`
WindowsPasswordTimeout *string `mapstructure:"windows_password_timeout" required:"false" cty:"windows_password_timeout"`
Type *string `mapstructure:"communicator" cty:"communicator"`
PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting"`
SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host"`
SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port"`
SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username"`
SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password"`
SSHKeyPairName *string `mapstructure:"ssh_keypair_name" cty:"ssh_keypair_name"`
SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys"`
SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" cty:"ssh_private_key_file"`
SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty"`
SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout"`
SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" cty:"ssh_agent_auth"`
SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding"`
SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts"`
SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host"`
SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port"`
SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth"`
SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username"`
SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password"`
SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file"`
SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method"`
SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host"`
SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port"`
SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username"`
SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password"`
SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval"`
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"`
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"`
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"`
SSHPublicKey []byte `mapstructure:"ssh_public_key" cty:"ssh_public_key"`
SSHPrivateKey []byte `mapstructure:"ssh_private_key" cty:"ssh_private_key"`
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"`
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"`
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"`
WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port"`
WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout"`
WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl"`
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure"`
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm"`
SSHInterface *string `mapstructure:"ssh_interface" cty:"ssh_interface"`
AMIMappings []common.FlatBlockDevice `mapstructure:"ami_block_device_mappings" required:"false" cty:"ami_block_device_mappings"`
LaunchMappings []common.FlatBlockDevice `mapstructure:"launch_block_device_mappings" required:"false" cty:"launch_block_device_mappings"`
AccountId *string `mapstructure:"account_id" required:"true" cty:"account_id"`
BundleDestination *string `mapstructure:"bundle_destination" required:"false" cty:"bundle_destination"`
BundlePrefix *string `mapstructure:"bundle_prefix" required:"false" cty:"bundle_prefix"`
BundleUploadCommand *string `mapstructure:"bundle_upload_command" required:"false" cty:"bundle_upload_command"`
BundleVolCommand *string `mapstructure:"bundle_vol_command" required:"false" cty:"bundle_vol_command"`
S3Bucket *string `mapstructure:"s3_bucket" required:"true" cty:"s3_bucket"`
X509CertPath *string `mapstructure:"x509_cert_path" required:"true" cty:"x509_cert_path"`
X509KeyPath *string `mapstructure:"x509_key_path" required:"true" cty:"x509_key_path"`
X509UploadPath *string `mapstructure:"x509_upload_path" required:"false" cty:"x509_upload_path"`
}
// FlatMapstructure returns a new FlatConfig.
// FlatConfig is an auto-generated flat version of Config.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatConfig)
}
// HCL2Spec returns the hcl spec of a Config.
// This spec is used by HCL to read the fields of Config.
// 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},
"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},
"decode_authorization_messages": &hcldec.AttrSpec{Name: "decode_authorization_messages", Type: cty.Bool, Required: false},
"insecure_skip_tls_verify": &hcldec.AttrSpec{Name: "insecure_skip_tls_verify", Type: cty.Bool, Required: false},
"mfa_code": &hcldec.AttrSpec{Name: "mfa_code", Type: cty.String, Required: false},
"profile": &hcldec.AttrSpec{Name: "profile", Type: cty.String, Required: false},
"region": &hcldec.AttrSpec{Name: "region", Type: cty.String, Required: false},
"secret_key": &hcldec.AttrSpec{Name: "secret_key", Type: cty.String, Required: false},
"skip_region_validation": &hcldec.AttrSpec{Name: "skip_region_validation", Type: cty.Bool, Required: false},
"skip_metadata_api_check": &hcldec.AttrSpec{Name: "skip_metadata_api_check", Type: cty.Bool, Required: false},
"token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false},
"vault_aws_engine": &hcldec.BlockSpec{TypeName: "vault_aws_engine", Nested: hcldec.ObjectSpec((*common.FlatVaultAWSEngineOptions)(nil).HCL2Spec())},
"ami_name": &hcldec.AttrSpec{Name: "ami_name", Type: cty.String, Required: false},
"ami_description": &hcldec.AttrSpec{Name: "ami_description", Type: cty.String, Required: false},
"ami_virtualization_type": &hcldec.AttrSpec{Name: "ami_virtualization_type", Type: cty.String, Required: false},
"ami_users": &hcldec.AttrSpec{Name: "ami_users", Type: cty.List(cty.String), Required: false},
"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},
"ena_support": &hcldec.AttrSpec{Name: "ena_support", Type: cty.Bool, Required: false},
"sriov_support": &hcldec.AttrSpec{Name: "sriov_support", Type: cty.Bool, 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},
"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},
"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_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},
"associate_public_ip_address": &hcldec.AttrSpec{Name: "associate_public_ip_address", Type: cty.Bool, Required: false},
"availability_zone": &hcldec.AttrSpec{Name: "availability_zone", Type: cty.String, Required: false},
"block_duration_minutes": &hcldec.AttrSpec{Name: "block_duration_minutes", Type: cty.Number, Required: false},
"disable_stop_instance": &hcldec.AttrSpec{Name: "disable_stop_instance", Type: cty.Bool, Required: false},
"ebs_optimized": &hcldec.AttrSpec{Name: "ebs_optimized", Type: cty.Bool, Required: false},
"enable_t2_unlimited": &hcldec.AttrSpec{Name: "enable_t2_unlimited", Type: cty.Bool, Required: false},
"iam_instance_profile": &hcldec.AttrSpec{Name: "iam_instance_profile", Type: cty.String, Required: false},
"skip_profile_validation": &hcldec.AttrSpec{Name: "skip_profile_validation", Type: cty.Bool, Required: false},
"temporary_iam_instance_profile_policy_document": &hcldec.BlockSpec{TypeName: "temporary_iam_instance_profile_policy_document", Nested: hcldec.ObjectSpec((*common.FlatPolicyDocument)(nil).HCL2Spec())},
"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},
"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_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())},
"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},
"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},
"temporary_security_group_source_cidrs": &hcldec.AttrSpec{Name: "temporary_security_group_source_cidrs", Type: cty.List(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},
"vpc_filter": &hcldec.BlockSpec{TypeName: "vpc_filter", Nested: hcldec.ObjectSpec((*common.FlatVpcFilterOptions)(nil).HCL2Spec())},
"vpc_id": &hcldec.AttrSpec{Name: "vpc_id", Type: cty.String, Required: false},
"windows_password_timeout": &hcldec.AttrSpec{Name: "windows_password_timeout", Type: 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},
"ssh_host": &hcldec.AttrSpec{Name: "ssh_host", Type: cty.String, Required: false},
"ssh_port": &hcldec.AttrSpec{Name: "ssh_port", Type: cty.Number, Required: false},
"ssh_username": &hcldec.AttrSpec{Name: "ssh_username", Type: cty.String, Required: false},
"ssh_password": &hcldec.AttrSpec{Name: "ssh_password", Type: cty.String, Required: false},
"ssh_keypair_name": &hcldec.AttrSpec{Name: "ssh_keypair_name", Type: cty.String, Required: false},
"ssh_clear_authorized_keys": &hcldec.AttrSpec{Name: "ssh_clear_authorized_keys", Type: cty.Bool, Required: false},
"ssh_private_key_file": &hcldec.AttrSpec{Name: "ssh_private_key_file", Type: cty.String, Required: false},
"ssh_pty": &hcldec.AttrSpec{Name: "ssh_pty", Type: cty.Bool, Required: false},
"ssh_timeout": &hcldec.AttrSpec{Name: "ssh_timeout", Type: cty.String, Required: false},
"ssh_agent_auth": &hcldec.AttrSpec{Name: "ssh_agent_auth", Type: cty.Bool, Required: false},
"ssh_disable_agent_forwarding": &hcldec.AttrSpec{Name: "ssh_disable_agent_forwarding", Type: cty.Bool, Required: false},
"ssh_handshake_attempts": &hcldec.AttrSpec{Name: "ssh_handshake_attempts", Type: cty.Number, Required: false},
"ssh_bastion_host": &hcldec.AttrSpec{Name: "ssh_bastion_host", Type: cty.String, Required: false},
"ssh_bastion_port": &hcldec.AttrSpec{Name: "ssh_bastion_port", Type: cty.Number, Required: false},
"ssh_bastion_agent_auth": &hcldec.AttrSpec{Name: "ssh_bastion_agent_auth", Type: cty.Bool, Required: false},
"ssh_bastion_username": &hcldec.AttrSpec{Name: "ssh_bastion_username", Type: cty.String, Required: false},
"ssh_bastion_password": &hcldec.AttrSpec{Name: "ssh_bastion_password", Type: cty.String, Required: false},
"ssh_bastion_private_key_file": &hcldec.AttrSpec{Name: "ssh_bastion_private_key_file", Type: cty.String, Required: false},
"ssh_file_transfer_method": &hcldec.AttrSpec{Name: "ssh_file_transfer_method", Type: cty.String, Required: false},
"ssh_proxy_host": &hcldec.AttrSpec{Name: "ssh_proxy_host", Type: cty.String, Required: false},
"ssh_proxy_port": &hcldec.AttrSpec{Name: "ssh_proxy_port", Type: cty.Number, Required: false},
"ssh_proxy_username": &hcldec.AttrSpec{Name: "ssh_proxy_username", Type: cty.String, Required: false},
"ssh_proxy_password": &hcldec.AttrSpec{Name: "ssh_proxy_password", Type: cty.String, Required: false},
"ssh_keep_alive_interval": &hcldec.AttrSpec{Name: "ssh_keep_alive_interval", Type: cty.String, Required: false},
"ssh_read_write_timeout": &hcldec.AttrSpec{Name: "ssh_read_write_timeout", Type: cty.String, Required: false},
"ssh_remote_tunnels": &hcldec.AttrSpec{Name: "ssh_remote_tunnels", Type: cty.List(cty.String), Required: false},
"ssh_local_tunnels": &hcldec.AttrSpec{Name: "ssh_local_tunnels", Type: cty.List(cty.String), Required: false},
"ssh_public_key": &hcldec.AttrSpec{Name: "ssh_public_key", Type: cty.List(cty.Number), Required: false},
"ssh_private_key": &hcldec.AttrSpec{Name: "ssh_private_key", Type: cty.List(cty.Number), Required: false},
"winrm_username": &hcldec.AttrSpec{Name: "winrm_username", Type: cty.String, Required: false},
"winrm_password": &hcldec.AttrSpec{Name: "winrm_password", Type: cty.String, Required: false},
"winrm_host": &hcldec.AttrSpec{Name: "winrm_host", Type: cty.String, Required: false},
"winrm_port": &hcldec.AttrSpec{Name: "winrm_port", Type: cty.Number, Required: false},
"winrm_timeout": &hcldec.AttrSpec{Name: "winrm_timeout", Type: cty.String, Required: false},
"winrm_use_ssl": &hcldec.AttrSpec{Name: "winrm_use_ssl", Type: cty.Bool, Required: false},
"winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false},
"winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false},
"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())},
"account_id": &hcldec.AttrSpec{Name: "account_id", Type: cty.String, Required: false},
"bundle_destination": &hcldec.AttrSpec{Name: "bundle_destination", Type: cty.String, Required: false},
"bundle_prefix": &hcldec.AttrSpec{Name: "bundle_prefix", Type: cty.String, Required: false},
"bundle_upload_command": &hcldec.AttrSpec{Name: "bundle_upload_command", Type: cty.String, Required: false},
"bundle_vol_command": &hcldec.AttrSpec{Name: "bundle_vol_command", Type: cty.String, Required: false},
"s3_bucket": &hcldec.AttrSpec{Name: "s3_bucket", Type: cty.String, Required: false},
"x509_cert_path": &hcldec.AttrSpec{Name: "x509_cert_path", Type: cty.String, Required: false},
"x509_key_path": &hcldec.AttrSpec{Name: "x509_key_path", Type: cty.String, Required: false},
"x509_upload_path": &hcldec.AttrSpec{Name: "x509_upload_path", Type: cty.String, Required: false},
}
return s
}

View File

@ -47,7 +47,7 @@ func TestBuilderPrepare_AccountId(t *testing.T) {
defer tempfile.Close() defer tempfile.Close()
config["account_id"] = "" config["account_id"] = ""
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -56,7 +56,7 @@ func TestBuilderPrepare_AccountId(t *testing.T) {
} }
config["account_id"] = "foo" config["account_id"] = "foo"
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -65,7 +65,7 @@ func TestBuilderPrepare_AccountId(t *testing.T) {
} }
config["account_id"] = "0123-0456-7890" config["account_id"] = "0123-0456-7890"
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -87,7 +87,7 @@ func TestBuilderPrepare_AMIName(t *testing.T) {
// Test good // Test good
config["ami_name"] = "foo" config["ami_name"] = "foo"
config["skip_region_validation"] = true config["skip_region_validation"] = true
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -98,7 +98,7 @@ func TestBuilderPrepare_AMIName(t *testing.T) {
// Test bad // Test bad
config["ami_name"] = "foo {{" config["ami_name"] = "foo {{"
b = Builder{} b = Builder{}
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -109,7 +109,7 @@ func TestBuilderPrepare_AMIName(t *testing.T) {
// Test bad // Test bad
delete(config, "ami_name") delete(config, "ami_name")
b = Builder{} b = Builder{}
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -126,7 +126,7 @@ func TestBuilderPrepare_BundleDestination(t *testing.T) {
defer tempfile.Close() defer tempfile.Close()
config["bundle_destination"] = "" config["bundle_destination"] = ""
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -146,7 +146,7 @@ func TestBuilderPrepare_BundlePrefix(t *testing.T) {
defer os.Remove(tempfile.Name()) defer os.Remove(tempfile.Name())
defer tempfile.Close() defer tempfile.Close()
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -167,7 +167,7 @@ func TestBuilderPrepare_InvalidKey(t *testing.T) {
// Add a random key // Add a random key
config["i_should_not_be_valid"] = true config["i_should_not_be_valid"] = true
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -184,7 +184,7 @@ func TestBuilderPrepare_S3Bucket(t *testing.T) {
defer tempfile.Close() defer tempfile.Close()
config["s3_bucket"] = "" config["s3_bucket"] = ""
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -193,7 +193,7 @@ func TestBuilderPrepare_S3Bucket(t *testing.T) {
} }
config["s3_bucket"] = "foo" config["s3_bucket"] = "foo"
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -210,7 +210,7 @@ func TestBuilderPrepare_X509CertPath(t *testing.T) {
defer tempfile.Close() defer tempfile.Close()
config["x509_cert_path"] = "" config["x509_cert_path"] = ""
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -219,7 +219,7 @@ func TestBuilderPrepare_X509CertPath(t *testing.T) {
} }
config["x509_cert_path"] = "i/am/a/file/that/doesnt/exist" config["x509_cert_path"] = "i/am/a/file/that/doesnt/exist"
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -235,7 +235,7 @@ func TestBuilderPrepare_X509CertPath(t *testing.T) {
defer tf.Close() defer tf.Close()
config["x509_cert_path"] = tf.Name() config["x509_cert_path"] = tf.Name()
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -252,7 +252,7 @@ func TestBuilderPrepare_X509KeyPath(t *testing.T) {
defer tempfile.Close() defer tempfile.Close()
config["x509_key_path"] = "" config["x509_key_path"] = ""
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -261,7 +261,7 @@ func TestBuilderPrepare_X509KeyPath(t *testing.T) {
} }
config["x509_key_path"] = "i/am/a/file/that/doesnt/exist" config["x509_key_path"] = "i/am/a/file/that/doesnt/exist"
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -277,7 +277,7 @@ func TestBuilderPrepare_X509KeyPath(t *testing.T) {
defer tf.Close() defer tf.Close()
config["x509_key_path"] = tf.Name() config["x509_key_path"] = tf.Name()
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -294,7 +294,7 @@ func TestBuilderPrepare_X509UploadPath(t *testing.T) {
defer tempfile.Close() defer tempfile.Close()
config["x509_upload_path"] = "" config["x509_upload_path"] = ""
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }

View File

@ -237,7 +237,7 @@ func NewAzureClient(subscriptionID, resourceGroupName, storageAccountName string
azureClient.GalleryImagesClient.RequestInspector = withInspection(maxlen) azureClient.GalleryImagesClient.RequestInspector = withInspection(maxlen)
azureClient.GalleryImagesClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) azureClient.GalleryImagesClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient))
azureClient.GalleryImagesClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(), azureClient.GalleryImagesClient.UserAgent) azureClient.GalleryImagesClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(), azureClient.GalleryImagesClient.UserAgent)
azureClient.GalleryImageVersionsClient.Client.PollingDuration = PollingDuration azureClient.GalleryImagesClient.Client.PollingDuration = PollingDuration
keyVaultURL, err := url.Parse(cloud.KeyVaultEndpoint) keyVaultURL, err := url.Parse(cloud.KeyVaultEndpoint)
if err != nil { if err != nil {

View File

@ -14,6 +14,7 @@ import (
"github.com/Azure/azure-sdk-for-go/storage" "github.com/Azure/azure-sdk-for-go/storage"
"github.com/Azure/go-autorest/autorest/adal" "github.com/Azure/go-autorest/autorest/adal"
"github.com/dgrijalva/jwt-go" "github.com/dgrijalva/jwt-go"
"github.com/hashicorp/hcl/v2/hcldec"
packerAzureCommon "github.com/hashicorp/packer/builder/azure/common" packerAzureCommon "github.com/hashicorp/packer/builder/azure/common"
"github.com/hashicorp/packer/builder/azure/common/constants" "github.com/hashicorp/packer/builder/azure/common/constants"
"github.com/hashicorp/packer/builder/azure/common/lin" "github.com/hashicorp/packer/builder/azure/common/lin"
@ -24,7 +25,7 @@ import (
) )
type Builder struct { type Builder struct {
config *Config config Config
stateBag multistep.StateBag stateBag multistep.StateBag
runner multistep.Runner runner multistep.Runner
} }
@ -34,20 +35,20 @@ const (
DefaultSecretName = "packerKeyVaultSecret" DefaultSecretName = "packerKeyVaultSecret"
) )
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() }
c, warnings, errs := newConfig(raws...)
if errs != nil {
return warnings, errs
}
b.config = c func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
warnings, errs := b.config.Prepare(raws...)
if errs != nil {
return nil, warnings, errs
}
b.stateBag = new(multistep.BasicStateBag) b.stateBag = new(multistep.BasicStateBag)
b.configureStateBag(b.stateBag) b.configureStateBag(b.stateBag)
b.setTemplateParameters(b.stateBag) b.setTemplateParameters(b.stateBag)
b.setImageParameters(b.stateBag) b.setImageParameters(b.stateBag)
return warnings, errs return nil, warnings, errs
} }
func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) { func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) {
@ -64,7 +65,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
} }
log.Print(":: Configuration") log.Print(":: Configuration")
packerAzureCommon.DumpConfig(b.config, func(s string) { log.Print(s) }) packerAzureCommon.DumpConfig(&b.config, func(s string) { log.Print(s) })
b.stateBag.Put("hook", hook) b.stateBag.Put("hook", hook)
b.stateBag.Put(constants.Ui, ui) b.stateBag.Put(constants.Ui, ui)
@ -90,7 +91,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
} }
resolver := newResourceResolver(azureClient) resolver := newResourceResolver(azureClient)
if err := resolver.Resolve(b.config); err != nil { if err := resolver.Resolve(&b.config); err != nil {
return nil, err return nil, err
} }
if b.config.ClientConfig.ObjectID == "" { if b.config.ClientConfig.ObjectID == "" {
@ -197,8 +198,8 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
if b.config.OSType == constants.Target_Linux { if b.config.OSType == constants.Target_Linux {
steps = []multistep.Step{ steps = []multistep.Step{
NewStepCreateResourceGroup(azureClient, ui), NewStepCreateResourceGroup(azureClient, ui),
NewStepValidateTemplate(azureClient, ui, b.config, GetVirtualMachineDeployment), NewStepValidateTemplate(azureClient, ui, &b.config, GetVirtualMachineDeployment),
NewStepDeployTemplate(azureClient, ui, b.config, deploymentName, GetVirtualMachineDeployment), NewStepDeployTemplate(azureClient, ui, &b.config, deploymentName, GetVirtualMachineDeployment),
NewStepGetIPAddress(azureClient, ui, endpointConnectType), NewStepGetIPAddress(azureClient, ui, endpointConnectType),
&communicator.StepConnectSSH{ &communicator.StepConnectSSH{
Config: &b.config.Comm, Config: &b.config.Comm,
@ -212,10 +213,10 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
NewStepGetOSDisk(azureClient, ui), NewStepGetOSDisk(azureClient, ui),
NewStepGetAdditionalDisks(azureClient, ui), NewStepGetAdditionalDisks(azureClient, ui),
NewStepPowerOffCompute(azureClient, ui), NewStepPowerOffCompute(azureClient, ui),
NewStepSnapshotOSDisk(azureClient, ui, b.config), NewStepSnapshotOSDisk(azureClient, ui, &b.config),
NewStepSnapshotDataDisks(azureClient, ui, b.config), NewStepSnapshotDataDisks(azureClient, ui, &b.config),
NewStepCaptureImage(azureClient, ui), NewStepCaptureImage(azureClient, ui),
NewStepPublishToSharedImageGallery(azureClient, ui, b.config), NewStepPublishToSharedImageGallery(azureClient, ui, &b.config),
NewStepDeleteResourceGroup(azureClient, ui), NewStepDeleteResourceGroup(azureClient, ui),
NewStepDeleteOSDisk(azureClient, ui), NewStepDeleteOSDisk(azureClient, ui),
NewStepDeleteAdditionalDisks(azureClient, ui), NewStepDeleteAdditionalDisks(azureClient, ui),
@ -224,17 +225,13 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
keyVaultDeploymentName := b.stateBag.Get(constants.ArmKeyVaultDeploymentName).(string) keyVaultDeploymentName := b.stateBag.Get(constants.ArmKeyVaultDeploymentName).(string)
steps = []multistep.Step{ steps = []multistep.Step{
NewStepCreateResourceGroup(azureClient, ui), NewStepCreateResourceGroup(azureClient, ui),
NewStepValidateTemplate(azureClient, ui, b.config, GetKeyVaultDeployment), NewStepValidateTemplate(azureClient, ui, &b.config, GetKeyVaultDeployment),
NewStepDeployTemplate(azureClient, ui, b.config, keyVaultDeploymentName, GetKeyVaultDeployment), NewStepDeployTemplate(azureClient, ui, &b.config, keyVaultDeploymentName, GetKeyVaultDeployment),
NewStepGetCertificate(azureClient, ui), NewStepGetCertificate(azureClient, ui),
NewStepSetCertificate(b.config, ui), NewStepSetCertificate(&b.config, ui),
NewStepValidateTemplate(azureClient, ui, b.config, GetVirtualMachineDeployment), NewStepValidateTemplate(azureClient, ui, &b.config, GetVirtualMachineDeployment),
NewStepDeployTemplate(azureClient, ui, b.config, deploymentName, GetVirtualMachineDeployment), NewStepDeployTemplate(azureClient, ui, &b.config, deploymentName, GetVirtualMachineDeployment),
NewStepGetIPAddress(azureClient, ui, endpointConnectType), NewStepGetIPAddress(azureClient, ui, endpointConnectType),
&StepSaveWinRMPassword{
Password: b.config.tmpAdminPassword,
BuildName: b.config.PackerBuildName,
},
&communicator.StepConnectWinRM{ &communicator.StepConnectWinRM{
Config: &b.config.Comm, Config: &b.config.Comm,
Host: func(stateBag multistep.StateBag) (string, error) { Host: func(stateBag multistep.StateBag) (string, error) {
@ -251,10 +248,10 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
NewStepGetOSDisk(azureClient, ui), NewStepGetOSDisk(azureClient, ui),
NewStepGetAdditionalDisks(azureClient, ui), NewStepGetAdditionalDisks(azureClient, ui),
NewStepPowerOffCompute(azureClient, ui), NewStepPowerOffCompute(azureClient, ui),
NewStepSnapshotOSDisk(azureClient, ui, b.config), NewStepSnapshotOSDisk(azureClient, ui, &b.config),
NewStepSnapshotDataDisks(azureClient, ui, b.config), NewStepSnapshotDataDisks(azureClient, ui, &b.config),
NewStepCaptureImage(azureClient, ui), NewStepCaptureImage(azureClient, ui),
NewStepPublishToSharedImageGallery(azureClient, ui, b.config), NewStepPublishToSharedImageGallery(azureClient, ui, &b.config),
NewStepDeleteResourceGroup(azureClient, ui), NewStepDeleteResourceGroup(azureClient, ui),
NewStepDeleteOSDisk(azureClient, ui), NewStepDeleteOSDisk(azureClient, ui),
NewStepDeleteAdditionalDisks(azureClient, ui), NewStepDeleteAdditionalDisks(azureClient, ui),
@ -398,6 +395,9 @@ func (b *Builder) configureStateBag(stateBag multistep.StateBag) {
stateBag.Put(constants.ArmManagedImageSharedGalleryImageName, b.config.SharedGalleryDestination.SigDestinationImageName) stateBag.Put(constants.ArmManagedImageSharedGalleryImageName, b.config.SharedGalleryDestination.SigDestinationImageName)
stateBag.Put(constants.ArmManagedImageSharedGalleryImageVersion, b.config.SharedGalleryDestination.SigDestinationImageVersion) stateBag.Put(constants.ArmManagedImageSharedGalleryImageVersion, b.config.SharedGalleryDestination.SigDestinationImageVersion)
stateBag.Put(constants.ArmManagedImageSubscription, b.config.ClientConfig.SubscriptionID) stateBag.Put(constants.ArmManagedImageSubscription, b.config.ClientConfig.SubscriptionID)
stateBag.Put(constants.ArmManagedImageSharedGalleryImageVersionEndOfLifeDate, b.config.SharedGalleryImageVersionEndOfLifeDate)
stateBag.Put(constants.ArmManagedImageSharedGalleryImageVersionReplicaCount, b.config.SharedGalleryImageVersionReplicaCount)
stateBag.Put(constants.ArmManagedImageSharedGalleryImageVersionExcludeFromLatest, b.config.SharedGalleryImageVersionExcludeFromLatest)
} }
} }

View File

@ -7,8 +7,8 @@ import (
) )
func TestStateBagShouldBePopulatedExpectedValues(t *testing.T) { func TestStateBagShouldBePopulatedExpectedValues(t *testing.T) {
var testSubject = &Builder{} var testSubject Builder
_, err := testSubject.Prepare(getArmBuilderConfiguration(), getPackerConfiguration()) _, _, err := testSubject.Prepare(getArmBuilderConfiguration(), getPackerConfiguration())
if err != nil { if err != nil {
t.Fatalf("failed to prepare: %s", err) t.Fatalf("failed to prepare: %s", err)
} }

View File

@ -27,7 +27,6 @@ import (
"github.com/hashicorp/packer/builder/azure/common/constants" "github.com/hashicorp/packer/builder/azure/common/constants"
"github.com/hashicorp/packer/builder/azure/pkcs12" "github.com/hashicorp/packer/builder/azure/pkcs12"
"github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common"
commonhelper "github.com/hashicorp/packer/helper/common"
"github.com/hashicorp/packer/helper/communicator" "github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/config" "github.com/hashicorp/packer/helper/config"
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"
@ -120,8 +119,6 @@ type Config struct {
// //
// Following is an example. // Following is an example.
// //
// <!-- -->
//
// "shared_image_gallery_destination": { // "shared_image_gallery_destination": {
// "resource_group": "ResourceGroup", // "resource_group": "ResourceGroup",
// "gallery_name": "GalleryName", // "gallery_name": "GalleryName",
@ -140,6 +137,16 @@ type Config struct {
// its default of "60m" (valid time units include `s` for seconds, `m` for // its default of "60m" (valid time units include `s` for seconds, `m` for
// minutes, and `h` for hours.) // minutes, and `h` for hours.)
SharedGalleryTimeout time.Duration `mapstructure:"shared_image_gallery_timeout"` SharedGalleryTimeout time.Duration `mapstructure:"shared_image_gallery_timeout"`
// The end of life date (2006-01-02T15:04:05.99Z) of the gallery Image Version. This property
// can be used for decommissioning purposes.
SharedGalleryImageVersionEndOfLifeDate string `mapstructure:"shared_gallery_image_version_end_of_life_date" required:"false"`
// The number of replicas of the Image Version to be created per region. This
// property would take effect for a region when regionalReplicaCount is not specified.
// Replica count must be between 1 and 10.
SharedGalleryImageVersionReplicaCount int32 `mapstructure:"shared_image_gallery_replica_count" required:"false"`
// If set to true, Virtual Machines deployed from the latest version of the
// Image Definition won't use this Image Version.
SharedGalleryImageVersionExcludeFromLatest bool `mapstructure:"shared_gallery_image_version_exclude_from_latest" required:"false"`
// PublisherName for your base image. See // PublisherName for your base image. See
// [documentation](https://azure.microsoft.com/en-us/documentation/articles/resource-groups-vm-searching/) // [documentation](https://azure.microsoft.com/en-us/documentation/articles/resource-groups-vm-searching/)
// for details. // for details.
@ -495,58 +502,57 @@ func (c *Config) createCertificate() (string, error) {
return base64.StdEncoding.EncodeToString(bytes), nil return base64.StdEncoding.EncodeToString(bytes), nil
} }
func newConfig(raws ...interface{}) (*Config, []string, error) { func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
var c Config
c.ctx.Funcs = azcommon.TemplateFuncs c.ctx.Funcs = azcommon.TemplateFuncs
err := config.Decode(&c, &config.DecodeOpts{ err := config.Decode(c, &config.DecodeOpts{
Interpolate: true, Interpolate: true,
InterpolateContext: &c.ctx, InterpolateContext: &c.ctx,
}, raws...) }, raws...)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
provideDefaultValues(&c) provideDefaultValues(c)
setRuntimeValues(&c) setRuntimeValues(c)
setUserNamePassword(&c) setUserNamePassword(c)
err = c.ClientConfig.SetDefaultValues() err = c.ClientConfig.SetDefaultValues()
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
err = setCustomData(&c) err = setCustomData(c)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
// NOTE: if the user did not specify a communicator, then default to both // NOTE: if the user did not specify a communicator, then default to both
// SSH and WinRM. This is for backwards compatibility because the code did // SSH and WinRM. This is for backwards compatibility because the code did
// not specifically force the user to set a communicator. // not specifically force the user to set a communicator.
if c.Comm.Type == "" || strings.EqualFold(c.Comm.Type, "ssh") { if c.Comm.Type == "" || strings.EqualFold(c.Comm.Type, "ssh") {
err = setSshValues(&c) err = setSshValues(c)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
} }
if c.Comm.Type == "" || strings.EqualFold(c.Comm.Type, "winrm") { if c.Comm.Type == "" || strings.EqualFold(c.Comm.Type, "winrm") {
err = setWinRMCertificate(&c) err = setWinRMCertificate(c)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
} }
var errs *packer.MultiError var errs *packer.MultiError
errs = packer.MultiErrorAppend(errs, c.Comm.Prepare(&c.ctx)...) errs = packer.MultiErrorAppend(errs, c.Comm.Prepare(&c.ctx)...)
assertRequiredParametersSet(&c, errs) assertRequiredParametersSet(c, errs)
assertTagProperties(&c, errs) assertTagProperties(c, errs)
if errs != nil && len(errs.Errors) > 0 { if errs != nil && len(errs.Errors) > 0 {
return nil, nil, errs return nil, errs
} }
return &c, nil, nil return nil, nil
} }
func setSshValues(c *Config) error { func setSshValues(c *Config) error {
@ -601,7 +607,6 @@ func setRuntimeValues(c *Config) {
c.tmpAdminPassword = tempName.AdminPassword c.tmpAdminPassword = tempName.AdminPassword
// store so that we can access this later during provisioning // store so that we can access this later during provisioning
commonhelper.SetSharedState("winrm_password", c.tmpAdminPassword, c.PackerConfig.PackerBuildName)
packer.LogSecretFilter.Set(c.tmpAdminPassword) packer.LogSecretFilter.Set(c.tmpAdminPassword)
c.tmpCertificatePassword = tempName.CertificatePassword c.tmpCertificatePassword = tempName.CertificatePassword

View File

@ -9,138 +9,147 @@ import (
// FlatConfig is an auto-generated flat version of Config. // FlatConfig is an auto-generated flat version of Config.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. // Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatConfig struct { type FlatConfig struct {
PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name"` PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name"`
PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type"` PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type"`
PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug"` PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug"`
PackerForce *bool `mapstructure:"packer_force" cty:"packer_force"` PackerForce *bool `mapstructure:"packer_force" cty:"packer_force"`
PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error"` PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error"`
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables"` PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables"`
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables"` PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables"`
CloudEnvironmentName *string `mapstructure:"cloud_environment_name" required:"false" cty:"cloud_environment_name"` CloudEnvironmentName *string `mapstructure:"cloud_environment_name" required:"false" cty:"cloud_environment_name"`
ClientID *string `mapstructure:"client_id" cty:"client_id"` ClientID *string `mapstructure:"client_id" cty:"client_id"`
ClientSecret *string `mapstructure:"client_secret" cty:"client_secret"` ClientSecret *string `mapstructure:"client_secret" cty:"client_secret"`
ClientCertPath *string `mapstructure:"client_cert_path" cty:"client_cert_path"` ClientCertPath *string `mapstructure:"client_cert_path" cty:"client_cert_path"`
ClientJWT *string `mapstructure:"client_jwt" cty:"client_jwt"` ClientJWT *string `mapstructure:"client_jwt" cty:"client_jwt"`
ObjectID *string `mapstructure:"object_id" cty:"object_id"` ObjectID *string `mapstructure:"object_id" cty:"object_id"`
TenantID *string `mapstructure:"tenant_id" required:"false" cty:"tenant_id"` TenantID *string `mapstructure:"tenant_id" required:"false" cty:"tenant_id"`
SubscriptionID *string `mapstructure:"subscription_id" cty:"subscription_id"` SubscriptionID *string `mapstructure:"subscription_id" cty:"subscription_id"`
CaptureNamePrefix *string `mapstructure:"capture_name_prefix" cty:"capture_name_prefix"` CaptureNamePrefix *string `mapstructure:"capture_name_prefix" cty:"capture_name_prefix"`
CaptureContainerName *string `mapstructure:"capture_container_name" cty:"capture_container_name"` CaptureContainerName *string `mapstructure:"capture_container_name" cty:"capture_container_name"`
SharedGallery *FlatSharedImageGallery `mapstructure:"shared_image_gallery" required:"false" cty:"shared_image_gallery"` SharedGallery *FlatSharedImageGallery `mapstructure:"shared_image_gallery" required:"false" cty:"shared_image_gallery"`
SharedGalleryDestination *FlatSharedImageGalleryDestination `mapstructure:"shared_image_gallery_destination" cty:"shared_image_gallery_destination"` SharedGalleryDestination *FlatSharedImageGalleryDestination `mapstructure:"shared_image_gallery_destination" cty:"shared_image_gallery_destination"`
SharedGalleryTimeout *string `mapstructure:"shared_image_gallery_timeout" cty:"shared_image_gallery_timeout"` SharedGalleryTimeout *string `mapstructure:"shared_image_gallery_timeout" cty:"shared_image_gallery_timeout"`
ImagePublisher *string `mapstructure:"image_publisher" required:"true" cty:"image_publisher"` SharedGalleryImageVersionEndOfLifeDate *string `mapstructure:"shared_gallery_image_version_end_of_life_date" required:"false" cty:"shared_gallery_image_version_end_of_life_date"`
ImageOffer *string `mapstructure:"image_offer" required:"true" cty:"image_offer"` SharedGalleryImageVersionReplicaCount *int32 `mapstructure:"shared_image_gallery_replica_count" required:"false" cty:"shared_image_gallery_replica_count"`
ImageSku *string `mapstructure:"image_sku" required:"true" cty:"image_sku"` SharedGalleryImageVersionExcludeFromLatest *bool `mapstructure:"shared_gallery_image_version_exclude_from_latest" required:"false" cty:"shared_gallery_image_version_exclude_from_latest"`
ImageVersion *string `mapstructure:"image_version" required:"false" cty:"image_version"` ImagePublisher *string `mapstructure:"image_publisher" required:"true" cty:"image_publisher"`
ImageUrl *string `mapstructure:"image_url" required:"false" cty:"image_url"` ImageOffer *string `mapstructure:"image_offer" required:"true" cty:"image_offer"`
CustomManagedImageResourceGroupName *string `mapstructure:"custom_managed_image_resource_group_name" required:"false" cty:"custom_managed_image_resource_group_name"` ImageSku *string `mapstructure:"image_sku" required:"true" cty:"image_sku"`
CustomManagedImageName *string `mapstructure:"custom_managed_image_name" required:"false" cty:"custom_managed_image_name"` ImageVersion *string `mapstructure:"image_version" required:"false" cty:"image_version"`
Location *string `mapstructure:"location" cty:"location"` ImageUrl *string `mapstructure:"image_url" required:"false" cty:"image_url"`
VMSize *string `mapstructure:"vm_size" required:"false" cty:"vm_size"` CustomManagedImageResourceGroupName *string `mapstructure:"custom_managed_image_resource_group_name" required:"false" cty:"custom_managed_image_resource_group_name"`
ManagedImageResourceGroupName *string `mapstructure:"managed_image_resource_group_name" cty:"managed_image_resource_group_name"` CustomManagedImageName *string `mapstructure:"custom_managed_image_name" required:"false" cty:"custom_managed_image_name"`
ManagedImageName *string `mapstructure:"managed_image_name" cty:"managed_image_name"` Location *string `mapstructure:"location" cty:"location"`
ManagedImageStorageAccountType *string `mapstructure:"managed_image_storage_account_type" required:"false" cty:"managed_image_storage_account_type"` VMSize *string `mapstructure:"vm_size" required:"false" cty:"vm_size"`
ManagedImageOSDiskSnapshotName *string `mapstructure:"managed_image_os_disk_snapshot_name" required:"false" cty:"managed_image_os_disk_snapshot_name"` ManagedImageResourceGroupName *string `mapstructure:"managed_image_resource_group_name" cty:"managed_image_resource_group_name"`
ManagedImageDataDiskSnapshotPrefix *string `mapstructure:"managed_image_data_disk_snapshot_prefix" required:"false" cty:"managed_image_data_disk_snapshot_prefix"` ManagedImageName *string `mapstructure:"managed_image_name" cty:"managed_image_name"`
ManagedImageZoneResilient *bool `mapstructure:"managed_image_zone_resilient" required:"false" cty:"managed_image_zone_resilient"` ManagedImageStorageAccountType *string `mapstructure:"managed_image_storage_account_type" required:"false" cty:"managed_image_storage_account_type"`
AzureTags map[string]*string `mapstructure:"azure_tags" required:"false" cty:"azure_tags"` ManagedImageOSDiskSnapshotName *string `mapstructure:"managed_image_os_disk_snapshot_name" required:"false" cty:"managed_image_os_disk_snapshot_name"`
ResourceGroupName *string `mapstructure:"resource_group_name" cty:"resource_group_name"` ManagedImageDataDiskSnapshotPrefix *string `mapstructure:"managed_image_data_disk_snapshot_prefix" required:"false" cty:"managed_image_data_disk_snapshot_prefix"`
StorageAccount *string `mapstructure:"storage_account" cty:"storage_account"` ManagedImageZoneResilient *bool `mapstructure:"managed_image_zone_resilient" required:"false" cty:"managed_image_zone_resilient"`
TempComputeName *string `mapstructure:"temp_compute_name" required:"false" cty:"temp_compute_name"` AzureTags map[string]*string `mapstructure:"azure_tags" required:"false" cty:"azure_tags"`
TempResourceGroupName *string `mapstructure:"temp_resource_group_name" cty:"temp_resource_group_name"` ResourceGroupName *string `mapstructure:"resource_group_name" cty:"resource_group_name"`
BuildResourceGroupName *string `mapstructure:"build_resource_group_name" cty:"build_resource_group_name"` StorageAccount *string `mapstructure:"storage_account" cty:"storage_account"`
PrivateVirtualNetworkWithPublicIp *bool `mapstructure:"private_virtual_network_with_public_ip" required:"false" cty:"private_virtual_network_with_public_ip"` TempComputeName *string `mapstructure:"temp_compute_name" required:"false" cty:"temp_compute_name"`
VirtualNetworkName *string `mapstructure:"virtual_network_name" required:"false" cty:"virtual_network_name"` TempResourceGroupName *string `mapstructure:"temp_resource_group_name" cty:"temp_resource_group_name"`
VirtualNetworkSubnetName *string `mapstructure:"virtual_network_subnet_name" required:"false" cty:"virtual_network_subnet_name"` BuildResourceGroupName *string `mapstructure:"build_resource_group_name" cty:"build_resource_group_name"`
VirtualNetworkResourceGroupName *string `mapstructure:"virtual_network_resource_group_name" required:"false" cty:"virtual_network_resource_group_name"` PrivateVirtualNetworkWithPublicIp *bool `mapstructure:"private_virtual_network_with_public_ip" required:"false" cty:"private_virtual_network_with_public_ip"`
CustomDataFile *string `mapstructure:"custom_data_file" required:"false" cty:"custom_data_file"` VirtualNetworkName *string `mapstructure:"virtual_network_name" required:"false" cty:"virtual_network_name"`
PlanInfo *FlatPlanInformation `mapstructure:"plan_info" required:"false" cty:"plan_info"` VirtualNetworkSubnetName *string `mapstructure:"virtual_network_subnet_name" required:"false" cty:"virtual_network_subnet_name"`
PollingDurationTimeout *string `mapstructure:"polling_duration_timeout" required:"false" cty:"polling_duration_timeout"` VirtualNetworkResourceGroupName *string `mapstructure:"virtual_network_resource_group_name" required:"false" cty:"virtual_network_resource_group_name"`
OSType *string `mapstructure:"os_type" required:"false" cty:"os_type"` CustomDataFile *string `mapstructure:"custom_data_file" required:"false" cty:"custom_data_file"`
OSDiskSizeGB *int32 `mapstructure:"os_disk_size_gb" required:"false" cty:"os_disk_size_gb"` PlanInfo *FlatPlanInformation `mapstructure:"plan_info" required:"false" cty:"plan_info"`
AdditionalDiskSize []int32 `mapstructure:"disk_additional_size" required:"false" cty:"disk_additional_size"` PollingDurationTimeout *string `mapstructure:"polling_duration_timeout" required:"false" cty:"polling_duration_timeout"`
DiskCachingType *string `mapstructure:"disk_caching_type" required:"false" cty:"disk_caching_type"` OSType *string `mapstructure:"os_type" required:"false" cty:"os_type"`
AllowedInboundIpAddresses []string `mapstructure:"allowed_inbound_ip_addresses" cty:"allowed_inbound_ip_addresses"` OSDiskSizeGB *int32 `mapstructure:"os_disk_size_gb" required:"false" cty:"os_disk_size_gb"`
UserName *string `cty:"user_name"` AdditionalDiskSize []int32 `mapstructure:"disk_additional_size" required:"false" cty:"disk_additional_size"`
Password *string `cty:"password"` DiskCachingType *string `mapstructure:"disk_caching_type" required:"false" cty:"disk_caching_type"`
Type *string `mapstructure:"communicator" cty:"communicator"` AllowedInboundIpAddresses []string `mapstructure:"allowed_inbound_ip_addresses" cty:"allowed_inbound_ip_addresses"`
PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting"` UserName *string `cty:"user_name"`
SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host"` Password *string `cty:"password"`
SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port"` Type *string `mapstructure:"communicator" cty:"communicator"`
SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username"` PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting"`
SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password"` SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host"`
SSHKeyPairName *string `mapstructure:"ssh_keypair_name" cty:"ssh_keypair_name"` SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port"`
SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" cty:"temporary_key_pair_name"` SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username"`
SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys"` SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password"`
SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" cty:"ssh_private_key_file"` SSHKeyPairName *string `mapstructure:"ssh_keypair_name" cty:"ssh_keypair_name"`
SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty"` SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" cty:"temporary_key_pair_name"`
SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout"` SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys"`
SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" cty:"ssh_agent_auth"` SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" cty:"ssh_private_key_file"`
SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding"` SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty"`
SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts"` SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout"`
SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host"` SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" cty:"ssh_agent_auth"`
SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port"` SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding"`
SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth"` SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts"`
SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username"` SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host"`
SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password"` SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port"`
SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file"` SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth"`
SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method"` SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username"`
SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host"` SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password"`
SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port"` SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file"`
SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username"` SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method"`
SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password"` SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host"`
SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval"` SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port"`
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"` SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username"`
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"` SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password"`
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"` SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval"`
SSHPublicKey []byte `cty:"ssh_public_key"` SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"`
SSHPrivateKey []byte `cty:"ssh_private_key"` SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"`
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"` SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"`
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"` SSHPublicKey []byte `mapstructure:"ssh_public_key" cty:"ssh_public_key"`
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"` SSHPrivateKey []byte `mapstructure:"ssh_private_key" cty:"ssh_private_key"`
WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port"` WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"`
WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout"` WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"`
WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl"` WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"`
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure"` WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port"`
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm"` WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout"`
AsyncResourceGroupDelete *bool `mapstructure:"async_resourcegroup_delete" required:"false" cty:"async_resourcegroup_delete"` WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl"`
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure"`
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm"`
AsyncResourceGroupDelete *bool `mapstructure:"async_resourcegroup_delete" required:"false" cty:"async_resourcegroup_delete"`
} }
// FlatMapstructure returns a new FlatConfig. // FlatMapstructure returns a new FlatConfig.
// FlatConfig is an auto-generated flat version of Config. // FlatConfig is an auto-generated flat version of Config.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*Config) FlatMapstructure() interface{} { return new(FlatConfig) } func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatConfig)
}
// HCL2Spec returns the hcldec.Spec of a FlatConfig. // HCL2Spec returns the hcl spec of a Config.
// This spec is used by HCL to read the fields of FlatConfig. // This spec is used by HCL to read the fields of Config.
// The decoded values from this spec will then be applied to a FlatConfig.
func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", 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_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_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", 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_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.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}, "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}, "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_id": &hcldec.AttrSpec{Name: "client_id", Type: cty.String, Required: false},
"client_secret": &hcldec.AttrSpec{Name: "client_secret", 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_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}, "client_jwt": &hcldec.AttrSpec{Name: "client_jwt", Type: cty.String, Required: false},
"object_id": &hcldec.AttrSpec{Name: "object_id", 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}, "tenant_id": &hcldec.AttrSpec{Name: "tenant_id", Type: cty.String, Required: false},
"subscription_id": &hcldec.AttrSpec{Name: "subscription_id", Type: cty.String, Required: false}, "subscription_id": &hcldec.AttrSpec{Name: "subscription_id", Type: cty.String, Required: false},
"capture_name_prefix": &hcldec.AttrSpec{Name: "capture_name_prefix", Type: cty.String, Required: false}, "capture_name_prefix": &hcldec.AttrSpec{Name: "capture_name_prefix", Type: cty.String, Required: false},
"capture_container_name": &hcldec.AttrSpec{Name: "capture_container_name", Type: cty.String, Required: false}, "capture_container_name": &hcldec.AttrSpec{Name: "capture_container_name", Type: cty.String, Required: false},
"shared_image_gallery": &hcldec.BlockSpec{TypeName: "shared_image_gallery", Nested: hcldec.ObjectSpec((*FlatSharedImageGallery)(nil).HCL2Spec())}, "shared_image_gallery": &hcldec.BlockSpec{TypeName: "shared_image_gallery", Nested: hcldec.ObjectSpec((*FlatSharedImageGallery)(nil).HCL2Spec())},
"shared_image_gallery_destination": &hcldec.BlockSpec{TypeName: "shared_image_gallery_destination", Nested: hcldec.ObjectSpec((*FlatSharedImageGalleryDestination)(nil).HCL2Spec())}, "shared_image_gallery_destination": &hcldec.BlockSpec{TypeName: "shared_image_gallery_destination", Nested: hcldec.ObjectSpec((*FlatSharedImageGalleryDestination)(nil).HCL2Spec())},
"shared_image_gallery_timeout": &hcldec.AttrSpec{Name: "shared_image_gallery_timeout", Type: cty.String, Required: false}, "shared_image_gallery_timeout": &hcldec.AttrSpec{Name: "shared_image_gallery_timeout", Type: cty.String, Required: false},
"image_publisher": &hcldec.AttrSpec{Name: "image_publisher", Type: cty.String, Required: false}, "shared_gallery_image_version_end_of_life_date": &hcldec.AttrSpec{Name: "shared_gallery_image_version_end_of_life_date", Type: cty.String, Required: false},
"image_offer": &hcldec.AttrSpec{Name: "image_offer", Type: cty.String, Required: false}, "shared_image_gallery_replica_count": &hcldec.AttrSpec{Name: "shared_image_gallery_replica_count", Type: cty.Number, Required: false},
"image_sku": &hcldec.AttrSpec{Name: "image_sku", Type: cty.String, Required: false}, "shared_gallery_image_version_exclude_from_latest": &hcldec.AttrSpec{Name: "shared_gallery_image_version_exclude_from_latest", Type: cty.Bool, Required: false},
"image_version": &hcldec.AttrSpec{Name: "image_version", Type: cty.String, Required: false}, "image_publisher": &hcldec.AttrSpec{Name: "image_publisher", Type: cty.String, Required: false},
"image_url": &hcldec.AttrSpec{Name: "image_url", Type: cty.String, Required: false}, "image_offer": &hcldec.AttrSpec{Name: "image_offer", Type: cty.String, Required: false},
"image_sku": &hcldec.AttrSpec{Name: "image_sku", Type: cty.String, Required: false},
"image_version": &hcldec.AttrSpec{Name: "image_version", Type: cty.String, Required: false},
"image_url": &hcldec.AttrSpec{Name: "image_url", Type: cty.String, Required: false},
"custom_managed_image_resource_group_name": &hcldec.AttrSpec{Name: "custom_managed_image_resource_group_name", Type: cty.String, Required: false}, "custom_managed_image_resource_group_name": &hcldec.AttrSpec{Name: "custom_managed_image_resource_group_name", Type: cty.String, Required: false},
"custom_managed_image_name": &hcldec.AttrSpec{Name: "custom_managed_image_name", Type: cty.String, Required: false}, "custom_managed_image_name": &hcldec.AttrSpec{Name: "custom_managed_image_name", Type: cty.String, Required: false},
"location": &hcldec.AttrSpec{Name: "location", Type: cty.String, Required: false}, "location": &hcldec.AttrSpec{Name: "location", Type: cty.String, Required: false},
@ -228,10 +237,13 @@ type FlatPlanInformation struct {
// FlatMapstructure returns a new FlatPlanInformation. // FlatMapstructure returns a new FlatPlanInformation.
// FlatPlanInformation is an auto-generated flat version of PlanInformation. // FlatPlanInformation is an auto-generated flat version of PlanInformation.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*PlanInformation) FlatMapstructure() interface{} { return new(FlatPlanInformation) } func (*PlanInformation) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatPlanInformation)
}
// HCL2Spec returns the hcldec.Spec of a FlatPlanInformation. // HCL2Spec returns the hcl spec of a PlanInformation.
// This spec is used by HCL to read the fields of FlatPlanInformation. // This spec is used by HCL to read the fields of PlanInformation.
// The decoded values from this spec will then be applied to a FlatPlanInformation.
func (*FlatPlanInformation) HCL2Spec() map[string]hcldec.Spec { func (*FlatPlanInformation) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"plan_name": &hcldec.AttrSpec{Name: "plan_name", Type: cty.String, Required: false}, "plan_name": &hcldec.AttrSpec{Name: "plan_name", Type: cty.String, Required: false},
@ -255,10 +267,13 @@ type FlatSharedImageGallery struct {
// FlatMapstructure returns a new FlatSharedImageGallery. // FlatMapstructure returns a new FlatSharedImageGallery.
// FlatSharedImageGallery is an auto-generated flat version of SharedImageGallery. // FlatSharedImageGallery is an auto-generated flat version of SharedImageGallery.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*SharedImageGallery) FlatMapstructure() interface{} { return new(FlatSharedImageGallery) } func (*SharedImageGallery) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatSharedImageGallery)
}
// HCL2Spec returns the hcldec.Spec of a FlatSharedImageGallery. // HCL2Spec returns the hcl spec of a SharedImageGallery.
// This spec is used by HCL to read the fields of FlatSharedImageGallery. // This spec is used by HCL to read the fields of SharedImageGallery.
// The decoded values from this spec will then be applied to a FlatSharedImageGallery.
func (*FlatSharedImageGallery) HCL2Spec() map[string]hcldec.Spec { func (*FlatSharedImageGallery) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"subscription": &hcldec.AttrSpec{Name: "subscription", Type: cty.String, Required: false}, "subscription": &hcldec.AttrSpec{Name: "subscription", Type: cty.String, Required: false},
@ -283,12 +298,13 @@ type FlatSharedImageGalleryDestination struct {
// FlatMapstructure returns a new FlatSharedImageGalleryDestination. // FlatMapstructure returns a new FlatSharedImageGalleryDestination.
// FlatSharedImageGalleryDestination is an auto-generated flat version of SharedImageGalleryDestination. // FlatSharedImageGalleryDestination is an auto-generated flat version of SharedImageGalleryDestination.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*SharedImageGalleryDestination) FlatMapstructure() interface{} { func (*SharedImageGalleryDestination) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatSharedImageGalleryDestination) return new(FlatSharedImageGalleryDestination)
} }
// HCL2Spec returns the hcldec.Spec of a FlatSharedImageGalleryDestination. // HCL2Spec returns the hcl spec of a SharedImageGalleryDestination.
// This spec is used by HCL to read the fields of FlatSharedImageGalleryDestination. // 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 { func (*FlatSharedImageGalleryDestination) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"resource_group": &hcldec.AttrSpec{Name: "resource_group", Type: cty.String, Required: false}, "resource_group": &hcldec.AttrSpec{Name: "resource_group", Type: cty.String, Required: false},

View File

@ -26,7 +26,8 @@ var requiredConfigValues = []string{
} }
func TestConfigShouldProvideReasonableDefaultValues(t *testing.T) { func TestConfigShouldProvideReasonableDefaultValues(t *testing.T) {
c, _, err := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) var c Config
_, err := c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration())
if err != nil { if err != nil {
t.Error("Expected configuration creation to succeed, but it failed!\n") t.Error("Expected configuration creation to succeed, but it failed!\n")
@ -63,7 +64,8 @@ func TestConfigShouldBeAbleToOverrideDefaultedValues(t *testing.T) {
builderValues["managed_image_storage_account_type"] = "Premium_LRS" builderValues["managed_image_storage_account_type"] = "Premium_LRS"
builderValues["disk_caching_type"] = "None" builderValues["disk_caching_type"] = "None"
c, _, err := newConfig(builderValues, getPackerConfiguration()) var c Config
_, err := c.Prepare(builderValues, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatalf("newConfig failed: %s", err) t.Fatalf("newConfig failed: %s", err)
@ -99,7 +101,8 @@ func TestConfigShouldBeAbleToOverrideDefaultedValues(t *testing.T) {
} }
func TestConfigShouldDefaultVMSizeToStandardA1(t *testing.T) { func TestConfigShouldDefaultVMSizeToStandardA1(t *testing.T) {
c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) var c Config
c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration())
if c.VMSize != "Standard_A1" { if c.VMSize != "Standard_A1" {
t.Errorf("Expected 'VMSize' to default to 'Standard_A1', but got '%s'.", c.VMSize) t.Errorf("Expected 'VMSize' to default to 'Standard_A1', but got '%s'.", c.VMSize)
@ -107,7 +110,8 @@ func TestConfigShouldDefaultVMSizeToStandardA1(t *testing.T) {
} }
func TestConfigShouldDefaultImageVersionToLatest(t *testing.T) { func TestConfigShouldDefaultImageVersionToLatest(t *testing.T) {
c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) var c Config
c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration())
if c.ImageVersion != "latest" { if c.ImageVersion != "latest" {
t.Errorf("Expected 'ImageVersion' to default to 'latest', but got '%s'.", c.ImageVersion) t.Errorf("Expected 'ImageVersion' to default to 'latest', but got '%s'.", c.ImageVersion)
@ -127,7 +131,8 @@ func TestConfigShouldNotDefaultImageVersionIfCustomImage(t *testing.T) {
"communicator": "none", "communicator": "none",
} }
c, _, _ := newConfig(config, getPackerConfiguration()) var c Config
c.Prepare(config, getPackerConfiguration())
if c.ImageVersion != "" { if c.ImageVersion != "" {
t.Errorf("Expected 'ImageVersion' to empty, but got '%s'.", c.ImageVersion) t.Errorf("Expected 'ImageVersion' to empty, but got '%s'.", c.ImageVersion)
} }
@ -153,7 +158,8 @@ func TestConfigShouldNormalizeOSTypeCase(t *testing.T) {
for k, v := range os_types { for k, v := range os_types {
for _, os_type := range v { for _, os_type := range v {
config["os_type"] = os_type config["os_type"] = os_type
c, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatalf("Expected config to accept the value %q, but it did not", os_type) t.Fatalf("Expected config to accept the value %q, but it did not", os_type)
} }
@ -167,7 +173,8 @@ func TestConfigShouldNormalizeOSTypeCase(t *testing.T) {
bad_os_types := []string{"", "does-not-exist"} bad_os_types := []string{"", "does-not-exist"}
for _, os_type := range bad_os_types { for _, os_type := range bad_os_types {
config["os_type"] = os_type config["os_type"] = os_type
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Fatalf("Expected config to not accept the value %q, but it did", os_type) t.Fatalf("Expected config to not accept the value %q, but it did", os_type)
} }
@ -191,7 +198,8 @@ func TestConfigShouldRejectCustomImageAndMarketPlace(t *testing.T) {
for _, x := range marketPlace { for _, x := range marketPlace {
config[x] = "ignore" config[x] = "ignore"
_, _, err := newConfig(config, packerConfiguration) var c Config
_, err := c.Prepare(config, packerConfiguration)
if err == nil { if err == nil {
t.Errorf("Expected Config to reject image_url and %s, but it did not", x) t.Errorf("Expected Config to reject image_url and %s, but it did not", x)
} }
@ -212,7 +220,8 @@ func TestConfigVirtualNetworkNameIsOptional(t *testing.T) {
"virtual_network_name": "MyVirtualNetwork", "virtual_network_name": "MyVirtualNetwork",
} }
c, _, _ := newConfig(config, getPackerConfiguration()) var c Config
c.Prepare(config, getPackerConfiguration())
if c.VirtualNetworkName != "MyVirtualNetwork" { if c.VirtualNetworkName != "MyVirtualNetwork" {
t.Errorf("Expected Config to set virtual_network_name to MyVirtualNetwork, but got %q", c.VirtualNetworkName) t.Errorf("Expected Config to set virtual_network_name to MyVirtualNetwork, but got %q", c.VirtualNetworkName)
} }
@ -241,7 +250,8 @@ func TestConfigVirtualNetworkResourceGroupNameMustBeSetWithVirtualNetworkName(t
"virtual_network_resource_group_name": "MyVirtualNetworkRG", "virtual_network_resource_group_name": "MyVirtualNetworkRG",
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Error("Expected Config to reject virtual_network_resource_group_name, if virtual_network_name is not set.") t.Error("Expected Config to reject virtual_network_resource_group_name, if virtual_network_name is not set.")
} }
@ -264,7 +274,8 @@ func TestConfigVirtualNetworkSubnetNameMustBeSetWithVirtualNetworkName(t *testin
"virtual_network_subnet_name": "MyVirtualNetworkRG", "virtual_network_subnet_name": "MyVirtualNetworkRG",
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Error("Expected Config to reject virtual_network_subnet_name, if virtual_network_name is not set.") t.Error("Expected Config to reject virtual_network_subnet_name, if virtual_network_name is not set.")
} }
@ -284,7 +295,8 @@ func TestConfigAllowedInboundIpAddressesIsOptional(t *testing.T) {
"virtual_network_name": "MyVirtualNetwork", "virtual_network_name": "MyVirtualNetwork",
} }
c, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -311,7 +323,8 @@ func TestConfigShouldAcceptCorrectInboundIpAddresses(t *testing.T) {
} }
config["allowed_inbound_ip_addresses"] = ipValue0 config["allowed_inbound_ip_addresses"] = ipValue0
c, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -321,7 +334,7 @@ func TestConfigShouldAcceptCorrectInboundIpAddresses(t *testing.T) {
} }
config["allowed_inbound_ip_addresses"] = cidrValue2 config["allowed_inbound_ip_addresses"] = cidrValue2
c, _, err = newConfig(config, getPackerConfiguration()) _, err = c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -331,7 +344,7 @@ func TestConfigShouldAcceptCorrectInboundIpAddresses(t *testing.T) {
} }
config["allowed_inbound_ip_addresses"] = []string{ipValue0, cidrValue2, ipValue1, cidrValue3} config["allowed_inbound_ip_addresses"] = []string{ipValue0, cidrValue2, ipValue1, cidrValue3}
c, _, err = newConfig(config, getPackerConfiguration()) _, err = c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -357,13 +370,14 @@ func TestConfigShouldRejectIncorrectInboundIpAddresses(t *testing.T) {
} }
config["allowed_inbound_ip_addresses"] = []string{"127.0.0.1", "127.0.0.two"} config["allowed_inbound_ip_addresses"] = []string{"127.0.0.1", "127.0.0.two"}
c, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Errorf("Expected configuration creation to fail, but it succeeded with the malformed allowed_inbound_ip_addresses set to %v", c.AllowedInboundIpAddresses) t.Errorf("Expected configuration creation to fail, but it succeeded with the malformed allowed_inbound_ip_addresses set to %v", c.AllowedInboundIpAddresses)
} }
config["allowed_inbound_ip_addresses"] = []string{"192.168.100.1000/24", "10.10.1.16/32"} config["allowed_inbound_ip_addresses"] = []string{"192.168.100.1000/24", "10.10.1.16/32"}
c, _, err = newConfig(config, getPackerConfiguration()) _, err = c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
// 192.168.100.1000/24 is invalid // 192.168.100.1000/24 is invalid
t.Errorf("Expected configuration creation to fail, but it succeeded with the malformed allowed_inbound_ip_addresses set to %v", c.AllowedInboundIpAddresses) t.Errorf("Expected configuration creation to fail, but it succeeded with the malformed allowed_inbound_ip_addresses set to %v", c.AllowedInboundIpAddresses)
@ -384,20 +398,22 @@ func TestConfigShouldRejectInboundIpAddressesWithVirtualNetwork(t *testing.T) {
"allowed_inbound_ip_addresses": "127.0.0.1", "allowed_inbound_ip_addresses": "127.0.0.1",
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
config["virtual_network_name"] = "some_vnet_name" config["virtual_network_name"] = "some_vnet_name"
_, _, err = newConfig(config, getPackerConfiguration()) _, err = c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Errorf("Expected configuration creation to fail, but it succeeded with allowed_inbound_ip_addresses and virtual_network_name both specified") t.Errorf("Expected configuration creation to fail, but it succeeded with allowed_inbound_ip_addresses and virtual_network_name both specified")
} }
} }
func TestConfigShouldDefaultToPublicCloud(t *testing.T) { func TestConfigShouldDefaultToPublicCloud(t *testing.T) {
c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) var c Config
c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration())
if c.ClientConfig.CloudEnvironmentName != "Public" { if c.ClientConfig.CloudEnvironmentName != "Public" {
t.Errorf("Expected 'CloudEnvironmentName' to default to 'Public', but got '%s'.", c.ClientConfig.CloudEnvironmentName) t.Errorf("Expected 'CloudEnvironmentName' to default to 'Public', but got '%s'.", c.ClientConfig.CloudEnvironmentName)
@ -448,7 +464,8 @@ func TestConfigInstantiatesCorrectAzureEnvironment(t *testing.T) {
for _, x := range table { for _, x := range table {
config["cloud_environment_name"] = x.name config["cloud_environment_name"] = x.name
c, _, err := newConfig(config, packerConfiguration) var c Config
_, err := c.Prepare(config, packerConfiguration)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -463,7 +480,8 @@ func TestUserShouldProvideRequiredValues(t *testing.T) {
builderValues := getArmBuilderConfiguration() builderValues := getArmBuilderConfiguration()
// Ensure we can successfully create a config. // Ensure we can successfully create a config.
_, _, err := newConfig(builderValues, getPackerConfiguration()) var c Config
_, err := c.Prepare(builderValues, getPackerConfiguration())
if err != nil { if err != nil {
t.Error("Expected configuration creation to succeed, but it failed!\n") t.Error("Expected configuration creation to succeed, but it failed!\n")
t.Fatalf(" -> %+v\n", builderValues) t.Fatalf(" -> %+v\n", builderValues)
@ -474,7 +492,8 @@ func TestUserShouldProvideRequiredValues(t *testing.T) {
originalValue := builderValues[v] originalValue := builderValues[v]
delete(builderValues, v) delete(builderValues, v)
_, _, err := newConfig(builderValues, getPackerConfiguration()) var c Config
_, err := c.Prepare(builderValues, getPackerConfiguration())
if err == nil { if err == nil {
t.Error("Expected configuration creation to fail, but it succeeded!\n") t.Error("Expected configuration creation to fail, but it succeeded!\n")
t.Fatalf(" -> %+v\n", builderValues) t.Fatalf(" -> %+v\n", builderValues)
@ -485,7 +504,8 @@ func TestUserShouldProvideRequiredValues(t *testing.T) {
} }
func TestSystemShouldDefineRuntimeValues(t *testing.T) { func TestSystemShouldDefineRuntimeValues(t *testing.T) {
c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) var c Config
c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration())
if c.Password == "" { if c.Password == "" {
t.Errorf("Expected Password to not be empty, but it was '%s'!", c.Password) t.Errorf("Expected Password to not be empty, but it was '%s'!", c.Password)
@ -513,7 +533,8 @@ func TestSystemShouldDefineRuntimeValues(t *testing.T) {
} }
func TestConfigShouldTransformToVirtualMachineCaptureParameters(t *testing.T) { func TestConfigShouldTransformToVirtualMachineCaptureParameters(t *testing.T) {
c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) var c Config
c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration())
parameters := c.toVirtualMachineCaptureParameters() parameters := c.toVirtualMachineCaptureParameters()
if *parameters.DestinationContainerName != c.CaptureContainerName { if *parameters.DestinationContainerName != c.CaptureContainerName {
@ -530,7 +551,8 @@ func TestConfigShouldTransformToVirtualMachineCaptureParameters(t *testing.T) {
} }
func TestConfigShouldSupportPackersConfigElements(t *testing.T) { func TestConfigShouldSupportPackersConfigElements(t *testing.T) {
c, _, err := newConfig( var c Config
_, err := c.Prepare(
getArmBuilderConfiguration(), getArmBuilderConfiguration(),
getPackerConfiguration(), getPackerConfiguration(),
getPackerCommunicatorConfiguration()) getPackerCommunicatorConfiguration())
@ -554,7 +576,8 @@ func TestWinRMConfigShouldSetRoundTripDecorator(t *testing.T) {
config["winrm_username"] = "username" config["winrm_username"] = "username"
config["winrm_password"] = "password" config["winrm_password"] = "password"
c, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -579,7 +602,8 @@ func TestUserDeviceLoginIsEnabledForLinux(t *testing.T) {
"communicator": "none", "communicator": "none",
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatalf("failed to use device login for Linux: %s", err) t.Fatalf("failed to use device login for Linux: %s", err)
} }
@ -610,7 +634,8 @@ func TestConfigShouldRejectMalformedCaptureNamePrefix(t *testing.T) {
for _, x := range wellFormedCaptureNamePrefix { for _, x := range wellFormedCaptureNamePrefix {
config["capture_name_prefix"] = x config["capture_name_prefix"] = x
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Errorf("Expected test to pass, but it failed with the well-formed capture_name_prefix set to %q.", x) t.Errorf("Expected test to pass, but it failed with the well-formed capture_name_prefix set to %q.", x)
@ -628,7 +653,8 @@ func TestConfigShouldRejectMalformedCaptureNamePrefix(t *testing.T) {
for _, x := range malformedCaptureNamePrefix { for _, x := range malformedCaptureNamePrefix {
config["capture_name_prefix"] = x config["capture_name_prefix"] = x
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Errorf("Expected test to fail, but it succeeded with the malformed capture_name_prefix set to %q.", x) t.Errorf("Expected test to fail, but it succeeded with the malformed capture_name_prefix set to %q.", x)
@ -660,7 +686,8 @@ func TestConfigShouldRejectMalformedCaptureContainerName(t *testing.T) {
for _, x := range wellFormedCaptureContainerName { for _, x := range wellFormedCaptureContainerName {
config["capture_container_name"] = x config["capture_container_name"] = x
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Errorf("Expected test to pass, but it failed with the well-formed capture_container_name set to %q.", x) t.Errorf("Expected test to pass, but it failed with the well-formed capture_container_name set to %q.", x)
@ -678,7 +705,8 @@ func TestConfigShouldRejectMalformedCaptureContainerName(t *testing.T) {
for _, x := range malformedCaptureContainerName { for _, x := range malformedCaptureContainerName {
config["capture_container_name"] = x config["capture_container_name"] = x
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Errorf("Expected test to fail, but it succeeded with the malformed capture_container_name set to %q.", x) t.Errorf("Expected test to fail, but it succeeded with the malformed capture_container_name set to %q.", x)
@ -710,7 +738,8 @@ func TestConfigShouldRejectMalformedManagedImageOSDiskSnapshotName(t *testing.T)
for _, x := range wellFormedManagedImageOSDiskSnapshotName { for _, x := range wellFormedManagedImageOSDiskSnapshotName {
config["managed_image_os_disk_snapshot_name"] = x config["managed_image_os_disk_snapshot_name"] = x
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Errorf("Expected test to pass, but it failed with the well-formed managed_image_os_disk_snapshot_name set to %q.", x) t.Errorf("Expected test to pass, but it failed with the well-formed managed_image_os_disk_snapshot_name set to %q.", x)
@ -727,7 +756,8 @@ func TestConfigShouldRejectMalformedManagedImageOSDiskSnapshotName(t *testing.T)
for _, x := range malformedManagedImageOSDiskSnapshotName { for _, x := range malformedManagedImageOSDiskSnapshotName {
config["managed_image_os_disk_snapshot_name"] = x config["managed_image_os_disk_snapshot_name"] = x
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Errorf("Expected test to fail, but it succeeded with the malformed managed_image_os_disk_snapshot_name set to %q.", x) t.Errorf("Expected test to fail, but it succeeded with the malformed managed_image_os_disk_snapshot_name set to %q.", x)
@ -760,7 +790,8 @@ func TestConfigShouldRejectMalformedManagedImageDataDiskSnapshotPrefix(t *testin
for _, x := range wellFormedManagedImageDataDiskSnapshotPrefix { for _, x := range wellFormedManagedImageDataDiskSnapshotPrefix {
config["managed_image_data_disk_snapshot_prefix"] = x config["managed_image_data_disk_snapshot_prefix"] = x
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Errorf("Expected test to pass, but it failed with the well-formed managed_image_data_disk_snapshot_prefix set to %q.", x) t.Errorf("Expected test to pass, but it failed with the well-formed managed_image_data_disk_snapshot_prefix set to %q.", x)
@ -777,7 +808,8 @@ func TestConfigShouldRejectMalformedManagedImageDataDiskSnapshotPrefix(t *testin
for _, x := range malformedManagedImageDataDiskSnapshotPrefix { for _, x := range malformedManagedImageDataDiskSnapshotPrefix {
config["managed_image_data_disk_snapshot_prefix"] = x config["managed_image_data_disk_snapshot_prefix"] = x
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Errorf("Expected test to fail, but it succeeded with the malformed managed_image_data_disk_snapshot_prefix set to %q.", x) t.Errorf("Expected test to fail, but it succeeded with the malformed managed_image_data_disk_snapshot_prefix set to %q.", x)
@ -805,7 +837,8 @@ func TestConfigShouldAcceptTags(t *testing.T) {
}, },
} }
c, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -855,7 +888,8 @@ func TestConfigShouldRejectTagsInExcessOf15AcceptTags(t *testing.T) {
"azure_tags": tooManyTags, "azure_tags": tooManyTags,
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Fatal("expected config to reject based on an excessive amount of tags (> 15)") t.Fatal("expected config to reject based on an excessive amount of tags (> 15)")
@ -887,7 +921,8 @@ func TestConfigShouldRejectExcessiveTagNameLength(t *testing.T) {
"azure_tags": tags, "azure_tags": tags,
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Fatal("expected config to reject tag name based on length (> 512)") t.Fatal("expected config to reject tag name based on length (> 512)")
} }
@ -918,7 +953,8 @@ func TestConfigShouldRejectExcessiveTagValueLength(t *testing.T) {
"azure_tags": tags, "azure_tags": tags,
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Fatal("expected config to reject tag value based on length (> 256)") t.Fatal("expected config to reject tag value based on length (> 256)")
} }
@ -935,7 +971,8 @@ func TestConfigZoneResilientShouldDefaultToFalse(t *testing.T) {
"os_type": "linux", "os_type": "linux",
} }
c, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -958,7 +995,8 @@ func TestConfigZoneResilientSetFromConfig(t *testing.T) {
"managed_image_zone_resilient": true, "managed_image_zone_resilient": true,
} }
c, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -986,7 +1024,8 @@ func TestConfigShouldRejectMissingCustomDataFile(t *testing.T) {
"custom_data_file": "/this/file/does/not/exist", "custom_data_file": "/this/file/does/not/exist",
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Fatal("expected config to reject missing custom data file") t.Fatal("expected config to reject missing custom data file")
} }
@ -1006,7 +1045,8 @@ func TestConfigShouldRejectManagedImageOSDiskSnapshotNameWithoutManagedImageName
"os_type": constants.Target_Linux, "os_type": constants.Target_Linux,
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Fatal("expected config to reject Managed Image build with OS disk snapshot name but without managed image name") t.Fatal("expected config to reject Managed Image build with OS disk snapshot name but without managed image name")
} }
@ -1026,7 +1066,8 @@ func TestConfigShouldRejectManagedImageOSDiskSnapshotNameWithoutManagedImageReso
"os_type": constants.Target_Linux, "os_type": constants.Target_Linux,
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Fatal("expected config to reject Managed Image build with OS disk snapshot name but without managed image resource group name") t.Fatal("expected config to reject Managed Image build with OS disk snapshot name but without managed image resource group name")
} }
@ -1046,7 +1087,8 @@ func TestConfigShouldRejectImageDataDiskSnapshotPrefixWithoutManagedImageName(t
"os_type": constants.Target_Linux, "os_type": constants.Target_Linux,
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Fatal("expected config to reject Managed Image build with data disk snapshot prefix but without managed image name") t.Fatal("expected config to reject Managed Image build with data disk snapshot prefix but without managed image name")
} }
@ -1066,7 +1108,8 @@ func TestConfigShouldRejectImageDataDiskSnapshotPrefixWithoutManagedImageResourc
"os_type": constants.Target_Linux, "os_type": constants.Target_Linux,
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Fatal("expected config to reject Managed Image build with data disk snapshot prefix but without managed image resource group name") t.Fatal("expected config to reject Managed Image build with data disk snapshot prefix but without managed image resource group name")
} }
@ -1088,7 +1131,8 @@ func TestConfigShouldAcceptManagedImageOSDiskSnapshotNameAndManagedImageDataDisk
"os_type": constants.Target_Linux, "os_type": constants.Target_Linux,
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatal("expected config to accept platform managed image build") t.Fatal("expected config to accept platform managed image build")
} }
@ -1109,7 +1153,8 @@ func TestConfigShouldRejectManagedImageOSDiskSnapshotNameAndManagedImageDataDisk
"os_type": constants.Target_Linux, "os_type": constants.Target_Linux,
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Fatal("expected config to reject Managed Image build with data disk snapshot prefix and OS disk snapshot name with capture container name") t.Fatal("expected config to reject Managed Image build with data disk snapshot prefix and OS disk snapshot name with capture container name")
} }
@ -1130,7 +1175,8 @@ func TestConfigShouldRejectManagedImageOSDiskSnapshotNameAndManagedImageDataDisk
"os_type": constants.Target_Linux, "os_type": constants.Target_Linux,
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Fatal("expected config to reject Managed Image build with data disk snapshot prefix and OS disk snapshot name with capture name prefix") t.Fatal("expected config to reject Managed Image build with data disk snapshot prefix and OS disk snapshot name with capture name prefix")
} }
@ -1151,7 +1197,8 @@ func TestConfigShouldAcceptPlatformManagedImageBuild(t *testing.T) {
"os_type": constants.Target_Linux, "os_type": constants.Target_Linux,
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatal("expected config to accept platform managed image build") t.Fatal("expected config to accept platform managed image build")
} }
@ -1175,7 +1222,8 @@ func TestConfigShouldRejectVhdAndManagedImageOutput(t *testing.T) {
"os_type": constants.Target_Linux, "os_type": constants.Target_Linux,
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Fatal("expected config to reject VHD and Managed Image build") t.Fatal("expected config to reject VHD and Managed Image build")
} }
@ -1195,7 +1243,8 @@ func TestConfigShouldRejectManagedImageSourceAndVhdOutput(t *testing.T) {
"os_type": constants.Target_Linux, "os_type": constants.Target_Linux,
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Fatal("expected config to reject VHD and Managed Image build") t.Fatal("expected config to reject VHD and Managed Image build")
} }
@ -1218,7 +1267,8 @@ func TestConfigShouldRejectCustomAndPlatformManagedImageBuild(t *testing.T) {
"os_type": constants.Target_Linux, "os_type": constants.Target_Linux,
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Fatal("expected config to reject custom and platform input for a managed image build") t.Fatal("expected config to reject custom and platform input for a managed image build")
} }
@ -1239,7 +1289,8 @@ func TestConfigShouldRejectCustomAndImageUrlForManagedImageBuild(t *testing.T) {
"os_type": constants.Target_Linux, "os_type": constants.Target_Linux,
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Fatal("expected config to reject custom and platform input for a managed image build") t.Fatal("expected config to reject custom and platform input for a managed image build")
} }
@ -1260,7 +1311,8 @@ func TestConfigShouldRejectMalformedManageImageStorageAccountTypes(t *testing.T)
"os_type": constants.Target_Linux, "os_type": constants.Target_Linux,
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Fatal("expected config to reject custom and platform input for a managed image build") t.Fatal("expected config to reject custom and platform input for a managed image build")
} }
@ -1281,7 +1333,8 @@ func TestConfigShouldRejectMalformedDiskCachingType(t *testing.T) {
"os_type": constants.Target_Linux, "os_type": constants.Target_Linux,
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Fatal("expected config to reject custom and platform input for a managed image build") t.Fatal("expected config to reject custom and platform input for a managed image build")
} }
@ -1305,7 +1358,8 @@ func TestConfigShouldAcceptManagedImageStorageAccountTypes(t *testing.T) {
for _, x := range storage_account_types { for _, x := range storage_account_types {
config["managed_image_storage_account_type"] = x config["managed_image_storage_account_type"] = x
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatalf("expected config to accept a managed_image_storage_account_type of %q", x) t.Fatalf("expected config to accept a managed_image_storage_account_type of %q", x)
} }
@ -1330,7 +1384,8 @@ func TestConfigShouldAcceptDiskCachingTypes(t *testing.T) {
for _, x := range storage_account_types { for _, x := range storage_account_types {
config["disk_caching_type"] = x config["disk_caching_type"] = x
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatalf("expected config to accept a disk_caching_type of %q", x) t.Fatalf("expected config to accept a disk_caching_type of %q", x)
} }
@ -1355,7 +1410,8 @@ func TestConfigShouldRejectTempAndBuildResourceGroupName(t *testing.T) {
"build_resource_group_name": "rgn00", "build_resource_group_name": "rgn00",
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Fatal("expected config to reject the use of both temp_resource_group_name and build_resource_group_name") t.Fatal("expected config to reject the use of both temp_resource_group_name and build_resource_group_name")
} }
@ -1402,7 +1458,8 @@ func TestConfigShouldRejectInvalidResourceGroupNames(t *testing.T) {
for _, y := range tests { for _, y := range tests {
config[x] = y.name config[x] = y.name
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if !y.ok && err == nil { if !y.ok && err == nil {
t.Errorf("expected config to reject %q for setting %q", y.name, x) t.Errorf("expected config to reject %q for setting %q", y.name, x)
} else if y.ok && err != nil { } else if y.ok && err != nil {
@ -1452,7 +1509,8 @@ func TestConfigShouldRejectManagedDiskNames(t *testing.T) {
for _, y := range testsResourceGroupNames { for _, y := range testsResourceGroupNames {
config[settingUnderTest] = y.name config[settingUnderTest] = y.name
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if !y.ok && err == nil { if !y.ok && err == nil {
t.Errorf("expected config to reject %q for setting %q", y.name, settingUnderTest) t.Errorf("expected config to reject %q for setting %q", y.name, settingUnderTest)
} else if y.ok && err != nil { } else if y.ok && err != nil {
@ -1486,7 +1544,8 @@ func TestConfigShouldRejectManagedDiskNames(t *testing.T) {
for _, y := range testNames { for _, y := range testNames {
config[settingUnderTest] = y.name config[settingUnderTest] = y.name
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if !y.ok && err == nil { if !y.ok && err == nil {
t.Logf("expected config to reject %q for setting %q", y.name, settingUnderTest) t.Logf("expected config to reject %q for setting %q", y.name, settingUnderTest)
} else if y.ok && err != nil { } else if y.ok && err != nil {
@ -1496,7 +1555,8 @@ func TestConfigShouldRejectManagedDiskNames(t *testing.T) {
} }
func TestConfigAdditionalDiskDefaultIsNil(t *testing.T) { func TestConfigAdditionalDiskDefaultIsNil(t *testing.T) {
c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) var c Config
c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration())
if c.AdditionalDiskSize != nil { if c.AdditionalDiskSize != nil {
t.Errorf("Expected Config to not have a set of additional disks, but got a non nil value") t.Errorf("Expected Config to not have a set of additional disks, but got a non nil value")
} }
@ -1519,7 +1579,8 @@ func TestConfigAdditionalDiskOverrideDefault(t *testing.T) {
"disk_additional_size": {32, 64}, "disk_additional_size": {32, 64},
} }
c, _, _ := newConfig(config, diskconfig, getPackerConfiguration()) var c Config
c.Prepare(config, diskconfig, getPackerConfiguration())
if c.AdditionalDiskSize == nil { if c.AdditionalDiskSize == nil {
t.Errorf("Expected Config to have a set of additional disks, but got nil") t.Errorf("Expected Config to have a set of additional disks, but got nil")
} }
@ -1561,19 +1622,20 @@ func TestPlanInfoConfiguration(t *testing.T) {
} }
config["plan_info"] = planInfo config["plan_info"] = planInfo
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Fatal("expected config to reject the use of plan_name without plan_product and plan_publisher") t.Fatal("expected config to reject the use of plan_name without plan_product and plan_publisher")
} }
planInfo["plan_product"] = "--plan-product--" planInfo["plan_product"] = "--plan-product--"
_, _, err = newConfig(config, getPackerConfiguration()) _, err = c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Fatal("expected config to reject the use of plan_name and plan_product without plan_publisher") t.Fatal("expected config to reject the use of plan_name and plan_product without plan_publisher")
} }
planInfo["plan_publisher"] = "--plan-publisher--" planInfo["plan_publisher"] = "--plan-publisher--"
c, _, err := newConfig(config, getPackerConfiguration()) _, err = c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatalf("expected config to accept a complete plan configuration: %s", err) t.Fatalf("expected config to accept a complete plan configuration: %s", err)
} }
@ -1610,7 +1672,8 @@ func TestPlanInfoPromotionCode(t *testing.T) {
}, },
} }
c, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatalf("expected config to accept plan_info configuration, but got %s", err) t.Fatalf("expected config to accept plan_info configuration, but got %s", err)
} }
@ -1659,7 +1722,8 @@ func TestPlanInfoTooManyTagsErrors(t *testing.T) {
}, },
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Fatal("expected config to reject configuration due to excess tags") t.Fatal("expected config to reject configuration due to excess tags")
} }
@ -1682,7 +1746,8 @@ func TestConfigShouldAllowTempNameOverrides(t *testing.T) {
"temp_compute_name": "myTempComputeName", "temp_compute_name": "myTempComputeName",
} }
c, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Errorf("newConfig failed with %q", err) t.Errorf("newConfig failed with %q", err)
} }
@ -1716,7 +1781,8 @@ func TestConfigShouldAllowAsyncResourceGroupOverride(t *testing.T) {
"async_resourcegroup_delete": "true", "async_resourcegroup_delete": "true",
} }
c, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Errorf("newConfig failed with %q", err) t.Errorf("newConfig failed with %q", err)
} }
@ -1738,7 +1804,8 @@ func TestConfigShouldAllowAsyncResourceGroupOverrideNoValue(t *testing.T) {
"managed_image_resource_group_name": "ignore", "managed_image_resource_group_name": "ignore",
} }
c, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Errorf("newConfig failed with %q", err) t.Errorf("newConfig failed with %q", err)
} }
@ -1761,10 +1828,10 @@ func TestConfigShouldAllowAsyncResourceGroupOverrideBadValue(t *testing.T) {
"async_resourcegroup_delete": "asdasda", "async_resourcegroup_delete": "asdasda",
} }
c, _, err := newConfig(config, getPackerConfiguration()) var c Config
if err != nil && c == nil { _, err := c.Prepare(config, getPackerConfiguration())
t.Log("newConfig failed which is expected ", err) if err != nil {
t.Log("newConfig failed which is expected ", err)
} }
} }
@ -1782,7 +1849,8 @@ func TestConfigShouldAllowSharedImageGalleryOptions(t *testing.T) {
}, },
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err == nil { if err == nil {
t.Log("expected config to accept Shared Image Gallery options", err) t.Log("expected config to accept Shared Image Gallery options", err)
} }
@ -1807,7 +1875,8 @@ func TestConfigShouldRejectSharedImageGalleryWithVhdTarget(t *testing.T) {
"capture_name_prefix": "ignore", "capture_name_prefix": "ignore",
} }
_, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Log("expected an error if Shared Image Gallery source is used with VHD target", err) t.Log("expected an error if Shared Image Gallery source is used with VHD target", err)
} }
@ -1818,7 +1887,8 @@ func Test_GivenZoneNotSupportingResiliency_ConfigValidate_ShouldWarn(t *testing.
builderValues["managed_image_zone_resilient"] = "true" builderValues["managed_image_zone_resilient"] = "true"
builderValues["location"] = "ukwest" builderValues["location"] = "ukwest"
c, _, err := newConfig(builderValues, getPackerConfiguration()) var c Config
_, err := c.Prepare(builderValues, getPackerConfiguration())
if err != nil { if err != nil {
t.Errorf("newConfig failed with %q", err) t.Errorf("newConfig failed with %q", err)
} }
@ -1836,7 +1906,8 @@ func Test_GivenZoneSupportingResiliency_ConfigValidate_ShouldNotWarn(t *testing.
builderValues["managed_image_zone_resilient"] = "true" builderValues["managed_image_zone_resilient"] = "true"
builderValues["location"] = "westeurope" builderValues["location"] = "westeurope"
c, _, err := newConfig(builderValues, getPackerConfiguration()) var c Config
_, err := c.Prepare(builderValues, getPackerConfiguration())
if err != nil { if err != nil {
t.Errorf("newConfig failed with %q", err) t.Errorf("newConfig failed with %q", err)
} }

View File

@ -5,14 +5,15 @@ import (
) )
func TestResourceResolverIgnoresEmptyVirtualNetworkName(t *testing.T) { func TestResourceResolverIgnoresEmptyVirtualNetworkName(t *testing.T) {
c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) var c Config
c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration())
if c.VirtualNetworkName != "" { if c.VirtualNetworkName != "" {
t.Fatalf("Expected VirtualNetworkName to be empty by default") t.Fatalf("Expected VirtualNetworkName to be empty by default")
} }
sut := newTestResourceResolver() sut := newTestResourceResolver()
sut.findVirtualNetworkResourceGroup = nil // assert that this is not even called sut.findVirtualNetworkResourceGroup = nil // assert that this is not even called
sut.Resolve(c) sut.Resolve(&c)
if c.VirtualNetworkName != "" { if c.VirtualNetworkName != "" {
t.Fatalf("Expected VirtualNetworkName to be empty") t.Fatalf("Expected VirtualNetworkName to be empty")
@ -25,7 +26,8 @@ func TestResourceResolverIgnoresEmptyVirtualNetworkName(t *testing.T) {
// If the user fully specified the virtual network name and resource group then // If the user fully specified the virtual network name and resource group then
// there is no need to do a lookup. // there is no need to do a lookup.
func TestResourceResolverIgnoresSetVirtualNetwork(t *testing.T) { func TestResourceResolverIgnoresSetVirtualNetwork(t *testing.T) {
c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) var c Config
c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration())
c.VirtualNetworkName = "--virtual-network-name--" c.VirtualNetworkName = "--virtual-network-name--"
c.VirtualNetworkResourceGroupName = "--virtual-network-resource-group-name--" c.VirtualNetworkResourceGroupName = "--virtual-network-resource-group-name--"
c.VirtualNetworkSubnetName = "--virtual-network-subnet-name--" c.VirtualNetworkSubnetName = "--virtual-network-subnet-name--"
@ -33,7 +35,7 @@ func TestResourceResolverIgnoresSetVirtualNetwork(t *testing.T) {
sut := newTestResourceResolver() sut := newTestResourceResolver()
sut.findVirtualNetworkResourceGroup = nil // assert that this is not even called sut.findVirtualNetworkResourceGroup = nil // assert that this is not even called
sut.findVirtualNetworkSubnet = nil // assert that this is not even called sut.findVirtualNetworkSubnet = nil // assert that this is not even called
sut.Resolve(c) sut.Resolve(&c)
if c.VirtualNetworkName != "--virtual-network-name--" { if c.VirtualNetworkName != "--virtual-network-name--" {
t.Fatalf("Expected VirtualNetworkName to be --virtual-network-name--") t.Fatalf("Expected VirtualNetworkName to be --virtual-network-name--")
@ -49,11 +51,12 @@ func TestResourceResolverIgnoresSetVirtualNetwork(t *testing.T) {
// If the user set virtual network name then the code should resolve virtual network // If the user set virtual network name then the code should resolve virtual network
// resource group name. // resource group name.
func TestResourceResolverSetVirtualNetworkResourceGroupName(t *testing.T) { func TestResourceResolverSetVirtualNetworkResourceGroupName(t *testing.T) {
c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) var c Config
c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration())
c.VirtualNetworkName = "--virtual-network-name--" c.VirtualNetworkName = "--virtual-network-name--"
sut := newTestResourceResolver() sut := newTestResourceResolver()
sut.Resolve(c) sut.Resolve(&c)
if c.VirtualNetworkResourceGroupName != "findVirtualNetworkResourceGroup is mocked" { if c.VirtualNetworkResourceGroupName != "findVirtualNetworkResourceGroup is mocked" {
t.Fatalf("Expected VirtualNetworkResourceGroupName to be 'findVirtualNetworkResourceGroup is mocked'") t.Fatalf("Expected VirtualNetworkResourceGroupName to be 'findVirtualNetworkResourceGroup is mocked'")

View File

@ -3,7 +3,9 @@ package arm
import ( import (
"context" "context"
"fmt" "fmt"
"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-03-01/compute"
"github.com/Azure/go-autorest/autorest/date"
"github.com/hashicorp/packer/builder/azure/common/constants" "github.com/hashicorp/packer/builder/azure/common/constants"
"github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"
@ -11,7 +13,7 @@ import (
type StepPublishToSharedImageGallery struct { type StepPublishToSharedImageGallery struct {
client *AzureClient client *AzureClient
publish func(ctx context.Context, mdiID, miSigPubRg, miSIGalleryName, miSGImageName, miSGImageVersion string, miSigReplicationRegions []string, location string, tags map[string]*string) (string, error) publish func(ctx context.Context, mdiID, miSigPubRg, miSIGalleryName, miSGImageName, miSGImageVersion string, miSigReplicationRegions []string, miSGImageVersionEndOfLifeDate string, miSGImageVersionExcludeFromLatest bool, miSigReplicaCount int32, location string, tags map[string]*string) (string, error)
say func(message string) say func(message string)
error func(e error) error func(e error)
toSIG func() bool toSIG func() bool
@ -35,7 +37,7 @@ func NewStepPublishToSharedImageGallery(client *AzureClient, ui packer.Ui, confi
return step return step
} }
func (s *StepPublishToSharedImageGallery) publishToSig(ctx context.Context, mdiID string, miSigPubRg string, miSIGalleryName string, miSGImageName string, miSGImageVersion string, miSigReplicationRegions []string, location string, tags map[string]*string) (string, error) { func (s *StepPublishToSharedImageGallery) publishToSig(ctx context.Context, mdiID string, miSigPubRg string, miSIGalleryName string, miSGImageName string, miSGImageVersion string, miSigReplicationRegions []string, miSGImageVersionEndOfLifeDate string, miSGImageVersionExcludeFromLatest bool, miSigReplicaCount int32, location string, tags map[string]*string) (string, error) {
replicationRegions := make([]compute.TargetRegion, len(miSigReplicationRegions)) replicationRegions := make([]compute.TargetRegion, len(miSigReplicationRegions))
for i, v := range miSigReplicationRegions { for i, v := range miSigReplicationRegions {
@ -43,6 +45,17 @@ func (s *StepPublishToSharedImageGallery) publishToSig(ctx context.Context, mdiI
replicationRegions[i] = compute.TargetRegion{Name: &regionName} replicationRegions[i] = compute.TargetRegion{Name: &regionName}
} }
var endOfLifeDate *date.Time
if miSGImageVersionEndOfLifeDate != "" {
parseDate, err := date.ParseTime("2006-01-02T15:04:05.99Z", miSGImageVersionEndOfLifeDate)
if err != nil {
s.say(fmt.Sprintf("Error parsing date from shared_gallery_image_version_end_of_life_date: %s", err))
return "", err
}
endOfLifeDate = &date.Time{Time: parseDate}
} else {
endOfLifeDate = (*date.Time)(nil)
}
galleryImageVersion := compute.GalleryImageVersion{ galleryImageVersion := compute.GalleryImageVersion{
Location: &location, Location: &location,
Tags: tags, Tags: tags,
@ -53,7 +66,10 @@ func (s *StepPublishToSharedImageGallery) publishToSig(ctx context.Context, mdiI
ID: &mdiID, ID: &mdiID,
}, },
}, },
TargetRegions: &replicationRegions, TargetRegions: &replicationRegions,
EndOfLifeDate: endOfLifeDate,
ExcludeFromLatest: &miSGImageVersionExcludeFromLatest,
ReplicaCount: &miSigReplicaCount,
}, },
}, },
} }
@ -101,14 +117,27 @@ func (s *StepPublishToSharedImageGallery) Run(ctx context.Context, stateBag mult
var targetManagedImageName = stateBag.Get(constants.ArmManagedImageName).(string) var targetManagedImageName = stateBag.Get(constants.ArmManagedImageName).(string)
var managedImageSubscription = stateBag.Get(constants.ArmManagedImageSubscription).(string) var managedImageSubscription = stateBag.Get(constants.ArmManagedImageSubscription).(string)
var mdiID = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/images/%s", managedImageSubscription, targetManagedImageResourceGroupName, targetManagedImageName) var mdiID = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/images/%s", managedImageSubscription, targetManagedImageResourceGroupName, targetManagedImageName)
miSGImageVersionEndOfLifeDate, _ := stateBag.Get(constants.ArmManagedImageSharedGalleryImageVersionEndOfLifeDate).(string)
miSGImageVersionExcludeFromLatest, _ := stateBag.Get(constants.ArmManagedImageSharedGalleryImageVersionExcludeFromLatest).(bool)
miSigReplicaCount, _ := stateBag.Get(constants.ArmManagedImageSharedGalleryImageVersionReplicaCount).(int32)
// Replica count must be between 1 and 10 inclusive.
if miSigReplicaCount <= 0 {
miSigReplicaCount = constants.SharedImageGalleryImageVersionDefaultMinReplicaCount
} else if miSigReplicaCount > 10 {
miSigReplicaCount = constants.SharedImageGalleryImageVersionDefaultMaxReplicaCount
}
s.say(fmt.Sprintf(" -> MDI ID used for SIG publish : '%s'", mdiID)) s.say(fmt.Sprintf(" -> MDI ID used for SIG publish : '%s'", mdiID))
s.say(fmt.Sprintf(" -> SIG publish resource group : '%s'", miSigPubRg)) s.say(fmt.Sprintf(" -> SIG publish resource group : '%s'", miSigPubRg))
s.say(fmt.Sprintf(" -> SIG gallery name : '%s'", miSIGalleryName)) s.say(fmt.Sprintf(" -> SIG gallery name : '%s'", miSIGalleryName))
s.say(fmt.Sprintf(" -> SIG image name : '%s'", miSGImageName)) s.say(fmt.Sprintf(" -> SIG image name : '%s'", miSGImageName))
s.say(fmt.Sprintf(" -> SIG image version : '%s'", miSGImageVersion)) s.say(fmt.Sprintf(" -> SIG image version : '%s'", miSGImageVersion))
s.say(fmt.Sprintf(" -> SIG replication regions : '%v'", miSigReplicationRegions)) s.say(fmt.Sprintf(" -> SIG replication regions : '%v'", miSigReplicationRegions))
createdGalleryImageVersionID, err := s.publish(ctx, mdiID, miSigPubRg, miSIGalleryName, miSGImageName, miSGImageVersion, miSigReplicationRegions, location, tags) s.say(fmt.Sprintf(" -> SIG image version endoflife date : '%s'", miSGImageVersionEndOfLifeDate))
s.say(fmt.Sprintf(" -> SIG image version exclude from latest : '%t'", miSGImageVersionExcludeFromLatest))
s.say(fmt.Sprintf(" -> SIG replica count [1, 10] : '%d'", miSigReplicaCount))
createdGalleryImageVersionID, err := s.publish(ctx, mdiID, miSigPubRg, miSIGalleryName, miSGImageName, miSGImageVersion, miSigReplicationRegions, miSGImageVersionEndOfLifeDate, miSGImageVersionExcludeFromLatest, miSigReplicaCount, location, tags)
if err != nil { if err != nil {
stateBag.Put(constants.Error, err) stateBag.Put(constants.Error, err)

View File

@ -2,14 +2,15 @@ package arm
import ( import (
"context" "context"
"testing"
"github.com/hashicorp/packer/builder/azure/common/constants" "github.com/hashicorp/packer/builder/azure/common/constants"
"github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/multistep"
"testing"
) )
func TestStepPublishToSharedImageGalleryShouldNotPublishForVhd(t *testing.T) { func TestStepPublishToSharedImageGalleryShouldNotPublishForVhd(t *testing.T) {
var testSubject = &StepPublishToSharedImageGallery{ var testSubject = &StepPublishToSharedImageGallery{
publish: func(context.Context, string, string, string, string, string, []string, string, map[string]*string) (string, error) { publish: func(context.Context, string, string, string, string, string, []string, string, bool, int32, string, map[string]*string) (string, error) {
return "test", nil return "test", nil
}, },
say: func(message string) {}, say: func(message string) {},
@ -30,7 +31,7 @@ func TestStepPublishToSharedImageGalleryShouldNotPublishForVhd(t *testing.T) {
func TestStepPublishToSharedImageGalleryShouldPublishForManagedImageWithSig(t *testing.T) { func TestStepPublishToSharedImageGalleryShouldPublishForManagedImageWithSig(t *testing.T) {
var testSubject = &StepPublishToSharedImageGallery{ var testSubject = &StepPublishToSharedImageGallery{
publish: func(context.Context, string, string, string, string, string, []string, string, map[string]*string) (string, error) { publish: func(context.Context, string, string, string, string, string, []string, string, bool, int32, string, map[string]*string) (string, error) {
return "", nil return "", nil
}, },
say: func(message string) {}, say: func(message string) {},

View File

@ -1,25 +0,0 @@
package arm
import (
"context"
commonhelper "github.com/hashicorp/packer/helper/common"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
type StepSaveWinRMPassword struct {
Password string
BuildName string
}
func (s *StepSaveWinRMPassword) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
// store so that we can access this later during provisioning
commonhelper.SetSharedState("winrm_password", s.Password, s.BuildName)
packer.LogSecretFilter.Set(s.Password)
return multistep.ActionContinue
}
func (s *StepSaveWinRMPassword) Cleanup(multistep.StateBag) {
commonhelper.RemoveSharedStateFile("winrm_password", s.BuildName)
}

View File

@ -13,8 +13,9 @@ import (
// Ensure the link values are not set, and the concrete values are set. // Ensure the link values are not set, and the concrete values are set.
func TestVirtualMachineDeployment00(t *testing.T) { func TestVirtualMachineDeployment00(t *testing.T) {
c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) var c Config
deployment, err := GetVirtualMachineDeployment(c) c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration())
deployment, err := GetVirtualMachineDeployment(&c)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -42,8 +43,9 @@ func TestVirtualMachineDeployment00(t *testing.T) {
// Ensure the Virtual Machine template is a valid JSON document. // Ensure the Virtual Machine template is a valid JSON document.
func TestVirtualMachineDeployment01(t *testing.T) { func TestVirtualMachineDeployment01(t *testing.T) {
c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) var c Config
deployment, err := GetVirtualMachineDeployment(c) c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration())
deployment, err := GetVirtualMachineDeployment(&c)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -56,8 +58,9 @@ func TestVirtualMachineDeployment01(t *testing.T) {
// Ensure the Virtual Machine template parameters are correct. // Ensure the Virtual Machine template parameters are correct.
func TestVirtualMachineDeployment02(t *testing.T) { func TestVirtualMachineDeployment02(t *testing.T) {
c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) var c Config
deployment, err := GetVirtualMachineDeployment(c) c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration())
deployment, err := GetVirtualMachineDeployment(&c)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -104,8 +107,9 @@ func TestVirtualMachineDeployment03(t *testing.T) {
m["image_sku"] = "ImageSku" m["image_sku"] = "ImageSku"
m["image_version"] = "ImageVersion" m["image_version"] = "ImageVersion"
c, _, _ := newConfig(m, getPackerConfiguration()) var c Config
deployment, err := GetVirtualMachineDeployment(c) c.Prepare(m, getPackerConfiguration())
deployment, err := GetVirtualMachineDeployment(&c)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -130,12 +134,13 @@ func TestVirtualMachineDeployment04(t *testing.T) {
"communicator": "none", "communicator": "none",
} }
c, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
deployment, err := GetVirtualMachineDeployment(c) deployment, err := GetVirtualMachineDeployment(&c)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -162,12 +167,13 @@ func TestVirtualMachineDeployment05(t *testing.T) {
"virtual_network_subnet_name": "virtualNetworkSubnetName", "virtual_network_subnet_name": "virtualNetworkSubnetName",
} }
c, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
deployment, err := GetVirtualMachineDeployment(c) deployment, err := GetVirtualMachineDeployment(&c)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -197,12 +203,13 @@ func TestVirtualMachineDeployment06(t *testing.T) {
}, },
} }
c, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
deployment, err := GetVirtualMachineDeployment(c) deployment, err := GetVirtualMachineDeployment(&c)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -227,7 +234,8 @@ func TestVirtualMachineDeployment07(t *testing.T) {
"communicator": "none", "communicator": "none",
} }
c, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -247,7 +255,7 @@ growpart:
base64CustomData := base64.StdEncoding.EncodeToString([]byte(customData)) base64CustomData := base64.StdEncoding.EncodeToString([]byte(customData))
c.customData = base64CustomData c.customData = base64CustomData
deployment, err := GetVirtualMachineDeployment(c) deployment, err := GetVirtualMachineDeployment(&c)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -271,12 +279,13 @@ func TestVirtualMachineDeployment08(t *testing.T) {
"managed_image_resource_group_name": "ManagedImageResourceGroupName", "managed_image_resource_group_name": "ManagedImageResourceGroupName",
} }
c, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
deployment, err := GetVirtualMachineDeployment(c) deployment, err := GetVirtualMachineDeployment(&c)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -302,12 +311,13 @@ func TestVirtualMachineDeployment09(t *testing.T) {
"managed_image_resource_group_name": "ManagedImageResourceGroupName", "managed_image_resource_group_name": "ManagedImageResourceGroupName",
} }
c, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
deployment, err := GetVirtualMachineDeployment(c) deployment, err := GetVirtualMachineDeployment(&c)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -339,12 +349,13 @@ func TestVirtualMachineDeployment10(t *testing.T) {
"managed_image_resource_group_name": "ManagedImageResourceGroupName", "managed_image_resource_group_name": "ManagedImageResourceGroupName",
} }
c, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
deployment, err := GetVirtualMachineDeployment(c) deployment, err := GetVirtualMachineDeployment(&c)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -375,12 +386,13 @@ func TestVirtualMachineDeployment11(t *testing.T) {
"capture_container_name": "packerimages", "capture_container_name": "packerimages",
} }
c, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
deployment, err := GetVirtualMachineDeployment(c) deployment, err := GetVirtualMachineDeployment(&c)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -409,12 +421,13 @@ func TestVirtualMachineDeployment12(t *testing.T) {
"managed_image_resource_group_name": "ManagedImageResourceGroupName", "managed_image_resource_group_name": "ManagedImageResourceGroupName",
} }
c, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
deployment, err := GetVirtualMachineDeployment(c) deployment, err := GetVirtualMachineDeployment(&c)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -442,13 +455,14 @@ func TestVirtualMachineDeployment13(t *testing.T) {
"allowed_inbound_ip_addresses": []string{"127.0.0.1", "192.168.100.0/24"}, "allowed_inbound_ip_addresses": []string{"127.0.0.1", "192.168.100.0/24"},
} }
c, _, err := newConfig(config, getPackerConfiguration()) var c Config
_, err := c.Prepare(config, getPackerConfiguration())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
c.tmpKeyVaultName = "--keyvault-name--" c.tmpKeyVaultName = "--keyvault-name--"
deployment, err := GetVirtualMachineDeployment(c) deployment, err := GetVirtualMachineDeployment(&c)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -461,8 +475,9 @@ func TestVirtualMachineDeployment13(t *testing.T) {
// Ensure the link values are not set, and the concrete values are set. // Ensure the link values are not set, and the concrete values are set.
func TestKeyVaultDeployment00(t *testing.T) { func TestKeyVaultDeployment00(t *testing.T) {
c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) var c Config
deployment, err := GetKeyVaultDeployment(c) c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration())
deployment, err := GetKeyVaultDeployment(&c)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -490,8 +505,9 @@ func TestKeyVaultDeployment00(t *testing.T) {
// Ensure the KeyVault template is a valid JSON document. // Ensure the KeyVault template is a valid JSON document.
func TestKeyVaultDeployment01(t *testing.T) { func TestKeyVaultDeployment01(t *testing.T) {
c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) var c Config
deployment, err := GetKeyVaultDeployment(c) c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration())
deployment, err := GetKeyVaultDeployment(&c)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -504,9 +520,10 @@ func TestKeyVaultDeployment01(t *testing.T) {
// Ensure the KeyVault template parameters are correct. // Ensure the KeyVault template parameters are correct.
func TestKeyVaultDeployment02(t *testing.T) { func TestKeyVaultDeployment02(t *testing.T) {
c, _, _ := newConfig(getArmBuilderConfigurationWithWindows(), getPackerConfiguration()) var c Config
c.Prepare(getArmBuilderConfigurationWithWindows(), getPackerConfiguration())
deployment, err := GetKeyVaultDeployment(c) deployment, err := GetKeyVaultDeployment(&c)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -546,8 +563,9 @@ func TestKeyVaultDeployment03(t *testing.T) {
}, },
} }
c, _, _ := newConfig(tags, getArmBuilderConfigurationWithWindows(), getPackerConfiguration()) var c Config
deployment, err := GetKeyVaultDeployment(c) c.Prepare(tags, getArmBuilderConfigurationWithWindows(), getPackerConfiguration())
deployment, err := GetKeyVaultDeployment(&c)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -567,8 +585,9 @@ func TestPlanInfo01(t *testing.T) {
}, },
} }
c, _, _ := newConfig(planInfo, getArmBuilderConfiguration(), getPackerConfiguration()) var c Config
deployment, err := GetVirtualMachineDeployment(c) c.Prepare(planInfo, getArmBuilderConfiguration(), getPackerConfiguration())
deployment, err := GetVirtualMachineDeployment(&c)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -592,8 +611,9 @@ func TestPlanInfo02(t *testing.T) {
}, },
} }
c, _, _ := newConfig(planInfo, getArmBuilderConfiguration(), getPackerConfiguration()) var c Config
deployment, err := GetVirtualMachineDeployment(c) c.Prepare(planInfo, getArmBuilderConfiguration(), getPackerConfiguration())
deployment, err := GetVirtualMachineDeployment(&c)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -1,4 +1,5 @@
//go:generate struct-markdown //go:generate struct-markdown
//go:generate mapstructure-to-hcl2 -type Config
// Package chroot is able to create an Azure managed image without requiring the // Package chroot is able to create an Azure managed image without requiring the
// launch of a new virtual machine for every build. It does this by attaching and // launch of a new virtual machine for every build. It does this by attaching and
@ -14,6 +15,7 @@ import (
"runtime" "runtime"
"strings" "strings"
"github.com/hashicorp/hcl/v2/hcldec"
azcommon "github.com/hashicorp/packer/builder/azure/common" azcommon "github.com/hashicorp/packer/builder/azure/common"
"github.com/hashicorp/packer/builder/azure/common/client" "github.com/hashicorp/packer/builder/azure/common/client"
"github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common"
@ -116,7 +118,9 @@ type Builder struct {
runner multistep.Runner runner multistep.Runner
} }
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { 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 = azcommon.TemplateFuncs
b.config.ctx.Funcs["vm"] = CreateVMMetadataTemplateFunc() b.config.ctx.Funcs["vm"] = CreateVMMetadataTemplateFunc()
err := config.Decode(&b.config, &config.DecodeOpts{ err := config.Decode(&b.config, &config.DecodeOpts{
@ -134,7 +138,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
}, },
}, raws...) }, raws...)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
var errs *packer.MultiError var errs *packer.MultiError
@ -143,7 +147,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
// Defaults // Defaults
err = b.config.ClientConfig.SetDefaultValues() err = b.config.ClientConfig.SetDefaultValues()
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
if b.config.ChrootMounts == nil { if b.config.ChrootMounts == nil {
@ -254,11 +258,11 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
} }
if errs != nil { if errs != nil {
return warns, errs return nil, warns, errs
} }
packer.LogSecretFilter.Set(b.config.ClientConfig.ClientSecret, b.config.ClientConfig.ClientJWT) packer.LogSecretFilter.Set(b.config.ClientConfig.ClientSecret, b.config.ClientConfig.ClientJWT)
return warns, nil return nil, warns, nil
} }
func checkDiskCacheType(s string) interface{} { func checkDiskCacheType(s string) interface{} {

View File

@ -0,0 +1,92 @@
// Code generated by "mapstructure-to-hcl2 -type Config"; DO NOT EDIT.
package chroot
import (
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/zclconf/go-cty/cty"
)
// 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"`
}
// FlatMapstructure returns a new FlatConfig.
// FlatConfig is an auto-generated flat version of Config.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatConfig)
}
// HCL2Spec returns the hcl spec of a Config.
// This spec is used by HCL to read the fields of Config.
// 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.BlockListSpec{TypeName: "chroot_mounts", Nested: &hcldec.AttrSpec{Name: "chroot_mounts", Type: 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},
}
return s
}

View File

@ -55,7 +55,7 @@ func TestBuilder_Prepare(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
b := &Builder{} b := &Builder{}
_, err := b.Prepare(tt.config) _, _, err := b.Prepare(tt.config)
if (err != nil) != tt.wantErr { if (err != nil) != tt.wantErr {
t.Errorf("Builder.Prepare() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("Builder.Prepare() error = %v, wantErr %v", err, tt.wantErr)

View File

@ -2,9 +2,10 @@ package chroot
import ( import (
"context" "context"
"github.com/Azure/go-autorest/autorest/to"
"testing" "testing"
"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-03-01/compute"
"github.com/hashicorp/packer/builder/azure/common/client" "github.com/hashicorp/packer/builder/azure/common/client"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"

View File

@ -3,13 +3,14 @@ package chroot
import ( import (
"context" "context"
"fmt" "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-03-01/compute"
"github.com/Azure/go-autorest/autorest/azure" "github.com/Azure/go-autorest/autorest/azure"
"github.com/Azure/go-autorest/autorest/to" "github.com/Azure/go-autorest/autorest/to"
"github.com/hashicorp/packer/builder/azure/common/client" "github.com/hashicorp/packer/builder/azure/common/client"
"github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"
"log"
) )
var _ multistep.Step = &StepCreateImage{} var _ multistep.Step = &StepCreateImage{}

View File

@ -3,11 +3,12 @@ package client
import ( import (
"context" "context"
"fmt" "fmt"
"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"
"github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute/computeapi" "github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute/computeapi"
"github.com/Azure/go-autorest/autorest/to" "github.com/Azure/go-autorest/autorest/to"
"regexp"
"strings"
) )
var platformImageRegex = regexp.MustCompile(`^[-_.a-zA-Z0-9]+:[-_.a-zA-Z0-9]+:[-_.a-zA-Z0-9]+:[-_.a-zA-Z0-9]+$`) var platformImageRegex = regexp.MustCompile(`^[-_.a-zA-Z0-9]+:[-_.a-zA-Z0-9]+:[-_.a-zA-Z0-9]+:[-_.a-zA-Z0-9]+$`)

View File

@ -9,6 +9,13 @@ const (
Thumbprint string = "thumbprint" Thumbprint string = "thumbprint"
Ui string = "ui" Ui string = "ui"
) )
// Default replica count for image versions in shared image gallery
const (
SharedImageGalleryImageVersionDefaultMinReplicaCount int32 = 1
SharedImageGalleryImageVersionDefaultMaxReplicaCount int32 = 10
)
const ( const (
ArmCaptureTemplate string = "arm.CaptureTemplate" ArmCaptureTemplate string = "arm.CaptureTemplate"
ArmComputeName string = "arm.ComputeName" ArmComputeName string = "arm.ComputeName"
@ -30,18 +37,21 @@ const (
ArmVirtualMachineCaptureParameters string = "arm.VirtualMachineCaptureParameters" ArmVirtualMachineCaptureParameters string = "arm.VirtualMachineCaptureParameters"
ArmIsExistingResourceGroup string = "arm.IsExistingResourceGroup" ArmIsExistingResourceGroup string = "arm.IsExistingResourceGroup"
ArmIsManagedImage string = "arm.IsManagedImage" ArmIsManagedImage string = "arm.IsManagedImage"
ArmManagedImageResourceGroupName string = "arm.ManagedImageResourceGroupName" ArmManagedImageResourceGroupName string = "arm.ManagedImageResourceGroupName"
ArmManagedImageLocation string = "arm.ManagedImageLocation" ArmManagedImageLocation string = "arm.ManagedImageLocation"
ArmManagedImageName string = "arm.ManagedImageName" ArmManagedImageName string = "arm.ManagedImageName"
ArmManagedImageSigPublishResourceGroup string = "arm.ManagedImageSigPublishResourceGroup" ArmManagedImageSigPublishResourceGroup string = "arm.ManagedImageSigPublishResourceGroup"
ArmManagedImageSharedGalleryName string = "arm.ManagedImageSharedGalleryName" ArmManagedImageSharedGalleryName string = "arm.ManagedImageSharedGalleryName"
ArmManagedImageSharedGalleryImageName string = "arm.ManagedImageSharedGalleryImageName" ArmManagedImageSharedGalleryImageName string = "arm.ManagedImageSharedGalleryImageName"
ArmManagedImageSharedGalleryImageVersion string = "arm.ManagedImageSharedGalleryImageVersion" ArmManagedImageSharedGalleryImageVersion string = "arm.ManagedImageSharedGalleryImageVersion"
ArmManagedImageSharedGalleryReplicationRegions string = "arm.ManagedImageSharedGalleryReplicationRegions" ArmManagedImageSharedGalleryReplicationRegions string = "arm.ManagedImageSharedGalleryReplicationRegions"
ArmManagedImageSharedGalleryId string = "arm.ArmManagedImageSharedGalleryId" ArmManagedImageSharedGalleryId string = "arm.ArmManagedImageSharedGalleryId"
ArmManagedImageSubscription string = "arm.ArmManagedImageSubscription" ArmManagedImageSharedGalleryImageVersionEndOfLifeDate string = "arm.ArmManagedImageSharedGalleryImageVersionEndOfLifeDate"
ArmAsyncResourceGroupDelete string = "arm.AsyncResourceGroupDelete" ArmManagedImageSharedGalleryImageVersionReplicaCount string = "arm.ArmManagedImageSharedGalleryImageVersionReplicaCount"
ArmManagedImageOSDiskSnapshotName string = "arm.ManagedImageOSDiskSnapshotName" ArmManagedImageSharedGalleryImageVersionExcludeFromLatest string = "arm.ArmManagedImageSharedGalleryImageVersionExcludeFromLatest"
ArmManagedImageDataDiskSnapshotPrefix string = "arm.ManagedImageDataDiskSnapshotPrefix" ArmManagedImageSubscription string = "arm.ArmManagedImageSubscription"
ArmAsyncResourceGroupDelete string = "arm.AsyncResourceGroupDelete"
ArmManagedImageOSDiskSnapshotName string = "arm.ManagedImageOSDiskSnapshotName"
ArmManagedImageDataDiskSnapshotPrefix string = "arm.ManagedImageDataDiskSnapshotPrefix"
) )

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/communicator" "github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/multistep"
@ -15,20 +16,20 @@ const BuilderId = "packer.cloudstack"
// Builder represents the CloudStack builder. // Builder represents the CloudStack builder.
type Builder struct { type Builder struct {
config *Config config Config
runner multistep.Runner runner multistep.Runner
ui packer.Ui ui packer.Ui
} }
// Prepare implements the packer.Builder interface. func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() }
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
config, errs := NewConfig(raws...)
if errs != nil {
return nil, errs
}
b.config = config
return nil, nil func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
errs := b.config.Prepare(raws...)
if errs != nil {
return nil, nil, errs
}
return nil, nil, nil
} }
// Run implements the packer.Builder interface. // Run implements the packer.Builder interface.
@ -52,7 +53,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
// Set up the state. // Set up the state.
state := new(multistep.BasicStateBag) state := new(multistep.BasicStateBag)
state.Put("client", client) state.Put("client", client)
state.Put("config", b.config) state.Put("config", &b.config)
state.Put("hook", hook) state.Put("hook", hook)
state.Put("ui", ui) state.Put("ui", ui)
@ -109,7 +110,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
// Build the artifact and return it // Build the artifact and return it
artifact := &Artifact{ artifact := &Artifact{
client: client, client: client,
config: b.config, config: &b.config,
template: state.Get("template").(*cloudstack.CreateTemplateResponse), template: state.Get("template").(*cloudstack.CreateTemplateResponse),
} }

View File

@ -40,10 +40,8 @@ func TestBuilder_Prepare(t *testing.T) {
}, },
} }
b := &Builder{}
for desc, tc := range cases { for desc, tc := range cases {
_, errs := b.Prepare(tc.Config) _, _, errs := (&Builder{}).Prepare(tc.Config)
if tc.Err { if tc.Err {
if errs == nil { if errs == nil {

View File

@ -167,8 +167,7 @@ type Config struct {
} }
// NewConfig parses and validates the given config. // NewConfig parses and validates the given config.
func NewConfig(raws ...interface{}) (*Config, error) { func (c *Config) Prepare(raws ...interface{}) error {
c := new(Config)
err := config.Decode(c, &config.DecodeOpts{ err := config.Decode(c, &config.DecodeOpts{
Interpolate: true, Interpolate: true,
InterpolateContext: &c.ctx, InterpolateContext: &c.ctx,
@ -179,7 +178,7 @@ func NewConfig(raws ...interface{}) (*Config, error) {
}, },
}, raws...) }, raws...)
if err != nil { if err != nil {
return nil, err return err
} }
var errs *packer.MultiError var errs *packer.MultiError
@ -309,8 +308,8 @@ func NewConfig(raws ...interface{}) (*Config, error) {
// Check for errors and return if we have any. // Check for errors and return if we have any.
if errs != nil && len(errs.Errors) > 0 { if errs != nil && len(errs.Errors) > 0 {
return nil, errs return errs
} }
return c, nil return nil
} }

View File

@ -49,8 +49,8 @@ type FlatConfig struct {
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"` SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"`
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"` SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"`
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"` SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"`
SSHPublicKey []byte `cty:"ssh_public_key"` SSHPublicKey []byte `mapstructure:"ssh_public_key" cty:"ssh_public_key"`
SSHPrivateKey []byte `cty:"ssh_private_key"` SSHPrivateKey []byte `mapstructure:"ssh_private_key" cty:"ssh_private_key"`
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"` WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"`
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"` WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"`
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"` WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"`
@ -104,10 +104,13 @@ type FlatConfig struct {
// FlatMapstructure returns a new FlatConfig. // FlatMapstructure returns a new FlatConfig.
// FlatConfig is an auto-generated flat version of Config. // FlatConfig is an auto-generated flat version of Config.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*Config) FlatMapstructure() interface{} { return new(FlatConfig) } func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatConfig)
}
// HCL2Spec returns the hcldec.Spec of a FlatConfig. // HCL2Spec returns the hcl spec of a Config.
// This spec is used by HCL to read the fields of FlatConfig. // This spec is used by HCL to read the fields of Config.
// The decoded values from this spec will then be applied to a FlatConfig.
func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false},

View File

@ -132,7 +132,8 @@ func TestNewConfig(t *testing.T) {
raw[tc.Nullify] = nil raw[tc.Nullify] = nil
} }
_, errs := NewConfig(raw) var c Config
errs := c.Prepare(raw)
if tc.Err { if tc.Err {
if errs == nil { if errs == nil {

View File

@ -10,6 +10,7 @@ import (
"net/url" "net/url"
"github.com/digitalocean/godo" "github.com/digitalocean/godo"
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/communicator" "github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/multistep"
@ -25,14 +26,15 @@ type Builder struct {
runner multistep.Runner runner multistep.Runner
} }
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() }
c, warnings, errs := NewConfig(raws...)
if errs != nil {
return warnings, errs
}
b.config = *c
return nil, nil func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
warnings, errs := b.config.Prepare(raws...)
if errs != nil {
return nil, warnings, errs
}
return nil, nil, nil
} }
func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) { func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) {

View File

@ -32,7 +32,7 @@ func TestBuilder_Prepare_BadType(t *testing.T) {
"api_key": []string{}, "api_key": []string{},
} }
warnings, err := b.Prepare(c) _, warnings, err := b.Prepare(c)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -47,7 +47,7 @@ func TestBuilderPrepare_InvalidKey(t *testing.T) {
// Add a random key // Add a random key
config["i_should_not_be_valid"] = true config["i_should_not_be_valid"] = true
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -62,7 +62,7 @@ func TestBuilderPrepare_Region(t *testing.T) {
// Test default // Test default
delete(config, "region") delete(config, "region")
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -75,7 +75,7 @@ func TestBuilderPrepare_Region(t *testing.T) {
// Test set // Test set
config["region"] = expected config["region"] = expected
b = Builder{} b = Builder{}
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -94,7 +94,7 @@ func TestBuilderPrepare_Size(t *testing.T) {
// Test default // Test default
delete(config, "size") delete(config, "size")
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -107,7 +107,7 @@ func TestBuilderPrepare_Size(t *testing.T) {
// Test set // Test set
config["size"] = expected config["size"] = expected
b = Builder{} b = Builder{}
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -126,7 +126,7 @@ func TestBuilderPrepare_Image(t *testing.T) {
// Test default // Test default
delete(config, "image") delete(config, "image")
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -139,7 +139,7 @@ func TestBuilderPrepare_Image(t *testing.T) {
// Test set // Test set
config["image"] = expected config["image"] = expected
b = Builder{} b = Builder{}
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -157,7 +157,7 @@ func TestBuilderPrepare_StateTimeout(t *testing.T) {
config := testConfig() config := testConfig()
// Test default // Test default
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -172,7 +172,7 @@ func TestBuilderPrepare_StateTimeout(t *testing.T) {
// Test set // Test set
config["state_timeout"] = "5m" config["state_timeout"] = "5m"
b = Builder{} b = Builder{}
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -183,7 +183,7 @@ func TestBuilderPrepare_StateTimeout(t *testing.T) {
// Test bad // Test bad
config["state_timeout"] = "tubes" config["state_timeout"] = "tubes"
b = Builder{} b = Builder{}
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -197,7 +197,7 @@ func TestBuilderPrepare_SnapshotTimeout(t *testing.T) {
config := testConfig() config := testConfig()
// Test default // Test default
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -212,7 +212,7 @@ func TestBuilderPrepare_SnapshotTimeout(t *testing.T) {
// Test set // Test set
config["snapshot_timeout"] = "15m" config["snapshot_timeout"] = "15m"
b = Builder{} b = Builder{}
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -223,7 +223,7 @@ func TestBuilderPrepare_SnapshotTimeout(t *testing.T) {
// Test bad // Test bad
config["snapshot_timeout"] = "badstring" config["snapshot_timeout"] = "badstring"
b = Builder{} b = Builder{}
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -237,7 +237,7 @@ func TestBuilderPrepare_PrivateNetworking(t *testing.T) {
config := testConfig() config := testConfig()
// Test default // Test default
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -252,7 +252,7 @@ func TestBuilderPrepare_PrivateNetworking(t *testing.T) {
// Test set // Test set
config["private_networking"] = true config["private_networking"] = true
b = Builder{} b = Builder{}
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -270,7 +270,7 @@ func TestBuilderPrepare_SnapshotName(t *testing.T) {
config := testConfig() config := testConfig()
// Test default // Test default
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -285,7 +285,7 @@ func TestBuilderPrepare_SnapshotName(t *testing.T) {
// Test set // Test set
config["snapshot_name"] = "foobarbaz" config["snapshot_name"] = "foobarbaz"
b = Builder{} b = Builder{}
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -296,7 +296,7 @@ func TestBuilderPrepare_SnapshotName(t *testing.T) {
// Test set with template // Test set with template
config["snapshot_name"] = "{{timestamp}}" config["snapshot_name"] = "{{timestamp}}"
b = Builder{} b = Builder{}
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -316,7 +316,7 @@ func TestBuilderPrepare_DropletName(t *testing.T) {
config := testConfig() config := testConfig()
// Test default // Test default
warnings, err := b.Prepare(config) _, warnings, err := b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -331,7 +331,7 @@ func TestBuilderPrepare_DropletName(t *testing.T) {
// Test normal set // Test normal set
config["droplet_name"] = "foobar" config["droplet_name"] = "foobar"
b = Builder{} b = Builder{}
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -342,7 +342,7 @@ func TestBuilderPrepare_DropletName(t *testing.T) {
// Test with template // Test with template
config["droplet_name"] = "foobar-{{timestamp}}" config["droplet_name"] = "foobar-{{timestamp}}"
b = Builder{} b = Builder{}
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }
@ -353,7 +353,7 @@ func TestBuilderPrepare_DropletName(t *testing.T) {
// Test with bad template // Test with bad template
config["droplet_name"] = "foobar-{{" config["droplet_name"] = "foobar-{{"
b = Builder{} b = Builder{}
warnings, err = b.Prepare(config) _, warnings, err = b.Prepare(config)
if len(warnings) > 0 { if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings) t.Fatalf("bad: %#v", warnings)
} }

View File

@ -89,8 +89,7 @@ type Config struct {
ctx interpolate.Context ctx interpolate.Context
} }
func NewConfig(raws ...interface{}) (*Config, []string, error) { func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
c := new(Config)
var md mapstructure.Metadata var md mapstructure.Metadata
err := config.Decode(c, &config.DecodeOpts{ err := config.Decode(c, &config.DecodeOpts{
@ -104,7 +103,7 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
}, },
}, raws...) }, raws...)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
// Defaults // Defaults
@ -189,9 +188,9 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
} }
if errs != nil && len(errs.Errors) > 0 { if errs != nil && len(errs.Errors) > 0 {
return nil, nil, errs return nil, errs
} }
packer.LogSecretFilter.Set(c.APIToken) packer.LogSecretFilter.Set(c.APIToken)
return c, nil, nil return nil, nil
} }

View File

@ -46,8 +46,8 @@ type FlatConfig struct {
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"` SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"`
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"` SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"`
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"` SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"`
SSHPublicKey []byte `cty:"ssh_public_key"` SSHPublicKey []byte `mapstructure:"ssh_public_key" cty:"ssh_public_key"`
SSHPrivateKey []byte `cty:"ssh_private_key"` SSHPrivateKey []byte `mapstructure:"ssh_private_key" cty:"ssh_private_key"`
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"` WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"`
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"` WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"`
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"` WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"`
@ -77,10 +77,13 @@ type FlatConfig struct {
// FlatMapstructure returns a new FlatConfig. // FlatMapstructure returns a new FlatConfig.
// FlatConfig is an auto-generated flat version of Config. // FlatConfig is an auto-generated flat version of Config.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*Config) FlatMapstructure() interface{} { return new(FlatConfig) } func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatConfig)
}
// HCL2Spec returns the hcldec.Spec of a FlatConfig. // HCL2Spec returns the hcl spec of a Config.
// This spec is used by HCL to read the fields of FlatConfig. // This spec is used by HCL to read the fields of Config.
// The decoded values from this spec will then be applied to a FlatConfig.
func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false},

View File

@ -63,6 +63,9 @@ func (s *stepCreateDroplet) Run(ctx context.Context, state multistep.StateBag) m
// Store the droplet id for later // Store the droplet id for later
state.Put("droplet_id", droplet.ID) state.Put("droplet_id", droplet.ID)
// instance_id is the generic term used so that users can have access to the
// instance id inside of the provisioners, used in step_provision.
state.Put("instance_id", droplet.ID)
return multistep.ActionContinue return multistep.ActionContinue
} }

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"log" "log"
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/communicator" "github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/multistep"
@ -16,18 +17,19 @@ const (
) )
type Builder struct { type Builder struct {
config *Config config Config
runner multistep.Runner runner multistep.Runner
} }
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() }
c, warnings, errs := NewConfig(raws...)
if errs != nil {
return warnings, errs
}
b.config = c
return warnings, nil func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
warnings, errs := b.config.Prepare(raws...)
if errs != nil {
return nil, warnings, errs
}
return nil, warnings, nil
} }
func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) { func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) {
@ -75,7 +77,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
// Setup the state bag and initial state for the steps // Setup the state bag and initial state for the steps
state := new(multistep.BasicStateBag) state := new(multistep.BasicStateBag)
state.Put("config", b.config) state.Put("config", &b.config)
state.Put("hook", hook) state.Put("hook", hook)
state.Put("ui", ui) state.Put("ui", ui)

View File

@ -35,7 +35,7 @@ func TestUploadDownload(t *testing.T) {
// Setup the builder // Setup the builder
builder := &Builder{} builder := &Builder{}
warnings, err := builder.Prepare(tpl.Builders["docker"].Config) _, warnings, err := builder.Prepare(tpl.Builders["docker"].Config)
if err != nil { if err != nil {
t.Fatalf("Error preparing configuration %s", err) t.Fatalf("Error preparing configuration %s", err)
} }
@ -118,7 +118,7 @@ func TestLargeDownload(t *testing.T) {
// Setup the builder // Setup the builder
builder := &Builder{} builder := &Builder{}
warnings, err := builder.Prepare(tpl.Builders["docker"].Config) _, warnings, err := builder.Prepare(tpl.Builders["docker"].Config)
if err != nil { if err != nil {
t.Fatalf("Error preparing configuration %s", err) t.Fatalf("Error preparing configuration %s", err)
} }
@ -222,7 +222,7 @@ func TestFixUploadOwner(t *testing.T) {
// Setup the builder // Setup the builder
builder := &Builder{} builder := &Builder{}
warnings, err := builder.Prepare(tpl.Builders["docker"].Config) _, warnings, err := builder.Prepare(tpl.Builders["docker"].Config)
if err != nil { if err != nil {
t.Fatalf("Error preparing configuration %s", err) t.Fatalf("Error preparing configuration %s", err)
} }

View File

@ -107,8 +107,7 @@ type Config struct {
ctx interpolate.Context ctx interpolate.Context
} }
func NewConfig(raws ...interface{}) (*Config, []string, error) { func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
c := new(Config)
c.FixUploadOwner = true c.FixUploadOwner = true
@ -124,7 +123,7 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
}, },
}, raws...) }, raws...)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
// Defaults // Defaults
@ -191,8 +190,8 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
} }
if errs != nil && len(errs.Errors) > 0 { if errs != nil && len(errs.Errors) > 0 {
return nil, nil, errs return nil, errs
} }
return c, nil, nil return nil, nil
} }

View File

@ -46,8 +46,8 @@ type FlatConfig struct {
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"` SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"`
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"` SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"`
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"` SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"`
SSHPublicKey []byte `cty:"ssh_public_key"` SSHPublicKey []byte `mapstructure:"ssh_public_key" cty:"ssh_public_key"`
SSHPrivateKey []byte `cty:"ssh_private_key"` SSHPrivateKey []byte `mapstructure:"ssh_private_key" cty:"ssh_private_key"`
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"` WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"`
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"` WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"`
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"` WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"`
@ -86,10 +86,13 @@ type FlatConfig struct {
// FlatMapstructure returns a new FlatConfig. // FlatMapstructure returns a new FlatConfig.
// FlatConfig is an auto-generated flat version of Config. // FlatConfig is an auto-generated flat version of Config.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*Config) FlatMapstructure() interface{} { return new(FlatConfig) } func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatConfig)
}
// HCL2Spec returns the hcldec.Spec of a FlatConfig. // HCL2Spec returns the hcl spec of a Config.
// This spec is used by HCL to read the fields of FlatConfig. // This spec is used by HCL to read the fields of Config.
// The decoded values from this spec will then be applied to a FlatConfig.
func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false},

View File

@ -14,7 +14,8 @@ func testConfig() map[string]interface{} {
} }
func testConfigStruct(t *testing.T) *Config { func testConfigStruct(t *testing.T) *Config {
c, warns, errs := NewConfig(testConfig()) var c Config
warns, errs := c.Prepare(testConfig())
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", len(warns)) t.Fatalf("bad: %#v", len(warns))
} }
@ -22,7 +23,7 @@ func testConfigStruct(t *testing.T) *Config {
t.Fatalf("bad: %#v", errs) t.Fatalf("bad: %#v", errs)
} }
return c return &c
} }
func testConfigErr(t *testing.T, warns []string, err error) { func testConfigErr(t *testing.T, warns []string, err error) {
@ -55,17 +56,18 @@ func TestConfigPrepare_exportPath(t *testing.T) {
// No export path. This is invalid. Previously this would not error during // No export path. This is invalid. Previously this would not error during
// validation and as a result the failure would happen at build time. // validation and as a result the failure would happen at build time.
delete(raw, "export_path") delete(raw, "export_path")
_, warns, errs := NewConfig(raw) var c Config
warns, errs := c.Prepare(raw)
testConfigErr(t, warns, errs) testConfigErr(t, warns, errs)
// Good export path // Good export path
raw["export_path"] = "good" raw["export_path"] = "good"
_, warns, errs = NewConfig(raw) warns, errs = c.Prepare(raw)
testConfigOk(t, warns, errs) testConfigOk(t, warns, errs)
// Bad export path (directory) // Bad export path (directory)
raw["export_path"] = td raw["export_path"] = td
_, warns, errs = NewConfig(raw) warns, errs = c.Prepare(raw)
testConfigErr(t, warns, errs) testConfigErr(t, warns, errs)
} }
@ -74,17 +76,17 @@ func TestConfigPrepare_exportPathAndCommit(t *testing.T) {
// Export but no commit (explicit default) // Export but no commit (explicit default)
raw["commit"] = false raw["commit"] = false
_, warns, errs := NewConfig(raw) warns, errs := (&Config{}).Prepare(raw)
testConfigOk(t, warns, errs) testConfigOk(t, warns, errs)
// Commit AND export specified (invalid) // Commit AND export specified (invalid)
raw["commit"] = true raw["commit"] = true
_, warns, errs = NewConfig(raw) warns, errs = (&Config{}).Prepare(raw)
testConfigErr(t, warns, errs) testConfigErr(t, warns, errs)
// Commit but no export // Commit but no export
delete(raw, "export_path") delete(raw, "export_path")
_, warns, errs = NewConfig(raw) warns, errs = (&Config{}).Prepare(raw)
testConfigOk(t, warns, errs) testConfigOk(t, warns, errs)
} }
@ -93,18 +95,18 @@ func TestConfigPrepare_exportDiscard(t *testing.T) {
// Export but no discard (explicit default) // Export but no discard (explicit default)
raw["discard"] = false raw["discard"] = false
_, warns, errs := NewConfig(raw) warns, errs := (&Config{}).Prepare(raw)
testConfigOk(t, warns, errs) testConfigOk(t, warns, errs)
// Discard AND export (invalid) // Discard AND export (invalid)
raw["discard"] = true raw["discard"] = true
_, warns, errs = NewConfig(raw) warns, errs = (&Config{}).Prepare(raw)
testConfigErr(t, warns, errs) testConfigErr(t, warns, errs)
// Discard but no export // Discard but no export
raw["discard"] = true raw["discard"] = true
delete(raw, "export_path") delete(raw, "export_path")
_, warns, errs = NewConfig(raw) warns, errs = (&Config{}).Prepare(raw)
testConfigOk(t, warns, errs) testConfigOk(t, warns, errs)
} }
@ -113,12 +115,13 @@ func TestConfigPrepare_image(t *testing.T) {
// No image // No image
delete(raw, "image") delete(raw, "image")
_, warns, errs := NewConfig(raw) var c Config
warns, errs := c.Prepare(raw)
testConfigErr(t, warns, errs) testConfigErr(t, warns, errs)
// Good image // Good image
raw["image"] = "path" raw["image"] = "path"
_, warns, errs = NewConfig(raw) warns, errs = c.Prepare(raw)
testConfigOk(t, warns, errs) testConfigOk(t, warns, errs)
} }
@ -127,7 +130,8 @@ func TestConfigPrepare_pull(t *testing.T) {
// No pull set // No pull set
delete(raw, "pull") delete(raw, "pull")
c, warns, errs := NewConfig(raw) var c Config
warns, errs := c.Prepare(raw)
testConfigOk(t, warns, errs) testConfigOk(t, warns, errs)
if !c.Pull { if !c.Pull {
t.Fatal("should pull by default") t.Fatal("should pull by default")
@ -135,7 +139,7 @@ func TestConfigPrepare_pull(t *testing.T) {
// Pull set // Pull set
raw["pull"] = false raw["pull"] = false
c, warns, errs = NewConfig(raw) warns, errs = c.Prepare(raw)
testConfigOk(t, warns, errs) testConfigOk(t, warns, errs)
if c.Pull { if c.Pull {
t.Fatal("should not pull") t.Fatal("should not pull")

View File

@ -14,11 +14,17 @@ type StepCommit struct {
} }
func (s *StepCommit) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { func (s *StepCommit) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
config, ok := state.Get("config").(*Config)
if !ok {
err := fmt.Errorf("error encountered obtaining docker config")
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
driver := state.Get("driver").(Driver) driver := state.Get("driver").(Driver)
containerId := state.Get("container_id").(string) containerId := state.Get("container_id").(string)
config := state.Get("config").(*Config)
ui := state.Get("ui").(packer.Ui)
if config.WindowsContainer { if config.WindowsContainer {
// docker can't commit a running Windows container // docker can't commit a running Windows container
err := driver.StopContainer(containerId) err := driver.StopContainer(containerId)

View File

@ -12,7 +12,13 @@ import (
type StepConnectDocker struct{} type StepConnectDocker struct{}
func (s *StepConnectDocker) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { func (s *StepConnectDocker) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config) config, ok := state.Get("config").(*Config)
if !ok {
err := fmt.Errorf("error encountered obtaining docker config")
state.Put("error", err)
return multistep.ActionHalt
}
containerId := state.Get("container_id").(string) containerId := state.Get("container_id").(string)
driver := state.Get("driver").(Driver) driver := state.Get("driver").(Driver)
tempDir := state.Get("temp_dir").(string) tempDir := state.Get("temp_dir").(string)

View File

@ -14,11 +14,14 @@ import (
type StepExport struct{} type StepExport struct{}
func (s *StepExport) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { func (s *StepExport) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config)
driver := state.Get("driver").(Driver)
containerId := state.Get("container_id").(string)
ui := state.Get("ui").(packer.Ui) ui := state.Get("ui").(packer.Ui)
config, ok := state.Get("config").(*Config)
if !ok {
err := fmt.Errorf("error encountered obtaining docker config")
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
// We should catch this in validation, but guard anyway // We should catch this in validation, but guard anyway
if config.ExportPath == "" { if config.ExportPath == "" {
@ -44,6 +47,9 @@ func (s *StepExport) Run(ctx context.Context, state multistep.StateBag) multiste
return multistep.ActionHalt return multistep.ActionHalt
} }
driver := state.Get("driver").(Driver)
containerId := state.Get("container_id").(string)
ui.Say("Exporting the container") ui.Say("Exporting the container")
if err := driver.Export(containerId, f); err != nil { if err := driver.Export(containerId, f); err != nil {
f.Close() f.Close()

View File

@ -12,9 +12,14 @@ import (
type StepPull struct{} type StepPull struct{}
func (s *StepPull) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { func (s *StepPull) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config)
driver := state.Get("driver").(Driver)
ui := state.Get("ui").(packer.Ui) ui := state.Get("ui").(packer.Ui)
config, ok := state.Get("config").(*Config)
if !ok {
err := fmt.Errorf("error encountered obtaining docker config")
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
if !config.Pull { if !config.Pull {
log.Println("Pull disabled, won't docker pull") log.Println("Pull disabled, won't docker pull")
@ -38,6 +43,7 @@ func (s *StepPull) Run(ctx context.Context, state multistep.StateBag) multistep.
config.LoginPassword = password config.LoginPassword = password
} }
driver := state.Get("driver").(Driver)
if config.Login || config.EcrLogin { if config.Login || config.EcrLogin {
ui.Message("Logging in...") ui.Message("Logging in...")
err := driver.Login( err := driver.Login(

View File

@ -13,10 +13,14 @@ type StepRun struct {
} }
func (s *StepRun) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { func (s *StepRun) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config)
driver := state.Get("driver").(Driver)
tempDir := state.Get("temp_dir").(string)
ui := state.Get("ui").(packer.Ui) ui := state.Get("ui").(packer.Ui)
config, ok := state.Get("config").(*Config)
if !ok {
err := fmt.Errorf("error encountered obtaining docker config")
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
runConfig := ContainerConfig{ runConfig := ContainerConfig{
Image: config.Image, Image: config.Image,
@ -28,8 +32,11 @@ func (s *StepRun) Run(ctx context.Context, state multistep.StateBag) multistep.S
for host, container := range config.Volumes { for host, container := range config.Volumes {
runConfig.Volumes[host] = container runConfig.Volumes[host] = container
} }
tempDir := state.Get("temp_dir").(string)
runConfig.Volumes[tempDir] = config.ContainerDir runConfig.Volumes[tempDir] = config.ContainerDir
driver := state.Get("driver").(Driver)
ui.Say("Starting docker container...") ui.Say("Starting docker container...")
containerId, err := driver.StartContainer(&runConfig) containerId, err := driver.StartContainer(&runConfig)
if err != nil { if err != nil {
@ -42,6 +49,9 @@ func (s *StepRun) Run(ctx context.Context, state multistep.StateBag) multistep.S
// Save the container ID // Save the container ID
s.containerId = containerId s.containerId = containerId
state.Put("container_id", s.containerId) state.Put("container_id", s.containerId)
// instance_id is the generic term used so that users can have access to the
// instance id inside of the provisioners, used in step_provision.
state.Put("instance_id", s.containerId)
ui.Message(fmt.Sprintf("Container ID: %s", s.containerId)) ui.Message(fmt.Sprintf("Container ID: %s", s.containerId))
return multistep.ActionContinue return multistep.ActionContinue
} }

View File

@ -12,6 +12,7 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"
) )
@ -19,18 +20,19 @@ import (
const BuilderId = "packer.file" const BuilderId = "packer.file"
type Builder struct { type Builder struct {
config *Config config Config
runner multistep.Runner runner multistep.Runner
} }
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() }
c, warnings, errs := NewConfig(raws...)
if errs != nil {
return warnings, errs
}
b.config = c
return warnings, nil func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
warnings, errs := b.config.Prepare(raws...)
if errs != nil {
return nil, warnings, errs
}
return nil, warnings, nil
} }
// Run is where the actual build should take place. It takes a Build and a Ui. // Run is where the actual build should take place. It takes a Build and a Ui.

View File

@ -22,8 +22,7 @@ type Config struct {
Content string `mapstructure:"content"` Content string `mapstructure:"content"`
} }
func NewConfig(raws ...interface{}) (*Config, []string, error) { func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
c := new(Config)
warnings := []string{} warnings := []string{}
err := config.Decode(c, &config.DecodeOpts{ err := config.Decode(c, &config.DecodeOpts{
@ -33,7 +32,7 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
}, },
}, raws...) }, raws...)
if err != nil { if err != nil {
return nil, warnings, err return warnings, err
} }
var errs *packer.MultiError var errs *packer.MultiError
@ -51,8 +50,8 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
} }
if errs != nil && len(errs.Errors) > 0 { if errs != nil && len(errs.Errors) > 0 {
return nil, warnings, errs return warnings, errs
} }
return c, warnings, nil return warnings, nil
} }

View File

@ -24,10 +24,13 @@ type FlatConfig struct {
// FlatMapstructure returns a new FlatConfig. // FlatMapstructure returns a new FlatConfig.
// FlatConfig is an auto-generated flat version of Config. // FlatConfig is an auto-generated flat version of Config.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*Config) FlatMapstructure() interface{} { return new(FlatConfig) } func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatConfig)
}
// HCL2Spec returns the hcldec.Spec of a FlatConfig. // HCL2Spec returns the hcl spec of a Config.
// This spec is used by HCL to read the fields of FlatConfig. // This spec is used by HCL to read the fields of Config.
// The decoded values from this spec will then be applied to a FlatConfig.
func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false},

View File

@ -16,7 +16,8 @@ func testConfig() map[string]interface{} {
func TestContentSourceConflict(t *testing.T) { func TestContentSourceConflict(t *testing.T) {
raw := testConfig() raw := testConfig()
_, _, errs := NewConfig(raw) var c Config
_, errs := c.Prepare(raw)
if !strings.Contains(errs.Error(), ErrContentSourceConflict.Error()) { if !strings.Contains(errs.Error(), ErrContentSourceConflict.Error()) {
t.Errorf("Expected config error: %s", ErrContentSourceConflict.Error()) t.Errorf("Expected config error: %s", ErrContentSourceConflict.Error())
} }
@ -26,7 +27,8 @@ func TestNoFilename(t *testing.T) {
raw := testConfig() raw := testConfig()
delete(raw, "filename") delete(raw, "filename")
_, _, errs := NewConfig(raw) var c Config
_, errs := c.Prepare(raw)
if errs == nil { if errs == nil {
t.Errorf("Expected config error: %s", ErrTargetRequired.Error()) t.Errorf("Expected config error: %s", ErrTargetRequired.Error())
} }
@ -37,7 +39,8 @@ func TestNoContent(t *testing.T) {
delete(raw, "content") delete(raw, "content")
delete(raw, "source") delete(raw, "source")
_, warns, _ := NewConfig(raw) var c Config
warns, _ := c.Prepare(raw)
if len(warns) == 0 { if len(warns) == 0 {
t.Error("Expected config warning without any content") t.Error("Expected config warning without any content")

View File

@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"log" "log"
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/communicator" "github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/multistep"
@ -18,18 +19,18 @@ const BuilderId = "packer.googlecompute"
// Builder represents a Packer Builder. // Builder represents a Packer Builder.
type Builder struct { type Builder struct {
config *Config config Config
runner multistep.Runner runner multistep.Runner
} }
// Prepare processes the build configuration parameters. func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() }
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
c, warnings, errs := NewConfig(raws...) func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
warnings, errs := b.config.Prepare(raws...)
if errs != nil { if errs != nil {
return warnings, errs return nil, warnings, errs
} }
b.config = c return nil, warnings, nil
return warnings, nil
} }
// Run executes a googlecompute Packer build and returns a packer.Artifact // Run executes a googlecompute Packer build and returns a packer.Artifact
@ -43,7 +44,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
// Set up the state. // Set up the state.
state := new(multistep.BasicStateBag) state := new(multistep.BasicStateBag)
state.Put("config", b.config) state.Put("config", &b.config)
state.Put("driver", driver) state.Put("driver", driver)
state.Put("hook", hook) state.Put("hook", hook)
state.Put("ui", ui) state.Put("ui", ui)
@ -97,7 +98,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
artifact := &Artifact{ artifact := &Artifact{
image: state.Get("image").(*Image), image: state.Get("image").(*Image),
driver: driver, driver: driver,
config: b.config, config: &b.config,
} }
return artifact, nil return artifact, nil
} }

View File

@ -187,8 +187,7 @@ type Config struct {
ctx interpolate.Context ctx interpolate.Context
} }
func NewConfig(raws ...interface{}) (*Config, []string, error) { func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
c := new(Config)
c.ctx.Funcs = TemplateFuncs c.ctx.Funcs = TemplateFuncs
err := config.Decode(c, &config.DecodeOpts{ err := config.Decode(c, &config.DecodeOpts{
Interpolate: true, Interpolate: true,
@ -200,7 +199,7 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
}, },
}, raws...) }, raws...)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
var errs *packer.MultiError var errs *packer.MultiError
@ -372,10 +371,10 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
// Check for any errors. // Check for any errors.
if errs != nil && len(errs.Errors) > 0 { if errs != nil && len(errs.Errors) > 0 {
return nil, nil, errs return nil, errs
} }
return c, nil, nil return nil, nil
} }
type CustomerEncryptionKey struct { type CustomerEncryptionKey struct {

View File

@ -46,8 +46,8 @@ type FlatConfig struct {
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"` SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"`
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"` SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"`
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"` SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"`
SSHPublicKey []byte `cty:"ssh_public_key"` SSHPublicKey []byte `mapstructure:"ssh_public_key" cty:"ssh_public_key"`
SSHPrivateKey []byte `cty:"ssh_private_key"` SSHPrivateKey []byte `mapstructure:"ssh_private_key" cty:"ssh_private_key"`
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"` WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"`
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"` WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"`
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"` WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"`
@ -100,10 +100,13 @@ type FlatConfig struct {
// FlatMapstructure returns a new FlatConfig. // FlatMapstructure returns a new FlatConfig.
// FlatConfig is an auto-generated flat version of Config. // FlatConfig is an auto-generated flat version of Config.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*Config) FlatMapstructure() interface{} { return new(FlatConfig) } func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatConfig)
}
// HCL2Spec returns the hcldec.Spec of a FlatConfig. // HCL2Spec returns the hcl spec of a Config.
// This spec is used by HCL to read the fields of FlatConfig. // This spec is used by HCL to read the fields of Config.
// The decoded values from this spec will then be applied to a FlatConfig.
func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false},
@ -206,10 +209,13 @@ type FlatCustomerEncryptionKey struct {
// FlatMapstructure returns a new FlatCustomerEncryptionKey. // FlatMapstructure returns a new FlatCustomerEncryptionKey.
// FlatCustomerEncryptionKey is an auto-generated flat version of CustomerEncryptionKey. // FlatCustomerEncryptionKey is an auto-generated flat version of CustomerEncryptionKey.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*CustomerEncryptionKey) FlatMapstructure() interface{} { return new(FlatCustomerEncryptionKey) } func (*CustomerEncryptionKey) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatCustomerEncryptionKey)
}
// HCL2Spec returns the hcldec.Spec of a FlatCustomerEncryptionKey. // HCL2Spec returns the hcl spec of a CustomerEncryptionKey.
// This spec is used by HCL to read the fields of FlatCustomerEncryptionKey. // This spec is used by HCL to read the fields of CustomerEncryptionKey.
// The decoded values from this spec will then be applied to a FlatCustomerEncryptionKey.
func (*FlatCustomerEncryptionKey) HCL2Spec() map[string]hcldec.Spec { func (*FlatCustomerEncryptionKey) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"kms_key_name": &hcldec.AttrSpec{Name: "kms_key_name", Type: cty.String, Required: false}, "kms_key_name": &hcldec.AttrSpec{Name: "kms_key_name", Type: cty.String, Required: false},

View File

@ -242,7 +242,8 @@ func TestConfigPrepare(t *testing.T) {
raw[tc.Key] = tc.Value raw[tc.Key] = tc.Value
} }
_, warns, errs := NewConfig(raw) var c Config
warns, errs := c.Prepare(raw)
if tc.Err { if tc.Err {
testConfigErr(t, warns, errs, tc.Key) testConfigErr(t, warns, errs, tc.Key)
@ -302,7 +303,8 @@ func TestConfigPrepareAccelerator(t *testing.T) {
} }
} }
_, warns, errs := NewConfig(raw) var c Config
warns, errs := c.Prepare(raw)
if tc.Err { if tc.Err {
testConfigErr(t, warns, errs, strings.TrimRight(errStr, ", ")) testConfigErr(t, warns, errs, strings.TrimRight(errStr, ", "))
@ -352,7 +354,8 @@ func TestConfigPrepareServiceAccount(t *testing.T) {
} }
} }
_, warns, errs := NewConfig(raw) var c Config
warns, errs := c.Prepare(raw)
if tc.Err { if tc.Err {
testConfigErr(t, warns, errs, strings.TrimRight(errStr, ", ")) testConfigErr(t, warns, errs, strings.TrimRight(errStr, ", "))
@ -371,7 +374,8 @@ func TestConfigPrepareStartupScriptFile(t *testing.T) {
"zone": "us-central1-a", "zone": "us-central1-a",
} }
_, _, errs := NewConfig(config) var c Config
_, errs := c.Prepare(config)
if errs == nil || !strings.Contains(errs.Error(), "startup_script_file") { if errs == nil || !strings.Contains(errs.Error(), "startup_script_file") {
t.Fatalf("should error: startup_script_file") t.Fatalf("should error: startup_script_file")
@ -398,10 +402,11 @@ func TestConfigDefaults(t *testing.T) {
raw, tempfile := testConfig(t) raw, tempfile := testConfig(t)
defer os.Remove(tempfile) defer os.Remove(tempfile)
c, warns, errs := NewConfig(raw) var c Config
warns, errs := c.Prepare(raw)
testConfigOk(t, warns, errs) testConfigOk(t, warns, errs)
actual := tc.Read(c) actual := tc.Read(&c)
if actual != tc.Value { if actual != tc.Value {
t.Fatalf("bad: %#v", actual) t.Fatalf("bad: %#v", actual)
} }
@ -412,7 +417,8 @@ func TestImageName(t *testing.T) {
raw, tempfile := testConfig(t) raw, tempfile := testConfig(t)
defer os.Remove(tempfile) defer os.Remove(tempfile)
c, _, _ := NewConfig(raw) var c Config
c.Prepare(raw)
if !strings.HasPrefix(c.ImageName, "packer-") { if !strings.HasPrefix(c.ImageName, "packer-") {
t.Fatalf("ImageName should have 'packer-' prefix, found %s", c.ImageName) t.Fatalf("ImageName should have 'packer-' prefix, found %s", c.ImageName)
} }
@ -425,7 +431,8 @@ func TestRegion(t *testing.T) {
raw, tempfile := testConfig(t) raw, tempfile := testConfig(t)
defer os.Remove(tempfile) defer os.Remove(tempfile)
c, _, _ := NewConfig(raw) var c Config
c.Prepare(raw)
if c.Region != "us-east1" { if c.Region != "us-east1" {
t.Fatalf("Region should be 'us-east1' given Zone of 'us-east1-a', but is %s", c.Region) t.Fatalf("Region should be 'us-east1' given Zone of 'us-east1-a', but is %s", c.Region)
} }
@ -460,7 +467,8 @@ func testConfigStruct(t *testing.T) *Config {
raw, tempfile := testConfig(t) raw, tempfile := testConfig(t)
defer os.Remove(tempfile) defer os.Remove(tempfile)
c, warns, errs := NewConfig(raw) var c Config
warns, errs := c.Prepare(raw)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", len(warns)) t.Fatalf("bad: %#v", len(warns))
} }
@ -468,7 +476,7 @@ func testConfigStruct(t *testing.T) *Config {
t.Fatalf("bad: %#v", errs) t.Fatalf("bad: %#v", errs)
} }
return c return &c
} }
func testConfigErr(t *testing.T, warns []string, err error, extra string) { func testConfigErr(t *testing.T, warns []string, err error, extra string) {

View File

@ -176,6 +176,9 @@ func (s *StepCreateInstance) Run(ctx context.Context, state multistep.StateBag)
// Things succeeded, store the name so we can remove it later // Things succeeded, store the name so we can remove it later
state.Put("instance_name", name) state.Put("instance_name", name)
// instance_id is the generic term used so that users can have access to the
// instance id inside of the provisioners, used in step_provision.
state.Put("instance_id", name)
return multistep.ActionContinue return multistep.ActionContinue
} }

View File

@ -13,7 +13,6 @@ import (
"os" "os"
"time" "time"
commonhelper "github.com/hashicorp/packer/helper/common"
"github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"
) )
@ -119,7 +118,6 @@ func (s *StepCreateWindowsPassword) Run(ctx context.Context, state multistep.Sta
} }
state.Put("winrm_password", data.password) state.Put("winrm_password", data.password)
commonhelper.SetSharedState("winrm_password", data.password, c.PackerConfig.PackerBuildName)
packer.LogSecretFilter.Set(data.password) packer.LogSecretFilter.Set(data.password)
return multistep.ActionContinue return multistep.ActionContinue

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/communicator" "github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/multistep"
@ -22,13 +23,15 @@ type Builder struct {
var pluginVersion = "1.0.0" var pluginVersion = "1.0.0"
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() }
config, warnings, errs := NewConfig(raws...)
func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
warnings, errs := b.config.Prepare(raws...)
if errs != nil { if errs != nil {
return warnings, errs return nil, warnings, errs
} }
b.config = *config
return nil, nil return nil, nil, nil
} }
func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) { func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) {

View File

@ -50,9 +50,7 @@ type imageFilter struct {
MostRecent bool `mapstructure:"most_recent"` MostRecent bool `mapstructure:"most_recent"`
} }
func NewConfig(raws ...interface{}) (*Config, []string, error) { func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
c := new(Config)
var md mapstructure.Metadata var md mapstructure.Metadata
err := config.Decode(c, &config.DecodeOpts{ err := config.Decode(c, &config.DecodeOpts{
Metadata: &md, Metadata: &md,
@ -65,7 +63,7 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
}, },
}, raws...) }, raws...)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
// Defaults // Defaults
@ -142,11 +140,11 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
} }
if errs != nil && len(errs.Errors) > 0 { if errs != nil && len(errs.Errors) > 0 {
return nil, nil, errs return nil, errs
} }
packer.LogSecretFilter.Set(c.HCloudToken) packer.LogSecretFilter.Set(c.HCloudToken)
return c, nil, nil return nil, nil
} }
func getServerIP(state multistep.StateBag) (string, error) { func getServerIP(state multistep.StateBag) (string, error) {

View File

@ -46,8 +46,8 @@ type FlatConfig struct {
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"` SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"`
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"` SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"`
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"` SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"`
SSHPublicKey []byte `cty:"ssh_public_key"` SSHPublicKey []byte `mapstructure:"ssh_public_key" cty:"ssh_public_key"`
SSHPrivateKey []byte `cty:"ssh_private_key"` SSHPrivateKey []byte `mapstructure:"ssh_private_key" cty:"ssh_private_key"`
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"` WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"`
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"` WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"`
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"` WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"`
@ -75,10 +75,13 @@ type FlatConfig struct {
// FlatMapstructure returns a new FlatConfig. // FlatMapstructure returns a new FlatConfig.
// FlatConfig is an auto-generated flat version of Config. // FlatConfig is an auto-generated flat version of Config.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*Config) FlatMapstructure() interface{} { return new(FlatConfig) } func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatConfig)
}
// HCL2Spec returns the hcldec.Spec of a FlatConfig. // HCL2Spec returns the hcl spec of a Config.
// This spec is used by HCL to read the fields of FlatConfig. // This spec is used by HCL to read the fields of Config.
// The decoded values from this spec will then be applied to a FlatConfig.
func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false},
@ -156,10 +159,13 @@ type FlatimageFilter struct {
// FlatMapstructure returns a new FlatimageFilter. // FlatMapstructure returns a new FlatimageFilter.
// FlatimageFilter is an auto-generated flat version of imageFilter. // FlatimageFilter is an auto-generated flat version of imageFilter.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*imageFilter) FlatMapstructure() interface{} { return new(FlatimageFilter) } func (*imageFilter) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatimageFilter)
}
// HCL2Spec returns the hcldec.Spec of a FlatimageFilter. // HCL2Spec returns the hcl spec of a imageFilter.
// This spec is used by HCL to read the fields of FlatimageFilter. // This spec is used by HCL to read the fields of imageFilter.
// The decoded values from this spec will then be applied to a FlatimageFilter.
func (*FlatimageFilter) HCL2Spec() map[string]hcldec.Spec { func (*FlatimageFilter) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"with_selector": &hcldec.AttrSpec{Name: "with_selector", Type: cty.List(cty.String), Required: false}, "with_selector": &hcldec.AttrSpec{Name: "with_selector", Type: cty.List(cty.String), Required: false},

View File

@ -85,6 +85,9 @@ func (s *stepCreateServer) Run(ctx context.Context, state multistep.StateBag) mu
// Store the server id for later // Store the server id for later
state.Put("server_id", serverCreateResult.Server.ID) state.Put("server_id", serverCreateResult.Server.ID)
// instance_id is the generic term used so that users can have access to the
// instance id inside of the provisioners, used in step_provision.
state.Put("instance_id", serverCreateResult.Server.ID)
if err := waitForAction(ctx, client, serverCreateResult.Action); err != nil { if err := waitForAction(ctx, client, serverCreateResult.Action); err != nil {
err := fmt.Errorf("Error creating server: %s", err) err := fmt.Errorf("Error creating server: %s", err)

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/communicator" "github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/multistep"
@ -20,13 +21,13 @@ type Builder struct {
client *openapi.APIClient client *openapi.APIClient
} }
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() }
config, warnings, errs := NewConfig(raws...)
if errs != nil {
return warnings, errs
}
b.config = *config func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
warnings, errs := b.config.Prepare(raws...)
if errs != nil {
return nil, warnings, errs
}
cfg := openapi.NewConfiguration() cfg := openapi.NewConfiguration()
cfg.AddDefaultHeader("x-auth-token", b.config.Token) cfg.AddDefaultHeader("x-auth-token", b.config.Token)
@ -43,7 +44,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
b.client = openapi.NewAPIClient(cfg) b.client = openapi.NewAPIClient(cfg)
return nil, nil return nil, nil, nil
} }
type wrappedCommandTemplate struct { type wrappedCommandTemplate struct {

View File

@ -114,8 +114,7 @@ type Config struct {
ctx interpolate.Context ctx interpolate.Context
} }
func NewConfig(raws ...interface{}) (*Config, []string, error) { func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
c := &Config{}
var md mapstructure.Metadata var md mapstructure.Metadata
err := config.Decode(c, &config.DecodeOpts{ err := config.Decode(c, &config.DecodeOpts{
@ -133,12 +132,12 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
}, },
}, raws...) }, raws...)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
cliConfig, err := loadCLIConfig() cliConfig, err := loadCLIConfig()
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
// Defaults // Defaults
@ -165,7 +164,7 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
if c.TokenLogin != "" && c.APIURL == "" { if c.TokenLogin != "" && c.APIURL == "" {
c.Token, err = fetchTokenBySSH(c.TokenLogin) c.Token, err = fetchTokenBySSH(c.TokenLogin)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
} }
} }
@ -181,7 +180,7 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
if c.ImageName == "" { if c.ImageName == "" {
name, err := interpolate.Render("packer-{{timestamp}}", nil) name, err := interpolate.Render("packer-{{timestamp}}", nil)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
c.ImageName = name c.ImageName = name
} }
@ -217,7 +216,7 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
if c.ChrootMountPath == "" { if c.ChrootMountPath == "" {
path, err := interpolate.Render("/mnt/packer-hyperone-volumes/{{timestamp}}", nil) path, err := interpolate.Render("/mnt/packer-hyperone-volumes/{{timestamp}}", nil)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
c.ChrootMountPath = path c.ChrootMountPath = path
} }
@ -281,12 +280,12 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
} }
if errs != nil && len(errs.Errors) > 0 { if errs != nil && len(errs.Errors) > 0 {
return nil, nil, errs return nil, errs
} }
packer.LogSecretFilter.Set(c.Token) packer.LogSecretFilter.Set(c.Token)
return c, nil, nil return nil, nil
} }
type cliConfig struct { type cliConfig struct {

View File

@ -46,8 +46,8 @@ type FlatConfig struct {
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"` SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"`
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"` SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"`
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"` SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"`
SSHPublicKey []byte `cty:"ssh_public_key"` SSHPublicKey []byte `mapstructure:"ssh_public_key" cty:"ssh_public_key"`
SSHPrivateKey []byte `cty:"ssh_private_key"` SSHPrivateKey []byte `mapstructure:"ssh_private_key" cty:"ssh_private_key"`
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"` WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"`
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"` WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"`
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"` WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"`
@ -94,10 +94,13 @@ type FlatConfig struct {
// FlatMapstructure returns a new FlatConfig. // FlatMapstructure returns a new FlatConfig.
// FlatConfig is an auto-generated flat version of Config. // FlatConfig is an auto-generated flat version of Config.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*Config) FlatMapstructure() interface{} { return new(FlatConfig) } func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatConfig)
}
// HCL2Spec returns the hcldec.Spec of a FlatConfig. // HCL2Spec returns the hcl spec of a Config.
// This spec is used by HCL to read the fields of FlatConfig. // This spec is used by HCL to read the fields of Config.
// The decoded values from this spec will then be applied to a FlatConfig.
func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false},

View File

@ -67,6 +67,9 @@ func (s *stepCreateVM) Run(ctx context.Context, state multistep.StateBag) multis
s.vmID = vm.Id s.vmID = vm.Id
state.Put("vm_id", vm.Id) state.Put("vm_id", vm.Id)
// instance_id is the generic term used so that users can have access to the
// instance id inside of the provisioners, used in step_provision.
state.Put("instance_id", vm.Id)
hdds, _, err := client.VmApi.VmListHdd(ctx, vm.Id) hdds, _, err := client.VmApi.VmListHdd(ctx, vm.Id)
if err != nil { if err != nil {

View File

@ -15,10 +15,13 @@ type FlatOutputConfig struct {
// FlatMapstructure returns a new FlatOutputConfig. // FlatMapstructure returns a new FlatOutputConfig.
// FlatOutputConfig is an auto-generated flat version of OutputConfig. // FlatOutputConfig is an auto-generated flat version of OutputConfig.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*OutputConfig) FlatMapstructure() interface{} { return new(FlatOutputConfig) } func (*OutputConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatOutputConfig)
}
// HCL2Spec returns the hcldec.Spec of a FlatOutputConfig. // HCL2Spec returns the hcl spec of a OutputConfig.
// This spec is used by HCL to read the fields of FlatOutputConfig. // This spec is used by HCL to read the fields of OutputConfig.
// The decoded values from this spec will then be applied to a FlatOutputConfig.
func (*FlatOutputConfig) HCL2Spec() map[string]hcldec.Spec { func (*FlatOutputConfig) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"output_directory": &hcldec.AttrSpec{Name: "output_directory", Type: cty.String, Required: false}, "output_directory": &hcldec.AttrSpec{Name: "output_directory", Type: cty.String, Required: false},

View File

@ -154,6 +154,9 @@ func (s *StepCloneVM) Run(ctx context.Context, state multistep.StateBag) multist
// Set the final name in the state bag so others can use it // Set the final name in the state bag so others can use it
state.Put("vmName", s.VMName) state.Put("vmName", s.VMName)
// instance_id is the generic term used so that users can have access to the
// instance id inside of the provisioners, used in step_provision.
state.Put("instance_id", s.VMName)
return multistep.ActionContinue return multistep.ActionContinue
} }

View File

@ -166,6 +166,9 @@ func (s *StepCreateVM) Run(ctx context.Context, state multistep.StateBag) multis
// Set the final name in the state bag so others can use it // Set the final name in the state bag so others can use it
state.Put("vmName", s.VMName) state.Put("vmName", s.VMName)
// instance_id is the generic term used so that users can have access to the
// instance id inside of the provisioners, used in step_provision.
state.Put("instance_id", s.VMName)
return multistep.ActionContinue return multistep.ActionContinue
} }

View File

@ -11,6 +11,7 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/hashicorp/hcl/v2/hcldec"
hypervcommon "github.com/hashicorp/packer/builder/hyperv/common" hypervcommon "github.com/hashicorp/packer/builder/hyperv/common"
"github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/common/bootcommand" "github.com/hashicorp/packer/common/bootcommand"
@ -84,8 +85,9 @@ type Config struct {
ctx interpolate.Context ctx interpolate.Context
} }
// Prepare processes the build configuration parameters. func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() }
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
err := config.Decode(&b.config, &config.DecodeOpts{ err := config.Decode(&b.config, &config.DecodeOpts{
Interpolate: true, Interpolate: true,
InterpolateContext: &b.config.ctx, InterpolateContext: &b.config.ctx,
@ -96,7 +98,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
}, },
}, raws...) }, raws...)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
// Accumulate any errors and warnings // Accumulate any errors and warnings
@ -164,10 +166,10 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
} }
if errs != nil && len(errs.Errors) > 0 { if errs != nil && len(errs.Errors) > 0 {
return warnings, errs return nil, warnings, errs
} }
return warnings, nil return nil, warnings, nil
} }
// Run executes a Packer build and returns a packer.Artifact representing // Run executes a Packer build and returns a packer.Artifact representing
@ -181,7 +183,6 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
// Set up the state. // Set up the state.
state := new(multistep.BasicStateBag) state := new(multistep.BasicStateBag)
state.Put("config", &b.config)
state.Put("debug", b.config.PackerDebug) state.Put("debug", b.config.PackerDebug)
state.Put("driver", driver) state.Put("driver", driver)
state.Put("hook", hook) state.Put("hook", hook)

View File

@ -60,8 +60,8 @@ type FlatConfig struct {
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"` SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"`
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"` SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"`
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"` SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"`
SSHPublicKey []byte `cty:"ssh_public_key"` SSHPublicKey []byte `mapstructure:"ssh_public_key" cty:"ssh_public_key"`
SSHPrivateKey []byte `cty:"ssh_private_key"` SSHPrivateKey []byte `mapstructure:"ssh_private_key" cty:"ssh_private_key"`
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"` WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"`
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"` WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"`
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"` WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"`
@ -108,10 +108,13 @@ type FlatConfig struct {
// FlatMapstructure returns a new FlatConfig. // FlatMapstructure returns a new FlatConfig.
// FlatConfig is an auto-generated flat version of Config. // FlatConfig is an auto-generated flat version of Config.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*Config) FlatMapstructure() interface{} { return new(FlatConfig) } func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatConfig)
}
// HCL2Spec returns the hcldec.Spec of a FlatConfig. // HCL2Spec returns the hcl spec of a Config.
// This spec is used by HCL to read the fields of FlatConfig. // This spec is used by HCL to read the fields of Config.
// The decoded values from this spec will then be applied to a FlatConfig.
func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{ s := map[string]hcldec.Spec{
"packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false},

View File

@ -42,7 +42,7 @@ func TestBuilderPrepare_Defaults(t *testing.T) {
var b Builder var b Builder
config := testConfig() config := testConfig()
warns, err := b.Prepare(config) _, warns, err := b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -60,7 +60,7 @@ func TestBuilderPrepare_DiskSize(t *testing.T) {
config := testConfig() config := testConfig()
delete(config, "disk_size") delete(config, "disk_size")
warns, err := b.Prepare(config) _, warns, err := b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -74,7 +74,7 @@ func TestBuilderPrepare_DiskSize(t *testing.T) {
config["disk_size"] = 256 config["disk_size"] = 256
b = Builder{} b = Builder{}
warns, err = b.Prepare(config) _, warns, err = b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -96,7 +96,7 @@ func TestBuilderPrepare_DiskBlockSize(t *testing.T) {
// Test default with empty disk_block_size // Test default with empty disk_block_size
delete(config, "disk_block_size") delete(config, "disk_block_size")
warns, err := b.Prepare(config) _, warns, err := b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -112,7 +112,7 @@ func TestBuilderPrepare_DiskBlockSize(t *testing.T) {
for _, test_size := range test_sizes { for _, test_size := range test_sizes {
config["disk_block_size"] = test_size config["disk_block_size"] = test_size
b = Builder{} b = Builder{}
warns, err = b.Prepare(config) _, warns, err = b.Prepare(config)
if test_size > expected_max_block_size || test_size < expected_min_block_size { if test_size > expected_max_block_size || test_size < expected_min_block_size {
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad, should have no warns: %#v", warns) t.Fatalf("bad, should have no warns: %#v", warns)
@ -153,7 +153,7 @@ func TestBuilderPrepare_FixedVHDFormat(t *testing.T) {
// use_fixed_vhd_format should work with generation = 1, skip_compaction // use_fixed_vhd_format should work with generation = 1, skip_compaction
// = true, and differencing_disk = false // = true, and differencing_disk = false
warns, err := b.Prepare(config) _, warns, err := b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -164,7 +164,7 @@ func TestBuilderPrepare_FixedVHDFormat(t *testing.T) {
//use_fixed_vhd_format should not work with differencing_disk = true //use_fixed_vhd_format should not work with differencing_disk = true
config["differencing_disk"] = true config["differencing_disk"] = true
b = Builder{} b = Builder{}
warns, err = b.Prepare(config) _, warns, err = b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -176,7 +176,7 @@ func TestBuilderPrepare_FixedVHDFormat(t *testing.T) {
//use_fixed_vhd_format should not work with skip_compaction = false //use_fixed_vhd_format should not work with skip_compaction = false
config["skip_compaction"] = false config["skip_compaction"] = false
b = Builder{} b = Builder{}
warns, err = b.Prepare(config) _, warns, err = b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -188,7 +188,7 @@ func TestBuilderPrepare_FixedVHDFormat(t *testing.T) {
//use_fixed_vhd_format should not work with generation = 2 //use_fixed_vhd_format should not work with generation = 2
config["generation"] = 2 config["generation"] = 2
b = Builder{} b = Builder{}
warns, err = b.Prepare(config) _, warns, err = b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -202,7 +202,7 @@ func TestBuilderPrepare_FloppyFiles(t *testing.T) {
config := testConfig() config := testConfig()
delete(config, "floppy_files") delete(config, "floppy_files")
warns, err := b.Prepare(config) _, warns, err := b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -217,7 +217,7 @@ func TestBuilderPrepare_FloppyFiles(t *testing.T) {
floppiesPath := "../../../common/test-fixtures/floppies" floppiesPath := "../../../common/test-fixtures/floppies"
config["floppy_files"] = []string{fmt.Sprintf("%s/bar.bat", floppiesPath), fmt.Sprintf("%s/foo.ps1", floppiesPath)} config["floppy_files"] = []string{fmt.Sprintf("%s/bar.bat", floppiesPath), fmt.Sprintf("%s/foo.ps1", floppiesPath)}
b = Builder{} b = Builder{}
warns, err = b.Prepare(config) _, warns, err = b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -236,7 +236,7 @@ func TestBuilderPrepare_InvalidFloppies(t *testing.T) {
config := testConfig() config := testConfig()
config["floppy_files"] = []string{"nonexistent.bat", "nonexistent.ps1"} config["floppy_files"] = []string{"nonexistent.bat", "nonexistent.ps1"}
b = Builder{} b = Builder{}
_, errs := b.Prepare(config) _, _, errs := b.Prepare(config)
if errs == nil { if errs == nil {
t.Fatalf("Nonexistent floppies should trigger multierror") t.Fatalf("Nonexistent floppies should trigger multierror")
} }
@ -252,7 +252,7 @@ func TestBuilderPrepare_InvalidKey(t *testing.T) {
// Add a random key // Add a random key
config["i_should_not_be_valid"] = true config["i_should_not_be_valid"] = true
warns, err := b.Prepare(config) _, warns, err := b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -267,7 +267,7 @@ func TestBuilderPrepare_ISOChecksum(t *testing.T) {
// Test bad // Test bad
config["iso_checksum"] = "" config["iso_checksum"] = ""
warns, err := b.Prepare(config) _, warns, err := b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -278,7 +278,7 @@ func TestBuilderPrepare_ISOChecksum(t *testing.T) {
// Test good // Test good
config["iso_checksum"] = "FOo" config["iso_checksum"] = "FOo"
b = Builder{} b = Builder{}
warns, err = b.Prepare(config) _, warns, err = b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -294,7 +294,7 @@ func TestBuilderPrepare_ISOChecksumType(t *testing.T) {
// Test bad // Test bad
config["iso_checksum_type"] = "" config["iso_checksum_type"] = ""
warns, err := b.Prepare(config) _, warns, err := b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -305,7 +305,7 @@ func TestBuilderPrepare_ISOChecksumType(t *testing.T) {
// Test good // Test good
config["iso_checksum_type"] = "mD5" config["iso_checksum_type"] = "mD5"
b = Builder{} b = Builder{}
warns, err = b.Prepare(config) _, warns, err = b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -320,7 +320,7 @@ func TestBuilderPrepare_ISOChecksumType(t *testing.T) {
// Test unknown // Test unknown
config["iso_checksum_type"] = "fake" config["iso_checksum_type"] = "fake"
b = Builder{} b = Builder{}
warns, err = b.Prepare(config) _, warns, err = b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -331,7 +331,7 @@ func TestBuilderPrepare_ISOChecksumType(t *testing.T) {
// Test none // Test none
config["iso_checksum_type"] = "none" config["iso_checksum_type"] = "none"
b = Builder{} b = Builder{}
warns, err = b.Prepare(config) _, warns, err = b.Prepare(config)
if len(warns) == 0 { if len(warns) == 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -353,7 +353,7 @@ func TestBuilderPrepare_ISOUrl(t *testing.T) {
// Test both empty // Test both empty
config["iso_url"] = "" config["iso_url"] = ""
b = Builder{} b = Builder{}
warns, err := b.Prepare(config) _, warns, err := b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -364,7 +364,7 @@ func TestBuilderPrepare_ISOUrl(t *testing.T) {
// Test iso_url set // Test iso_url set
config["iso_url"] = "http://www.packer.io" config["iso_url"] = "http://www.packer.io"
b = Builder{} b = Builder{}
warns, err = b.Prepare(config) _, warns, err = b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -381,7 +381,7 @@ func TestBuilderPrepare_ISOUrl(t *testing.T) {
config["iso_url"] = "http://www.packer.io" config["iso_url"] = "http://www.packer.io"
config["iso_urls"] = []string{"http://www.packer.io"} config["iso_urls"] = []string{"http://www.packer.io"}
b = Builder{} b = Builder{}
warns, err = b.Prepare(config) _, warns, err = b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -397,7 +397,7 @@ func TestBuilderPrepare_ISOUrl(t *testing.T) {
} }
b = Builder{} b = Builder{}
warns, err = b.Prepare(config) _, warns, err = b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -431,7 +431,7 @@ func TestBuilderPrepare_SizeNotRequiredWhenUsingExistingHarddrive(t *testing.T)
} }
b = Builder{} b = Builder{}
warns, err := b.Prepare(config) _, warns, err := b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -455,7 +455,7 @@ func TestBuilderPrepare_SizeNotRequiredWhenUsingExistingHarddrive(t *testing.T)
} }
b = Builder{} b = Builder{}
warns, err = b.Prepare(config) _, warns, err = b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -489,7 +489,7 @@ func TestBuilderPrepare_SizeIsRequiredWhenNotUsingExistingHarddrive(t *testing.T
} }
b = Builder{} b = Builder{}
warns, err := b.Prepare(config) _, warns, err := b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -517,7 +517,7 @@ func TestBuilderPrepare_MaximumOfSixtyFourAdditionalDisks(t *testing.T) {
config["disk_additional_size"] = disks config["disk_additional_size"] = disks
b = Builder{} b = Builder{}
warns, err := b.Prepare(config) _, warns, err := b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -537,7 +537,7 @@ func TestBuilderPrepare_CommConfig(t *testing.T) {
config["winrm_host"] = "1.2.3.4" config["winrm_host"] = "1.2.3.4"
var b Builder var b Builder
warns, err := b.Prepare(config) _, warns, err := b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -565,7 +565,7 @@ func TestBuilderPrepare_CommConfig(t *testing.T) {
config["ssh_host"] = "1.2.3.4" config["ssh_host"] = "1.2.3.4"
var b Builder var b Builder
warns, err := b.Prepare(config) _, warns, err := b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -593,7 +593,7 @@ func TestUserVariablesInBootCommand(t *testing.T) {
config[packer.UserVariablesConfigKey] = map[string]string{"test-variable": "test"} config[packer.UserVariablesConfigKey] = map[string]string{"test-variable": "test"}
config["boot_command"] = []string{"blah {{user `test-variable`}} blah"} config["boot_command"] = []string{"blah {{user `test-variable`}} blah"}
warns, err := b.Prepare(config) _, warns, err := b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -634,7 +634,7 @@ func TestBuilderPrepare_UseLegacyNetworkAdapter(t *testing.T) {
config["use_legacy_network_adapter"] = true config["use_legacy_network_adapter"] = true
b = Builder{} b = Builder{}
warns, err := b.Prepare(config) _, warns, err := b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }
@ -646,7 +646,7 @@ func TestBuilderPrepare_UseLegacyNetworkAdapter(t *testing.T) {
config["generation"] = 2 config["generation"] = 2
b = Builder{} b = Builder{}
warns, err = b.Prepare(config) _, warns, err = b.Prepare(config)
if len(warns) > 0 { if len(warns) > 0 {
t.Fatalf("bad: %#v", warns) t.Fatalf("bad: %#v", warns)
} }

View File

@ -10,6 +10,7 @@ import (
"os" "os"
"strings" "strings"
"github.com/hashicorp/hcl/v2/hcldec"
hypervcommon "github.com/hashicorp/packer/builder/hyperv/common" hypervcommon "github.com/hashicorp/packer/builder/hyperv/common"
"github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/common/bootcommand" "github.com/hashicorp/packer/common/bootcommand"
@ -77,8 +78,9 @@ type Config struct {
ctx interpolate.Context ctx interpolate.Context
} }
// Prepare processes the build configuration parameters. func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() }
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
err := config.Decode(&b.config, &config.DecodeOpts{ err := config.Decode(&b.config, &config.DecodeOpts{
Interpolate: true, Interpolate: true,
InterpolateContext: &b.config.ctx, InterpolateContext: &b.config.ctx,
@ -89,7 +91,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
}, },
}, raws...) }, raws...)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
// Accumulate any errors and warnings // Accumulate any errors and warnings
@ -204,10 +206,10 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
} }
if errs != nil && len(errs.Errors) > 0 { if errs != nil && len(errs.Errors) > 0 {
return warnings, errs return nil, warnings, errs
} }
return warnings, nil return nil, warnings, nil
} }
// Run executes a Packer build and returns a packer.Artifact representing // Run executes a Packer build and returns a packer.Artifact representing
@ -221,7 +223,6 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
// Set up the state. // Set up the state.
state := new(multistep.BasicStateBag) state := new(multistep.BasicStateBag)
state.Put("config", &b.config)
state.Put("debug", b.config.PackerDebug) state.Put("debug", b.config.PackerDebug)
state.Put("driver", driver) state.Put("driver", driver)
state.Put("hook", hook) state.Put("hook", hook)
@ -235,23 +236,15 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
Force: b.config.PackerForce, Force: b.config.PackerForce,
Path: b.config.OutputDir, Path: b.config.OutputDir,
}, },
} &common.StepDownload{
Checksum: b.config.ISOChecksum,
if b.config.RawSingleISOUrl != "" || len(b.config.ISOUrls) > 0 { ChecksumType: b.config.ISOChecksumType,
steps = append(steps, Description: "ISO",
&common.StepDownload{ ResultKey: "iso_path",
Checksum: b.config.ISOChecksum, Url: b.config.ISOUrls,
ChecksumType: b.config.ISOChecksumType, Extension: b.config.TargetExtension,
Description: "ISO", TargetPath: b.config.TargetPath,
ResultKey: "iso_path", },
Url: b.config.ISOUrls,
Extension: b.config.TargetExtension,
TargetPath: b.config.TargetPath,
},
)
}
steps = append(steps,
&common.StepCreateFloppy{ &common.StepCreateFloppy{
Files: b.config.FloppyFiles, Files: b.config.FloppyFiles,
Directories: b.config.FloppyConfig.FloppyDirectories, Directories: b.config.FloppyConfig.FloppyDirectories,
@ -366,9 +359,9 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
OutputDir: b.config.OutputDir, OutputDir: b.config.OutputDir,
SkipExport: b.config.SkipExport, SkipExport: b.config.SkipExport,
}, },
}
// the clean up actions for each step will be executed reverse order // the clean up actions for each step will be executed reverse order
)
// Run the steps. // Run the steps.
b.runner = common.NewRunner(steps, b.config.PackerConfig, ui) b.runner = common.NewRunner(steps, b.config.PackerConfig, ui)

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