Compare commits

...

48 Commits

Author SHA1 Message Date
Wilken Rivera 36c3d1b185 Add vault functions to HCL2 side navigation 2020-10-16 10:09:06 -04:00
Megan Marsh 66b81d9bee add build.name to hcl code (#10114) 2020-10-16 10:57:42 +02:00
Wilken Rivera a17b1a5a89 Fix references to source blocks (#10113) 2020-10-16 10:26:29 +02:00
Wilken Rivera 7ba2ffe171 Merge pull request #10106 from hashicorp/more_hcl_docs
More hcl docs
2020-10-15 13:50:46 -04:00
Wilken Rivera 5d2f2b20e7 Merge pull request #10112 from jmfury/jm.bump-hsm-version-1.0.7
[Website] Update HSM version w/ waypoint
2020-10-15 13:45:48 -04:00
Jimmy Merritello f79b9dc735 Update HSM version 2020-10-15 11:35:19 -05:00
Wilken Rivera 343ac2d48d syntax-json: Fix nested provisioner block example (#10109) 2020-10-15 16:04:01 +02:00
Megan Marsh 06efa61c13 a tiny bit more cleanup 2020-10-14 15:56:58 -07:00
Megan Marsh da15b85451 more updates 2020-10-14 13:35:21 -07:00
Megan Marsh 2cdc052d7c Merge pull request #10097 from hashicorp/more_hcl_docs
Update HCL docs with a local resource-free example to empower users t…
2020-10-14 13:34:54 -07:00
Megan Marsh 31df482b61 remove old docs for previous behavior 2020-10-14 13:11:52 -07:00
Megan Marsh 00cc425b84 docs tweaks 2020-10-14 12:58:04 -07:00
Megan Marsh 5522980e4d Merge pull request #10103 from jmfury/jm.website-bump-hsm-menu-v1.0.5
[Website] Bump HSM version
2020-10-14 12:46:16 -07:00
Megan Marsh 84d5de369f Merge pull request #10104 from pwillis-els/pwillis-els-patch-1
Fix typos in hcl2_upgrade
2020-10-14 12:38:07 -07:00
Peter Willis f1b57b1e66 Fix typos 2020-10-14 15:04:18 -04:00
Peter Willis a81811663a Fix typos 2020-10-14 14:52:17 -04:00
Megan Marsh c16354d594 Update HCL docs with a local resource-free example to empower users to tinker. 2020-10-14 11:24:15 -07:00
Jimmy Merritello e98b2d39db Updated pkg 2020-10-14 12:55:53 -05:00
Jimmy Merritello 8121d6d8dc Bump HSM version 2020-10-14 09:39:50 -05:00
Wilken Rivera c7ba5c9a14 Fix line ending issues for test files (#10096) 2020-10-14 11:03:43 +02:00
Megan Marsh 22622b234b Merge pull request #10095 from hashicorp/hcl_docs
add docs for hcl2_upgrade command
2020-10-13 15:36:49 -07:00
Megan Marsh 33019a0e01 add docs for hcl2_upgrade command 2020-10-13 13:56:54 -07:00
Megan Marsh 4810a3d86f Merge pull request #10077 from hashicorp/document_3348
builder/qemu: docs: users must re-apply packer defaults for drive and device arguments
2020-10-13 11:41:28 -07:00
Wilken Rivera 3abae29752 Update generated docs 2020-10-13 10:33:59 -04:00
Megan Marsh ad129e7df9 update changelog 2020-10-12 16:29:41 -07:00
Megan Marsh 75cfc97da4 Merge pull request #10081 from hashicorp/f-ansible-remote-ssm-connectivity
provisioner/Ansible: Add Amazon SSM setup documentation
2020-10-12 10:49:41 -07:00
Megan Marsh 01ed398756 fix up alicloud docs to make it clearer that disk_size and other disk device options are not top level fields. (#10080) 2020-10-12 10:28:25 +02:00
Wilken Rivera d378a4477a Merge pull request #10079 from hashicorp/vsphere_cluster_host_investigation
fix docs linking issue
2020-10-09 22:11:31 -04:00
Wilken Rivera 8154e5772f provisioner/Ansible: Add Amazon SSM setup documentation 2020-10-09 17:05:14 -04:00
Megan Marsh 709a173060 fix docs linking issue 2020-10-09 14:01:21 -07:00
Megan Marsh b05fd9303e document that users must re-apply packer defualts for drive and device arguments 2020-10-09 10:39:27 -07:00
Megan Marsh b460d687ea Merge pull request #10068 from jmfury/jm.website-bump-hsm-menu
Bump HSM version and rm meganav styles
2020-10-09 10:15:23 -07:00
Megan Marsh 774a168957 Merge pull request #10064 from hashicorp/refactor_step_run
builder/qemu: (tech-debt) Major refactor of step_run.
2020-10-08 11:54:34 -07:00
Jimmy Merritello 7ed2c2920f Bump HSM version and rm meganav styles 2020-10-08 13:53:36 -05:00
Megan Marsh 3e35630d8d remove slashes to prevent windows test fails 2020-10-08 11:36:36 -07:00
James Cradock 153d4111fa Fix typo in build argument description (#10066) 2020-10-08 14:58:22 +02:00
Megan Marsh 62a401ef28 Fix 10060 (#10065)
* fix overeager validation
* fix validation of openstack source images
2020-10-08 10:54:41 +02:00
Megan Marsh d6aa172edc remove typo'd option from docs 2020-10-07 16:14:13 -07:00
Megan Marsh d7ba10c23e update changelog 2020-10-07 15:52:06 -07:00
Megan Marsh f076c97e5c Merge pull request #10062 from jmfury/jm.add-hashi-stack-menu
[Website] Add new HashiStackMenu
2020-10-07 15:36:31 -07:00
Megan Marsh 8e632866b1 typo 2020-10-07 15:22:08 -07:00
Megan Marsh b54b778572 major refactor of the step_run. Splits step into two major parts:
- generating defaults
- overriding defaults with user args

The default generation has been shuffled around some, in order to
make sure that any changes to a specific arg happen in one place
to make it easier to reason about those args. Related args have
been moved close to one another.

The deviceArgs and driveArgs were overly complex after several
layers of copy/paste modifications. Careful pruning reduced the
layers of logic and repeated code, to help make it easier to reason
about.
2020-10-07 15:09:45 -07:00
Jimmy Merritello ea3b804af1 Bump version 2020-10-07 15:30:18 -05:00
Adrien Delorme 14e253f316 upgrade panicwrap to v1 (#10059)
* and go mod tidy this allows us to get rid of a dep
2020-10-07 11:22:32 -04:00
Jimmy Merritello 7f0a043a63 Add new HashiStackMenu 2020-10-07 09:57:47 -05:00
Patrik d4d78feed2 feat(scaleway): get image by label if not an UUID (#10061)
Signed-off-by: Patrik Cyvoct <patrik@ptrk.io>
2020-10-07 16:04:00 +02:00
abarbare a478bf6f37 fix: update scaleway website documentation (#10058) 2020-10-07 12:02:08 +02:00
Ricardo Rosales 809f38be3a [azure-chroot] Updating parameter exlude_from_latest to exclude_from_latest (#10034) 2020-10-07 11:08:33 +02:00
83 changed files with 1945 additions and 1230 deletions
+7
View File
@@ -2,6 +2,10 @@
### BUG FIXES:
* builder/azure-chroot: Fix typo in option `exlude_from_latest` to
`exclude_from_latest`. Old name will still be respected. [GH-10034]
* builder/openstack: Fix source image validation regression when using filters.
[GH-10065]
* core/hcl2: Packer HCL's "Coalesce" function now behaves same way as
Terraform's. [GH-10016]
* core/HCL: Hide sensitive variables from output. [GH-10031]
@@ -14,9 +18,12 @@
### IMPROVEMENTS:
* builder/google: Add service account impersonation. [GH-9968] [GH-10054]
* builder/oracle-oci: New option to specify image compartment separate from
build compartment. [GH-10040]
* builder/oracle-oci: New option to specify boot volume size. [GH-10017]
* builder/scaleway: Allow the user to use an image label (eg ubuntu_focal)
instead of a hardcoded UUID on the Scaleway builder. [GH-10061]
## 1.6.4 (September 30, 2020)
+41 -81
View File
@@ -12,6 +12,8 @@ import (
"github.com/hashicorp/packer/template/interpolate"
)
// The "AlicloudDiskDevice" object us used for the `ECSSystemDiskMapping` and
// `ECSImagesDiskMappings` options, and contains the following fields:
type AlicloudDiskDevice struct {
// The value of disk name is blank by default. [2,
// 128] English or Chinese characters, must begin with an
@@ -19,8 +21,7 @@ type AlicloudDiskDevice struct {
// ., _ 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:
// Category of the system disk. Optional values are:
// - cloud - general cloud disk
// - cloud_efficiency - efficiency cloud disk
// - cloud_ssd - cloud SSD
@@ -32,6 +33,8 @@ type AlicloudDiskDevice struct {
// 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.
// This field is only used in the ECSImagesDiskMappings option, not
// the ECSSystemDiskMapping option.
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
@@ -44,94 +47,51 @@ type AlicloudDiskDevice struct {
// 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
// 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.
// 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"`
}
// The "AlicloudDiskDevices" object is used to define disk mappings for your
// instance.
type AlicloudDiskDevices struct {
// 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}.
// Image disk mapping for the system disk.
// See the [disk device configuration](#disk-devices-configuration) section
// for more information on options.
// Usage example:
//
// ```json
// "builders": [{
// "type":"alicloud-ecs",
// "system_disk_mapping": {
// "disk_size": 50,
// "disk_name": "mydisk"
// },
// ...
// }
// ```
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.
// Add one or more data disks to the image.
// See the [disk device configuration](#disk-devices-configuration) section
// for more information on options.
// Usage example:
//
// ```json
// "builders": [{
// "type":"alicloud-ecs",
// "image_disk_mappings": [
// {
// "disk_snapshot_id": "someid",
// "disk_device": "dev/xvdb"
// }
// ],
// ...
// }
// ```
ECSImagesDiskMappings []AlicloudDiskDevice `mapstructure:"image_disk_mappings" required:"false"`
}
@@ -1,4 +1,4 @@
ERROR: -> DeploymentFailed : At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/arm-debug for usage details.
ERROR: -> BadRequest
ERROR: -> InvalidRequestFormat : Cannot parse the request.
ERROR: -> InvalidJson : Error converting value "playground" to type 'Microsoft.WindowsAzure.Networking.Nrp.Frontend.Contract.Csm.Public.IpAllocationMethod'. Path 'properties.publicIPAllocationMethod', line 1, position 130.
ERROR: -> DeploymentFailed : At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/arm-debug for usage details.
ERROR: -> BadRequest
ERROR: -> InvalidRequestFormat : Cannot parse the request.
ERROR: -> InvalidJson : Error converting value "playground" to type 'Microsoft.WindowsAzure.Networking.Nrp.Frontend.Contract.Csm.Public.IpAllocationMethod'. Path 'properties.publicIPAllocationMethod', line 1, position 130.
@@ -1 +1 @@
ERROR: -> ResourceNotFound : The Resource 'Microsoft.Compute/images/PackerUbuntuImage' under resource group 'packer-test00' was not found.
ERROR: -> ResourceNotFound : The Resource 'Microsoft.Compute/images/PackerUbuntuImage' under resource group 'packer-test00' was not found.
@@ -16,8 +16,9 @@ type SharedImageGalleryDestination struct {
ImageName string `mapstructure:"image_name" required:"true"`
ImageVersion string `mapstructure:"image_version" required:"true"`
TargetRegions []TargetRegion `mapstructure:"target_regions"`
ExcludeFromLatest bool `mapstructure:"exlude_from_latest"`
TargetRegions []TargetRegion `mapstructure:"target_regions"`
ExcludeFromLatest bool `mapstructure:"exclude_from_latest"`
ExcludeFromLatestTypo bool `mapstructure:"exlude_from_latest" undocumented:"true"`
}
// TargetRegion describes a region where the shared image should be replicated
@@ -61,5 +62,10 @@ func (sigd *SharedImageGalleryDestination) Validate(prefix string) (errs []error
warns = append(warns,
fmt.Sprintf("%s.target_regions is empty; image will only be available in the region of the gallery", prefix))
}
if sigd.ExcludeFromLatestTypo == true && sigd.ExcludeFromLatest == false {
warns = append(warns,
fmt.Sprintf("%s.exlude_from_latest is being deprecated, please use exclude_from_latest", prefix))
sigd.ExcludeFromLatest = sigd.ExcludeFromLatestTypo
}
return
}
@@ -9,12 +9,13 @@ import (
// FlatSharedImageGalleryDestination is an auto-generated flat version of SharedImageGalleryDestination.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatSharedImageGalleryDestination struct {
ResourceGroup *string `mapstructure:"resource_group" required:"true" cty:"resource_group" hcl:"resource_group"`
GalleryName *string `mapstructure:"gallery_name" required:"true" cty:"gallery_name" hcl:"gallery_name"`
ImageName *string `mapstructure:"image_name" required:"true" cty:"image_name" hcl:"image_name"`
ImageVersion *string `mapstructure:"image_version" required:"true" cty:"image_version" hcl:"image_version"`
TargetRegions []FlatTargetRegion `mapstructure:"target_regions" cty:"target_regions" hcl:"target_regions"`
ExcludeFromLatest *bool `mapstructure:"exlude_from_latest" cty:"exlude_from_latest" hcl:"exlude_from_latest"`
ResourceGroup *string `mapstructure:"resource_group" required:"true" cty:"resource_group" hcl:"resource_group"`
GalleryName *string `mapstructure:"gallery_name" required:"true" cty:"gallery_name" hcl:"gallery_name"`
ImageName *string `mapstructure:"image_name" required:"true" cty:"image_name" hcl:"image_name"`
ImageVersion *string `mapstructure:"image_version" required:"true" cty:"image_version" hcl:"image_version"`
TargetRegions []FlatTargetRegion `mapstructure:"target_regions" cty:"target_regions" hcl:"target_regions"`
ExcludeFromLatest *bool `mapstructure:"exclude_from_latest" cty:"exclude_from_latest" hcl:"exclude_from_latest"`
ExcludeFromLatestTypo *bool `mapstructure:"exlude_from_latest" undocumented:"true" cty:"exlude_from_latest" hcl:"exlude_from_latest"`
}
// FlatMapstructure returns a new FlatSharedImageGalleryDestination.
@@ -29,12 +30,13 @@ func (*SharedImageGalleryDestination) FlatMapstructure() interface{ HCL2Spec() m
// The decoded values from this spec will then be applied to a FlatSharedImageGalleryDestination.
func (*FlatSharedImageGalleryDestination) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{
"resource_group": &hcldec.AttrSpec{Name: "resource_group", Type: cty.String, Required: false},
"gallery_name": &hcldec.AttrSpec{Name: "gallery_name", Type: cty.String, Required: false},
"image_name": &hcldec.AttrSpec{Name: "image_name", Type: cty.String, Required: false},
"image_version": &hcldec.AttrSpec{Name: "image_version", Type: cty.String, Required: false},
"target_regions": &hcldec.BlockListSpec{TypeName: "target_regions", Nested: hcldec.ObjectSpec((*FlatTargetRegion)(nil).HCL2Spec())},
"exlude_from_latest": &hcldec.AttrSpec{Name: "exlude_from_latest", Type: cty.Bool, Required: false},
"resource_group": &hcldec.AttrSpec{Name: "resource_group", Type: cty.String, Required: false},
"gallery_name": &hcldec.AttrSpec{Name: "gallery_name", Type: cty.String, Required: false},
"image_name": &hcldec.AttrSpec{Name: "image_name", Type: cty.String, Required: false},
"image_version": &hcldec.AttrSpec{Name: "image_version", Type: cty.String, Required: false},
"target_regions": &hcldec.BlockListSpec{TypeName: "target_regions", Nested: hcldec.ObjectSpec((*FlatTargetRegion)(nil).HCL2Spec())},
"exclude_from_latest": &hcldec.AttrSpec{Name: "exclude_from_latest", Type: cty.Bool, Required: false},
"exlude_from_latest": &hcldec.AttrSpec{Name: "exlude_from_latest", Type: cty.Bool, Required: false},
}
return s
}
@@ -21,12 +21,13 @@ func TestSharedImageGalleryDestination_ResourceID(t *testing.T) {
func TestSharedImageGalleryDestination_Validate(t *testing.T) {
type fields struct {
ResourceGroup string
GalleryName string
ImageName string
ImageVersion string
TargetRegions []TargetRegion
ExcludeFromLatest bool
ResourceGroup string
GalleryName string
ImageName string
ImageVersion string
TargetRegions []TargetRegion
ExcludeFromLatest bool
ExcludeFromLatestTypo bool
}
tests := []struct {
name string
@@ -66,6 +67,29 @@ func TestSharedImageGalleryDestination_Validate(t *testing.T) {
},
wantWarns: []string{"sigdest.target_regions is empty; image will only be available in the region of the gallery"},
},
{
name: "warn if using exlude_from_latest",
fields: fields{
ResourceGroup: "ResourceGroup",
GalleryName: "GalleryName",
ImageName: "ImageName",
ImageVersion: "0.1.2",
TargetRegions: []TargetRegion{
TargetRegion{
Name: "region1",
ReplicaCount: 5,
StorageAccountType: "Standard_ZRS",
},
TargetRegion{
Name: "region2",
ReplicaCount: 3,
StorageAccountType: "Standard_LRS",
},
},
ExcludeFromLatestTypo: true,
},
wantWarns: []string{"sigdest.exlude_from_latest is being deprecated, please use exclude_from_latest"},
},
{
name: "version format",
wantErrs: []string{
@@ -105,12 +129,13 @@ func TestSharedImageGalleryDestination_Validate(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
sigd := &SharedImageGalleryDestination{
ResourceGroup: tt.fields.ResourceGroup,
GalleryName: tt.fields.GalleryName,
ImageName: tt.fields.ImageName,
ImageVersion: tt.fields.ImageVersion,
TargetRegions: tt.fields.TargetRegions,
ExcludeFromLatest: tt.fields.ExcludeFromLatest,
ResourceGroup: tt.fields.ResourceGroup,
GalleryName: tt.fields.GalleryName,
ImageName: tt.fields.ImageName,
ImageVersion: tt.fields.ImageVersion,
TargetRegions: tt.fields.TargetRegions,
ExcludeFromLatest: tt.fields.ExcludeFromLatest,
ExcludeFromLatestTypo: tt.fields.ExcludeFromLatestTypo,
}
gotErrs, gotWarns := sigd.Validate("sigdest")
+13 -6
View File
@@ -252,14 +252,21 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
}
}
hasOnlySourceImage := len(c.SourceImage) > 0 && len(c.SourceImageName) == 0 && len(c.ExternalSourceImageURL) == 0
hasOnlySourceImageName := len(c.SourceImageName) > 0 && len(c.SourceImage) == 0 && len(c.ExternalSourceImageURL) == 0
hasOnlyExternalSourceImageURL := len(c.ExternalSourceImageURL) > 0 && len(c.SourceImage) == 0 && len(c.SourceImageName) == 0
if c.SourceImage == "" && c.SourceImageName == "" && c.ExternalSourceImageURL == "" && c.SourceImageFilters.Filters.Empty() {
errs = append(errs, errors.New("Either a source_image, a source_image_name, an external_source_image_url or source_image_filter must be specified"))
} else if !(hasOnlySourceImage || hasOnlySourceImageName || hasOnlyExternalSourceImageURL) {
errs = append(errs, errors.New("Only a source_image, a source_image_name or an external_source_image_url can be specified, not multiple."))
} else {
// Make sure we've only set one image source option
thereCanBeOnlyOne := []bool{len(c.SourceImageName) > 0, len(c.SourceImage) > 0, len(c.ExternalSourceImageURL) > 0, !c.SourceImageFilters.Filters.Empty()}
numSet := 0
for _, val := range thereCanBeOnlyOne {
if val {
numSet += 1
}
}
if numSet > 1 {
errs = append(errs, errors.New("Only one of the options source_image, source_image_name, external_source_image_url, or source_image_filter can be specified, not multiple."))
}
}
// if external_source_image_format is not set use qcow2 as default
+24
View File
@@ -141,6 +141,7 @@ func TestRunConfigPrepare_ExternalSourceImageURL(t *testing.T) {
t.Fatalf("err: %s", err)
}
c = testRunConfig()
// test setting both ExternalSourceImageURL and SourceImageName causes an error
c.SourceImage = ""
c.SourceImageName = "abcd"
@@ -149,6 +150,7 @@ func TestRunConfigPrepare_ExternalSourceImageURL(t *testing.T) {
t.Fatalf("err: %s", err)
}
c = testRunConfig()
// test neither setting SourceImage, SourceImageName or ExternalSourceImageURL causes an error
c.SourceImage = ""
c.SourceImageName = ""
@@ -157,6 +159,7 @@ func TestRunConfigPrepare_ExternalSourceImageURL(t *testing.T) {
t.Fatalf("err: %s", err)
}
c = testRunConfig()
// test setting only ExternalSourceImageURL passes
c.SourceImage = ""
c.SourceImageName = ""
@@ -174,6 +177,27 @@ func TestRunConfigPrepare_ExternalSourceImageURL(t *testing.T) {
if matches, _ := regexp.MatchString(p, c.SourceImageName); !matches {
t.Fatalf("invalid format for SourceImageName: %s", c.SourceImageName)
}
c = testRunConfig()
// test setting a filter passes
c.SourceImage = ""
c.SourceImageName = ""
c.ExternalSourceImageURL = ""
c.SourceImageFilters = ImageFilter{
Filters: ImageFilterOptions{
Name: "Ubuntu 16.04",
Visibility: "public",
Owner: "1234567890",
Tags: []string{"prod", "ready"},
Properties: map[string]string{"os_distro": "ubuntu", "os_version": "16.04"},
},
MostRecent: true,
}
if err := c.Prepare(nil); len(err) != 0 {
t.Fatalf("Should not error if everything but filter is empty: %s", err)
}
}
// This test case confirms that only allowed fields will be set to values
+2
View File
@@ -192,6 +192,8 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
artifact.state["generated_data"] = state.Get("generated_data")
artifact.state["diskName"] = b.config.VMName
// placed in state in step_create_disk.go
diskpaths, ok := state.Get("qemu_disk_paths").([]string)
if ok {
artifact.state["diskPaths"] = diskpaths
+16 -8
View File
@@ -208,19 +208,27 @@ type Config struct {
// 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
// Allows complete control over the qemu command line (though not 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.
// beware of conflicting arguments causing failures of your run.
// For instance adding a "--drive" or "--device" override will mean that
// none of the default configuration Packer sets will be used. To see the
// defaults that Packer sets, look in your packer.log
// file (set PACKER_LOG=1 to get verbose logging) and search for the
// qemu-system-x86 command. The arguments are all printed for review, and
// you can use those arguments along with the template engines allowed
// by qemu-args to set up a working configuration that includes both the
// Packer defaults and your extra arguments.
//
// Another pitfall could be setting arguments like --no-acpi, which could
// break the ability to send power signal type commands
// (e.g., shutdown -P now) to the virtual machine, thus preventing proper
// shutdown.
//
// The following shows a sample usage:
//
+214 -173
View File
@@ -16,41 +16,45 @@ import (
// stepRun runs the virtual machine
type stepRun struct {
DiskImage bool
}
type qemuArgsTemplateData struct {
HTTPIP string
HTTPPort int
HTTPDir string
OutputDir string
Name string
SSHHostPort int
atLeastVersion2 bool
ui packer.Ui
}
func (s *stepRun) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config)
driver := state.Get("driver").(Driver)
ui := state.Get("ui").(packer.Ui)
s.ui = state.Get("ui").(packer.Ui)
// Run command is different depending whether we're booting from an
// installation CD or a pre-baked image
bootDrive := "once=d"
message := "Starting VM, booting from CD-ROM"
if s.DiskImage {
bootDrive = "c"
message = "Starting VM, booting disk image"
// Figure out version of qemu; store on step for later use
rawVersion, err := driver.Version()
if err != nil {
err := fmt.Errorf("Error determining qemu version: %s", err)
s.ui.Error(err.Error())
return multistep.ActionHalt
}
ui.Say(message)
qemuVersion, err := version.NewVersion(rawVersion)
if err != nil {
err := fmt.Errorf("Error parsing qemu version: %s", err)
s.ui.Error(err.Error())
return multistep.ActionHalt
}
v2 := version.Must(version.NewVersion("2.0"))
command, err := getCommandArgs(bootDrive, state)
s.atLeastVersion2 = qemuVersion.GreaterThanOrEqual(v2)
// Generate the qemu command
command, err := s.getCommandArgs(config, state)
if err != nil {
err := fmt.Errorf("Error processing QemuArgs: %s", err)
ui.Error(err.Error())
s.ui.Error(err.Error())
return multistep.ActionHalt
}
// run the qemu command
if err := driver.Qemu(command...); err != nil {
err := fmt.Errorf("Error launching VM: %s", err)
ui.Error(err.Error())
s.ui.Error(err.Error())
return multistep.ActionHalt
}
@@ -66,140 +70,187 @@ func (s *stepRun) Cleanup(state multistep.StateBag) {
}
}
func getCommandArgs(bootDrive string, state multistep.StateBag) ([]string, error) {
config := state.Get("config").(*Config)
isoPath := state.Get("iso_path").(string)
vncIP := config.VNCBindAddress
vncPort := state.Get("vnc_port").(int)
ui := state.Get("ui").(packer.Ui)
driver := state.Get("driver").(Driver)
vmName := config.VMName
imgPath := filepath.Join(config.OutputDir, vmName)
func (s *stepRun) getDefaultArgs(config *Config, state multistep.StateBag) map[string]interface{} {
defaultArgs := make(map[string]interface{})
var deviceArgs []string
var driveArgs []string
var commHostPort int
// Configure "boot" arguement
// Run command is different depending whether we're booting from an
// installation CD or a pre-baked image
bootDrive := "once=d"
message := "Starting VM, booting from CD-ROM"
if s.DiskImage {
bootDrive = "c"
message = "Starting VM, booting disk image"
}
s.ui.Say(message)
defaultArgs["-boot"] = bootDrive
// configure "-qmp" arguments
if config.QMPEnable {
defaultArgs["-qmp"] = fmt.Sprintf("unix:%s,server,nowait", config.QMPSocketPath)
}
// configure "-name" arguments
defaultArgs["-name"] = config.VMName
// Configure "-machine" arguments
if config.Accelerator == "none" {
defaultArgs["-machine"] = fmt.Sprintf("type=%s", config.MachineType)
s.ui.Message("WARNING: The VM will be started with no hardware acceleration.\n" +
"The installation may take considerably longer to finish.\n")
} else {
defaultArgs["-machine"] = fmt.Sprintf("type=%s,accel=%s",
config.MachineType, config.Accelerator)
}
// Configure "-netdev" arguments
defaultArgs["-netdev"] = fmt.Sprintf("bridge,id=user.0,br=%s", config.NetBridge)
if config.NetBridge == "" {
defaultArgs["-netdev"] = fmt.Sprintf("user,id=user.0")
if config.CommConfig.Comm.Type != "none" {
commHostPort := state.Get("commHostPort").(int)
defaultArgs["-netdev"] = fmt.Sprintf("user,id=user.0,hostfwd=tcp::%v-:%d", commHostPort, config.CommConfig.Comm.Port())
}
}
// Configure "-vnc" arguments
// vncPort is always set in stepConfigureVNC, so we don't need to
// defensively assert
vncPort := state.Get("vnc_port").(int)
vncIP := config.VNCBindAddress
vncPort = vncPort - config.VNCPortMin
vnc := fmt.Sprintf("%s:%d", vncIP, vncPort)
if config.VNCUsePassword {
vnc = fmt.Sprintf("%s:%d,password", vncIP, vncPort)
}
defaultArgs["-vnc"] = vnc
if config.QMPEnable {
defaultArgs["-qmp"] = fmt.Sprintf("unix:%s,server,nowait", config.QMPSocketPath)
// Track the connection for the user
vncPass, _ := state.Get("vnc_password").(string)
message = getVncConnectionMessage(config.Headless, vnc, vncPass)
if message != "" {
s.ui.Message(message)
}
defaultArgs["-name"] = vmName
defaultArgs["-machine"] = fmt.Sprintf("type=%s", config.MachineType)
// Configure "-m" memory argument
defaultArgs["-m"] = fmt.Sprintf("%dM", config.MemorySize)
if config.NetBridge == "" {
if config.CommConfig.Comm.Type != "none" {
commHostPort = state.Get("commHostPort").(int)
defaultArgs["-netdev"] = fmt.Sprintf("user,id=user.0,hostfwd=tcp::%v-:%d", commHostPort, config.CommConfig.Comm.Port())
} else {
defaultArgs["-netdev"] = fmt.Sprintf("user,id=user.0")
}
// Configure "-smp" processor hardware arguments
if config.CpuCount > 1 {
defaultArgs["-smp"] = fmt.Sprintf("cpus=%d,sockets=%d", config.CpuCount, config.CpuCount)
}
// Configure "-fda" floppy disk attachment
if floppyPathRaw, ok := state.GetOk("floppy_path"); ok {
defaultArgs["-fda"] = floppyPathRaw.(string)
} else {
defaultArgs["-netdev"] = fmt.Sprintf("bridge,id=user.0,br=%s", config.NetBridge)
log.Println("Qemu Builder has no floppy files, not attaching a floppy.")
}
rawVersion, err := driver.Version()
if err != nil {
return nil, err
}
qemuVersion, err := version.NewVersion(rawVersion)
if err != nil {
return nil, err
}
v2 := version.Must(version.NewVersion("2.0"))
if qemuVersion.GreaterThanOrEqual(v2) {
if config.DiskInterface == "virtio-scsi" {
if config.DiskImage {
deviceArgs = append(deviceArgs, "virtio-scsi-pci,id=scsi0", "scsi-hd,bus=scsi0.0,drive=drive0")
driveArgumentString := fmt.Sprintf("if=none,file=%s,id=drive0,cache=%s,discard=%s,format=%s", imgPath, config.DiskCache, config.DiskDiscard, config.Format)
if config.DetectZeroes != "off" {
driveArgumentString = fmt.Sprintf("%s,detect-zeroes=%s", driveArgumentString, config.DetectZeroes)
}
driveArgs = append(driveArgs, driveArgumentString)
} else {
deviceArgs = append(deviceArgs, "virtio-scsi-pci,id=scsi0")
diskFullPaths := state.Get("qemu_disk_paths").([]string)
for i, diskFullPath := range diskFullPaths {
deviceArgs = append(deviceArgs, fmt.Sprintf("scsi-hd,bus=scsi0.0,drive=drive%d", i))
driveArgumentString := fmt.Sprintf("if=none,file=%s,id=drive%d,cache=%s,discard=%s,format=%s", diskFullPath, i, config.DiskCache, config.DiskDiscard, config.Format)
if config.DetectZeroes != "off" {
driveArgumentString = fmt.Sprintf("%s,detect-zeroes=%s", driveArgumentString, config.DetectZeroes)
}
driveArgs = append(driveArgs, driveArgumentString)
}
}
} else {
if config.DiskImage {
driveArgumentString := fmt.Sprintf("file=%s,if=%s,cache=%s,discard=%s,format=%s", imgPath, config.DiskInterface, config.DiskCache, config.DiskDiscard, config.Format)
if config.DetectZeroes != "off" {
driveArgumentString = fmt.Sprintf("%s,detect-zeroes=%s", driveArgumentString, config.DetectZeroes)
}
driveArgs = append(driveArgs, driveArgumentString)
} else {
diskFullPaths := state.Get("qemu_disk_paths").([]string)
for _, diskFullPath := range diskFullPaths {
driveArgumentString := fmt.Sprintf("file=%s,if=%s,cache=%s,discard=%s,format=%s", diskFullPath, config.DiskInterface, config.DiskCache, config.DiskDiscard, config.Format)
if config.DetectZeroes != "off" {
driveArgumentString = fmt.Sprintf("%s,detect-zeroes=%s", driveArgumentString, config.DetectZeroes)
}
driveArgs = append(driveArgs, driveArgumentString)
}
}
}
} else {
driveArgs = append(driveArgs, fmt.Sprintf("file=%s,if=%s,cache=%s,format=%s", imgPath, config.DiskInterface, config.DiskCache, config.Format))
}
deviceArgs = append(deviceArgs, fmt.Sprintf("%s,netdev=user.0", config.NetDevice))
if config.Headless == true {
vncPortRaw, vncPortOk := state.GetOk("vnc_port")
vncPass := state.Get("vnc_password")
if vncPortOk && vncPass != nil && len(vncPass.(string)) > 0 {
vncPort := vncPortRaw.(int)
ui.Message(fmt.Sprintf(
"The VM will be run headless, without a GUI. If you want to\n"+
"view the screen of the VM, connect via VNC to vnc://%s:%d\n"+
"with the password: %s", vncIP, vncPort, vncPass))
} else if vncPortOk {
vncPort := vncPortRaw.(int)
ui.Message(fmt.Sprintf(
"The VM will be run headless, without a GUI. If you want to\n"+
"view the screen of the VM, connect via VNC without a password to\n"+
"vnc://%s:%d", vncIP, vncPort))
} else {
ui.Message("The VM will be run headless, without a GUI, as configured.\n" +
"If the run isn't succeeding as you expect, please enable the GUI\n" +
"to inspect the progress of the build.")
}
} else {
if qemuVersion.GreaterThanOrEqual(v2) {
if len(config.Display) > 0 {
if config.Display != "none" {
defaultArgs["-display"] = config.Display
}
// Configure GUI display
if !config.Headless {
if s.atLeastVersion2 {
// FIXME: "none" is a valid display option in qemu but we have
// departed from the qemu usage here to instaed mean "let qemu
// set a reasonable default". We need to deprecate this behavior
// and let users just set "UseDefaultDisplay" if they want to let
// qemu do its thing.
if len(config.Display) > 0 && config.Display != "none" {
defaultArgs["-display"] = config.Display
} else if !config.UseDefaultDisplay {
defaultArgs["-display"] = "gtk"
}
} else {
ui.Message("WARNING: The version of qemu on your host doesn't support display mode.\n" +
s.ui.Message("WARNING: The version of qemu on your host doesn't support display mode.\n" +
"The display parameter will be ignored.")
}
}
deviceArgs, driveArgs := s.getDeviceAndDriveArgs(config, state)
defaultArgs["-device"] = deviceArgs
defaultArgs["-drive"] = driveArgs
return defaultArgs
}
func getVncConnectionMessage(headless bool, vnc string, vncPass string) string {
// Configure GUI display
if headless {
if vnc == "" {
return "The VM will be run headless, without a GUI, as configured.\n" +
"If the run isn't succeeding as you expect, please enable the GUI\n" +
"to inspect the progress of the build."
}
if vncPass != "" {
return fmt.Sprintf(
"The VM will be run headless, without a GUI. If you want to\n"+
"view the screen of the VM, connect via VNC to vnc://%s\n"+
"with the password: %s", vnc, vncPass)
}
return fmt.Sprintf(
"The VM will be run headless, without a GUI. If you want to\n"+
"view the screen of the VM, connect via VNC without a password to\n"+
"vnc://%s", vnc)
}
return ""
}
func (s *stepRun) getDeviceAndDriveArgs(config *Config, state multistep.StateBag) ([]string, []string) {
var deviceArgs []string
var driveArgs []string
vmName := config.VMName
imgPath := filepath.Join(config.OutputDir, vmName)
// Configure virtual hard drives
if s.atLeastVersion2 {
// We have different things to attach based on whether we are booting
// from an iso or a boot image.
drivesToAttach := []string{}
if config.DiskImage {
drivesToAttach = append(drivesToAttach, imgPath)
}
diskFullPaths := state.Get("qemu_disk_paths").([]string)
drivesToAttach = append(drivesToAttach, diskFullPaths...)
for i, drivePath := range drivesToAttach {
driveArgumentString := fmt.Sprintf("file=%s,if=%s,cache=%s,discard=%s,format=%s", drivePath, config.DiskInterface, config.DiskCache, config.DiskDiscard, config.Format)
if config.DiskInterface == "virtio-scsi" {
// TODO: Megan: Remove this conditional. This, and the code
// under the TODO below, reproduce the old behavior. While it
// may be broken, the goal of this commit is to refactor in a way
// that creates a result that is testably the same as the old
// code. A pr will follow fixing this broken behavior.
if i == 0 {
deviceArgs = append(deviceArgs, fmt.Sprintf("virtio-scsi-pci,id=scsi%d", i))
}
// TODO: Megan: When you remove above conditional,
// set deviceArgs = append(deviceArgs, fmt.Sprintf("scsi-hd,bus=scsi%d.0,drive=drive%d", i, i))
deviceArgs = append(deviceArgs, fmt.Sprintf("scsi-hd,bus=scsi0.0,drive=drive%d", i))
driveArgumentString = fmt.Sprintf("if=none,file=%s,id=drive%d,cache=%s,discard=%s,format=%s", drivePath, i, config.DiskCache, config.DiskDiscard, config.Format)
}
if config.DetectZeroes != "off" {
driveArgumentString = fmt.Sprintf("%s,detect-zeroes=%s", driveArgumentString, config.DetectZeroes)
}
driveArgs = append(driveArgs, driveArgumentString)
}
} else {
driveArgs = append(driveArgs, fmt.Sprintf("file=%s,if=%s,cache=%s,format=%s", imgPath, config.DiskInterface, config.DiskCache, config.Format))
}
deviceArgs = append(deviceArgs, fmt.Sprintf("%s,netdev=user.0", config.NetDevice))
// Configure virtual CDs
cdPaths := []string{}
// Add the installation CD to the run command
if !config.DiskImage {
isoPath := state.Get("iso_path").(string)
cdPaths = append(cdPaths, isoPath)
}
// Add our custom CD created from cd_files, if it exists
@@ -220,64 +271,48 @@ func getCommandArgs(bootDrive string, state multistep.StateBag) ([]string, error
}
}
defaultArgs["-device"] = deviceArgs
defaultArgs["-drive"] = driveArgs
return deviceArgs, driveArgs
}
defaultArgs["-boot"] = bootDrive
defaultArgs["-m"] = fmt.Sprintf("%dM", config.MemorySize)
if config.CpuCount > 1 {
defaultArgs["-smp"] = fmt.Sprintf("cpus=%d,sockets=%d", config.CpuCount, config.CpuCount)
}
defaultArgs["-vnc"] = vnc
// Append the accelerator to the machine type if it is specified
if config.Accelerator != "none" {
defaultArgs["-machine"] = fmt.Sprintf("%s,accel=%s", defaultArgs["-machine"], config.Accelerator)
} else {
ui.Message("WARNING: The VM will be started with no hardware acceleration.\n" +
"The installation may take considerably longer to finish.\n")
}
// Determine if we have a floppy disk to attach
if floppyPathRaw, ok := state.GetOk("floppy_path"); ok {
defaultArgs["-fda"] = floppyPathRaw.(string)
} else {
log.Println("Qemu Builder has no floppy files, not attaching a floppy.")
}
func (s *stepRun) applyUserOverrides(defaultArgs map[string]interface{}, config *Config, state multistep.StateBag) ([]string, error) {
// Done setting up defaults; time to process user args and defaults together
// and generate output args
inArgs := make(map[string][]string)
if len(config.QemuArgs) > 0 {
ui.Say("Overriding default Qemu arguments with QemuArgs...")
s.ui.Say("Overriding default Qemu arguments with qemuargs template option...")
commHostPort := state.Get("commHostPort").(int)
httpIp := state.Get("http_ip").(string)
httpPort := state.Get("http_port").(int)
ictx := config.ctx
if config.CommConfig.Comm.Type != "none" {
ictx.Data = qemuArgsTemplateData{
httpIp,
httpPort,
config.HTTPDir,
config.OutputDir,
config.VMName,
commHostPort,
}
} else {
ictx.Data = qemuArgsTemplateData{
HTTPIP: httpIp,
HTTPPort: httpPort,
HTTPDir: config.HTTPDir,
OutputDir: config.OutputDir,
Name: config.VMName,
}
type qemuArgsTemplateData struct {
HTTPIP string
HTTPPort int
HTTPDir string
OutputDir string
Name string
SSHHostPort int
}
ictx := config.ctx
ictx.Data = qemuArgsTemplateData{
HTTPIP: httpIp,
HTTPPort: httpPort,
HTTPDir: config.HTTPDir,
OutputDir: config.OutputDir,
Name: config.VMName,
SSHHostPort: commHostPort,
}
// Interpolate each string in qemuargs
newQemuArgs, err := processArgs(config.QemuArgs, &ictx)
if err != nil {
return nil, err
}
// because qemu supports multiple appearances of the same
// switch, just different values, each key in the args hash
// will have an array of string values
// Qemu supports multiple appearances of the same switch. This means
// each key in the args hash will have an array of string values
for _, qemuArgs := range newQemuArgs {
key := qemuArgs[0]
val := strings.Join(qemuArgs[1:], "")
@@ -326,6 +361,12 @@ func getCommandArgs(bootDrive string, state multistep.StateBag) ([]string, error
return outArgs, nil
}
func (s *stepRun) getCommandArgs(config *Config, state multistep.StateBag) ([]string, error) {
defaultArgs := s.getDefaultArgs(config, state)
return s.applyUserOverrides(defaultArgs, config, state)
}
func processArgs(args [][]string, ctx *interpolate.Context) ([][]string, error) {
var err error
+632 -73
View File
@@ -4,6 +4,8 @@ import (
"fmt"
"testing"
"github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/stretchr/testify/assert"
@@ -11,8 +13,6 @@ import (
func runTestState(t *testing.T, config *Config) multistep.StateBag {
state := new(multistep.BasicStateBag)
state.Put("ui", packer.TestUi(t))
state.Put("config", config)
d := new(DriverMock)
@@ -31,86 +31,396 @@ func runTestState(t *testing.T, config *Config) multistep.StateBag {
return state
}
func Test_getCommandArgs(t *testing.T) {
state := runTestState(t, &Config{})
args, err := getCommandArgs("", state)
if err != nil {
t.Fatalf("should not have an error getting args. Error: %s", err)
func Test_UserOverrides(t *testing.T) {
type testCase struct {
Config *Config
Expected []string
Reason string
}
testcases := []testCase{
{
&Config{
HTTPConfig: common.HTTPConfig{
HTTPDir: "http/directory",
},
OutputDir: "output/directory",
VMName: "myvm",
QemuArgs: [][]string{
{"-randomflag1", "{{.HTTPIP}}-{{.HTTPPort}}-{{.HTTPDir}}"},
{"-randomflag2", "{{.OutputDir}}-{{.Name}}"},
},
},
[]string{
"-display", "gtk",
"-drive", "file=/path/to/test.iso,index=0,media=cdrom",
"-randomflag1", "127.0.0.1-1234-http/directory",
"-randomflag2", "output/directory-myvm",
"-device", ",netdev=user.0",
},
"Test that interpolation overrides work.",
},
{
&Config{
VMName: "myvm",
QemuArgs: [][]string{{"-display", "partydisplay"}},
},
[]string{
"-display", "partydisplay",
"-drive", "file=/path/to/test.iso,index=0,media=cdrom",
"-device", ",netdev=user.0",
},
"User input overrides default, rest is populated as normal",
},
{
&Config{
VMName: "myvm",
NetDevice: "mynetdevice",
QemuArgs: [][]string{{"-device", "somerandomdevice"}},
},
[]string{
"-display", "gtk",
"-device", "somerandomdevice",
"-device", "mynetdevice,netdev=user.0",
"-drive", "file=/path/to/test.iso,index=0,media=cdrom",
},
"Net device gets added",
},
}
expected := []string{
"-display", "gtk",
"-m", "0M",
"-boot", "",
"-fda", "fake_floppy_path",
"-name", "",
"-netdev", "user,id=user.0,hostfwd=tcp::5000-:0",
"-vnc", ":5905",
"-machine", "type=,accel=",
"-device", ",netdev=user.0",
"-drive", "file=/path/to/test.iso,index=0,media=cdrom",
for _, tc := range testcases {
state := runTestState(t, tc.Config)
step := &stepRun{
atLeastVersion2: true,
ui: packer.TestUi(t),
}
args, err := step.getCommandArgs(tc.Config, state)
if err != nil {
t.Fatalf("should not have an error getting args. Error: %s", err)
}
expected := append([]string{
"-m", "0M",
"-boot", "once=d",
"-fda", "fake_floppy_path",
"-name", "myvm",
"-netdev", "user,id=user.0,hostfwd=tcp::5000-:0",
"-vnc", ":5905",
"-machine", "type=,accel="},
tc.Expected...)
assert.ElementsMatch(t, args, expected,
fmt.Sprintf("%s, \nRecieved: %#v", tc.Reason, args))
}
assert.ElementsMatch(t, args, expected, "unexpected generated args")
}
func Test_CDFilesPath(t *testing.T) {
// cd_path is set and DiskImage is false
state := runTestState(t, &Config{})
state.Put("cd_path", "fake_cd_path.iso")
args, err := getCommandArgs("", state)
if err != nil {
t.Fatalf("should not have an error getting args. Error: %s", err)
func Test_DriveAndDeviceArgs(t *testing.T) {
type testCase struct {
Config *Config
ExtraState map[string]interface{}
Step *stepRun
Expected []string
Reason string
}
expected := []string{
"-display", "gtk",
"-m", "0M",
"-boot", "",
"-fda", "fake_floppy_path",
"-name", "",
"-netdev", "user,id=user.0,hostfwd=tcp::5000-:0",
"-vnc", ":5905",
"-machine", "type=,accel=",
"-device", ",netdev=user.0",
"-drive", "file=/path/to/test.iso,index=0,media=cdrom",
"-drive", "file=fake_cd_path.iso,index=1,media=cdrom",
testcases := []testCase{
{
&Config{},
map[string]interface{}{},
&stepRun{
atLeastVersion2: true,
ui: packer.TestUi(t),
},
[]string{
"-display", "gtk",
"-boot", "once=d",
"-drive", "file=/path/to/test.iso,index=0,media=cdrom",
},
"Boot value should default to once=d when diskImage isn't set",
},
{
&Config{
DiskImage: true,
DiskInterface: "virtio-scsi",
OutputDir: "path_to_output",
DiskCache: "writeback",
Format: "qcow2",
DetectZeroes: "off",
},
map[string]interface{}{
"cd_path": "fake_cd_path.iso",
},
&stepRun{
DiskImage: true,
atLeastVersion2: true,
ui: packer.TestUi(t),
},
[]string{
"-display", "gtk",
"-boot", "c",
"-device", "virtio-scsi-pci,id=scsi0",
"-device", "scsi-hd,bus=scsi0.0,drive=drive0",
"-drive", "if=none,file=path_to_output,id=drive0,cache=writeback,discard=,format=qcow2",
"-drive", "file=fake_cd_path.iso,index=0,media=cdrom",
},
"virtio-scsi interface, DiskImage true, extra cdrom, detectZeroes off",
},
{
&Config{
DiskImage: true,
DiskInterface: "virtio-scsi",
OutputDir: "path_to_output",
DiskCache: "writeback",
Format: "qcow2",
DetectZeroes: "on",
},
map[string]interface{}{
"cd_path": "fake_cd_path.iso",
},
&stepRun{
DiskImage: true,
atLeastVersion2: true,
ui: packer.TestUi(t),
},
[]string{
"-display", "gtk",
"-boot", "c",
"-device", "virtio-scsi-pci,id=scsi0",
"-device", "scsi-hd,bus=scsi0.0,drive=drive0",
"-drive", "if=none,file=path_to_output,id=drive0,cache=writeback,discard=,format=qcow2,detect-zeroes=on",
"-drive", "file=fake_cd_path.iso,index=0,media=cdrom",
},
"virtio-scsi interface, DiskImage true, extra cdrom, detectZeroes on",
},
{
&Config{
DiskInterface: "virtio-scsi",
OutputDir: "path_to_output",
DiskCache: "writeback",
Format: "qcow2",
DetectZeroes: "off",
},
map[string]interface{}{
"cd_path": "fake_cd_path.iso",
// when disk image is false, we will always have at least one
// disk path: the one we create to be the main disk.
"qemu_disk_paths": []string{"qemupath1", "qemupath2"},
},
&stepRun{
atLeastVersion2: true,
ui: packer.TestUi(t),
},
[]string{
"-display", "gtk",
"-boot", "once=d",
"-device", "virtio-scsi-pci,id=scsi0",
"-device", "scsi-hd,bus=scsi0.0,drive=drive0",
"-device", "scsi-hd,bus=scsi0.0,drive=drive1",
"-drive", "if=none,file=qemupath1,id=drive0,cache=writeback,discard=,format=qcow2",
"-drive", "if=none,file=qemupath2,id=drive1,cache=writeback,discard=,format=qcow2",
"-drive", "file=/path/to/test.iso,index=0,media=cdrom",
"-drive", "file=fake_cd_path.iso,index=1,media=cdrom",
},
"virtio-scsi interface, bootable iso, cdrom",
},
{
&Config{
DiskInterface: "virtio-scsi",
OutputDir: "path_to_output",
DiskCache: "writeback",
Format: "qcow2",
DetectZeroes: "on",
},
map[string]interface{}{
"cd_path": "fake_cd_path.iso",
// when disk image is false, we will always have at least one
// disk path: the one we create to be the main disk.
"qemu_disk_paths": []string{"qemupath1", "qemupath2"},
},
&stepRun{
atLeastVersion2: true,
ui: packer.TestUi(t),
},
[]string{
"-display", "gtk",
"-boot", "once=d",
"-device", "virtio-scsi-pci,id=scsi0",
"-device", "scsi-hd,bus=scsi0.0,drive=drive0",
"-device", "scsi-hd,bus=scsi0.0,drive=drive1",
"-drive", "if=none,file=qemupath1,id=drive0,cache=writeback,discard=,format=qcow2,detect-zeroes=on",
"-drive", "if=none,file=qemupath2,id=drive1,cache=writeback,discard=,format=qcow2,detect-zeroes=on",
"-drive", "file=/path/to/test.iso,index=0,media=cdrom",
"-drive", "file=fake_cd_path.iso,index=1,media=cdrom",
},
"virtio-scsi interface, DiskImage false, extra cdrom, detect zeroes on",
},
{
&Config{
DiskInterface: "virtio-scsi",
OutputDir: "path_to_output",
DiskCache: "writeback",
Format: "qcow2",
},
map[string]interface{}{
// when disk image is false, we will always have at least one
// disk path: the one we create to be the main disk.
"qemu_disk_paths": []string{"output/dir/path/mydisk.qcow2"},
},
&stepRun{
atLeastVersion2: true,
ui: packer.TestUi(t),
},
[]string{
"-display", "gtk",
"-boot", "once=d",
"-device", "virtio-scsi-pci,id=scsi0",
"-device", "scsi-hd,bus=scsi0.0,drive=drive0",
"-drive", "if=none,file=output/dir/path/mydisk.qcow2,id=drive0,cache=writeback,discard=,format=qcow2,detect-zeroes=",
"-drive", "file=/path/to/test.iso,index=0,media=cdrom",
},
"virtio-scsi interface, DiskImage false, no extra disks or cds",
},
{
&Config{},
map[string]interface{}{
"cd_path": "fake_cd_path.iso",
"qemu_disk_paths": []string{"output/dir/path/mydisk.qcow2"},
},
&stepRun{
atLeastVersion2: true,
ui: packer.TestUi(t),
},
[]string{
"-display", "gtk",
"-boot", "once=d",
"-drive", "file=output/dir/path/mydisk.qcow2,if=,cache=,discard=,format=,detect-zeroes=",
"-drive", "file=/path/to/test.iso,index=0,media=cdrom",
"-drive", "file=fake_cd_path.iso,index=1,media=cdrom",
},
"cd_path is set and DiskImage is false",
},
{
&Config{},
map[string]interface{}{
// when disk image is false, we will always have at least one
// disk path: the one we create to be the main disk.
"qemu_disk_paths": []string{"output/dir/path/mydisk.qcow2"},
},
&stepRun{
atLeastVersion2: true,
ui: packer.TestUi(t),
},
[]string{
"-display", "gtk",
"-boot", "once=d",
"-drive", "file=output/dir/path/mydisk.qcow2,if=,cache=,discard=,format=,detect-zeroes=",
"-drive", "file=/path/to/test.iso,index=0,media=cdrom",
},
"empty config",
},
{
&Config{
OutputDir: "path_to_output",
DiskInterface: "virtio",
DiskCache: "writeback",
Format: "qcow2",
},
map[string]interface{}{
// when disk image is false, we will always have at least one
// disk path: the one we create to be the main disk.
"qemu_disk_paths": []string{"output/dir/path/mydisk.qcow2"},
},
&stepRun{
atLeastVersion2: false,
ui: packer.TestUi(t),
},
[]string{
"-boot", "once=d",
"-drive", "file=path_to_output,if=virtio,cache=writeback,format=qcow2",
"-drive", "file=/path/to/test.iso,index=0,media=cdrom",
},
"version less than 2",
},
{
&Config{
OutputDir: "path_to_output",
DiskInterface: "virtio",
DiskCache: "writeback",
Format: "qcow2",
},
map[string]interface{}{
"cd_path": "fake_cd_path.iso",
"qemu_disk_paths": []string{"qemupath1", "qemupath2"},
},
&stepRun{
atLeastVersion2: true,
ui: packer.TestUi(t),
},
[]string{
"-display", "gtk",
"-boot", "once=d",
"-drive", "file=qemupath1,if=virtio,cache=writeback,discard=,format=qcow2,detect-zeroes=",
"-drive", "file=qemupath2,if=virtio,cache=writeback,discard=,format=qcow2,detect-zeroes=",
"-drive", "file=fake_cd_path.iso,index=1,media=cdrom",
"-drive", "file=/path/to/test.iso,index=0,media=cdrom",
},
"virtio interface with extra disks",
},
{
&Config{
DiskImage: true,
OutputDir: "path_to_output",
DiskInterface: "virtio",
DiskCache: "writeback",
Format: "qcow2",
},
map[string]interface{}{
"cd_path": "fake_cd_path.iso",
},
&stepRun{
DiskImage: true,
atLeastVersion2: true,
ui: packer.TestUi(t),
},
[]string{
"-display", "gtk",
"-boot", "c",
"-drive", "file=path_to_output,if=virtio,cache=writeback,discard=,format=qcow2,detect-zeroes=",
"-drive", "file=fake_cd_path.iso,index=0,media=cdrom",
},
"virtio interface with disk image",
},
}
for _, tc := range testcases {
state := runTestState(t, &Config{})
for k, v := range tc.ExtraState {
state.Put(k, v)
}
assert.ElementsMatch(t, args, expected, fmt.Sprintf("unexpected generated args: %#v", args))
args, err := tc.Step.getCommandArgs(tc.Config, state)
if err != nil {
t.Fatalf("should not have an error getting args. Error: %s", err)
}
// cd_path is set and DiskImage is true
config := &Config{
DiskImage: true,
DiskInterface: "virtio-scsi",
expected := append([]string{
"-m", "0M",
"-fda", "fake_floppy_path",
"-name", "",
"-netdev", "user,id=user.0,hostfwd=tcp::5000-:0",
"-vnc", ":5905",
"-machine", "type=,accel=",
"-device", ",netdev=user.0"},
tc.Expected...)
assert.ElementsMatch(t, args, expected,
fmt.Sprintf("%s, \nRecieved: %#v", tc.Reason, args))
}
state = runTestState(t, config)
state.Put("cd_path", "fake_cd_path.iso")
args, err = getCommandArgs("c", state)
if err != nil {
t.Fatalf("should not have an error getting args. Error: %s", err)
}
expected = []string{
"-display", "gtk",
"-m", "0M",
"-boot", "c",
"-fda", "fake_floppy_path",
"-name", "",
"-netdev", "user,id=user.0,hostfwd=tcp::5000-:0",
"-vnc", ":5905",
"-machine", "type=,accel=",
"-device", ",netdev=user.0",
"-device", "virtio-scsi-pci,id=scsi0",
"-device", "scsi-hd,bus=scsi0.0,drive=drive0",
"-drive", "if=none,file=,id=drive0,cache=,discard=,format=,detect-zeroes=",
"-drive", "file=fake_cd_path.iso,index=0,media=cdrom",
}
assert.ElementsMatch(t, args, expected, fmt.Sprintf("unexpected generated args: %#v", args))
}
func Test_OptionalConfigOptionsGetSet(t *testing.T) {
@@ -124,8 +434,11 @@ func Test_OptionalConfigOptionsGetSet(t *testing.T) {
}
state := runTestState(t, c)
args, err := getCommandArgs("once=d", state)
step := &stepRun{
atLeastVersion2: true,
ui: packer.TestUi(t),
}
args, err := step.getCommandArgs(c, state)
if err != nil {
t.Fatalf("should not have an error getting args. Error: %s", err)
}
@@ -144,5 +457,251 @@ func Test_OptionalConfigOptionsGetSet(t *testing.T) {
"-qmp", "unix:qmp_path,server,nowait",
}
assert.ElementsMatch(t, args, expected, "password flag should be set, and d drive should be set.")
assert.ElementsMatch(t, args, expected, "password flag should be set, and d drive should be set: %s", args)
}
// Tests for presence of Packer-generated arguments. Doesn't test that
// arguments which shouldn't be there are absent.
func Test_Defaults(t *testing.T) {
type testCase struct {
Config *Config
ExtraState map[string]interface{}
Step *stepRun
Expected []string
Reason string
}
testcases := []testCase{
{
&Config{},
map[string]interface{}{},
&stepRun{ui: packer.TestUi(t)},
[]string{"-boot", "once=d"},
"Boot value should default to once=d",
},
{
&Config{},
map[string]interface{}{},
&stepRun{
DiskImage: true,
ui: packer.TestUi(t),
},
[]string{"-boot", "c"},
"Boot value should be set to c when DiskImage is set on step",
},
{
&Config{
QMPEnable: true,
QMPSocketPath: "/path/to/socket",
},
map[string]interface{}{},
&stepRun{ui: packer.TestUi(t)},
[]string{"-qmp", "unix:/path/to/socket,server,nowait"},
"Args should contain -qmp when qmp_enable is set",
},
{
&Config{
QMPEnable: true,
},
map[string]interface{}{},
&stepRun{ui: packer.TestUi(t)},
[]string{"-qmp", "unix:,server,nowait"},
"Args contain -qmp even when socket path isn't set, if qmp enabled",
},
{
&Config{
VMName: "partyname",
},
map[string]interface{}{},
&stepRun{ui: packer.TestUi(t)},
[]string{"-name", "partyname"},
"Name is set from config",
},
{
&Config{},
map[string]interface{}{},
&stepRun{ui: packer.TestUi(t)},
[]string{"-name", ""},
"Name is set from config, even when name is blank (which won't " +
"happen for real thanks to defaulting in build prepare)",
},
{
&Config{
Accelerator: "none",
MachineType: "fancymachine",
},
map[string]interface{}{},
&stepRun{ui: packer.TestUi(t)},
[]string{"-machine", "type=fancymachine"},
"Don't add accelerator tag when no accelerator is set.",
},
{
&Config{
Accelerator: "kvm",
MachineType: "fancymachine",
},
map[string]interface{}{},
&stepRun{ui: packer.TestUi(t)},
[]string{"-machine", "type=fancymachine,accel=kvm"},
"Add accelerator tag when accelerator is set.",
},
{
&Config{
NetBridge: "fakebridge",
},
map[string]interface{}{},
&stepRun{ui: packer.TestUi(t)},
[]string{"-netdev", "bridge,id=user.0,br=fakebridge"},
"Add netbridge tag when netbridge is set.",
},
{
&Config{
CommConfig: CommConfig{
Comm: communicator.Config{
Type: "none",
},
},
},
map[string]interface{}{},
&stepRun{ui: packer.TestUi(t)},
[]string{"-netdev", "user,id=user.0"},
"No host forwarding when no net bridge and no communicator",
},
{
&Config{
CommConfig: CommConfig{
Comm: communicator.Config{
Type: "ssh",
SSH: communicator.SSH{
SSHPort: 4567,
},
},
},
},
map[string]interface{}{
"commHostPort": 1111,
},
&stepRun{ui: packer.TestUi(t)},
[]string{"-netdev", "user,id=user.0,hostfwd=tcp::1111-:4567"},
"Host forwarding when a communicator is configured",
},
{
&Config{
VNCBindAddress: "1.1.1.1",
},
map[string]interface{}{
"vnc_port": 5959,
},
&stepRun{ui: packer.TestUi(t)},
[]string{"-vnc", "1.1.1.1:5959"},
"no VNC password should be set",
},
{
&Config{
VNCBindAddress: "1.1.1.1",
VNCUsePassword: true,
},
map[string]interface{}{
"vnc_port": 5959,
},
&stepRun{ui: packer.TestUi(t)},
[]string{"-vnc", "1.1.1.1:5959,password"},
"VNC password should be set",
},
{
&Config{
MemorySize: 2345,
},
map[string]interface{}{},
&stepRun{ui: packer.TestUi(t)},
[]string{"-m", "2345M"},
"Memory is set, with unit M",
},
{
&Config{
CpuCount: 2,
},
map[string]interface{}{},
&stepRun{ui: packer.TestUi(t)},
[]string{"-smp", "cpus=2,sockets=2"},
"both cpus and sockets are set to config's CpuCount",
},
{
&Config{
CpuCount: 2,
},
map[string]interface{}{},
&stepRun{ui: packer.TestUi(t)},
[]string{"-smp", "cpus=2,sockets=2"},
"both cpus and sockets are set to config's CpuCount",
},
{
&Config{
CpuCount: 2,
},
map[string]interface{}{
"floppy_path": "/path/to/floppy",
},
&stepRun{ui: packer.TestUi(t)},
[]string{"-fda", "/path/to/floppy"},
"floppy path should be set under fda flag, when it exists",
},
{
&Config{
Headless: false,
Display: "fakedisplay",
UseDefaultDisplay: false,
},
map[string]interface{}{},
&stepRun{
atLeastVersion2: true,
ui: packer.TestUi(t),
},
[]string{"-display", "fakedisplay"},
"Display option should value config display",
},
{
&Config{
Headless: false,
},
map[string]interface{}{},
&stepRun{
atLeastVersion2: true,
ui: packer.TestUi(t),
},
[]string{"-display", "gtk"},
"Display option should default to gtk",
},
}
for _, tc := range testcases {
state := runTestState(t, &Config{})
for k, v := range tc.ExtraState {
state.Put(k, v)
}
args, err := tc.Step.getCommandArgs(tc.Config, state)
if err != nil {
t.Fatalf("should not have an error getting args. Error: %s", err)
}
if !matchArgument(args, tc.Expected) {
t.Fatalf("Couldn't find %#v in result. Got: %#v, Reason: %s",
tc.Expected, args, tc.Reason)
}
}
}
// This test makes sure that arguments don't end up in the final boot command
// if they aren't configured in the config.
// func TestDefaultsAbsentValues(t *testing.T) {}
func matchArgument(actual []string, expected []string) bool {
key := expected[0]
for i, k := range actual {
if key == k {
if expected[1] == actual[i+1] {
return true
}
}
}
return false
}
+3 -4
View File
@@ -44,12 +44,11 @@ type Config struct {
// 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.
// The marketplace image label (eg `ubuntu_focal`) also works.
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
// C1, C2L, C2M, C2S, DEV1-S, DEV1-M, DEV1-L, DEV1-XL,
// GP1-XS, GP1-S, GP1-M, GP1-L, GP1-XL, RENDER-S
CommercialType string `mapstructure:"commercial_type" required:"true"`
// The name of the resulting snapshot that will
// appear in your account. Default packer-TIMESTAMP
+22 -1
View File
@@ -5,9 +5,11 @@ import (
"fmt"
"log"
"github.com/hashicorp/go-uuid"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/scaleway/scaleway-sdk-go/api/instance/v1"
"github.com/scaleway/scaleway-sdk-go/api/marketplace/v1"
"github.com/scaleway/scaleway-sdk-go/scw"
)
@@ -22,8 +24,27 @@ func (s *stepImage) Run(ctx context.Context, state multistep.StateBag) multistep
ui.Say(fmt.Sprintf("Creating image: %v", c.ImageName))
imageID := c.Image
// if not a UUID, we check the Marketplace API
_, err := uuid.ParseUUID(c.Image)
if err != nil {
apiMarketplace := marketplace.NewAPI(state.Get("client").(*scw.Client))
imageID, err = apiMarketplace.GetLocalImageIDByLabel(&marketplace.GetLocalImageIDByLabelRequest{
ImageLabel: c.Image,
Zone: scw.Zone(c.Zone),
CommercialType: c.CommercialType,
})
if err != nil {
err := fmt.Errorf("Error getting initial image info from marketplace: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
}
imageResp, err := instanceAPI.GetImage(&instance.GetImageRequest{
ImageID: c.Image,
ImageID: imageID,
})
if err != nil {
err := fmt.Errorf("Error getting initial image info: %s", err)
+8 -5
View File
@@ -14,15 +14,18 @@ type LocationConfig struct {
VMName string `mapstructure:"vm_name"`
// VM folder to create the VM in.
Folder string `mapstructure:"folder"`
// ESXi cluster where target VM is created. See
// [Working with Clusters](#working-with-clusters).
// ESXi cluster where target VM is created. See the
// [Working With Clusters And Hosts](#working-with-clusters-and-hosts)
// section above for more details.
Cluster string `mapstructure:"cluster"`
// ESXi host where target VM is created. A full path must be specified if
// the host is in a folder. For example `folder/host`. See the
// `Specifying Clusters and Hosts` section above for more details.
// [Working With Clusters And Hosts](#working-with-clusters-and-hosts)
// section above for more details.
Host string `mapstructure:"host"`
// VMWare resource pool. If not set, it will look for the root resource pool of the `host` or `cluster`.
// If a root resource is not found, it will then look for a default resource pool.
// VMWare resource pool. If not set, it will look for the root resource
// pool of the `host` or `cluster`. If a root resource is not found, it
// will then look for a default resource pool.
ResourcePool string `mapstructure:"resource_pool"`
// VMWare datastore. Required if `host` is a cluster, or if `host` has
// multiple datastores.
+2 -2
View File
@@ -382,7 +382,7 @@ Options:
-color=false Disable color output. (Default: color)
-debug Debug mode enabled for builds.
-except=foo,bar,baz Run all builds and post-procesors other than these.
-except=foo,bar,baz Run all builds and post-processors other than these.
-only=foo,bar,baz Build only the specified builds.
-force Force a build to continue if artifacts exist, deletes existing artifacts.
-machine-readable Produce machine-readable output.
@@ -390,7 +390,7 @@ Options:
-parallel-builds=1 Number of builds to run in parallel. 1 disables parallelization. 0 means no limit (Default: 0)
-timestamp-ui Enable prefixing of each ui output with an RFC3339 timestamp.
-var 'key=value' Variable for templates, can be used multiple times.
-var-file=path JSON file containing user variables.
-var-file=path JSON or HCL2 file containing user variables.
`
return strings.TrimSpace(helpText)
+12 -2
View File
@@ -138,7 +138,7 @@ func TestBuild(t *testing.T) {
},
{
name: "build name: HCL",
name: "source name: HCL",
args: []string{
"-parallel-builds=1", // to ensure order is kept
testFixture("build-name-and-type"),
@@ -297,7 +297,6 @@ func TestBuild(t *testing.T) {
},
},
},
{
name: "hcl - recipes - only recipes",
args: []string{
@@ -314,6 +313,17 @@ func TestBuild(t *testing.T) {
},
},
},
{
name: "hcl - build.name accessible",
args: []string{
filepath.Join(testFixture("build-name-and-type"), "buildname.pkr.hcl"),
},
fileCheck: fileCheck{
expected: []string{
"pineapple.pizza.txt",
},
},
},
}
for _, tt := range tc {
+1 -1
View File
@@ -81,7 +81,7 @@ Usage: packer console [options] [TEMPLATE]
Options:
-var 'key=value' Variable for templates, can be used multiple times.
-var-file=path JSON file containing user variables. [ Note that even in HCL mode this expects file to contain JSON, a fix is comming soon ]
-var-file=path JSON or HCL2 file containing user variables. [ Note that even in HCL mode this expects file to contain JSON, a fix is comming soon ]
`
return strings.TrimSpace(helpText)
+7 -7
View File
@@ -55,7 +55,7 @@ func (c *HCL2UpgradeCommand) ParseArgs(args []string) (*HCL2UpgradeArgs, int) {
}
const (
hcl2UpgradeFileHeader = `# This file was autogenerate by the BETA 'packer hcl2_upgrade' command. We
hcl2UpgradeFileHeader = `# This file was autogenerated by the BETA 'packer hcl2_upgrade' command. We
# recommend double checking that everything is correct before going forward. We
# also recommend treating this file as disposable. The HCL2 blocks in this
# file can be moved to other files. For example, the variable blocks could be
@@ -64,20 +64,20 @@ const (
# once they also need to be in the same folder. 'packer inspect folder/'
# will describe to you what is in that folder.
# All generated input variables will be of string type as this how Packer JSON
# views them; you can later on change their type. Read the variables type
# All generated input variables will be of 'string' type as this is how Packer JSON
# views them; you can change their type later on. Read the variables type
# constraints documentation
# https://www.packer.io/docs/from-1.5/variables#type-constraints for more info.
`
sourcesHeader = `
# source blocks are generated from your builders; a source can be referenced in
# build blocks. A build block runs provisioner and post-processors onto a
# build blocks. A build block runs provisioner and post-processors on a
# source. Read the documentation for source blocks here:
# https://www.packer.io/docs/from-1.5/blocks/source`
buildHeader = `
# a build block invokes sources and runs provisionning steps on them. The
# a build block invokes sources and runs provisioning steps on them. The
# documentation for build blocks can be found here:
# https://www.packer.io/docs/from-1.5/blocks/build
build {
@@ -413,14 +413,14 @@ func (*HCL2UpgradeCommand) Help() string {
helpText := `
Usage: packer hcl2_upgrade -output-file=JSON_TEMPLATE.pkr.hcl JSON_TEMPLATE...
Will transform your JSON template to a HCL2 configuration.
Will transform your JSON template into an HCL2 configuration.
`
return strings.TrimSpace(helpText)
}
func (*HCL2UpgradeCommand) Synopsis() string {
return "transform a JSON template into a HCL2 configuration"
return "transform a JSON template into an HCL2 configuration"
}
func (*HCL2UpgradeCommand) AutocompleteArgs() complete.Predictor {
@@ -0,0 +1,16 @@
source "null" "pizza" {
communicator = "none"
}
build {
name = "pineapple"
sources = [
"sources.null.pizza",
]
provisioner "shell-local" {
inline = [
"echo '' > ${build.name}.${source.name}.txt"
]
}
}
@@ -1,4 +1,4 @@
# This file was autogenerate by the BETA 'packer hcl2_upgrade' command. We
# This file was autogenerated by the BETA 'packer hcl2_upgrade' command. We
# recommend double checking that everything is correct before going forward. We
# also recommend treating this file as disposable. The HCL2 blocks in this
# file can be moved to other files. For example, the variable blocks could be
@@ -7,8 +7,8 @@
# once they also need to be in the same folder. 'packer inspect folder/'
# will describe to you what is in that folder.
# All generated input variables will be of string type as this how Packer JSON
# views them; you can later on change their type. Read the variables type
# All generated input variables will be of 'string' type as this is how Packer JSON
# views them; you can change their type later on. Read the variables type
# constraints documentation
# https://www.packer.io/docs/from-1.5/variables#type-constraints for more info.
variable "aws_access_key" {
@@ -31,7 +31,7 @@ variable "aws_secret_key" {
locals { timestamp = regex_replace(timestamp(), "[- TZ:]", "") }
# source blocks are generated from your builders; a source can be referenced in
# build blocks. A build block runs provisioner and post-processors onto a
# build blocks. A build block runs provisioner and post-processors on a
# source. Read the documentation for source blocks here:
# https://www.packer.io/docs/from-1.5/blocks/source
source "amazon-ebs" "autogenerated_1" {
@@ -70,7 +70,7 @@ source "amazon-ebs" "autogenerated_1" {
}
}
# a build block invokes sources and runs provisionning steps on them. The
# a build block invokes sources and runs provisioning steps on them. The
# documentation for build blocks can be found here:
# https://www.packer.io/docs/from-1.5/blocks/build
build {
+1 -1
View File
@@ -92,7 +92,7 @@ Options:
-except=foo,bar,baz Validate all builds other than these.
-only=foo,bar,baz Validate only these builds.
-var 'key=value' Variable for templates, can be used multiple times.
-var-file=path JSON file containing user variables. [ Note that even in HCL mode this expects file to contain JSON, a fix is comming soon ]
-var-file=path JSON or HCL2 file containing user variables. [ Note that even in HCL mode this expects file to contain JSON, a fix is comming soon ]
`
return strings.TrimSpace(helpText)
+3 -3
View File
@@ -14,13 +14,13 @@ _packer () {
'-force[Force a build to continue if artifacts exist, deletes existing artifacts.]'
'-machine-readable[Produce machine-readable output.]'
'-color=[(false) Disable color output. (Default: color)]'
'-except=[(foo,bar,baz) Run all builds and post-procesors other than these.]'
'-except=[(foo,bar,baz) Run all builds and post-processors other than these.]'
'-on-error=[(cleanup,abort,ask) If the build fails do: clean up (default), abort, or ask.]'
'-only=[(foo,bar,baz) Only build the given builds by name.]'
'-parallel=[(false) Disable parallelization. (Default: false)]'
'-parallel-builds=[(0) Number of builds to run in parallel. (Defaults to infinite: 0)]'
'-var[("key=value") Variable for templates, can be used multiple times.]'
'-var-file=[(path) JSON file containing user variables.]'
'-var-file=[(path) JSON or HCL2 file containing user variables.]'
'(-)*:files:_files -g "*.json"'
)
@@ -34,7 +34,7 @@ _packer () {
'-except=[(foo,bar,baz) Validate all builds other than these.]'
'-only=[(foo,bar,baz) Validate only these builds.]'
'-var[("key=value") Variable for templates, can be used multiple times.]'
'-var-file=[(path) JSON file containing user variables.]'
'-var-file=[(path) JSON or HCL2 file containing user variables.]'
'(-)*:files:_files -g "*.json"'
)
+41
View File
@@ -0,0 +1,41 @@
{
"variables": {
"client_id": "{{env `ARM_CLIENT_ID`}}",
"client_secret": "{{env `ARM_CLIENT_SECRET`}}",
"subscription_id": "{{env `ARM_SUBSCRIPTION_ID`}}",
"resource_group": "{{env `ARM_IMAGE_RESOURCEGROUP_ID`}}",
"gallery_name": "{{env `ARM_GALLERY_NAME`}}"
},
"builders": [{
"type": "azure-chroot",
"client_id": "{{user `client_id`}}",
"client_secret": "{{user `client_secret`}}",
"subscription_id": "{{user `subscription_id`}}",
"source": "Canonical:UbuntuServer:20.04-LTS:latest",
"shared_image_destination": {
"resource_group": "{{user `resource_group`}}",
"gallery_name": "{{user `gallery_name`}}",
"image_name": "MyUbuntuOSImage",
"image_version": "1.0.0",
"exclude_from_latest": false,
"target_regions": [
{
"name": "eastus",
"replicas": "1",
"storage_account_type": "standard_zrs"
}
]
}
}],
"provisioners": [{
"inline": [
"apt update",
"apt upgrade -y"
],
"inline_shebang": "/bin/sh -x",
"type": "shell"
}]
}
+2
View File
@@ -58,6 +58,7 @@ func init() {
"vsphere-iso-net-disk": new(FixerVSphereNetworkDisk),
"iso-checksum-type-and-url": new(FixerISOChecksumTypeAndURL),
"qemu-host-port": new(FixerQEMUHostPort),
"azure-exclude_from_latest": new(FixerAzureExcludeFromLatest),
}
FixerOrder = []string{
@@ -93,5 +94,6 @@ func init() {
"vsphere-iso-net-disk",
"iso-checksum-type-and-url",
"qemu-host-port",
"azure-exclude_from_latest",
}
}
+70
View File
@@ -0,0 +1,70 @@
package fix
import (
"strings"
"github.com/mitchellh/mapstructure"
)
// FixerAzureExcludeFromLatest fix the spelling of "exclude_from_latest"
// template in an Azure builder
type FixerAzureExcludeFromLatest struct{}
func (FixerAzureExcludeFromLatest) DeprecatedOptions() []string {
return []string{"exlude_from_latest"}
}
func (FixerAzureExcludeFromLatest) Fix(input map[string]interface{}) (map[string]interface{}, error) {
// The type we'll decode into; we only care about builders
type template struct {
Builders []map[string]interface{}
}
// Decode the input into our structure, if we can
var tpl template
if err := mapstructure.Decode(input, &tpl); err != nil {
return nil, err
}
for _, builder := range tpl.Builders {
builderTypeRaw, ok := builder["type"]
if !ok {
continue
}
builderType, ok := builderTypeRaw.(string)
if !ok {
continue
}
if !strings.HasPrefix(builderType, "azure-chroot") {
continue
}
if !strings.HasPrefix(builderType, "azure-chroot") {
continue
}
sharedImageDestination, ok := builder["shared_image_destination"].(map[string]interface{})
if !ok {
continue
}
excludeFromLatest, ok := sharedImageDestination["exlude_from_latest"]
if !ok {
continue
}
sharedImageDestination["exclude_from_latest"] = excludeFromLatest
delete(sharedImageDestination, "exlude_from_latest")
builder["shared_image_destination"] = sharedImageDestination
}
input["builders"] = tpl.Builders
return input, nil
}
func (FixerAzureExcludeFromLatest) Synopsis() string {
return `Changes "exlude_from_latest" to "exclude_from_latest" in Azure builders.`
}
@@ -0,0 +1,66 @@
package fix
import (
"reflect"
"testing"
)
func TestFixerAzureExcludeFromLatest(t *testing.T) {
var _ Fixer = new(FixerAzureExcludeFromLatest)
}
func TestFixerAzureExcludeFromLatest_Fix_exlude_from_latest(t *testing.T) {
cases := []struct {
Input map[string]interface{}
Expected map[string]interface{}
}{
// No shared_image_destination field
{
Input: map[string]interface{}{
"type": "azure-chroot",
},
Expected: map[string]interface{}{
"type": "azure-chroot",
},
},
// exlude_from_latest field
{
Input: map[string]interface{}{
"type": "azure-chroot",
"shared_image_destination": map[string]interface{}{
"exlude_from_latest": "false",
},
},
Expected: map[string]interface{}{
"type": "azure-chroot",
"shared_image_destination": map[string]interface{}{
"exclude_from_latest": "false",
},
},
},
}
for _, tc := range cases {
var f FixerAzureExcludeFromLatest
input := map[string]interface{}{
"builders": []map[string]interface{}{tc.Input},
}
expected := map[string]interface{}{
"builders": []map[string]interface{}{tc.Expected},
}
output, err := f.Fix(input)
if err != nil {
t.Fatalf("err: %s", err)
}
if !reflect.DeepEqual(output, expected) {
t.Fatalf("unexpected: %#v\nexpected: %#v\n", output, expected)
}
}
}
+2 -6
View File
@@ -42,7 +42,6 @@ require (
github.com/gobwas/glob v0.2.3
github.com/gofrs/flock v0.7.3
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3
github.com/golang/protobuf v1.4.2 // indirect
github.com/google/go-cmp v0.5.2
github.com/google/go-querystring v1.0.0 // indirect
github.com/google/shlex v0.0.0-20150127133951-6f45313302b9
@@ -79,7 +78,6 @@ require (
github.com/joyent/triton-go v0.0.0-20180628001255-830d2b111e62
github.com/json-iterator/go v1.1.6 // indirect
github.com/jtolds/gls v4.2.1+incompatible // indirect
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 // indirect
github.com/klauspost/compress v0.0.0-20160131094358-f86d2e6d8a77 // indirect
github.com/klauspost/cpuid v0.0.0-20160106104451-349c67577817 // indirect
github.com/klauspost/crc32 v0.0.0-20160114101742-999f3125931f // indirect
@@ -94,10 +92,9 @@ require (
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/go-testing-interface v1.0.3 // indirect
github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed
github.com/mitchellh/gox v1.0.1 // indirect
github.com/mitchellh/iochan v1.0.0
github.com/mitchellh/mapstructure v1.2.3
github.com/mitchellh/panicwrap v0.0.0-20170106182340-fce601fe5557
github.com/mitchellh/panicwrap v1.0.0
github.com/mitchellh/prefixedio v0.0.0-20151214002211-6e6954073784
github.com/mitchellh/reflectwalk v1.0.0
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
@@ -113,7 +110,7 @@ require (
github.com/posener/complete v1.2.3
github.com/profitbricks/profitbricks-sdk-go v4.0.2+incompatible
github.com/satori/go.uuid v1.2.0 // indirect
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.6.0.20200903143645-c0ce17a0443d
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7
github.com/shirou/gopsutil v2.18.12+incompatible
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 // indirect
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect
@@ -137,7 +134,6 @@ require (
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208
golang.org/x/sys v0.0.0-20200918174421-af09f7315aff
golang.org/x/text v0.3.3 // indirect
golang.org/x/tools v0.0.0-20200918232735-d647fc253266
google.golang.org/api v0.32.0
google.golang.org/genproto v0.0.0-20200918140846-d0d605568037 // indirect
+4 -8
View File
@@ -376,7 +376,6 @@ github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0=
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E=
@@ -434,8 +433,6 @@ github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfE
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE=
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/NeTKd4f1QXZItOX389VN3B6qC8ro=
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v0.0.0-20160131094358-f86d2e6d8a77 h1:rJnR80lkojFgjdg/oQPhbZoY8t8uM51XMz8DrJrjabk=
@@ -513,15 +510,14 @@ github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZX
github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/gox v1.0.1/go.mod h1:ED6BioOGXMswlXa2zxfh/xdd5QhwYliBFn9V18Ap4z4=
github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.2.3 h1:f/MjBEBDLttYCGfRaKBbKSRVF5aV2O6fnBpzknuE3jU=
github.com/mitchellh/mapstructure v1.2.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/panicwrap v0.0.0-20170106182340-fce601fe5557 h1:w1QuuAA2km2Hax+EPamrq5ZRBeaNv2vsjvgB4an0zoU=
github.com/mitchellh/panicwrap v0.0.0-20170106182340-fce601fe5557/go.mod h1:QuAqW7/z+iv6aWFJdrA8kCbsF0OOJVKCICqTcYBexuY=
github.com/mitchellh/panicwrap v1.0.0 h1:67zIyVakCIvcs69A0FGfZjBdPleaonSgGlXRSRlb6fE=
github.com/mitchellh/panicwrap v1.0.0/go.mod h1:pKvZHwWrZowLUzftuFq7coarnxbBXU4aQh3N0BJOeeA=
github.com/mitchellh/prefixedio v0.0.0-20151214002211-6e6954073784 h1:+DAetXqxv/mSyCkE9KBIYOZs9b68y7SUaDCxQMRjA68=
github.com/mitchellh/prefixedio v0.0.0-20151214002211-6e6954073784/go.mod h1:kB1naBgV9ORnkiTVeyJOI1DavaJkG4oNIq0Af6ZVKUo=
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
@@ -581,8 +577,8 @@ github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkB
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.6.0.20200903143645-c0ce17a0443d h1:pK33AoOAlzj6gJs/V1vi2Ouj2u1Ww84pREwxFi1oxkM=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.6.0.20200903143645-c0ce17a0443d/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7 h1:Do8ksLD4Nr3pA0x0hnLOLftZgkiTDvwPDShRTUxtXpE=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
+3
View File
@@ -31,6 +31,9 @@ func (p *HCL2Provisioner) HCL2Prepare(buildVars map[string]interface{}) error {
if len(buildVars) > 0 {
ectx = p.evalContext.NewChild()
buildValues := map[string]cty.Value{}
if !p.evalContext.Variables[buildAccessor].IsNull() {
buildValues = p.evalContext.Variables[buildAccessor].AsValueMap()
}
for k, v := range buildVars {
switch v := v.(type) {
case string:
+1
View File
@@ -383,6 +383,7 @@ func (cfg *PackerConfig) GetBuilds(opts packer.GetBuildsOptions) ([]packer.Build
for _, k := range append(packer.BuilderDataCommonKeys, generatedVars...) {
unknownBuildValues[k] = cty.StringVal("<unknown>")
}
unknownBuildValues["name"] = cty.StringVal(build.Name)
variables := map[string]cty.Value{
sourcesAccessor: cty.ObjectVal(src.ctyValues()),
+1
View File
@@ -40,4 +40,5 @@ var DeprecatedOptions = []string{
"iso_checksum_type",
"ssh_host_port_max",
"ssh_host_port_min",
"exlude_from_latest",
}
Binary file not shown.
-27
View File
@@ -1,27 +0,0 @@
Copyright (c) 2012 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-21
View File
@@ -1,21 +0,0 @@
### Extensions to the "os" package.
[![GoDoc](https://godoc.org/github.com/kardianos/osext?status.svg)](https://godoc.org/github.com/kardianos/osext)
## Find the current Executable and ExecutableFolder.
As of go1.8 the Executable function may be found in `os`. The Executable function
in the std lib `os` package is used if available.
There is sometimes utility in finding the current executable file
that is running. This can be used for upgrading the current executable
or finding resources located relative to the executable file. Both
working directory and the os.Args[0] value are arbitrary and cannot
be relied on; os.Args[0] can be "faked".
Multi-platform and supports:
* Linux
* OS X
* Windows
* Plan 9
* BSDs.
-33
View File
@@ -1,33 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Extensions to the standard "os" package.
package osext // import "github.com/kardianos/osext"
import "path/filepath"
var cx, ce = executableClean()
func executableClean() (string, error) {
p, err := executable()
return filepath.Clean(p), err
}
// Executable returns an absolute path that can be used to
// re-invoke the current program.
// It may not be valid after the current program exits.
func Executable() (string, error) {
return cx, ce
}
// Returns same path as Executable, returns just the folder
// path. Excludes the executable name and any trailing slash.
func ExecutableFolder() (string, error) {
p, err := Executable()
if err != nil {
return "", err
}
return filepath.Dir(p), nil
}
-9
View File
@@ -1,9 +0,0 @@
//+build go1.8,!openbsd
package osext
import "os"
func executable() (string, error) {
return os.Executable()
}
-22
View File
@@ -1,22 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//+build !go1.8
package osext
import (
"os"
"strconv"
"syscall"
)
func executable() (string, error) {
f, err := os.Open("/proc/" + strconv.Itoa(os.Getpid()) + "/text")
if err != nil {
return "", err
}
defer f.Close()
return syscall.Fd2path(int(f.Fd()))
}
-36
View File
@@ -1,36 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.8,android !go1.8,linux !go1.8,netbsd !go1.8,solaris !go1.8,dragonfly
package osext
import (
"errors"
"fmt"
"os"
"runtime"
"strings"
)
func executable() (string, error) {
switch runtime.GOOS {
case "linux", "android":
const deletedTag = " (deleted)"
execpath, err := os.Readlink("/proc/self/exe")
if err != nil {
return execpath, err
}
execpath = strings.TrimSuffix(execpath, deletedTag)
execpath = strings.TrimPrefix(execpath, deletedTag)
return execpath, nil
case "netbsd":
return os.Readlink("/proc/curproc/exe")
case "dragonfly":
return os.Readlink("/proc/curproc/file")
case "solaris":
return os.Readlink(fmt.Sprintf("/proc/%d/path/a.out", os.Getpid()))
}
return "", errors.New("ExecPath not implemented for " + runtime.GOOS)
}
-126
View File
@@ -1,126 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.8,darwin !go1.8,freebsd openbsd
package osext
import (
"os"
"os/exec"
"path/filepath"
"runtime"
"syscall"
"unsafe"
)
var initCwd, initCwdErr = os.Getwd()
func executable() (string, error) {
var mib [4]int32
switch runtime.GOOS {
case "freebsd":
mib = [4]int32{1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1}
case "darwin":
mib = [4]int32{1 /* CTL_KERN */, 38 /* KERN_PROCARGS */, int32(os.Getpid()), -1}
case "openbsd":
mib = [4]int32{1 /* CTL_KERN */, 55 /* KERN_PROC_ARGS */, int32(os.Getpid()), 1 /* KERN_PROC_ARGV */}
}
n := uintptr(0)
// Get length.
_, _, errNum := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, 0, uintptr(unsafe.Pointer(&n)), 0, 0)
if errNum != 0 {
return "", errNum
}
if n == 0 { // This shouldn't happen.
return "", nil
}
buf := make([]byte, n)
_, _, errNum = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&n)), 0, 0)
if errNum != 0 {
return "", errNum
}
if n == 0 { // This shouldn't happen.
return "", nil
}
var execPath string
switch runtime.GOOS {
case "openbsd":
// buf now contains **argv, with pointers to each of the C-style
// NULL terminated arguments.
var args []string
argv := uintptr(unsafe.Pointer(&buf[0]))
Loop:
for {
argp := *(**[1 << 20]byte)(unsafe.Pointer(argv))
if argp == nil {
break
}
for i := 0; uintptr(i) < n; i++ {
// we don't want the full arguments list
if string(argp[i]) == " " {
break Loop
}
if argp[i] != 0 {
continue
}
args = append(args, string(argp[:i]))
n -= uintptr(i)
break
}
if n < unsafe.Sizeof(argv) {
break
}
argv += unsafe.Sizeof(argv)
n -= unsafe.Sizeof(argv)
}
execPath = args[0]
// There is no canonical way to get an executable path on
// OpenBSD, so check PATH in case we are called directly
if execPath[0] != '/' && execPath[0] != '.' {
execIsInPath, err := exec.LookPath(execPath)
if err == nil {
execPath = execIsInPath
}
}
default:
for i, v := range buf {
if v == 0 {
buf = buf[:i]
break
}
}
execPath = string(buf)
}
var err error
// execPath will not be empty due to above checks.
// Try to get the absolute path if the execPath is not rooted.
if execPath[0] != '/' {
execPath, err = getAbs(execPath)
if err != nil {
return execPath, err
}
}
// For darwin KERN_PROCARGS may return the path to a symlink rather than the
// actual executable.
if runtime.GOOS == "darwin" {
if execPath, err = filepath.EvalSymlinks(execPath); err != nil {
return execPath, err
}
}
return execPath, nil
}
func getAbs(execPath string) (string, error) {
if initCwdErr != nil {
return execPath, initCwdErr
}
// The execPath may begin with a "../" or a "./" so clean it first.
// Join the two paths, trailing and starting slashes undetermined, so use
// the generic Join function.
return filepath.Join(initCwd, filepath.Clean(execPath)), nil
}
-36
View File
@@ -1,36 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//+build !go1.8
package osext
import (
"syscall"
"unicode/utf16"
"unsafe"
)
var (
kernel = syscall.MustLoadDLL("kernel32.dll")
getModuleFileNameProc = kernel.MustFindProc("GetModuleFileNameW")
)
// GetModuleFileName() with hModule = NULL
func executable() (exePath string, err error) {
return getModuleFileName()
}
func getModuleFileName() (string, error) {
var n uint32
b := make([]uint16, syscall.MAX_PATH)
size := uint32(len(b))
r0, _, e1 := getModuleFileNameProc.Call(0, uintptr(unsafe.Pointer(&b[0])), uintptr(size))
n = uint32(r0)
if n == 0 {
return "", e1
}
return string(utf16.Decode(b[0:n])), nil
}
+3
View File
@@ -0,0 +1,3 @@
module github.com/mitchellh/panicwrap
go 1.13
View File
+9 -3
View File
@@ -20,8 +20,6 @@ import (
"sync/atomic"
"syscall"
"time"
"github.com/kardianos/osext"
)
const (
@@ -118,7 +116,7 @@ func Wrap(c *WrapConfig) (int, error) {
}
// Get the path to our current executable
exePath, err := osext.Executable()
exePath, err := os.Executable()
if err != nil {
return -1, err
}
@@ -229,6 +227,11 @@ func Wrap(c *WrapConfig) (int, error) {
// Wrapped checks if we're already wrapped according to the configuration
// given.
//
// It must be only called once with a non-nil configuration as it unsets
// the environment variable it uses to check if we are already wrapped.
// This prevents false positive if your program tries to execute itself
// recursively.
//
// Wrapped is very cheap and can be used early to short-circuit some pre-wrap
// logic your application may have.
//
@@ -253,6 +256,9 @@ func Wrapped(c *WrapConfig) bool {
// If the cookie key/value match our environment, then we are the
// child, so just exit now and tell the caller that we're the child
result := os.Getenv(c.CookieKey) == c.CookieValue
if result {
os.Unsetenv(c.CookieKey)
}
wrapCache.Store(result)
return result
}
+85 -78
View File
@@ -613,7 +613,7 @@ type Bootscript struct {
Initrd string `json:"initrd"`
// Kernel: the server kernel version
Kernel string `json:"kernel"`
// Organization: the bootscript organization
// Organization: the bootscript organization ID
Organization string `json:"organization"`
// Project: the bootscript project ID
Project string `json:"project"`
@@ -892,7 +892,7 @@ type PlacementGroup struct {
ID string `json:"id"`
// Name: the placement group name
Name string `json:"name"`
// Organization: the placement group organization
// Organization: the placement group organization ID
Organization string `json:"organization"`
// Project: the placement group project ID
Project string `json:"project"`
@@ -950,11 +950,11 @@ type SecurityGroup struct {
OutboundDefaultPolicy SecurityGroupPolicy `json:"outbound_default_policy"`
// Organization: the security groups organization ID
Organization string `json:"organization"`
// Project: the project ID of the security group
// Project: the security group project ID
Project string `json:"project"`
// OrganizationDefault: true if it is your default security group for this organization
// Deprecated: OrganizationDefault: true if it is your default security group for this organization ID
OrganizationDefault bool `json:"organization_default"`
// ProjectDefault: true if it is your default security group for this project id
// ProjectDefault: true if it is your default security group for this project ID
ProjectDefault bool `json:"project_default"`
// CreationDate: the security group creation date
CreationDate *time.Time `json:"creation_date"`
@@ -1014,7 +1014,7 @@ type Server struct {
ID string `json:"id"`
// Name: the server name
Name string `json:"name"`
// Organization: the server organization
// Organization: the server organization ID
Organization string `json:"organization"`
// Project: the server project ID
Project string `json:"project"`
@@ -1181,37 +1181,41 @@ type SetPlacementGroupServersResponse struct {
Servers []*PlacementGroupServer `json:"servers"`
}
// Snapshot: snapshot
type Snapshot struct {
// ID: the snapshot ID
ID string `json:"id"`
// Name: the snapshot name
Name string `json:"name"`
// Organization: the snapshot organization ID
Organization string `json:"organization"`
// VolumeType:
// Project: the snapshot project ID
Project string `json:"project"`
// VolumeType: the snapshot volume type
//
// Default value: l_ssd
VolumeType VolumeVolumeType `json:"volume_type"`
// Size: the snapshot size
Size scw.Size `json:"size"`
// State:
// State: the snapshot state
//
// Default value: available
State SnapshotState `json:"state"`
// BaseVolume: the volume on which the snapshot is based on
BaseVolume *SnapshotBaseVolume `json:"base_volume"`
// CreationDate: the snapshot creation date
CreationDate *time.Time `json:"creation_date"`
// ModificationDate: the snapshot modification date
ModificationDate *time.Time `json:"modification_date"`
Project string `json:"project"`
// Zone: the snapshot zone
Zone scw.Zone `json:"zone"`
}
// SnapshotBaseVolume: snapshot. base volume
type SnapshotBaseVolume struct {
// ID: the volume ID on which the snapshot is based on
ID string `json:"id"`
// Name: the volume name on which the snapshot is based on
Name string `json:"name"`
}
@@ -1261,29 +1265,29 @@ type UpdateVolumeResponse struct {
// Volume: volume
type Volume struct {
// ID: the volumes unique ID
// ID: the volume unique ID
ID string `json:"id"`
// Name: the volumes names
// Name: the volume name
Name string `json:"name"`
// ExportURI: show the volumes NBD export URI
// ExportURI: show the volume NBD export URI
ExportURI string `json:"export_uri"`
// Size: the volumes disk size
// Size: the volume disk size
Size scw.Size `json:"size"`
// VolumeType: the volumes type
// VolumeType: the volume type
//
// Default value: l_ssd
VolumeType VolumeVolumeType `json:"volume_type"`
// CreationDate: the volumes creation date
// CreationDate: the volume creation date
CreationDate *time.Time `json:"creation_date"`
// ModificationDate: the volumes modification date
// ModificationDate: the volume modification date
ModificationDate *time.Time `json:"modification_date"`
// Organization: the volumes organization
// Organization: the volume organization ID
Organization string `json:"organization"`
// Project: the volumes project ID
// Project: the volume project ID
Project string `json:"project"`
// Server: the server attached to the volume
Server *ServerSummary `json:"server"`
// State: the volumes state
// State: the volume state
//
// Default value: available
State VolumeState `json:"state"`
@@ -1315,10 +1319,12 @@ type VolumeTemplate struct {
//
// Default value: l_ssd
VolumeType VolumeVolumeType `json:"volume_type,omitempty"`
// Organization: organization ID of the volume
Organization string `json:"organization,omitempty"`
// Deprecated: Organization: organization ID of the volume
// Precisely one of Organization, Project must be set.
Organization *string `json:"organization,omitempty"`
// Project: project ID of the volume
Project string `json:"project,omitempty"`
// Precisely one of Organization, Project must be set.
Project *string `json:"project,omitempty"`
}
type VolumeType struct {
@@ -1518,7 +1524,7 @@ type ListServersRequest struct {
PerPage *uint32 `json:"-"`
// Page: a positive integer to choose the page to return
Page *int32 `json:"-"`
// Organization: list only servers of this organization
// Organization: list only servers of this organization ID
Organization *string `json:"-"`
// Project: list only servers of this project ID
Project *string `json:"-"`
@@ -1536,6 +1542,8 @@ type ListServersRequest struct {
State *ServerState `json:"-"`
// Tags: list servers with these exact tags
Tags []string `json:"-"`
// PrivateNetwork: list servers in this Private Network
PrivateNetwork *string `json:"-"`
}
// ListServers: list all servers
@@ -1565,6 +1573,7 @@ func (s *API) ListServers(req *ListServersRequest, opts ...scw.RequestOption) (*
if len(req.Tags) != 0 {
parameter.AddToQuery(query, "tags", strings.Join(req.Tags, ","))
}
parameter.AddToQuery(query, "private_network", req.PrivateNetwork)
if fmt.Sprint(req.Zone) == "" {
return nil, errors.New("field Zone cannot be empty in request")
@@ -1627,7 +1636,7 @@ type CreateServerRequest struct {
BootType *BootType `json:"boot_type,omitempty"`
// Bootscript: the bootscript ID to use when `boot_type` is set to `bootscript`
Bootscript *string `json:"bootscript,omitempty"`
// Organization: the server organization ID
// Deprecated: Organization: the server organization ID
// Precisely one of Organization, Project must be set.
Organization *string `json:"organization,omitempty"`
// Project: the server project ID
@@ -1639,8 +1648,6 @@ type CreateServerRequest struct {
SecurityGroup *string `json:"security_group,omitempty"`
// PlacementGroup: placement group ID if server must be part of a placement group
PlacementGroup *string `json:"placement_group,omitempty"`
// PrivateNetwork: private Network IDs if the server need to be part of one or more Private Networks
PrivateNetwork []string `json:"private_network,omitempty"`
}
// createServer: create a server
@@ -1774,7 +1781,7 @@ type setServerRequest struct {
ID string `json:"-"`
// Name: the server name
Name string `json:"name"`
// Organization: the server organization
// Organization: the server organization ID
Organization string `json:"organization"`
// Project: the server project ID
Project string `json:"project"`
@@ -2262,7 +2269,7 @@ type CreateImageRequest struct {
DefaultBootscript string `json:"default_bootscript,omitempty"`
// ExtraVolumes: additional volumes of the image
ExtraVolumes map[string]*VolumeTemplate `json:"extra_volumes,omitempty"`
// Organization: organization ID of the image
// Deprecated: Organization: organization ID of the image
// Precisely one of Organization, Project must be set.
Organization *string `json:"organization,omitempty"`
// Project: project ID of the image
@@ -2520,10 +2527,10 @@ type CreateSnapshotRequest struct {
Name string `json:"name,omitempty"`
// VolumeID: UUID of the volume
VolumeID string `json:"volume_id,omitempty"`
// Deprecated: Organization: organization ID of the snapshot
// Precisely one of Organization, Project must be set.
Organization *string `json:"organization,omitempty"`
// Project: project ID of the snapshot
// Precisely one of Organization, Project must be set.
Project *string `json:"project,omitempty"`
}
@@ -2742,7 +2749,7 @@ type ListVolumesRequest struct {
PerPage *uint32 `json:"-"`
// Page: a positive integer to choose the page to return
Page *int32 `json:"-"`
// Organization: filter volume by organization
// Organization: filter volume by organization ID
Organization *string `json:"-"`
// Project: filter volume by project ID
Project *string `json:"-"`
@@ -2813,27 +2820,27 @@ func (r *ListVolumesResponse) UnsafeAppend(res interface{}) (uint32, error) {
type CreateVolumeRequest struct {
Zone scw.Zone `json:"-"`
// Name: the volume name
Name string `json:"name,omitempty"`
// Deprecated: Organization: the volume organization ID
// Precisely one of Organization, Project must be set.
Organization *string `json:"organization,omitempty"`
// VolumeType:
// Project: the volume project ID
// Precisely one of Organization, Project must be set.
Project *string `json:"project,omitempty"`
// VolumeType: the volume type
//
// Default value: l_ssd
VolumeType VolumeVolumeType `json:"volume_type"`
// Size: the volume disk size
// Precisely one of BaseSnapshot, BaseVolume, Size must be set.
Size *scw.Size `json:"size,omitempty"`
// BaseVolume: the ID of the volume on which this volume will be based
// Precisely one of BaseSnapshot, BaseVolume, Size must be set.
BaseVolume *string `json:"base_volume,omitempty"`
// BaseSnapshot: the ID of the snapshot on which this volume will be based
// Precisely one of BaseSnapshot, BaseVolume, Size must be set.
BaseSnapshot *string `json:"base_snapshot,omitempty"`
// Precisely one of Organization, Project must be set.
Project *string `json:"project,omitempty"`
}
// CreateVolume: create a volume
@@ -3090,13 +3097,13 @@ type CreateSecurityGroupRequest struct {
Name string `json:"name,omitempty"`
// Description: description of the security group
Description string `json:"description,omitempty"`
// Organization: organization the security group belongs to
// Deprecated: Organization: organization ID the security group belongs to
// Precisely one of Organization, Project must be set.
Organization *string `json:"organization,omitempty"`
// Project: project ID the security group belong to
// Precisely one of Organization, Project must be set.
Project *string `json:"project,omitempty"`
// OrganizationDefault: whether this security group becomes the default security group for new instances
// Deprecated: OrganizationDefault: whether this security group becomes the default security group for new instances
//
// Default value: false
// Precisely one of OrganizationDefault, ProjectDefault must be set.
@@ -3245,38 +3252,38 @@ func (s *API) DeleteSecurityGroup(req *DeleteSecurityGroupRequest, opts ...scw.R
type setSecurityGroupRequest struct {
Zone scw.Zone `json:"-"`
// ID: the ID of the security group (will be ignored)
ID string `json:"-"`
// Name: the name of the security group
Name string `json:"name"`
// CreationDate: the creation date of the security group (will be ignored)
CreationDate *time.Time `json:"creation_date"`
// ModificationDate: the modification date of the security group (will be ignored)
ModificationDate *time.Time `json:"modification_date"`
// Description: the description of the security group
Description string `json:"description"`
// EnableDefaultSecurity: true to block SMTP on IPv4 and IPv6
EnableDefaultSecurity bool `json:"enable_default_security"`
// InboundDefaultPolicy:
// InboundDefaultPolicy: the default inbound policy
//
// Default value: accept
InboundDefaultPolicy SecurityGroupPolicy `json:"inbound_default_policy"`
Organization string `json:"organization"`
OrganizationDefault bool `json:"organization_default"`
// OutboundDefaultPolicy:
// OutboundDefaultPolicy: the default outbound policy
//
// Default value: accept
OutboundDefaultPolicy SecurityGroupPolicy `json:"outbound_default_policy"`
Servers []*ServerSummary `json:"servers"`
Stateful bool `json:"stateful"`
// Organization: the security groups organization ID
Organization string `json:"organization"`
// Project: the security group project ID
Project string `json:"project"`
// Deprecated: OrganizationDefault: please use project_default instead
OrganizationDefault bool `json:"organization_default"`
// ProjectDefault: true use this security group for future instances created in this project
ProjectDefault bool `json:"project_default"`
// Servers: the servers attached to this security group
Servers []*ServerSummary `json:"servers"`
// Stateful: true to set the security group as stateful
Stateful bool `json:"stateful"`
}
// setSecurityGroup: update a security group
@@ -3637,7 +3644,7 @@ type ListPlacementGroupsRequest struct {
PerPage *uint32 `json:"-"`
// Page: a positive integer to choose the page to return
Page *int32 `json:"-"`
// Organization: list only placement groups of this organization
// Organization: list only placement groups of this organization ID
Organization *string `json:"-"`
// Project: list only placement groups of this project ID
Project *string `json:"-"`
@@ -3711,17 +3718,17 @@ type CreatePlacementGroupRequest struct {
Zone scw.Zone `json:"-"`
// Name: name of the placement group
Name string `json:"name,omitempty"`
// Deprecated: Organization: organization ID of the placement group
// Precisely one of Organization, Project must be set.
Organization *string `json:"organization,omitempty"`
// Project: project ID of the placement group
// Precisely one of Organization, Project must be set.
Project *string `json:"project,omitempty"`
// PolicyMode:
// PolicyMode: the operating mode of the placement group
//
// Default value: optional
PolicyMode PlacementGroupPolicyMode `json:"policy_mode"`
// PolicyType:
// PolicyType: the policy type of the placement group
//
// Default value: max_availability
PolicyType PlacementGroupPolicyType `json:"policy_type"`
@@ -4114,8 +4121,6 @@ func (s *API) UpdatePlacementGroupServers(req *UpdatePlacementGroupServersReques
type ListIPsRequest struct {
Zone scw.Zone `json:"-"`
// Project: the project ID the IPs are reserved in
Project *string `json:"-"`
// Organization: the organization ID the IPs are reserved in
Organization *string `json:"-"`
// Name: filter on the IP address (Works as a LIKE operation on the IP address)
@@ -4126,6 +4131,8 @@ type ListIPsRequest struct {
PerPage *uint32 `json:"-"`
// Page: a positive integer to choose the page to return
Page *int32 `json:"-"`
// Project: the project ID the IPs are reserved in
Project *string `json:"-"`
}
// ListIPs: list all flexible IPs
@@ -4143,11 +4150,11 @@ func (s *API) ListIPs(req *ListIPsRequest, opts ...scw.RequestOption) (*ListIPsR
}
query := url.Values{}
parameter.AddToQuery(query, "project", req.Project)
parameter.AddToQuery(query, "organization", req.Organization)
parameter.AddToQuery(query, "name", req.Name)
parameter.AddToQuery(query, "per_page", req.PerPage)
parameter.AddToQuery(query, "page", req.Page)
parameter.AddToQuery(query, "project", req.Project)
if fmt.Sprint(req.Zone) == "" {
return nil, errors.New("field Zone cannot be empty in request")
@@ -4190,7 +4197,7 @@ func (r *ListIPsResponse) UnsafeAppend(res interface{}) (uint32, error) {
type CreateIPRequest struct {
Zone scw.Zone `json:"-"`
// Organization: the organization ID the IP is reserved in
// Deprecated: Organization: the organization ID the IP is reserved in
// Precisely one of Organization, Project must be set.
Organization *string `json:"organization,omitempty"`
// Project: the project ID the IP is reserved in
+14 -12
View File
@@ -5,10 +5,11 @@
Recommended config file:
```yaml
# get your credentials on https://console.scaleway.com/account/credentials
# Get your credentials on https://console.scaleway.com/project/credentials
access_key: SCWXXXXXXXXXXXXXXXXX
secret_key: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
default_organization_id: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
default_project_id: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
default_region: fr-par
default_zone: fr-par-1
```
@@ -20,7 +21,7 @@ The function [`GetConfigPath`](https://godoc.org/github.com/scaleway/scaleway-sd
1. Custom directory: `$SCW_CONFIG_PATH`
2. [XDG base directory](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html): `$XDG_CONFIG_HOME/scw/config.yaml`
3. Unix home directory: `$HOME/.config/scw/config.yaml`
3. Windows home directory: `%USERPROFILE%/.config/scw/config.yaml`
4. Windows home directory: `%USERPROFILE%/.config/scw/config.yaml`
## V1 config (DEPRECATED)
@@ -43,13 +44,14 @@ scw.NewClient(
## Environment variables
| Variable | Description | Legacy variables |
| :------------------------ | :-------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------ |
| `$SCW_ACCESS_KEY` | Access key of a token ([get yours](https://console.scaleway.com/account/credentials)) | `$SCALEWAY_ACCESS_KEY` (used by terraform) |
| `$SCW_SECRET_KEY` | Secret key of a token ([get yours](https://console.scaleway.com/account/credentials)) | `$SCW_TOKEN` (used by cli), `$SCALEWAY_TOKEN` (used by terraform), `$SCALEWAY_ACCESS_KEY` (used by terraform) |
| `$SCW_DEFAULT_ORGANIZATION_ID` | Your default organization ID, if you don't have one use your organization ID ([get yours](https://console.scaleway.com/account/credentials)) | `$SCW_ORGANIZATION` (used by cli),`$SCALEWAY_ORGANIZATION` (used by terraform) |
| `$SCW_DEFAULT_REGION` | Your default [region](https://developers.scaleway.com/en/quickstart/#region-and-zone) | `$SCW_REGION` (used by cli),`$SCALEWAY_REGION` (used by terraform) |
| `$SCW_DEFAULT_ZONE` | Your default [availability zone](https://developers.scaleway.com/en/quickstart/#region-and-zone) | `$SCW_ZONE` (used by cli),`$SCALEWAY_ZONE` (used by terraform) |
| `$SCW_API_URL` | Url of the API | - |
| `$SCW_INSECURE` | Set this to `true` to enable the insecure mode | `$SCW_TLSVERIFY` (inverse flag used by the cli) |
| `$SCW_PROFILE` | Set the config profile to use | - |
| Variable | Description | Legacy variables |
| :----------------------------- | :----------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------ |
| `$SCW_ACCESS_KEY` | Access key of a token ([get yours](https://console.scaleway.com/project/credentials)) | `$SCALEWAY_ACCESS_KEY` (used by terraform) |
| `$SCW_SECRET_KEY` | Secret key of a token ([get yours](https://console.scaleway.com/project/credentials)) | `$SCW_TOKEN` (used by cli), `$SCALEWAY_TOKEN` (used by terraform), `$SCALEWAY_ACCESS_KEY` (used by terraform) |
| `$SCW_DEFAULT_ORGANIZATION_ID` | Your default organization ID ([get yours](https://console.scaleway.com/project/credentials)) | `$SCW_ORGANIZATION` (used by cli),`$SCALEWAY_ORGANIZATION` (used by terraform) |
| `$SCW_DEFAULT_PROJECT_ID` | Your default project ID ([get yours](https://console.scaleway.com/project/credentials)) | |
| `$SCW_DEFAULT_REGION` | Your default [region](https://developers.scaleway.com/en/quickstart/#region-and-zone) | `$SCW_REGION` (used by cli),`$SCALEWAY_REGION` (used by terraform) |
| `$SCW_DEFAULT_ZONE` | Your default [availability zone](https://developers.scaleway.com/en/quickstart/#region-and-zone) | `$SCW_ZONE` (used by cli),`$SCALEWAY_ZONE` (used by terraform) |
| `$SCW_API_URL` | Url of the API | - |
| `$SCW_INSECURE` | Set this to `true` to enable the insecure mode | `$SCW_TLSVERIFY` (inverse flag used by the cli) |
| `$SCW_PROFILE` | Set the config profile to use | - |
+1 -1
View File
@@ -30,7 +30,7 @@ const configFileTemplate = `# Scaleway configuration file
# - Scaleway Terraform Provider (https://www.terraform.io/docs/providers/scaleway/index.html)
# You need an access key and a secret key to connect to Scaleway API.
# Generate your token at the following address: https://console.scaleway.com/account/credentials
# Generate your token at the following address: https://console.scaleway.com/project/credentials
# An access key is a secret key identifier.
{{ if .AccessKey }}access_key: {{.AccessKey}}{{ else }}# access_key: SCW11111111111111111{{ end }}
+8
View File
@@ -23,6 +23,8 @@ const (
ZoneFrPar2 = Zone("fr-par-2")
// ZoneNlAms1 represents the nl-ams-1 zone
ZoneNlAms1 = Zone("nl-ams-1")
// ZonePlWaw1 represents the pl-waw-1 zone
ZonePlWaw1 = Zone("pl-waw-1")
)
var (
@@ -31,6 +33,7 @@ var (
ZoneFrPar1,
ZoneFrPar2,
ZoneNlAms1,
ZonePlWaw1,
}
)
@@ -68,6 +71,8 @@ const (
RegionFrPar = Region("fr-par")
// RegionNlAms represents the nl-ams region
RegionNlAms = Region("nl-ams")
// RegionPlWaw represents the pl-waw region
RegionPlWaw = Region("pl-waw")
)
var (
@@ -75,6 +80,7 @@ var (
AllRegions = []Region{
RegionFrPar,
RegionNlAms,
RegionPlWaw,
}
)
@@ -95,6 +101,8 @@ func (region Region) GetZones() []Zone {
return []Zone{ZoneFrPar1, ZoneFrPar2}
case RegionNlAms:
return []Zone{ZoneNlAms1}
case RegionPlWaw:
return []Zone{ZonePlWaw1}
default:
return []Zone{}
}
+1 -1
View File
@@ -6,6 +6,6 @@ import (
)
// TODO: versioning process
const version = "v1.0.0-beta.6+dev"
const version = "v1.0.0-beta.7"
var userAgent = fmt.Sprintf("scaleway-sdk-go/%s (%s; %s; %s)", version, runtime.Version(), runtime.GOOS, runtime.GOARCH)
+2 -4
View File
@@ -406,8 +406,6 @@ github.com/json-iterator/go
github.com/jstemmer/go-junit-report
github.com/jstemmer/go-junit-report/formatter
github.com/jstemmer/go-junit-report/parser
# github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1
github.com/kardianos/osext
# github.com/klauspost/compress v0.0.0-20160131094358-f86d2e6d8a77
github.com/klauspost/compress/flate
# github.com/klauspost/cpuid v0.0.0-20160106104451-349c67577817
@@ -454,7 +452,7 @@ github.com/mitchellh/go-wordwrap
github.com/mitchellh/iochan
# github.com/mitchellh/mapstructure v1.2.3
github.com/mitchellh/mapstructure
# github.com/mitchellh/panicwrap v0.0.0-20170106182340-fce601fe5557
# github.com/mitchellh/panicwrap v1.0.0
github.com/mitchellh/panicwrap
# github.com/mitchellh/prefixedio v0.0.0-20151214002211-6e6954073784
github.com/mitchellh/prefixedio
@@ -496,7 +494,7 @@ github.com/profitbricks/profitbricks-sdk-go
github.com/ryanuber/go-glob
# github.com/satori/go.uuid v1.2.0
github.com/satori/go.uuid
# github.com/scaleway/scaleway-sdk-go v1.0.0-beta.6.0.20200903143645-c0ce17a0443d
# github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7
github.com/scaleway/scaleway-sdk-go/api/instance/v1
github.com/scaleway/scaleway-sdk-go/api/marketplace/v1
github.com/scaleway/scaleway-sdk-go/internal/async
+4
View File
@@ -144,6 +144,10 @@ export default [
category: 'conversion',
content: ['can', 'convert', 'try'],
},
{
category: 'kvstore',
content: ['vault'],
},
],
},
'variables',
+2 -1
View File
@@ -3,9 +3,10 @@ const path = require('path')
module.exports = withHashicorp({
defaultLayout: true,
transpileModules: ['is-absolute-url', '@hashicorp/react-mega-nav'],
transpileModules: ['is-absolute-url', '@hashicorp/react-.*'],
mdx: { resolveIncludes: path.join(__dirname, 'pages/partials') },
})({
svgo: { plugins: [{ removeViewBox: false }] },
experimental: {
modern: true,
rewrites: () => [
+21 -8
View File
@@ -1666,6 +1666,27 @@
"resolved": "https://registry.npmjs.org/@hashicorp/react-global-styles/-/react-global-styles-4.4.0.tgz",
"integrity": "sha512-lv6XR2plm2m3+qO6VE+RYquTzOODIt3mQ/1fBT1bn7wsR0qxFiuryW4JfsF94oCGk++LkDkRt/8V742HiT+fHw=="
},
"@hashicorp/react-hashi-stack-menu": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@hashicorp/react-hashi-stack-menu/-/react-hashi-stack-menu-1.0.7.tgz",
"integrity": "sha512-WcPD9T2WjjuAlUmCNG3ed6zmroKC0T9LDf5ocL/IWTI5TSnqtjmlC63066v1YCPytG1B/QMkarFP9SYZUrIJrQ==",
"requires": {
"@hashicorp/react-inline-svg": "^1.0.2",
"slugify": "1.3.4"
},
"dependencies": {
"@hashicorp/react-inline-svg": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@hashicorp/react-inline-svg/-/react-inline-svg-1.0.2.tgz",
"integrity": "sha512-AAFnBslSTgnEr++dTbMn3sybAqvn7myIj88ijGigF6u11eSRiV64zqEcyYLQKWTV6dF4AvYoxiYC6GSOgiM0Yw=="
},
"slugify": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/slugify/-/slugify-1.3.4.tgz",
"integrity": "sha512-KP0ZYk5hJNBS8/eIjGkFDCzGQIoZ1mnfQRYS5WM3273z+fxGWXeN0fkwf2ebEweydv9tioZIHGZKoF21U07/nw=="
}
}
},
"@hashicorp/react-head": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@hashicorp/react-head/-/react-head-1.1.1.tgz",
@@ -1693,14 +1714,6 @@
"is-absolute-url": "^3.0.3"
}
},
"@hashicorp/react-mega-nav": {
"version": "4.0.1-2",
"resolved": "https://registry.npmjs.org/@hashicorp/react-mega-nav/-/react-mega-nav-4.0.1-2.tgz",
"integrity": "sha512-uDw+vk6YBDSR9sZoZa3oYd0N15UzYpuGLV1/2lofM6O4/IhEkWlGlsyWpzWABV+pcHBB4KOqnCUxpvmS9Ar61g==",
"requires": {
"@hashicorp/react-inline-svg": "^1.0.0"
}
},
"@hashicorp/react-product-downloader": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@hashicorp/react-product-downloader/-/react-product-downloader-4.0.2.tgz",
+1 -1
View File
@@ -10,8 +10,8 @@
"@hashicorp/react-docs-page": "4.0.0",
"@hashicorp/react-docs-sidenav": "3.2.5",
"@hashicorp/react-global-styles": "4.4.0",
"@hashicorp/react-hashi-stack-menu": "^1.0.7",
"@hashicorp/react-head": "1.1.1",
"@hashicorp/react-mega-nav": "4.0.1-2",
"@hashicorp/react-product-downloader": "4.0.2",
"@hashicorp/react-search": "^2.1.0",
"@hashicorp/react-section-header": "2.0.0",
+2 -2
View File
@@ -2,7 +2,7 @@ import './style.css'
import '@hashicorp/nextjs-scripts/lib/nprogress/style.css'
import ProductSubnav from 'components/subnav'
import MegaNav from '@hashicorp/react-mega-nav'
import HashiStackMenu from '@hashicorp/react-hashi-stack-menu'
import Footer from 'components/footer'
import Error from './_error'
import Head from 'next/head'
@@ -44,7 +44,7 @@ export default function App({ Component, pageProps }) {
{ href: '/fonts/dejavu/mono.woff2', as: 'font' },
]}
/>
<MegaNav product="Packer" />
<HashiStackMenu />
<ProductSubnav />
<div className="content">
<Component {...pageProps} />
+3 -2
View File
@@ -33,8 +33,6 @@ builder.
@include 'builder/alicloud/ecs/AlicloudAccessConfig-not-required.mdx'
@include 'builder/alicloud/ecs/AlicloudDiskDevice-not-required.mdx'
@include 'builder/alicloud/ecs/AlicloudDiskDevices-not-required.mdx'
@include 'builder/alicloud/ecs/RunConfig-not-required.mdx'
@@ -49,6 +47,9 @@ builder.
@include 'helper/communicator/SSH-Agent-Auth-not-required.mdx'
# Disk Devices Configuration:
@include 'builder/alicloud/ecs/AlicloudDiskDevice-not-required.mdx'
## Basic Example
Here is a basic example for Alicloud.
+7 -47
View File
@@ -43,52 +43,11 @@ can also be supplied to override the typical auto-generated key:
### Required:
- `organization_id` (string) - 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](https://cloud.scaleway.com/#/account) of the
control panel.
Previously named: `api_access_key` with environment variable: `SCALEWAY_API_ACCESS_KEY`
- `api_token` (string) - 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](https://cloud.scaleway.com/#/credentials) of the control panel.
- `image` (string) - 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](https://api-marketplace.scaleway.com/images)
get the complete list of the accepted image UUID.
- `region` (string) - The name of the region to launch the server in (`par1`
or `ams1`). Consequently, this is the region where the snapshot will be
available.
- `commercial_type` (string) - 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`
@include 'builder/scaleway/Config-required.mdx'
### Optional:
- `server_name` (string) - The name assigned to the server. Default
`packer-UUID`
- `image_name` (string) - The name of the resulting image that will appear in
your account. Default `packer-TIMESTAMP`
- `snapshot_name` (string) - The name of the resulting snapshot that will
appear in your account. Default `packer-TIMESTAMP`
- `boottype` (string) - The type of boot, can be either `local` or
`bootscript`. Default `local`
- `bootscript` (string) - The id of an existing bootscript to use when
booting the server.
- `remove_volume` (boolean) - Force Packer to delete volume associated with
the resulting snapshot after the build. Default `false`.
@include 'builder/scaleway/Config-not-required.mdx'
## Basic Example
@@ -98,11 +57,12 @@ access tokens:
```json
{
"type": "scaleway",
"organization_id": "YOUR ORGANIZATION ID",
"api_token": "YOUR TOKEN",
"project_id": "YOUR PROJECT ID",
"access_key": "YOUR ACCESS KEY",
"secret_key": "YOUR SECRET KEY",
"image": "UUID OF THE BASE IMAGE",
"region": "par1",
"commercial_type": "START1-S",
"zone": "fr-par-1",
"commercial_type": "DEV1-S",
"ssh_username": "root",
"ssh_private_key_file": "~/.ssh/id_rsa"
}
@@ -280,7 +280,7 @@ Minimal example of usage:
</Tab>
</Tabs>
## Working with Clusters
## Working With Clusters And Hosts
#### Standalone Hosts
@@ -290,7 +290,7 @@ Minimal example of usage to import a OVF template:
@include 'helper/communicator/WinRM-not-required.mdx'
## Working with Clusters
## Working With Clusters And Hosts
#### Standalone Hosts
@@ -17,8 +17,8 @@ To use builders in a `build` block you can either:
- Set the `sources` array of string with references to pre-defined sources.
- Define [build-level `source` blocks](/docs/from-1.5/blocks/build/source) or
`sources` to use builders. This also allows you to set specific fields.
- Define [build-level `source` blocks](/docs/from-1.5/blocks/build/source).
This also allows you to set specific fields.
`@include 'from-1.5/builds/example-block.mdx'`
@@ -19,10 +19,10 @@ block](/docs/from-1.5/blocks/build), for example :
```hcl
build {
source = [
sources = [
# Here Packer will use a default ami_name when saving the image.
"sources.amazon-ebs.example",
"sources.amazon-ebs.foo",
"source.amazon-ebs.example",
"source.amazon-ebs.foo",
]
}
```
@@ -32,7 +32,7 @@ set specific source fields.
```hcl
build {
source "sources.amazon-ebs.example" {
source "source.amazon-ebs.example" {
# Here Packer will use the provided ami_name instead of defaulting it.
ami_name = "specific"
}
@@ -18,14 +18,28 @@ Build variables will allow you to access connection information and basic instan
All special build variables are stored in the `build` variable:
```hcl
provisioner "shell" {
environment_vars = ["TESTVAR=${build.PackerRunUUID}"]
inline = ["echo $TESTVAR"]
source "null" "first-example" {
communicator = "none"
}
build {
name = "my-build-name"
sources = ["null.first-example"]
provisioner "shell-local" {
environment_vars = ["TESTVAR=${build.PackerRunUUID}"]
inline = ["echo source.name is ${source.name}.",
"echo build.name is ${build.name}.",
"echo build.PackerRunUUID is $TESTVAR"]
}
}
```
Here is the list of available build variables:
- **name** Represents the name of the build block being run. This is different
than the name of the source block being run.
- **ID**: Represents the vm being provisioned. For example, in Amazon it is the instance id; in digitalocean,
it is the droplet id; in Vmware, it is the vm name.
+3 -4
View File
@@ -65,10 +65,9 @@ Whenever the distinction isn't relevant, the Packer documentation uses each
pair of terms interchangeably (with a historical preference for "list" and
"map").
However, module authors and provider developers should understand the
differences between these similar types (and the related `set` type), since they
offer different ways to restrict the allowed values for input variables and
source arguments.
However, plugin authors should understand the differences between these similar
types (and the related `set` type), since they offer different ways to restrict
the allowed values for input variables and source arguments.
### Type Conversion
@@ -0,0 +1,6 @@
---
layout: docs
page_title: keystore - Functions - Configuration Language
sidebar_title: Key Store Functions
description: Overview of available keystore functions
---
@@ -46,7 +46,7 @@ stored at the key `foo`, storing it as the local variable `local.foo`.
In order for this to work, you must set the environment variables `VAULT_TOKEN`
and `VAULT_ADDR` to valid values.
-> **NOTE:** HCL functions can be used in local variable definitions or inline
-> **NOTE:** HCL functions can be used in local variable definitions or inline
with a provisioner/post-processor. They cannot be used in global variable definitions.
The api tool we use allows for more custom configuration of the Vault client via
@@ -73,4 +73,4 @@ The full list of available environment variables is:
```
and detailed documentation for usage of each of those variables can be found
[here](https://www.vaultproject.io/docs/commands/#environment-variables).
[here](https://www.vaultproject.io/docs/commands/#environment-variables).
@@ -1,6 +0,0 @@
---
layout: docs
page_title: vault - Functions - Configuration Language
sidebar_title: vault Functions
description: Overview of available vault functions
---
+29 -26
View File
@@ -20,13 +20,18 @@ syntax is useful when generating portions of a configuration programmatically,
since existing JSON libraries can be used to prepare the generated
configuration files.
This syntax is not to be confused with the pre-version-1.5 "legacy" Packer
templates, which were exclusively JSON and follow a different format.
The JSON syntax is defined in terms of the native syntax. Everything that can
be expressed in native syntax can also be expressed in JSON syntax, but some
constructs are more complex to represent in JSON due to limitations of the
JSON grammar.
Packer expects native syntax for files named with a `.pkr.hcl` suffix, and JSON
syntax for files named with a `.pkr.json` suffix.
syntax for files named with a `.pkr.json` suffix. If you leave out the `.pkr`
portion of suffix, Packer will try to read your json file as a legacy Packer
template.
The low-level JSON syntax, just as with the native syntax, is defined in terms
of a specification called _HCL_. It is not necessary to know all of the details
@@ -168,15 +173,15 @@ source "amazon-ebs" "example" {
When the nested block type requires one or more labels, or when multiple
blocks of the same type can be given, the mapping gets a little more
complicated. For example, the `provisioner` nested block type used
within `source` blocks expects a label giving the provisioner to use,
within `build` blocks expects a label giving the provisioner to use,
and the ordering of provisioner blocks is significant to decide the order
of operations.
The following native syntax example shows a `source` block with a number
The following native syntax example shows a `build` block with a number
of provisioners of different types:
```hcl
source "amazon-ebs" "example" {
build {
# (source configuration omitted for brevity)
provisioner "shell-local" {
@@ -200,29 +205,27 @@ this JSON equivalent of the above:
```json
{
"source": {
"amazon-ebs": {
"example": {
"provisioner": [
{
"shell-local": {
"inline": ["echo 'Hello World' >example.txt"]
}
},
{
"file": {
"source": "example.txt",
"destination": "/tmp/example.txt"
}
},
{
"shell": {
"inline": ["sudo install-something -f /tmp/example.txt"]
}
}
]
"build": {
"//": "(source configuration omitted for brevity)",
"provisioner": [
{
"shell-local": {
"inline": ["echo 'Hello World' >example.txt"]
}
},
{
"file": {
"source": "example.txt",
"destination": "/tmp/example.txt"
}
},
{
"shell": {
"inline": ["sudo install-something -f /tmp/example.txt"]
}
}
}
]
}
}
```
+10 -69
View File
@@ -177,71 +177,10 @@ The `-var` option can be used any number of times in a single command.
If you plan to assign variables via the command line, we strongly recommend that
you at least set a default type instead of using empty blocks; this helps the
HCL parser understand what is being set.
HCL parser understand what is being set. Otherwise, the interpreter will assume
that any variable set on the command line is a string.
For example:
```hcl
variable "pizza" {
type = string
}
source "null" "example" {
communicator = "none"
}
build {
sources = [
"source.null.example"
]
provisioner "shell-local" {
inline = ["echo $PIZZA"]
environment_vars = ["PIZZA=${var.pizza}"]
}
}
```
If you call the above template using the command
```sh
packer build -var pizza=pineapple shell_local_variables.pkr.hcl
```
then the Packer build will run successfully. However, if you define the variable
using an empty block, the parser will not know what type the variable is, and it
cannot infer the type from the command line, as shown in this example:
```hcl
variable "pizza" {}
source "null" "example" {
communicator = "none"
}
build {
sources = [
"source.null.example"
]
provisioner "shell-local" {
inline = ["echo $PIZZA"]
environment_vars = ["PIZZA=${var.pizza}"]
}
}
```
The above template will result in the error:
```
Error: Variables not allowed
on <value for var.pizza from arguments> line 1:
(source code not available)
Variables may not be used here.
```
You can work around this either by quoting the variable on the command line, or
by adding the type to the variable block as shown in the previous example.
Setting the expected type is the more resilient option.
```sh
packer build -var 'pizza="pineapple"' shell_local_variables.pkr.hcl
```
### Variable Definitions (`.pkrvars.hcl`) Files
### Variable Definitions (`.pkrvars.hcl` and `.auto.pkrvars.hcl`) Files
To set lots of variables, it is more convenient to specify their values in a
_variable definitions file_ (with a filename ending in either `.pkrvars.hcl` or
@@ -330,18 +269,20 @@ files.
### Variable Definition Precedence
The above mechanisms for setting variables can be used together in any
combination. If the same variable is assigned multiple values, Packer uses the
_last_ value it finds, overriding any previous values. Note that the same
variable cannot be assigned multiple values within a single source.
combination.
Packer loads variables in the following order, with later sources taking
precedence over earlier ones:
- Environment variables
- Environment variables (lowest priority)
- Any `*.auto.pkrvars.hcl` or `*.auto.pkrvars.json` files, processed in lexical
order of their filenames.
- Any `-var` and `-var-file` options on the command line, in the order they are
provided.
provided. (highest priority)
If the same variable is assigned multiple values using different mechanisms,
Packer uses the _last_ value it finds, overriding any previous values. Note
that the same variable cannot be assigned multiple values within a single source.
~> **Important:** Variables with map and object values behave the same way as
other variables: the last value found overrides the previous values.
+146 -2
View File
@@ -25,6 +25,10 @@ accept jinja2 `{{ function }}` macro syntax in a way that can be preserved to
the Ansible run. If you need to set variables using Ansible macros, you need to
do so inside your playbooks or inventory files.
Please see the [Debugging](#debugging), [Limitations](#limitations), or [Troubleshooting](#troubleshooting) if you are having trouble
getting started.
## Basic Example
This is a fully functional template that will provision an image on
@@ -575,8 +579,7 @@ Example Packer template:
"groups": [ "webserver" ],
"playbook_file": "./webserver.yml",
"extra_arguments": [
"--extra-vars",
"ansible_host={{user `ansible_host`}} ansible_connection={{user `ansible_connection`}}"
"--extra-vars", "ansible_host={{user `ansible_host`}} ansible_connection={{user `ansible_connection`}}"
]
}
]
@@ -630,6 +633,147 @@ Example playbook:
name: httpd
```
### Amazon Session Manager
When trying to use Ansible with Amazon's Session Manager, you may run into an error where Ansible
is unable to connect to the remote Amazon instance if the local proxy adapter for Ansible [use_proxy](#use_proxy) is false.
The error may look something like the following:
```
amazon-ebs: fatal: [default]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: connect to host 127.0.0.1 port 8362: Connection timed out", "unreachable": true}
```
The error is caused by a limitation on using Amazon's SSM default Port Forwarding session which only allows for one
remote connection on the forwarded port. Since Ansible's SSH communication is not using the local proxy adapter
it will try to make a new SSH connection to the same forwarded localhost port and fail.
In order to workaround this issue Ansible can be configured via a custom inventory file to use the AWS session-manager-plugin
directly to create a new session, separate from the one created by Packer, at runtime to connect and remotely provision the instance.
-> **Warning:** Please note that the default region configured for the `aws` cli must match the build region where the instance is being
provisioned otherwise you may run into a TargetNotConnected error. Users can use `AWS_DEFAULT_REGION` to temporarily override
their configured region.
<Tabs>
<Tab heading="JSON">
```json
"provisioners": [
{
"type": "ansible",
"use_proxy": false,
"ansible_env_vars": ["PACKER_BUILD_NAME={{ build_name }}"],
"playbook_file": "./playbooks/playbook_remote.yml",
"inventory_file_template": "{{ .HostAlias }} ansible_host={{ .ID }} ansible_user={{ .User }} ansible_ssh_common_args='-o StrictHostKeyChecking=no -o ProxyCommand=\"sh -c \\\"aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters portNumber=%p\\\"\"'\n"
}
]
```
</Tab>
<Tab heading="HCL2">
```hcl
provisioner "ansible" {
use_proxy = false
playbook_file = "./playbooks/playbook_remote.yml"
ansible_env_vars = ["PACKER_BUILD_NAME={{ build_name }}"]
inventory_file_template = "{{ .HostAlias }} ansible_host={{ .ID }} ansible_user={{ .User }} ansible_ssh_common_args='-o StrictHostKeyChecking=no -o ProxyCommand=\"sh -c \\\"aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters portNumber=%p\\\"\"'\n"
}
```
</Tab>
</Tabs>
Full Packer template example:
<Tabs>
<Tab heading="JSON">
```json
{
"variables": {
"instance_role": "SSMInstanceProfile"
},
"builders": [
{
"type": "amazon-ebs",
"region": "us-east-1",
"ami_name": "packer-ami-ansible",
"instance_type": "t2.micro",
"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
},
"communicator": "ssh",
"ssh_username": "ubuntu",
"ssh_interface": "session_manager",
"iam_instance_profile":"{{user `instance_role`}}"
}
],
"provisioners": [
{
"type": "ansible",
"use_proxy": false,
"ansible_env_vars": ["PACKER_BUILD_NAME={{ build_name }}"],
"playbook_file": "./playbooks/playbook_remote.yml",
"inventory_file_template": "{{ .HostAlias }} ansible_host={{ .ID }} ansible_user={{ .User }} ansible_ssh_common_args='-o StrictHostKeyChecking=no -o ProxyCommand=\"sh -c \\\"aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters portNumber=%p\\\"\"'\n"
}
]
}
```
</Tab>
<Tab heading="HCL2">
```hcl
variables {
instance_role = "SSMInstanceProfile"
}
source "amazon-ebs" "ansible-example" {
region = "us-east-1"
ami_name = "packer-ami-ansible"
instance_type = "t2.micro"
source_ami_filter {
filters = {
name = "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*"
virtualization-type = "hvm"
root-device-type = "ebs"
}
owners = [ "099720109477" ]
most_recent = true
}
communicator = "ssh"
ssh_username = "ubuntu"
ssh_interface = "session_manager"
iam_instance_profile = var.instance_role
}
build {
sources = ["source.amazon-ebs.ansible-example"]
provisioner "ansible" {
use_proxy = false
playbook_file = "./playbooks/playbook_remote.yml"
ansible_env_vars = ["PACKER_BUILD_NAME={{ build_name }}"]
inventory_file_template = "{{ .HostAlias }} ansible_host={{ .ID }} ansible_user={{ .User }} ansible_ssh_common_args='-o StrictHostKeyChecking=no -o ProxyCommand=\"sh -c \\\"aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters portNumber=%p\\\"\"'\n"
}
}
```
</Tab>
</Tabs>
### Troubleshooting
If you are using an Ansible version >= 2.8 and Packer hangs in the
+26 -11
View File
@@ -13,8 +13,22 @@ description: |-
@include 'guides/hcl2-beta-note.mdx'
We will soon provide a programatic way to transpose a v1 buildfile to a v1.5
HCL file. In the meantime we will show how to manually do it.
As of v1.6.4, Packer provides a tool to help you convert legacy JSON files to
HCL2 files. To run it, you can use the `hcl2_upgrade` command.
for example,
```sh
packer hcl2_upgrade mytemplate.json
```
will convert your packer template to a new HCL2 file in your current working
directory named mytemplate.json.pkr.hcl. It is not a perfect converter yet;
please open an issue if you find a problem with the conversion. Packer will not
destroy your legacy json template, so this is not a risky command to call.
Following is an explanation of how to manually upgrade a JSON template to an
HCL2 template.
The following file :
@@ -143,6 +157,7 @@ repeatable blocks with the same identifier. For example:
}
],
}
]
```
Becomes:
@@ -162,19 +177,19 @@ source "amazon-ebs" "example" {
delete_on_termination = true
encrypted = true
}
}
```
There is soon going to be a PR to drop the `s` at the end of these fields.
### Deprecation
The current layout of buildfiles will be supported until we and the community
love the new format. Only then the v1 format will be carefully deprecated.
As we become more confident in the new templates, we may begin to add new
features that are HCL2-only; one of our major motivations to moving to the new
template format is that HCL2 provides us with the flexibility to implement some
features which would be very difficult to add to the legacy JSON templates.
-> **Note:** The HCL parsing library can read JSON and if it is your
configuration format of predilection, you will still be able to do it. You will
have to tweak a few things in order to use future versions of Packer that have
deprecated the current format. Sorry about that! Because the HCL reading code
is generated from the JSON parsing settings; every builder, provisioner and
post-processor setting should look and work the same. A config file transposer
is currently in the making.
However, the Packer team will continue to support the main functionality of the
current "legacy JSON" packer templates alongside the new HCL2 templates until
we and the community love the new templates. Only then the v1 format will be
deprecated. We do not anticipate this happening until late 2021 at the earliest.
+176 -112
View File
@@ -18,54 +18,131 @@ Local variables can be a compound of input variables and local variables.
## Defining Variables and locals
Let's create a file `variables.pkr.hcl` with the following contents.
In the legacy JSON packer templates, any variables we hadn't already defined in
the "variables" stanza of our json template could simply be passed in via the
command line or a var-file; if a variable was never defined it would generally
be interpolated to an empty string.
*In the HCL2 packer templates, we must always pre-define our variables in the
HCL equivalent of the "variables" stanza.*
Another difference between JSON and HCL packer templates is that in JSON packer
templates, the "variables" stanza, if used, was always in the same .json file
as the builds and builders. In HCL, it can exist in its own file if you want it
to.
To demonstrate, let's create a file `variables.pkr.hcl` with the following
contents.
-> **Note**: that the file can be named anything, since Packer loads all
files ending in `.pkr.hcl` in a directory. If you split your configuration
across multiple files, use `packer build <source directory>` to initiate
a build.
across multiple files, use
`packer build <command line flags> <source directory>` to initiate a build.
```hcl
# variables.pkr.hcl
// variables.pkr.hcl
variable "access_key" {}
variable "secret_key" {}
variable "region" {
default = "us-east-1"
// For those variables that you don't provide a default for, you must
// set them from the command line, a var-file, or the environment.
variable "weekday" {}
variable "sudo_password" {
type = string
default = "mypassword"
// Sensitive vars are hidden from output as of Packer v1.6.5
sensitive = true
}
variable "flavor" {
type = string
default = "strawberry"
}
variable "exit_codes" {
type = list(number)
default = [0]
}
locals {
debian_ami_name = "${var.image_id}-debian"
ice_cream_flavor = "${var.flavor}-ice-cream"
foo = "bar"
}
```
This defines three variables within your Packer configuration. The first
two have empty blocks `{}`. The third sets a default. If a default value is
set, the variable is optional. Otherwise, the variable is required.
This also defines two locals: `debian_ami_name` and `foo`.
This defines several variables within your Packer configuration, each showing
off a different way to set them. The first variable, "weekday", is an empty
block `{}`, without a type or a default.
-> **Note**: that it is _not_ possible to use variables in a variable definition
but it _is_ possible to use locals and variables in a local definition.
However, it's generally best to provide the type in your variable definition,
as you can see in variable "flavor", which we have given a type of "string",
and variable "exit_codes", which we have given a type of "list(number)",
meaning it is a list/array of numbers.
When a variable is passed from the cli or environment and the variable's type
is not set, Packer will expect it to be a string. But if it is passed from a
var-file where Packer can interpret HCL properly it can be a slice or any
supported type.
In addition to setting the type, the "flavor" and "exit_codes" variables also
provide a default. If you set a default value, then you don't need to set the
variable at run time. Packer will use a provided command-line var,
var-file, or environment var if it exists, but if not Packer will fall back to
this default value.
If you do not set a default value, Packer will fail immediately when you try to
run a `build` if you have not provided the missing variable via the
command-line, a var-file, or the environment. The `validate`, `inspect` and
`console` commands will work, but variables with unknown values will be
`<unknown>`.
This also defines two locals: `ice_cream_flavor` and `foo`.
-> **Note**: that it is _not_ possible to reference a variable in the
definition of another variable. But it _is_ possible to use locals and
variables in the definition of a local, as shown in the ice_cream_flavor
definition.
## Using Variables and locals in Configuration
Next, you can define a source using the variables :
For simplicity's sake, we're going to put a null source in the same file as
we are putting the build configuration. This file demonstrates how to use the
variables we previously defined.
```hcl
# source.pkr.hcl
// null_example.pkr.hcl
source "amazon-ebs" "debian" {
ami_name = local.debian_ami_name
access_key = var.aws_access_key
secret_key = "${var.aws_secret_key}"
region = "${var.aws_region}"
source "null" "example" {
communicator = "none"
}
build {
sources = [
"source.null.example"
]
provisioner "shell-local" {
// Note that for options that are documented as template engines,
// we still have to use the golang template engine syntax rather than our
// specialized HCL2 variable syntax. This example shows a combination of
// an HCL2 variable and the golang template engines built into the
// execute_command option
execute_command = ["/bin/sh", "-c", "echo ${var.sudo_password}| {{.Vars}} {{.Script}}"]
environment_vars = ["HELLO_USER=packeruser", "UUID=${build.PackerRunUUID}"]
inline = ["echo the Packer run uuid is $UUID"]
}
provisioner "shell-local" {
inline = ["echo var.flavor is: ${var.flavor}",
"echo local.ice_cream_flavor is: ${local.ice_cream_flavor}"]
valid_exit_codes = var.exit_codes
}
}
```
This uses more interpolations, this time prefixed with `var.` and `local.`.
This tells Packer that you're accessing variables. This configures the builder
with the given variables.
As you can see in the example, you can access your variables directly by
giving them the `var.` or `local.` prefix. If you want to embed the variables
in a string, you can do so with the `${}` HCL interpolation syntax. If you are
using an option that is a template engine, you still need to use the golang
templating engine syntax `{{ .OPTION }}` for those engines.
## Assigning Variables
@@ -80,86 +157,18 @@ You can set variables directly on the command-line with the
```shell-session
$ packer build \
-var 'access_key=foo' \
-var 'secret_key=bar'
# ...
-var 'weekday=Sunday' \
-var 'flavor=chocolate' \
-var 'sudo_password=hunter42' .
```
Once again, setting variables this way will not save them, and they'll
have to be input repeatedly as commands are executed.
If you plan to assign variables via the command line, we strongly recommend that
you at least set a default type instead of using empty blocks; this helps the
HCL parser understand what is being set.
For example:
```hcl
variable "pizza" {
type = string
}
source "null" "example" {
communicator = "none"
}
build {
sources = [
"source.null.example"
]
provisioner "shell-local" {
inline = ["echo $PIZZA"]
environment_vars = ["PIZZA=${var.pizza}"]
}
}
```
If you call the above template using the command
```sh
packer build -var pizza=pineapple shell_local_variables.pkr.hcl
```
then the Packer build will run successfully. However, if you define the variable
using an empty block, the parser will not know what type the variable is, and it
cannot infer the type from the command line, as shown in this example:
```hcl
variable "pizza" {}
source "null" "example" {
communicator = "none"
}
build {
sources = [
"source.null.example"
]
provisioner "shell-local" {
inline = ["echo $PIZZA"]
environment_vars = ["PIZZA=${var.pizza}"]
}
}
```
The above template will result in the error:
```
Error: Variables not allowed
on <value for var.pizza from arguments> line 1:
(source code not available)
Variables may not be used here.
```
You can work around this either by quoting the variable on the command line, or
by adding the type to the variable block as shown in the previous example.
Setting the expected type is the more resilient option.
```sh
packer build -var 'pizza="pineapple"' shell_local_variables.pkr.hcl
```
HCL parser understand what is being set. Otherwise it will interpret all of your
command line variables as strings.
#### From a file
@@ -168,17 +177,48 @@ this file. Create a file named `variables.pkrvars.hcl` with the following
contents:
```hcl
access_key = "foo"
secret_key = "bar"
sudo_password = "partyparrot"
weekday = "Sunday"
```
For all files which match `*.auto.pkrvars.hcl` present in the current
directory, Packer automatically loads them to populate variables. If the file
is named something else, you can use the `-var-file` flag directly to specify a
file. These files are the same syntax as Packer configuration files. And like
Packer configuration files, these files can also be JSON.
You tell Packer to use this var file using the `-var-file` command line flag.
We don't recommend saving usernames and password to version control, but you
```shell-session
$ packer build -var-file="variables.pkrvars.hcl" .
```
Packer will automatically load any var file that matches the name
`*.auto.pkrvars.hcl`, without the need to pass the file via the command line.
if we rename the above var-file from variables.pkrvars.hcl to
variables.auto.pkrvars.hcl, then we can run our build simply by calling
```shell-session
$ packer build .
```
You may provide as many -var-file flags as you would like:
```shell-session
$ packer build \
-var-file="secret.pkrvars.hcl" \
-var-file="production.pkrvars.hcl" .
```
These files can also be JSON:
variables.json:
```json
{
"weekday": "sunday",
"flavor": "mint"
}
```
```shell-session
$ packer build -var-file=variables.json
```
We don't recommend saving sensitive information to version control, but you
can create a local secret variables file and use `-var-file` to load it.
You can use multiple `-var-file` arguments in a single command, with some
@@ -187,7 +227,7 @@ checked in to version control and others not checked in. For example:
```shell-session
$ packer build \
-var-file="secret.pkrvars.hcl" \
-var-file="production.pkrvars.hcl"
-var-file="production.pkrvars.hcl" .
```
#### From environment variables
@@ -196,18 +236,42 @@ Packer will read environment variables in the form of `PKR_VAR_name` to find
the value for a variable. For example, the `PKR_VAR_access_key` variable can be
set to set the `access_key` variable.
```shell-session
$ export PKR_VAR_weekday=Monday
$ packer build .
```
#### Variable Defaults
If no value is assigned to a variable via any of these methods and the
variable has a `default` key in its declaration, that value will be used
for the variable.
#### Unspecified values fails
If all of your variables have defaults, then you can call a packer build using:
If you execute `packer build` with certain variables unspecified and those are
used somewhere, Packer will error.
```shell-session
$ packer build .
```
## Lists
You can make this work for yourself using the variable example file above by
commenting out or removing the "weekday" variable declaration, since it is not
actually used in the example build.
If your variable definitions are stored in the same file as your source and
build, you can call the build against that specific file:
```shell-session
$ packer build self_contained_example.pkr.hcl
```
#### Unspecified Values Fail
If you call `packer build` with any variables defined but not set, Packer will
error.
## Variable Type Reference
### Lists
Lists are defined either explicitly or implicitly
@@ -225,7 +289,7 @@ You can specify lists in a `variables.pkrvars.hcl` file:
cidrs = [ "10.0.0.0/16", "10.1.0.0/16" ]
```
## Maps
### Maps
Maps are a way to create variables that are lookup tables. An example
will show this best. Let's extract our AMIs into a map and add
@@ -6,8 +6,7 @@
., _ and -. The disk name will appear on the console. It cannot
begin with `http://` or `https://`.
- `disk_category` (string) - Category of the system disk. Optional values
are:
- `disk_category` (string) - Category of the system disk. Optional values are:
- cloud - general cloud disk
- cloud_efficiency - efficiency cloud disk
- cloud_ssd - cloud SSD
@@ -19,6 +18,8 @@
- `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.
This field is only used in the ECSImagesDiskMappings option, not
the ECSSystemDiskMapping option.
- `disk_description` (string) - The value of disk description is blank by
default. [2, 256] characters. The disk description will appear on the
@@ -31,8 +32,9 @@
such as /dev/xvdb It is null unless the Status is In_use.
- `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
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.
it was in the source image. Please refer to Introduction of ECS disk
encryption for more details.
@@ -0,0 +1,4 @@
<!-- Code generated from the comments of the AlicloudDiskDevice struct in builder/alicloud/ecs/image_config.go; DO NOT EDIT MANUALLY -->
The "AlicloudDiskDevice" object us used for the `ECSSystemDiskMapping` and
`ECSImagesDiskMappings` options, and contains the following fields:
@@ -1,79 +1,35 @@
<!-- Code generated from the comments of the AlicloudDiskDevices struct in builder/alicloud/ecs/image_config.go; DO NOT EDIT MANUALLY -->
- `system_disk_mapping` (AlicloudDiskDevice) - 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
- `system_disk_mapping` (AlicloudDiskDevice) - Image disk mapping for the system disk.
See the [disk device configuration](#disk-devices-configuration) section
for more information on options.
Usage example:
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}.
```json
"builders": [{
"type":"alicloud-ecs",
"system_disk_mapping": {
"disk_size": 50,
"disk_name": "mydisk"
},
...
}
```
- `image_disk_mappings` ([]AlicloudDiskDevice) - Add one or more data
disks to the image.
- `image_disk_mappings` ([]AlicloudDiskDevice) - Add one or more data disks to the image.
See the [disk device configuration](#disk-devices-configuration) section
for more information on options.
Usage example:
- `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.
```json
"builders": [{
"type":"alicloud-ecs",
"image_disk_mappings": [
{
"disk_snapshot_id": "someid",
"disk_device": "dev/xvdb"
}
],
...
}
```
@@ -0,0 +1,4 @@
<!-- Code generated from the comments of the AlicloudDiskDevices struct in builder/alicloud/ecs/image_config.go; DO NOT EDIT MANUALLY -->
The "AlicloudDiskDevices" object is used to define disk mappings for your
instance.
@@ -2,4 +2,4 @@
- `target_regions` ([]TargetRegion) - Target Regions
- `exlude_from_latest` (bool) - Exclude From Latest
- `exclude_from_latest` (bool) - Exclude From Latest
@@ -136,19 +136,27 @@
the builder. By default this is output-BUILDNAME where "BUILDNAME" is the
name of the build.
- `qemuargs` ([][]string) - 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
- `qemuargs` ([][]string) - Allows complete control over the qemu command line (though not 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.
beware of conflicting arguments causing failures of your run.
For instance adding a "--drive" or "--device" override will mean that
none of the default configuration Packer sets will be used. To see the
defaults that Packer sets, look in your packer.log
file (set PACKER_LOG=1 to get verbose logging) and search for the
qemu-system-x86 command. The arguments are all printed for review, and
you can use those arguments along with the template engines allowed
by qemu-args to set up a working configuration that includes both the
Packer defaults and your extra arguments.
Another pitfall could be setting arguments like --no-acpi, which could
break the ability to send power signal type commands
(e.g., shutdown -P now) to the virtual machine, thus preventing proper
shutdown.
The following shows a sample usage:
@@ -16,9 +16,8 @@
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.
The marketplace image label (eg `ubuntu_focal`) also works.
- `commercial_type` (string) - 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
C1, C2L, C2M, C2S, DEV1-S, DEV1-M, DEV1-L, DEV1-XL,
GP1-XS, GP1-S, GP1-M, GP1-L, GP1-XL, RENDER-S
@@ -4,15 +4,18 @@
- `folder` (string) - VM folder to create the VM in.
- `cluster` (string) - ESXi cluster where target VM is created. See
[Working with Clusters](#working-with-clusters).
- `cluster` (string) - ESXi cluster where target VM is created. See the
[Working With Clusters And Hosts](#working-with-clusters-and-hosts)
section above for more details.
- `host` (string) - ESXi host where target VM is created. A full path must be specified if
the host is in a folder. For example `folder/host`. See the
`Specifying Clusters and Hosts` section above for more details.
[Working With Clusters And Hosts](#working-with-clusters-and-hosts)
section above for more details.
- `resource_pool` (string) - VMWare resource pool. If not set, it will look for the root resource pool of the `host` or `cluster`.
If a root resource is not found, it will then look for a default resource pool.
- `resource_pool` (string) - VMWare resource pool. If not set, it will look for the root resource
pool of the `host` or `cluster`. If a root resource is not found, it
will then look for a default resource pool.
- `datastore` (string) - VMWare datastore. Required if `host` is a cluster, or if `host` has
multiple datastores.
@@ -3,6 +3,6 @@
Once a variable is declared in your configuration, you can set it:
- Individually, with the `-var foo=bar` command line option.
- In variable definitions (`.pkrvars.hcl`) files, either specified on the
command line or automatically loaded.
- In variable definitions (`.pkrvars.hcl` and `.auto.pkrvars.hcl`) files,
either specified on the command line or automatically loaded.
- As environment variables, for example: `PKR_VAR_foo=bar`
@@ -5,6 +5,7 @@ Take the following variable for example:
```hcl
variable "foo" {
type = string
}
```
Here `foo` must have a known value but you can default it to `null` to make
-1
View File
@@ -15,7 +15,6 @@
@import '~@hashicorp/react-content/dist/style.css';
@import '~@hashicorp/react-docs-page/style.css';
@import '~@hashicorp/react-docs-sidenav/dist/style.css';
@import '~@hashicorp/react-mega-nav/style.css';
@import '~@hashicorp/react-product-downloader/dist/style.css';
@import '~@hashicorp/react-search/dist/style.css';
@import '~@hashicorp/react-section-header/dist/style.css';