Merge remote-tracking branch 'origin/master' into switch_sed_because_license
This commit is contained in:
commit
0f14077664
|
@ -26,3 +26,4 @@ packer-test*.log
|
|||
Thumbs.db
|
||||
/packer.exe
|
||||
.project
|
||||
cache
|
||||
|
|
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -3,6 +3,8 @@
|
|||
### IMPROVEMENTS:
|
||||
* builder/amazon: Add ability to set `run_volume_tags` [GH-8051]
|
||||
* builder/amazon: Add AWS API call reties on AMI prevalidation [GH-8034]
|
||||
* builder/cloudstack: New step to detach iso. [GH-8106]
|
||||
* builder/googlecompute: Fail fast when image name is invalid. [GH-8112]
|
||||
* builder/hcloud: Allow selecting image based on filters [GH-7945]
|
||||
* builder/hyper-v: Decrease the delay between Hyper-V VM startup and hyper-v
|
||||
builder's ability to send keystrokes to the target VM. [GH-7970]
|
||||
|
@ -12,19 +14,25 @@
|
|||
* builder/ucloud: Make ucloud builder's base url configurable [GH-8095]
|
||||
* builder/virtualbox-vm: Make target snapshot optional [GH-8011] [GH-8004]
|
||||
* builder/yandex: Support GPU instances and set source image by name [GH-8091]
|
||||
* communicator/ssh: Support for SSH port tunneling [GH-7918]
|
||||
* core: Add a new `floppy_label` option [GH-8099]
|
||||
* core: Added version compatibility to console command [GH-8080]
|
||||
* post-processor/vagrant-cloud: Allow blank access_token for private vagrant
|
||||
box hosting [GH-8097]
|
||||
* post-processor/vagrant-cloud: Allow use of the Artifice post-processor with
|
||||
the Vagrant Cloud post-processor [GH-8018] [GH-8027]
|
||||
* post-processor/vsphere: Removed redundant whitelist check for builders,
|
||||
allowing users to use post-processor withough the VMWare builder [GH-8064]
|
||||
|
||||
|
||||
### BUG FIXES:
|
||||
* builder/amazon: Fix FleetID crash [GH-8013]
|
||||
* builder/amazon: Fix FleetID crash. [GH-8013]
|
||||
* builder/amazon: Gracefully handle rate limiting when retrieving winrm
|
||||
password. [GH-8087]
|
||||
* builder/azure: Avoid a panic in getObjectIdFromToken [GH-8047]
|
||||
* builder/googlecompute: Fix crash caused by nil account file. [GH-8102]
|
||||
* builder/hyper-v: Fix when management interface is not part of virtual switch
|
||||
[GH-8017]
|
||||
* builder/openstack: Fix dropped error when creating image client. [GH-8110]
|
||||
* builder/openstack: Fix race condition created when adding metadata [GH-8016]
|
||||
* builder/outscale: Get SSH Host from VM.Nics instead of VM Root [GH-8077]
|
||||
* builder/proxmox: Bump proxmox api dep, fixing bug with checking http status
|
||||
|
@ -33,8 +41,10 @@
|
|||
[GH-8084]
|
||||
* builder/proxmox: Fix panic caused by cancelling build [GH-8067] [GH-8072]
|
||||
* builder/qemu: Fix dropped error when retrieving version [GH-8050]
|
||||
* builder/vagrant: Fix dropped errors in code and tests. [GH-8118]
|
||||
* builder/vagrant: Fix provisioning boxes, define source and output boxes
|
||||
[GH-7957]
|
||||
* builder/vagrant: Fix ssh and package steps to use source syntax. [GH-8125]
|
||||
* builder/vagrant: Use GlobalID when provided [GH-8092]
|
||||
* builder/virtualbox: Fix windows pathing problem for guest additions checksum
|
||||
download. [GH-7996]
|
||||
|
@ -45,6 +55,7 @@
|
|||
* core: Fix handling of booleans where "unset" is a value distinct from
|
||||
"false". [GH-8021]
|
||||
* core: Fix tests that swallowed errors in goroutines [GH-8094]
|
||||
* post-processor/amazon-import: Fix non-default encryption. [GH-8113]
|
||||
* provisioner/ansible: Fix provisioner dropped errors [GH-8045]
|
||||
|
||||
## 1.4.3 (August 14, 2019)
|
||||
|
|
3
Makefile
3
Makefile
|
@ -52,6 +52,7 @@ install-gen-deps: ## Install dependencies for code generation
|
|||
# master.
|
||||
@(cd $(TEMPDIR) && GO111MODULE=on go get github.com/mna/pigeon@master)
|
||||
@(cd $(TEMPDIR) && GO111MODULE=on go get github.com/alvaroloes/enumer@master)
|
||||
@go install ./cmd/struct-markdown
|
||||
|
||||
dev: ## Build and install a development build
|
||||
@grep 'const VersionPrerelease = ""' version/version.go > /dev/null ; if [ $$? -eq 0 ]; then \
|
||||
|
@ -94,6 +95,8 @@ fmt-examples:
|
|||
# generate runs `go generate` to build the dynamically generated
|
||||
# source files.
|
||||
generate: install-gen-deps ## Generate dynamically generated code
|
||||
@echo "==> removing autogenerated markdown..."
|
||||
@find website/source/ -type f | xargs grep -l '^<!-- Code generated' | xargs rm
|
||||
go generate ./...
|
||||
go fmt common/bootcommand/boot_command.go
|
||||
go fmt command/plugin.go
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
# appveyor.yml reference : http://www.appveyor.com/docs/appveyor-yml
|
||||
|
||||
version: "{build}"
|
||||
|
||||
skip_tags: true
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
os: Windows Server 2012 R2
|
||||
|
||||
environment:
|
||||
GOPATH: c:\gopath
|
||||
|
||||
clone_folder: c:\gopath\src\github.com\hashicorp\packer
|
||||
|
||||
install:
|
||||
- set GO111MODULE=off
|
||||
- echo %Path%
|
||||
- go version
|
||||
- go env
|
||||
|
||||
build_script:
|
||||
- git rev-parse HEAD
|
||||
# go test $(go list ./... | grep -v vendor)
|
||||
- ps: |
|
||||
go.exe test -timeout=2m (go.exe list ./... `
|
||||
|? { -not $_.Contains('/vendor/') } `
|
||||
|? { $_ -ne 'github.com/hashicorp/packer/builder/parallels/common' } `
|
||||
|? { $_ -ne 'github.com/hashicorp/packer/provisioner/ansible' })
|
||||
|
||||
test: off
|
||||
|
||||
deploy: off
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package ecs
|
||||
|
||||
import (
|
||||
|
@ -12,11 +14,21 @@ import (
|
|||
|
||||
// Config of alicloud
|
||||
type AlicloudAccessConfig struct {
|
||||
AlicloudAccessKey string `mapstructure:"access_key"`
|
||||
AlicloudSecretKey string `mapstructure:"secret_key"`
|
||||
AlicloudRegion string `mapstructure:"region"`
|
||||
AlicloudSkipValidation bool `mapstructure:"skip_region_validation"`
|
||||
SecurityToken string `mapstructure:"security_token"`
|
||||
// This is the Alicloud access key. It must be provided, but it can also be
|
||||
// sourced from the ALICLOUD_ACCESS_KEY environment variable.
|
||||
AlicloudAccessKey string `mapstructure:"access_key" required:"true"`
|
||||
// This is the Alicloud secret key. It must be provided, but it can also be
|
||||
// sourced from the ALICLOUD_SECRET_KEY environment variable.
|
||||
AlicloudSecretKey string `mapstructure:"secret_key" required:"true"`
|
||||
// This is the Alicloud region. It must be provided, but it can also be
|
||||
// sourced from the ALICLOUD_REGION environment variables.
|
||||
AlicloudRegion string `mapstructure:"region" required:"true"`
|
||||
// The region validation can be skipped if this value is true, the default
|
||||
// value is false.
|
||||
AlicloudSkipValidation bool `mapstructure:"skip_region_validation" required:"false"`
|
||||
// STS access token, can be set through template or by exporting as
|
||||
// environment variable such as `export SECURITY_TOKEN=value`.
|
||||
SecurityToken string `mapstructure:"security_token" required:"false"`
|
||||
|
||||
client *ClientWrapper
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package ecs
|
||||
|
||||
import (
|
||||
|
@ -10,37 +12,187 @@ import (
|
|||
)
|
||||
|
||||
type AlicloudDiskDevice struct {
|
||||
DiskName string `mapstructure:"disk_name"`
|
||||
DiskCategory string `mapstructure:"disk_category"`
|
||||
DiskSize int `mapstructure:"disk_size"`
|
||||
SnapshotId string `mapstructure:"disk_snapshot_id"`
|
||||
Description string `mapstructure:"disk_description"`
|
||||
DeleteWithInstance bool `mapstructure:"disk_delete_with_instance"`
|
||||
Device string `mapstructure:"disk_device"`
|
||||
Encrypted config.Trilean `mapstructure:"disk_encrypted"`
|
||||
// The value of disk name is blank by default. [2,
|
||||
// 128] English or Chinese characters, must begin with an
|
||||
// uppercase/lowercase letter or Chinese character. Can contain numbers,
|
||||
// ., _ and -. The disk name will appear on the console. It cannot
|
||||
// begin with http:// or https://.
|
||||
DiskName string `mapstructure:"disk_name" required:"false"`
|
||||
// Category of the system disk. Optional values
|
||||
// are:
|
||||
// - cloud - general cloud disk
|
||||
// - cloud_efficiency - efficiency cloud disk
|
||||
// - cloud_ssd - cloud SSD
|
||||
DiskCategory string `mapstructure:"disk_category" required:"false"`
|
||||
// Size of the system disk, measured in GiB. Value
|
||||
// range: [20, 500]. The specified value must be equal to or greater
|
||||
// than max{20, ImageSize}. Default value: max{40, ImageSize}.
|
||||
DiskSize int `mapstructure:"disk_size" required:"false"`
|
||||
// Snapshots are used to create the data
|
||||
// disk After this parameter is specified, Size is ignored. The actual
|
||||
// size of the created disk is the size of the specified snapshot.
|
||||
SnapshotId string `mapstructure:"disk_snapshot_id" required:"false"`
|
||||
// The value of disk description is blank by
|
||||
// default. [2, 256] characters. The disk description will appear on the
|
||||
// console. It cannot begin with http:// or https://.
|
||||
Description string `mapstructure:"disk_description" required:"false"`
|
||||
// Whether or not the disk is
|
||||
// released along with the instance:
|
||||
DeleteWithInstance bool `mapstructure:"disk_delete_with_instance" required:"false"`
|
||||
// Device information of the related instance:
|
||||
// such as /dev/xvdb It is null unless the Status is In_use.
|
||||
Device string `mapstructure:"disk_device" required:"false"`
|
||||
// Whether or not to encrypt the data disk.
|
||||
// If this option is set to true, the data disk will be encryped and corresponding snapshot in the target image will also be encrypted. By
|
||||
// default, if this is an extra data disk, Packer will not encrypt the
|
||||
// data disk. Otherwise, Packer will keep the encryption setting to what
|
||||
// it was in the source image. Please refer to Introduction of ECS disk encryption
|
||||
// for more details.
|
||||
Encrypted config.Trilean `mapstructure:"disk_encrypted" required:"false"`
|
||||
}
|
||||
|
||||
type AlicloudDiskDevices struct {
|
||||
ECSSystemDiskMapping AlicloudDiskDevice `mapstructure:"system_disk_mapping"`
|
||||
ECSImagesDiskMappings []AlicloudDiskDevice `mapstructure:"image_disk_mappings"`
|
||||
// Image disk mapping for system
|
||||
// disk.
|
||||
// - `disk_category` (string) - Category of the system disk. Optional values
|
||||
// are:
|
||||
// - `cloud` - general cloud disk
|
||||
// - `cloud_efficiency` - efficiency cloud disk
|
||||
// - `cloud_ssd` - cloud SSD
|
||||
//
|
||||
// For phased-out instance types and non-I/O optimized instances, the
|
||||
// default value is cloud. Otherwise, the default value is
|
||||
// cloud\_efficiency.
|
||||
//
|
||||
// - `disk_description` (string) - The value of disk description is blank by
|
||||
// default. \[2, 256\] characters. The disk description will appear on the
|
||||
// console. It cannot begin with `http://` or `https://`.
|
||||
//
|
||||
// - `disk_name` (string) - The value of disk name is blank by default. \[2,
|
||||
// 128\] English or Chinese characters, must begin with an
|
||||
// uppercase/lowercase letter or Chinese character. Can contain numbers,
|
||||
// `.`, `_` and `-`. The disk name will appear on the console. It cannot
|
||||
// begin with `http://` or `https://`.
|
||||
//
|
||||
// - `disk_size` (number) - Size of the system disk, measured in GiB. Value
|
||||
// range: \[20, 500\]. The specified value must be equal to or greater
|
||||
// than max{20, ImageSize}. Default value: max{40, ImageSize}.
|
||||
//
|
||||
ECSSystemDiskMapping AlicloudDiskDevice `mapstructure:"system_disk_mapping" required:"false"`
|
||||
// Add one or more data
|
||||
// disks to the image.
|
||||
//
|
||||
// - `disk_category` (string) - Category of the data disk. Optional values
|
||||
// are:
|
||||
// - `cloud` - general cloud disk
|
||||
// - `cloud_efficiency` - efficiency cloud disk
|
||||
// - `cloud_ssd` - cloud SSD
|
||||
//
|
||||
// Default value: cloud.
|
||||
//
|
||||
// - `disk_delete_with_instance` (boolean) - Whether or not the disk is
|
||||
// released along with the instance:
|
||||
// - True indicates that when the instance is released, this disk will
|
||||
// be released with it
|
||||
// - False indicates that when the instance is released, this disk will
|
||||
// be retained.
|
||||
// - `disk_description` (string) - The value of disk description is blank by
|
||||
// default. \[2, 256\] characters. The disk description will appear on the
|
||||
// console. It cannot begin with `http://` or `https://`.
|
||||
//
|
||||
// - `disk_device` (string) - Device information of the related instance:
|
||||
// such as `/dev/xvdb` It is null unless the Status is In\_use.
|
||||
//
|
||||
// - `disk_name` (string) - The value of disk name is blank by default. \[2,
|
||||
// 128\] English or Chinese characters, must begin with an
|
||||
// uppercase/lowercase letter or Chinese character. Can contain numbers,
|
||||
// `.`, `_` and `-`. The disk name will appear on the console. It cannot
|
||||
// begin with `http://` or `https://`.
|
||||
//
|
||||
// - `disk_size` (number) - Size of the data disk, in GB, values range:
|
||||
// - `cloud` - 5 \~ 2000
|
||||
// - `cloud_efficiency` - 20 \~ 2048
|
||||
// - `cloud_ssd` - 20 \~ 2048
|
||||
//
|
||||
// The value should be equal to or greater than the size of the specific
|
||||
// SnapshotId.
|
||||
//
|
||||
// - `disk_snapshot_id` (string) - Snapshots are used to create the data
|
||||
// disk After this parameter is specified, Size is ignored. The actual
|
||||
// size of the created disk is the size of the specified snapshot.
|
||||
//
|
||||
// Snapshots from on or before July 15, 2013 cannot be used to create a
|
||||
// disk.
|
||||
//
|
||||
// - `disk_encrypted` (boolean) - Whether or not to encrypt the data disk.
|
||||
// If this option is set to true, the data disk will be encryped and corresponding snapshot in the target image will also be encrypted. By
|
||||
// default, if this is an extra data disk, Packer will not encrypt the
|
||||
// data disk. Otherwise, Packer will keep the encryption setting to what
|
||||
// it was in the source image. Please refer to Introduction of [ECS disk encryption](https://www.alibabacloud.com/help/doc-detail/59643.htm)
|
||||
// for more details.
|
||||
//
|
||||
ECSImagesDiskMappings []AlicloudDiskDevice `mapstructure:"image_disk_mappings" required:"false"`
|
||||
}
|
||||
|
||||
type AlicloudImageConfig struct {
|
||||
AlicloudImageName string `mapstructure:"image_name"`
|
||||
AlicloudImageVersion string `mapstructure:"image_version"`
|
||||
AlicloudImageDescription string `mapstructure:"image_description"`
|
||||
AlicloudImageShareAccounts []string `mapstructure:"image_share_account"`
|
||||
AlicloudImageUNShareAccounts []string `mapstructure:"image_unshare_account"`
|
||||
AlicloudImageDestinationRegions []string `mapstructure:"image_copy_regions"`
|
||||
AlicloudImageDestinationNames []string `mapstructure:"image_copy_names"`
|
||||
ImageEncrypted config.Trilean `mapstructure:"image_encrypted"`
|
||||
AlicloudImageForceDelete bool `mapstructure:"image_force_delete"`
|
||||
AlicloudImageForceDeleteSnapshots bool `mapstructure:"image_force_delete_snapshots"`
|
||||
AlicloudImageForceDeleteInstances bool `mapstructure:"image_force_delete_instances"`
|
||||
AlicloudImageIgnoreDataDisks bool `mapstructure:"image_ignore_data_disks"`
|
||||
AlicloudImageSkipRegionValidation bool `mapstructure:"skip_region_validation"`
|
||||
AlicloudImageTags map[string]string `mapstructure:"tags"`
|
||||
AlicloudDiskDevices `mapstructure:",squash"`
|
||||
// The name of the user-defined image, [2, 128]
|
||||
// English or Chinese characters. It must begin with an uppercase/lowercase
|
||||
// letter or a Chinese character, and may contain numbers, _ or -. It
|
||||
// cannot begin with http:// or https://.
|
||||
AlicloudImageName string `mapstructure:"image_name" required:"true"`
|
||||
// The version number of the image, with a length
|
||||
// limit of 1 to 40 English characters.
|
||||
AlicloudImageVersion string `mapstructure:"image_version" required:"false"`
|
||||
// The description of the image, with a length
|
||||
// limit of 0 to 256 characters. Leaving it blank means null, which is the
|
||||
// default value. It cannot begin with http:// or https://.
|
||||
AlicloudImageDescription string `mapstructure:"image_description" required:"false"`
|
||||
// The IDs of to-be-added Aliyun
|
||||
// accounts to which the image is shared. The number of accounts is 1 to 10.
|
||||
// If number of accounts is greater than 10, this parameter is ignored.
|
||||
AlicloudImageShareAccounts []string `mapstructure:"image_share_account" required:"false"`
|
||||
AlicloudImageUNShareAccounts []string `mapstructure:"image_unshare_account"`
|
||||
// Copy to the destination regionIds.
|
||||
AlicloudImageDestinationRegions []string `mapstructure:"image_copy_regions" required:"false"`
|
||||
// The name of the destination image,
|
||||
// [2, 128] English or Chinese characters. It must begin with an
|
||||
// uppercase/lowercase letter or a Chinese character, and may contain numbers,
|
||||
// _ or -. It cannot begin with http:// or https://.
|
||||
AlicloudImageDestinationNames []string `mapstructure:"image_copy_names" required:"false"`
|
||||
// Whether or not to encrypt the target images, including those copied if image_copy_regions is specified. If this option
|
||||
// is set to true, a temporary image will be created from the provisioned
|
||||
// instance in the main region and an encrypted copy will be generated in the
|
||||
// same region. By default, Packer will keep the encryption setting to what
|
||||
// it was in the source image.
|
||||
ImageEncrypted config.Trilean `mapstructure:"image_encrypted" required:"false"`
|
||||
// If this value is true, when the target image names including those
|
||||
// copied are duplicated with existing images, it will delete the existing
|
||||
// images and then create the target images, otherwise, the creation will
|
||||
// fail. The default value is false. Check `image_name` and
|
||||
// `image_copy_names` options for names of target images. If
|
||||
// [-force](https://packer.io/docs/commands/build.html#force) option is
|
||||
// provided in `build` command, this option can be omitted and taken as
|
||||
// true.
|
||||
AlicloudImageForceDelete bool `mapstructure:"image_force_delete" required:"false"`
|
||||
// If this value is true, when delete the duplicated existing images, the
|
||||
// source snapshots of those images will be delete either. If
|
||||
// [-force](https://packer.io/docs/commands/build.html#force) option is
|
||||
// provided in `build` command, this option can be omitted and taken as
|
||||
// true.
|
||||
AlicloudImageForceDeleteSnapshots bool `mapstructure:"image_force_delete_snapshots" required:"false"`
|
||||
AlicloudImageForceDeleteInstances bool `mapstructure:"image_force_delete_instances"`
|
||||
// If this value is true, the image
|
||||
// created will not include any snapshot of data disks. This option would be
|
||||
// useful for any circumstance that default data disks with instance types are
|
||||
// not concerned. The default value is false.
|
||||
AlicloudImageIgnoreDataDisks bool `mapstructure:"image_ignore_data_disks" required:"false"`
|
||||
// The region validation can be skipped
|
||||
// if this value is true, the default value is false.
|
||||
AlicloudImageSkipRegionValidation bool `mapstructure:"skip_region_validation" required:"false"`
|
||||
// Tags applied to the destination
|
||||
// image and relevant snapshots.
|
||||
AlicloudImageTags map[string]string `mapstructure:"tags" required:"false"`
|
||||
AlicloudDiskDevices `mapstructure:",squash"`
|
||||
}
|
||||
|
||||
func (c *AlicloudImageConfig) Prepare(ctx *interpolate.Context) []error {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package ecs
|
||||
|
||||
import (
|
||||
|
@ -13,31 +15,110 @@ import (
|
|||
)
|
||||
|
||||
type RunConfig struct {
|
||||
AssociatePublicIpAddress bool `mapstructure:"associate_public_ip_address"`
|
||||
ZoneId string `mapstructure:"zone_id"`
|
||||
IOOptimized config.Trilean `mapstructure:"io_optimized"`
|
||||
InstanceType string `mapstructure:"instance_type"`
|
||||
Description string `mapstructure:"description"`
|
||||
AlicloudSourceImage string `mapstructure:"source_image"`
|
||||
ForceStopInstance bool `mapstructure:"force_stop_instance"`
|
||||
DisableStopInstance bool `mapstructure:"disable_stop_instance"`
|
||||
SecurityGroupId string `mapstructure:"security_group_id"`
|
||||
SecurityGroupName string `mapstructure:"security_group_name"`
|
||||
UserData string `mapstructure:"user_data"`
|
||||
UserDataFile string `mapstructure:"user_data_file"`
|
||||
VpcId string `mapstructure:"vpc_id"`
|
||||
VpcName string `mapstructure:"vpc_name"`
|
||||
CidrBlock string `mapstructure:"vpc_cidr_block"`
|
||||
VSwitchId string `mapstructure:"vswitch_id"`
|
||||
VSwitchName string `mapstructure:"vswitch_id"`
|
||||
InstanceName string `mapstructure:"instance_name"`
|
||||
InternetChargeType string `mapstructure:"internet_charge_type"`
|
||||
InternetMaxBandwidthOut int `mapstructure:"internet_max_bandwidth_out"`
|
||||
WaitSnapshotReadyTimeout int `mapstructure:"wait_snapshot_ready_timeout"`
|
||||
|
||||
AssociatePublicIpAddress bool `mapstructure:"associate_public_ip_address"`
|
||||
// ID of the zone to which the disk belongs.
|
||||
ZoneId string `mapstructure:"zone_id" required:"false"`
|
||||
// Whether an ECS instance is I/O optimized or not. If this option is not
|
||||
// provided, the value will be determined by product API according to what
|
||||
// `instance_type` is used.
|
||||
IOOptimized config.Trilean `mapstructure:"io_optimized" required:"false"`
|
||||
// Type of the instance. For values, see [Instance Type
|
||||
// Table](https://www.alibabacloud.com/help/doc-detail/25378.htm?spm=a3c0i.o25499en.a3.9.14a36ac8iYqKRA).
|
||||
// You can also obtain the latest instance type table by invoking the
|
||||
// [Querying Instance Type
|
||||
// Table](https://intl.aliyun.com/help/doc-detail/25620.htm?spm=a3c0i.o25499en.a3.6.Dr1bik)
|
||||
// interface.
|
||||
InstanceType string `mapstructure:"instance_type" required:"true"`
|
||||
Description string `mapstructure:"description"`
|
||||
// This is the base image id which you want to
|
||||
// create your customized images.
|
||||
AlicloudSourceImage string `mapstructure:"source_image" required:"true"`
|
||||
// Whether to force shutdown upon device
|
||||
// restart. The default value is `false`.
|
||||
//
|
||||
// If it is set to `false`, the system is shut down normally; if it is set to
|
||||
// `true`, the system is forced to shut down.
|
||||
ForceStopInstance bool `mapstructure:"force_stop_instance" required:"false"`
|
||||
// If this option is set to true, Packer
|
||||
// will not stop the instance for you, and you need to make sure the instance
|
||||
// will be stopped in the final provisioner command. Otherwise, Packer will
|
||||
// timeout while waiting the instance to be stopped. This option is provided
|
||||
// for some specific scenarios that you want to stop the instance by yourself.
|
||||
// E.g., Sysprep a windows which may shutdown the instance within its command.
|
||||
// The default value is false.
|
||||
DisableStopInstance bool `mapstructure:"disable_stop_instance" required:"false"`
|
||||
// ID of the security group to which a newly
|
||||
// created instance belongs. Mutual access is allowed between instances in one
|
||||
// security group. If not specified, the newly created instance will be added
|
||||
// to the default security group. If the default group doesn’t exist, or the
|
||||
// number of instances in it has reached the maximum limit, a new security
|
||||
// group will be created automatically.
|
||||
SecurityGroupId string `mapstructure:"security_group_id" required:"false"`
|
||||
// The security group name. The default value
|
||||
// is blank. [2, 128] English or Chinese characters, must begin with an
|
||||
// uppercase/lowercase letter or Chinese character. Can contain numbers, .,
|
||||
// _ or -. It cannot begin with http:// or https://.
|
||||
SecurityGroupName string `mapstructure:"security_group_name" required:"false"`
|
||||
// User data to apply when launching the instance. Note
|
||||
// that you need to be careful about escaping characters due to the templates
|
||||
// being JSON. It is often more convenient to use user_data_file, instead.
|
||||
// Packer will not automatically wait for a user script to finish before
|
||||
// shutting down the instance this must be handled in a provisioner.
|
||||
UserData string `mapstructure:"user_data" required:"false"`
|
||||
// Path to a file that will be used for the user
|
||||
// data when launching the instance.
|
||||
UserDataFile string `mapstructure:"user_data_file" required:"false"`
|
||||
// VPC ID allocated by the system.
|
||||
VpcId string `mapstructure:"vpc_id" required:"false"`
|
||||
// The VPC name. The default value is blank. [2, 128]
|
||||
// English or Chinese characters, must begin with an uppercase/lowercase
|
||||
// letter or Chinese character. Can contain numbers, _ and -. The disk
|
||||
// description will appear on the console. Cannot begin with http:// or
|
||||
// https://.
|
||||
VpcName string `mapstructure:"vpc_name" required:"false"`
|
||||
// Value options: 192.168.0.0/16 and
|
||||
// 172.16.0.0/16. When not specified, the default value is 172.16.0.0/16.
|
||||
CidrBlock string `mapstructure:"vpc_cidr_block" required:"false"`
|
||||
// The ID of the VSwitch to be used.
|
||||
VSwitchId string `mapstructure:"vswitch_id" required:"false"`
|
||||
// The ID of the VSwitch to be used.
|
||||
VSwitchName string `mapstructure:"vswitch_name" required:"false"`
|
||||
// Display name of the instance, which is a string of 2 to 128 Chinese or
|
||||
// English characters. It must begin with an uppercase/lowercase letter or
|
||||
// a Chinese character and can contain numerals, `.`, `_`, or `-`. The
|
||||
// instance name is displayed on the Alibaba Cloud console. If this
|
||||
// parameter is not specified, the default value is InstanceId of the
|
||||
// instance. It cannot begin with `http://` or `https://`.
|
||||
InstanceName string `mapstructure:"instance_name" required:"false"`
|
||||
// Internet charge type, which can be
|
||||
// `PayByTraffic` or `PayByBandwidth`. Optional values:
|
||||
// - `PayByBandwidth`
|
||||
// - `PayByTraffic`
|
||||
//
|
||||
// If this parameter is not specified, the default value is `PayByBandwidth`.
|
||||
// For the regions out of China, currently only support `PayByTraffic`, you
|
||||
// must set it manfully.
|
||||
InternetChargeType string `mapstructure:"internet_charge_type" required:"false"`
|
||||
// Maximum outgoing bandwidth to the
|
||||
// public network, measured in Mbps (Mega bits per second).
|
||||
//
|
||||
// Value range:
|
||||
// - `PayByBandwidth`: \[0, 100\]. If this parameter is not specified, API
|
||||
// automatically sets it to 0 Mbps.
|
||||
// - `PayByTraffic`: \[1, 100\]. If this parameter is not specified, an
|
||||
// error is returned.
|
||||
InternetMaxBandwidthOut int `mapstructure:"internet_max_bandwidth_out" required:"false"`
|
||||
// Timeout of creating snapshot(s).
|
||||
// The default timeout is 3600 seconds if this option is not set or is set
|
||||
// to 0. For those disks containing lots of data, it may require a higher
|
||||
// timeout value.
|
||||
WaitSnapshotReadyTimeout int `mapstructure:"wait_snapshot_ready_timeout" required:"false"`
|
||||
// Communicator settings
|
||||
Comm communicator.Config `mapstructure:",squash"`
|
||||
SSHPrivateIp bool `mapstructure:"ssh_private_ip"`
|
||||
Comm communicator.Config `mapstructure:",squash"`
|
||||
// If this value is true, packer will connect to
|
||||
// the ECS created through private ip instead of allocating a public ip or an
|
||||
// EIP. The default value is false.
|
||||
SSHPrivateIp bool `mapstructure:"ssh_private_ip" required:"false"`
|
||||
}
|
||||
|
||||
func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
|
||||
|
|
|
@ -13,7 +13,9 @@ func testConfig() *RunConfig {
|
|||
AlicloudSourceImage: "alicloud_images",
|
||||
InstanceType: "ecs.n1.tiny",
|
||||
Comm: communicator.Config{
|
||||
SSHUsername: "alicloud",
|
||||
SSH: communicator.SSH{
|
||||
SSHUsername: "alicloud",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package chroot
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
awscommon "github.com/hashicorp/packer/builder/amazon/common"
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
type BlockDevice struct {
|
||||
awscommon.BlockDevice `mapstructure:",squash"`
|
||||
// ID, alias or ARN of the KMS key to use for boot volume encryption. This
|
||||
// only applies to the main region, other regions where the AMI will be
|
||||
// copied will be encrypted by the default EBS KMS key. For valid formats
|
||||
// see KmsKeyId in the [AWS API docs -
|
||||
// CopyImage](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CopyImage.html)
|
||||
// This field is validated by Packer, when using an alias, you will have to
|
||||
// prefix kms_key_id with alias/.
|
||||
KmsKeyId string `mapstructure:"kms_key_id" required:"false"`
|
||||
}
|
||||
|
||||
type BlockDevices []BlockDevice
|
||||
|
||||
func (bds BlockDevices) BuildEC2BlockDeviceMappings() []*ec2.BlockDeviceMapping {
|
||||
var blockDevices []*ec2.BlockDeviceMapping
|
||||
|
||||
for _, blockDevice := range bds {
|
||||
blockDevices = append(blockDevices, blockDevice.BuildEC2BlockDeviceMapping())
|
||||
}
|
||||
return blockDevices
|
||||
}
|
||||
|
||||
func (blockDevice BlockDevice) BuildEC2BlockDeviceMapping() *ec2.BlockDeviceMapping {
|
||||
mapping := blockDevice.BlockDevice.BuildEC2BlockDeviceMapping()
|
||||
|
||||
if blockDevice.KmsKeyId != "" {
|
||||
mapping.Ebs.KmsKeyId = aws.String(blockDevice.KmsKeyId)
|
||||
}
|
||||
return mapping
|
||||
}
|
||||
|
||||
func (b *BlockDevice) Prepare(ctx *interpolate.Context) error {
|
||||
err := b.BlockDevice.Prepare(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Warn that encrypted must be true when setting kms_key_id
|
||||
if b.KmsKeyId != "" && b.Encrypted.True() {
|
||||
return fmt.Errorf("The device %v, must also have `encrypted: "+
|
||||
"true` when setting a kms_key_id.", b.DeviceName)
|
||||
}
|
||||
|
||||
_, err = interpolate.RenderInterface(&b, ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
func (bds BlockDevices) Prepare(ctx *interpolate.Context) (errs []error) {
|
||||
for _, block := range bds {
|
||||
if err := block.Prepare(ctx); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
// The chroot package is able to create an Amazon AMI without requiring
|
||||
// the launch of a new instance for every build. It does this by attaching
|
||||
// and mounting the root volume of another AMI and chrooting into that
|
||||
// directory. It then creates an AMI from that attached drive.
|
||||
//go:generate struct-markdown
|
||||
|
||||
// The chroot package is able to create an Amazon AMI without requiring the
|
||||
// launch of a new instance for every build. It does this by attaching and
|
||||
// mounting the root volume of another AMI and chrooting into that directory.
|
||||
// It then creates an AMI from that attached drive.
|
||||
package chroot
|
||||
|
||||
import (
|
||||
|
@ -21,32 +23,147 @@ import (
|
|||
// The unique ID for this builder
|
||||
const BuilderId = "mitchellh.amazon.chroot"
|
||||
|
||||
// Config is the configuration that is chained through the steps and
|
||||
// settable from the template.
|
||||
// Config is the configuration that is chained through the steps and settable
|
||||
// from the template.
|
||||
type Config struct {
|
||||
common.PackerConfig `mapstructure:",squash"`
|
||||
awscommon.AMIBlockDevices `mapstructure:",squash"`
|
||||
awscommon.AMIConfig `mapstructure:",squash"`
|
||||
awscommon.AccessConfig `mapstructure:",squash"`
|
||||
|
||||
ChrootMounts [][]string `mapstructure:"chroot_mounts"`
|
||||
CommandWrapper string `mapstructure:"command_wrapper"`
|
||||
CopyFiles []string `mapstructure:"copy_files"`
|
||||
DevicePath string `mapstructure:"device_path"`
|
||||
NVMEDevicePath string `mapstructure:"nvme_device_path"`
|
||||
FromScratch bool `mapstructure:"from_scratch"`
|
||||
MountOptions []string `mapstructure:"mount_options"`
|
||||
MountPartition string `mapstructure:"mount_partition"`
|
||||
MountPath string `mapstructure:"mount_path"`
|
||||
PostMountCommands []string `mapstructure:"post_mount_commands"`
|
||||
PreMountCommands []string `mapstructure:"pre_mount_commands"`
|
||||
RootDeviceName string `mapstructure:"root_device_name"`
|
||||
RootVolumeSize int64 `mapstructure:"root_volume_size"`
|
||||
RootVolumeType string `mapstructure:"root_volume_type"`
|
||||
SourceAmi string `mapstructure:"source_ami"`
|
||||
SourceAmiFilter awscommon.AmiFilterOptions `mapstructure:"source_ami_filter"`
|
||||
RootVolumeTags awscommon.TagMap `mapstructure:"root_volume_tags"`
|
||||
Architecture string `mapstructure:"ami_architecture"`
|
||||
common.PackerConfig `mapstructure:",squash"`
|
||||
awscommon.AMIConfig `mapstructure:",squash"`
|
||||
awscommon.AccessConfig `mapstructure:",squash"`
|
||||
// Add one or more [block device
|
||||
// mappings](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/block-device-mapping-concepts.html)
|
||||
// to the AMI. If this field is populated, and you are building from an
|
||||
// existing source image, the block device mappings in the source image
|
||||
// will be overwritten. This means you must have a block device mapping
|
||||
// entry for your root volume, `root_volume_size` and `root_device_name`.
|
||||
// See the [BlockDevices](#block-devices-configuration) documentation for
|
||||
// fields.
|
||||
AMIMappings BlockDevices `mapstructure:"ami_block_device_mappings" required:"false"`
|
||||
// This is a list of devices to mount into the chroot environment. This
|
||||
// configuration parameter requires some additional documentation which is
|
||||
// in the Chroot Mounts section. Please read that section for more
|
||||
// information on how to use this.
|
||||
ChrootMounts [][]string `mapstructure:"chroot_mounts" required:"false"`
|
||||
// How to run shell commands. This defaults to {{.Command}}. This may be
|
||||
// useful to set if you want to set environmental variables or perhaps run
|
||||
// it with sudo or so on. This is a configuration template where the
|
||||
// .Command variable is replaced with the command to be run. Defaults to
|
||||
// {{.Command}}.
|
||||
CommandWrapper string `mapstructure:"command_wrapper" required:"false"`
|
||||
// Paths to files on the running EC2 instance that will be copied into the
|
||||
// chroot environment prior to provisioning. Defaults to /etc/resolv.conf
|
||||
// so that DNS lookups work. Pass an empty list to skip copying
|
||||
// /etc/resolv.conf. You may need to do this if you're building an image
|
||||
// that uses systemd.
|
||||
CopyFiles []string `mapstructure:"copy_files" required:"false"`
|
||||
// The path to the device where the root volume of the source AMI will be
|
||||
// attached. This defaults to "" (empty string), which forces Packer to
|
||||
// find an open device automatically.
|
||||
DevicePath string `mapstructure:"device_path" required:"false"`
|
||||
// When we call the mount command (by default mount -o device dir), the
|
||||
// string provided in nvme_mount_path will replace device in that command.
|
||||
// When this option is not set, device in that command will be something
|
||||
// like /dev/sdf1, mirroring the attached device name. This assumption
|
||||
// works for most instances but will fail with c5 and m5 instances. In
|
||||
// order to use the chroot builder with c5 and m5 instances, you must
|
||||
// manually set nvme_device_path and device_path.
|
||||
NVMEDevicePath string `mapstructure:"nvme_device_path" required:"false"`
|
||||
// Build a new volume instead of starting from an existing AMI root volume
|
||||
// snapshot. Default false. If true, source_ami is no longer used and the
|
||||
// following options become required: ami_virtualization_type,
|
||||
// pre_mount_commands and root_volume_size. The below options are also
|
||||
// required in this mode only:
|
||||
FromScratch bool `mapstructure:"from_scratch" required:"false"`
|
||||
// Options to supply the mount command when mounting devices. Each option
|
||||
// will be prefixed with -o and supplied to the mount command ran by
|
||||
// Packer. Because this command is ran in a shell, user discretion is
|
||||
// advised. See this manual page for the mount command for valid file
|
||||
// system specific options.
|
||||
MountOptions []string `mapstructure:"mount_options" required:"false"`
|
||||
// The partition number containing the / partition. By default this is the
|
||||
// first partition of the volume, (for example, xvda1) but you can
|
||||
// designate the entire block device by setting "mount_partition": "0" in
|
||||
// your config, which will mount xvda instead.
|
||||
MountPartition string `mapstructure:"mount_partition" required:"false"`
|
||||
// The path where the volume will be mounted. This is where the chroot
|
||||
// environment will be. This defaults to
|
||||
// /mnt/packer-amazon-chroot-volumes/{{.Device}}. This is a configuration
|
||||
// template where the .Device variable is replaced with the name of the
|
||||
// device where the volume is attached.
|
||||
MountPath string `mapstructure:"mount_path" required:"false"`
|
||||
// As pre_mount_commands, but the commands are executed after mounting the
|
||||
// root device and before the extra mount and copy steps. The device and
|
||||
// mount path are provided by {{.Device}} and {{.MountPath}}.
|
||||
PostMountCommands []string `mapstructure:"post_mount_commands" required:"false"`
|
||||
// A series of commands to execute after attaching the root volume and
|
||||
// before mounting the chroot. This is not required unless using
|
||||
// from_scratch. If so, this should include any partitioning and filesystem
|
||||
// creation commands. The path to the device is provided by {{.Device}}.
|
||||
PreMountCommands []string `mapstructure:"pre_mount_commands" required:"false"`
|
||||
// The root device name. For example, xvda.
|
||||
RootDeviceName string `mapstructure:"root_device_name" required:"false"`
|
||||
// The size of the root volume in GB for the chroot environment and the
|
||||
// resulting AMI. Default size is the snapshot size of the source_ami
|
||||
// unless from_scratch is true, in which case this field must be defined.
|
||||
RootVolumeSize int64 `mapstructure:"root_volume_size" required:"false"`
|
||||
// The type of EBS volume for the chroot environment and resulting AMI. The
|
||||
// default value is the type of the source_ami, unless from_scratch is
|
||||
// true, in which case the default value is gp2. You can only specify io1
|
||||
// if building based on top of a source_ami which is also io1.
|
||||
RootVolumeType string `mapstructure:"root_volume_type" required:"false"`
|
||||
// The source AMI whose root volume will be copied and provisioned on the
|
||||
// currently running instance. This must be an EBS-backed AMI with a root
|
||||
// volume snapshot that you have access to. Note: this is not used when
|
||||
// from_scratch is set to true.
|
||||
SourceAmi string `mapstructure:"source_ami" required:"true"`
|
||||
// Filters used to populate the source_ami field. Example:
|
||||
//
|
||||
//
|
||||
// ``` json
|
||||
// {
|
||||
// "source_ami_filter": {
|
||||
// "filters": {
|
||||
// "virtualization-type": "hvm",
|
||||
// "name": "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*",
|
||||
// "root-device-type": "ebs"
|
||||
// },
|
||||
// "owners": ["099720109477"],
|
||||
// "most_recent": true
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// This selects the most recent Ubuntu 16.04 HVM EBS AMI from Canonical. NOTE:
|
||||
// This will fail unless *exactly* one AMI is returned. In the above example,
|
||||
// `most_recent` will cause this to succeed by selecting the newest image.
|
||||
//
|
||||
// - `filters` (map of strings) - filters used to select a `source_ami`.
|
||||
// NOTE: This will fail unless *exactly* one AMI is returned. Any filter
|
||||
// described in the docs for
|
||||
// [DescribeImages](http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeImages.html)
|
||||
// is valid.
|
||||
//
|
||||
// - `owners` (array of strings) - Filters the images by their owner. You
|
||||
// may specify one or more AWS account IDs, "self" (which will use the
|
||||
// account whose credentials you are using to run Packer), or an AWS owner
|
||||
// alias: for example, "amazon", "aws-marketplace", or "microsoft". This
|
||||
// option is required for security reasons.
|
||||
//
|
||||
// - `most_recent` (boolean) - Selects the newest created image when true.
|
||||
// This is most useful for selecting a daily distro build.
|
||||
//
|
||||
// You may set this in place of `source_ami` or in conjunction with it. If you
|
||||
// set this in conjunction with `source_ami`, the `source_ami` will be added
|
||||
// to the filter. The provided `source_ami` must meet all of the filtering
|
||||
// criteria provided in `source_ami_filter`; this pins the AMI returned by the
|
||||
// filter, but will cause Packer to fail if the `source_ami` does not exist.
|
||||
SourceAmiFilter awscommon.AmiFilterOptions `mapstructure:"source_ami_filter" required:"false"`
|
||||
// Tags to apply to the volumes that are *launched*. This is a [template
|
||||
// engine](/docs/templates/engine.html), see [Build template
|
||||
// data](#build-template-data) for more information.
|
||||
RootVolumeTags awscommon.TagMap `mapstructure:"root_volume_tags" required:"false"`
|
||||
// what architecture to use when registering the final AMI; valid options
|
||||
// are "x86_64" or "arm64". Defaults to "x86_64".
|
||||
Architecture string `mapstructure:"ami_architecture" required:"false"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
@ -171,8 +288,8 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
|||
}
|
||||
if len(b.config.AMIMappings) > 0 && b.config.RootDeviceName != "" {
|
||||
if b.config.RootVolumeSize == 0 {
|
||||
// Although, they can specify the device size in the block device mapping, it's easier to
|
||||
// be specific here.
|
||||
// Although, they can specify the device size in the block
|
||||
// device mapping, it's easier to be specific here.
|
||||
errs = packer.MultiErrorAppend(
|
||||
errs, errors.New("root_volume_size is required if ami_block_device_mappings is specified"))
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ func buildBaseRegisterOpts(config *Config, sourceImage *ec2.Image, rootVolumeSiz
|
|||
|
||||
generatingNewBlockDeviceMappings := config.FromScratch || len(config.AMIMappings) > 0
|
||||
if generatingNewBlockDeviceMappings {
|
||||
mappings = config.AMIBlockDevices.BuildAMIDevices()
|
||||
mappings = config.AMIMappings.BuildEC2BlockDeviceMappings()
|
||||
rootDeviceName = config.RootDeviceName
|
||||
} else {
|
||||
// If config.FromScratch is false, source image must be set
|
||||
|
|
|
@ -92,12 +92,10 @@ func TestStepRegisterAmi_buildRegisterOptsFromScratch(t *testing.T) {
|
|||
config := Config{
|
||||
FromScratch: true,
|
||||
PackerConfig: common.PackerConfig{},
|
||||
AMIBlockDevices: amazon.AMIBlockDevices{
|
||||
AMIMappings: []amazon.BlockDevice{
|
||||
{
|
||||
DeviceName: rootDeviceName,
|
||||
},
|
||||
},
|
||||
AMIMappings: []BlockDevice{
|
||||
{BlockDevice: amazon.BlockDevice{
|
||||
DeviceName: rootDeviceName,
|
||||
}},
|
||||
},
|
||||
RootDeviceName: rootDeviceName,
|
||||
}
|
||||
|
@ -169,12 +167,10 @@ func TestStepRegisterAmi_buildRegisterOptFromExistingImageWithBlockDeviceMapping
|
|||
config := Config{
|
||||
FromScratch: false,
|
||||
PackerConfig: common.PackerConfig{},
|
||||
AMIBlockDevices: amazon.AMIBlockDevices{
|
||||
AMIMappings: []amazon.BlockDevice{
|
||||
{
|
||||
DeviceName: rootDeviceName,
|
||||
},
|
||||
},
|
||||
AMIMappings: []BlockDevice{
|
||||
{BlockDevice: amazon.BlockDevice{
|
||||
DeviceName: rootDeviceName,
|
||||
}},
|
||||
},
|
||||
RootDeviceName: rootDeviceName,
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
|
@ -19,9 +21,18 @@ import (
|
|||
)
|
||||
|
||||
type VaultAWSEngineOptions struct {
|
||||
Name string `mapstructure:"name"`
|
||||
RoleARN string `mapstructure:"role_arn"`
|
||||
TTL string `mapstructure:"ttl"`
|
||||
Name string `mapstructure:"name"`
|
||||
RoleARN string `mapstructure:"role_arn"`
|
||||
// Specifies the TTL for the use of the STS token. This
|
||||
// is specified as a string with a duration suffix. Valid only when
|
||||
// credential_type is assumed_role or federation_token. When not
|
||||
// specified, the default_sts_ttl set for the role will be used. If that
|
||||
// is also not set, then the default value of 3600s will be used. AWS
|
||||
// places limits on the maximum TTL allowed. See the AWS documentation on
|
||||
// the DurationSeconds parameter for AssumeRole (for assumed_role
|
||||
// credential types) and GetFederationToken (for federation_token
|
||||
// credential types) for more details.
|
||||
TTL string `mapstructure:"ttl" required:"false"`
|
||||
EngineName string `mapstructure:"engine_name"`
|
||||
}
|
||||
|
||||
|
@ -32,19 +43,85 @@ func (v *VaultAWSEngineOptions) Empty() bool {
|
|||
|
||||
// AccessConfig is for common configuration related to AWS access
|
||||
type AccessConfig struct {
|
||||
AccessKey string `mapstructure:"access_key"`
|
||||
CustomEndpointEc2 string `mapstructure:"custom_endpoint_ec2"`
|
||||
DecodeAuthZMessages bool `mapstructure:"decode_authorization_messages"`
|
||||
InsecureSkipTLSVerify bool `mapstructure:"insecure_skip_tls_verify"`
|
||||
MFACode string `mapstructure:"mfa_code"`
|
||||
ProfileName string `mapstructure:"profile"`
|
||||
RawRegion string `mapstructure:"region"`
|
||||
SecretKey string `mapstructure:"secret_key"`
|
||||
SkipValidation bool `mapstructure:"skip_region_validation"`
|
||||
SkipMetadataApiCheck bool `mapstructure:"skip_metadata_api_check"`
|
||||
Token string `mapstructure:"token"`
|
||||
session *session.Session
|
||||
VaultAWSEngine VaultAWSEngineOptions `mapstructure:"vault_aws_engine"`
|
||||
// The access key used to communicate with AWS. [Learn how to set this]
|
||||
// (/docs/builders/amazon.html#specifying-amazon-credentials). On EBS, this
|
||||
// is not required if you are using `use_vault_aws_engine` for
|
||||
// authentication instead.
|
||||
AccessKey string `mapstructure:"access_key" required:"true"`
|
||||
// This option is useful if you use a cloud
|
||||
// provider whose API is compatible with aws EC2. Specify another endpoint
|
||||
// like this https://ec2.custom.endpoint.com.
|
||||
CustomEndpointEc2 string `mapstructure:"custom_endpoint_ec2" required:"false"`
|
||||
// Enable automatic decoding of any encoded authorization (error) messages
|
||||
// using the `sts:DecodeAuthorizationMessage` API. Note: requires that the
|
||||
// effective user/role have permissions to `sts:DecodeAuthorizationMessage`
|
||||
// on resource `*`. Default `false`.
|
||||
DecodeAuthZMessages bool `mapstructure:"decode_authorization_messages" required:"false"`
|
||||
// This allows skipping TLS
|
||||
// verification of the AWS EC2 endpoint. The default is false.
|
||||
InsecureSkipTLSVerify bool `mapstructure:"insecure_skip_tls_verify" required:"false"`
|
||||
// The MFA
|
||||
// [TOTP](https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm)
|
||||
// code. This should probably be a user variable since it changes all the
|
||||
// time.
|
||||
MFACode string `mapstructure:"mfa_code" required:"false"`
|
||||
// The profile to use in the shared credentials file for
|
||||
// AWS. See Amazon's documentation on [specifying
|
||||
// profiles](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-profiles)
|
||||
// for more details.
|
||||
ProfileName string `mapstructure:"profile" required:"false"`
|
||||
// The name of the region, such as `us-east-1`, in which
|
||||
// to launch the EC2 instance to create the AMI.
|
||||
// When chroot building, this value is guessed from environment.
|
||||
RawRegion string `mapstructure:"region" required:"true"`
|
||||
// The secret key used to communicate with AWS. [Learn how to set
|
||||
// this](amazon.html#specifying-amazon-credentials). This is not required
|
||||
// if you are using `use_vault_aws_engine` for authentication instead.
|
||||
SecretKey string `mapstructure:"secret_key" required:"true"`
|
||||
// Set to true if you want to skip
|
||||
// validation of the ami_regions configuration option. Default false.
|
||||
SkipValidation bool `mapstructure:"skip_region_validation" required:"false"`
|
||||
SkipMetadataApiCheck bool `mapstructure:"skip_metadata_api_check"`
|
||||
// The access token to use. This is different from the
|
||||
// access key and secret key. If you're not sure what this is, then you
|
||||
// probably don't need it. This will also be read from the AWS_SESSION_TOKEN
|
||||
// environmental variable.
|
||||
Token string `mapstructure:"token" required:"false"`
|
||||
session *session.Session
|
||||
// Get credentials from Hashicorp Vault's aws secrets engine. You must
|
||||
// already have created a role to use. For more information about
|
||||
// generating credentials via the Vault engine, see the [Vault
|
||||
// docs.](https://www.vaultproject.io/api/secret/aws/index.html#generate-credentials)
|
||||
// If you set this flag, you must also set the below options:
|
||||
// - `name` (string) - Required. Specifies the name of the role to generate
|
||||
// credentials against. This is part of the request URL.
|
||||
// - `engine_name` (string) - The name of the aws secrets engine. In the
|
||||
// Vault docs, this is normally referred to as "aws", and Packer will
|
||||
// default to "aws" if `engine_name` is not set.
|
||||
// - `role_arn` (string)- The ARN of the role to assume if credential\_type
|
||||
// on the Vault role is assumed\_role. Must match one of the allowed role
|
||||
// ARNs in the Vault role. Optional if the Vault role only allows a single
|
||||
// AWS role ARN; required otherwise.
|
||||
// - `ttl` (string) - Specifies the TTL for the use of the STS token. This
|
||||
// is specified as a string with a duration suffix. Valid only when
|
||||
// credential\_type is assumed\_role or federation\_token. When not
|
||||
// specified, the default\_sts\_ttl set for the role will be used. If that
|
||||
// is also not set, then the default value of 3600s will be used. AWS
|
||||
// places limits on the maximum TTL allowed. See the AWS documentation on
|
||||
// the DurationSeconds parameter for AssumeRole (for assumed\_role
|
||||
// credential types) and GetFederationToken (for federation\_token
|
||||
// credential types) for more details.
|
||||
//
|
||||
// ``` json
|
||||
// {
|
||||
// "vault_aws_engine": {
|
||||
// "name": "myrole",
|
||||
// "role_arn": "myarn",
|
||||
// "ttl": "3600s"
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
VaultAWSEngine VaultAWSEngineOptions `mapstructure:"vault_aws_engine" required:"false"`
|
||||
|
||||
getEC2Connection func() ec2iface.EC2API
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
|
@ -11,26 +13,116 @@ import (
|
|||
|
||||
// AMIConfig is for common configuration related to creating AMIs.
|
||||
type AMIConfig struct {
|
||||
AMIName string `mapstructure:"ami_name"`
|
||||
AMIDescription string `mapstructure:"ami_description"`
|
||||
AMIVirtType string `mapstructure:"ami_virtualization_type"`
|
||||
AMIUsers []string `mapstructure:"ami_users"`
|
||||
AMIGroups []string `mapstructure:"ami_groups"`
|
||||
AMIProductCodes []string `mapstructure:"ami_product_codes"`
|
||||
AMIRegions []string `mapstructure:"ami_regions"`
|
||||
AMISkipRegionValidation bool `mapstructure:"skip_region_validation"`
|
||||
AMITags TagMap `mapstructure:"tags"`
|
||||
AMIENASupport config.Trilean `mapstructure:"ena_support"`
|
||||
AMISriovNetSupport bool `mapstructure:"sriov_support"`
|
||||
AMIForceDeregister bool `mapstructure:"force_deregister"`
|
||||
AMIForceDeleteSnapshot bool `mapstructure:"force_delete_snapshot"`
|
||||
AMIEncryptBootVolume config.Trilean `mapstructure:"encrypt_boot"`
|
||||
AMIKmsKeyId string `mapstructure:"kms_key_id"`
|
||||
AMIRegionKMSKeyIDs map[string]string `mapstructure:"region_kms_key_ids"`
|
||||
SnapshotTags TagMap `mapstructure:"snapshot_tags"`
|
||||
SnapshotUsers []string `mapstructure:"snapshot_users"`
|
||||
SnapshotGroups []string `mapstructure:"snapshot_groups"`
|
||||
AMISkipBuildRegion bool `mapstructure:"skip_save_build_region"`
|
||||
// The name of the resulting AMI that will appear when managing AMIs in the
|
||||
// AWS console or via APIs. This must be unique. To help make this unique,
|
||||
// use a function like timestamp (see [template
|
||||
// engine](../templates/engine.html) for more info).
|
||||
AMIName string `mapstructure:"ami_name" required:"true"`
|
||||
// The description to set for the resulting
|
||||
// AMI(s). By default this description is empty. This is a template
|
||||
// engine, see Build template
|
||||
// data for more information.
|
||||
AMIDescription string `mapstructure:"ami_description" required:"false"`
|
||||
// The description to set for the resulting AMI(s). By default this
|
||||
// description is empty. This is a [template
|
||||
// engine](../templates/engine.html), see [Build template
|
||||
// data](#build-template-data) for more information.
|
||||
AMIVirtType string `mapstructure:"ami_virtualization_type" required:"false"`
|
||||
// A list of account IDs that have access to
|
||||
// launch the resulting AMI(s). By default no additional users other than the
|
||||
// user creating the AMI has permissions to launch it.
|
||||
AMIUsers []string `mapstructure:"ami_users" required:"false"`
|
||||
// A list of groups that have access to
|
||||
// launch the resulting AMI(s). By default no groups have permission to launch
|
||||
// the AMI. all will make the AMI publicly accessible.
|
||||
AMIGroups []string `mapstructure:"ami_groups" required:"false"`
|
||||
// A list of product codes to
|
||||
// associate with the AMI. By default no product codes are associated with the
|
||||
// AMI.
|
||||
AMIProductCodes []string `mapstructure:"ami_product_codes" required:"false"`
|
||||
// A list of regions to copy the AMI to.
|
||||
// Tags and attributes are copied along with the AMI. AMI copying takes time
|
||||
// depending on the size of the AMI, but will generally take many minutes.
|
||||
AMIRegions []string `mapstructure:"ami_regions" required:"false"`
|
||||
// Set to true if you want to skip
|
||||
// validation of the ami_regions configuration option. Default false.
|
||||
AMISkipRegionValidation bool `mapstructure:"skip_region_validation" required:"false"`
|
||||
// Tags applied to the AMI. This is a
|
||||
// [template engine](/docs/templates/engine.html), see [Build template
|
||||
// data](#build-template-data) for more information.
|
||||
AMITags TagMap `mapstructure:"tags" required:"false"`
|
||||
// Enable enhanced networking (ENA but not SriovNetSupport) on
|
||||
// HVM-compatible AMIs. If set, add `ec2:ModifyInstanceAttribute` to your
|
||||
// AWS IAM policy.
|
||||
//
|
||||
// Note: you must make sure enhanced networking is enabled on your
|
||||
// instance. See [Amazon's documentation on enabling enhanced
|
||||
// networking](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking.html#enabling_enhanced_networking).
|
||||
AMIENASupport config.Trilean `mapstructure:"ena_support" required:"false"`
|
||||
// Enable enhanced networking (SriovNetSupport but not ENA) on
|
||||
// HVM-compatible AMIs. If true, add `ec2:ModifyInstanceAttribute` to your
|
||||
// AWS IAM policy. Note: you must make sure enhanced networking is enabled
|
||||
// on your instance. See [Amazon's documentation on enabling enhanced
|
||||
// networking](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking.html#enabling_enhanced_networking).
|
||||
// Default `false`.
|
||||
AMISriovNetSupport bool `mapstructure:"sriov_support" required:"false"`
|
||||
// Force Packer to first deregister an existing
|
||||
// AMI if one with the same name already exists. Default false.
|
||||
AMIForceDeregister bool `mapstructure:"force_deregister" required:"false"`
|
||||
// Force Packer to delete snapshots
|
||||
// associated with AMIs, which have been deregistered by force_deregister.
|
||||
// Default false.
|
||||
AMIForceDeleteSnapshot bool `mapstructure:"force_delete_snapshot" required:"false"`
|
||||
// Whether or not to encrypt the resulting AMI when
|
||||
// copying a provisioned instance to an AMI. By default, Packer will keep the
|
||||
// encryption setting to what it was in the source image. Setting false will
|
||||
// result in an unencrypted image, and true will result in an encrypted one.
|
||||
AMIEncryptBootVolume config.Trilean `mapstructure:"encrypt_boot" required:"false"`
|
||||
// ID, alias or ARN of the KMS key to use for boot volume encryption. This
|
||||
// only applies to the main `region`, other regions where the AMI will be
|
||||
// copied will be encrypted by the default EBS KMS key. For valid formats
|
||||
// see *KmsKeyId* in the [AWS API docs -
|
||||
// CopyImage](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CopyImage.html).
|
||||
// This field is validated by Packer, when using an alias, you will have to
|
||||
// prefix `kms_key_id` with `alias/`.
|
||||
AMIKmsKeyId string `mapstructure:"kms_key_id" required:"false"`
|
||||
// regions to copy the ami to, along with the custom kms key id (alias or
|
||||
// arn) to use for encryption for that region. Keys must match the regions
|
||||
// provided in `ami_regions`. If you just want to encrypt using a default
|
||||
// ID, you can stick with `kms_key_id` and `ami_regions`. If you want a
|
||||
// region to be encrypted with that region's default key ID, you can use an
|
||||
// empty string `""` instead of a key id in this map. (e.g. `"us-east-1":
|
||||
// ""`) However, you cannot use default key IDs if you are using this in
|
||||
// conjunction with `snapshot_users` -- in that situation you must use
|
||||
// custom keys. For valid formats see *KmsKeyId* in the [AWS API docs -
|
||||
// CopyImage](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CopyImage.html).
|
||||
//
|
||||
// This option supercedes the `kms_key_id` option -- if you set both, and
|
||||
// they are different, Packer will respect the value in
|
||||
// `region_kms_key_ids` for your build region and silently disregard the
|
||||
// value provided in `kms_key_id`.
|
||||
AMIRegionKMSKeyIDs map[string]string `mapstructure:"region_kms_key_ids" required:"false"`
|
||||
// If true, Packer will not check whether an AMI with the `ami_name` exists
|
||||
// in the region it is building in. It will use an intermediary AMI name,
|
||||
// which it will not convert to an AMI in the build region. It will copy
|
||||
// the intermediary AMI into any regions provided in `ami_regions`, then
|
||||
// delete the intermediary AMI. Default `false`.
|
||||
AMISkipBuildRegion bool `mapstructure:"skip_save_build_region"`
|
||||
// Tags to apply to snapshot.
|
||||
// They will override AMI tags if already applied to snapshot. This is a
|
||||
// [template engine](../templates/engine.html), see [Build template
|
||||
// data](#build-template-data) for more information.
|
||||
SnapshotTags TagMap `mapstructure:"snapshot_tags" required:"false"`
|
||||
// A list of account IDs that have
|
||||
// access to create volumes from the snapshot(s). By default no additional
|
||||
// users other than the user creating the AMI has permissions to create
|
||||
// volumes from the backing snapshot(s).
|
||||
SnapshotUsers []string `mapstructure:"snapshot_users" required:"false"`
|
||||
// A list of groups that have access to
|
||||
// create volumes from the snapshot(s). By default no groups have permission
|
||||
// to create volumes from the snapshot(s). all will make the snapshot
|
||||
// publicly accessible.
|
||||
SnapshotGroups []string `mapstructure:"snapshot_groups" required:"false"`
|
||||
}
|
||||
|
||||
func stringInSlice(s []string, searchstr string) bool {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
|
@ -10,86 +12,121 @@ import (
|
|||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
// BlockDevice
|
||||
// These will be attached when booting a new instance from your AMI. Your
|
||||
// options here may vary depending on the type of VM you use. Example value:
|
||||
//
|
||||
// ``` json
|
||||
// [{
|
||||
// "device_name":"xvda",
|
||||
// "delete_on_termination":true,
|
||||
// "volume_type":"gp2"
|
||||
// }]
|
||||
// ```
|
||||
// Documentation for Block Devices Mappings can be found here:
|
||||
// https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/block-device-mapping-concepts.html
|
||||
type BlockDevice struct {
|
||||
DeleteOnTermination bool `mapstructure:"delete_on_termination"`
|
||||
DeviceName string `mapstructure:"device_name"`
|
||||
Encrypted config.Trilean `mapstructure:"encrypted"`
|
||||
IOPS int64 `mapstructure:"iops"`
|
||||
NoDevice bool `mapstructure:"no_device"`
|
||||
SnapshotId string `mapstructure:"snapshot_id"`
|
||||
VirtualName string `mapstructure:"virtual_name"`
|
||||
VolumeType string `mapstructure:"volume_type"`
|
||||
VolumeSize int64 `mapstructure:"volume_size"`
|
||||
KmsKeyId string `mapstructure:"kms_key_id"`
|
||||
// ebssurrogate only
|
||||
OmitFromArtifact bool `mapstructure:"omit_from_artifact"`
|
||||
// Indicates whether the EBS volume is deleted on instance termination.
|
||||
// Default false. NOTE: If this value is not explicitly set to true and
|
||||
// volumes are not cleaned up by an alternative method, additional volumes
|
||||
// will accumulate after every build.
|
||||
DeleteOnTermination bool `mapstructure:"delete_on_termination" required:"false"`
|
||||
// The device name exposed to the instance (for example, /dev/sdh or xvdh).
|
||||
// Required for every device in the block device mapping.
|
||||
DeviceName string `mapstructure:"device_name" required:"false"`
|
||||
// Indicates whether or not to encrypt the volume. By default, Packer will
|
||||
// keep the encryption setting to what it was in the source image. Setting
|
||||
// false will result in an unencrypted device, and true will result in an
|
||||
// encrypted one.
|
||||
Encrypted config.Trilean `mapstructure:"encrypted" required:"false"`
|
||||
// The number of I/O operations per second (IOPS) that the volume supports.
|
||||
// See the documentation on
|
||||
// [IOPs](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_EbsBlockDevice.html)
|
||||
// for more information
|
||||
IOPS int64 `mapstructure:"iops" required:"false"`
|
||||
// Suppresses the specified device included in the block device mapping of
|
||||
// the AMI.
|
||||
NoDevice bool `mapstructure:"no_device" required:"false"`
|
||||
// The ID of the snapshot.
|
||||
SnapshotId string `mapstructure:"snapshot_id" required:"false"`
|
||||
// The virtual device name. See the documentation on Block Device Mapping
|
||||
// for more information.
|
||||
VirtualName string `mapstructure:"virtual_name" required:"false"`
|
||||
// The volume type. gp2 for General Purpose (SSD) volumes, io1 for
|
||||
// Provisioned IOPS (SSD) volumes, st1 for Throughput Optimized HDD, sc1
|
||||
// for Cold HDD, and standard for Magnetic volumes.
|
||||
VolumeType string `mapstructure:"volume_type" required:"false"`
|
||||
// The size of the volume, in GiB. Required if not specifying a
|
||||
// snapshot_id.
|
||||
VolumeSize int64 `mapstructure:"volume_size" required:"false"`
|
||||
// ID, alias or ARN of the KMS key to use for boot volume encryption. This
|
||||
// only applies to the main region, other regions where the AMI will be
|
||||
// copied will be encrypted by the default EBS KMS key. For valid formats
|
||||
// see KmsKeyId in the [AWS API docs -
|
||||
// CopyImage](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CopyImage.html)
|
||||
// This field is validated by Packer, when using an alias, you will have to
|
||||
// prefix kms_key_id with alias/.
|
||||
KmsKeyId string `mapstructure:"kms_key_id" required:"false"`
|
||||
}
|
||||
|
||||
type BlockDevices struct {
|
||||
AMIBlockDevices `mapstructure:",squash"`
|
||||
LaunchBlockDevices `mapstructure:",squash"`
|
||||
}
|
||||
type BlockDevices []BlockDevice
|
||||
|
||||
type AMIBlockDevices struct {
|
||||
AMIMappings []BlockDevice `mapstructure:"ami_block_device_mappings"`
|
||||
}
|
||||
|
||||
type LaunchBlockDevices struct {
|
||||
LaunchMappings []BlockDevice `mapstructure:"launch_block_device_mappings"`
|
||||
}
|
||||
|
||||
func buildBlockDevices(b []BlockDevice) []*ec2.BlockDeviceMapping {
|
||||
func (bds BlockDevices) BuildEC2BlockDeviceMappings() []*ec2.BlockDeviceMapping {
|
||||
var blockDevices []*ec2.BlockDeviceMapping
|
||||
|
||||
for _, blockDevice := range b {
|
||||
mapping := &ec2.BlockDeviceMapping{
|
||||
DeviceName: aws.String(blockDevice.DeviceName),
|
||||
}
|
||||
|
||||
if blockDevice.NoDevice {
|
||||
mapping.NoDevice = aws.String("")
|
||||
} else if blockDevice.VirtualName != "" {
|
||||
if strings.HasPrefix(blockDevice.VirtualName, "ephemeral") {
|
||||
mapping.VirtualName = aws.String(blockDevice.VirtualName)
|
||||
}
|
||||
} else {
|
||||
ebsBlockDevice := &ec2.EbsBlockDevice{
|
||||
DeleteOnTermination: aws.Bool(blockDevice.DeleteOnTermination),
|
||||
}
|
||||
|
||||
if blockDevice.VolumeType != "" {
|
||||
ebsBlockDevice.VolumeType = aws.String(blockDevice.VolumeType)
|
||||
}
|
||||
|
||||
if blockDevice.VolumeSize > 0 {
|
||||
ebsBlockDevice.VolumeSize = aws.Int64(blockDevice.VolumeSize)
|
||||
}
|
||||
|
||||
// IOPS is only valid for io1 type
|
||||
if blockDevice.VolumeType == "io1" {
|
||||
ebsBlockDevice.Iops = aws.Int64(blockDevice.IOPS)
|
||||
}
|
||||
|
||||
// You cannot specify Encrypted if you specify a Snapshot ID
|
||||
if blockDevice.SnapshotId != "" {
|
||||
ebsBlockDevice.SnapshotId = aws.String(blockDevice.SnapshotId)
|
||||
}
|
||||
|
||||
ebsBlockDevice.Encrypted = blockDevice.Encrypted.ToBoolPointer()
|
||||
|
||||
if blockDevice.KmsKeyId != "" {
|
||||
ebsBlockDevice.KmsKeyId = aws.String(blockDevice.KmsKeyId)
|
||||
}
|
||||
|
||||
mapping.Ebs = ebsBlockDevice
|
||||
}
|
||||
|
||||
blockDevices = append(blockDevices, mapping)
|
||||
for _, blockDevice := range bds {
|
||||
blockDevices = append(blockDevices, blockDevice.BuildEC2BlockDeviceMapping())
|
||||
}
|
||||
return blockDevices
|
||||
}
|
||||
|
||||
func (blockDevice BlockDevice) BuildEC2BlockDeviceMapping() *ec2.BlockDeviceMapping {
|
||||
|
||||
mapping := &ec2.BlockDeviceMapping{
|
||||
DeviceName: aws.String(blockDevice.DeviceName),
|
||||
}
|
||||
|
||||
if blockDevice.NoDevice {
|
||||
mapping.NoDevice = aws.String("")
|
||||
return mapping
|
||||
} else if blockDevice.VirtualName != "" {
|
||||
if strings.HasPrefix(blockDevice.VirtualName, "ephemeral") {
|
||||
mapping.VirtualName = aws.String(blockDevice.VirtualName)
|
||||
}
|
||||
return mapping
|
||||
}
|
||||
|
||||
ebsBlockDevice := &ec2.EbsBlockDevice{
|
||||
DeleteOnTermination: aws.Bool(blockDevice.DeleteOnTermination),
|
||||
}
|
||||
|
||||
if blockDevice.VolumeType != "" {
|
||||
ebsBlockDevice.VolumeType = aws.String(blockDevice.VolumeType)
|
||||
}
|
||||
|
||||
if blockDevice.VolumeSize > 0 {
|
||||
ebsBlockDevice.VolumeSize = aws.Int64(blockDevice.VolumeSize)
|
||||
}
|
||||
|
||||
// IOPS is only valid for io1 type
|
||||
if blockDevice.VolumeType == "io1" {
|
||||
ebsBlockDevice.Iops = aws.Int64(blockDevice.IOPS)
|
||||
}
|
||||
|
||||
// You cannot specify Encrypted if you specify a Snapshot ID
|
||||
if blockDevice.SnapshotId != "" {
|
||||
ebsBlockDevice.SnapshotId = aws.String(blockDevice.SnapshotId)
|
||||
}
|
||||
ebsBlockDevice.Encrypted = blockDevice.Encrypted.ToBoolPointer()
|
||||
|
||||
if blockDevice.KmsKeyId != "" {
|
||||
ebsBlockDevice.KmsKeyId = aws.String(blockDevice.KmsKeyId)
|
||||
}
|
||||
|
||||
mapping.Ebs = ebsBlockDevice
|
||||
|
||||
return mapping
|
||||
}
|
||||
|
||||
func (b *BlockDevice) Prepare(ctx *interpolate.Context) error {
|
||||
if b.DeviceName == "" {
|
||||
return fmt.Errorf("The `device_name` must be specified " +
|
||||
|
@ -102,37 +139,15 @@ func (b *BlockDevice) Prepare(ctx *interpolate.Context) error {
|
|||
"true` when setting a kms_key_id.", b.DeviceName)
|
||||
}
|
||||
|
||||
return nil
|
||||
_, err := interpolate.RenderInterface(&b, ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
func (b *BlockDevices) Prepare(ctx *interpolate.Context) (errs []error) {
|
||||
for _, d := range b.AMIMappings {
|
||||
if err := d.Prepare(ctx); err != nil {
|
||||
errs = append(errs, fmt.Errorf("AMIMapping: %s", err.Error()))
|
||||
}
|
||||
}
|
||||
for _, d := range b.LaunchMappings {
|
||||
if err := d.Prepare(ctx); err != nil {
|
||||
errs = append(errs, fmt.Errorf("LaunchMapping: %s", err.Error()))
|
||||
func (bds BlockDevices) Prepare(ctx *interpolate.Context) (errs []error) {
|
||||
for _, block := range bds {
|
||||
if err := block.Prepare(ctx); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
func (b *AMIBlockDevices) BuildAMIDevices() []*ec2.BlockDeviceMapping {
|
||||
return buildBlockDevices(b.AMIMappings)
|
||||
}
|
||||
|
||||
func (b *LaunchBlockDevices) BuildLaunchDevices() []*ec2.BlockDeviceMapping {
|
||||
return buildBlockDevices(b.LaunchMappings)
|
||||
}
|
||||
|
||||
func (b *LaunchBlockDevices) GetOmissions() map[string]bool {
|
||||
omitMap := make(map[string]bool)
|
||||
|
||||
for _, blockDevice := range b.LaunchMappings {
|
||||
omitMap[blockDevice.DeviceName] = blockDevice.OmitFromArtifact
|
||||
}
|
||||
|
||||
return omitMap
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/hashicorp/packer/helper/config"
|
||||
)
|
||||
|
||||
|
@ -146,26 +146,20 @@ func TestBlockDevice(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
amiBlockDevices := AMIBlockDevices{
|
||||
AMIMappings: []BlockDevice{*tc.Config},
|
||||
}
|
||||
var amiBlockDevices BlockDevices = []BlockDevice{*tc.Config}
|
||||
|
||||
launchBlockDevices := LaunchBlockDevices{
|
||||
LaunchMappings: []BlockDevice{*tc.Config},
|
||||
}
|
||||
var launchBlockDevices BlockDevices = []BlockDevice{*tc.Config}
|
||||
|
||||
expected := []*ec2.BlockDeviceMapping{tc.Result}
|
||||
|
||||
amiResults := amiBlockDevices.BuildAMIDevices()
|
||||
if !reflect.DeepEqual(expected, amiResults) {
|
||||
t.Fatalf("Bad block device, \nexpected: %#v\n\ngot: %#v",
|
||||
expected, amiResults)
|
||||
amiResults := amiBlockDevices.BuildEC2BlockDeviceMappings()
|
||||
if diff := cmp.Diff(expected, amiResults); diff != "" {
|
||||
t.Fatalf("Bad block device: %s", diff)
|
||||
}
|
||||
|
||||
launchResults := launchBlockDevices.BuildLaunchDevices()
|
||||
if !reflect.DeepEqual(expected, launchResults) {
|
||||
t.Fatalf("Bad block device, \nexpected: %#v\n\ngot: %#v",
|
||||
expected, launchResults)
|
||||
launchResults := launchBlockDevices.BuildEC2BlockDeviceMappings()
|
||||
if diff := cmp.Diff(expected, launchResults); diff != "" {
|
||||
t.Fatalf("Bad block device: %s", diff)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
|
@ -58,34 +60,279 @@ func (d *SecurityGroupFilterOptions) Empty() bool {
|
|||
// RunConfig contains configuration for running an instance from a source
|
||||
// AMI and details on how to access that launched image.
|
||||
type RunConfig struct {
|
||||
AssociatePublicIpAddress bool `mapstructure:"associate_public_ip_address"`
|
||||
AvailabilityZone string `mapstructure:"availability_zone"`
|
||||
BlockDurationMinutes int64 `mapstructure:"block_duration_minutes"`
|
||||
DisableStopInstance bool `mapstructure:"disable_stop_instance"`
|
||||
EbsOptimized bool `mapstructure:"ebs_optimized"`
|
||||
EnableT2Unlimited bool `mapstructure:"enable_t2_unlimited"`
|
||||
IamInstanceProfile string `mapstructure:"iam_instance_profile"`
|
||||
InstanceInitiatedShutdownBehavior string `mapstructure:"shutdown_behavior"`
|
||||
InstanceType string `mapstructure:"instance_type"`
|
||||
SecurityGroupFilter SecurityGroupFilterOptions `mapstructure:"security_group_filter"`
|
||||
RunTags map[string]string `mapstructure:"run_tags"`
|
||||
SecurityGroupId string `mapstructure:"security_group_id"`
|
||||
SecurityGroupIds []string `mapstructure:"security_group_ids"`
|
||||
SourceAmi string `mapstructure:"source_ami"`
|
||||
SourceAmiFilter AmiFilterOptions `mapstructure:"source_ami_filter"`
|
||||
SpotInstanceTypes []string `mapstructure:"spot_instance_types"`
|
||||
SpotPrice string `mapstructure:"spot_price"`
|
||||
SpotPriceAutoProduct string `mapstructure:"spot_price_auto_product"`
|
||||
SpotTags map[string]string `mapstructure:"spot_tags"`
|
||||
SubnetFilter SubnetFilterOptions `mapstructure:"subnet_filter"`
|
||||
SubnetId string `mapstructure:"subnet_id"`
|
||||
TemporaryKeyPairName string `mapstructure:"temporary_key_pair_name"`
|
||||
TemporarySGSourceCidrs []string `mapstructure:"temporary_security_group_source_cidrs"`
|
||||
UserData string `mapstructure:"user_data"`
|
||||
UserDataFile string `mapstructure:"user_data_file"`
|
||||
VpcFilter VpcFilterOptions `mapstructure:"vpc_filter"`
|
||||
VpcId string `mapstructure:"vpc_id"`
|
||||
WindowsPasswordTimeout time.Duration `mapstructure:"windows_password_timeout"`
|
||||
// If using a non-default VPC,
|
||||
// public IP addresses are not provided by default. If this is true, your
|
||||
// new instance will get a Public IP. default: false
|
||||
AssociatePublicIpAddress bool `mapstructure:"associate_public_ip_address" required:"false"`
|
||||
// Destination availability zone to launch
|
||||
// instance in. Leave this empty to allow Amazon to auto-assign.
|
||||
AvailabilityZone string `mapstructure:"availability_zone" required:"false"`
|
||||
// Requires spot_price to be set. The
|
||||
// required duration for the Spot Instances (also known as Spot blocks). This
|
||||
// value must be a multiple of 60 (60, 120, 180, 240, 300, or 360). You can't
|
||||
// specify an Availability Zone group or a launch group if you specify a
|
||||
// duration.
|
||||
BlockDurationMinutes int64 `mapstructure:"block_duration_minutes" required:"false"`
|
||||
// Packer normally stops the build instance after all provisioners have
|
||||
// run. For Windows instances, it is sometimes desirable to [run
|
||||
// Sysprep](http://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ami-create-standard.html)
|
||||
// which will stop the instance for you. If this is set to `true`, Packer
|
||||
// *will not* stop the instance but will assume that you will send the stop
|
||||
// signal yourself through your final provisioner. You can do this with a
|
||||
// [windows-shell
|
||||
// provisioner](https://www.packer.io/docs/provisioners/windows-shell.html).
|
||||
// Note that Packer will still wait for the instance to be stopped, and
|
||||
// failing to send the stop signal yourself, when you have set this flag to
|
||||
// `true`, will cause a timeout.
|
||||
// Example of a valid shutdown command:
|
||||
//
|
||||
// ``` json
|
||||
// {
|
||||
// "type": "windows-shell",
|
||||
// "inline": ["\"c:\\Program Files\\Amazon\\Ec2ConfigService\\ec2config.exe\" -sysprep"]
|
||||
// }
|
||||
// ```
|
||||
DisableStopInstance bool `mapstructure:"disable_stop_instance" required:"false"`
|
||||
// Mark instance as [EBS
|
||||
// Optimized](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSOptimized.html).
|
||||
// Default `false`.
|
||||
EbsOptimized bool `mapstructure:"ebs_optimized" required:"false"`
|
||||
// Enabling T2 Unlimited allows the source instance to burst additional CPU
|
||||
// beyond its available [CPU
|
||||
// Credits](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-credits-baseline-concepts.html)
|
||||
// for as long as the demand exists. This is in contrast to the standard
|
||||
// configuration that only allows an instance to consume up to its
|
||||
// available CPU Credits. See the AWS documentation for [T2
|
||||
// Unlimited](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-unlimited.html)
|
||||
// and the **T2 Unlimited Pricing** section of the [Amazon EC2 On-Demand
|
||||
// Pricing](https://aws.amazon.com/ec2/pricing/on-demand/) document for
|
||||
// more information. By default this option is disabled and Packer will set
|
||||
// up a [T2
|
||||
// Standard](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-std.html)
|
||||
// instance instead.
|
||||
//
|
||||
// To use T2 Unlimited you must use a T2 instance type, e.g. `t2.micro`.
|
||||
// Additionally, T2 Unlimited cannot be used in conjunction with Spot
|
||||
// Instances, e.g. when the `spot_price` option has been configured.
|
||||
// Attempting to do so will cause an error.
|
||||
//
|
||||
// !> **Warning!** Additional costs may be incurred by enabling T2
|
||||
// Unlimited - even for instances that would usually qualify for the
|
||||
// [AWS Free Tier](https://aws.amazon.com/free/).
|
||||
EnableT2Unlimited bool `mapstructure:"enable_t2_unlimited" required:"false"`
|
||||
// The name of an [IAM instance
|
||||
// profile](https://docs.aws.amazon.com/IAM/latest/UserGuide/instance-profiles.html)
|
||||
// to launch the EC2 instance with.
|
||||
IamInstanceProfile string `mapstructure:"iam_instance_profile" required:"false"`
|
||||
// Automatically terminate instances on
|
||||
// shutdown in case Packer exits ungracefully. Possible values are stop and
|
||||
// terminate. Defaults to stop.
|
||||
InstanceInitiatedShutdownBehavior string `mapstructure:"shutdown_behavior" required:"false"`
|
||||
// The EC2 instance type to use while building the
|
||||
// AMI, such as t2.small.
|
||||
InstanceType string `mapstructure:"instance_type" required:"true"`
|
||||
// Filters used to populate the `security_group_ids` field. Example:
|
||||
//
|
||||
// ``` json
|
||||
// {
|
||||
// "security_group_filter": {
|
||||
// "filters": {
|
||||
// "tag:Class": "packer"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// This selects the SG's with tag `Class` with the value `packer`.
|
||||
//
|
||||
// - `filters` (map of strings) - filters used to select a
|
||||
// `security_group_ids`. Any filter described in the docs for
|
||||
// [DescribeSecurityGroups](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSecurityGroups.html)
|
||||
// is valid.
|
||||
//
|
||||
// `security_group_ids` take precedence over this.
|
||||
SecurityGroupFilter SecurityGroupFilterOptions `mapstructure:"security_group_filter" required:"false"`
|
||||
// Tags to apply to the instance that is that is *launched* to create the
|
||||
// EBS volumes. This is a [template engine](/docs/templates/engine.html),
|
||||
// see [Build template data](#build-template-data) for more information.
|
||||
RunTags map[string]string `mapstructure:"run_tags" required:"false"`
|
||||
// The ID (not the name) of the security
|
||||
// group to assign to the instance. By default this is not set and Packer will
|
||||
// automatically create a new temporary security group to allow SSH access.
|
||||
// Note that if this is specified, you must be sure the security group allows
|
||||
// access to the ssh_port given below.
|
||||
SecurityGroupId string `mapstructure:"security_group_id" required:"false"`
|
||||
// A list of security groups as
|
||||
// described above. Note that if this is specified, you must omit the
|
||||
// security_group_id.
|
||||
SecurityGroupIds []string `mapstructure:"security_group_ids" required:"false"`
|
||||
// The source AMI whose root volume will be copied and
|
||||
// provisioned on the currently running instance. This must be an EBS-backed
|
||||
// AMI with a root volume snapshot that you have access to. Note: this is not
|
||||
// used when from_scratch is set to true.
|
||||
SourceAmi string `mapstructure:"source_ami" required:"true"`
|
||||
// Filters used to populate the `source_ami`
|
||||
// field. Example:
|
||||
//
|
||||
// ``` json
|
||||
// {
|
||||
// "source_ami_filter": {
|
||||
// "filters": {
|
||||
// "virtualization-type": "hvm",
|
||||
// "name": "ubuntu/images/\*ubuntu-xenial-16.04-amd64-server-\*",
|
||||
// "root-device-type": "ebs"
|
||||
// },
|
||||
// "owners": ["099720109477"],
|
||||
// "most_recent": true
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// This selects the most recent Ubuntu 16.04 HVM EBS AMI from Canonical. NOTE:
|
||||
// This will fail unless *exactly* one AMI is returned. In the above example,
|
||||
// `most_recent` will cause this to succeed by selecting the newest image.
|
||||
//
|
||||
// - `filters` (map of strings) - filters used to select a `source_ami`.
|
||||
// NOTE: This will fail unless *exactly* one AMI is returned. Any filter
|
||||
// described in the docs for
|
||||
// [DescribeImages](http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeImages.html)
|
||||
// is valid.
|
||||
//
|
||||
// - `owners` (array of strings) - Filters the images by their owner. You
|
||||
// may specify one or more AWS account IDs, "self" (which will use the
|
||||
// account whose credentials you are using to run Packer), or an AWS owner
|
||||
// alias: for example, `amazon`, `aws-marketplace`, or `microsoft`. This
|
||||
// option is required for security reasons.
|
||||
//
|
||||
// - `most_recent` (boolean) - Selects the newest created image when true.
|
||||
// This is most useful for selecting a daily distro build.
|
||||
//
|
||||
// You may set this in place of `source_ami` or in conjunction with it. If you
|
||||
// set this in conjunction with `source_ami`, the `source_ami` will be added
|
||||
// to the filter. The provided `source_ami` must meet all of the filtering
|
||||
// criteria provided in `source_ami_filter`; this pins the AMI returned by the
|
||||
// filter, but will cause Packer to fail if the `source_ami` does not exist.
|
||||
SourceAmiFilter AmiFilterOptions `mapstructure:"source_ami_filter" required:"false"`
|
||||
// a list of acceptable instance
|
||||
// types to run your build on. We will request a spot instance using the max
|
||||
// price of spot_price and the allocation strategy of "lowest price".
|
||||
// Your instance will be launched on an instance type of the lowest available
|
||||
// price that you have in your list. This is used in place of instance_type.
|
||||
// You may only set either spot_instance_types or instance_type, not both.
|
||||
// This feature exists to help prevent situations where a Packer build fails
|
||||
// because a particular availability zone does not have capacity for the
|
||||
// specific instance_type requested in instance_type.
|
||||
SpotInstanceTypes []string `mapstructure:"spot_instance_types" required:"false"`
|
||||
// The maximum hourly price to pay for a spot instance
|
||||
// to create the AMI. Spot instances are a type of instance that EC2 starts
|
||||
// when the current spot price is less than the maximum price you specify.
|
||||
// Spot price will be updated based on available spot instance capacity and
|
||||
// current spot instance requests. It may save you some costs. You can set
|
||||
// this to auto for Packer to automatically discover the best spot price or
|
||||
// to "0" to use an on demand instance (default).
|
||||
SpotPrice string `mapstructure:"spot_price" required:"false"`
|
||||
// Required if spot_price is set to
|
||||
// auto. This tells Packer what sort of AMI you're launching to find the
|
||||
// best spot price. This must be one of: Linux/UNIX, SUSE Linux,
|
||||
// Windows, Linux/UNIX (Amazon VPC), SUSE Linux (Amazon VPC),
|
||||
// Windows (Amazon VPC)
|
||||
SpotPriceAutoProduct string `mapstructure:"spot_price_auto_product" required:"false"`
|
||||
// Requires spot_price to be
|
||||
// set. This tells Packer to apply tags to the spot request that is issued.
|
||||
SpotTags map[string]string `mapstructure:"spot_tags" required:"false"`
|
||||
// Filters used to populate the `subnet_id` field.
|
||||
// Example:
|
||||
//
|
||||
// ``` json
|
||||
// {
|
||||
// "subnet_filter": {
|
||||
// "filters": {
|
||||
// "tag:Class": "build"
|
||||
// },
|
||||
// "most_free": true,
|
||||
// "random": false
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// This selects the Subnet with tag `Class` with the value `build`, which has
|
||||
// the most free IP addresses. NOTE: This will fail unless *exactly* one
|
||||
// Subnet is returned. By using `most_free` or `random` one will be selected
|
||||
// from those matching the filter.
|
||||
//
|
||||
// - `filters` (map of strings) - filters used to select a `subnet_id`.
|
||||
// NOTE: This will fail unless *exactly* one Subnet is returned. Any
|
||||
// filter described in the docs for
|
||||
// [DescribeSubnets](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSubnets.html)
|
||||
// is valid.
|
||||
//
|
||||
// - `most_free` (boolean) - The Subnet with the most free IPv4 addresses
|
||||
// will be used if multiple Subnets matches the filter.
|
||||
//
|
||||
// - `random` (boolean) - A random Subnet will be used if multiple Subnets
|
||||
// matches the filter. `most_free` have precendence over this.
|
||||
//
|
||||
// `subnet_id` take precedence over this.
|
||||
SubnetFilter SubnetFilterOptions `mapstructure:"subnet_filter" required:"false"`
|
||||
// If using VPC, the ID of the subnet, such as
|
||||
// subnet-12345def, where Packer will launch the EC2 instance. This field is
|
||||
// required if you are using an non-default VPC.
|
||||
SubnetId string `mapstructure:"subnet_id" required:"false"`
|
||||
// The name of the temporary key pair to
|
||||
// generate. By default, Packer generates a name that looks like
|
||||
// `packer_<UUID>`, where <UUID> is a 36 character unique identifier.
|
||||
TemporaryKeyPairName string `mapstructure:"temporary_key_pair_name" required:"false"`
|
||||
// A list of IPv4 CIDR blocks to be authorized access to the instance, when
|
||||
// packer is creating a temporary security group.
|
||||
//
|
||||
// The default is [`0.0.0.0/0`] (i.e., allow any IPv4 source). This is only
|
||||
// used when `security_group_id` or `security_group_ids` is not specified.
|
||||
TemporarySGSourceCidrs []string `mapstructure:"temporary_security_group_source_cidrs" required:"false"`
|
||||
// User data to apply when launching the instance. Note
|
||||
// that you need to be careful about escaping characters due to the templates
|
||||
// being JSON. It is often more convenient to use user_data_file, instead.
|
||||
// Packer will not automatically wait for a user script to finish before
|
||||
// shutting down the instance this must be handled in a provisioner.
|
||||
UserData string `mapstructure:"user_data" required:"false"`
|
||||
// Path to a file that will be used for the user
|
||||
// data when launching the instance.
|
||||
UserDataFile string `mapstructure:"user_data_file" required:"false"`
|
||||
// Filters used to populate the `vpc_id` field.
|
||||
// Example:
|
||||
//
|
||||
// ``` json
|
||||
// {
|
||||
// "vpc_filter": {
|
||||
// "filters": {
|
||||
// "tag:Class": "build",
|
||||
// "isDefault": "false",
|
||||
// "cidr": "/24"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// This selects the VPC with tag `Class` with the value `build`, which is not
|
||||
// the default VPC, and have a IPv4 CIDR block of `/24`. NOTE: This will fail
|
||||
// unless *exactly* one VPC is returned.
|
||||
//
|
||||
// - `filters` (map of strings) - filters used to select a `vpc_id`. NOTE:
|
||||
// This will fail unless *exactly* one VPC is returned. Any filter
|
||||
// described in the docs for
|
||||
// [DescribeVpcs](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpcs.html)
|
||||
// is valid.
|
||||
//
|
||||
// `vpc_id` take precedence over this.
|
||||
VpcFilter VpcFilterOptions `mapstructure:"vpc_filter" required:"false"`
|
||||
// If launching into a VPC subnet, Packer needs the VPC ID
|
||||
// in order to create a temporary security group within the VPC. Requires
|
||||
// subnet_id to be set. If this field is left blank, Packer will try to get
|
||||
// the VPC ID from the subnet_id.
|
||||
VpcId string `mapstructure:"vpc_id" required:"false"`
|
||||
// The timeout for waiting for a Windows
|
||||
// password for Windows instances. Defaults to 20 minutes. Example value:
|
||||
// 10m
|
||||
WindowsPasswordTimeout time.Duration `mapstructure:"windows_password_timeout" required:"false"`
|
||||
|
||||
// Communicator settings
|
||||
Comm communicator.Config `mapstructure:",squash"`
|
||||
|
|
|
@ -24,7 +24,9 @@ func testConfig() *RunConfig {
|
|||
InstanceType: "m1.small",
|
||||
|
||||
Comm: communicator.Config{
|
||||
SSHUsername: "foo",
|
||||
SSH: communicator.SSH{
|
||||
SSHUsername: "foo",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
// remain after termination of the instance. These volumes are typically ones
|
||||
// that are marked as "delete on terminate:false" in the source_ami of a build.
|
||||
type StepCleanupVolumes struct {
|
||||
BlockDevices BlockDevices
|
||||
LaunchMappings BlockDevices
|
||||
}
|
||||
|
||||
func (s *StepCleanupVolumes) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
|
@ -79,7 +79,7 @@ func (s *StepCleanupVolumes) Cleanup(state multistep.StateBag) {
|
|||
|
||||
// Filter out any devices created as part of the launch mappings, since
|
||||
// we'll let amazon follow the `delete_on_termination` setting.
|
||||
for _, b := range s.BlockDevices.LaunchMappings {
|
||||
for _, b := range s.LaunchMappings {
|
||||
for volKey, volName := range volList {
|
||||
if volName == b.DeviceName {
|
||||
delete(volList, volKey)
|
||||
|
|
|
@ -21,7 +21,7 @@ import (
|
|||
|
||||
type StepRunSourceInstance struct {
|
||||
AssociatePublicIpAddress bool
|
||||
BlockDevices BlockDevices
|
||||
LaunchMappings EC2BlockDeviceMappingsBuilder
|
||||
Comm *communicator.Config
|
||||
Ctx interpolate.Context
|
||||
Debug bool
|
||||
|
@ -111,7 +111,7 @@ func (s *StepRunSourceInstance) Run(ctx context.Context, state multistep.StateBa
|
|||
MaxCount: aws.Int64(1),
|
||||
MinCount: aws.Int64(1),
|
||||
IamInstanceProfile: &ec2.IamInstanceProfileSpecification{Name: &s.IamInstanceProfile},
|
||||
BlockDeviceMappings: s.BlockDevices.BuildLaunchDevices(),
|
||||
BlockDeviceMappings: s.LaunchMappings.BuildEC2BlockDeviceMappings(),
|
||||
Placement: &ec2.Placement{AvailabilityZone: &az},
|
||||
EbsOptimized: &s.EbsOptimized,
|
||||
}
|
||||
|
|
|
@ -19,9 +19,13 @@ import (
|
|||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
type EC2BlockDeviceMappingsBuilder interface {
|
||||
BuildEC2BlockDeviceMappings() []*ec2.BlockDeviceMapping
|
||||
}
|
||||
|
||||
type StepRunSpotInstance struct {
|
||||
AssociatePublicIpAddress bool
|
||||
BlockDevices BlockDevices
|
||||
LaunchMappings EC2BlockDeviceMappingsBuilder
|
||||
BlockDurationMinutes int64
|
||||
Debug bool
|
||||
Comm *communicator.Config
|
||||
|
@ -53,7 +57,7 @@ func (s *StepRunSpotInstance) CreateTemplateData(userData *string, az string,
|
|||
// LaunchTemplateEbsBlockDeviceRequest structs are themselves
|
||||
// identical except for the struct's name, so you can cast one directly
|
||||
// into the other.
|
||||
blockDeviceMappings := s.BlockDevices.BuildLaunchDevices()
|
||||
blockDeviceMappings := s.LaunchMappings.BuildEC2BlockDeviceMappings()
|
||||
var launchMappingRequests []*ec2.LaunchTemplateBlockDeviceMappingRequest
|
||||
for _, mapping := range blockDeviceMappings {
|
||||
launchRequest := &ec2.LaunchTemplateBlockDeviceMappingRequest{
|
||||
|
|
|
@ -81,18 +81,13 @@ func tStateSpot() multistep.StateBag {
|
|||
func getBasicStep() *StepRunSpotInstance {
|
||||
stepRunSpotInstance := StepRunSpotInstance{
|
||||
AssociatePublicIpAddress: false,
|
||||
BlockDevices: BlockDevices{
|
||||
AMIBlockDevices: AMIBlockDevices{
|
||||
AMIMappings: []BlockDevice(nil),
|
||||
},
|
||||
LaunchBlockDevices: LaunchBlockDevices{
|
||||
LaunchMappings: []BlockDevice(nil),
|
||||
},
|
||||
},
|
||||
BlockDurationMinutes: 0,
|
||||
Debug: false,
|
||||
LaunchMappings: BlockDevices{},
|
||||
BlockDurationMinutes: 0,
|
||||
Debug: false,
|
||||
Comm: &communicator.Config{
|
||||
SSHKeyPairName: "foo",
|
||||
SSH: communicator.SSH{
|
||||
SSHKeyPairName: "foo",
|
||||
},
|
||||
},
|
||||
EbsOptimized: false,
|
||||
ExpectedRootDevice: "ebs",
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
// The amazonebs package contains a packer.Builder implementation that
|
||||
// builds AMIs for Amazon EC2.
|
||||
//
|
||||
|
@ -26,9 +28,29 @@ type Config struct {
|
|||
common.PackerConfig `mapstructure:",squash"`
|
||||
awscommon.AccessConfig `mapstructure:",squash"`
|
||||
awscommon.AMIConfig `mapstructure:",squash"`
|
||||
awscommon.BlockDevices `mapstructure:",squash"`
|
||||
awscommon.RunConfig `mapstructure:",squash"`
|
||||
VolumeRunTags awscommon.TagMap `mapstructure:"run_volume_tags"`
|
||||
// Add one or more block device mappings to the AMI. These will be attached
|
||||
// when booting a new instance from your AMI. To add a block device during
|
||||
// the Packer build see `launch_block_device_mappings` below. Your options
|
||||
// here may vary depending on the type of VM you use. See the
|
||||
// [BlockDevices](#block-devices-configuration) documentation for fields.
|
||||
AMIMappings awscommon.BlockDevices `mapstructure:"ami_block_device_mappings" required:"false"`
|
||||
// Add one or more block devices before the Packer build starts. If you add
|
||||
// instance store volumes or EBS volumes in addition to the root device
|
||||
// volume, the created AMI will contain block device mapping information
|
||||
// for those volumes. Amazon creates snapshots of the source instance's
|
||||
// root volume and any other EBS volumes described here. When you launch an
|
||||
// instance from this new AMI, the instance automatically launches with
|
||||
// these additional volumes, and will restore them from snapshots taken
|
||||
// from the source instance. See the
|
||||
// [BlockDevices](#block-devices-configuration) documentation for fields.
|
||||
LaunchMappings awscommon.BlockDevices `mapstructure:"launch_block_device_mappings" required:"false"`
|
||||
// Tags to apply to the volumes that are *launched* to create the AMI.
|
||||
// These tags are *not* applied to the resulting AMI unless they're
|
||||
// duplicated in `tags`. This is a [template
|
||||
// engine](/docs/templates/engine.html), see [Build template
|
||||
// data](#build-template-data) for more information.
|
||||
VolumeRunTags awscommon.TagMap `mapstructure:"run_volume_tags"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
@ -69,7 +91,8 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
|||
errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(&b.config.ctx)...)
|
||||
errs = packer.MultiErrorAppend(errs,
|
||||
b.config.AMIConfig.Prepare(&b.config.AccessConfig, &b.config.ctx)...)
|
||||
errs = packer.MultiErrorAppend(errs, b.config.BlockDevices.Prepare(&b.config.ctx)...)
|
||||
errs = packer.MultiErrorAppend(errs, b.config.AMIMappings.Prepare(&b.config.ctx)...)
|
||||
errs = packer.MultiErrorAppend(errs, b.config.LaunchMappings.Prepare(&b.config.ctx)...)
|
||||
errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...)
|
||||
|
||||
if b.config.IsSpotInstance() && (b.config.AMIENASupport.True() || b.config.AMISriovNetSupport) {
|
||||
|
@ -119,7 +142,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
if b.config.IsSpotInstance() {
|
||||
instanceStep = &awscommon.StepRunSpotInstance{
|
||||
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
|
||||
BlockDevices: b.config.BlockDevices,
|
||||
LaunchMappings: b.config.LaunchMappings,
|
||||
BlockDurationMinutes: b.config.BlockDurationMinutes,
|
||||
Ctx: b.config.ctx,
|
||||
Comm: &b.config.RunConfig.Comm,
|
||||
|
@ -141,7 +164,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
} else {
|
||||
instanceStep = &awscommon.StepRunSourceInstance{
|
||||
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
|
||||
BlockDevices: b.config.BlockDevices,
|
||||
LaunchMappings: b.config.LaunchMappings,
|
||||
Comm: &b.config.RunConfig.Comm,
|
||||
Ctx: b.config.ctx,
|
||||
Debug: b.config.PackerDebug,
|
||||
|
@ -195,7 +218,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
TemporarySGSourceCidrs: b.config.TemporarySGSourceCidrs,
|
||||
},
|
||||
&awscommon.StepCleanupVolumes{
|
||||
BlockDevices: b.config.BlockDevices,
|
||||
LaunchMappings: b.config.LaunchMappings,
|
||||
},
|
||||
instanceStep,
|
||||
&awscommon.StepGetPassword{
|
||||
|
|
|
@ -45,7 +45,7 @@ func (s *stepCreateAMI) Run(ctx context.Context, state multistep.StateBag) multi
|
|||
createOpts := &ec2.CreateImageInput{
|
||||
InstanceId: instance.InstanceId,
|
||||
Name: &amiName,
|
||||
BlockDeviceMappings: config.BlockDevices.BuildAMIDevices(),
|
||||
BlockDeviceMappings: config.AMIMappings.BuildEC2BlockDeviceMappings(),
|
||||
}
|
||||
|
||||
createResp, err := ec2conn.CreateImage(createOpts)
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package ebssurrogate
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
awscommon "github.com/hashicorp/packer/builder/amazon/common"
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
type BlockDevice struct {
|
||||
awscommon.BlockDevice `mapstructure:",squash"`
|
||||
|
||||
// If true, this block device will not be snapshotted and the created AMI
|
||||
// will not contain block device mapping information for this volume. If
|
||||
// false, the block device will be mapped into the final created AMI. Set
|
||||
// this option to true if you need a block device mounted in the surrogate
|
||||
// AMI but not in the final created AMI.
|
||||
OmitFromArtifact bool `mapstructure:"omit_from_artifact"`
|
||||
}
|
||||
|
||||
type BlockDevices []BlockDevice
|
||||
|
||||
func (bds BlockDevices) Common() []awscommon.BlockDevice {
|
||||
res := []awscommon.BlockDevice{}
|
||||
for _, bd := range bds {
|
||||
res = append(res, bd.BlockDevice)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (bds BlockDevices) BuildEC2BlockDeviceMappings() []*ec2.BlockDeviceMapping {
|
||||
var blockDevices []*ec2.BlockDeviceMapping
|
||||
|
||||
for _, blockDevice := range bds {
|
||||
blockDevices = append(blockDevices, blockDevice.BuildEC2BlockDeviceMapping())
|
||||
}
|
||||
return blockDevices
|
||||
}
|
||||
|
||||
func (blockDevice BlockDevice) BuildEC2BlockDeviceMapping() *ec2.BlockDeviceMapping {
|
||||
|
||||
mapping := &ec2.BlockDeviceMapping{
|
||||
DeviceName: aws.String(blockDevice.DeviceName),
|
||||
}
|
||||
|
||||
if blockDevice.NoDevice {
|
||||
mapping.NoDevice = aws.String("")
|
||||
return mapping
|
||||
} else if blockDevice.VirtualName != "" {
|
||||
if strings.HasPrefix(blockDevice.VirtualName, "ephemeral") {
|
||||
mapping.VirtualName = aws.String(blockDevice.VirtualName)
|
||||
}
|
||||
return mapping
|
||||
}
|
||||
|
||||
ebsBlockDevice := &ec2.EbsBlockDevice{
|
||||
DeleteOnTermination: aws.Bool(blockDevice.DeleteOnTermination),
|
||||
}
|
||||
|
||||
if blockDevice.VolumeType != "" {
|
||||
ebsBlockDevice.VolumeType = aws.String(blockDevice.VolumeType)
|
||||
}
|
||||
|
||||
if blockDevice.VolumeSize > 0 {
|
||||
ebsBlockDevice.VolumeSize = aws.Int64(blockDevice.VolumeSize)
|
||||
}
|
||||
|
||||
// IOPS is only valid for io1 type
|
||||
if blockDevice.VolumeType == "io1" {
|
||||
ebsBlockDevice.Iops = aws.Int64(blockDevice.IOPS)
|
||||
}
|
||||
|
||||
// You cannot specify Encrypted if you specify a Snapshot ID
|
||||
if blockDevice.SnapshotId != "" {
|
||||
ebsBlockDevice.SnapshotId = aws.String(blockDevice.SnapshotId)
|
||||
}
|
||||
ebsBlockDevice.Encrypted = blockDevice.Encrypted.ToBoolPointer()
|
||||
|
||||
mapping.Ebs = ebsBlockDevice
|
||||
|
||||
return mapping
|
||||
}
|
||||
|
||||
func (bds BlockDevices) Prepare(ctx *interpolate.Context) (errs []error) {
|
||||
for _, block := range bds {
|
||||
if err := block.Prepare(ctx); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
func (b BlockDevices) GetOmissions() map[string]bool {
|
||||
omitMap := make(map[string]bool)
|
||||
|
||||
for _, blockDevice := range b {
|
||||
omitMap[blockDevice.DeviceName] = blockDevice.OmitFromArtifact
|
||||
}
|
||||
|
||||
return omitMap
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
// The ebssurrogate package contains a packer.Builder implementation that
|
||||
// builds a new EBS-backed AMI using an ephemeral instance.
|
||||
package ebssurrogate
|
||||
|
@ -23,12 +25,41 @@ type Config struct {
|
|||
common.PackerConfig `mapstructure:",squash"`
|
||||
awscommon.AccessConfig `mapstructure:",squash"`
|
||||
awscommon.RunConfig `mapstructure:",squash"`
|
||||
awscommon.BlockDevices `mapstructure:",squash"`
|
||||
awscommon.AMIConfig `mapstructure:",squash"`
|
||||
|
||||
RootDevice RootBlockDevice `mapstructure:"ami_root_device"`
|
||||
// Add one or more block device mappings to the AMI. These will be attached
|
||||
// when booting a new instance from your AMI. To add a block device during
|
||||
// the Packer build see `launch_block_device_mappings` below. Your options
|
||||
// here may vary depending on the type of VM you use. See the
|
||||
// [BlockDevices](#block-devices-configuration) documentation for fields.
|
||||
AMIMappings awscommon.BlockDevices `mapstructure:"ami_block_device_mappings" required:"false"`
|
||||
// Add one or more block devices before the Packer build starts. If you add
|
||||
// instance store volumes or EBS volumes in addition to the root device
|
||||
// volume, the created AMI will contain block device mapping information
|
||||
// for those volumes. Amazon creates snapshots of the source instance's
|
||||
// root volume and any other EBS volumes described here. When you launch an
|
||||
// instance from this new AMI, the instance automatically launches with
|
||||
// these additional volumes, and will restore them from snapshots taken
|
||||
// from the source instance. See the
|
||||
// [BlockDevices](#block-devices-configuration) documentation for fields.
|
||||
LaunchMappings BlockDevices `mapstructure:"launch_block_device_mappings" required:"false"`
|
||||
// A block device mapping describing the root device of the AMI. This looks
|
||||
// like the mappings in `ami_block_device_mapping`, except with an
|
||||
// additional field:
|
||||
//
|
||||
// - `source_device_name` (string) - The device name of the block device on
|
||||
// the source instance to be used as the root device for the AMI. This
|
||||
// must correspond to a block device in `launch_block_device_mapping`.
|
||||
RootDevice RootBlockDevice `mapstructure:"ami_root_device" required:"true"`
|
||||
// Tags to apply to the volumes that are *launched* to create the AMI.
|
||||
// These tags are *not* applied to the resulting AMI unless they're
|
||||
// duplicated in `tags`. This is a [template
|
||||
// engine](/docs/templates/engine.html), see [Build template
|
||||
// data](#build-template-data) for more information.
|
||||
VolumeRunTags awscommon.TagMap `mapstructure:"run_volume_tags"`
|
||||
Architecture string `mapstructure:"ami_architecture"`
|
||||
// what architecture to use when registering the
|
||||
// final AMI; valid options are "x86_64" or "arm64". Defaults to "x86_64".
|
||||
Architecture string `mapstructure:"ami_architecture" required:"false"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
@ -69,7 +100,8 @@ 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.AMIConfig.Prepare(&b.config.AccessConfig, &b.config.ctx)...)
|
||||
errs = packer.MultiErrorAppend(errs, b.config.BlockDevices.Prepare(&b.config.ctx)...)
|
||||
errs = packer.MultiErrorAppend(errs, b.config.AMIMappings.Prepare(&b.config.ctx)...)
|
||||
errs = packer.MultiErrorAppend(errs, b.config.LaunchMappings.Prepare(&b.config.ctx)...)
|
||||
errs = packer.MultiErrorAppend(errs, b.config.RootDevice.Prepare(&b.config.ctx)...)
|
||||
|
||||
if b.config.AMIVirtType == "" {
|
||||
|
@ -77,7 +109,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
|||
}
|
||||
|
||||
foundRootVolume := false
|
||||
for _, launchDevice := range b.config.BlockDevices.LaunchMappings {
|
||||
for _, launchDevice := range b.config.LaunchMappings {
|
||||
if launchDevice.DeviceName == b.config.RootDevice.SourceDeviceName {
|
||||
foundRootVolume = true
|
||||
if launchDevice.OmitFromArtifact {
|
||||
|
@ -149,7 +181,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
if b.config.IsSpotInstance() {
|
||||
instanceStep = &awscommon.StepRunSpotInstance{
|
||||
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
|
||||
BlockDevices: b.config.BlockDevices,
|
||||
LaunchMappings: b.config.LaunchMappings,
|
||||
BlockDurationMinutes: b.config.BlockDurationMinutes,
|
||||
Ctx: b.config.ctx,
|
||||
Comm: &b.config.RunConfig.Comm,
|
||||
|
@ -171,7 +203,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
} else {
|
||||
instanceStep = &awscommon.StepRunSourceInstance{
|
||||
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
|
||||
BlockDevices: b.config.BlockDevices,
|
||||
LaunchMappings: b.config.LaunchMappings,
|
||||
Comm: &b.config.RunConfig.Comm,
|
||||
Ctx: b.config.ctx,
|
||||
Debug: b.config.PackerDebug,
|
||||
|
@ -190,8 +222,8 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
}
|
||||
}
|
||||
|
||||
amiDevices := b.config.BuildAMIDevices()
|
||||
launchDevices := b.config.BuildLaunchDevices()
|
||||
amiDevices := b.config.AMIMappings.BuildEC2BlockDeviceMappings()
|
||||
launchDevices := b.config.LaunchMappings.BuildEC2BlockDeviceMappings()
|
||||
|
||||
// Build the steps
|
||||
steps := []multistep.Step{
|
||||
|
@ -227,7 +259,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
TemporarySGSourceCidrs: b.config.TemporarySGSourceCidrs,
|
||||
},
|
||||
&awscommon.StepCleanupVolumes{
|
||||
BlockDevices: b.config.BlockDevices,
|
||||
LaunchMappings: b.config.LaunchMappings.Common(),
|
||||
},
|
||||
instanceStep,
|
||||
&awscommon.StepGetPassword{
|
||||
|
@ -257,7 +289,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
},
|
||||
&StepSnapshotVolumes{
|
||||
LaunchDevices: launchDevices,
|
||||
SnapshotOmitMap: b.config.GetOmissions(),
|
||||
SnapshotOmitMap: b.config.LaunchMappings.GetOmissions(),
|
||||
},
|
||||
&awscommon.StepDeregisterAMI{
|
||||
AccessConfig: &b.config.AccessConfig,
|
||||
|
@ -273,7 +305,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
EnableAMISriovNetSupport: b.config.AMISriovNetSupport,
|
||||
EnableAMIENASupport: b.config.AMIENASupport,
|
||||
Architecture: b.config.Architecture,
|
||||
LaunchOmitMap: b.config.GetOmissions(),
|
||||
LaunchOmitMap: b.config.LaunchMappings.GetOmissions(),
|
||||
},
|
||||
&awscommon.StepAMIRegionCopy{
|
||||
AccessConfig: &b.config.AccessConfig,
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package ebssurrogate
|
||||
|
||||
import (
|
||||
|
@ -7,12 +9,30 @@ import (
|
|||
)
|
||||
|
||||
type RootBlockDevice struct {
|
||||
SourceDeviceName string `mapstructure:"source_device_name"`
|
||||
DeviceName string `mapstructure:"device_name"`
|
||||
DeleteOnTermination bool `mapstructure:"delete_on_termination"`
|
||||
IOPS int64 `mapstructure:"iops"`
|
||||
VolumeType string `mapstructure:"volume_type"`
|
||||
VolumeSize int64 `mapstructure:"volume_size"`
|
||||
SourceDeviceName string `mapstructure:"source_device_name"`
|
||||
// The device name exposed to the instance (for
|
||||
// example, /dev/sdh or xvdh). Required for every device in the block
|
||||
// device mapping.
|
||||
DeviceName string `mapstructure:"device_name" required:"false"`
|
||||
// Indicates whether the EBS volume is
|
||||
// deleted on instance termination. Default false. NOTE: If this
|
||||
// value is not explicitly set to true and volumes are not cleaned up by
|
||||
// an alternative method, additional volumes will accumulate after every
|
||||
// build.
|
||||
DeleteOnTermination bool `mapstructure:"delete_on_termination" required:"false"`
|
||||
// The number of I/O operations per second (IOPS) that
|
||||
// the volume supports. See the documentation on
|
||||
// IOPs
|
||||
// for more information
|
||||
IOPS int64 `mapstructure:"iops" required:"false"`
|
||||
// The volume type. gp2 for General Purpose
|
||||
// (SSD) volumes, io1 for Provisioned IOPS (SSD) volumes, st1 for
|
||||
// Throughput Optimized HDD, sc1 for Cold HDD, and standard for
|
||||
// Magnetic volumes.
|
||||
VolumeType string `mapstructure:"volume_type" required:"false"`
|
||||
// The size of the volume, in GiB. Required if
|
||||
// not specifying a snapshot_id.
|
||||
VolumeSize int64 `mapstructure:"volume_size" required:"false"`
|
||||
}
|
||||
|
||||
func (c *RootBlockDevice) Prepare(ctx *interpolate.Context) []error {
|
||||
|
|
|
@ -1,29 +1,37 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package ebsvolume
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
awscommon "github.com/hashicorp/packer/builder/amazon/common"
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
type BlockDevice struct {
|
||||
awscommon.BlockDevice `mapstructure:"-,squash"`
|
||||
Tags awscommon.TagMap `mapstructure:"tags"`
|
||||
awscommon.BlockDevice `mapstructure:",squash"`
|
||||
// Tags to apply to the volume. These are retained after the builder
|
||||
// completes. This is a [template engine](/docs/templates/engine.html), see
|
||||
// [Build template data](#build-template-data) for more information.
|
||||
Tags awscommon.TagMap `mapstructure:"tags" required:"false"`
|
||||
}
|
||||
|
||||
func commonBlockDevices(mappings []BlockDevice, ctx *interpolate.Context) (awscommon.BlockDevices, error) {
|
||||
result := make([]awscommon.BlockDevice, len(mappings))
|
||||
type BlockDevices []BlockDevice
|
||||
|
||||
for i, mapping := range mappings {
|
||||
interpolateBlockDev, err := interpolate.RenderInterface(&mapping.BlockDevice, ctx)
|
||||
if err != nil {
|
||||
return awscommon.BlockDevices{}, err
|
||||
}
|
||||
result[i] = *interpolateBlockDev.(*awscommon.BlockDevice)
|
||||
func (bds BlockDevices) BuildEC2BlockDeviceMappings() []*ec2.BlockDeviceMapping {
|
||||
var blockDevices []*ec2.BlockDeviceMapping
|
||||
|
||||
for _, blockDevice := range bds {
|
||||
blockDevices = append(blockDevices, blockDevice.BuildEC2BlockDeviceMapping())
|
||||
}
|
||||
|
||||
return awscommon.BlockDevices{
|
||||
LaunchBlockDevices: awscommon.LaunchBlockDevices{
|
||||
LaunchMappings: result,
|
||||
},
|
||||
}, nil
|
||||
return blockDevices
|
||||
}
|
||||
|
||||
func (bds BlockDevices) Prepare(ctx *interpolate.Context) (errs []error) {
|
||||
for _, block := range bds {
|
||||
if err := block.Prepare(ctx); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
// The ebsvolume package contains a packer.Builder implementation that
|
||||
// builds EBS volumes for Amazon EC2 using an ephemeral instance,
|
||||
//go:generate struct-markdown
|
||||
|
||||
// The ebsvolume package contains a packer.Builder implementation that builds
|
||||
// EBS volumes for Amazon EC2 using an ephemeral instance,
|
||||
package ebsvolume
|
||||
|
||||
import (
|
||||
|
@ -23,13 +25,47 @@ type Config struct {
|
|||
awscommon.AccessConfig `mapstructure:",squash"`
|
||||
awscommon.RunConfig `mapstructure:",squash"`
|
||||
|
||||
AMIENASupport config.Trilean `mapstructure:"ena_support"`
|
||||
AMISriovNetSupport bool `mapstructure:"sriov_support"`
|
||||
VolumeMappings []BlockDevice `mapstructure:"ebs_volumes"`
|
||||
VolumeRunTags awscommon.TagMap `mapstructure:"run_volume_tags"`
|
||||
// Enable enhanced networking (ENA but not SriovNetSupport) on
|
||||
// HVM-compatible AMIs. If set, add `ec2:ModifyInstanceAttribute` to your
|
||||
// AWS IAM policy. Note: you must make sure enhanced networking is enabled
|
||||
// on your instance. See [Amazon's documentation on enabling enhanced
|
||||
// networking](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking.html#enabling_enhanced_networking).
|
||||
AMIENASupport config.Trilean `mapstructure:"ena_support" required:"false"`
|
||||
// Enable enhanced networking (SriovNetSupport but not ENA) on
|
||||
// HVM-compatible AMIs. If true, add `ec2:ModifyInstanceAttribute` to your
|
||||
// AWS IAM policy. Note: you must make sure enhanced networking is enabled
|
||||
// on your instance. See [Amazon's documentation on enabling enhanced
|
||||
// networking](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking.html#enabling_enhanced_networking).
|
||||
// Default `false`.
|
||||
AMISriovNetSupport bool `mapstructure:"sriov_support" required:"false"`
|
||||
|
||||
launchBlockDevices awscommon.BlockDevices
|
||||
ctx interpolate.Context
|
||||
// Add the block device mappings to the AMI. If you add instance store
|
||||
// volumes or EBS volumes in addition to the root device volume, the
|
||||
// created AMI will contain block device mapping information for those
|
||||
// volumes. Amazon creates snapshots of the source instance's root volume
|
||||
// and any other EBS volumes described here. When you launch an instance
|
||||
// from this new AMI, the instance automatically launches with these
|
||||
// additional volumes, and will restore them from snapshots taken from the
|
||||
// source instance. See the [BlockDevices](#block-devices-configuration)
|
||||
// documentation for fields.
|
||||
VolumeMappings BlockDevices `mapstructure:"ebs_volumes" required:"false"`
|
||||
// Tags to apply to the volumes of the instance that is *launched* to
|
||||
// create EBS Volumes. These tags will *not* appear in the tags of the
|
||||
// resulting EBS volumes unless they're duplicated under `tags` in the
|
||||
// `ebs_volumes` setting. This is a [template
|
||||
// engine](/docs/templates/engine.html), see [Build template
|
||||
// data](#build-template-data) for more information.
|
||||
//
|
||||
// Note: The tags specified here will be *temporarily* applied to volumes
|
||||
// specified in `ebs_volumes` - but only while the instance is being
|
||||
// created. Packer will replace all tags on the volume with the tags
|
||||
// configured in the `ebs_volumes` section as soon as the instance is
|
||||
// reported as 'ready'.
|
||||
VolumeRunTags awscommon.TagMap `mapstructure:"run_volume_tags"`
|
||||
|
||||
launchBlockDevices BlockDevices
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
||||
type Builder struct {
|
||||
|
@ -71,7 +107,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
|||
}
|
||||
}
|
||||
|
||||
b.config.launchBlockDevices, err = commonBlockDevices(b.config.VolumeMappings, &b.config.ctx)
|
||||
b.config.launchBlockDevices = b.config.VolumeMappings
|
||||
if err != nil {
|
||||
errs = packer.MultiErrorAppend(errs, err)
|
||||
}
|
||||
|
@ -119,7 +155,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
if b.config.IsSpotInstance() {
|
||||
instanceStep = &awscommon.StepRunSpotInstance{
|
||||
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
|
||||
BlockDevices: b.config.launchBlockDevices,
|
||||
LaunchMappings: b.config.launchBlockDevices,
|
||||
BlockDurationMinutes: b.config.BlockDurationMinutes,
|
||||
Comm: &b.config.RunConfig.Comm,
|
||||
Ctx: b.config.ctx,
|
||||
|
@ -141,7 +177,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
} else {
|
||||
instanceStep = &awscommon.StepRunSourceInstance{
|
||||
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
|
||||
BlockDevices: b.config.launchBlockDevices,
|
||||
LaunchMappings: b.config.launchBlockDevices,
|
||||
Comm: &b.config.RunConfig.Comm,
|
||||
Ctx: b.config.ctx,
|
||||
Debug: b.config.PackerDebug,
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
// The instance package contains a packer.Builder implementation that builds
|
||||
// AMIs for Amazon EC2 backed by instance storage, as opposed to EBS storage.
|
||||
package instance
|
||||
|
@ -22,24 +24,65 @@ import (
|
|||
// The unique ID for this builder
|
||||
const BuilderId = "mitchellh.amazon.instance"
|
||||
|
||||
// Config is the configuration that is chained through the steps and
|
||||
// settable from the template.
|
||||
// Config is the configuration that is chained through the steps and settable
|
||||
// from the template.
|
||||
type Config struct {
|
||||
common.PackerConfig `mapstructure:",squash"`
|
||||
awscommon.AccessConfig `mapstructure:",squash"`
|
||||
awscommon.AMIConfig `mapstructure:",squash"`
|
||||
awscommon.BlockDevices `mapstructure:",squash"`
|
||||
awscommon.RunConfig `mapstructure:",squash"`
|
||||
|
||||
AccountId string `mapstructure:"account_id"`
|
||||
BundleDestination string `mapstructure:"bundle_destination"`
|
||||
BundlePrefix string `mapstructure:"bundle_prefix"`
|
||||
BundleUploadCommand string `mapstructure:"bundle_upload_command"`
|
||||
BundleVolCommand string `mapstructure:"bundle_vol_command"`
|
||||
S3Bucket string `mapstructure:"s3_bucket"`
|
||||
X509CertPath string `mapstructure:"x509_cert_path"`
|
||||
X509KeyPath string `mapstructure:"x509_key_path"`
|
||||
X509UploadPath string `mapstructure:"x509_upload_path"`
|
||||
// Add one or more block device mappings to the AMI. These will be attached
|
||||
// when booting a new instance from your AMI. To add a block device during
|
||||
// the Packer build see `launch_block_device_mappings` below. Your options
|
||||
// here may vary depending on the type of VM you use. See the
|
||||
// [BlockDevices](#block-devices-configuration) documentation for fields.
|
||||
AMIMappings awscommon.BlockDevices `mapstructure:"ami_block_device_mappings" required:"false"`
|
||||
// Add one or more block devices before the Packer build starts. If you add
|
||||
// instance store volumes or EBS volumes in addition to the root device
|
||||
// volume, the created AMI will contain block device mapping information
|
||||
// for those volumes. Amazon creates snapshots of the source instance's
|
||||
// root volume and any other EBS volumes described here. When you launch an
|
||||
// instance from this new AMI, the instance automatically launches with
|
||||
// these additional volumes, and will restore them from snapshots taken
|
||||
// from the source instance. See the
|
||||
// [BlockDevices](#block-devices-configuration) documentation for fields.
|
||||
LaunchMappings awscommon.BlockDevices `mapstructure:"launch_block_device_mappings" required:"false"`
|
||||
// Your AWS account ID. This is required for bundling the AMI. This is not
|
||||
// the same as the access key. You can find your account ID in the security
|
||||
// credentials page of your AWS account.
|
||||
AccountId string `mapstructure:"account_id" required:"true"`
|
||||
// The directory on the running instance where the bundled AMI will be
|
||||
// saved prior to uploading. By default this is /tmp. This directory must
|
||||
// exist and be writable.
|
||||
BundleDestination string `mapstructure:"bundle_destination" required:"false"`
|
||||
// The prefix for files created from bundling the root volume. By default
|
||||
// this is image-{{timestamp}}. The timestamp variable should be used to
|
||||
// make sure this is unique, otherwise it can collide with other created
|
||||
// AMIs by Packer in your account.
|
||||
BundlePrefix string `mapstructure:"bundle_prefix" required:"false"`
|
||||
// The command to use to upload the bundled volume. See the "custom bundle
|
||||
// commands" section below for more information.
|
||||
BundleUploadCommand string `mapstructure:"bundle_upload_command" required:"false"`
|
||||
// The command to use to bundle the volume. See the "custom bundle
|
||||
// commands" section below for more information.
|
||||
BundleVolCommand string `mapstructure:"bundle_vol_command" required:"false"`
|
||||
// The name of the S3 bucket to upload the AMI. This bucket will be created
|
||||
// if it doesn't exist.
|
||||
S3Bucket string `mapstructure:"s3_bucket" required:"true"`
|
||||
// The local path to a valid X509 certificate for your AWS account. This is
|
||||
// used for bundling the AMI. This X509 certificate must be registered with
|
||||
// your account from the security credentials page in the AWS console.
|
||||
X509CertPath string `mapstructure:"x509_cert_path" required:"true"`
|
||||
// The local path to the private key for the X509 certificate specified by
|
||||
// x509_cert_path. This is used for bundling the AMI.
|
||||
X509KeyPath string `mapstructure:"x509_key_path" required:"true"`
|
||||
// The path on the remote machine where the X509 certificate will be
|
||||
// uploaded. This path must already exist and be writable. X509
|
||||
// certificates are uploaded after provisioning is run, so it is perfectly
|
||||
// okay to create this directory as part of the provisioning process.
|
||||
// Defaults to /tmp.
|
||||
X509UploadPath string `mapstructure:"x509_upload_path" required:"false"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
@ -128,7 +171,8 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
|||
var errs *packer.MultiError
|
||||
var warns []string
|
||||
errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(&b.config.ctx)...)
|
||||
errs = packer.MultiErrorAppend(errs, b.config.BlockDevices.Prepare(&b.config.ctx)...)
|
||||
errs = packer.MultiErrorAppend(errs, b.config.AMIMappings.Prepare(&b.config.ctx)...)
|
||||
errs = packer.MultiErrorAppend(errs, b.config.LaunchMappings.Prepare(&b.config.ctx)...)
|
||||
errs = packer.MultiErrorAppend(errs,
|
||||
b.config.AMIConfig.Prepare(&b.config.AccessConfig, &b.config.ctx)...)
|
||||
errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...)
|
||||
|
@ -201,7 +245,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
if b.config.IsSpotInstance() {
|
||||
instanceStep = &awscommon.StepRunSpotInstance{
|
||||
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
|
||||
BlockDevices: b.config.BlockDevices,
|
||||
LaunchMappings: b.config.LaunchMappings,
|
||||
BlockDurationMinutes: b.config.BlockDurationMinutes,
|
||||
Ctx: b.config.ctx,
|
||||
Comm: &b.config.RunConfig.Comm,
|
||||
|
@ -220,7 +264,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
} else {
|
||||
instanceStep = &awscommon.StepRunSourceInstance{
|
||||
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
|
||||
BlockDevices: b.config.BlockDevices,
|
||||
LaunchMappings: b.config.LaunchMappings,
|
||||
Comm: &b.config.RunConfig.Comm,
|
||||
Ctx: b.config.ctx,
|
||||
Debug: b.config.PackerDebug,
|
||||
|
|
|
@ -27,7 +27,7 @@ func (s *StepRegisterAMI) Run(ctx context.Context, state multistep.StateBag) mul
|
|||
registerOpts := &ec2.RegisterImageInput{
|
||||
ImageLocation: &manifestPath,
|
||||
Name: aws.String(config.AMIName),
|
||||
BlockDeviceMappings: config.BlockDevices.BuildAMIDevices(),
|
||||
BlockDeviceMappings: config.AMIMappings.BuildEC2BlockDeviceMappings(),
|
||||
}
|
||||
|
||||
if config.AMIVirtType != "" {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package arm
|
||||
|
||||
import (
|
||||
|
@ -14,9 +16,10 @@ import (
|
|||
|
||||
// ClientConfig allows for various ways to authenticate Azure clients
|
||||
type ClientConfig struct {
|
||||
// Describes where API's are
|
||||
|
||||
CloudEnvironmentName string `mapstructure:"cloud_environment_name"`
|
||||
// One of Public, China, Germany, or
|
||||
// USGovernment. Defaults to Public. Long forms such as
|
||||
// USGovernmentCloud and AzureUSGovernmentCloud are also supported.
|
||||
CloudEnvironmentName string `mapstructure:"cloud_environment_name" required:"false"`
|
||||
cloudEnvironment *azure.Environment
|
||||
|
||||
// Authentication fields
|
||||
|
@ -28,9 +31,12 @@ type ClientConfig struct {
|
|||
// Certificate path for client auth
|
||||
ClientCertPath string `mapstructure:"client_cert_path"`
|
||||
// JWT bearer token for client auth (RFC 7523, Sec. 2.2)
|
||||
ClientJWT string `mapstructure:"client_jwt"`
|
||||
ObjectID string `mapstructure:"object_id"`
|
||||
TenantID string `mapstructure:"tenant_id"`
|
||||
ClientJWT string `mapstructure:"client_jwt"`
|
||||
ObjectID string `mapstructure:"object_id"`
|
||||
// The account identifier with which your client_id and
|
||||
// subscription_id are associated. If not specified, tenant_id will be
|
||||
// looked up using subscription_id.
|
||||
TenantID string `mapstructure:"tenant_id" required:"false"`
|
||||
SubscriptionID string `mapstructure:"subscription_id"`
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package arm
|
||||
|
||||
import (
|
||||
|
@ -70,7 +72,12 @@ type SharedImageGallery struct {
|
|||
ResourceGroup string `mapstructure:"resource_group"`
|
||||
GalleryName string `mapstructure:"gallery_name"`
|
||||
ImageName string `mapstructure:"image_name"`
|
||||
ImageVersion string `mapstructure:"image_version"`
|
||||
// Specify a specific version of an OS to boot from.
|
||||
// Defaults to latest. There may be a difference in versions available
|
||||
// across regions due to image synchronization latency. To ensure a consistent
|
||||
// version across regions set this value to one that is available in all
|
||||
// regions where you are deploying.
|
||||
ImageVersion string `mapstructure:"image_version" required:"false"`
|
||||
}
|
||||
|
||||
type SharedImageGalleryDestination struct {
|
||||
|
@ -90,61 +97,249 @@ type Config struct {
|
|||
// Capture
|
||||
CaptureNamePrefix string `mapstructure:"capture_name_prefix"`
|
||||
CaptureContainerName string `mapstructure:"capture_container_name"`
|
||||
|
||||
// Shared Gallery
|
||||
SharedGallery SharedImageGallery `mapstructure:"shared_image_gallery"`
|
||||
|
||||
// Shared Gallery Destination
|
||||
// Use a [Shared Gallery
|
||||
// image](https://azure.microsoft.com/en-us/blog/announcing-the-public-preview-of-shared-image-gallery/)
|
||||
// as the source for this build. *VHD targets are incompatible with this
|
||||
// build type* - the target must be a *Managed Image*.
|
||||
//
|
||||
// "shared_image_gallery": {
|
||||
// "subscription": "00000000-0000-0000-0000-00000000000",
|
||||
// "resource_group": "ResourceGroup",
|
||||
// "gallery_name": "GalleryName",
|
||||
// "image_name": "ImageName",
|
||||
// "image_version": "1.0.0"
|
||||
// }
|
||||
// "managed_image_name": "TargetImageName",
|
||||
// "managed_image_resource_group_name": "TargetResourceGroup"
|
||||
SharedGallery SharedImageGallery `mapstructure:"shared_image_gallery" required:"false"`
|
||||
// The name of the Shared Image Gallery under which the managed image will be published as Shared Gallery Image version.
|
||||
//
|
||||
// Following is an example.
|
||||
//
|
||||
// <!-- -->
|
||||
//
|
||||
// "shared_image_gallery_destination": {
|
||||
// "resource_group": "ResourceGroup",
|
||||
// "gallery_name": "GalleryName",
|
||||
// "image_name": "ImageName",
|
||||
// "image_version": "1.0.0",
|
||||
// "replication_regions": ["regionA", "regionB", "regionC"]
|
||||
// }
|
||||
// "managed_image_name": "TargetImageName",
|
||||
// "managed_image_resource_group_name": "TargetResourceGroup"
|
||||
SharedGalleryDestination SharedImageGalleryDestination `mapstructure:"shared_image_gallery_destination"`
|
||||
SharedGalleryTimeout time.Duration `mapstructure:"shared_image_gallery_timeout"`
|
||||
|
||||
// Compute
|
||||
ImagePublisher string `mapstructure:"image_publisher"`
|
||||
ImageOffer string `mapstructure:"image_offer"`
|
||||
ImageSku string `mapstructure:"image_sku"`
|
||||
ImageVersion string `mapstructure:"image_version"`
|
||||
ImageUrl string `mapstructure:"image_url"`
|
||||
|
||||
CustomManagedImageResourceGroupName string `mapstructure:"custom_managed_image_resource_group_name"`
|
||||
CustomManagedImageName string `mapstructure:"custom_managed_image_name"`
|
||||
customManagedImageID string
|
||||
// How long to wait for an image to be published to the shared image
|
||||
// gallery before timing out. If your Packer build is failing on the
|
||||
// Publishing to Shared Image Gallery step with the error `Original Error:
|
||||
// context deadline exceeded`, but the image is present when you check your
|
||||
// Azure dashboard, then you probably need to increase this timeout from
|
||||
// its default of "60m" (valid time units include `s` for seconds, `m` for
|
||||
// minutes, and `h` for hours.)
|
||||
SharedGalleryTimeout time.Duration `mapstructure:"shared_image_gallery_timeout"`
|
||||
// PublisherName for your base image. See
|
||||
// [documentation](https://azure.microsoft.com/en-us/documentation/articles/resource-groups-vm-searching/)
|
||||
// for details.
|
||||
//
|
||||
// CLI example `az vm image list-publishers --location westus`
|
||||
ImagePublisher string `mapstructure:"image_publisher" required:"true"`
|
||||
// Offer for your base image. See
|
||||
// [documentation](https://azure.microsoft.com/en-us/documentation/articles/resource-groups-vm-searching/)
|
||||
// for details.
|
||||
//
|
||||
// CLI example
|
||||
// `az vm image list-offers --location westus --publisher Canonical`
|
||||
ImageOffer string `mapstructure:"image_offer" required:"true"`
|
||||
// SKU for your base image. See
|
||||
// [documentation](https://azure.microsoft.com/en-us/documentation/articles/resource-groups-vm-searching/)
|
||||
// for details.
|
||||
//
|
||||
// CLI example
|
||||
// `az vm image list-skus --location westus --publisher Canonical --offer UbuntuServer`
|
||||
ImageSku string `mapstructure:"image_sku" required:"true"`
|
||||
// Specify a specific version of an OS to boot from.
|
||||
// Defaults to `latest`. There may be a difference in versions available
|
||||
// across regions due to image synchronization latency. To ensure a consistent
|
||||
// version across regions set this value to one that is available in all
|
||||
// regions where you are deploying.
|
||||
//
|
||||
// CLI example
|
||||
// `az vm image list --location westus --publisher Canonical --offer UbuntuServer --sku 16.04.0-LTS --all`
|
||||
ImageVersion string `mapstructure:"image_version" required:"false"`
|
||||
// Specify a custom VHD to use. If this value is set, do
|
||||
// not set image_publisher, image_offer, image_sku, or image_version.
|
||||
ImageUrl string `mapstructure:"image_url" required:"false"`
|
||||
// Specify the source managed image's resource group used to use. If this
|
||||
// value is set, do not set image\_publisher, image\_offer, image\_sku, or
|
||||
// image\_version. If this value is set, the value
|
||||
// `custom_managed_image_name` must also be set. See
|
||||
// [documentation](https://docs.microsoft.com/en-us/azure/storage/storage-managed-disks-overview#images)
|
||||
// to learn more about managed images.
|
||||
CustomManagedImageResourceGroupName string `mapstructure:"custom_managed_image_resource_group_name" required:"false"`
|
||||
// Specify the source managed image's name to use. If this value is set, do
|
||||
// not set image\_publisher, image\_offer, image\_sku, or image\_version.
|
||||
// If this value is set, the value
|
||||
// `custom_managed_image_resource_group_name` must also be set. See
|
||||
// [documentation](https://docs.microsoft.com/en-us/azure/storage/storage-managed-disks-overview#images)
|
||||
// to learn more about managed images.
|
||||
CustomManagedImageName string `mapstructure:"custom_managed_image_name" required:"false"`
|
||||
customManagedImageID string
|
||||
|
||||
Location string `mapstructure:"location"`
|
||||
VMSize string `mapstructure:"vm_size"`
|
||||
// Size of the VM used for building. This can be changed when you deploy a
|
||||
// VM from your VHD. See
|
||||
// [pricing](https://azure.microsoft.com/en-us/pricing/details/virtual-machines/)
|
||||
// information. Defaults to `Standard_A1`.
|
||||
//
|
||||
// CLI example `az vm list-sizes --location westus`
|
||||
VMSize string `mapstructure:"vm_size" required:"false"`
|
||||
|
||||
ManagedImageResourceGroupName string `mapstructure:"managed_image_resource_group_name"`
|
||||
ManagedImageName string `mapstructure:"managed_image_name"`
|
||||
ManagedImageStorageAccountType string `mapstructure:"managed_image_storage_account_type"`
|
||||
managedImageStorageAccountType compute.StorageAccountTypes
|
||||
ManagedImageOSDiskSnapshotName string `mapstructure:"managed_image_os_disk_snapshot_name"`
|
||||
ManagedImageDataDiskSnapshotPrefix string `mapstructure:"managed_image_data_disk_snapshot_prefix"`
|
||||
// Specify the managed image resource group name where the result of the
|
||||
// Packer build will be saved. The resource group must already exist. If
|
||||
// this value is set, the value managed_image_name must also be set. See
|
||||
// documentation to learn more about managed images.
|
||||
ManagedImageResourceGroupName string `mapstructure:"managed_image_resource_group_name"`
|
||||
// Specify the managed image name where the result of the Packer build will
|
||||
// be saved. The image name must not exist ahead of time, and will not be
|
||||
// overwritten. If this value is set, the value
|
||||
// managed_image_resource_group_name must also be set. See documentation to
|
||||
// learn more about managed images.
|
||||
ManagedImageName string `mapstructure:"managed_image_name"`
|
||||
// Specify the storage account
|
||||
// type for a managed image. Valid values are Standard_LRS and Premium_LRS.
|
||||
// The default is Standard_LRS.
|
||||
ManagedImageStorageAccountType string `mapstructure:"managed_image_storage_account_type" required:"false"`
|
||||
managedImageStorageAccountType compute.StorageAccountTypes
|
||||
// If
|
||||
// managed_image_os_disk_snapshot_name is set, a snapshot of the OS disk
|
||||
// is created with the same name as this value before the VM is captured.
|
||||
ManagedImageOSDiskSnapshotName string `mapstructure:"managed_image_os_disk_snapshot_name" required:"false"`
|
||||
// If
|
||||
// managed_image_data_disk_snapshot_prefix is set, snapshot of the data
|
||||
// disk(s) is created with the same prefix as this value before the VM is
|
||||
// captured.
|
||||
ManagedImageDataDiskSnapshotPrefix string `mapstructure:"managed_image_data_disk_snapshot_prefix" required:"false"`
|
||||
manageImageLocation string
|
||||
ManagedImageZoneResilient bool `mapstructure:"managed_image_zone_resilient"`
|
||||
|
||||
// Deployment
|
||||
AzureTags map[string]*string `mapstructure:"azure_tags"`
|
||||
ResourceGroupName string `mapstructure:"resource_group_name"`
|
||||
StorageAccount string `mapstructure:"storage_account"`
|
||||
TempComputeName string `mapstructure:"temp_compute_name"`
|
||||
TempResourceGroupName string `mapstructure:"temp_resource_group_name"`
|
||||
BuildResourceGroupName string `mapstructure:"build_resource_group_name"`
|
||||
storageAccountBlobEndpoint string
|
||||
PrivateVirtualNetworkWithPublicIp bool `mapstructure:"private_virtual_network_with_public_ip"`
|
||||
VirtualNetworkName string `mapstructure:"virtual_network_name"`
|
||||
VirtualNetworkSubnetName string `mapstructure:"virtual_network_subnet_name"`
|
||||
VirtualNetworkResourceGroupName string `mapstructure:"virtual_network_resource_group_name"`
|
||||
CustomDataFile string `mapstructure:"custom_data_file"`
|
||||
customData string
|
||||
PlanInfo PlanInformation `mapstructure:"plan_info"`
|
||||
|
||||
// OS
|
||||
OSType string `mapstructure:"os_type"`
|
||||
OSDiskSizeGB int32 `mapstructure:"os_disk_size_gb"`
|
||||
|
||||
// Additional Disks
|
||||
AdditionalDiskSize []int32 `mapstructure:"disk_additional_size"`
|
||||
DiskCachingType string `mapstructure:"disk_caching_type"`
|
||||
diskCachingType compute.CachingTypes
|
||||
// Store the image in zone-resilient storage. You need to create it in a
|
||||
// region that supports [availability
|
||||
// zones](https://docs.microsoft.com/en-us/azure/availability-zones/az-overview).
|
||||
ManagedImageZoneResilient bool `mapstructure:"managed_image_zone_resilient" required:"false"`
|
||||
// the user can define up to 15
|
||||
// tags. Tag names cannot exceed 512 characters, and tag values cannot exceed
|
||||
// 256 characters. Tags are applied to every resource deployed by a Packer
|
||||
// build, i.e. Resource Group, VM, NIC, VNET, Public IP, KeyVault, etc.
|
||||
AzureTags map[string]*string `mapstructure:"azure_tags" required:"false"`
|
||||
// Resource group under which the final artifact will be stored.
|
||||
ResourceGroupName string `mapstructure:"resource_group_name"`
|
||||
// Storage account under which the final artifact will be stored.
|
||||
StorageAccount string `mapstructure:"storage_account"`
|
||||
// temporary name assigned to the VM. If this
|
||||
// value is not set, a random value will be assigned. Knowing the resource
|
||||
// group and VM name allows one to execute commands to update the VM during a
|
||||
// Packer build, e.g. attach a resource disk to the VM.
|
||||
TempComputeName string `mapstructure:"temp_compute_name" required:"false"`
|
||||
// name assigned to the temporary resource group created during the build.
|
||||
// If this value is not set, a random value will be assigned. This resource
|
||||
// group is deleted at the end of the build.
|
||||
TempResourceGroupName string `mapstructure:"temp_resource_group_name"`
|
||||
// Specify an existing resource group to run the build in.
|
||||
BuildResourceGroupName string `mapstructure:"build_resource_group_name"`
|
||||
storageAccountBlobEndpoint string
|
||||
// This value allows you to
|
||||
// set a virtual_network_name and obtain a public IP. If this value is not
|
||||
// set and virtual_network_name is defined Packer is only allowed to be
|
||||
// executed from a host on the same subnet / virtual network.
|
||||
PrivateVirtualNetworkWithPublicIp bool `mapstructure:"private_virtual_network_with_public_ip" required:"false"`
|
||||
// Use a pre-existing virtual network for the
|
||||
// VM. This option enables private communication with the VM, no public IP
|
||||
// address is used or provisioned (unless you set
|
||||
// private_virtual_network_with_public_ip).
|
||||
VirtualNetworkName string `mapstructure:"virtual_network_name" required:"false"`
|
||||
// If virtual_network_name is set,
|
||||
// this value may also be set. If virtual_network_name is set, and this
|
||||
// value is not set the builder attempts to determine the subnet to use with
|
||||
// the virtual network. If the subnet cannot be found, or it cannot be
|
||||
// disambiguated, this value should be set.
|
||||
VirtualNetworkSubnetName string `mapstructure:"virtual_network_subnet_name" required:"false"`
|
||||
// If virtual_network_name is
|
||||
// set, this value may also be set. If virtual_network_name is set, and
|
||||
// this value is not set the builder attempts to determine the resource group
|
||||
// containing the virtual network. If the resource group cannot be found, or
|
||||
// it cannot be disambiguated, this value should be set.
|
||||
VirtualNetworkResourceGroupName string `mapstructure:"virtual_network_resource_group_name" required:"false"`
|
||||
// Specify a file containing custom data to inject into the cloud-init
|
||||
// process. The contents of the file are read and injected into the ARM
|
||||
// template. The custom data will be passed to cloud-init for processing at
|
||||
// the time of provisioning. See
|
||||
// [documentation](http://cloudinit.readthedocs.io/en/latest/topics/examples.html)
|
||||
// to learn more about custom data, and how it can be used to influence the
|
||||
// provisioning process.
|
||||
CustomDataFile string `mapstructure:"custom_data_file" required:"false"`
|
||||
customData string
|
||||
// Used for creating images from Marketplace images. Please refer to
|
||||
// [Deploy an image with Marketplace
|
||||
// terms](https://aka.ms/azuremarketplaceapideployment) for more details.
|
||||
// Not all Marketplace images support programmatic deployment, and support
|
||||
// is controlled by the image publisher.
|
||||
//
|
||||
// An example plan\_info object is defined below.
|
||||
//
|
||||
// ``` json
|
||||
// {
|
||||
// "plan_info": {
|
||||
// "plan_name": "rabbitmq",
|
||||
// "plan_product": "rabbitmq",
|
||||
// "plan_publisher": "bitnami"
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// `plan_name` (string) - The plan name, required. `plan_product` (string) -
|
||||
// The plan product, required. `plan_publisher` (string) - The plan publisher,
|
||||
// required. `plan_promotion_code` (string) - Some images accept a promotion
|
||||
// code, optional.
|
||||
//
|
||||
// Images created from the Marketplace with `plan_info` **must** specify
|
||||
// `plan_info` whenever the image is deployed. The builder automatically adds
|
||||
// tags to the image to ensure this information is not lost. The following
|
||||
// tags are added.
|
||||
//
|
||||
// 1. PlanName
|
||||
// 2. PlanProduct
|
||||
// 3. PlanPublisher
|
||||
// 4. PlanPromotionCode
|
||||
//
|
||||
PlanInfo PlanInformation `mapstructure:"plan_info" required:"false"`
|
||||
// If either Linux or Windows is specified Packer will
|
||||
// automatically configure authentication credentials for the provisioned
|
||||
// machine. For Linux this configures an SSH authorized key. For Windows
|
||||
// this configures a WinRM certificate.
|
||||
OSType string `mapstructure:"os_type" required:"false"`
|
||||
// Specify the size of the OS disk in GB
|
||||
// (gigabytes). Values of zero or less than zero are ignored.
|
||||
OSDiskSizeGB int32 `mapstructure:"os_disk_size_gb" required:"false"`
|
||||
// The size(s) of any additional hard disks for the VM in gigabytes. If
|
||||
// this is not specified then the VM will only contain an OS disk. The
|
||||
// number of additional disks and maximum size of a disk depends on the
|
||||
// configuration of your VM. See
|
||||
// [Windows](https://docs.microsoft.com/en-us/azure/virtual-machines/windows/about-disks-and-vhds)
|
||||
// or
|
||||
// [Linux](https://docs.microsoft.com/en-us/azure/virtual-machines/linux/about-disks-and-vhds)
|
||||
// for more information.
|
||||
//
|
||||
// For VHD builds the final artifacts will be named
|
||||
// `PREFIX-dataDisk-<n>.UUID.vhd` and stored in the specified capture
|
||||
// container along side the OS disk. The additional disks are included in
|
||||
// the deployment template `PREFIX-vmTemplate.UUID`.
|
||||
//
|
||||
// For Managed build the final artifacts are included in the managed image.
|
||||
// The additional disk will have the same storage account type as the OS
|
||||
// disk, as specified with the `managed_image_storage_account_type`
|
||||
// setting.
|
||||
AdditionalDiskSize []int32 `mapstructure:"disk_additional_size" required:"false"`
|
||||
// Specify the disk caching type. Valid values
|
||||
// are None, ReadOnly, and ReadWrite. The default value is ReadWrite.
|
||||
DiskCachingType string `mapstructure:"disk_caching_type" required:"false"`
|
||||
diskCachingType compute.CachingTypes
|
||||
|
||||
// Runtime Values
|
||||
UserName string
|
||||
|
@ -170,9 +365,11 @@ type Config struct {
|
|||
|
||||
Comm communicator.Config `mapstructure:",squash"`
|
||||
ctx interpolate.Context
|
||||
|
||||
//Cleanup
|
||||
AsyncResourceGroupDelete bool `mapstructure:"async_resourcegroup_delete"`
|
||||
// If you want packer to delete the
|
||||
// temporary resource group asynchronously set this value. It's a boolean
|
||||
// value and defaults to false. Important Setting this true means that
|
||||
// your builds are faster, however any failed deletes are not reported.
|
||||
AsyncResourceGroupDelete bool `mapstructure:"async_resourcegroup_delete" required:"false"`
|
||||
}
|
||||
|
||||
type keyVaultCertificate struct {
|
||||
|
|
|
@ -75,6 +75,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
Debug: b.config.PackerDebug,
|
||||
},
|
||||
&stepSetupNetworking{},
|
||||
&stepDetachIso{},
|
||||
&communicator.StepConnect{
|
||||
Config: &b.config.Comm,
|
||||
Host: communicator.CommHost(b.config.Comm.SSHHost, "ipaddress"),
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package cloudstack
|
||||
|
||||
import (
|
||||
|
@ -20,44 +22,141 @@ type Config struct {
|
|||
common.HTTPConfig `mapstructure:",squash"`
|
||||
Comm communicator.Config `mapstructure:",squash"`
|
||||
|
||||
APIURL string `mapstructure:"api_url"`
|
||||
APIKey string `mapstructure:"api_key"`
|
||||
SecretKey string `mapstructure:"secret_key"`
|
||||
AsyncTimeout time.Duration `mapstructure:"async_timeout"`
|
||||
HTTPGetOnly bool `mapstructure:"http_get_only"`
|
||||
SSLNoVerify bool `mapstructure:"ssl_no_verify"`
|
||||
|
||||
CIDRList []string `mapstructure:"cidr_list"`
|
||||
CreateSecurityGroup bool `mapstructure:"create_security_group"`
|
||||
DiskOffering string `mapstructure:"disk_offering"`
|
||||
DiskSize int64 `mapstructure:"disk_size"`
|
||||
Expunge bool `mapstructure:"expunge"`
|
||||
Hypervisor string `mapstructure:"hypervisor"`
|
||||
InstanceName string `mapstructure:"instance_name"`
|
||||
Network string `mapstructure:"network"`
|
||||
Project string `mapstructure:"project"`
|
||||
PublicIPAddress string `mapstructure:"public_ip_address"`
|
||||
PublicPort int `mapstructure:"public_port"`
|
||||
SecurityGroups []string `mapstructure:"security_groups"`
|
||||
ServiceOffering string `mapstructure:"service_offering"`
|
||||
PreventFirewallChanges bool `mapstructure:"prevent_firewall_changes"`
|
||||
SourceISO string `mapstructure:"source_iso"`
|
||||
SourceTemplate string `mapstructure:"source_template"`
|
||||
TemporaryKeypairName string `mapstructure:"temporary_keypair_name"`
|
||||
UseLocalIPAddress bool `mapstructure:"use_local_ip_address"`
|
||||
UserData string `mapstructure:"user_data"`
|
||||
UserDataFile string `mapstructure:"user_data_file"`
|
||||
Zone string `mapstructure:"zone"`
|
||||
|
||||
TemplateName string `mapstructure:"template_name"`
|
||||
TemplateDisplayText string `mapstructure:"template_display_text"`
|
||||
TemplateOS string `mapstructure:"template_os"`
|
||||
TemplateFeatured bool `mapstructure:"template_featured"`
|
||||
TemplatePublic bool `mapstructure:"template_public"`
|
||||
TemplatePasswordEnabled bool `mapstructure:"template_password_enabled"`
|
||||
TemplateRequiresHVM bool `mapstructure:"template_requires_hvm"`
|
||||
TemplateScalable bool `mapstructure:"template_scalable"`
|
||||
TemplateTag string `mapstructure:"template_tag"`
|
||||
// The CloudStack API endpoint we will connect to. It can
|
||||
// also be specified via environment variable CLOUDSTACK_API_URL, if set.
|
||||
APIURL string `mapstructure:"api_url" required:"true"`
|
||||
// The API key used to sign all API requests. It can also
|
||||
// be specified via environment variable CLOUDSTACK_API_KEY, if set.
|
||||
APIKey string `mapstructure:"api_key" required:"true"`
|
||||
// The secret key used to sign all API requests. It
|
||||
// can also be specified via environment variable CLOUDSTACK_SECRET_KEY, if
|
||||
// set.
|
||||
SecretKey string `mapstructure:"secret_key" required:"true"`
|
||||
// The time duration to wait for async calls to
|
||||
// finish. Defaults to 30m.
|
||||
AsyncTimeout time.Duration `mapstructure:"async_timeout" required:"false"`
|
||||
// Some cloud providers only allow HTTP GET calls
|
||||
// to their CloudStack API. If using such a provider, you need to set this to
|
||||
// true in order for the provider to only make GET calls and no POST calls.
|
||||
HTTPGetOnly bool `mapstructure:"http_get_only" required:"false"`
|
||||
// Set to true to skip SSL verification.
|
||||
// Defaults to false.
|
||||
SSLNoVerify bool `mapstructure:"ssl_no_verify" required:"false"`
|
||||
// List of CIDR's that will have access to the new
|
||||
// instance. This is needed in order for any provisioners to be able to
|
||||
// connect to the instance. Defaults to [ "0.0.0.0/0" ]. Only required when
|
||||
// use_local_ip_address is false.
|
||||
CIDRList []string `mapstructure:"cidr_list" required:"false"`
|
||||
// If true a temporary security group
|
||||
// will be created which allows traffic towards the instance from the
|
||||
// cidr_list. This option will be ignored if security_groups is also
|
||||
// defined. Requires expunge set to true. Defaults to false.
|
||||
CreateSecurityGroup bool `mapstructure:"create_security_group" required:"false"`
|
||||
// The name or ID of the disk offering used for the
|
||||
// instance. This option is only available (and also required) when using
|
||||
// source_iso.
|
||||
DiskOffering string `mapstructure:"disk_offering" required:"false"`
|
||||
// The size (in GB) of the root disk of the new
|
||||
// instance. This option is only available when using source_template.
|
||||
DiskSize int64 `mapstructure:"disk_size" required:"false"`
|
||||
// If `true` make a call to the CloudStack API, after loading image to
|
||||
// cache, requesting to check and detach ISO file (if any) currently
|
||||
// attached to a virtual machine. Defaults to `false`. This option is only
|
||||
// available when using `source_iso`.
|
||||
EjectISO bool `mapstructure:"eject_iso"`
|
||||
// Configure the duration time to wait, making sure virtual machine is able
|
||||
// to finish installing OS before it ejects safely. Requires `eject_iso`
|
||||
// set to `true` and this option is only available when using `source_iso`.
|
||||
EjectISODelay time.Duration `mapstructure:"eject_iso_delay"`
|
||||
// Set to true to expunge the instance when it is
|
||||
// destroyed. Defaults to false.
|
||||
Expunge bool `mapstructure:"expunge" required:"false"`
|
||||
// The target hypervisor (e.g. XenServer, KVM) for
|
||||
// the new template. This option is required when using source_iso.
|
||||
Hypervisor string `mapstructure:"hypervisor" required:"false"`
|
||||
// The name of the instance. Defaults to
|
||||
// "packer-UUID" where UUID is dynamically generated.
|
||||
InstanceName string `mapstructure:"instance_name" required:"false"`
|
||||
// The name or ID of the network to connect the instance
|
||||
// to.
|
||||
Network string `mapstructure:"network" required:"true"`
|
||||
// The name or ID of the project to deploy the instance
|
||||
// to.
|
||||
Project string `mapstructure:"project" required:"false"`
|
||||
// The public IP address or it's ID used for
|
||||
// connecting any provisioners to. If not provided, a temporary public IP
|
||||
// address will be associated and released during the Packer run.
|
||||
PublicIPAddress string `mapstructure:"public_ip_address" required:"false"`
|
||||
// The fixed port you want to configure in the port
|
||||
// forwarding rule. Set this attribute if you do not want to use the a random
|
||||
// public port.
|
||||
PublicPort int `mapstructure:"public_port" required:"false"`
|
||||
// A list of security group IDs or
|
||||
// names to associate the instance with.
|
||||
SecurityGroups []string `mapstructure:"security_groups" required:"false"`
|
||||
// The name or ID of the service offering used
|
||||
// for the instance.
|
||||
ServiceOffering string `mapstructure:"service_offering" required:"true"`
|
||||
// Set to true to prevent network
|
||||
// ACLs or firewall rules creation. Defaults to false.
|
||||
PreventFirewallChanges bool `mapstructure:"prevent_firewall_changes" required:"false"`
|
||||
// The name or ID of an ISO that will be mounted
|
||||
// before booting the instance. This option is mutually exclusive with
|
||||
// source_template. When using source_iso, both disk_offering and
|
||||
// hypervisor are required.
|
||||
SourceISO string `mapstructure:"source_iso" required:"true"`
|
||||
// The name or ID of the template used as base
|
||||
// template for the instance. This option is mutually exclusive with
|
||||
// source_iso.
|
||||
SourceTemplate string `mapstructure:"source_template" required:"true"`
|
||||
// The name of the temporary SSH key pair
|
||||
// to generate. By default, Packer generates a name that looks like
|
||||
// packer_<UUID>, where <UUID> is a 36 character unique identifier.
|
||||
TemporaryKeypairName string `mapstructure:"temporary_keypair_name" required:"false"`
|
||||
// Set to true to indicate that the
|
||||
// provisioners should connect to the local IP address of the instance.
|
||||
UseLocalIPAddress bool `mapstructure:"use_local_ip_address" required:"false"`
|
||||
// User data to launch with the instance. This is a
|
||||
// template engine see User Data bellow for
|
||||
// more details. Packer will not automatically wait for a user script to
|
||||
// finish before shutting down the instance this must be handled in a
|
||||
// provisioner.
|
||||
UserData string `mapstructure:"user_data" required:"false"`
|
||||
// Path to a file that will be used for the user
|
||||
// data when launching the instance. This file will be parsed as a template
|
||||
// engine see User Data bellow for more
|
||||
// details.
|
||||
UserDataFile string `mapstructure:"user_data_file" required:"false"`
|
||||
// The name or ID of the zone where the instance will be
|
||||
// created.
|
||||
Zone string `mapstructure:"zone" required:"true"`
|
||||
// The name of the new template. Defaults to
|
||||
// "packer-{{timestamp}}" where timestamp will be the current time.
|
||||
TemplateName string `mapstructure:"template_name" required:"false"`
|
||||
// The display text of the new template.
|
||||
// Defaults to the template_name.
|
||||
TemplateDisplayText string `mapstructure:"template_display_text" required:"false"`
|
||||
// The name or ID of the template OS for the new
|
||||
// template that will be created.
|
||||
TemplateOS string `mapstructure:"template_os" required:"true"`
|
||||
// Set to true to indicate that the template
|
||||
// is featured. Defaults to false.
|
||||
TemplateFeatured bool `mapstructure:"template_featured" required:"false"`
|
||||
// Set to true to indicate that the template
|
||||
// is available for all accounts. Defaults to false.
|
||||
TemplatePublic bool `mapstructure:"template_public" required:"false"`
|
||||
// Set to true to indicate the
|
||||
// template should be password enabled. Defaults to false.
|
||||
TemplatePasswordEnabled bool `mapstructure:"template_password_enabled" required:"false"`
|
||||
// Set to true to indicate the template
|
||||
// requires hardware-assisted virtualization. Defaults to false.
|
||||
TemplateRequiresHVM bool `mapstructure:"template_requires_hvm" required:"false"`
|
||||
// Set to true to indicate that the template
|
||||
// contains tools to support dynamic scaling of VM cpu/memory. Defaults to
|
||||
// false.
|
||||
TemplateScalable bool `mapstructure:"template_scalable" required:"false"`
|
||||
//
|
||||
TemplateTag string `mapstructure:"template_tag"`
|
||||
|
||||
Tags map[string]string `mapstructure:"tags"`
|
||||
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
package cloudstack
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/xanzy/go-cloudstack/cloudstack"
|
||||
)
|
||||
|
||||
type stepDetachIso struct{}
|
||||
|
||||
// Detaches currently ISO file attached to a virtual machine if any.
|
||||
func (s *stepDetachIso) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
config := state.Get("config").(*Config)
|
||||
|
||||
// Check if state uses iso file and has need to eject it
|
||||
if !config.EjectISO || config.SourceISO == "" {
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
ui.Say("Checking attached iso...")
|
||||
|
||||
// Wait to make call detachIso
|
||||
if config.EjectISODelay > 0 {
|
||||
ui.Message(fmt.Sprintf("Waiting for %v before detaching ISO from virtual machine...", config.EjectISODelay))
|
||||
time.Sleep(config.EjectISODelay)
|
||||
}
|
||||
|
||||
client := state.Get("client").(*cloudstack.CloudStackClient)
|
||||
|
||||
instanceID, ok := state.Get("instance_id").(string)
|
||||
if !ok || instanceID == "" {
|
||||
err := fmt.Errorf("Could not retrieve instance_id from state")
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
ui.Message("Detaching iso from virtual machine...")
|
||||
|
||||
// Get a new DetachIsoParams and detaches Iso file from given virtualMachine instance
|
||||
detachIsoParams := client.ISO.NewDetachIsoParams(instanceID)
|
||||
response, err := client.ISO.DetachIso(detachIsoParams)
|
||||
if err != nil || response == nil {
|
||||
err := fmt.Errorf("Error detaching ISO from virtual machine: %s", err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepDetachIso) Cleanup(state multistep.StateBag) {
|
||||
// Nothing to cleanup for this step.
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package digitalocean
|
||||
|
||||
import (
|
||||
|
@ -19,25 +21,69 @@ import (
|
|||
type Config struct {
|
||||
common.PackerConfig `mapstructure:",squash"`
|
||||
Comm communicator.Config `mapstructure:",squash"`
|
||||
|
||||
APIToken string `mapstructure:"api_token"`
|
||||
APIURL string `mapstructure:"api_url"`
|
||||
|
||||
Region string `mapstructure:"region"`
|
||||
Size string `mapstructure:"size"`
|
||||
Image string `mapstructure:"image"`
|
||||
|
||||
PrivateNetworking bool `mapstructure:"private_networking"`
|
||||
Monitoring bool `mapstructure:"monitoring"`
|
||||
IPv6 bool `mapstructure:"ipv6"`
|
||||
SnapshotName string `mapstructure:"snapshot_name"`
|
||||
SnapshotRegions []string `mapstructure:"snapshot_regions"`
|
||||
StateTimeout time.Duration `mapstructure:"state_timeout"`
|
||||
SnapshotTimeout time.Duration `mapstructure:"snapshot_timeout"`
|
||||
DropletName string `mapstructure:"droplet_name"`
|
||||
UserData string `mapstructure:"user_data"`
|
||||
UserDataFile string `mapstructure:"user_data_file"`
|
||||
Tags []string `mapstructure:"tags"`
|
||||
// The client TOKEN to use to access your account. It
|
||||
// can also be specified via environment variable DIGITALOCEAN_API_TOKEN, if
|
||||
// set.
|
||||
APIToken string `mapstructure:"api_token" required:"true"`
|
||||
// Non standard api endpoint URL. Set this if you are
|
||||
// using a DigitalOcean API compatible service. It can also be specified via
|
||||
// environment variable DIGITALOCEAN_API_URL.
|
||||
APIURL string `mapstructure:"api_url" required:"false"`
|
||||
// The name (or slug) of the region to launch the droplet
|
||||
// in. Consequently, this is the region where the snapshot will be available.
|
||||
// See
|
||||
// https://developers.digitalocean.com/documentation/v2/#list-all-regions
|
||||
// for the accepted region names/slugs.
|
||||
Region string `mapstructure:"region" required:"true"`
|
||||
// The name (or slug) of the droplet size to use. See
|
||||
// https://developers.digitalocean.com/documentation/v2/#list-all-sizes
|
||||
// for the accepted size names/slugs.
|
||||
Size string `mapstructure:"size" required:"true"`
|
||||
// The name (or slug) of the base image to use. This is the
|
||||
// image that will be used to launch a new droplet and provision it. See
|
||||
// https://developers.digitalocean.com/documentation/v2/#list-all-images
|
||||
// for details on how to get a list of the accepted image names/slugs.
|
||||
Image string `mapstructure:"image" required:"true"`
|
||||
// Set to true to enable private networking
|
||||
// for the droplet being created. This defaults to false, or not enabled.
|
||||
PrivateNetworking bool `mapstructure:"private_networking" required:"false"`
|
||||
// Set to true to enable monitoring for the droplet
|
||||
// being created. This defaults to false, or not enabled.
|
||||
Monitoring bool `mapstructure:"monitoring" required:"false"`
|
||||
// Set to true to enable ipv6 for the droplet being
|
||||
// created. This defaults to false, or not enabled.
|
||||
IPv6 bool `mapstructure:"ipv6" required:"false"`
|
||||
// The name of the resulting snapshot that will
|
||||
// appear in your account. Defaults to "packer-{{timestamp}}" (see
|
||||
// configuration templates for more info).
|
||||
SnapshotName string `mapstructure:"snapshot_name" required:"false"`
|
||||
// The regions of the resulting
|
||||
// snapshot that will appear in your account.
|
||||
SnapshotRegions []string `mapstructure:"snapshot_regions" required:"false"`
|
||||
// The time to wait, as a duration string, for a
|
||||
// droplet to enter a desired state (such as "active") before timing out. The
|
||||
// default state timeout is "6m".
|
||||
StateTimeout time.Duration `mapstructure:"state_timeout" required:"false"`
|
||||
// How long to wait for an image to be published to the shared image
|
||||
// gallery before timing out. If your Packer build is failing on the
|
||||
// Publishing to Shared Image Gallery step with the error `Original Error:
|
||||
// context deadline exceeded`, but the image is present when you check your
|
||||
// Azure dashboard, then you probably need to increase this timeout from
|
||||
// its default of "60m" (valid time units include `s` for seconds, `m` for
|
||||
// minutes, and `h` for hours.)
|
||||
SnapshotTimeout time.Duration `mapstructure:"snapshot_timeout" required:"false"`
|
||||
// The name assigned to the droplet. DigitalOcean
|
||||
// sets the hostname of the machine to this value.
|
||||
DropletName string `mapstructure:"droplet_name" required:"false"`
|
||||
// User data to launch with the Droplet. Packer will
|
||||
// not automatically wait for a user script to finish before shutting down the
|
||||
// instance this must be handled in a provisioner.
|
||||
UserData string `mapstructure:"user_data" required:"false"`
|
||||
// Path to a file that will be used for the user
|
||||
// data when launching the Droplet.
|
||||
UserDataFile string `mapstructure:"user_data_file" required:"false"`
|
||||
// Tags to apply to the droplet when it is created
|
||||
Tags []string `mapstructure:"tags" required:"false"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package docker
|
||||
|
||||
import (
|
||||
|
@ -23,30 +25,82 @@ type Config struct {
|
|||
common.PackerConfig `mapstructure:",squash"`
|
||||
Comm communicator.Config `mapstructure:",squash"`
|
||||
|
||||
Author string
|
||||
Changes []string
|
||||
Commit bool
|
||||
ContainerDir string `mapstructure:"container_dir"`
|
||||
Discard bool
|
||||
ExecUser string `mapstructure:"exec_user"`
|
||||
ExportPath string `mapstructure:"export_path"`
|
||||
Image string
|
||||
Message string
|
||||
Privileged bool `mapstructure:"privileged"`
|
||||
Pty bool
|
||||
Pull bool
|
||||
RunCommand []string `mapstructure:"run_command"`
|
||||
Volumes map[string]string
|
||||
FixUploadOwner bool `mapstructure:"fix_upload_owner"`
|
||||
WindowsContainer bool `mapstructure:"windows_container"`
|
||||
// Set the author (e-mail) of a commit.
|
||||
Author string `mapstructure:"author"`
|
||||
// Dockerfile instructions to add to the commit. Example of instructions
|
||||
// are CMD, ENTRYPOINT, ENV, and EXPOSE. Example: [ "USER ubuntu", "WORKDIR
|
||||
// /app", "EXPOSE 8080" ]
|
||||
Changes []string `mapstructure:"changes"`
|
||||
// If true, the container will be committed to an image rather than exported.
|
||||
Commit bool `mapstructure:"commit" required:"true"`
|
||||
|
||||
// The directory inside container to mount temp directory from host server
|
||||
// for work [file provisioner](/docs/provisioners/file.html). This defaults
|
||||
// to c:/packer-files on windows and /packer-files on other systems.
|
||||
ContainerDir string `mapstructure:"container_dir" required:"false"`
|
||||
// Throw away the container when the build is complete. This is useful for
|
||||
// the [artifice
|
||||
// post-processor](https://www.packer.io/docs/post-processors/artifice.html).
|
||||
Discard bool `mapstructure:"discard" required:"true"`
|
||||
// Username (UID) to run remote commands with. You can also set the group
|
||||
// name/ID if you want: (UID or UID:GID). You may need this if you get
|
||||
// permission errors trying to run the shell or other provisioners.
|
||||
ExecUser string `mapstructure:"exec_user" required:"false"`
|
||||
// The path where the final container will be exported as a tar file.
|
||||
ExportPath string `mapstructure:"export_path" required:"true"`
|
||||
// The base image for the Docker container that will be started. This image
|
||||
// will be pulled from the Docker registry if it doesn't already exist.
|
||||
Image string `mapstructure:"image" required:"true"`
|
||||
// Set a message for the commit.
|
||||
Message string `mapstructure:"message" required:"true"`
|
||||
// If true, run the docker container with the `--privileged` flag. This
|
||||
// defaults to false if not set.
|
||||
Privileged bool `mapstructure:"privileged" required:"false"`
|
||||
Pty bool
|
||||
// If true, the configured image will be pulled using `docker pull` prior
|
||||
// to use. Otherwise, it is assumed the image already exists and can be
|
||||
// used. This defaults to true if not set.
|
||||
Pull bool `mapstructure:"pull" required:"false"`
|
||||
// An array of arguments to pass to docker run in order to run the
|
||||
// container. By default this is set to ["-d", "-i", "-t",
|
||||
// "--entrypoint=/bin/sh", "--", "{{.Image}}"] if you are using a linux
|
||||
// container, and ["-d", "-i", "-t", "--entrypoint=powershell", "--",
|
||||
// "{{.Image}}"] if you are running a windows container. {{.Image}} is a
|
||||
// template variable that corresponds to the image template option. Passing
|
||||
// the entrypoint option this way will make it the default entrypoint of
|
||||
// the resulting image, so running docker run -it --rm will start the
|
||||
// docker image from the /bin/sh shell interpreter; you could run a script
|
||||
// or another shell by running docker run -it --rm -c /bin/bash. If your
|
||||
// docker image embeds a binary intended to be run often, you should
|
||||
// consider changing the default entrypoint to point to it.
|
||||
RunCommand []string `mapstructure:"run_command" required:"false"`
|
||||
// A mapping of additional volumes to mount into this container. The key of
|
||||
// the object is the host path, the value is the container path.
|
||||
Volumes map[string]string `mapstructure:"volumes" required:"false"`
|
||||
// If true, files uploaded to the container will be owned by the user the
|
||||
// container is running as. If false, the owner will depend on the version
|
||||
// of docker installed in the system. Defaults to true.
|
||||
FixUploadOwner bool `mapstructure:"fix_upload_owner" required:"false"`
|
||||
// If "true", tells Packer that you are building a Windows container
|
||||
// running on a windows host. This is necessary for building Windows
|
||||
// containers, because our normal docker bindings do not work for them.
|
||||
WindowsContainer bool `mapstructure:"windows_container" required:"false"`
|
||||
|
||||
// This is used to login to dockerhub to pull a private base container. For
|
||||
// pushing to dockerhub, see the docker post-processors
|
||||
Login bool
|
||||
LoginPassword string `mapstructure:"login_password"`
|
||||
LoginServer string `mapstructure:"login_server"`
|
||||
LoginUsername string `mapstructure:"login_username"`
|
||||
EcrLogin bool `mapstructure:"ecr_login"`
|
||||
Login bool `mapstructure:"login" required:"false"`
|
||||
// The password to use to authenticate to login.
|
||||
LoginPassword string `mapstructure:"login_password" required:"false"`
|
||||
// The server address to login to.
|
||||
LoginServer string `mapstructure:"login_server" required:"false"`
|
||||
// The username to use to authenticate to login.
|
||||
LoginUsername string `mapstructure:"login_username" required:"false"`
|
||||
// Defaults to false. If true, the builder will login in order to pull the
|
||||
// image from Amazon EC2 Container Registry (ECR). The builder only logs in
|
||||
// for the duration of the pull. If true login_server is required and
|
||||
// login, login_username, and login_password will be ignored. For more
|
||||
// information see the section on ECR.
|
||||
EcrLogin bool `mapstructure:"ecr_login" required:"false"`
|
||||
AwsAccessConfig `mapstructure:",squash"`
|
||||
|
||||
ctx interpolate.Context
|
||||
|
@ -83,7 +137,7 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
|||
// Default Pull if it wasn't set
|
||||
hasPull := false
|
||||
for _, k := range md.Keys {
|
||||
if k == "Pull" {
|
||||
if k == "pull" {
|
||||
hasPull = true
|
||||
break
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package docker
|
||||
|
||||
import (
|
||||
|
@ -13,11 +15,24 @@ import (
|
|||
)
|
||||
|
||||
type AwsAccessConfig struct {
|
||||
AccessKey string `mapstructure:"aws_access_key"`
|
||||
SecretKey string `mapstructure:"aws_secret_key"`
|
||||
Token string `mapstructure:"aws_token"`
|
||||
Profile string `mapstructure:"aws_profile"`
|
||||
cfg *common.AccessConfig
|
||||
// The AWS access key used to communicate with
|
||||
// AWS. Learn how to set
|
||||
// this.
|
||||
AccessKey string `mapstructure:"aws_access_key" required:"false"`
|
||||
// The AWS secret key used to communicate with
|
||||
// AWS. Learn how to set
|
||||
// this.
|
||||
SecretKey string `mapstructure:"aws_secret_key" required:"false"`
|
||||
// The AWS access token to use. This is different from
|
||||
// the access key and secret key. If you're not sure what this is, then you
|
||||
// probably don't need it. This will also be read from the AWS_SESSION_TOKEN
|
||||
// environmental variable.
|
||||
Token string `mapstructure:"aws_token" required:"false"`
|
||||
// The AWS shared credentials profile used to
|
||||
// communicate with AWS. Learn how to set
|
||||
// this.
|
||||
Profile string `mapstructure:"aws_profile" required:"false"`
|
||||
cfg *common.AccessConfig
|
||||
}
|
||||
|
||||
// Get a login token for Amazon AWS ECR. Returns username and password
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package googlecompute
|
||||
|
||||
import (
|
||||
|
@ -17,7 +19,8 @@ import (
|
|||
compute "google.golang.org/api/compute/v1"
|
||||
)
|
||||
|
||||
var reImageFamily = regexp.MustCompile(`^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$`)
|
||||
// used for ImageName and ImageFamily
|
||||
var validImageName = regexp.MustCompile(`^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$`)
|
||||
|
||||
// Config is the configuration structure for the GCE builder. It stores
|
||||
// both the publicly settable state as well as the privately generated
|
||||
|
@ -26,45 +29,145 @@ type Config struct {
|
|||
common.PackerConfig `mapstructure:",squash"`
|
||||
Comm communicator.Config `mapstructure:",squash"`
|
||||
|
||||
AccountFile string `mapstructure:"account_file"`
|
||||
ProjectId string `mapstructure:"project_id"`
|
||||
|
||||
AcceleratorType string `mapstructure:"accelerator_type"`
|
||||
AcceleratorCount int64 `mapstructure:"accelerator_count"`
|
||||
Address string `mapstructure:"address"`
|
||||
DisableDefaultServiceAccount bool `mapstructure:"disable_default_service_account"`
|
||||
DiskName string `mapstructure:"disk_name"`
|
||||
DiskSizeGb int64 `mapstructure:"disk_size"`
|
||||
DiskType string `mapstructure:"disk_type"`
|
||||
ImageName string `mapstructure:"image_name"`
|
||||
ImageDescription string `mapstructure:"image_description"`
|
||||
ImageEncryptionKey *compute.CustomerEncryptionKey `mapstructure:"image_encryption_key"`
|
||||
ImageFamily string `mapstructure:"image_family"`
|
||||
ImageLabels map[string]string `mapstructure:"image_labels"`
|
||||
ImageLicenses []string `mapstructure:"image_licenses"`
|
||||
InstanceName string `mapstructure:"instance_name"`
|
||||
Labels map[string]string `mapstructure:"labels"`
|
||||
MachineType string `mapstructure:"machine_type"`
|
||||
Metadata map[string]string `mapstructure:"metadata"`
|
||||
MinCpuPlatform string `mapstructure:"min_cpu_platform"`
|
||||
Network string `mapstructure:"network"`
|
||||
NetworkProjectId string `mapstructure:"network_project_id"`
|
||||
OmitExternalIP bool `mapstructure:"omit_external_ip"`
|
||||
OnHostMaintenance string `mapstructure:"on_host_maintenance"`
|
||||
Preemptible bool `mapstructure:"preemptible"`
|
||||
RawStateTimeout string `mapstructure:"state_timeout"`
|
||||
Region string `mapstructure:"region"`
|
||||
Scopes []string `mapstructure:"scopes"`
|
||||
ServiceAccountEmail string `mapstructure:"service_account_email"`
|
||||
SourceImage string `mapstructure:"source_image"`
|
||||
SourceImageFamily string `mapstructure:"source_image_family"`
|
||||
SourceImageProjectId string `mapstructure:"source_image_project_id"`
|
||||
StartupScriptFile string `mapstructure:"startup_script_file"`
|
||||
Subnetwork string `mapstructure:"subnetwork"`
|
||||
Tags []string `mapstructure:"tags"`
|
||||
UseInternalIP bool `mapstructure:"use_internal_ip"`
|
||||
MetadataFiles map[string]string `mapstructure:"metadata_files"`
|
||||
Zone string `mapstructure:"zone"`
|
||||
// The JSON file containing your account credentials. Not required if you
|
||||
// run Packer on a GCE instance with a service account. Instructions for
|
||||
// creating the file or using service accounts are above.
|
||||
AccountFile string `mapstructure:"account_file" required:"false"`
|
||||
// The project ID that will be used to launch instances and store images.
|
||||
ProjectId string `mapstructure:"project_id" required:"true"`
|
||||
// Full or partial URL of the guest accelerator type. GPU accelerators can
|
||||
// only be used with `"on_host_maintenance": "TERMINATE"` option set.
|
||||
// Example:
|
||||
// `"projects/project_id/zones/europe-west1-b/acceleratorTypes/nvidia-tesla-k80"`
|
||||
AcceleratorType string `mapstructure:"accelerator_type" required:"false"`
|
||||
// Number of guest accelerator cards to add to the launched instance.
|
||||
AcceleratorCount int64 `mapstructure:"accelerator_count" required:"false"`
|
||||
// The name of a pre-allocated static external IP address. Note, must be
|
||||
// the name and not the actual IP address.
|
||||
Address string `mapstructure:"address" required:"false"`
|
||||
// If true, the default service account will not be used if
|
||||
// service_account_email is not specified. Set this value to true and omit
|
||||
// service_account_email to provision a VM with no service account.
|
||||
DisableDefaultServiceAccount bool `mapstructure:"disable_default_service_account" required:"false"`
|
||||
// The name of the disk, if unset the instance name will be used.
|
||||
DiskName string `mapstructure:"disk_name" required:"false"`
|
||||
// The size of the disk in GB. This defaults to 10, which is 10GB.
|
||||
DiskSizeGb int64 `mapstructure:"disk_size" required:"false"`
|
||||
// Type of disk used to back your instance, like pd-ssd or pd-standard.
|
||||
// Defaults to pd-standard.
|
||||
DiskType string `mapstructure:"disk_type" required:"false"`
|
||||
// The unique name of the resulting image. Defaults to
|
||||
// "packer-{{timestamp}}".
|
||||
ImageName string `mapstructure:"image_name" required:"false"`
|
||||
// The description of the resulting image.
|
||||
ImageDescription string `mapstructure:"image_description" required:"false"`
|
||||
// Image encryption key to apply to the created image. Possible values:
|
||||
// * kmsKeyName - The name of the encryption key that is stored in Google Cloud KMS.
|
||||
// * RawKey: - A 256-bit customer-supplied encryption key, encodes in RFC 4648 base64.
|
||||
//
|
||||
// example:
|
||||
//
|
||||
// ``` json
|
||||
// {
|
||||
// "kmsKeyName": "projects/${project}/locations/${region}/keyRings/computeEngine/cryptoKeys/computeEngine/cryptoKeyVersions/4"
|
||||
// }
|
||||
// ```
|
||||
ImageEncryptionKey *compute.CustomerEncryptionKey `mapstructure:"image_encryption_key" required:"false"`
|
||||
// The name of the image family to which the resulting image belongs. You
|
||||
// can create disks by specifying an image family instead of a specific
|
||||
// image name. The image family always returns its latest image that is not
|
||||
// deprecated.
|
||||
ImageFamily string `mapstructure:"image_family" required:"false"`
|
||||
// Key/value pair labels to apply to the created image.
|
||||
ImageLabels map[string]string `mapstructure:"image_labels" required:"false"`
|
||||
// Licenses to apply to the created image.
|
||||
ImageLicenses []string `mapstructure:"image_licenses" required:"false"`
|
||||
// A name to give the launched instance. Beware that this must be unique.
|
||||
// Defaults to "packer-{{uuid}}".
|
||||
InstanceName string `mapstructure:"instance_name" required:"false"`
|
||||
// Key/value pair labels to apply to the launched instance.
|
||||
Labels map[string]string `mapstructure:"labels" required:"false"`
|
||||
// The machine type. Defaults to "n1-standard-1".
|
||||
MachineType string `mapstructure:"machine_type" required:"false"`
|
||||
// Metadata applied to the launched instance.
|
||||
Metadata map[string]string `mapstructure:"metadata" required:"false"`
|
||||
// Metadata applied to the launched instance. Values are files.
|
||||
MetadataFiles map[string]string `mapstructure:"metadata_files"`
|
||||
// A Minimum CPU Platform for VM Instance. Availability and default CPU
|
||||
// platforms vary across zones, based on the hardware available in each GCP
|
||||
// zone.
|
||||
// [Details](https://cloud.google.com/compute/docs/instances/specify-min-cpu-platform)
|
||||
MinCpuPlatform string `mapstructure:"min_cpu_platform" required:"false"`
|
||||
// The Google Compute network id or URL to use for the launched instance.
|
||||
// Defaults to "default". If the value is not a URL, it will be
|
||||
// interpolated to
|
||||
// projects/((network_project_id))/global/networks/((network)). This value
|
||||
// is not required if a subnet is specified.
|
||||
Network string `mapstructure:"network" required:"false"`
|
||||
// The project ID for the network and subnetwork to use for launched
|
||||
// instance. Defaults to project_id.
|
||||
NetworkProjectId string `mapstructure:"network_project_id" required:"false"`
|
||||
// If true, the instance will not have an external IP. use_internal_ip must
|
||||
// be true if this property is true.
|
||||
OmitExternalIP bool `mapstructure:"omit_external_ip" required:"false"`
|
||||
// Sets Host Maintenance Option. Valid choices are `MIGRATE` and
|
||||
// `TERMINATE`. Please see [GCE Instance Scheduling
|
||||
// Options](https://cloud.google.com/compute/docs/instances/setting-instance-scheduling-options),
|
||||
// as not all machine\_types support `MIGRATE` (i.e. machines with GPUs).
|
||||
// If preemptible is true this can only be `TERMINATE`. If preemptible is
|
||||
// false, it defaults to `MIGRATE`
|
||||
OnHostMaintenance string `mapstructure:"on_host_maintenance" required:"false"`
|
||||
// If true, launch a preemptible instance.
|
||||
Preemptible bool `mapstructure:"preemptible" required:"false"`
|
||||
// The time to wait for instance state changes. Defaults to "5m".
|
||||
RawStateTimeout string `mapstructure:"state_timeout" required:"false"`
|
||||
// The region in which to launch the instance. Defaults to the region
|
||||
// hosting the specified zone.
|
||||
Region string `mapstructure:"region" required:"false"`
|
||||
// The service account scopes for launched
|
||||
// instance. Defaults to:
|
||||
//
|
||||
// ``` json
|
||||
// [
|
||||
// "https://www.googleapis.com/auth/userinfo.email",
|
||||
// "https://www.googleapis.com/auth/compute",
|
||||
// "https://www.googleapis.com/auth/devstorage.full_control"
|
||||
// ]
|
||||
// ```
|
||||
Scopes []string `mapstructure:"scopes" required:"false"`
|
||||
// The service account to be used for launched instance. Defaults to the
|
||||
// project's default service account unless disable_default_service_account
|
||||
// is true.
|
||||
ServiceAccountEmail string `mapstructure:"service_account_email" required:"false"`
|
||||
// The source image to use to create the new image from. You can also
|
||||
// specify source_image_family instead. If both source_image and
|
||||
// source_image_family are specified, source_image takes precedence.
|
||||
// Example: "debian-8-jessie-v20161027"
|
||||
SourceImage string `mapstructure:"source_image" required:"true"`
|
||||
// The source image family to use to create the new image from. The image
|
||||
// family always returns its latest image that is not deprecated. Example:
|
||||
// "debian-8".
|
||||
SourceImageFamily string `mapstructure:"source_image_family" required:"true"`
|
||||
// The project ID of the project containing the source image.
|
||||
SourceImageProjectId string `mapstructure:"source_image_project_id" required:"false"`
|
||||
// The path to a startup script to run on the VM from which the image will
|
||||
// be made.
|
||||
StartupScriptFile string `mapstructure:"startup_script_file" required:"false"`
|
||||
// The Google Compute subnetwork id or URL to use for the launched
|
||||
// instance. Only required if the network has been created with custom
|
||||
// subnetting. Note, the region of the subnetwork must match the region or
|
||||
// zone in which the VM is launched. If the value is not a URL, it will be
|
||||
// interpolated to
|
||||
// projects/((network_project_id))/regions/((region))/subnetworks/((subnetwork))
|
||||
Subnetwork string `mapstructure:"subnetwork" required:"false"`
|
||||
// Assign network tags to apply firewall rules to VM instance.
|
||||
Tags []string `mapstructure:"tags" required:"false"`
|
||||
// If true, use the instance's internal IP instead of its external IP
|
||||
// during building.
|
||||
UseInternalIP bool `mapstructure:"use_internal_ip" required:"false"`
|
||||
// The zone in which to launch the instance used to create the image.
|
||||
// Example: "us-central1-a"
|
||||
Zone string `mapstructure:"zone" required:"true"`
|
||||
|
||||
Account *jwt.Config
|
||||
stateTimeout time.Duration
|
||||
|
@ -142,17 +245,27 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// used for ImageName and ImageFamily
|
||||
imageErrorText := "Invalid image %s %q: The first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash"
|
||||
|
||||
if len(c.ImageName) > 63 {
|
||||
errs = packer.MultiErrorAppend(errs,
|
||||
errors.New("Invalid image name: Must not be longer than 63 characters"))
|
||||
}
|
||||
|
||||
if !validImageName.MatchString(c.ImageName) {
|
||||
errs = packer.MultiErrorAppend(errs, errors.New(fmt.Sprintf(imageErrorText, "name", c.ImageName)))
|
||||
}
|
||||
|
||||
if len(c.ImageFamily) > 63 {
|
||||
errs = packer.MultiErrorAppend(errs,
|
||||
errors.New("Invalid image family: Must not be longer than 63 characters"))
|
||||
}
|
||||
|
||||
if c.ImageFamily != "" {
|
||||
if !reImageFamily.MatchString(c.ImageFamily) {
|
||||
errs = packer.MultiErrorAppend(errs,
|
||||
errors.New("Invalid image family: The first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash"))
|
||||
if !validImageName.MatchString(c.ImageFamily) {
|
||||
errs = packer.MultiErrorAppend(errs, errors.New(fmt.Sprintf(imageErrorText, "family", c.ImageFamily)))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if c.InstanceName == "" {
|
||||
|
|
|
@ -156,6 +156,24 @@ func TestConfigPrepare(t *testing.T) {
|
|||
"foo bar",
|
||||
true,
|
||||
},
|
||||
{
|
||||
// underscore is not allowed
|
||||
"image_name",
|
||||
"foo_bar",
|
||||
true,
|
||||
},
|
||||
{
|
||||
// too long
|
||||
"image_name",
|
||||
"foobar123xyz_abc-456-one-two_three_five_nine_seventeen_eleventy-seven",
|
||||
true,
|
||||
},
|
||||
{
|
||||
// starts with non-alphabetic character
|
||||
"image_name",
|
||||
"1boohoo",
|
||||
true,
|
||||
},
|
||||
{
|
||||
"image_encryption_key",
|
||||
map[string]string{"kmsKeyName": "foo"},
|
||||
|
|
|
@ -55,12 +55,17 @@ func (s *StepCreateWindowsPassword) Run(ctx context.Context, state multistep.Sta
|
|||
buf := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(buf, uint32(priv.E))
|
||||
|
||||
email := ""
|
||||
if c.Account != nil {
|
||||
email = c.Account.Email
|
||||
}
|
||||
|
||||
data := WindowsPasswordConfig{
|
||||
key: priv,
|
||||
UserName: c.Comm.WinRMUser,
|
||||
Modulus: base64.StdEncoding.EncodeToString(priv.N.Bytes()),
|
||||
Exponent: base64.StdEncoding.EncodeToString(buf[1:]),
|
||||
Email: c.Account.Email,
|
||||
Email: email,
|
||||
ExpireOn: time.Now().Add(time.Minute * 5),
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ func isalphanumeric(b byte) bool {
|
|||
// Clean up image name by replacing invalid characters with "-"
|
||||
// and converting upper cases to lower cases
|
||||
func templateCleanImageName(s string) string {
|
||||
if reImageFamily.MatchString(s) {
|
||||
if validImageName.MatchString(s) {
|
||||
return s
|
||||
}
|
||||
b := []byte(strings.ToLower(s))
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package hyperone
|
||||
|
||||
import (
|
||||
|
@ -32,32 +34,61 @@ const (
|
|||
type Config struct {
|
||||
common.PackerConfig `mapstructure:",squash"`
|
||||
Comm communicator.Config `mapstructure:",squash"`
|
||||
|
||||
APIURL string `mapstructure:"api_url"`
|
||||
Token string `mapstructure:"token"`
|
||||
Project string `mapstructure:"project"`
|
||||
TokenLogin string `mapstructure:"token_login"`
|
||||
|
||||
StateTimeout time.Duration `mapstructure:"state_timeout"`
|
||||
|
||||
SourceImage string `mapstructure:"source_image"`
|
||||
ImageName string `mapstructure:"image_name"`
|
||||
ImageDescription string `mapstructure:"image_description"`
|
||||
ImageTags map[string]interface{} `mapstructure:"image_tags"`
|
||||
ImageService string `mapstructure:"image_service"`
|
||||
|
||||
VmType string `mapstructure:"vm_type"`
|
||||
VmName string `mapstructure:"vm_name"`
|
||||
VmTags map[string]interface{} `mapstructure:"vm_tags"`
|
||||
|
||||
DiskName string `mapstructure:"disk_name"`
|
||||
DiskType string `mapstructure:"disk_type"`
|
||||
DiskSize float32 `mapstructure:"disk_size"`
|
||||
|
||||
Network string `mapstructure:"network"`
|
||||
PrivateIP string `mapstructure:"private_ip"`
|
||||
PublicIP string `mapstructure:"public_ip"`
|
||||
PublicNetAdpService string `mapstructure:"public_netadp_service"`
|
||||
// Custom API endpoint URL, compatible with HyperOne.
|
||||
// It can also be specified via environment variable HYPERONE_API_URL.
|
||||
APIURL string `mapstructure:"api_url" required:"false"`
|
||||
// The authentication token used to access your account.
|
||||
// This can be either a session token or a service account token.
|
||||
// If not defined, the builder will attempt to find it in the following order:
|
||||
Token string `mapstructure:"token" required:"true"`
|
||||
// The id or name of the project. This field is required
|
||||
// only if using session tokens. It should be skipped when using service
|
||||
// account authentication.
|
||||
Project string `mapstructure:"project" required:"true"`
|
||||
// Login (an e-mail) on HyperOne platform. Set this
|
||||
// if you want to fetch the token by SSH authentication.
|
||||
TokenLogin string `mapstructure:"token_login" required:"false"`
|
||||
// Timeout for waiting on the API to complete
|
||||
// a request. Defaults to 5m.
|
||||
StateTimeout time.Duration `mapstructure:"state_timeout" required:"false"`
|
||||
// ID or name of the image to launch server from.
|
||||
SourceImage string `mapstructure:"source_image" required:"true"`
|
||||
// The name of the resulting image. Defaults to
|
||||
// "packer-{{timestamp}}"
|
||||
// (see configuration templates for more info).
|
||||
ImageName string `mapstructure:"image_name" required:"false"`
|
||||
// The description of the resulting image.
|
||||
ImageDescription string `mapstructure:"image_description" required:"false"`
|
||||
// Key/value pair tags to
|
||||
// add to the created image.
|
||||
ImageTags map[string]interface{} `mapstructure:"image_tags" required:"false"`
|
||||
// The service of the resulting image.
|
||||
ImageService string `mapstructure:"image_service" required:"false"`
|
||||
// ID or name of the type this server should be created with.
|
||||
VmType string `mapstructure:"vm_type" required:"true"`
|
||||
// The name of the created server.
|
||||
VmName string `mapstructure:"vm_name" required:"false"`
|
||||
// Key/value pair tags to
|
||||
// add to the created server.
|
||||
VmTags map[string]interface{} `mapstructure:"vm_tags" required:"false"`
|
||||
// The name of the created disk.
|
||||
DiskName string `mapstructure:"disk_name" required:"false"`
|
||||
// The type of the created disk. Defaults to ssd.
|
||||
DiskType string `mapstructure:"disk_type" required:"false"`
|
||||
// Size of the created disk, in GiB.
|
||||
DiskSize float32 `mapstructure:"disk_size" required:"true"`
|
||||
// The ID of the network to attach to the created server.
|
||||
Network string `mapstructure:"network" required:"false"`
|
||||
// The ID of the private IP within chosen network
|
||||
// that should be assigned to the created server.
|
||||
PrivateIP string `mapstructure:"private_ip" required:"false"`
|
||||
// The ID of the public IP that should be assigned to
|
||||
// the created server. If network is chosen, the public IP will be associated
|
||||
// with server's private IP.
|
||||
PublicIP string `mapstructure:"public_ip" required:"false"`
|
||||
// Custom service of public network adapter.
|
||||
// Can be useful when using custom api_url. Defaults to public.
|
||||
PublicNetAdpService string `mapstructure:"public_netadp_service" required:"false"`
|
||||
|
||||
ChrootDisk bool `mapstructure:"chroot_disk"`
|
||||
ChrootDiskSize float32 `mapstructure:"chroot_disk_size"`
|
||||
|
@ -71,9 +102,13 @@ type Config struct {
|
|||
MountPartition string `mapstructure:"mount_partition"`
|
||||
PreMountCommands []string `mapstructure:"pre_mount_commands"`
|
||||
PostMountCommands []string `mapstructure:"post_mount_commands"`
|
||||
|
||||
SSHKeys []string `mapstructure:"ssh_keys"`
|
||||
UserData string `mapstructure:"user_data"`
|
||||
// List of SSH keys by name or id to be added
|
||||
// to the server on launch.
|
||||
SSHKeys []string `mapstructure:"ssh_keys" required:"false"`
|
||||
// User data to launch with the server. Packer will not
|
||||
// automatically wait for a user script to finish before shutting down the
|
||||
// instance, this must be handled in a provisioner.
|
||||
UserData string `mapstructure:"user_data" required:"false"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
func testConfigTemplate(t *testing.T) *interpolate.Context {
|
||||
return &interpolate.Context{}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
|
@ -8,7 +10,14 @@ import (
|
|||
)
|
||||
|
||||
type OutputConfig struct {
|
||||
OutputDir string `mapstructure:"output_directory"`
|
||||
// This setting specifies the directory that
|
||||
// artifacts from the build, such as the virtual machine files and disks,
|
||||
// will be output to. The path to the directory may be relative or
|
||||
// absolute. If relative, the path is relative to the working directory
|
||||
// packer is executed from. This directory must not exist or, if
|
||||
// created, must be empty prior to running the builder. By default this is
|
||||
// "output-BUILDNAME" where "BUILDNAME" is the name of the build.
|
||||
OutputDir string `mapstructure:"output_directory" required:"false"`
|
||||
}
|
||||
|
||||
func (c *OutputConfig) Prepare(ctx *interpolate.Context, pc *common.PackerConfig) []error {
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/common"
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
func TestOutputConfigPrepare(t *testing.T) {
|
||||
|
@ -15,7 +16,7 @@ func TestOutputConfigPrepare(t *testing.T) {
|
|||
}
|
||||
|
||||
pc := &common.PackerConfig{PackerBuildName: "foo"}
|
||||
errs := c.Prepare(testConfigTemplate(t), pc)
|
||||
errs := c.Prepare(interpolate.NewContext(), pc)
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("err: %#v", errs)
|
||||
}
|
||||
|
@ -39,7 +40,7 @@ func TestOutputConfigPrepare_exists(t *testing.T) {
|
|||
PackerBuildName: "foo",
|
||||
PackerForce: false,
|
||||
}
|
||||
errs := c.Prepare(testConfigTemplate(t), pc)
|
||||
errs := c.Prepare(interpolate.NewContext(), pc)
|
||||
if len(errs) != 0 {
|
||||
t.Fatal("should not have errors")
|
||||
}
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
type ShutdownConfig struct {
|
||||
ShutdownCommand string `mapstructure:"shutdown_command"`
|
||||
RawShutdownTimeout string `mapstructure:"shutdown_timeout"`
|
||||
|
||||
ShutdownTimeout time.Duration ``
|
||||
}
|
||||
|
||||
func (c *ShutdownConfig) Prepare(ctx *interpolate.Context) []error {
|
||||
if c.RawShutdownTimeout == "" {
|
||||
c.RawShutdownTimeout = "5m"
|
||||
}
|
||||
|
||||
var errs []error
|
||||
var err error
|
||||
c.ShutdownTimeout, err = time.ParseDuration(c.RawShutdownTimeout)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("Failed parsing shutdown_timeout: %s", err))
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func testShutdownConfig() *ShutdownConfig {
|
||||
return &ShutdownConfig{}
|
||||
}
|
||||
|
||||
func TestShutdownConfigPrepare_ShutdownCommand(t *testing.T) {
|
||||
var c *ShutdownConfig
|
||||
var errs []error
|
||||
|
||||
c = testShutdownConfig()
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("err: %#v", errs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShutdownConfigPrepare_ShutdownTimeout(t *testing.T) {
|
||||
var c *ShutdownConfig
|
||||
var errs []error
|
||||
|
||||
// Test with a bad value
|
||||
c = testShutdownConfig()
|
||||
c.RawShutdownTimeout = "this is not good"
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
if len(errs) == 0 {
|
||||
t.Fatalf("should have error")
|
||||
}
|
||||
|
||||
// Test with a good one
|
||||
c = testShutdownConfig()
|
||||
c.RawShutdownTimeout = "5s"
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("err: %#v", errs)
|
||||
}
|
||||
if c.ShutdownTimeout != 5*time.Second {
|
||||
t.Fatalf("bad: %s", c.ShutdownTimeout)
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package iso
|
||||
|
||||
import (
|
||||
|
@ -14,6 +16,7 @@ import (
|
|||
"github.com/hashicorp/packer/common/bootcommand"
|
||||
powershell "github.com/hashicorp/packer/common/powershell"
|
||||
"github.com/hashicorp/packer/common/powershell/hyperv"
|
||||
"github.com/hashicorp/packer/common/shutdowncommand"
|
||||
"github.com/hashicorp/packer/helper/communicator"
|
||||
"github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
|
@ -50,71 +53,146 @@ type Builder struct {
|
|||
}
|
||||
|
||||
type Config struct {
|
||||
common.PackerConfig `mapstructure:",squash"`
|
||||
common.HTTPConfig `mapstructure:",squash"`
|
||||
common.ISOConfig `mapstructure:",squash"`
|
||||
common.FloppyConfig `mapstructure:",squash"`
|
||||
bootcommand.BootConfig `mapstructure:",squash"`
|
||||
hypervcommon.OutputConfig `mapstructure:",squash"`
|
||||
hypervcommon.SSHConfig `mapstructure:",squash"`
|
||||
hypervcommon.ShutdownConfig `mapstructure:",squash"`
|
||||
|
||||
// The size, in megabytes, of the hard disk to create for the VM.
|
||||
// By default, this is 130048 (about 127 GB).
|
||||
DiskSize uint `mapstructure:"disk_size"`
|
||||
|
||||
// The size, in megabytes, of the block size used to create the hard disk.
|
||||
// By default, this is 32768 (about 32 MB)
|
||||
DiskBlockSize uint `mapstructure:"disk_block_size"`
|
||||
|
||||
// The size, in megabytes, of the computer memory in the VM.
|
||||
// By default, this is 1024 (about 1 GB).
|
||||
RamSize uint `mapstructure:"memory"`
|
||||
|
||||
common.PackerConfig `mapstructure:",squash"`
|
||||
common.HTTPConfig `mapstructure:",squash"`
|
||||
common.ISOConfig `mapstructure:",squash"`
|
||||
common.FloppyConfig `mapstructure:",squash"`
|
||||
bootcommand.BootConfig `mapstructure:",squash"`
|
||||
hypervcommon.OutputConfig `mapstructure:",squash"`
|
||||
hypervcommon.SSHConfig `mapstructure:",squash"`
|
||||
shutdowncommand.ShutdownConfig `mapstructure:",squash"`
|
||||
// The size, in megabytes, of the hard disk to create
|
||||
// for the VM. By default, this is 40 GB.
|
||||
DiskSize uint `mapstructure:"disk_size" required:"false"`
|
||||
// The block size of the VHD to be created.
|
||||
// Recommended disk block size for Linux hyper-v guests is 1 MiB. This
|
||||
// defaults to "32" MiB.
|
||||
DiskBlockSize uint `mapstructure:"disk_block_size" required:"false"`
|
||||
// The amount, in megabytes, of RAM to assign to the
|
||||
// VM. By default, this is 1 GB.
|
||||
RamSize uint `mapstructure:"memory" required:"false"`
|
||||
// A list of ISO paths to
|
||||
// attach to a VM when it is booted. This is most useful for unattended
|
||||
// Windows installs, which look for an Autounattend.xml file on removable
|
||||
// media. By default, no secondary ISO will be attached.
|
||||
SecondaryDvdImages []string `mapstructure:"secondary_iso_images" required:"false"`
|
||||
// If set to attach then attach and
|
||||
// mount the ISO image specified in guest_additions_path. If set to
|
||||
// none then guest additions are not attached and mounted; This is the
|
||||
// default.
|
||||
GuestAdditionsMode string `mapstructure:"guest_additions_mode" required:"false"`
|
||||
// The path to the ISO image for guest
|
||||
// additions.
|
||||
GuestAdditionsPath string `mapstructure:"guest_additions_path" required:"false"`
|
||||
// This is the name of the new virtual machine,
|
||||
// without the file extension. By default this is "packer-BUILDNAME",
|
||||
// where "BUILDNAME" is the name of the build.
|
||||
VMName string `mapstructure:"vm_name" required:"false"`
|
||||
// The name of the switch to connect the virtual
|
||||
// machine to. By default, leaving this value unset will cause Packer to
|
||||
// try and determine the switch to use by looking for an external switch
|
||||
// that is up and running.
|
||||
SwitchName string `mapstructure:"switch_name" required:"false"`
|
||||
// This is the VLAN of the virtual switch's
|
||||
// network card. By default none is set. If none is set then a VLAN is not
|
||||
// set on the switch's network card. If this value is set it should match
|
||||
// the VLAN specified in by vlan_id.
|
||||
SwitchVlanId string `mapstructure:"switch_vlan_id" required:"false"`
|
||||
// This allows a specific MAC address to be used on
|
||||
// the default virtual network card. The MAC address must be a string with
|
||||
// no delimiters, for example "0000deadbeef".
|
||||
MacAddress string `mapstructure:"mac_address" required:"false"`
|
||||
// This is the VLAN of the virtual machine's network
|
||||
// card for the new virtual machine. By default none is set. If none is set
|
||||
// then VLANs are not set on the virtual machine's network card.
|
||||
VlanId string `mapstructure:"vlan_id" required:"false"`
|
||||
// The number of CPUs the virtual machine should use. If
|
||||
// this isn't specified, the default is 1 CPU.
|
||||
Cpu uint `mapstructure:"cpus" required:"false"`
|
||||
// The Hyper-V generation for the virtual machine. By
|
||||
// default, this is 1. Generation 2 Hyper-V virtual machines do not support
|
||||
// floppy drives. In this scenario use secondary_iso_images instead. Hard
|
||||
// drives and DVD drives will also be SCSI and not IDE.
|
||||
Generation uint `mapstructure:"generation" required:"false"`
|
||||
// If true enable MAC address spoofing
|
||||
// for the virtual machine. This defaults to false.
|
||||
EnableMacSpoofing bool `mapstructure:"enable_mac_spoofing" required:"false"`
|
||||
// If true use a legacy network adapter as the NIC.
|
||||
// This defaults to false. A legacy network adapter is fully emulated NIC, and is thus
|
||||
// supported by various exotic operating systems, but this emulation requires
|
||||
// additional overhead and should only be used if absolutely necessary.
|
||||
UseLegacyNetworkAdapter bool `mapstructure:"use_legacy_network_adapter" required:"false"`
|
||||
// If true enable dynamic memory for
|
||||
// the virtual machine. This defaults to false.
|
||||
EnableDynamicMemory bool `mapstructure:"enable_dynamic_memory" required:"false"`
|
||||
// If true enable secure boot for the
|
||||
// virtual machine. This defaults to false. See secure_boot_template
|
||||
// below for additional settings.
|
||||
EnableSecureBoot bool `mapstructure:"enable_secure_boot" required:"false"`
|
||||
// The secure boot template to be
|
||||
// configured. Valid values are "MicrosoftWindows" (Windows) or
|
||||
// "MicrosoftUEFICertificateAuthority" (Linux). This only takes effect if
|
||||
// enable_secure_boot is set to "true". This defaults to "MicrosoftWindows".
|
||||
SecureBootTemplate string `mapstructure:"secure_boot_template" required:"false"`
|
||||
// If true enable
|
||||
// virtualization extensions for the virtual machine. This defaults to
|
||||
// false. For nested virtualization you need to enable MAC spoofing,
|
||||
// disable dynamic memory and have at least 4GB of RAM assigned to the
|
||||
// virtual machine.
|
||||
EnableVirtualizationExtensions bool `mapstructure:"enable_virtualization_extensions" required:"false"`
|
||||
// The location under which Packer will create a directory to house all the
|
||||
// VM files and folders during the build. By default `%TEMP%` is used
|
||||
// which, for most systems, will evaluate to
|
||||
// `%USERPROFILE%/AppData/Local/Temp`.
|
||||
//
|
||||
SecondaryDvdImages []string `mapstructure:"secondary_iso_images"`
|
||||
|
||||
// Should integration services iso be mounted
|
||||
GuestAdditionsMode string `mapstructure:"guest_additions_mode"`
|
||||
|
||||
// The path to the integration services iso
|
||||
GuestAdditionsPath string `mapstructure:"guest_additions_path"`
|
||||
|
||||
// This is the name of the new virtual machine.
|
||||
// By default this is "packer-BUILDNAME", where "BUILDNAME" is the name of the build.
|
||||
VMName string `mapstructure:"vm_name"`
|
||||
|
||||
SwitchName string `mapstructure:"switch_name"`
|
||||
SwitchVlanId string `mapstructure:"switch_vlan_id"`
|
||||
MacAddress string `mapstructure:"mac_address"`
|
||||
VlanId string `mapstructure:"vlan_id"`
|
||||
Cpu uint `mapstructure:"cpus"`
|
||||
Generation uint `mapstructure:"generation"`
|
||||
EnableMacSpoofing bool `mapstructure:"enable_mac_spoofing"`
|
||||
UseLegacyNetworkAdapter bool `mapstructure:"use_legacy_network_adapter"`
|
||||
EnableDynamicMemory bool `mapstructure:"enable_dynamic_memory"`
|
||||
EnableSecureBoot bool `mapstructure:"enable_secure_boot"`
|
||||
SecureBootTemplate string `mapstructure:"secure_boot_template"`
|
||||
EnableVirtualizationExtensions bool `mapstructure:"enable_virtualization_extensions"`
|
||||
TempPath string `mapstructure:"temp_path"`
|
||||
Version string `mapstructure:"configuration_version"`
|
||||
KeepRegistered bool `mapstructure:"keep_registered"`
|
||||
// The build directory housed under `temp_path` will have a name similar to
|
||||
// `packerhv1234567`. The seven digit number at the end of the name is
|
||||
// automatically generated by Packer to ensure the directory name is
|
||||
// unique.
|
||||
TempPath string `mapstructure:"temp_path" required:"false"`
|
||||
// This allows you to set the vm version when calling New-VM to generate
|
||||
// the vm.
|
||||
Version string `mapstructure:"configuration_version" required:"false"`
|
||||
// If "true", Packer will not delete the VM from
|
||||
// The Hyper-V manager.
|
||||
KeepRegistered bool `mapstructure:"keep_registered" required:"false"`
|
||||
|
||||
Communicator string `mapstructure:"communicator"`
|
||||
|
||||
AdditionalDiskSize []uint `mapstructure:"disk_additional_size"`
|
||||
|
||||
SkipCompaction bool `mapstructure:"skip_compaction"`
|
||||
|
||||
SkipExport bool `mapstructure:"skip_export"`
|
||||
|
||||
// Use differencing disk
|
||||
DifferencingDisk bool `mapstructure:"differencing_disk"`
|
||||
|
||||
// Create the VM with a Fixed VHD format disk instead of Dynamic VHDX
|
||||
FixedVHD bool `mapstructure:"use_fixed_vhd_format"`
|
||||
|
||||
Headless bool `mapstructure:"headless"`
|
||||
// The size or sizes of any
|
||||
// additional hard disks for the VM in megabytes. If this is not specified
|
||||
// then the VM will only contain a primary hard disk. Additional drives
|
||||
// will be attached to the SCSI interface only. The builder uses
|
||||
// expandable rather than fixed-size virtual hard disks, so the actual
|
||||
// file representing the disk will not use the full size unless it is
|
||||
// full.
|
||||
AdditionalDiskSize []uint `mapstructure:"disk_additional_size" required:"false"`
|
||||
// If true skip compacting the hard disk for
|
||||
// the virtual machine when exporting. This defaults to false.
|
||||
SkipCompaction bool `mapstructure:"skip_compaction" required:"false"`
|
||||
// If true Packer will skip the export of the VM.
|
||||
// If you are interested only in the VHD/VHDX files, you can enable this
|
||||
// option. The resulting VHD/VHDX file will be output to
|
||||
// <output_directory>/Virtual Hard Disks. By default this option is false
|
||||
// and Packer will export the VM to output_directory.
|
||||
SkipExport bool `mapstructure:"skip_export" required:"false"`
|
||||
// If true enables differencing disks. Only
|
||||
// the changes will be written to the new disk. This is especially useful if
|
||||
// your source is a VHD/VHDX. This defaults to false.
|
||||
DifferencingDisk bool `mapstructure:"differencing_disk" required:"false"`
|
||||
// If true, creates the boot disk on the
|
||||
// virtual machine as a fixed VHD format disk. The default is false, which
|
||||
// creates a dynamic VHDX format disk. This option requires setting
|
||||
// generation to 1, skip_compaction to true, and
|
||||
// differencing_disk to false. Additionally, any value entered for
|
||||
// disk_block_size will be ignored. The most likely use case for this
|
||||
// option is outputing a disk that is in the format required for upload to
|
||||
// Azure.
|
||||
FixedVHD bool `mapstructure:"use_fixed_vhd_format" required:"false"`
|
||||
// Packer defaults to building Hyper-V virtual
|
||||
// machines by launching a GUI that shows the console of the machine being
|
||||
// built. When this value is set to true, the machine will start without a
|
||||
// console.
|
||||
Headless bool `mapstructure:"headless" required:"false"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package vmcx
|
||||
|
||||
import (
|
||||
|
@ -13,6 +15,7 @@ import (
|
|||
"github.com/hashicorp/packer/common/bootcommand"
|
||||
powershell "github.com/hashicorp/packer/common/powershell"
|
||||
"github.com/hashicorp/packer/common/powershell/hyperv"
|
||||
"github.com/hashicorp/packer/common/shutdowncommand"
|
||||
"github.com/hashicorp/packer/helper/communicator"
|
||||
"github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
|
@ -40,70 +43,132 @@ type Builder struct {
|
|||
}
|
||||
|
||||
type Config struct {
|
||||
common.PackerConfig `mapstructure:",squash"`
|
||||
common.HTTPConfig `mapstructure:",squash"`
|
||||
common.ISOConfig `mapstructure:",squash"`
|
||||
common.FloppyConfig `mapstructure:",squash"`
|
||||
bootcommand.BootConfig `mapstructure:",squash"`
|
||||
hypervcommon.OutputConfig `mapstructure:",squash"`
|
||||
hypervcommon.SSHConfig `mapstructure:",squash"`
|
||||
hypervcommon.ShutdownConfig `mapstructure:",squash"`
|
||||
|
||||
// The size, in megabytes, of the computer memory in the VM.
|
||||
// By default, this is 1024 (about 1 GB).
|
||||
RamSize uint `mapstructure:"memory"`
|
||||
|
||||
//
|
||||
SecondaryDvdImages []string `mapstructure:"secondary_iso_images"`
|
||||
|
||||
// Should integration services iso be mounted
|
||||
GuestAdditionsMode string `mapstructure:"guest_additions_mode"`
|
||||
|
||||
// The path to the integration services iso
|
||||
GuestAdditionsPath string `mapstructure:"guest_additions_path"`
|
||||
common.PackerConfig `mapstructure:",squash"`
|
||||
common.HTTPConfig `mapstructure:",squash"`
|
||||
common.ISOConfig `mapstructure:",squash"`
|
||||
common.FloppyConfig `mapstructure:",squash"`
|
||||
bootcommand.BootConfig `mapstructure:",squash"`
|
||||
hypervcommon.OutputConfig `mapstructure:",squash"`
|
||||
hypervcommon.SSHConfig `mapstructure:",squash"`
|
||||
shutdowncommand.ShutdownConfig `mapstructure:",squash"`
|
||||
// The amount, in megabytes, of RAM to assign to the
|
||||
// VM. By default, this is 1 GB.
|
||||
RamSize uint `mapstructure:"memory" required:"false"`
|
||||
// A list of ISO paths to
|
||||
// attach to a VM when it is booted. This is most useful for unattended
|
||||
// Windows installs, which look for an Autounattend.xml file on removable
|
||||
// media. By default, no secondary ISO will be attached.
|
||||
SecondaryDvdImages []string `mapstructure:"secondary_iso_images" required:"false"`
|
||||
// If set to attach then attach and
|
||||
// mount the ISO image specified in guest_additions_path. If set to
|
||||
// none then guest additions are not attached and mounted; This is the
|
||||
// default.
|
||||
GuestAdditionsMode string `mapstructure:"guest_additions_mode" required:"false"`
|
||||
// The path to the ISO image for guest
|
||||
// additions.
|
||||
GuestAdditionsPath string `mapstructure:"guest_additions_path" required:"false"`
|
||||
|
||||
// This is the path to a directory containing an exported virtual machine.
|
||||
CloneFromVMCXPath string `mapstructure:"clone_from_vmcx_path"`
|
||||
|
||||
// This is the name of the virtual machine to clone from.
|
||||
CloneFromVMName string `mapstructure:"clone_from_vm_name"`
|
||||
|
||||
// This is the name of the snapshot to clone from. A blank snapshot name will use the latest snapshot.
|
||||
CloneFromSnapshotName string `mapstructure:"clone_from_snapshot_name"`
|
||||
|
||||
// This will clone all snapshots if true. It will clone latest snapshot if false.
|
||||
CloneAllSnapshots bool `mapstructure:"clone_all_snapshots"`
|
||||
|
||||
// This is the name of the new virtual machine.
|
||||
// By default this is "packer-BUILDNAME", where "BUILDNAME" is the name of the build.
|
||||
VMName string `mapstructure:"vm_name"`
|
||||
|
||||
// Use differencing disk
|
||||
DifferencingDisk bool `mapstructure:"differencing_disk"`
|
||||
|
||||
SwitchName string `mapstructure:"switch_name"`
|
||||
CompareCopy bool `mapstructure:"copy_in_compare"`
|
||||
SwitchVlanId string `mapstructure:"switch_vlan_id"`
|
||||
MacAddress string `mapstructure:"mac_address"`
|
||||
VlanId string `mapstructure:"vlan_id"`
|
||||
Cpu uint `mapstructure:"cpus"`
|
||||
Generation uint `mapstructure:"generation"`
|
||||
EnableMacSpoofing bool `mapstructure:"enable_mac_spoofing"`
|
||||
EnableDynamicMemory bool `mapstructure:"enable_dynamic_memory"`
|
||||
EnableSecureBoot bool `mapstructure:"enable_secure_boot"`
|
||||
SecureBootTemplate string `mapstructure:"secure_boot_template"`
|
||||
EnableVirtualizationExtensions bool `mapstructure:"enable_virtualization_extensions"`
|
||||
TempPath string `mapstructure:"temp_path"`
|
||||
Version string `mapstructure:"configuration_version"`
|
||||
KeepRegistered bool `mapstructure:"keep_registered"`
|
||||
// The name of a snapshot in the
|
||||
// source machine to use as a starting point for the clone. If the value
|
||||
// given is an empty string, the last snapshot present in the source will
|
||||
// be chosen as the starting point for the new VM.
|
||||
CloneFromSnapshotName string `mapstructure:"clone_from_snapshot_name" required:"false"`
|
||||
// If set to true all snapshots
|
||||
// present in the source machine will be copied when the machine is
|
||||
// cloned. The final result of the build will be an exported virtual
|
||||
// machine that contains all the snapshots of the parent.
|
||||
CloneAllSnapshots bool `mapstructure:"clone_all_snapshots" required:"false"`
|
||||
// This is the name of the new virtual machine,
|
||||
// without the file extension. By default this is "packer-BUILDNAME",
|
||||
// where "BUILDNAME" is the name of the build.
|
||||
VMName string `mapstructure:"vm_name" required:"false"`
|
||||
// If true enables differencing disks. Only
|
||||
// the changes will be written to the new disk. This is especially useful if
|
||||
// your source is a VHD/VHDX. This defaults to false.
|
||||
DifferencingDisk bool `mapstructure:"differencing_disk" required:"false"`
|
||||
// The name of the switch to connect the virtual
|
||||
// machine to. By default, leaving this value unset will cause Packer to
|
||||
// try and determine the switch to use by looking for an external switch
|
||||
// that is up and running.
|
||||
SwitchName string `mapstructure:"switch_name" required:"false"`
|
||||
// When cloning a vm to build from, we run a powershell
|
||||
// Compare-VM command, which, depending on your version of Windows, may need
|
||||
// the "Copy" flag to be set to true or false. Defaults to "false". Command:
|
||||
CompareCopy bool `mapstructure:"copy_in_compare" required:"false"`
|
||||
// This is the VLAN of the virtual switch's
|
||||
// network card. By default none is set. If none is set then a VLAN is not
|
||||
// set on the switch's network card. If this value is set it should match
|
||||
// the VLAN specified in by vlan_id.
|
||||
SwitchVlanId string `mapstructure:"switch_vlan_id" required:"false"`
|
||||
// This allows a specific MAC address to be used on
|
||||
// the default virtual network card. The MAC address must be a string with
|
||||
// no delimiters, for example "0000deadbeef".
|
||||
MacAddress string `mapstructure:"mac_address" required:"false"`
|
||||
// This is the VLAN of the virtual machine's network
|
||||
// card for the new virtual machine. By default none is set. If none is set
|
||||
// then VLANs are not set on the virtual machine's network card.
|
||||
VlanId string `mapstructure:"vlan_id" required:"false"`
|
||||
// The number of CPUs the virtual machine should use. If
|
||||
// this isn't specified, the default is 1 CPU.
|
||||
Cpu uint `mapstructure:"cpus" required:"false"`
|
||||
// The Hyper-V generation for the virtual machine. By
|
||||
// default, this is 1. Generation 2 Hyper-V virtual machines do not support
|
||||
// floppy drives. In this scenario use secondary_iso_images instead. Hard
|
||||
// drives and DVD drives will also be SCSI and not IDE.
|
||||
Generation uint `mapstructure:"generation" required:"false"`
|
||||
// If true enable MAC address spoofing
|
||||
// for the virtual machine. This defaults to false.
|
||||
EnableMacSpoofing bool `mapstructure:"enable_mac_spoofing" required:"false"`
|
||||
// If true enable dynamic memory for
|
||||
// the virtual machine. This defaults to false.
|
||||
EnableDynamicMemory bool `mapstructure:"enable_dynamic_memory" required:"false"`
|
||||
// If true enable secure boot for the
|
||||
// virtual machine. This defaults to false. See secure_boot_template
|
||||
// below for additional settings.
|
||||
EnableSecureBoot bool `mapstructure:"enable_secure_boot" required:"false"`
|
||||
// The secure boot template to be
|
||||
// configured. Valid values are "MicrosoftWindows" (Windows) or
|
||||
// "MicrosoftUEFICertificateAuthority" (Linux). This only takes effect if
|
||||
// enable_secure_boot is set to "true". This defaults to "MicrosoftWindows".
|
||||
SecureBootTemplate string `mapstructure:"secure_boot_template" required:"false"`
|
||||
// If true enable
|
||||
// virtualization extensions for the virtual machine. This defaults to
|
||||
// false. For nested virtualization you need to enable MAC spoofing,
|
||||
// disable dynamic memory and have at least 4GB of RAM assigned to the
|
||||
// virtual machine.
|
||||
EnableVirtualizationExtensions bool `mapstructure:"enable_virtualization_extensions" required:"false"`
|
||||
// The location under which Packer will create a
|
||||
// directory to house all the VM files and folders during the build.
|
||||
// By default %TEMP% is used which, for most systems, will evaluate to
|
||||
// %USERPROFILE%/AppData/Local/Temp.
|
||||
TempPath string `mapstructure:"temp_path" required:"false"`
|
||||
// This allows you to set the vm version when
|
||||
// calling New-VM to generate the vm.
|
||||
Version string `mapstructure:"configuration_version" required:"false"`
|
||||
// If "true", Packer will not delete the VM from
|
||||
// The Hyper-V manager.
|
||||
KeepRegistered bool `mapstructure:"keep_registered" required:"false"`
|
||||
|
||||
Communicator string `mapstructure:"communicator"`
|
||||
|
||||
SkipCompaction bool `mapstructure:"skip_compaction"`
|
||||
|
||||
SkipExport bool `mapstructure:"skip_export"`
|
||||
|
||||
Headless bool `mapstructure:"headless"`
|
||||
// If true skip compacting the hard disk for
|
||||
// the virtual machine when exporting. This defaults to false.
|
||||
SkipCompaction bool `mapstructure:"skip_compaction" required:"false"`
|
||||
// If true Packer will skip the export of the VM.
|
||||
// If you are interested only in the VHD/VHDX files, you can enable this
|
||||
// option. The resulting VHD/VHDX file will be output to
|
||||
// <output_directory>/Virtual Hard Disks. By default this option is false
|
||||
// and Packer will export the VM to output_directory.
|
||||
SkipExport bool `mapstructure:"skip_export" required:"false"`
|
||||
// Packer defaults to building Hyper-V virtual
|
||||
// machines by launching a GUI that shows the console of the machine being
|
||||
// built. When this value is set to true, the machine will start without a
|
||||
// console.
|
||||
Headless bool `mapstructure:"headless" required:"false"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package lxc
|
||||
|
||||
import (
|
||||
|
@ -14,19 +16,53 @@ import (
|
|||
|
||||
type Config struct {
|
||||
common.PackerConfig `mapstructure:",squash"`
|
||||
ConfigFile string `mapstructure:"config_file"`
|
||||
OutputDir string `mapstructure:"output_directory"`
|
||||
ContainerName string `mapstructure:"container_name"`
|
||||
CommandWrapper string `mapstructure:"command_wrapper"`
|
||||
RawInitTimeout string `mapstructure:"init_timeout"`
|
||||
CreateOptions []string `mapstructure:"create_options"`
|
||||
StartOptions []string `mapstructure:"start_options"`
|
||||
AttachOptions []string `mapstructure:"attach_options"`
|
||||
Name string `mapstructure:"template_name"`
|
||||
Parameters []string `mapstructure:"template_parameters"`
|
||||
EnvVars []string `mapstructure:"template_environment_vars"`
|
||||
TargetRunlevel int `mapstructure:"target_runlevel"`
|
||||
InitTimeout time.Duration
|
||||
// The path to the lxc configuration file.
|
||||
ConfigFile string `mapstructure:"config_file" required:"true"`
|
||||
// The directory in which to save the exported
|
||||
// tar.gz. Defaults to output-<BuildName> in the current directory.
|
||||
OutputDir string `mapstructure:"output_directory" required:"false"`
|
||||
// The name of the LXC container. Usually stored
|
||||
// in /var/lib/lxc/containers/<container_name>. Defaults to
|
||||
// packer-<BuildName>.
|
||||
ContainerName string `mapstructure:"container_name" required:"false"`
|
||||
// Allows you to specify a wrapper command, such
|
||||
// as ssh so you can execute packer builds on a remote host. Defaults to
|
||||
// Empty.
|
||||
CommandWrapper string `mapstructure:"command_wrapper" required:"false"`
|
||||
// The timeout in seconds to wait for the the
|
||||
// container to start. Defaults to 20 seconds.
|
||||
RawInitTimeout string `mapstructure:"init_timeout" required:"false"`
|
||||
// Options to pass to lxc-create. For
|
||||
// instance, you can specify a custom LXC container configuration file with
|
||||
// ["-f", "/path/to/lxc.conf"]. Defaults to []. See man 1 lxc-create for
|
||||
// available options.
|
||||
CreateOptions []string `mapstructure:"create_options" required:"false"`
|
||||
// Options to pass to lxc-start. For
|
||||
// instance, you can override parameters from the LXC container configuration
|
||||
// file via ["--define", "KEY=VALUE"]. Defaults to []. See
|
||||
// man 1 lxc-start for available options.
|
||||
StartOptions []string `mapstructure:"start_options" required:"false"`
|
||||
// Options to pass to lxc-attach. For
|
||||
// instance, you can prevent the container from inheriting the host machine's
|
||||
// environment by specifying ["--clear-env"]. Defaults to []. See
|
||||
// man 1 lxc-attach for available options.
|
||||
AttachOptions []string `mapstructure:"attach_options" required:"false"`
|
||||
// The LXC template name to use.
|
||||
Name string `mapstructure:"template_name" required:"true"`
|
||||
// Options to pass to the given
|
||||
// lxc-template command, usually located in
|
||||
// /usr/share/lxc/templates/lxc-<template_name>. Note: This gets passed as
|
||||
// ARGV to the template command. Ensure you have an array of strings, as a
|
||||
// single string with spaces probably won't work. Defaults to [].
|
||||
Parameters []string `mapstructure:"template_parameters" required:"false"`
|
||||
// Environmental variables to
|
||||
// use to build the template with.
|
||||
EnvVars []string `mapstructure:"template_environment_vars" required:"true"`
|
||||
// The minimum run level to wait for the
|
||||
// container to reach. Note some distributions (Ubuntu) simulate run levels
|
||||
// and may report 5 rather than 3.
|
||||
TargetRunlevel int `mapstructure:"target_runlevel" required:"false"`
|
||||
InitTimeout time.Duration
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package lxd
|
||||
|
||||
import (
|
||||
|
@ -12,14 +14,30 @@ import (
|
|||
|
||||
type Config struct {
|
||||
common.PackerConfig `mapstructure:",squash"`
|
||||
OutputImage string `mapstructure:"output_image"`
|
||||
ContainerName string `mapstructure:"container_name"`
|
||||
CommandWrapper string `mapstructure:"command_wrapper"`
|
||||
Image string `mapstructure:"image"`
|
||||
Profile string `mapstructure:"profile"`
|
||||
InitSleep string `mapstructure:"init_sleep"`
|
||||
PublishProperties map[string]string `mapstructure:"publish_properties"`
|
||||
LaunchConfig map[string]string `mapstructure:"launch_config"`
|
||||
// The name of the output artifact. Defaults to
|
||||
// name.
|
||||
OutputImage string `mapstructure:"output_image" required:"false"`
|
||||
ContainerName string `mapstructure:"container_name"`
|
||||
// Lets you prefix all builder commands, such as
|
||||
// with ssh for a remote build host. Defaults to "".
|
||||
CommandWrapper string `mapstructure:"command_wrapper" required:"false"`
|
||||
// The source image to use when creating the build
|
||||
// container. This can be a (local or remote) image (name or fingerprint).
|
||||
// E.G. my-base-image, ubuntu-daily:x, 08fababf6f27, ...
|
||||
Image string `mapstructure:"image" required:"true"`
|
||||
Profile string `mapstructure:"profile"`
|
||||
// The number of seconds to sleep between launching
|
||||
// the LXD instance and provisioning it; defaults to 3 seconds.
|
||||
InitSleep string `mapstructure:"init_sleep" required:"false"`
|
||||
// Pass key values to the publish
|
||||
// step to be set as properties on the output image. This is most helpful to
|
||||
// set the description, but can be used to set anything needed. See
|
||||
// https://stgraber.org/2016/03/30/lxd-2-0-image-management-512/
|
||||
// for more properties.
|
||||
PublishProperties map[string]string `mapstructure:"publish_properties" required:"false"`
|
||||
// List of key/value pairs you wish to
|
||||
// pass to lxc launch via --config. Defaults to empty.
|
||||
LaunchConfig map[string]string `mapstructure:"launch_config" required:"false"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package ncloud
|
||||
|
||||
import (
|
||||
|
@ -16,18 +18,41 @@ import (
|
|||
type Config struct {
|
||||
common.PackerConfig `mapstructure:",squash"`
|
||||
|
||||
AccessKey string `mapstructure:"access_key"`
|
||||
SecretKey string `mapstructure:"secret_key"`
|
||||
ServerImageProductCode string `mapstructure:"server_image_product_code"`
|
||||
ServerProductCode string `mapstructure:"server_product_code"`
|
||||
MemberServerImageNo string `mapstructure:"member_server_image_no"`
|
||||
ServerImageName string `mapstructure:"server_image_name"`
|
||||
ServerImageDescription string `mapstructure:"server_image_description"`
|
||||
UserData string `mapstructure:"user_data"`
|
||||
UserDataFile string `mapstructure:"user_data_file"`
|
||||
BlockStorageSize int `mapstructure:"block_storage_size"`
|
||||
Region string `mapstructure:"region"`
|
||||
AccessControlGroupConfigurationNo string `mapstructure:"access_control_group_configuration_no"`
|
||||
AccessKey string `mapstructure:"access_key"`
|
||||
SecretKey string `mapstructure:"secret_key"`
|
||||
// Product code of an image to create.
|
||||
// (member_server_image_no is required if not specified)
|
||||
ServerImageProductCode string `mapstructure:"server_image_product_code" required:"true"`
|
||||
// Product (spec) code to create.
|
||||
ServerProductCode string `mapstructure:"server_product_code" required:"true"`
|
||||
// Previous image code. If there is an
|
||||
// image previously created, it can be used to create a new image.
|
||||
// (server_image_product_code is required if not specified)
|
||||
MemberServerImageNo string `mapstructure:"member_server_image_no" required:"false"`
|
||||
// Name of an image to create.
|
||||
ServerImageName string `mapstructure:"server_image_name" required:"false"`
|
||||
// Description of an image to create.
|
||||
ServerImageDescription string `mapstructure:"server_image_description" required:"false"`
|
||||
// User data to apply when launching the instance. Note
|
||||
// that you need to be careful about escaping characters due to the templates
|
||||
// being JSON. It is often more convenient to use user_data_file, instead.
|
||||
// Packer will not automatically wait for a user script to finish before
|
||||
// shutting down the instance this must be handled in a provisioner.
|
||||
UserData string `mapstructure:"user_data" required:"false"`
|
||||
// Path to a file that will be used for the user
|
||||
// data when launching the instance.
|
||||
UserDataFile string `mapstructure:"user_data_file" required:"false"`
|
||||
// You can add block storage ranging from 10
|
||||
// GB to 2000 GB, in increments of 10 GB.
|
||||
BlockStorageSize int `mapstructure:"block_storage_size" required:"false"`
|
||||
// Name of the region where you want to create an image.
|
||||
// (default: Korea)
|
||||
Region string `mapstructure:"region" required:"false"`
|
||||
// This is used to allow
|
||||
// winrm access when you create a Windows server. An ACG that specifies an
|
||||
// access source (0.0.0.0/0) and allowed port (5985) must be created in
|
||||
// advance.
|
||||
AccessControlGroupConfigurationNo string `mapstructure:"access_control_group_configuration_no" required:"false"`
|
||||
|
||||
Comm communicator.Config `mapstructure:",squash"`
|
||||
ctx *interpolate.Context
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package openstack
|
||||
|
||||
import (
|
||||
|
@ -16,25 +18,73 @@ import (
|
|||
|
||||
// AccessConfig is for common configuration related to openstack access
|
||||
type AccessConfig struct {
|
||||
Username string `mapstructure:"username"`
|
||||
UserID string `mapstructure:"user_id"`
|
||||
Password string `mapstructure:"password"`
|
||||
IdentityEndpoint string `mapstructure:"identity_endpoint"`
|
||||
TenantID string `mapstructure:"tenant_id"`
|
||||
TenantName string `mapstructure:"tenant_name"`
|
||||
DomainID string `mapstructure:"domain_id"`
|
||||
DomainName string `mapstructure:"domain_name"`
|
||||
Insecure bool `mapstructure:"insecure"`
|
||||
Region string `mapstructure:"region"`
|
||||
EndpointType string `mapstructure:"endpoint_type"`
|
||||
CACertFile string `mapstructure:"cacert"`
|
||||
ClientCertFile string `mapstructure:"cert"`
|
||||
ClientKeyFile string `mapstructure:"key"`
|
||||
Token string `mapstructure:"token"`
|
||||
ApplicationCredentialName string `mapstructure:"application_credential_name"`
|
||||
ApplicationCredentialID string `mapstructure:"application_credential_id"`
|
||||
ApplicationCredentialSecret string `mapstructure:"application_credential_secret"`
|
||||
Cloud string `mapstructure:"cloud"`
|
||||
// The username or id used to connect to the OpenStack service. If not
|
||||
// specified, Packer will use the environment variable OS_USERNAME or
|
||||
// OS_USERID, if set. This is not required if using access token or
|
||||
// application credential instead of password, or if using cloud.yaml.
|
||||
Username string `mapstructure:"username" required:"true"`
|
||||
// Sets username
|
||||
UserID string `mapstructure:"user_id"`
|
||||
// The password used to connect to the OpenStack service. If not specified,
|
||||
// Packer will use the environment variables OS_PASSWORD, if set. This is
|
||||
// not required if using access token or application credential instead of
|
||||
// password, or if using cloud.yaml.
|
||||
Password string `mapstructure:"password" required:"true"`
|
||||
// The URL to the OpenStack Identity service. If not specified, Packer will
|
||||
// use the environment variables OS_AUTH_URL, if set. This is not required
|
||||
// if using cloud.yaml.
|
||||
IdentityEndpoint string `mapstructure:"identity_endpoint" required:"true"`
|
||||
// The tenant ID or name to boot the instance into. Some OpenStack
|
||||
// installations require this. If not specified, Packer will use the
|
||||
// environment variable OS_TENANT_NAME or OS_TENANT_ID, if set. Tenant is
|
||||
// also called Project in later versions of OpenStack.
|
||||
TenantID string `mapstructure:"tenant_id" required:"false"`
|
||||
TenantName string `mapstructure:"tenant_name"`
|
||||
DomainID string `mapstructure:"domain_id"`
|
||||
// The Domain name or ID you are authenticating with. OpenStack
|
||||
// installations require this if identity v3 is used. Packer will use the
|
||||
// environment variable OS_DOMAIN_NAME or OS_DOMAIN_ID, if set.
|
||||
DomainName string `mapstructure:"domain_name" required:"false"`
|
||||
// Whether or not the connection to OpenStack can be done over an insecure
|
||||
// connection. By default this is false.
|
||||
Insecure bool `mapstructure:"insecure" required:"false"`
|
||||
// The name of the region, such as "DFW", in which to launch the server to
|
||||
// create the image. If not specified, Packer will use the environment
|
||||
// variable OS_REGION_NAME, if set.
|
||||
Region string `mapstructure:"region" required:"false"`
|
||||
// The endpoint type to use. Can be any of "internal", "internalURL",
|
||||
// "admin", "adminURL", "public", and "publicURL". By default this is
|
||||
// "public".
|
||||
EndpointType string `mapstructure:"endpoint_type" required:"false"`
|
||||
// Custom CA certificate file path. If omitted the OS_CACERT environment
|
||||
// variable can be used.
|
||||
CACertFile string `mapstructure:"cacert" required:"false"`
|
||||
// Client certificate file path for SSL client authentication. If omitted
|
||||
// the OS_CERT environment variable can be used.
|
||||
ClientCertFile string `mapstructure:"cert" required:"false"`
|
||||
// Client private key file path for SSL client authentication. If omitted
|
||||
// the OS_KEY environment variable can be used.
|
||||
ClientKeyFile string `mapstructure:"key" required:"false"`
|
||||
// the token (id) to use with token based authorization. Packer will use
|
||||
// the environment variable OS_TOKEN, if set.
|
||||
Token string `mapstructure:"token" required:"false"`
|
||||
// The application credential name to use with application credential based
|
||||
// authorization. Packer will use the environment variable
|
||||
// OS_APPLICATION_CREDENTIAL_NAME, if set.
|
||||
ApplicationCredentialName string `mapstructure:"application_credential_name" required:"false"`
|
||||
// The application credential id to use with application credential based
|
||||
// authorization. Packer will use the environment variable
|
||||
// OS_APPLICATION_CREDENTIAL_ID, if set.
|
||||
ApplicationCredentialID string `mapstructure:"application_credential_id" required:"false"`
|
||||
// The application credential secret to use with application credential
|
||||
// based authorization. Packer will use the environment variable
|
||||
// OS_APPLICATION_CREDENTIAL_SECRET, if set.
|
||||
ApplicationCredentialSecret string `mapstructure:"application_credential_secret" required:"false"`
|
||||
// An entry in a `clouds.yaml` file. See the OpenStack os-client-config
|
||||
// [documentation](https://docs.openstack.org/os-client-config/latest/user/configuration.html)
|
||||
// for more information about `clouds.yaml` files. If omitted, the
|
||||
// `OS_CLOUD` environment variable is used.
|
||||
Cloud string `mapstructure:"cloud" required:"false"`
|
||||
|
||||
osClient *gophercloud.ProviderClient
|
||||
}
|
||||
|
@ -157,8 +207,8 @@ func (c *AccessConfig) Prepare(ctx *interpolate.Context) []error {
|
|||
tls_config.RootCAs = caCertPool
|
||||
}
|
||||
|
||||
// If we have insecure set, then create a custom HTTP client that
|
||||
// ignores SSL errors.
|
||||
// If we have insecure set, then create a custom HTTP client that ignores
|
||||
// SSL errors.
|
||||
if c.Insecure {
|
||||
tls_config.InsecureSkipVerify = true
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package openstack
|
||||
|
||||
import (
|
||||
|
@ -10,13 +12,23 @@ import (
|
|||
|
||||
// ImageConfig is for common configuration related to creating Images.
|
||||
type ImageConfig struct {
|
||||
ImageName string `mapstructure:"image_name"`
|
||||
ImageMetadata map[string]string `mapstructure:"metadata"`
|
||||
ImageVisibility imageservice.ImageVisibility `mapstructure:"image_visibility"`
|
||||
ImageMembers []string `mapstructure:"image_members"`
|
||||
ImageDiskFormat string `mapstructure:"image_disk_format"`
|
||||
ImageTags []string `mapstructure:"image_tags"`
|
||||
ImageMinDisk int `mapstructure:"image_min_disk"`
|
||||
// The name of the resulting image.
|
||||
ImageName string `mapstructure:"image_name" required:"true"`
|
||||
// Glance metadata that will be applied to the image.
|
||||
ImageMetadata map[string]string `mapstructure:"metadata" required:"false"`
|
||||
// One of "public", "private", "shared", or "community".
|
||||
ImageVisibility imageservice.ImageVisibility `mapstructure:"image_visibility" required:"false"`
|
||||
// List of members to add to the image after creation. An image member is
|
||||
// usually a project (also called the "tenant") with whom the image is
|
||||
// shared.
|
||||
ImageMembers []string `mapstructure:"image_members" required:"false"`
|
||||
// Disk format of the resulting image. This option works if
|
||||
// use_blockstorage_volume is true.
|
||||
ImageDiskFormat string `mapstructure:"image_disk_format" required:"false"`
|
||||
// List of tags to add to the image after creation.
|
||||
ImageTags []string `mapstructure:"image_tags" required:"false"`
|
||||
// Minimum disk size needed to boot image, in gigabytes.
|
||||
ImageMinDisk int `mapstructure:"image_min_disk" required:"false"`
|
||||
}
|
||||
|
||||
func (c *ImageConfig) Prepare(ctx *interpolate.Context) []error {
|
||||
|
@ -27,9 +39,9 @@ func (c *ImageConfig) Prepare(ctx *interpolate.Context) []error {
|
|||
|
||||
// By default, OpenStack seems to create the image with an image_type of
|
||||
// "snapshot", since it came from snapshotting a VM. A "snapshot" looks
|
||||
// slightly different in the OpenStack UI and OpenStack won't show "snapshot"
|
||||
// images as a choice in the list of images to boot from for a new instance.
|
||||
// See https://github.com/hashicorp/packer/issues/3038
|
||||
// slightly different in the OpenStack UI and OpenStack won't show
|
||||
// "snapshot" images as a choice in the list of images to boot from for a
|
||||
// new instance. See https://github.com/hashicorp/packer/issues/3038
|
||||
if c.ImageMetadata == nil {
|
||||
c.ImageMetadata = map[string]string{"image_type": "image"}
|
||||
} else if c.ImageMetadata["image_type"] == "" {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package openstack
|
||||
|
||||
import (
|
||||
|
@ -10,53 +12,172 @@ import (
|
|||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
// RunConfig contains configuration for running an instance from a source
|
||||
// image and details on how to access that launched image.
|
||||
// RunConfig contains configuration for running an instance from a source image
|
||||
// and details on how to access that launched image.
|
||||
type RunConfig struct {
|
||||
Comm communicator.Config `mapstructure:",squash"`
|
||||
SSHInterface string `mapstructure:"ssh_interface"`
|
||||
SSHIPVersion string `mapstructure:"ssh_ip_version"`
|
||||
|
||||
SourceImage string `mapstructure:"source_image"`
|
||||
SourceImageName string `mapstructure:"source_image_name"`
|
||||
SourceImageFilters ImageFilter `mapstructure:"source_image_filter"`
|
||||
Flavor string `mapstructure:"flavor"`
|
||||
AvailabilityZone string `mapstructure:"availability_zone"`
|
||||
RackconnectWait bool `mapstructure:"rackconnect_wait"`
|
||||
FloatingIPNetwork string `mapstructure:"floating_ip_network"`
|
||||
FloatingIP string `mapstructure:"floating_ip"`
|
||||
ReuseIPs bool `mapstructure:"reuse_ips"`
|
||||
SecurityGroups []string `mapstructure:"security_groups"`
|
||||
Networks []string `mapstructure:"networks"`
|
||||
InstanceFloatingIPNet string `mapstructure:"instance_floating_ip_net"`
|
||||
Ports []string `mapstructure:"ports"`
|
||||
UserData string `mapstructure:"user_data"`
|
||||
UserDataFile string `mapstructure:"user_data_file"`
|
||||
InstanceName string `mapstructure:"instance_name"`
|
||||
InstanceMetadata map[string]string `mapstructure:"instance_metadata"`
|
||||
ForceDelete bool `mapstructure:"force_delete"`
|
||||
|
||||
ConfigDrive bool `mapstructure:"config_drive"`
|
||||
|
||||
// Used for BC, value will be passed to the "floating_ip_network"
|
||||
FloatingIPPool string `mapstructure:"floating_ip_pool"`
|
||||
|
||||
UseBlockStorageVolume bool `mapstructure:"use_blockstorage_volume"`
|
||||
VolumeName string `mapstructure:"volume_name"`
|
||||
VolumeType string `mapstructure:"volume_type"`
|
||||
VolumeSize int `mapstructure:"volume_size"`
|
||||
VolumeAvailabilityZone string `mapstructure:"volume_availability_zone"`
|
||||
Comm communicator.Config `mapstructure:",squash"`
|
||||
// The type of interface to connect via SSH. Values useful for Rackspace
|
||||
// are "public" or "private", and the default behavior is to connect via
|
||||
// whichever is returned first from the OpenStack API.
|
||||
SSHInterface string `mapstructure:"ssh_interface" required:"false"`
|
||||
// The IP version to use for SSH connections, valid values are `4` and `6`.
|
||||
// Useful on dual stacked instances where the default behavior is to
|
||||
// connect via whichever IP address is returned first from the OpenStack
|
||||
// API.
|
||||
SSHIPVersion string `mapstructure:"ssh_ip_version" required:"false"`
|
||||
// The ID or full URL to the base image to use. This is the image that will
|
||||
// be used to launch a new server and provision it. Unless you specify
|
||||
// completely custom SSH settings, the source image must have cloud-init
|
||||
// installed so that the keypair gets assigned properly.
|
||||
SourceImage string `mapstructure:"source_image" required:"true"`
|
||||
// The name of the base image to use. This is an alternative way of
|
||||
// providing source_image and only either of them can be specified.
|
||||
SourceImageName string `mapstructure:"source_image_name" required:"true"`
|
||||
// Filters used to populate filter options. Example:
|
||||
//
|
||||
// ``` json {
|
||||
// "source_image_filter": {
|
||||
// "filters": {
|
||||
// "name": "ubuntu-16.04",
|
||||
// "visibility": "protected",
|
||||
// "owner": "d1a588cf4b0743344508dc145649372d1",
|
||||
// "tags": ["prod", "ready"],
|
||||
// "properties": {
|
||||
// "os_distro": "ubuntu"
|
||||
// }
|
||||
// },
|
||||
// "most_recent": true
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// This selects the most recent production Ubuntu 16.04 shared to you by
|
||||
// the given owner. NOTE: This will fail unless *exactly* one image is
|
||||
// returned, or `most_recent` is set to true. In the example of multiple
|
||||
// returned images, `most_recent` will cause this to succeed by selecting
|
||||
// the newest image of the returned images.
|
||||
//
|
||||
// - `filters` (map of strings) - filters used to select a
|
||||
// `source_image`.
|
||||
// NOTE: This will fail unless *exactly* one image is returned, or
|
||||
// `most_recent` is set to true. Of the filters described in
|
||||
// [ImageService](https://developer.openstack.org/api-ref/image/v2/), the
|
||||
// following are valid:
|
||||
//
|
||||
// - name (string)
|
||||
//
|
||||
// - owner (string)
|
||||
//
|
||||
// - tags (array of strings)
|
||||
//
|
||||
// - visibility (string)
|
||||
//
|
||||
// - properties (map of strings to strings) (fields that can be set
|
||||
// with `openstack image set --property key=value`)
|
||||
//
|
||||
// - `most_recent` (boolean) - Selects the newest created image when
|
||||
// true.
|
||||
// This is most useful for selecting a daily distro build.
|
||||
//
|
||||
// You may set use this in place of `source_image` If `source_image_filter`
|
||||
// is provided alongside `source_image`, the `source_image` will override
|
||||
// the filter. The filter will not be used in this case.
|
||||
SourceImageFilters ImageFilter `mapstructure:"source_image_filter" required:"true"`
|
||||
// The ID, name, or full URL for the desired flavor for the server to be
|
||||
// created.
|
||||
Flavor string `mapstructure:"flavor" required:"true"`
|
||||
// The availability zone to launch the server in. If this isn't specified,
|
||||
// the default enforced by your OpenStack cluster will be used. This may be
|
||||
// required for some OpenStack clusters.
|
||||
AvailabilityZone string `mapstructure:"availability_zone" required:"false"`
|
||||
// For rackspace, whether or not to wait for Rackconnect to assign the
|
||||
// machine an IP address before connecting via SSH. Defaults to false.
|
||||
RackconnectWait bool `mapstructure:"rackconnect_wait" required:"false"`
|
||||
// The ID or name of an external network that can be used for creation of a
|
||||
// new floating IP.
|
||||
FloatingIPNetwork string `mapstructure:"floating_ip_network" required:"false"`
|
||||
// The ID of the network to which the instance is attached and which should
|
||||
// be used to associate with the floating IP. This provides control over
|
||||
// the floating ip association on multi-homed instances. The association
|
||||
// otherwise depends on a first-returned-interface policy which could fail
|
||||
// if the network to which it is connected is unreachable from the floating
|
||||
// IP network.
|
||||
InstanceFloatingIPNet string `mapstructure:"instance_floating_ip_net" required:"false"`
|
||||
// A specific floating IP to assign to this instance.
|
||||
FloatingIP string `mapstructure:"floating_ip" required:"false"`
|
||||
// Whether or not to attempt to reuse existing unassigned floating ips in
|
||||
// the project before allocating a new one. Note that it is not possible to
|
||||
// safely do this concurrently, so if you are running multiple openstack
|
||||
// builds concurrently, or if other processes are assigning and using
|
||||
// floating IPs in the same openstack project while packer is running, you
|
||||
// should not set this to true. Defaults to false.
|
||||
ReuseIPs bool `mapstructure:"reuse_ips" required:"false"`
|
||||
// A list of security groups by name to add to this instance.
|
||||
SecurityGroups []string `mapstructure:"security_groups" required:"false"`
|
||||
// A list of networks by UUID to attach to this instance.
|
||||
Networks []string `mapstructure:"networks" required:"false"`
|
||||
// A list of ports by UUID to attach to this instance.
|
||||
Ports []string `mapstructure:"ports" required:"false"`
|
||||
// User data to apply when launching the instance. Note that you need to be
|
||||
// careful about escaping characters due to the templates being JSON. It is
|
||||
// often more convenient to use user_data_file, instead. Packer will not
|
||||
// automatically wait for a user script to finish before shutting down the
|
||||
// instance this must be handled in a provisioner.
|
||||
UserData string `mapstructure:"user_data" required:"false"`
|
||||
// Path to a file that will be used for the user data when launching the
|
||||
// instance.
|
||||
UserDataFile string `mapstructure:"user_data_file" required:"false"`
|
||||
// Name that is applied to the server instance created by Packer. If this
|
||||
// isn't specified, the default is same as image_name.
|
||||
InstanceName string `mapstructure:"instance_name" required:"false"`
|
||||
// Metadata that is applied to the server instance created by Packer. Also
|
||||
// called server properties in some documentation. The strings have a max
|
||||
// size of 255 bytes each.
|
||||
InstanceMetadata map[string]string `mapstructure:"instance_metadata" required:"false"`
|
||||
// Whether to force the OpenStack instance to be forcefully deleted. This
|
||||
// is useful for environments that have reclaim / soft deletion enabled. By
|
||||
// default this is false.
|
||||
ForceDelete bool `mapstructure:"force_delete" required:"false"`
|
||||
// Whether or not nova should use ConfigDrive for cloud-init metadata.
|
||||
ConfigDrive bool `mapstructure:"config_drive" required:"false"`
|
||||
// Deprecated use floating_ip_network instead.
|
||||
FloatingIPPool string `mapstructure:"floating_ip_pool" required:"false"`
|
||||
// Use Block Storage service volume for the instance root volume instead of
|
||||
// Compute service local volume (default).
|
||||
UseBlockStorageVolume bool `mapstructure:"use_blockstorage_volume" required:"false"`
|
||||
// Name of the Block Storage service volume. If this isn't specified,
|
||||
// random string will be used.
|
||||
VolumeName string `mapstructure:"volume_name" required:"false"`
|
||||
// Type of the Block Storage service volume. If this isn't specified, the
|
||||
// default enforced by your OpenStack cluster will be used.
|
||||
VolumeType string `mapstructure:"volume_type" required:"false"`
|
||||
// Size of the Block Storage service volume in GB. If this isn't specified,
|
||||
// it is set to source image min disk value (if set) or calculated from the
|
||||
// source image bytes size. Note that in some cases this needs to be
|
||||
// specified, if use_blockstorage_volume is true.
|
||||
VolumeSize int `mapstructure:"volume_size" required:"false"`
|
||||
// Availability zone of the Block Storage service volume. If omitted,
|
||||
// Compute instance availability zone will be used. If both of Compute
|
||||
// instance and Block Storage volume availability zones aren't specified,
|
||||
// the default enforced by your OpenStack cluster will be used.
|
||||
VolumeAvailabilityZone string `mapstructure:"volume_availability_zone" required:"false"`
|
||||
|
||||
// Not really used, but here for BC
|
||||
OpenstackProvider string `mapstructure:"openstack_provider"`
|
||||
UseFloatingIp bool `mapstructure:"use_floating_ip"`
|
||||
// *Deprecated* use `floating_ip` or `floating_ip_pool` instead.
|
||||
UseFloatingIp bool `mapstructure:"use_floating_ip" required:"false"`
|
||||
|
||||
sourceImageOpts images.ListOpts
|
||||
}
|
||||
|
||||
type ImageFilter struct {
|
||||
Filters ImageFilterOptions `mapstructure:"filters"`
|
||||
MostRecent bool `mapstructure:"most_recent"`
|
||||
// filters used to select a source_image. NOTE: This will fail unless
|
||||
// exactly one image is returned, or most_recent is set to true. Of the
|
||||
// filters described in ImageService, the following are valid:
|
||||
Filters ImageFilterOptions `mapstructure:"filters" required:"false"`
|
||||
// Selects the newest created image when true. This is most useful for
|
||||
// selecting a daily distro build.
|
||||
MostRecent bool `mapstructure:"most_recent" required:"false"`
|
||||
}
|
||||
|
||||
type ImageFilterOptions struct {
|
||||
|
@ -149,8 +270,8 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
|
|||
}
|
||||
|
||||
if c.UseBlockStorageVolume {
|
||||
// Use Compute instance availability zone for the Block Storage volume if
|
||||
// it's not provided.
|
||||
// Use Compute instance availability zone for the Block Storage volume
|
||||
// if it's not provided.
|
||||
if c.VolumeAvailabilityZone == "" {
|
||||
c.VolumeAvailabilityZone = c.AvailabilityZone
|
||||
}
|
||||
|
@ -161,7 +282,8 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
|
|||
}
|
||||
}
|
||||
|
||||
// if neither ID or image name is provided outside the filter, build the filter
|
||||
// if neither ID or image name is provided outside the filter, build the
|
||||
// filter
|
||||
if len(c.SourceImage) == 0 && len(c.SourceImageName) == 0 {
|
||||
|
||||
listOpts, filterErr := c.SourceImageFilters.Filters.Build()
|
||||
|
|
|
@ -23,7 +23,9 @@ func testRunConfig() *RunConfig {
|
|||
Flavor: "m1.small",
|
||||
|
||||
Comm: communicator.Config{
|
||||
SSHUsername: "foo",
|
||||
SSH: communicator.SSH{
|
||||
SSHUsername: "foo",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,9 +22,10 @@ func testConfig() *RunConfig {
|
|||
return &RunConfig{
|
||||
SourceOmi: "abcd",
|
||||
VmType: "m1.small",
|
||||
|
||||
Comm: communicator.Config{
|
||||
SSHUsername: "foo",
|
||||
SSH: communicator.SSH{
|
||||
SSHUsername: "foo",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
func testConfigTemplate(t *testing.T) *interpolate.Context {
|
||||
return &interpolate.Context{}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
|
@ -7,14 +9,18 @@ import (
|
|||
)
|
||||
|
||||
type HWConfig struct {
|
||||
|
||||
// cpu information
|
||||
CpuCount int `mapstructure:"cpus"`
|
||||
MemorySize int `mapstructure:"memory"`
|
||||
|
||||
// device presence
|
||||
Sound bool `mapstructure:"sound"`
|
||||
USB bool `mapstructure:"usb"`
|
||||
// The number of cpus to use for building the VM.
|
||||
// Defaults to 1.
|
||||
CpuCount int `mapstructure:"cpus" required:"false"`
|
||||
// The amount of memory to use for building the VM in
|
||||
// megabytes. Defaults to 512 megabytes.
|
||||
MemorySize int `mapstructure:"memory" required:"false"`
|
||||
// Specifies whether to enable the sound device when
|
||||
// building the VM. Defaults to false.
|
||||
Sound bool `mapstructure:"sound" required:"false"`
|
||||
// Specifies whether to enable the USB bus when building
|
||||
// the VM. Defaults to false.
|
||||
USB bool `mapstructure:"usb" required:"false"`
|
||||
}
|
||||
|
||||
func (c *HWConfig) Prepare(ctx *interpolate.Context) []error {
|
||||
|
|
|
@ -2,11 +2,13 @@ package common
|
|||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
func TestHWConfigPrepare(t *testing.T) {
|
||||
c := new(HWConfig)
|
||||
if errs := c.Prepare(testConfigTemplate(t)); len(errs) > 0 {
|
||||
if errs := c.Prepare(interpolate.NewContext()); len(errs) > 0 {
|
||||
t.Fatalf("err: %#v", errs)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
|
@ -11,7 +13,13 @@ import (
|
|||
|
||||
// OutputConfig contains the configuration for builder's output.
|
||||
type OutputConfig struct {
|
||||
OutputDir string `mapstructure:"output_directory"`
|
||||
// This is the path to the directory where the
|
||||
// resulting virtual machine will be created. This may be relative or absolute.
|
||||
// If relative, the path is relative to the working directory when packer
|
||||
// is executed. This directory must not exist or be empty prior to running
|
||||
// the builder. By default this is "output-BUILDNAME" where "BUILDNAME" is the
|
||||
// name of the build.
|
||||
OutputDir string `mapstructure:"output_directory" required:"false"`
|
||||
}
|
||||
|
||||
// Prepare configures the output directory or returns an error if it already exists.
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/common"
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
func TestOutputConfigPrepare(t *testing.T) {
|
||||
|
@ -17,7 +18,7 @@ func TestOutputConfigPrepare(t *testing.T) {
|
|||
}
|
||||
|
||||
pc := &common.PackerConfig{PackerBuildName: "foo"}
|
||||
errs := c.Prepare(testConfigTemplate(t), pc)
|
||||
errs := c.Prepare(interpolate.NewContext(), pc)
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("err: %#v", errs)
|
||||
}
|
||||
|
@ -41,7 +42,7 @@ func TestOutputConfigPrepare_exists(t *testing.T) {
|
|||
PackerBuildName: "foo",
|
||||
PackerForce: false,
|
||||
}
|
||||
errs := c.Prepare(testConfigTemplate(t), pc)
|
||||
errs := c.Prepare(interpolate.NewContext(), pc)
|
||||
if len(errs) == 0 {
|
||||
t.Fatal("should have errors")
|
||||
}
|
||||
|
@ -61,7 +62,7 @@ func TestOutputConfigPrepare_forceExists(t *testing.T) {
|
|||
PackerBuildName: "foo",
|
||||
PackerForce: true,
|
||||
}
|
||||
errs := c.Prepare(testConfigTemplate(t), pc)
|
||||
errs := c.Prepare(interpolate.NewContext(), pc)
|
||||
if len(errs) > 0 {
|
||||
t.Fatal("should not have errors")
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
|
@ -7,7 +9,17 @@ import (
|
|||
// PrlctlConfig contains the configuration for running "prlctl" commands
|
||||
// before the VM start.
|
||||
type PrlctlConfig struct {
|
||||
Prlctl [][]string `mapstructure:"prlctl"`
|
||||
// Custom prlctl commands to execute
|
||||
// in order to further customize the virtual machine being created. The value
|
||||
// of this is an array of commands to execute. The commands are executed in the
|
||||
// order defined in the template. For each command, the command is defined
|
||||
// itself as an array of strings, where each string represents a single
|
||||
// argument on the command-line to prlctl (but excluding prlctl itself).
|
||||
// Each arg is treated as a configuration
|
||||
// template, where the Name
|
||||
// variable is replaced with the VM name. More details on how to use prlctl
|
||||
// are below.
|
||||
Prlctl [][]string `mapstructure:"prlctl" required:"false"`
|
||||
}
|
||||
|
||||
// Prepare sets the default value of "Prlctl" property.
|
||||
|
|
|
@ -3,12 +3,14 @@ package common
|
|||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
func TestPrlctlConfigPrepare_Prlctl(t *testing.T) {
|
||||
// Test with empty
|
||||
c := new(PrlctlConfig)
|
||||
errs := c.Prepare(testConfigTemplate(t))
|
||||
errs := c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("err: %#v", errs)
|
||||
}
|
||||
|
@ -22,7 +24,7 @@ func TestPrlctlConfigPrepare_Prlctl(t *testing.T) {
|
|||
c.Prlctl = [][]string{
|
||||
{"foo", "bar", "baz"},
|
||||
}
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("err: %#v", errs)
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
|
@ -7,7 +9,10 @@ import (
|
|||
// PrlctlPostConfig contains the configuration for running "prlctl" commands
|
||||
// in the end of artifact build.
|
||||
type PrlctlPostConfig struct {
|
||||
PrlctlPost [][]string `mapstructure:"prlctl_post"`
|
||||
// Identical to prlctl, except
|
||||
// that it is run after the virtual machine is shutdown, and before the virtual
|
||||
// machine is exported.
|
||||
PrlctlPost [][]string `mapstructure:"prlctl_post" required:"false"`
|
||||
}
|
||||
|
||||
// Prepare sets the default value of "PrlctlPost" property.
|
||||
|
|
|
@ -3,12 +3,14 @@ package common
|
|||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
func TestPrlctlPostConfigPrepare_PrlctlPost(t *testing.T) {
|
||||
// Test with empty
|
||||
c := new(PrlctlPostConfig)
|
||||
errs := c.Prepare(testConfigTemplate(t))
|
||||
errs := c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("err: %#v", errs)
|
||||
}
|
||||
|
@ -22,7 +24,7 @@ func TestPrlctlPostConfigPrepare_PrlctlPost(t *testing.T) {
|
|||
c.PrlctlPost = [][]string{
|
||||
{"foo", "bar", "baz"},
|
||||
}
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("err: %#v", errs)
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
|
@ -6,7 +8,12 @@ import (
|
|||
|
||||
// PrlctlVersionConfig contains the configuration for `prlctl` version.
|
||||
type PrlctlVersionConfig struct {
|
||||
PrlctlVersionFile string `mapstructure:"prlctl_version_file"`
|
||||
// The path within the virtual machine to
|
||||
// upload a file that contains the prlctl version that was used to create
|
||||
// the machine. This information can be useful for provisioning. By default
|
||||
// this is ".prlctl_version", which will generally upload it into the
|
||||
// home directory.
|
||||
PrlctlVersionFile string `mapstructure:"prlctl_version_file" required:"false"`
|
||||
}
|
||||
|
||||
// Prepare sets the default value of "PrlctlVersionFile" property.
|
||||
|
|
|
@ -2,6 +2,8 @@ package common
|
|||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
func TestPrlctlVersionConfigPrepare_BootWait(t *testing.T) {
|
||||
|
@ -10,7 +12,7 @@ func TestPrlctlVersionConfigPrepare_BootWait(t *testing.T) {
|
|||
|
||||
// Test empty
|
||||
c = new(PrlctlVersionConfig)
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("should not have error: %s", errs)
|
||||
}
|
||||
|
@ -22,7 +24,7 @@ func TestPrlctlVersionConfigPrepare_BootWait(t *testing.T) {
|
|||
// Test with a good one
|
||||
c = new(PrlctlVersionConfig)
|
||||
c.PrlctlVersionFile = "foo"
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("should not have error: %s", errs)
|
||||
}
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
// ShutdownConfig contains the configuration for VM shutdown.
|
||||
type ShutdownConfig struct {
|
||||
ShutdownCommand string `mapstructure:"shutdown_command"`
|
||||
RawShutdownTimeout string `mapstructure:"shutdown_timeout"`
|
||||
|
||||
ShutdownTimeout time.Duration ``
|
||||
}
|
||||
|
||||
// Prepare sets default values to the VM shutdown configuration.
|
||||
func (c *ShutdownConfig) Prepare(ctx *interpolate.Context) []error {
|
||||
if c.RawShutdownTimeout == "" {
|
||||
c.RawShutdownTimeout = "5m"
|
||||
}
|
||||
|
||||
var errs []error
|
||||
var err error
|
||||
c.ShutdownTimeout, err = time.ParseDuration(c.RawShutdownTimeout)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("Failed parsing shutdown_timeout: %s", err))
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func testShutdownConfig() *ShutdownConfig {
|
||||
return &ShutdownConfig{}
|
||||
}
|
||||
|
||||
func TestShutdownConfigPrepare_ShutdownCommand(t *testing.T) {
|
||||
var c *ShutdownConfig
|
||||
var errs []error
|
||||
|
||||
c = testShutdownConfig()
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("err: %#v", errs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShutdownConfigPrepare_ShutdownTimeout(t *testing.T) {
|
||||
var c *ShutdownConfig
|
||||
var errs []error
|
||||
|
||||
// Test with a bad value
|
||||
c = testShutdownConfig()
|
||||
c.RawShutdownTimeout = "this is not good"
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
if len(errs) == 0 {
|
||||
t.Fatalf("should have error")
|
||||
}
|
||||
|
||||
// Test with a good one
|
||||
c = testShutdownConfig()
|
||||
c.RawShutdownTimeout = "5s"
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("err: %#v", errs)
|
||||
}
|
||||
if c.ShutdownTimeout != 5*time.Second {
|
||||
t.Fatalf("bad: %s", c.ShutdownTimeout)
|
||||
}
|
||||
}
|
|
@ -6,19 +6,22 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/helper/communicator"
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
func testSSHConfig() *SSHConfig {
|
||||
return &SSHConfig{
|
||||
Comm: communicator.Config{
|
||||
SSHUsername: "foo",
|
||||
SSH: communicator.SSH{
|
||||
SSHUsername: "foo",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestSSHConfigPrepare(t *testing.T) {
|
||||
c := testSSHConfig()
|
||||
errs := c.Prepare(testConfigTemplate(t))
|
||||
errs := c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("err: %#v", errs)
|
||||
}
|
||||
|
@ -34,14 +37,14 @@ func TestSSHConfigPrepare_SSHPrivateKey(t *testing.T) {
|
|||
|
||||
c = testSSHConfig()
|
||||
c.Comm.SSHPrivateKeyFile = ""
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("should not have error: %#v", errs)
|
||||
}
|
||||
|
||||
c = testSSHConfig()
|
||||
c.Comm.SSHPrivateKeyFile = "/i/dont/exist"
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) == 0 {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
@ -60,7 +63,7 @@ func TestSSHConfigPrepare_SSHPrivateKey(t *testing.T) {
|
|||
|
||||
c = testSSHConfig()
|
||||
c.Comm.SSHPrivateKeyFile = tf.Name()
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) == 0 {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
@ -71,7 +74,7 @@ func TestSSHConfigPrepare_SSHPrivateKey(t *testing.T) {
|
|||
tf.Write([]byte(testPem))
|
||||
c = testSSHConfig()
|
||||
c.Comm.SSHPrivateKeyFile = tf.Name()
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("should not have error: %#v", errs)
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
|
@ -17,9 +19,26 @@ const (
|
|||
|
||||
// ToolsConfig contains the builder configuration related to Parallels Tools.
|
||||
type ToolsConfig struct {
|
||||
ParallelsToolsFlavor string `mapstructure:"parallels_tools_flavor"`
|
||||
ParallelsToolsGuestPath string `mapstructure:"parallels_tools_guest_path"`
|
||||
ParallelsToolsMode string `mapstructure:"parallels_tools_mode"`
|
||||
// The flavor of the Parallels Tools ISO to
|
||||
// install into the VM. Valid values are "win", "lin", "mac", "os2"
|
||||
// and "other". This can be omitted only if parallels_tools_mode
|
||||
// is "disable".
|
||||
ParallelsToolsFlavor string `mapstructure:"parallels_tools_flavor" required:"true"`
|
||||
// The path in the virtual machine to
|
||||
// upload Parallels Tools. This only takes effect if parallels_tools_mode
|
||||
// is "upload". This is a configuration
|
||||
// template that has a single
|
||||
// valid variable: Flavor, which will be the value of
|
||||
// parallels_tools_flavor. By default this is "prl-tools-{{.Flavor}}.iso"
|
||||
// which should upload into the login directory of the user.
|
||||
ParallelsToolsGuestPath string `mapstructure:"parallels_tools_guest_path" required:"false"`
|
||||
// The method by which Parallels Tools are
|
||||
// made available to the guest for installation. Valid options are "upload",
|
||||
// "attach", or "disable". If the mode is "attach" the Parallels Tools ISO will
|
||||
// be attached as a CD device to the virtual machine. If the mode is "upload"
|
||||
// the Parallels Tools ISO will be uploaded to the path specified by
|
||||
// parallels_tools_guest_path. The default value is "upload".
|
||||
ParallelsToolsMode string `mapstructure:"parallels_tools_mode" required:"false"`
|
||||
}
|
||||
|
||||
// Prepare validates & sets up configuration options related to Parallels Tools.
|
||||
|
|
|
@ -2,6 +2,8 @@ package common
|
|||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
func testToolsConfig() *ToolsConfig {
|
||||
|
@ -14,7 +16,7 @@ func testToolsConfig() *ToolsConfig {
|
|||
|
||||
func TestToolsConfigPrepare(t *testing.T) {
|
||||
c := testToolsConfig()
|
||||
errs := c.Prepare(testConfigTemplate(t))
|
||||
errs := c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("bad err: %#v", errs)
|
||||
}
|
||||
|
@ -27,7 +29,7 @@ func TestToolsConfigPrepare_ParallelsToolsMode(t *testing.T) {
|
|||
// Test default mode
|
||||
c = testToolsConfig()
|
||||
c.ParallelsToolsMode = ""
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("should not have error: %#v", errs)
|
||||
}
|
||||
|
@ -38,7 +40,7 @@ func TestToolsConfigPrepare_ParallelsToolsMode(t *testing.T) {
|
|||
// Test another mode
|
||||
c = testToolsConfig()
|
||||
c.ParallelsToolsMode = "attach"
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("should not have error: %#v", errs)
|
||||
}
|
||||
|
@ -49,7 +51,7 @@ func TestToolsConfigPrepare_ParallelsToolsMode(t *testing.T) {
|
|||
// Test invalid mode
|
||||
c = testToolsConfig()
|
||||
c.ParallelsToolsMode = "invalid_mode"
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) == 0 {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
@ -62,7 +64,7 @@ func TestToolsConfigPrepare_ParallelsToolsGuestPath(t *testing.T) {
|
|||
// Test default path
|
||||
c = testToolsConfig()
|
||||
c.ParallelsToolsGuestPath = ""
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("should not have error: %#v", errs)
|
||||
}
|
||||
|
@ -73,7 +75,7 @@ func TestToolsConfigPrepare_ParallelsToolsGuestPath(t *testing.T) {
|
|||
// Test with a good one
|
||||
c = testToolsConfig()
|
||||
c.ParallelsToolsGuestPath = "foo"
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("should not have error: %s", errs)
|
||||
}
|
||||
|
@ -90,7 +92,7 @@ func TestToolsConfigPrepare_ParallelsToolsFlavor(t *testing.T) {
|
|||
// Test with a default value
|
||||
c = testToolsConfig()
|
||||
c.ParallelsToolsFlavor = ""
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) == 0 {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
@ -99,7 +101,7 @@ func TestToolsConfigPrepare_ParallelsToolsFlavor(t *testing.T) {
|
|||
c = testToolsConfig()
|
||||
c.ParallelsToolsMode = "attach"
|
||||
c.ParallelsToolsFlavor = ""
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) == 0 {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
@ -108,7 +110,7 @@ func TestToolsConfigPrepare_ParallelsToolsFlavor(t *testing.T) {
|
|||
c = testToolsConfig()
|
||||
c.ParallelsToolsMode = "disable"
|
||||
c.ParallelsToolsFlavor = ""
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("should not have error: %s", errs)
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package iso
|
||||
|
||||
import (
|
||||
|
@ -8,6 +10,7 @@ import (
|
|||
parallelscommon "github.com/hashicorp/packer/builder/parallels/common"
|
||||
"github.com/hashicorp/packer/common"
|
||||
"github.com/hashicorp/packer/common/bootcommand"
|
||||
"github.com/hashicorp/packer/common/shutdowncommand"
|
||||
"github.com/hashicorp/packer/helper/communicator"
|
||||
"github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
|
@ -33,17 +36,47 @@ type Config struct {
|
|||
parallelscommon.PrlctlConfig `mapstructure:",squash"`
|
||||
parallelscommon.PrlctlPostConfig `mapstructure:",squash"`
|
||||
parallelscommon.PrlctlVersionConfig `mapstructure:",squash"`
|
||||
parallelscommon.ShutdownConfig `mapstructure:",squash"`
|
||||
shutdowncommand.ShutdownConfig `mapstructure:",squash"`
|
||||
parallelscommon.SSHConfig `mapstructure:",squash"`
|
||||
parallelscommon.ToolsConfig `mapstructure:",squash"`
|
||||
|
||||
DiskSize uint `mapstructure:"disk_size"`
|
||||
DiskType string `mapstructure:"disk_type"`
|
||||
GuestOSType string `mapstructure:"guest_os_type"`
|
||||
HardDriveInterface string `mapstructure:"hard_drive_interface"`
|
||||
HostInterfaces []string `mapstructure:"host_interfaces"`
|
||||
SkipCompaction bool `mapstructure:"skip_compaction"`
|
||||
VMName string `mapstructure:"vm_name"`
|
||||
// The size, in megabytes, of the hard disk to create
|
||||
// for the VM. By default, this is 40000 (about 40 GB).
|
||||
DiskSize uint `mapstructure:"disk_size" required:"false"`
|
||||
// The type for image file based virtual disk drives,
|
||||
// defaults to expand. Valid options are expand (expanding disk) that the
|
||||
// image file is small initially and grows in size as you add data to it, and
|
||||
// plain (plain disk) that the image file has a fixed size from the moment it
|
||||
// is created (i.e the space is allocated for the full drive). Plain disks
|
||||
// perform faster than expanding disks. skip_compaction will be set to true
|
||||
// automatically for plain disks.
|
||||
DiskType string `mapstructure:"disk_type" required:"false"`
|
||||
// The guest OS type being installed. By default
|
||||
// this is "other", but you can get dramatic performance improvements by
|
||||
// setting this to the proper value. To view all available values for this run
|
||||
// prlctl create x --distribution list. Setting the correct value hints to
|
||||
// Parallels Desktop how to optimize the virtual hardware to work best with
|
||||
// that operating system.
|
||||
GuestOSType string `mapstructure:"guest_os_type" required:"false"`
|
||||
// The type of controller that the hard
|
||||
// drives are attached to, defaults to "sata". Valid options are "sata", "ide",
|
||||
// and "scsi".
|
||||
HardDriveInterface string `mapstructure:"hard_drive_interface" required:"false"`
|
||||
// A list of which interfaces on the
|
||||
// host should be searched for a IP address. The first IP address found on one
|
||||
// of these will be used as {{ .HTTPIP }} in the boot_command. Defaults to
|
||||
// ["en0", "en1", "en2", "en3", "en4", "en5", "en6", "en7", "en8", "en9",
|
||||
// "ppp0", "ppp1", "ppp2"].
|
||||
HostInterfaces []string `mapstructure:"host_interfaces" required:"false"`
|
||||
// Virtual disk image is compacted at the end of
|
||||
// the build process using prl_disk_tool utility (except for the case that
|
||||
// disk_type is set to plain). In certain rare cases, this might corrupt
|
||||
// the resulting disk image. If you find this to be the case, you can disable
|
||||
// compaction using this configuration value.
|
||||
SkipCompaction bool `mapstructure:"skip_compaction" required:"false"`
|
||||
// This is the name of the PVM directory for the new
|
||||
// virtual machine, without the file extension. By default this is
|
||||
// "packer-BUILDNAME", where "BUILDNAME" is the name of the build.
|
||||
VMName string `mapstructure:"vm_name" required:"false"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package pvm
|
||||
|
||||
import (
|
||||
|
@ -7,6 +9,7 @@ import (
|
|||
parallelscommon "github.com/hashicorp/packer/builder/parallels/common"
|
||||
"github.com/hashicorp/packer/common"
|
||||
"github.com/hashicorp/packer/common/bootcommand"
|
||||
"github.com/hashicorp/packer/common/shutdowncommand"
|
||||
"github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
|
@ -21,14 +24,26 @@ type Config struct {
|
|||
parallelscommon.PrlctlPostConfig `mapstructure:",squash"`
|
||||
parallelscommon.PrlctlVersionConfig `mapstructure:",squash"`
|
||||
parallelscommon.SSHConfig `mapstructure:",squash"`
|
||||
parallelscommon.ShutdownConfig `mapstructure:",squash"`
|
||||
shutdowncommand.ShutdownConfig `mapstructure:",squash"`
|
||||
bootcommand.BootConfig `mapstructure:",squash"`
|
||||
parallelscommon.ToolsConfig `mapstructure:",squash"`
|
||||
|
||||
SourcePath string `mapstructure:"source_path"`
|
||||
SkipCompaction bool `mapstructure:"skip_compaction"`
|
||||
VMName string `mapstructure:"vm_name"`
|
||||
ReassignMAC bool `mapstructure:"reassign_mac"`
|
||||
// The path to a PVM directory that acts as the source
|
||||
// of this build.
|
||||
SourcePath string `mapstructure:"source_path" required:"true"`
|
||||
// Virtual disk image is compacted at the end of
|
||||
// the build process using prl_disk_tool utility (except for the case that
|
||||
// disk_type is set to plain). In certain rare cases, this might corrupt
|
||||
// the resulting disk image. If you find this to be the case, you can disable
|
||||
// compaction using this configuration value.
|
||||
SkipCompaction bool `mapstructure:"skip_compaction" required:"false"`
|
||||
// This is the name of the PVM directory for the new
|
||||
// virtual machine, without the file extension. By default this is
|
||||
// "packer-BUILDNAME", where "BUILDNAME" is the name of the build.
|
||||
VMName string `mapstructure:"vm_name" required:"false"`
|
||||
// If this is "false" the MAC address of the first
|
||||
// NIC will reused when imported else a new MAC address will be generated
|
||||
// by Parallels. Defaults to "false".
|
||||
ReassignMAC bool `mapstructure:"reassign_mac" required:"false"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package qemu
|
||||
|
||||
import (
|
||||
|
@ -13,6 +15,7 @@ import (
|
|||
|
||||
"github.com/hashicorp/packer/common"
|
||||
"github.com/hashicorp/packer/common/bootcommand"
|
||||
"github.com/hashicorp/packer/common/shutdowncommand"
|
||||
"github.com/hashicorp/packer/helper/communicator"
|
||||
"github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
|
@ -89,56 +92,239 @@ type Builder struct {
|
|||
}
|
||||
|
||||
type Config struct {
|
||||
common.PackerConfig `mapstructure:",squash"`
|
||||
common.HTTPConfig `mapstructure:",squash"`
|
||||
common.ISOConfig `mapstructure:",squash"`
|
||||
bootcommand.VNCConfig `mapstructure:",squash"`
|
||||
Comm communicator.Config `mapstructure:",squash"`
|
||||
common.FloppyConfig `mapstructure:",squash"`
|
||||
|
||||
ISOSkipCache bool `mapstructure:"iso_skip_cache"`
|
||||
Accelerator string `mapstructure:"accelerator"`
|
||||
CpuCount int `mapstructure:"cpus"`
|
||||
AdditionalDiskSize []string `mapstructure:"disk_additional_size"`
|
||||
DiskInterface string `mapstructure:"disk_interface"`
|
||||
DiskSize uint `mapstructure:"disk_size"`
|
||||
DiskCache string `mapstructure:"disk_cache"`
|
||||
DiskDiscard string `mapstructure:"disk_discard"`
|
||||
DetectZeroes string `mapstructure:"disk_detect_zeroes"`
|
||||
SkipCompaction bool `mapstructure:"skip_compaction"`
|
||||
DiskCompression bool `mapstructure:"disk_compression"`
|
||||
Format string `mapstructure:"format"`
|
||||
Headless bool `mapstructure:"headless"`
|
||||
DiskImage bool `mapstructure:"disk_image"`
|
||||
UseBackingFile bool `mapstructure:"use_backing_file"`
|
||||
MachineType string `mapstructure:"machine_type"`
|
||||
MemorySize int `mapstructure:"memory"`
|
||||
NetDevice string `mapstructure:"net_device"`
|
||||
OutputDir string `mapstructure:"output_directory"`
|
||||
QemuArgs [][]string `mapstructure:"qemuargs"`
|
||||
QemuBinary string `mapstructure:"qemu_binary"`
|
||||
QMPSocketPath string `mapstructure:"qmp_socket_path"`
|
||||
ShutdownCommand string `mapstructure:"shutdown_command"`
|
||||
SSHHostPortMin int `mapstructure:"ssh_host_port_min"`
|
||||
SSHHostPortMax int `mapstructure:"ssh_host_port_max"`
|
||||
UseDefaultDisplay bool `mapstructure:"use_default_display"`
|
||||
VNCBindAddress string `mapstructure:"vnc_bind_address"`
|
||||
VNCPortMin int `mapstructure:"vnc_port_min"`
|
||||
VNCPortMax int `mapstructure:"vnc_port_max"`
|
||||
VNCUsePassword bool `mapstructure:"vnc_use_password"`
|
||||
VMName string `mapstructure:"vm_name"`
|
||||
common.PackerConfig `mapstructure:",squash"`
|
||||
common.HTTPConfig `mapstructure:",squash"`
|
||||
common.ISOConfig `mapstructure:",squash"`
|
||||
bootcommand.VNCConfig `mapstructure:",squash"`
|
||||
shutdowncommand.ShutdownConfig `mapstructure:",squash"`
|
||||
Comm communicator.Config `mapstructure:",squash"`
|
||||
common.FloppyConfig `mapstructure:",squash"`
|
||||
// Use iso from provided url. Qemu must support
|
||||
// curl block device. This defaults to `false`.
|
||||
ISOSkipCache bool `mapstructure:"iso_skip_cache" required:"false"`
|
||||
// The accelerator type to use when running the VM.
|
||||
// This may be `none`, `kvm`, `tcg`, `hax`, `hvf`, `whpx`, or `xen`. The appropriate
|
||||
// software must have already been installed on your build machine to use the
|
||||
// accelerator you specified. When no accelerator is specified, Packer will try
|
||||
// to use `kvm` if it is available but will default to `tcg` otherwise.
|
||||
//
|
||||
// -> The `hax` accelerator has issues attaching CDROM ISOs. This is an
|
||||
// upstream issue which can be tracked
|
||||
// [here](https://github.com/intel/haxm/issues/20).
|
||||
//
|
||||
// -> The `hvf` and `whpx` accelerator are new and experimental as of
|
||||
// [QEMU 2.12.0](https://wiki.qemu.org/ChangeLog/2.12#Host_support).
|
||||
// You may encounter issues unrelated to Packer when using these. You may need to
|
||||
// add [ "-global", "virtio-pci.disable-modern=on" ] to `qemuargs` depending on the
|
||||
// guest operating system.
|
||||
//
|
||||
// -> For `whpx`, note that [Stefan Weil's QEMU for Windows distribution](https://qemu.weilnetz.de/w64/)
|
||||
// does not include WHPX support and users may need to compile or source a
|
||||
// build of QEMU for Windows themselves with WHPX support.
|
||||
Accelerator string `mapstructure:"accelerator" required:"false"`
|
||||
// Additional disks to create. Uses `vm_name` as the disk name template and
|
||||
// appends `-#` where `#` is the position in the array. `#` starts at 1 since 0
|
||||
// is the default disk. Each string represents the disk image size in bytes.
|
||||
// Optional suffixes 'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G'
|
||||
// (gigabyte, 1024M), 'T' (terabyte, 1024G), 'P' (petabyte, 1024T) and 'E'
|
||||
// (exabyte, 1024P) are supported. 'b' is ignored. Per qemu-img documentation.
|
||||
// Each additional disk uses the same disk parameters as the default disk.
|
||||
// Unset by default.
|
||||
AdditionalDiskSize []string `mapstructure:"disk_additional_size" required:"false"`
|
||||
// The number of cpus to use when building the VM.
|
||||
// The default is `1` CPU.
|
||||
CpuCount int `mapstructure:"cpus" required:"false"`
|
||||
// The interface to use for the disk. Allowed values include any of `ide`,
|
||||
// `scsi`, `virtio` or `virtio-scsi`^\*. Note also that any boot commands
|
||||
// or kickstart type scripts must have proper adjustments for resulting
|
||||
// device names. The Qemu builder uses `virtio` by default.
|
||||
//
|
||||
// ^\* Please be aware that use of the `scsi` disk interface has been
|
||||
// disabled by Red Hat due to a bug described
|
||||
// [here](https://bugzilla.redhat.com/show_bug.cgi?id=1019220). If you are
|
||||
// running Qemu on RHEL or a RHEL variant such as CentOS, you *must* choose
|
||||
// one of the other listed interfaces. Using the `scsi` interface under
|
||||
// these circumstances will cause the build to fail.
|
||||
DiskInterface string `mapstructure:"disk_interface" required:"false"`
|
||||
// The size, in megabytes, of the hard disk to create
|
||||
// for the VM. By default, this is 40960 (40 GB).
|
||||
DiskSize uint `mapstructure:"disk_size" required:"false"`
|
||||
// The cache mode to use for disk. Allowed values include any of
|
||||
// `writethrough`, `writeback`, `none`, `unsafe` or `directsync`. By
|
||||
// default, this is set to `writeback`.
|
||||
DiskCache string `mapstructure:"disk_cache" required:"false"`
|
||||
// The discard mode to use for disk. Allowed values
|
||||
// include any of unmap or ignore. By default, this is set to ignore.
|
||||
DiskDiscard string `mapstructure:"disk_discard" required:"false"`
|
||||
// The detect-zeroes mode to use for disk.
|
||||
// Allowed values include any of unmap, on or off. Defaults to off.
|
||||
// When the value is "off" we don't set the flag in the qemu command, so that
|
||||
// Packer still works with old versions of QEMU that don't have this option.
|
||||
DetectZeroes string `mapstructure:"disk_detect_zeroes" required:"false"`
|
||||
// Packer compacts the QCOW2 image using
|
||||
// qemu-img convert. Set this option to true to disable compacting.
|
||||
// Defaults to false.
|
||||
SkipCompaction bool `mapstructure:"skip_compaction" required:"false"`
|
||||
// Apply compression to the QCOW2 disk file
|
||||
// using qemu-img convert. Defaults to false.
|
||||
DiskCompression bool `mapstructure:"disk_compression" required:"false"`
|
||||
// Either `qcow2` or `raw`, this specifies the output format of the virtual
|
||||
// machine image. This defaults to `qcow2`.
|
||||
Format string `mapstructure:"format" required:"false"`
|
||||
// Packer defaults to building QEMU virtual machines by
|
||||
// launching a GUI that shows the console of the machine being built. When this
|
||||
// value is set to `true`, the machine will start without a console.
|
||||
//
|
||||
// You can still see the console if you make a note of the VNC display
|
||||
// number chosen, and then connect using `vncviewer -Shared <host>:<display>`
|
||||
Headless bool `mapstructure:"headless" required:"false"`
|
||||
// Packer defaults to building from an ISO file, this parameter controls
|
||||
// whether the ISO URL supplied is actually a bootable QEMU image. When
|
||||
// this value is set to `true`, the machine will either clone the source or
|
||||
// use it as a backing file (if `use_backing_file` is `true`); then, it
|
||||
// will resize the image according to `disk_size` and boot it.
|
||||
DiskImage bool `mapstructure:"disk_image" required:"false"`
|
||||
// Only applicable when disk_image is true
|
||||
// and format is qcow2, set this option to true to create a new QCOW2
|
||||
// file that uses the file located at iso_url as a backing file. The new file
|
||||
// will only contain blocks that have changed compared to the backing file, so
|
||||
// enabling this option can significantly reduce disk usage.
|
||||
UseBackingFile bool `mapstructure:"use_backing_file" required:"false"`
|
||||
// The type of machine emulation to use. Run your qemu binary with the
|
||||
// flags `-machine help` to list available types for your system. This
|
||||
// defaults to `pc`.
|
||||
MachineType string `mapstructure:"machine_type" required:"false"`
|
||||
// The amount of memory to use when building the VM
|
||||
// in megabytes. This defaults to 512 megabytes.
|
||||
MemorySize int `mapstructure:"memory" required:"false"`
|
||||
// The driver to use for the network interface. Allowed values `ne2k_pci`,
|
||||
// `i82551`, `i82557b`, `i82559er`, `rtl8139`, `e1000`, `pcnet`, `virtio`,
|
||||
// `virtio-net`, `virtio-net-pci`, `usb-net`, `i82559a`, `i82559b`,
|
||||
// `i82559c`, `i82550`, `i82562`, `i82557a`, `i82557c`, `i82801`,
|
||||
// `vmxnet3`, `i82558a` or `i82558b`. The Qemu builder uses `virtio-net` by
|
||||
// default.
|
||||
NetDevice string `mapstructure:"net_device" required:"false"`
|
||||
// This is the path to the directory where the
|
||||
// resulting virtual machine will be created. This may be relative or absolute.
|
||||
// If relative, the path is relative to the working directory when packer
|
||||
// is executed. This directory must not exist or be empty prior to running
|
||||
// the builder. By default this is output-BUILDNAME where "BUILDNAME" is the
|
||||
// name of the build.
|
||||
OutputDir string `mapstructure:"output_directory" required:"false"`
|
||||
// Allows complete control over the qemu command line (though not, at this
|
||||
// time, qemu-img). Each array of strings makes up a command line switch
|
||||
// that overrides matching default switch/value pairs. Any value specified
|
||||
// as an empty string is ignored. All values after the switch are
|
||||
// concatenated with no separator.
|
||||
//
|
||||
// ~> **Warning:** The qemu command line allows extreme flexibility, so
|
||||
// beware of conflicting arguments causing failures of your run. For
|
||||
// instance, using --no-acpi could break the ability to send power signal
|
||||
// type commands (e.g., shutdown -P now) to the virtual machine, thus
|
||||
// preventing proper shutdown. To see the defaults, look in the packer.log
|
||||
// file and search for the qemu-system-x86 command. The arguments are all
|
||||
// printed for review.
|
||||
//
|
||||
// The following shows a sample usage:
|
||||
//
|
||||
// ``` json {
|
||||
// "qemuargs": [
|
||||
// [ "-m", "1024M" ],
|
||||
// [ "--no-acpi", "" ],
|
||||
// [
|
||||
// "-netdev",
|
||||
// "user,id=mynet0,",
|
||||
// "hostfwd=hostip:hostport-guestip:guestport",
|
||||
// ""
|
||||
// ],
|
||||
// [ "-device", "virtio-net,netdev=mynet0" ]
|
||||
// ]
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// would produce the following (not including other defaults supplied by
|
||||
// the builder and not otherwise conflicting with the qemuargs):
|
||||
//
|
||||
// ``` text qemu-system-x86 -m 1024m --no-acpi -netdev
|
||||
// user,id=mynet0,hostfwd=hostip:hostport-guestip:guestport -device
|
||||
// virtio-net,netdev=mynet0" ```
|
||||
//
|
||||
// ~> **Windows Users:** [QEMU for Windows](https://qemu.weilnetz.de/)
|
||||
// builds are available though an environmental variable does need to be
|
||||
// set for QEMU for Windows to redirect stdout to the console instead of
|
||||
// stdout.txt.
|
||||
//
|
||||
// The following shows the environment variable that needs to be set for
|
||||
// Windows QEMU support:
|
||||
//
|
||||
// ``` text setx SDL_STDIO_REDIRECT=0 ```
|
||||
//
|
||||
// You can also use the `SSHHostPort` template variable to produce a packer
|
||||
// template that can be invoked by `make` in parallel:
|
||||
//
|
||||
// ``` json {
|
||||
// "qemuargs": [
|
||||
// [ "-netdev", "user,hostfwd=tcp::{{ .SSHHostPort }}-:22,id=forward"],
|
||||
// [ "-device", "virtio-net,netdev=forward,id=net0"]
|
||||
// ]
|
||||
// } ```
|
||||
//
|
||||
// `make -j 3 my-awesome-packer-templates` spawns 3 packer processes, each
|
||||
// of which will bind to their own SSH port as determined by each process.
|
||||
// This will also work with WinRM, just change the port forward in
|
||||
// `qemuargs` to map to WinRM's default port of `5985` or whatever value
|
||||
// you have the service set to listen on.
|
||||
QemuArgs [][]string `mapstructure:"qemuargs" required:"false"`
|
||||
// The name of the Qemu binary to look for. This
|
||||
// defaults to qemu-system-x86_64, but may need to be changed for
|
||||
// some platforms. For example qemu-kvm, or qemu-system-i386 may be a
|
||||
// better choice for some systems.
|
||||
QemuBinary string `mapstructure:"qemu_binary" required:"false"`
|
||||
// Enable QMP socket. Location is specified by `qmp_socket_path`. Defaults
|
||||
// to false.
|
||||
QMPEnable bool `mapstructure:"qmp_enable" required:"false"`
|
||||
// QMP Socket Path when `qmp_enable` is true. Defaults to
|
||||
// `output_directory`/`vm_name`.monitor.
|
||||
QMPSocketPath string `mapstructure:"qmp_socket_path" required:"false"`
|
||||
// The minimum and maximum port to use for the SSH port on the host machine
|
||||
// which is forwarded to the SSH port on the guest machine. Because Packer
|
||||
// often runs in parallel, Packer will choose a randomly available port in
|
||||
// this range to use as the host port. By default this is 2222 to 4444.
|
||||
SSHHostPortMin int `mapstructure:"ssh_host_port_min" required:"false"`
|
||||
SSHHostPortMax int `mapstructure:"ssh_host_port_max" required:"false"`
|
||||
// If true, do not pass a -display option
|
||||
// to qemu, allowing it to choose the default. This may be needed when running
|
||||
// under macOS, and getting errors about sdl not being available.
|
||||
UseDefaultDisplay bool `mapstructure:"use_default_display" required:"false"`
|
||||
// The IP address that should be
|
||||
// binded to for VNC. By default packer will use 127.0.0.1 for this. If you
|
||||
// wish to bind to all interfaces use 0.0.0.0.
|
||||
VNCBindAddress string `mapstructure:"vnc_bind_address" required:"false"`
|
||||
// Whether or not to set a password on the VNC server. This option
|
||||
// automatically enables the QMP socket. See `qmp_socket_path`. Defaults to
|
||||
// `false`.
|
||||
VNCUsePassword bool `mapstructure:"vnc_use_password" required:"false"`
|
||||
// The minimum and maximum port
|
||||
// to use for VNC access to the virtual machine. The builder uses VNC to type
|
||||
// the initial boot_command. Because Packer generally runs in parallel,
|
||||
// Packer uses a randomly chosen port in this range that appears available. By
|
||||
// default this is 5900 to 6000. The minimum and maximum ports are inclusive.
|
||||
VNCPortMin int `mapstructure:"vnc_port_min" required:"false"`
|
||||
VNCPortMax int `mapstructure:"vnc_port_max"`
|
||||
// This is the name of the image (QCOW2 or IMG) file for
|
||||
// the new virtual machine. By default this is packer-BUILDNAME, where
|
||||
// "BUILDNAME" is the name of the build. Currently, no file extension will be
|
||||
// used unless it is specified in this option.
|
||||
VMName string `mapstructure:"vm_name" required:"false"`
|
||||
|
||||
// These are deprecated, but we keep them around for BC
|
||||
// TODO(@mitchellh): remove
|
||||
SSHWaitTimeout time.Duration `mapstructure:"ssh_wait_timeout"`
|
||||
SSHWaitTimeout time.Duration `mapstructure:"ssh_wait_timeout" required:"false"`
|
||||
|
||||
// TODO(mitchellh): deprecate
|
||||
RunOnce bool `mapstructure:"run_once"`
|
||||
|
||||
RawShutdownTimeout string `mapstructure:"shutdown_timeout"`
|
||||
|
||||
shutdownTimeout time.Duration ``
|
||||
ctx interpolate.Context
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
||||
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
|
@ -159,6 +345,8 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
|||
var errs *packer.MultiError
|
||||
warnings := make([]string, 0)
|
||||
|
||||
errs = packer.MultiErrorAppend(errs, b.config.ShutdownConfig.Prepare(&b.config.ctx)...)
|
||||
|
||||
if b.config.DiskSize == 0 {
|
||||
b.config.DiskSize = 40960
|
||||
}
|
||||
|
@ -332,16 +520,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
|||
}
|
||||
}
|
||||
|
||||
if b.config.RawShutdownTimeout == "" {
|
||||
b.config.RawShutdownTimeout = "5m"
|
||||
}
|
||||
|
||||
b.config.shutdownTimeout, err = time.ParseDuration(b.config.RawShutdownTimeout)
|
||||
if err != nil {
|
||||
errs = packer.MultiErrorAppend(
|
||||
errs, fmt.Errorf("Failed parsing shutdown_timeout: %s", err))
|
||||
}
|
||||
|
||||
if b.config.SSHHostPortMin > b.config.SSHHostPortMax {
|
||||
errs = packer.MultiErrorAppend(
|
||||
errs, errors.New("ssh_host_port_min must be less than ssh_host_port_max"))
|
||||
|
|
|
@ -33,7 +33,7 @@ func (s *stepShutdown) Run(ctx context.Context, state multistep.StateBag) multis
|
|||
cancelCh := make(chan struct{}, 1)
|
||||
go func() {
|
||||
defer close(cancelCh)
|
||||
<-time.After(config.shutdownTimeout)
|
||||
<-time.After(config.ShutdownTimeout)
|
||||
}()
|
||||
ui.Say("Waiting for shutdown...")
|
||||
if ok := driver.WaitForShutdown(cancelCh); ok {
|
||||
|
@ -63,10 +63,10 @@ func (s *stepShutdown) Run(ctx context.Context, state multistep.StateBag) multis
|
|||
cancelCh := make(chan struct{}, 1)
|
||||
go func() {
|
||||
defer close(cancelCh)
|
||||
<-time.After(config.shutdownTimeout)
|
||||
<-time.After(config.ShutdownTimeout)
|
||||
}()
|
||||
|
||||
log.Printf("Waiting max %s for shutdown to complete", config.shutdownTimeout)
|
||||
log.Printf("Waiting max %s for shutdown to complete", config.ShutdownTimeout)
|
||||
if ok := driver.WaitForShutdown(cancelCh); !ok {
|
||||
err := errors.New("Timeout while waiting for machine to shut down.")
|
||||
state.Put("error", err)
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package scaleway
|
||||
|
||||
import (
|
||||
|
@ -19,19 +21,48 @@ import (
|
|||
type Config struct {
|
||||
common.PackerConfig `mapstructure:",squash"`
|
||||
Comm communicator.Config `mapstructure:",squash"`
|
||||
|
||||
Token string `mapstructure:"api_token"`
|
||||
Organization string `mapstructure:"organization_id"`
|
||||
|
||||
Region string `mapstructure:"region"`
|
||||
Image string `mapstructure:"image"`
|
||||
CommercialType string `mapstructure:"commercial_type"`
|
||||
|
||||
SnapshotName string `mapstructure:"snapshot_name"`
|
||||
ImageName string `mapstructure:"image_name"`
|
||||
ServerName string `mapstructure:"server_name"`
|
||||
Bootscript string `mapstructure:"bootscript"`
|
||||
BootType string `mapstructure:"boottype"`
|
||||
// The token to use to authenticate with your account.
|
||||
// It can also be specified via environment variable SCALEWAY_API_TOKEN. You
|
||||
// can see and generate tokens in the "Credentials"
|
||||
// section of the control panel.
|
||||
Token string `mapstructure:"api_token" required:"true"`
|
||||
// The organization id to use to identify your
|
||||
// organization. It can also be specified via environment variable
|
||||
// SCALEWAY_ORGANIZATION. Your organization id is available in the
|
||||
// "Account" section of the
|
||||
// control panel.
|
||||
// Previously named: api_access_key with environment variable: SCALEWAY_API_ACCESS_KEY
|
||||
Organization string `mapstructure:"organization_id" required:"true"`
|
||||
// The name of the region to launch the server in (par1
|
||||
// or ams1). Consequently, this is the region where the snapshot will be
|
||||
// available.
|
||||
Region string `mapstructure:"region" required:"true"`
|
||||
// The UUID of the base image to use. This is the image
|
||||
// that will be used to launch a new server and provision it. See
|
||||
// the images list
|
||||
// get the complete list of the accepted image UUID.
|
||||
Image string `mapstructure:"image" required:"true"`
|
||||
// The name of the server commercial type:
|
||||
// ARM64-128GB, ARM64-16GB, ARM64-2GB, ARM64-32GB, ARM64-4GB,
|
||||
// ARM64-64GB, ARM64-8GB, C1, C2L, C2M, C2S, START1-L,
|
||||
// START1-M, START1-S, START1-XS, X64-120GB, X64-15GB, X64-30GB,
|
||||
// X64-60GB
|
||||
CommercialType string `mapstructure:"commercial_type" required:"true"`
|
||||
// The name of the resulting snapshot that will
|
||||
// appear in your account. Default packer-TIMESTAMP
|
||||
SnapshotName string `mapstructure:"snapshot_name" required:"false"`
|
||||
// The name of the resulting image that will appear in
|
||||
// your account. Default packer-TIMESTAMP
|
||||
ImageName string `mapstructure:"image_name" required:"false"`
|
||||
// The name assigned to the server. Default
|
||||
// packer-UUID
|
||||
ServerName string `mapstructure:"server_name" required:"false"`
|
||||
// The id of an existing bootscript to use when
|
||||
// booting the server.
|
||||
Bootscript string `mapstructure:"bootscript" required:"false"`
|
||||
// The type of boot, can be either local or
|
||||
// bootscript, Default bootscript
|
||||
BootType string `mapstructure:"boottype" required:"false"`
|
||||
|
||||
RemoveVolume bool `mapstructure:"remove_volume"`
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package cvm
|
||||
|
||||
import (
|
||||
|
@ -44,11 +46,22 @@ var ValidRegions = []Region{
|
|||
}
|
||||
|
||||
type TencentCloudAccessConfig struct {
|
||||
SecretId string `mapstructure:"secret_id"`
|
||||
SecretKey string `mapstructure:"secret_key"`
|
||||
Region string `mapstructure:"region"`
|
||||
Zone string `mapstructure:"zone"`
|
||||
SkipValidation bool `mapstructure:"skip_region_validation"`
|
||||
// Tencentcloud secret id. You should set it directly,
|
||||
// or set the TENCENTCLOUD_ACCESS_KEY environment variable.
|
||||
SecretId string `mapstructure:"secret_id" required:"true"`
|
||||
// Tencentcloud secret key. You should set it directly,
|
||||
// or set the TENCENTCLOUD_SECRET_KEY environment variable.
|
||||
SecretKey string `mapstructure:"secret_key" required:"true"`
|
||||
// The region where your cvm will be launch. You should
|
||||
// reference Region and Zone
|
||||
// for parameter taking.
|
||||
Region string `mapstructure:"region" required:"true"`
|
||||
// The zone where your cvm will be launch. You should
|
||||
// reference Region and Zone
|
||||
// for parameter taking.
|
||||
Zone string `mapstructure:"zone" required:"true"`
|
||||
// Do not check region and zone when validate.
|
||||
SkipValidation bool `mapstructure:"skip_region_validation" required:"false"`
|
||||
}
|
||||
|
||||
func (cf *TencentCloudAccessConfig) Client() (*cvm.Client, *vpc.Client, error) {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package cvm
|
||||
|
||||
import (
|
||||
|
@ -7,15 +9,29 @@ import (
|
|||
)
|
||||
|
||||
type TencentCloudImageConfig struct {
|
||||
ImageName string `mapstructure:"image_name"`
|
||||
ImageDescription string `mapstructure:"image_description"`
|
||||
Reboot bool `mapstructure:"reboot"`
|
||||
ForcePoweroff bool `mapstructure:"force_poweroff"`
|
||||
Sysprep bool `mapstructure:"sysprep"`
|
||||
ImageForceDelete bool `mapstructure:"image_force_delete"`
|
||||
ImageCopyRegions []string `mapstructure:"image_copy_regions"`
|
||||
ImageShareAccounts []string `mapstructure:"image_share_accounts"`
|
||||
SkipValidation bool `mapstructure:"skip_region_validation"`
|
||||
// The name you want to create your customize image,
|
||||
// it should be composed of no more than 20 characters, of letters, numbers
|
||||
// or minus sign.
|
||||
ImageName string `mapstructure:"image_name" required:"true"`
|
||||
// Image description.
|
||||
ImageDescription string `mapstructure:"image_description" required:"false"`
|
||||
// Whether shutdown cvm to create Image. Default value is
|
||||
// false.
|
||||
Reboot bool `mapstructure:"reboot" required:"false"`
|
||||
// Whether to force power off cvm when create image.
|
||||
// Default value is false.
|
||||
ForcePoweroff bool `mapstructure:"force_poweroff" required:"false"`
|
||||
// Whether enable Sysprep during creating windows image.
|
||||
Sysprep bool `mapstructure:"sysprep" required:"false"`
|
||||
ImageForceDelete bool `mapstructure:"image_force_delete"`
|
||||
// regions that will be copied to after
|
||||
// your image created.
|
||||
ImageCopyRegions []string `mapstructure:"image_copy_regions" required:"false"`
|
||||
// accounts that will be shared to
|
||||
// after your image created.
|
||||
ImageShareAccounts []string `mapstructure:"image_share_accounts" required:"false"`
|
||||
// Do not check region and zone when validate.
|
||||
SkipValidation bool `mapstructure:"skip_region_validation" required:"false"`
|
||||
}
|
||||
|
||||
func (cf *TencentCloudImageConfig) Prepare(ctx *interpolate.Context) []error {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package cvm
|
||||
|
||||
import (
|
||||
|
@ -17,28 +19,68 @@ type tencentCloudDataDisk struct {
|
|||
}
|
||||
|
||||
type TencentCloudRunConfig struct {
|
||||
AssociatePublicIpAddress bool `mapstructure:"associate_public_ip_address"`
|
||||
SourceImageId string `mapstructure:"source_image_id"`
|
||||
InstanceType string `mapstructure:"instance_type"`
|
||||
InstanceName string `mapstructure:"instance_name"`
|
||||
DiskType string `mapstructure:"disk_type"`
|
||||
DiskSize int64 `mapstructure:"disk_size"`
|
||||
DataDisks []tencentCloudDataDisk `mapstructure:"data_disks"`
|
||||
VpcId string `mapstructure:"vpc_id"`
|
||||
VpcName string `mapstructure:"vpc_name"`
|
||||
VpcIp string `mapstructure:"vpc_ip"`
|
||||
SubnetId string `mapstructure:"subnet_id"`
|
||||
SubnetName string `mapstructure:"subnet_name"`
|
||||
CidrBlock string `mapstructure:"cidr_block"` // 10.0.0.0/16(default), 172.16.0.0/12, 192.168.0.0/16
|
||||
SubnectCidrBlock string `mapstructure:"subnect_cidr_block"`
|
||||
InternetChargeType string `mapstructure:"internet_charge_type"`
|
||||
InternetMaxBandwidthOut int64 `mapstructure:"internet_max_bandwidth_out"`
|
||||
SecurityGroupId string `mapstructure:"security_group_id"`
|
||||
SecurityGroupName string `mapstructure:"security_group_name"`
|
||||
UserData string `mapstructure:"user_data"`
|
||||
UserDataFile string `mapstructure:"user_data_file"`
|
||||
HostName string `mapstructure:"host_name"`
|
||||
RunTags map[string]string `mapstructure:"run_tags"`
|
||||
// Whether allocate public ip to your cvm.
|
||||
// Default value is false.
|
||||
AssociatePublicIpAddress bool `mapstructure:"associate_public_ip_address" required:"false"`
|
||||
// The base image id of Image you want to create
|
||||
// your customized image from.
|
||||
SourceImageId string `mapstructure:"source_image_id" required:"true"`
|
||||
// The instance type your cvm will be launched by.
|
||||
// You should reference Instace Type
|
||||
// for parameter taking.
|
||||
InstanceType string `mapstructure:"instance_type" required:"true"`
|
||||
// Instance name.
|
||||
InstanceName string `mapstructure:"instance_name" required:"false"`
|
||||
// Root disk type your cvm will be launched by. you could
|
||||
// reference Disk Type
|
||||
// for parameter taking.
|
||||
DiskType string `mapstructure:"disk_type" required:"false"`
|
||||
// Root disk size your cvm will be launched by. values range(in GB):
|
||||
DiskSize int64 `mapstructure:"disk_size" required:"false"`
|
||||
// Add one or more data disks to the instance before creating the image.
|
||||
// Note that if the source image has data disk snapshots, this argument
|
||||
// will be ignored, and the running instance will use source image data
|
||||
// disk settings, in such case, `disk_type` argument will be used as disk
|
||||
// type for all data disks, and each data disk size will use the origin
|
||||
// value in source image.
|
||||
// The data disks allow for the following argument:
|
||||
// - `disk_type` - Type of the data disk. Valid choices: `CLOUD_BASIC`, `CLOUD_PREMIUM` and `CLOUD_SSD`.
|
||||
// - `disk_size` - Size of the data disk.
|
||||
// - `disk_snapshot_id` - Id of the snapshot for a data disk.
|
||||
DataDisks []tencentCloudDataDisk `mapstructure:"data_disks"`
|
||||
// Specify vpc your cvm will be launched by.
|
||||
VpcId string `mapstructure:"vpc_id" required:"false"`
|
||||
// Specify vpc name you will create. if vpc_id is not set, packer will
|
||||
// create a vpc for you named this parameter.
|
||||
VpcName string `mapstructure:"vpc_name" required:"false"`
|
||||
VpcIp string `mapstructure:"vpc_ip"`
|
||||
// Specify subnet your cvm will be launched by.
|
||||
SubnetId string `mapstructure:"subnet_id" required:"false"`
|
||||
// Specify subnet name you will create. if subnet_id is not set, packer will
|
||||
// create a subnet for you named this parameter.
|
||||
SubnetName string `mapstructure:"subnet_name" required:"false"`
|
||||
// Specify cider block of the vpc you will create if vpc_id not set
|
||||
CidrBlock string `mapstructure:"cidr_block" required:"false"` // 10.0.0.0/16(default), 172.16.0.0/12, 192.168.0.0/16
|
||||
// Specify cider block of the subnet you will create if
|
||||
// subnet_id not set
|
||||
SubnectCidrBlock string `mapstructure:"subnect_cidr_block" required:"false"`
|
||||
InternetChargeType string `mapstructure:"internet_charge_type"`
|
||||
// Max bandwidth out your cvm will be launched by(in MB).
|
||||
// values can be set between 1 ~ 100.
|
||||
InternetMaxBandwidthOut int64 `mapstructure:"internet_max_bandwidth_out" required:"false"`
|
||||
// Specify security group your cvm will be launched by.
|
||||
SecurityGroupId string `mapstructure:"security_group_id" required:"false"`
|
||||
// Specify security name you will create if security_group_id not set.
|
||||
SecurityGroupName string `mapstructure:"security_group_name" required:"false"`
|
||||
// userdata.
|
||||
UserData string `mapstructure:"user_data" required:"false"`
|
||||
// userdata file.
|
||||
UserDataFile string `mapstructure:"user_data_file" required:"false"`
|
||||
// host name.
|
||||
HostName string `mapstructure:"host_name" required:"false"`
|
||||
// Tags to apply to the instance that is *launched* to create the image.
|
||||
// These tags are *not* applied to the resulting image.
|
||||
RunTags map[string]string `mapstructure:"run_tags" required:"false"`
|
||||
|
||||
// Communicator settings
|
||||
Comm communicator.Config `mapstructure:",squash"`
|
||||
|
|
|
@ -13,7 +13,9 @@ func testConfig() *TencentCloudRunConfig {
|
|||
SourceImageId: "img-qwer1234",
|
||||
InstanceType: "S3.SMALL2",
|
||||
Comm: communicator.Config{
|
||||
SSHUsername: "tencentcloud",
|
||||
SSH: communicator.SSH{
|
||||
SSHUsername: "tencentcloud",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package triton
|
||||
|
||||
import (
|
||||
|
@ -17,12 +19,32 @@ import (
|
|||
|
||||
// AccessConfig is for common configuration related to Triton access
|
||||
type AccessConfig struct {
|
||||
Endpoint string `mapstructure:"triton_url"`
|
||||
Account string `mapstructure:"triton_account"`
|
||||
Username string `mapstructure:"triton_user"`
|
||||
KeyID string `mapstructure:"triton_key_id"`
|
||||
KeyMaterial string `mapstructure:"triton_key_material"`
|
||||
InsecureSkipTLSVerify bool `mapstructure:"insecure_skip_tls_verify"`
|
||||
// The URL of the Triton cloud API to use. If omitted
|
||||
// it will default to the us-sw-1 region of the Joyent Public cloud. If you
|
||||
// are using your own private Triton installation you will have to supply the
|
||||
// URL of the cloud API of your own Triton installation.
|
||||
Endpoint string `mapstructure:"triton_url" required:"false"`
|
||||
// The username of the Triton account to use when
|
||||
// using the Triton Cloud API.
|
||||
Account string `mapstructure:"triton_account" required:"true"`
|
||||
// The username of a user who has access to your
|
||||
// Triton account.
|
||||
Username string `mapstructure:"triton_user" required:"false"`
|
||||
// The fingerprint of the public key of the SSH key
|
||||
// pair to use for authentication with the Triton Cloud API. If
|
||||
// triton_key_material is not set, it is assumed that the SSH agent has the
|
||||
// private key corresponding to this key ID loaded.
|
||||
KeyID string `mapstructure:"triton_key_id" required:"true"`
|
||||
// Path to the file in which the private key
|
||||
// of triton_key_id is stored. For example /home/soandso/.ssh/id_rsa. If
|
||||
// this is not specified, the SSH agent is used to sign requests with the
|
||||
// triton_key_id specified.
|
||||
KeyMaterial string `mapstructure:"triton_key_material" required:"false"`
|
||||
//secure_skip_tls_verify - (bool) This allows skipping TLS verification
|
||||
// of the Triton endpoint. It is useful when connecting to a temporary Triton
|
||||
// installation such as Cloud-On-A-Laptop which does not generally use a
|
||||
// certificate signed by a trusted root CA. The default is false.
|
||||
InsecureSkipTLSVerify bool `mapstructure:"insecure_skip_tls_verify" required:"false"`
|
||||
|
||||
signer authentication.Signer
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package triton
|
||||
|
||||
import (
|
||||
|
@ -9,14 +11,60 @@ import (
|
|||
// SourceMachineConfig represents the configuration to run a machine using
|
||||
// the SDC API in order for provisioning to take place.
|
||||
type SourceMachineConfig struct {
|
||||
MachineName string `mapstructure:"source_machine_name"`
|
||||
MachinePackage string `mapstructure:"source_machine_package"`
|
||||
MachineImage string `mapstructure:"source_machine_image"`
|
||||
MachineNetworks []string `mapstructure:"source_machine_networks"`
|
||||
MachineMetadata map[string]string `mapstructure:"source_machine_metadata"`
|
||||
MachineTags map[string]string `mapstructure:"source_machine_tags"`
|
||||
MachineFirewallEnabled bool `mapstructure:"source_machine_firewall_enabled"`
|
||||
MachineImageFilters MachineImageFilter `mapstructure:"source_machine_image_filter"`
|
||||
// Name of the VM used for building the
|
||||
// image. Does not affect (and does not have to be the same) as the name for a
|
||||
// VM instance running this image. Maximum 512 characters but should in
|
||||
// practice be much shorter (think between 5 and 20 characters). For example
|
||||
// mysql-64-server-image-builder. When omitted defaults to
|
||||
// packer-builder-[image_name].
|
||||
MachineName string `mapstructure:"source_machine_name" required:"false"`
|
||||
// The Triton package to use while
|
||||
// building the image. Does not affect (and does not have to be the same) as
|
||||
// the package which will be used for a VM instance running this image. On the
|
||||
// Joyent public cloud this could for example be g3-standard-0.5-smartos.
|
||||
MachinePackage string `mapstructure:"source_machine_package" required:"true"`
|
||||
// The UUID of the image to base the new
|
||||
// image on. Triton supports multiple types of images, called 'brands' in
|
||||
// Triton / Joyent lingo, for contains and VM's. See the chapter Containers
|
||||
// and virtual machines in
|
||||
// the Joyent Triton documentation for detailed information. The following
|
||||
// brands are currently supported by this builder:joyent andkvm. The
|
||||
// choice of base image automatically decides the brand. On the Joyent public
|
||||
// cloud a valid source_machine_image could for example be
|
||||
// 70e3ae72-96b6-11e6-9056-9737fd4d0764 for version 16.3.1 of the 64bit
|
||||
// SmartOS base image (a 'joyent' brand image). source_machine_image_filter
|
||||
// can be used to populate this UUID.
|
||||
MachineImage string `mapstructure:"source_machine_image" required:"true"`
|
||||
// The UUID's of Triton
|
||||
// networks added to the source machine used for creating the image. For
|
||||
// example if any of the provisioners which are run need Internet access you
|
||||
// will need to add the UUID's of the appropriate networks here. If this is
|
||||
// not specified, instances will be placed into the default Triton public and
|
||||
// internal networks.
|
||||
MachineNetworks []string `mapstructure:"source_machine_networks" required:"false"`
|
||||
// Triton metadata
|
||||
// applied to the VM used to create the image. Metadata can be used to pass
|
||||
// configuration information to the VM without the need for networking. See
|
||||
// Using the metadata
|
||||
// API in the
|
||||
// Joyent documentation for more information. This can for example be used to
|
||||
// set the user-script metadata key to have Triton start a user supplied
|
||||
// script after the VM has booted.
|
||||
MachineMetadata map[string]string `mapstructure:"source_machine_metadata" required:"false"`
|
||||
// Tags applied to the
|
||||
// VM used to create the image.
|
||||
MachineTags map[string]string `mapstructure:"source_machine_tags" required:"false"`
|
||||
// Whether or not the firewall
|
||||
// of the VM used to create an image of is enabled. The Triton firewall only
|
||||
// filters inbound traffic to the VM. All outbound traffic is always allowed.
|
||||
// Currently this builder does not provide an interface to add specific
|
||||
// firewall rules. Unless you have a global rule defined in Triton which
|
||||
// allows SSH traffic enabling the firewall will interfere with the SSH
|
||||
// provisioner. The default is false.
|
||||
MachineFirewallEnabled bool `mapstructure:"source_machine_firewall_enabled" required:"false"`
|
||||
// Filters used to populate the
|
||||
// source_machine_image field. Example:
|
||||
MachineImageFilters MachineImageFilter `mapstructure:"source_machine_image_filter" required:"false"`
|
||||
}
|
||||
|
||||
type MachineImageFilter struct {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package triton
|
||||
|
||||
import (
|
||||
|
@ -9,13 +11,31 @@ import (
|
|||
// TargetImageConfig represents the configuration for the image to be created
|
||||
// from the source machine.
|
||||
type TargetImageConfig struct {
|
||||
ImageName string `mapstructure:"image_name"`
|
||||
ImageVersion string `mapstructure:"image_version"`
|
||||
ImageDescription string `mapstructure:"image_description"`
|
||||
ImageHomepage string `mapstructure:"image_homepage"`
|
||||
ImageEULA string `mapstructure:"image_eula_url"`
|
||||
ImageACL []string `mapstructure:"image_acls"`
|
||||
ImageTags map[string]string `mapstructure:"image_tags"`
|
||||
// The name the finished image in Triton will be
|
||||
// assigned. Maximum 512 characters but should in practice be much shorter
|
||||
// (think between 5 and 20 characters). For example postgresql-95-server for
|
||||
// an image used as a PostgreSQL 9.5 server.
|
||||
ImageName string `mapstructure:"image_name" required:"true"`
|
||||
// The version string for this image. Maximum 128
|
||||
// characters. Any string will do but a format of Major.Minor.Patch is
|
||||
// strongly advised by Joyent. See Semantic Versioning
|
||||
// for more information on the Major.Minor.Patch versioning format.
|
||||
ImageVersion string `mapstructure:"image_version" required:"true"`
|
||||
// Description of the image. Maximum 512
|
||||
// characters.
|
||||
ImageDescription string `mapstructure:"image_description" required:"false"`
|
||||
// URL of the homepage where users can find
|
||||
// information about the image. Maximum 128 characters.
|
||||
ImageHomepage string `mapstructure:"image_homepage" required:"false"`
|
||||
// URL of the End User License Agreement (EULA)
|
||||
// for the image. Maximum 128 characters.
|
||||
ImageEULA string `mapstructure:"image_eula_url" required:"false"`
|
||||
// The UUID's of the users which will have
|
||||
// access to this image. When omitted only the owner (the Triton user whose
|
||||
// credentials are used) will have access to the image.
|
||||
ImageACL []string `mapstructure:"image_acls" required:"false"`
|
||||
// Tag applied to the image.
|
||||
ImageTags map[string]string `mapstructure:"image_tags" required:"false"`
|
||||
}
|
||||
|
||||
// Prepare performs basic validation on a TargetImageConfig struct.
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
package uhost
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/packer/helper/communicator"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/helper/communicator"
|
||||
)
|
||||
|
||||
func testConfig() *RunConfig {
|
||||
|
@ -11,7 +12,9 @@ func testConfig() *RunConfig {
|
|||
InstanceType: "n-basic-2",
|
||||
Zone: "cn-bj2-02",
|
||||
Comm: communicator.Config{
|
||||
SSHUsername: "ucloud",
|
||||
SSH: communicator.SSH{
|
||||
SSHUsername: "ucloud",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package vagrant
|
||||
|
||||
import (
|
||||
|
@ -36,39 +38,91 @@ type Config struct {
|
|||
common.FloppyConfig `mapstructure:",squash"`
|
||||
bootcommand.BootConfig `mapstructure:",squash"`
|
||||
SSHConfig `mapstructure:",squash"`
|
||||
|
||||
// This is the name of the new virtual machine.
|
||||
// By default this is "packer-BUILDNAME", where "BUILDNAME" is the name of the build.
|
||||
OutputDir string `mapstructure:"output_dir"`
|
||||
SourceBox string `mapstructure:"source_path"`
|
||||
GlobalID string `mapstructure:"global_id"`
|
||||
Checksum string `mapstructure:"checksum"`
|
||||
ChecksumType string `mapstructure:"checksum_type"`
|
||||
BoxName string `mapstructure:"box_name"`
|
||||
|
||||
Provider string `mapstructure:"provider"`
|
||||
// The directory to create that will contain your output box. We always
|
||||
// create this directory and run from inside of it to prevent Vagrant init
|
||||
// collisions. If unset, it will be set to packer- plus your buildname.
|
||||
OutputDir string `mapstructure:"output_dir" required:"false"`
|
||||
// URL of the vagrant box to use, or the name of the vagrant box.
|
||||
// hashicorp/precise64, ./mylocalbox.box and https://example.com/my-box.box
|
||||
// are all valid source boxes. If your source is a .box file, whether
|
||||
// locally or from a URL like the latter example above, you will also need
|
||||
// to provide a box_name. This option is required, unless you set
|
||||
// global_id. You may only set one or the other, not both.
|
||||
SourceBox string `mapstructure:"source_path" required:"true"`
|
||||
// the global id of a Vagrant box already added to Vagrant on your system.
|
||||
// You can find the global id of your Vagrant boxes using the command
|
||||
// vagrant global-status; your global_id will be a 7-digit number and
|
||||
// letter comination that you'll find in the leftmost column of the
|
||||
// global-status output. If you choose to use global_id instead of
|
||||
// source_box, Packer will skip the Vagrant initialize and add steps, and
|
||||
// simply launch the box directly using the global id.
|
||||
GlobalID string `mapstructure:"global_id" required:"true"`
|
||||
// The checksum for the .box file. The type of the checksum is specified
|
||||
// with checksum_type, documented below.
|
||||
Checksum string `mapstructure:"checksum" required:"false"`
|
||||
// The type of the checksum specified in checksum. Valid values are none,
|
||||
// md5, sha1, sha256, or sha512. Although the checksum will not be verified
|
||||
// when checksum_type is set to "none", this is not recommended since OVA
|
||||
// files can be very large and corruption does happen from time to time.
|
||||
ChecksumType string `mapstructure:"checksum_type" required:"false"`
|
||||
// if your source_box is a boxfile that we need to add to Vagrant, this is
|
||||
// the name to give it. If left blank, will default to "packer_" plus your
|
||||
// buildname.
|
||||
BoxName string `mapstructure:"box_name" required:"false"`
|
||||
// The vagrant provider.
|
||||
// This parameter is required when source_path have more than one provider,
|
||||
// or when using vagrant-cloud post-processor. Defaults to unset.
|
||||
Provider string `mapstructure:"provider" required:"false"`
|
||||
|
||||
Communicator string `mapstructure:"communicator"`
|
||||
|
||||
// Whether to Halt, Suspend, or Destroy the box
|
||||
TeardownMethod string `mapstructure:"teardown_method"`
|
||||
|
||||
// Options for the "vagrant init" command
|
||||
BoxVersion string `mapstructure:"box_version"`
|
||||
Template string `mapstructure:"template"`
|
||||
|
||||
// What vagrantfile to use
|
||||
VagrantfileTpl string `mapstructure:"vagrantfile_template"`
|
||||
// Whether to halt, suspend, or destroy the box when the build has
|
||||
// completed. Defaults to "halt"
|
||||
TeardownMethod string `mapstructure:"teardown_method" required:"false"`
|
||||
// What box version to use when initializing Vagrant.
|
||||
BoxVersion string `mapstructure:"box_version" required:"false"`
|
||||
// a path to a golang template for a vagrantfile. Our default template can
|
||||
// be found here. So far the only template variables available to you are
|
||||
// {{ .BoxName }} and {{ .SyncedFolder }}, which correspond to the Packer
|
||||
// options box_name and synced_folder.
|
||||
Template string `mapstructure:"template" required:"false"`
|
||||
|
||||
SyncedFolder string `mapstructure:"synced_folder"`
|
||||
|
||||
// Options for the "vagrant box add" command
|
||||
SkipAdd bool `mapstructure:"skip_add"`
|
||||
AddCACert string `mapstructure:"add_cacert"`
|
||||
AddCAPath string `mapstructure:"add_capath"`
|
||||
AddCert string `mapstructure:"add_cert"`
|
||||
AddClean bool `mapstructure:"add_clean"`
|
||||
AddForce bool `mapstructure:"add_force"`
|
||||
AddInsecure bool `mapstructure:"add_insecure"`
|
||||
|
||||
// Don't package the Vagrant box after build.
|
||||
SkipPackage bool `mapstructure:"skip_package"`
|
||||
// Don't call "vagrant add" to add the box to your local environment; this
|
||||
// is necessary if you want to launch a box that is already added to your
|
||||
// vagrant environment.
|
||||
SkipAdd bool `mapstructure:"skip_add" required:"false"`
|
||||
// Equivalent to setting the
|
||||
// --cacert
|
||||
// option in vagrant add; defaults to unset.
|
||||
AddCACert string `mapstructure:"add_cacert" required:"false"`
|
||||
// Equivalent to setting the
|
||||
// --capath option
|
||||
// in vagrant add; defaults to unset.
|
||||
AddCAPath string `mapstructure:"add_capath" required:"false"`
|
||||
// Equivalent to setting the
|
||||
// --cert option in
|
||||
// vagrant add; defaults to unset.
|
||||
AddCert string `mapstructure:"add_cert" required:"false"`
|
||||
// Equivalent to setting the
|
||||
// --clean flag in
|
||||
// vagrant add; defaults to unset.
|
||||
AddClean bool `mapstructure:"add_clean" required:"false"`
|
||||
// Equivalent to setting the
|
||||
// --force flag in
|
||||
// vagrant add; defaults to unset.
|
||||
AddForce bool `mapstructure:"add_force" required:"false"`
|
||||
// Equivalent to setting the
|
||||
// --insecure flag in
|
||||
// vagrant add; defaults to unset.
|
||||
AddInsecure bool `mapstructure:"add_insecure" required:"false"`
|
||||
// if true, Packer will not call vagrant package to
|
||||
// package your base box into its own standalone .box file.
|
||||
SkipPackage bool `mapstructure:"skip_package" required:"false"`
|
||||
OutputVagrantfile string `mapstructure:"output_vagrantfile"`
|
||||
PackageInclude []string `mapstructure:"package_include"`
|
||||
|
||||
|
|
|
@ -25,10 +25,13 @@ func (s *StepPackage) Run(ctx context.Context, state multistep.StateBag) multist
|
|||
}
|
||||
ui.Say("Packaging box...")
|
||||
packageArgs := []string{}
|
||||
box := "source"
|
||||
if s.GlobalID != "" {
|
||||
packageArgs = append(packageArgs, s.GlobalID)
|
||||
box = s.GlobalID
|
||||
}
|
||||
|
||||
packageArgs = append(packageArgs, box)
|
||||
|
||||
if len(s.Include) > 0 {
|
||||
packageArgs = append(packageArgs, "--include", strings.Join(s.Include, ","))
|
||||
}
|
||||
|
|
|
@ -30,7 +30,11 @@ func (s *StepSSHConfig) Run(ctx context.Context, state multistep.StateBag) multi
|
|||
driver := state.Get("driver").(VagrantDriver)
|
||||
config := state.Get("config").(*Config)
|
||||
|
||||
sshConfig, err := driver.SSHConfig(s.GlobalID)
|
||||
box := "source"
|
||||
if s.GlobalID != "" {
|
||||
box = s.GlobalID
|
||||
}
|
||||
sshConfig, err := driver.SSHConfig(box)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
func testConfigTemplate(t *testing.T) *interpolate.Context {
|
||||
return &interpolate.Context{}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
|
@ -7,7 +9,50 @@ import (
|
|||
)
|
||||
|
||||
type ExportConfig struct {
|
||||
Format string `mapstructure:"format"`
|
||||
// Either ovf or ova, this specifies the output format
|
||||
// of the exported virtual machine. This defaults to ovf.
|
||||
Format string `mapstructure:"format" required:"false"`
|
||||
// Additional options to pass to the [VBoxManage
|
||||
// export](https://www.virtualbox.org/manual/ch09.html#vboxmanage-export).
|
||||
// This can be useful for passing product information to include in the
|
||||
// resulting appliance file. Packer JSON configuration file example:
|
||||
//
|
||||
// ``` json
|
||||
// {
|
||||
// "type": "virtualbox-iso",
|
||||
// "export_opts":
|
||||
// [
|
||||
// "--manifest",
|
||||
// "--vsys", "0",
|
||||
// "--description", "{{user `vm_description`}}",
|
||||
// "--version", "{{user `vm_version`}}"
|
||||
// ],
|
||||
// "format": "ova",
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// A VirtualBox [VM
|
||||
// description](https://www.virtualbox.org/manual/ch09.html#vboxmanage-export-ovf)
|
||||
// may contain arbitrary strings; the GUI interprets HTML formatting. However,
|
||||
// the JSON format does not allow arbitrary newlines within a value. Add a
|
||||
// multi-line description by preparing the string in the shell before the
|
||||
// packer call like this (shell `>` continuation character snipped for easier
|
||||
// copy & paste):
|
||||
//
|
||||
// ``` {.shell}
|
||||
//
|
||||
// vm_description='some
|
||||
// multiline
|
||||
// description'
|
||||
//
|
||||
// vm_version='0.2.0'
|
||||
//
|
||||
// packer build \
|
||||
// -var "vm_description=${vm_description}" \
|
||||
// -var "vm_version=${vm_version}" \
|
||||
// "packer_conf.json"
|
||||
// ```
|
||||
ExportOpts []string `mapstructure:"export_opts" required:"false"`
|
||||
}
|
||||
|
||||
func (c *ExportConfig) Prepare(ctx *interpolate.Context) []error {
|
||||
|
@ -21,5 +66,9 @@ func (c *ExportConfig) Prepare(ctx *interpolate.Context) []error {
|
|||
errors.New("invalid format, only 'ovf' or 'ova' are allowed"))
|
||||
}
|
||||
|
||||
if c.ExportOpts == nil {
|
||||
c.ExportOpts = make([]string, 0)
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ package common
|
|||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
func TestExportConfigPrepare_BootWait(t *testing.T) {
|
||||
|
@ -11,7 +13,7 @@ func TestExportConfigPrepare_BootWait(t *testing.T) {
|
|||
// Bad
|
||||
c = new(ExportConfig)
|
||||
c.Format = "illegal"
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) == 0 {
|
||||
t.Fatalf("bad: %#v", errs)
|
||||
}
|
||||
|
@ -19,7 +21,7 @@ func TestExportConfigPrepare_BootWait(t *testing.T) {
|
|||
// Good
|
||||
c = new(ExportConfig)
|
||||
c.Format = "ova"
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("should not have error: %s", errs)
|
||||
}
|
||||
|
@ -27,7 +29,22 @@ func TestExportConfigPrepare_BootWait(t *testing.T) {
|
|||
// Good
|
||||
c = new(ExportConfig)
|
||||
c.Format = "ovf"
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("should not have error: %s", errs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExportConfigPrepare_Opts(t *testing.T) {
|
||||
var c *ExportConfig
|
||||
var errs []error
|
||||
|
||||
// Good
|
||||
c = new(ExportConfig)
|
||||
c.ExportOpts = []string{
|
||||
"--options",
|
||||
}
|
||||
errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("should not have error: %s", errs)
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
type ExportOpts struct {
|
||||
ExportOpts []string `mapstructure:"export_opts"`
|
||||
}
|
||||
|
||||
func (c *ExportOpts) Prepare(ctx *interpolate.Context) []error {
|
||||
if c.ExportOpts == nil {
|
||||
c.ExportOpts = make([]string, 0)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestExportOptsPrepare_BootWait(t *testing.T) {
|
||||
var c *ExportOpts
|
||||
var errs []error
|
||||
|
||||
// Good
|
||||
c = new(ExportOpts)
|
||||
c.ExportOpts = []string{
|
||||
"--options",
|
||||
}
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("should not have error: %s", errs)
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
|
@ -15,8 +17,15 @@ const (
|
|||
)
|
||||
|
||||
type GuestAdditionsConfig struct {
|
||||
Communicator string `mapstructure:"communicator"`
|
||||
GuestAdditionsMode string `mapstructure:"guest_additions_mode"`
|
||||
Communicator string `mapstructure:"communicator"`
|
||||
// The method by which guest additions are
|
||||
// made available to the guest for installation. Valid options are upload,
|
||||
// attach, or disable. If the mode is attach the guest additions ISO will
|
||||
// be attached as a CD device to the virtual machine. If the mode is upload
|
||||
// the guest additions ISO will be uploaded to the path specified by
|
||||
// guest_additions_path. The default value is upload. If disable is used,
|
||||
// guest additions won't be downloaded, either.
|
||||
GuestAdditionsMode string `mapstructure:"guest_additions_mode" required:"false"`
|
||||
}
|
||||
|
||||
func (c *GuestAdditionsConfig) Prepare(ctx *interpolate.Context) []error {
|
||||
|
|
|
@ -2,6 +2,8 @@ package common
|
|||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
func TestGuestAdditionsConfigPrepare(t *testing.T) {
|
||||
|
@ -10,7 +12,7 @@ func TestGuestAdditionsConfigPrepare(t *testing.T) {
|
|||
|
||||
c.GuestAdditionsMode = "disable"
|
||||
c.Communicator = "none"
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("should not have error: %s", errs)
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
|
@ -7,14 +9,19 @@ import (
|
|||
)
|
||||
|
||||
type HWConfig struct {
|
||||
|
||||
// cpu information
|
||||
CpuCount int `mapstructure:"cpus"`
|
||||
MemorySize int `mapstructure:"memory"`
|
||||
|
||||
// device presence
|
||||
Sound string `mapstructure:"sound"`
|
||||
USB bool `mapstructure:"usb"`
|
||||
// The number of cpus to use for building the VM.
|
||||
// Defaults to 1.
|
||||
CpuCount int `mapstructure:"cpus" required:"false"`
|
||||
// The amount of memory to use for building the VM
|
||||
// in megabytes. Defaults to 512 megabytes.
|
||||
MemorySize int `mapstructure:"memory" required:"false"`
|
||||
// Defaults to none. The type of audio device to use for
|
||||
// sound when building the VM. Some of the options that are available are
|
||||
// dsound, oss, alsa, pulse, coreaudio, null.
|
||||
Sound string `mapstructure:"sound" required:"false"`
|
||||
// Specifies whether or not to enable the USB bus when
|
||||
// building the VM. Defaults to false.
|
||||
USB bool `mapstructure:"usb" required:"false"`
|
||||
}
|
||||
|
||||
func (c *HWConfig) Prepare(ctx *interpolate.Context) []error {
|
||||
|
|
|
@ -2,11 +2,13 @@ package common
|
|||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
func TestHWConfigPrepare(t *testing.T) {
|
||||
c := new(HWConfig)
|
||||
if errs := c.Prepare(testConfigTemplate(t)); len(errs) > 0 {
|
||||
if errs := c.Prepare(interpolate.NewContext()); len(errs) > 0 {
|
||||
t.Fatalf("err: %#v", errs)
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue