Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e0e9b26457 | |||
| 155d6c2e32 | |||
| 105173a7c7 | |||
| b82704cc70 | |||
| c2b2bb2271 | |||
| 8445b6ff20 |
@@ -2,10 +2,6 @@
|
||||
|
||||
### 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]
|
||||
@@ -18,12 +14,9 @@
|
||||
|
||||
### 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)
|
||||
|
||||
|
||||
@@ -12,8 +12,6 @@ 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
|
||||
@@ -21,7 +19,8 @@ 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
|
||||
@@ -33,8 +32,6 @@ 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
|
||||
@@ -47,51 +44,94 @@ 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 the system disk.
|
||||
// See the [disk device configuration](#disk-devices-configuration) section
|
||||
// for more information on options.
|
||||
// Usage example:
|
||||
// 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}.
|
||||
//
|
||||
// ```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.
|
||||
// See the [disk device configuration](#disk-devices-configuration) section
|
||||
// for more information on options.
|
||||
// Usage example:
|
||||
// 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.
|
||||
//
|
||||
// ```json
|
||||
// "builders": [{
|
||||
// "type":"alicloud-ecs",
|
||||
// "image_disk_mappings": [
|
||||
// {
|
||||
// "disk_snapshot_id": "someid",
|
||||
// "disk_device": "dev/xvdb"
|
||||
// }
|
||||
// ],
|
||||
// ...
|
||||
// }
|
||||
// ```
|
||||
ECSImagesDiskMappings []AlicloudDiskDevice `mapstructure:"image_disk_mappings" required:"false"`
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -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
@@ -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,9 +16,8 @@ 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:"exclude_from_latest"`
|
||||
ExcludeFromLatestTypo bool `mapstructure:"exlude_from_latest" undocumented:"true"`
|
||||
TargetRegions []TargetRegion `mapstructure:"target_regions"`
|
||||
ExcludeFromLatest bool `mapstructure:"exlude_from_latest"`
|
||||
}
|
||||
|
||||
// TargetRegion describes a region where the shared image should be replicated
|
||||
@@ -62,10 +61,5 @@ 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,13 +9,12 @@ 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:"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"`
|
||||
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"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatSharedImageGalleryDestination.
|
||||
@@ -30,13 +29,12 @@ 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())},
|
||||
"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},
|
||||
"resource_group": &hcldec.AttrSpec{Name: "resource_group", Type: cty.String, Required: false},
|
||||
"gallery_name": &hcldec.AttrSpec{Name: "gallery_name", Type: cty.String, Required: false},
|
||||
"image_name": &hcldec.AttrSpec{Name: "image_name", Type: cty.String, Required: false},
|
||||
"image_version": &hcldec.AttrSpec{Name: "image_version", Type: cty.String, Required: false},
|
||||
"target_regions": &hcldec.BlockListSpec{TypeName: "target_regions", Nested: hcldec.ObjectSpec((*FlatTargetRegion)(nil).HCL2Spec())},
|
||||
"exlude_from_latest": &hcldec.AttrSpec{Name: "exlude_from_latest", Type: cty.Bool, Required: false},
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -21,13 +21,12 @@ 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
|
||||
ExcludeFromLatestTypo bool
|
||||
ResourceGroup string
|
||||
GalleryName string
|
||||
ImageName string
|
||||
ImageVersion string
|
||||
TargetRegions []TargetRegion
|
||||
ExcludeFromLatest bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -67,29 +66,6 @@ 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{
|
||||
@@ -129,13 +105,12 @@ 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,
|
||||
ExcludeFromLatestTypo: tt.fields.ExcludeFromLatestTypo,
|
||||
ResourceGroup: tt.fields.ResourceGroup,
|
||||
GalleryName: tt.fields.GalleryName,
|
||||
ImageName: tt.fields.ImageName,
|
||||
ImageVersion: tt.fields.ImageVersion,
|
||||
TargetRegions: tt.fields.TargetRegions,
|
||||
ExcludeFromLatest: tt.fields.ExcludeFromLatest,
|
||||
}
|
||||
gotErrs, gotWarns := sigd.Validate("sigdest")
|
||||
|
||||
|
||||
@@ -252,21 +252,14 @@ 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 {
|
||||
// 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."))
|
||||
}
|
||||
} else if !(hasOnlySourceImage || hasOnlySourceImageName || hasOnlyExternalSourceImageURL) {
|
||||
errs = append(errs, errors.New("Only a source_image, a source_image_name or an external_source_image_url can be specified, not multiple."))
|
||||
}
|
||||
|
||||
// if external_source_image_format is not set use qcow2 as default
|
||||
|
||||
@@ -141,7 +141,6 @@ 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"
|
||||
@@ -150,7 +149,6 @@ 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 = ""
|
||||
@@ -159,7 +157,6 @@ func TestRunConfigPrepare_ExternalSourceImageURL(t *testing.T) {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
c = testRunConfig()
|
||||
// test setting only ExternalSourceImageURL passes
|
||||
c.SourceImage = ""
|
||||
c.SourceImageName = ""
|
||||
@@ -177,27 +174,6 @@ 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
|
||||
|
||||
@@ -192,8 +192,6 @@ 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
|
||||
|
||||
+8
-16
@@ -208,27 +208,19 @@ 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 qemu-img).
|
||||
// Each array of strings makes up a command line switch
|
||||
// Allows complete control over the qemu command line (though not, at this
|
||||
// time, qemu-img). Each array of strings makes up a command line switch
|
||||
// that overrides matching default switch/value pairs. Any value specified
|
||||
// as an empty string is ignored. All values after the switch are
|
||||
// concatenated with no separator.
|
||||
//
|
||||
// ~> **Warning:** The qemu command line allows extreme flexibility, so
|
||||
// beware of conflicting arguments causing failures of your run.
|
||||
// For instance 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.
|
||||
// beware of conflicting arguments causing failures of your run. For
|
||||
// instance, using --no-acpi could break the ability to send power signal
|
||||
// type commands (e.g., shutdown -P now) to the virtual machine, thus
|
||||
// preventing proper shutdown. To see the defaults, look in the packer.log
|
||||
// file and search for the qemu-system-x86 command. The arguments are all
|
||||
// printed for review.
|
||||
//
|
||||
// The following shows a sample usage:
|
||||
//
|
||||
|
||||
+170
-211
@@ -16,45 +16,41 @@ import (
|
||||
// stepRun runs the virtual machine
|
||||
type stepRun struct {
|
||||
DiskImage bool
|
||||
}
|
||||
|
||||
atLeastVersion2 bool
|
||||
ui packer.Ui
|
||||
type qemuArgsTemplateData struct {
|
||||
HTTPIP string
|
||||
HTTPPort int
|
||||
HTTPDir string
|
||||
OutputDir string
|
||||
Name string
|
||||
SSHHostPort int
|
||||
}
|
||||
|
||||
func (s *stepRun) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*Config)
|
||||
driver := state.Get("driver").(Driver)
|
||||
s.ui = state.Get("ui").(packer.Ui)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
// 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
|
||||
// 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"
|
||||
}
|
||||
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"))
|
||||
ui.Say(message)
|
||||
|
||||
s.atLeastVersion2 = qemuVersion.GreaterThanOrEqual(v2)
|
||||
|
||||
// Generate the qemu command
|
||||
command, err := s.getCommandArgs(config, state)
|
||||
command, err := s.getCommandArgs(bootDrive, state)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error processing QemuArgs: %s", err)
|
||||
s.ui.Error(err.Error())
|
||||
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)
|
||||
s.ui.Error(err.Error())
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
@@ -70,187 +66,140 @@ func (s *stepRun) Cleanup(state multistep.StateBag) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *stepRun) getDefaultArgs(config *Config, state multistep.StateBag) map[string]interface{} {
|
||||
func (s *stepRun) 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)
|
||||
|
||||
defaultArgs := make(map[string]interface{})
|
||||
|
||||
// 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
|
||||
var deviceArgs []string
|
||||
var driveArgs []string
|
||||
var commHostPort int
|
||||
|
||||
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
|
||||
|
||||
// Track the connection for the user
|
||||
vncPass, _ := state.Get("vnc_password").(string)
|
||||
|
||||
message = getVncConnectionMessage(config.Headless, vnc, vncPass)
|
||||
if message != "" {
|
||||
s.ui.Message(message)
|
||||
if config.QMPEnable {
|
||||
defaultArgs["-qmp"] = fmt.Sprintf("unix:%s,server,nowait", config.QMPSocketPath)
|
||||
}
|
||||
|
||||
// Configure "-m" memory argument
|
||||
defaultArgs["-m"] = fmt.Sprintf("%dM", config.MemorySize)
|
||||
defaultArgs["-name"] = vmName
|
||||
defaultArgs["-machine"] = fmt.Sprintf("type=%s", config.MachineType)
|
||||
|
||||
// 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)
|
||||
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")
|
||||
}
|
||||
} else {
|
||||
log.Println("Qemu Builder has no floppy files, not attaching a floppy.")
|
||||
defaultArgs["-netdev"] = fmt.Sprintf("bridge,id=user.0,br=%s", config.NetBridge)
|
||||
}
|
||||
|
||||
// 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"
|
||||
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 {
|
||||
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))
|
||||
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)
|
||||
}
|
||||
// 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
|
||||
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
|
||||
}
|
||||
} else if !config.UseDefaultDisplay {
|
||||
defaultArgs["-display"] = "gtk"
|
||||
}
|
||||
} else {
|
||||
ui.Message("WARNING: The version of qemu on your host doesn't support display mode.\n" +
|
||||
"The display parameter will be ignored.")
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@@ -271,48 +220,64 @@ func (s *stepRun) getDeviceAndDriveArgs(config *Config, state multistep.StateBag
|
||||
}
|
||||
}
|
||||
|
||||
return deviceArgs, driveArgs
|
||||
}
|
||||
defaultArgs["-device"] = deviceArgs
|
||||
defaultArgs["-drive"] = driveArgs
|
||||
|
||||
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
|
||||
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.")
|
||||
}
|
||||
|
||||
inArgs := make(map[string][]string)
|
||||
if len(config.QemuArgs) > 0 {
|
||||
s.ui.Say("Overriding default Qemu arguments with qemuargs template option...")
|
||||
ui.Say("Overriding default Qemu arguments with QemuArgs...")
|
||||
|
||||
commHostPort := state.Get("commHostPort").(int)
|
||||
httpIp := state.Get("http_ip").(string)
|
||||
httpPort := state.Get("http_port").(int)
|
||||
|
||||
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,
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
// Interpolate each string in qemuargs
|
||||
newQemuArgs, err := processArgs(config.QemuArgs, &ictx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Qemu supports multiple appearances of the same switch. This means
|
||||
// each key in the args hash will have an array of string values
|
||||
// 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
|
||||
for _, qemuArgs := range newQemuArgs {
|
||||
key := qemuArgs[0]
|
||||
val := strings.Join(qemuArgs[1:], "")
|
||||
@@ -361,12 +326,6 @@ func (s *stepRun) applyUserOverrides(defaultArgs map[string]interface{}, config
|
||||
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
|
||||
|
||||
|
||||
+73
-118
@@ -19,6 +19,8 @@ func runTestState(t *testing.T, config *Config) multistep.StateBag {
|
||||
d.VersionResult = "3.0.0"
|
||||
state.Put("driver", d)
|
||||
|
||||
state.Put("ui", packer.TestUi(t))
|
||||
|
||||
state.Put("commHostPort", 5000)
|
||||
state.Put("floppy_path", "fake_floppy_path")
|
||||
state.Put("http_ip", "127.0.0.1")
|
||||
@@ -52,6 +54,7 @@ func Test_UserOverrides(t *testing.T) {
|
||||
},
|
||||
[]string{
|
||||
"-display", "gtk",
|
||||
"-boot", "once=d",
|
||||
"-drive", "file=/path/to/test.iso,index=0,media=cdrom",
|
||||
"-randomflag1", "127.0.0.1-1234-http/directory",
|
||||
"-randomflag2", "output/directory-myvm",
|
||||
@@ -66,6 +69,7 @@ func Test_UserOverrides(t *testing.T) {
|
||||
},
|
||||
[]string{
|
||||
"-display", "partydisplay",
|
||||
"-boot", "once=d",
|
||||
"-drive", "file=/path/to/test.iso,index=0,media=cdrom",
|
||||
"-device", ",netdev=user.0",
|
||||
},
|
||||
@@ -81,6 +85,7 @@ func Test_UserOverrides(t *testing.T) {
|
||||
"-display", "gtk",
|
||||
"-device", "somerandomdevice",
|
||||
"-device", "mynetdevice,netdev=user.0",
|
||||
"-boot", "once=d",
|
||||
"-drive", "file=/path/to/test.iso,index=0,media=cdrom",
|
||||
},
|
||||
"Net device gets added",
|
||||
@@ -90,18 +95,21 @@ func Test_UserOverrides(t *testing.T) {
|
||||
for _, tc := range testcases {
|
||||
state := runTestState(t, tc.Config)
|
||||
|
||||
step := &stepRun{
|
||||
atLeastVersion2: true,
|
||||
ui: packer.TestUi(t),
|
||||
// figure out boot config
|
||||
bootval := "c"
|
||||
for i, val := range tc.Expected {
|
||||
if val == "-boot" {
|
||||
bootval = tc.Expected[i+1]
|
||||
}
|
||||
}
|
||||
args, err := step.getCommandArgs(tc.Config, state)
|
||||
step := &stepRun{}
|
||||
args, err := step.getCommandArgs(bootval, 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",
|
||||
@@ -128,10 +136,7 @@ func Test_DriveAndDeviceArgs(t *testing.T) {
|
||||
{
|
||||
&Config{},
|
||||
map[string]interface{}{},
|
||||
&stepRun{
|
||||
atLeastVersion2: true,
|
||||
ui: packer.TestUi(t),
|
||||
},
|
||||
&stepRun{},
|
||||
[]string{
|
||||
"-display", "gtk",
|
||||
"-boot", "once=d",
|
||||
@@ -144,7 +149,7 @@ func Test_DriveAndDeviceArgs(t *testing.T) {
|
||||
DiskImage: true,
|
||||
DiskInterface: "virtio-scsi",
|
||||
|
||||
OutputDir: "path_to_output",
|
||||
OutputDir: "/path/to/output",
|
||||
DiskCache: "writeback",
|
||||
Format: "qcow2",
|
||||
DetectZeroes: "off",
|
||||
@@ -152,17 +157,13 @@ func Test_DriveAndDeviceArgs(t *testing.T) {
|
||||
map[string]interface{}{
|
||||
"cd_path": "fake_cd_path.iso",
|
||||
},
|
||||
&stepRun{
|
||||
DiskImage: true,
|
||||
atLeastVersion2: true,
|
||||
ui: packer.TestUi(t),
|
||||
},
|
||||
&stepRun{},
|
||||
[]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", "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",
|
||||
@@ -172,7 +173,7 @@ func Test_DriveAndDeviceArgs(t *testing.T) {
|
||||
DiskImage: true,
|
||||
DiskInterface: "virtio-scsi",
|
||||
|
||||
OutputDir: "path_to_output",
|
||||
OutputDir: "/path/to/output",
|
||||
DiskCache: "writeback",
|
||||
Format: "qcow2",
|
||||
DetectZeroes: "on",
|
||||
@@ -180,17 +181,13 @@ func Test_DriveAndDeviceArgs(t *testing.T) {
|
||||
map[string]interface{}{
|
||||
"cd_path": "fake_cd_path.iso",
|
||||
},
|
||||
&stepRun{
|
||||
DiskImage: true,
|
||||
atLeastVersion2: true,
|
||||
ui: packer.TestUi(t),
|
||||
},
|
||||
&stepRun{},
|
||||
[]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", "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",
|
||||
@@ -199,7 +196,7 @@ func Test_DriveAndDeviceArgs(t *testing.T) {
|
||||
&Config{
|
||||
DiskInterface: "virtio-scsi",
|
||||
|
||||
OutputDir: "path_to_output",
|
||||
OutputDir: "/path/to/output",
|
||||
DiskCache: "writeback",
|
||||
Format: "qcow2",
|
||||
DetectZeroes: "off",
|
||||
@@ -210,10 +207,7 @@ func Test_DriveAndDeviceArgs(t *testing.T) {
|
||||
// disk path: the one we create to be the main disk.
|
||||
"qemu_disk_paths": []string{"qemupath1", "qemupath2"},
|
||||
},
|
||||
&stepRun{
|
||||
atLeastVersion2: true,
|
||||
ui: packer.TestUi(t),
|
||||
},
|
||||
&stepRun{},
|
||||
[]string{
|
||||
"-display", "gtk",
|
||||
"-boot", "once=d",
|
||||
@@ -231,7 +225,7 @@ func Test_DriveAndDeviceArgs(t *testing.T) {
|
||||
&Config{
|
||||
DiskInterface: "virtio-scsi",
|
||||
|
||||
OutputDir: "path_to_output",
|
||||
OutputDir: "/path/to/output",
|
||||
DiskCache: "writeback",
|
||||
Format: "qcow2",
|
||||
DetectZeroes: "on",
|
||||
@@ -242,10 +236,7 @@ func Test_DriveAndDeviceArgs(t *testing.T) {
|
||||
// disk path: the one we create to be the main disk.
|
||||
"qemu_disk_paths": []string{"qemupath1", "qemupath2"},
|
||||
},
|
||||
&stepRun{
|
||||
atLeastVersion2: true,
|
||||
ui: packer.TestUi(t),
|
||||
},
|
||||
&stepRun{},
|
||||
[]string{
|
||||
"-display", "gtk",
|
||||
"-boot", "once=d",
|
||||
@@ -263,7 +254,7 @@ func Test_DriveAndDeviceArgs(t *testing.T) {
|
||||
&Config{
|
||||
DiskInterface: "virtio-scsi",
|
||||
|
||||
OutputDir: "path_to_output",
|
||||
OutputDir: "/path/to/output",
|
||||
DiskCache: "writeback",
|
||||
Format: "qcow2",
|
||||
},
|
||||
@@ -272,10 +263,7 @@ func Test_DriveAndDeviceArgs(t *testing.T) {
|
||||
// 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),
|
||||
},
|
||||
&stepRun{},
|
||||
[]string{
|
||||
"-display", "gtk",
|
||||
"-boot", "once=d",
|
||||
@@ -292,10 +280,7 @@ func Test_DriveAndDeviceArgs(t *testing.T) {
|
||||
"cd_path": "fake_cd_path.iso",
|
||||
"qemu_disk_paths": []string{"output/dir/path/mydisk.qcow2"},
|
||||
},
|
||||
&stepRun{
|
||||
atLeastVersion2: true,
|
||||
ui: packer.TestUi(t),
|
||||
},
|
||||
&stepRun{},
|
||||
[]string{
|
||||
"-display", "gtk",
|
||||
"-boot", "once=d",
|
||||
@@ -312,10 +297,7 @@ func Test_DriveAndDeviceArgs(t *testing.T) {
|
||||
// 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),
|
||||
},
|
||||
&stepRun{},
|
||||
[]string{
|
||||
"-display", "gtk",
|
||||
"-boot", "once=d",
|
||||
@@ -326,30 +308,7 @@ func Test_DriveAndDeviceArgs(t *testing.T) {
|
||||
},
|
||||
{
|
||||
&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",
|
||||
OutputDir: "/path/to/output",
|
||||
DiskInterface: "virtio",
|
||||
DiskCache: "writeback",
|
||||
Format: "qcow2",
|
||||
@@ -358,10 +317,7 @@ func Test_DriveAndDeviceArgs(t *testing.T) {
|
||||
"cd_path": "fake_cd_path.iso",
|
||||
"qemu_disk_paths": []string{"qemupath1", "qemupath2"},
|
||||
},
|
||||
&stepRun{
|
||||
atLeastVersion2: true,
|
||||
ui: packer.TestUi(t),
|
||||
},
|
||||
&stepRun{},
|
||||
[]string{
|
||||
"-display", "gtk",
|
||||
"-boot", "once=d",
|
||||
@@ -375,7 +331,7 @@ func Test_DriveAndDeviceArgs(t *testing.T) {
|
||||
{
|
||||
&Config{
|
||||
DiskImage: true,
|
||||
OutputDir: "path_to_output",
|
||||
OutputDir: "/path/to/output",
|
||||
DiskInterface: "virtio",
|
||||
DiskCache: "writeback",
|
||||
Format: "qcow2",
|
||||
@@ -383,27 +339,30 @@ func Test_DriveAndDeviceArgs(t *testing.T) {
|
||||
map[string]interface{}{
|
||||
"cd_path": "fake_cd_path.iso",
|
||||
},
|
||||
&stepRun{
|
||||
DiskImage: true,
|
||||
atLeastVersion2: true,
|
||||
ui: packer.TestUi(t),
|
||||
},
|
||||
&stepRun{},
|
||||
[]string{
|
||||
"-display", "gtk",
|
||||
"-boot", "c",
|
||||
"-drive", "file=path_to_output,if=virtio,cache=writeback,discard=,format=qcow2,detect-zeroes=",
|
||||
"-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{})
|
||||
state := runTestState(t, tc.Config)
|
||||
for k, v := range tc.ExtraState {
|
||||
state.Put(k, v)
|
||||
}
|
||||
// figure out boot config
|
||||
bootval := "c"
|
||||
for i, val := range tc.Expected {
|
||||
if val == "-boot" {
|
||||
bootval = tc.Expected[i+1]
|
||||
}
|
||||
}
|
||||
|
||||
args, err := tc.Step.getCommandArgs(tc.Config, state)
|
||||
args, err := tc.Step.getCommandArgs(bootval, state)
|
||||
if err != nil {
|
||||
t.Fatalf("should not have an error getting args. Error: %s", err)
|
||||
}
|
||||
@@ -434,11 +393,8 @@ func Test_OptionalConfigOptionsGetSet(t *testing.T) {
|
||||
}
|
||||
|
||||
state := runTestState(t, c)
|
||||
step := &stepRun{
|
||||
atLeastVersion2: true,
|
||||
ui: packer.TestUi(t),
|
||||
}
|
||||
args, err := step.getCommandArgs(c, state)
|
||||
step := &stepRun{}
|
||||
args, err := step.getCommandArgs("once=d", state)
|
||||
if err != nil {
|
||||
t.Fatalf("should not have an error getting args. Error: %s", err)
|
||||
}
|
||||
@@ -475,17 +431,14 @@ func Test_Defaults(t *testing.T) {
|
||||
{
|
||||
&Config{},
|
||||
map[string]interface{}{},
|
||||
&stepRun{ui: packer.TestUi(t)},
|
||||
&stepRun{},
|
||||
[]string{"-boot", "once=d"},
|
||||
"Boot value should default to once=d",
|
||||
},
|
||||
{
|
||||
&Config{},
|
||||
map[string]interface{}{},
|
||||
&stepRun{
|
||||
DiskImage: true,
|
||||
ui: packer.TestUi(t),
|
||||
},
|
||||
&stepRun{},
|
||||
[]string{"-boot", "c"},
|
||||
"Boot value should be set to c when DiskImage is set on step",
|
||||
},
|
||||
@@ -495,7 +448,7 @@ func Test_Defaults(t *testing.T) {
|
||||
QMPSocketPath: "/path/to/socket",
|
||||
},
|
||||
map[string]interface{}{},
|
||||
&stepRun{ui: packer.TestUi(t)},
|
||||
&stepRun{},
|
||||
[]string{"-qmp", "unix:/path/to/socket,server,nowait"},
|
||||
"Args should contain -qmp when qmp_enable is set",
|
||||
},
|
||||
@@ -504,7 +457,7 @@ func Test_Defaults(t *testing.T) {
|
||||
QMPEnable: true,
|
||||
},
|
||||
map[string]interface{}{},
|
||||
&stepRun{ui: packer.TestUi(t)},
|
||||
&stepRun{},
|
||||
[]string{"-qmp", "unix:,server,nowait"},
|
||||
"Args contain -qmp even when socket path isn't set, if qmp enabled",
|
||||
},
|
||||
@@ -513,14 +466,14 @@ func Test_Defaults(t *testing.T) {
|
||||
VMName: "partyname",
|
||||
},
|
||||
map[string]interface{}{},
|
||||
&stepRun{ui: packer.TestUi(t)},
|
||||
&stepRun{},
|
||||
[]string{"-name", "partyname"},
|
||||
"Name is set from config",
|
||||
},
|
||||
{
|
||||
&Config{},
|
||||
map[string]interface{}{},
|
||||
&stepRun{ui: packer.TestUi(t)},
|
||||
&stepRun{},
|
||||
[]string{"-name", ""},
|
||||
"Name is set from config, even when name is blank (which won't " +
|
||||
"happen for real thanks to defaulting in build prepare)",
|
||||
@@ -531,7 +484,7 @@ func Test_Defaults(t *testing.T) {
|
||||
MachineType: "fancymachine",
|
||||
},
|
||||
map[string]interface{}{},
|
||||
&stepRun{ui: packer.TestUi(t)},
|
||||
&stepRun{},
|
||||
[]string{"-machine", "type=fancymachine"},
|
||||
"Don't add accelerator tag when no accelerator is set.",
|
||||
},
|
||||
@@ -541,7 +494,7 @@ func Test_Defaults(t *testing.T) {
|
||||
MachineType: "fancymachine",
|
||||
},
|
||||
map[string]interface{}{},
|
||||
&stepRun{ui: packer.TestUi(t)},
|
||||
&stepRun{},
|
||||
[]string{"-machine", "type=fancymachine,accel=kvm"},
|
||||
"Add accelerator tag when accelerator is set.",
|
||||
},
|
||||
@@ -550,7 +503,7 @@ func Test_Defaults(t *testing.T) {
|
||||
NetBridge: "fakebridge",
|
||||
},
|
||||
map[string]interface{}{},
|
||||
&stepRun{ui: packer.TestUi(t)},
|
||||
&stepRun{},
|
||||
[]string{"-netdev", "bridge,id=user.0,br=fakebridge"},
|
||||
"Add netbridge tag when netbridge is set.",
|
||||
},
|
||||
@@ -563,7 +516,7 @@ func Test_Defaults(t *testing.T) {
|
||||
},
|
||||
},
|
||||
map[string]interface{}{},
|
||||
&stepRun{ui: packer.TestUi(t)},
|
||||
&stepRun{},
|
||||
[]string{"-netdev", "user,id=user.0"},
|
||||
"No host forwarding when no net bridge and no communicator",
|
||||
},
|
||||
@@ -581,7 +534,7 @@ func Test_Defaults(t *testing.T) {
|
||||
map[string]interface{}{
|
||||
"commHostPort": 1111,
|
||||
},
|
||||
&stepRun{ui: packer.TestUi(t)},
|
||||
&stepRun{},
|
||||
[]string{"-netdev", "user,id=user.0,hostfwd=tcp::1111-:4567"},
|
||||
"Host forwarding when a communicator is configured",
|
||||
},
|
||||
@@ -592,7 +545,7 @@ func Test_Defaults(t *testing.T) {
|
||||
map[string]interface{}{
|
||||
"vnc_port": 5959,
|
||||
},
|
||||
&stepRun{ui: packer.TestUi(t)},
|
||||
&stepRun{},
|
||||
[]string{"-vnc", "1.1.1.1:5959"},
|
||||
"no VNC password should be set",
|
||||
},
|
||||
@@ -604,7 +557,7 @@ func Test_Defaults(t *testing.T) {
|
||||
map[string]interface{}{
|
||||
"vnc_port": 5959,
|
||||
},
|
||||
&stepRun{ui: packer.TestUi(t)},
|
||||
&stepRun{},
|
||||
[]string{"-vnc", "1.1.1.1:5959,password"},
|
||||
"VNC password should be set",
|
||||
},
|
||||
@@ -613,7 +566,7 @@ func Test_Defaults(t *testing.T) {
|
||||
MemorySize: 2345,
|
||||
},
|
||||
map[string]interface{}{},
|
||||
&stepRun{ui: packer.TestUi(t)},
|
||||
&stepRun{},
|
||||
[]string{"-m", "2345M"},
|
||||
"Memory is set, with unit M",
|
||||
},
|
||||
@@ -622,7 +575,7 @@ func Test_Defaults(t *testing.T) {
|
||||
CpuCount: 2,
|
||||
},
|
||||
map[string]interface{}{},
|
||||
&stepRun{ui: packer.TestUi(t)},
|
||||
&stepRun{},
|
||||
[]string{"-smp", "cpus=2,sockets=2"},
|
||||
"both cpus and sockets are set to config's CpuCount",
|
||||
},
|
||||
@@ -631,7 +584,7 @@ func Test_Defaults(t *testing.T) {
|
||||
CpuCount: 2,
|
||||
},
|
||||
map[string]interface{}{},
|
||||
&stepRun{ui: packer.TestUi(t)},
|
||||
&stepRun{},
|
||||
[]string{"-smp", "cpus=2,sockets=2"},
|
||||
"both cpus and sockets are set to config's CpuCount",
|
||||
},
|
||||
@@ -642,7 +595,7 @@ func Test_Defaults(t *testing.T) {
|
||||
map[string]interface{}{
|
||||
"floppy_path": "/path/to/floppy",
|
||||
},
|
||||
&stepRun{ui: packer.TestUi(t)},
|
||||
&stepRun{},
|
||||
[]string{"-fda", "/path/to/floppy"},
|
||||
"floppy path should be set under fda flag, when it exists",
|
||||
},
|
||||
@@ -653,10 +606,7 @@ func Test_Defaults(t *testing.T) {
|
||||
UseDefaultDisplay: false,
|
||||
},
|
||||
map[string]interface{}{},
|
||||
&stepRun{
|
||||
atLeastVersion2: true,
|
||||
ui: packer.TestUi(t),
|
||||
},
|
||||
&stepRun{},
|
||||
[]string{"-display", "fakedisplay"},
|
||||
"Display option should value config display",
|
||||
},
|
||||
@@ -665,22 +615,27 @@ func Test_Defaults(t *testing.T) {
|
||||
Headless: false,
|
||||
},
|
||||
map[string]interface{}{},
|
||||
&stepRun{
|
||||
atLeastVersion2: true,
|
||||
ui: packer.TestUi(t),
|
||||
},
|
||||
&stepRun{},
|
||||
[]string{"-display", "gtk"},
|
||||
"Display option should default to gtk",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
state := runTestState(t, &Config{})
|
||||
state := runTestState(t, tc.Config)
|
||||
for k, v := range tc.ExtraState {
|
||||
state.Put(k, v)
|
||||
}
|
||||
|
||||
args, err := tc.Step.getCommandArgs(tc.Config, state)
|
||||
// figure out boot config
|
||||
bootval := "c"
|
||||
for i, val := range tc.Expected {
|
||||
if val == "-boot" {
|
||||
bootval = tc.Expected[i+1]
|
||||
}
|
||||
}
|
||||
|
||||
args, err := tc.Step.getCommandArgs(bootval, state)
|
||||
if err != nil {
|
||||
t.Fatalf("should not have an error getting args. Error: %s", err)
|
||||
}
|
||||
|
||||
@@ -44,11 +44,12 @@ 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:
|
||||
// C1, C2L, C2M, C2S, DEV1-S, DEV1-M, DEV1-L, DEV1-XL,
|
||||
// GP1-XS, GP1-S, GP1-M, GP1-L, GP1-XL, RENDER-S
|
||||
// ARM64-128GB, ARM64-16GB, ARM64-2GB, ARM64-32GB, ARM64-4GB,
|
||||
// ARM64-64GB, ARM64-8GB, C1, C2L, C2M, C2S, START1-L,
|
||||
// START1-M, START1-S, START1-XS, X64-120GB, X64-15GB, X64-30GB,
|
||||
// X64-60GB
|
||||
CommercialType string `mapstructure:"commercial_type" required:"true"`
|
||||
// The name of the resulting snapshot that will
|
||||
// appear in your account. Default packer-TIMESTAMP
|
||||
|
||||
@@ -5,11 +5,9 @@ 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"
|
||||
)
|
||||
|
||||
@@ -24,27 +22,8 @@ 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: imageID,
|
||||
ImageID: c.Image,
|
||||
})
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error getting initial image info: %s", err)
|
||||
|
||||
@@ -14,18 +14,15 @@ 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 the
|
||||
// [Working With Clusters And Hosts](#working-with-clusters-and-hosts)
|
||||
// section above for more details.
|
||||
// ESXi cluster where target VM is created. See
|
||||
// [Working with Clusters](#working-with-clusters).
|
||||
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
|
||||
// [Working With Clusters And Hosts](#working-with-clusters-and-hosts)
|
||||
// section above for more details.
|
||||
// `Specifying 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
@@ -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-processors other than these.
|
||||
-except=foo,bar,baz Run all builds and post-procesors 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 or HCL2 file containing user variables.
|
||||
-var-file=path JSON file containing user variables.
|
||||
`
|
||||
|
||||
return strings.TrimSpace(helpText)
|
||||
|
||||
+2
-12
@@ -138,7 +138,7 @@ func TestBuild(t *testing.T) {
|
||||
},
|
||||
|
||||
{
|
||||
name: "source name: HCL",
|
||||
name: "build name: HCL",
|
||||
args: []string{
|
||||
"-parallel-builds=1", // to ensure order is kept
|
||||
testFixture("build-name-and-type"),
|
||||
@@ -297,6 +297,7 @@ func TestBuild(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "hcl - recipes - only recipes",
|
||||
args: []string{
|
||||
@@ -313,17 +314,6 @@ 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
@@ -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 or HCL2 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 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)
|
||||
|
||||
@@ -55,7 +55,7 @@ func (c *HCL2UpgradeCommand) ParseArgs(args []string) (*HCL2UpgradeArgs, int) {
|
||||
}
|
||||
|
||||
const (
|
||||
hcl2UpgradeFileHeader = `# This file was autogenerated by the BETA 'packer hcl2_upgrade' command. We
|
||||
hcl2UpgradeFileHeader = `# This file was autogenerate 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 is how Packer JSON
|
||||
# views them; you can change their type later on. Read the variables type
|
||||
# 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
|
||||
# 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 on a
|
||||
# build blocks. A build block runs provisioner and post-processors onto 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 provisioning steps on them. The
|
||||
# a build block invokes sources and runs provisionning 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 into an HCL2 configuration.
|
||||
Will transform your JSON template to a HCL2 configuration.
|
||||
`
|
||||
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
||||
func (*HCL2UpgradeCommand) Synopsis() string {
|
||||
return "transform a JSON template into an HCL2 configuration"
|
||||
return "transform a JSON template into a HCL2 configuration"
|
||||
}
|
||||
|
||||
func (*HCL2UpgradeCommand) AutocompleteArgs() complete.Predictor {
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
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 autogenerated by the BETA 'packer hcl2_upgrade' command. We
|
||||
# This file was autogenerate 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 is how Packer JSON
|
||||
# views them; you can change their type later on. Read the variables type
|
||||
# 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
|
||||
# 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 on a
|
||||
# build blocks. A build block runs provisioner and post-processors onto 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 provisioning steps on them. The
|
||||
# a build block invokes sources and runs provisionning 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
@@ -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 or HCL2 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 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)
|
||||
|
||||
@@ -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-processors other than these.]'
|
||||
'-except=[(foo,bar,baz) Run all builds and post-procesors 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 or HCL2 file containing user variables.]'
|
||||
'-var-file=[(path) JSON 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 or HCL2 file containing user variables.]'
|
||||
'-var-file=[(path) JSON file containing user variables.]'
|
||||
'(-)*:files:_files -g "*.json"'
|
||||
)
|
||||
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}]
|
||||
}
|
||||
@@ -58,7 +58,6 @@ 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{
|
||||
@@ -94,6 +93,5 @@ func init() {
|
||||
"vsphere-iso-net-disk",
|
||||
"iso-checksum-type-and-url",
|
||||
"qemu-host-port",
|
||||
"azure-exclude_from_latest",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
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.`
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,7 @@ 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
|
||||
@@ -78,6 +79,7 @@ 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
|
||||
@@ -92,9 +94,10 @@ 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 v1.0.0
|
||||
github.com/mitchellh/panicwrap v0.0.0-20170106182340-fce601fe5557
|
||||
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
|
||||
@@ -110,7 +113,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.7
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.6.0.20200903143645-c0ce17a0443d
|
||||
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
|
||||
@@ -134,6 +137,7 @@ 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
|
||||
|
||||
@@ -376,6 +376,7 @@ 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=
|
||||
@@ -433,6 +434,8 @@ 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=
|
||||
@@ -510,14 +513,15 @@ 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 v1.0.0 h1:67zIyVakCIvcs69A0FGfZjBdPleaonSgGlXRSRlb6fE=
|
||||
github.com/mitchellh/panicwrap v1.0.0/go.mod h1:pKvZHwWrZowLUzftuFq7coarnxbBXU4aQh3N0BJOeeA=
|
||||
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/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=
|
||||
@@ -577,8 +581,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.7 h1:Do8ksLD4Nr3pA0x0hnLOLftZgkiTDvwPDShRTUxtXpE=
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
|
||||
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/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=
|
||||
|
||||
@@ -31,9 +31,6 @@ 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:
|
||||
|
||||
@@ -383,7 +383,6 @@ 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()),
|
||||
|
||||
@@ -40,5 +40,4 @@ var DeprecatedOptions = []string{
|
||||
"iso_checksum_type",
|
||||
"ssh_host_port_max",
|
||||
"ssh_host_port_min",
|
||||
"exlude_from_latest",
|
||||
}
|
||||
|
||||
Binary file not shown.
+27
@@ -0,0 +1,27 @@
|
||||
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
@@ -0,0 +1,21 @@
|
||||
### Extensions to the "os" package.
|
||||
|
||||
[](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
@@ -0,0 +1,33 @@
|
||||
// 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
@@ -0,0 +1,9 @@
|
||||
//+build go1.8,!openbsd
|
||||
|
||||
package osext
|
||||
|
||||
import "os"
|
||||
|
||||
func executable() (string, error) {
|
||||
return os.Executable()
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// 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
@@ -0,0 +1,36 @@
|
||||
// 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
@@ -0,0 +1,126 @@
|
||||
// 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
@@ -0,0 +1,36 @@
|
||||
// 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
@@ -1,3 +0,0 @@
|
||||
module github.com/mitchellh/panicwrap
|
||||
|
||||
go 1.13
|
||||
+3
-9
@@ -20,6 +20,8 @@ import (
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/kardianos/osext"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -116,7 +118,7 @@ func Wrap(c *WrapConfig) (int, error) {
|
||||
}
|
||||
|
||||
// Get the path to our current executable
|
||||
exePath, err := os.Executable()
|
||||
exePath, err := osext.Executable()
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
@@ -227,11 +229,6 @@ 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.
|
||||
//
|
||||
@@ -256,9 +253,6 @@ 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
|
||||
}
|
||||
|
||||
+78
-85
@@ -613,7 +613,7 @@ type Bootscript struct {
|
||||
Initrd string `json:"initrd"`
|
||||
// Kernel: the server kernel version
|
||||
Kernel string `json:"kernel"`
|
||||
// Organization: the bootscript organization ID
|
||||
// Organization: the bootscript organization
|
||||
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 ID
|
||||
// Organization: the placement group organization
|
||||
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 security group project ID
|
||||
// Project: the project ID of the security group
|
||||
Project string `json:"project"`
|
||||
// Deprecated: OrganizationDefault: true if it is your default security group for this organization ID
|
||||
// OrganizationDefault: true if it is your default security group for this organization
|
||||
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 ID
|
||||
// Organization: the server organization
|
||||
Organization string `json:"organization"`
|
||||
// Project: the server project ID
|
||||
Project string `json:"project"`
|
||||
@@ -1181,41 +1181,37 @@ 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"`
|
||||
// Project: the snapshot project ID
|
||||
Project string `json:"project"`
|
||||
// VolumeType: the snapshot volume type
|
||||
// VolumeType:
|
||||
//
|
||||
// Default value: l_ssd
|
||||
VolumeType VolumeVolumeType `json:"volume_type"`
|
||||
// Size: the snapshot size
|
||||
|
||||
Size scw.Size `json:"size"`
|
||||
// State: the snapshot state
|
||||
// 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"`
|
||||
// Zone: the snapshot zone
|
||||
|
||||
Project string `json:"project"`
|
||||
|
||||
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"`
|
||||
}
|
||||
|
||||
@@ -1265,29 +1261,29 @@ type UpdateVolumeResponse struct {
|
||||
|
||||
// Volume: volume
|
||||
type Volume struct {
|
||||
// ID: the volume unique ID
|
||||
// ID: the volumes unique ID
|
||||
ID string `json:"id"`
|
||||
// Name: the volume name
|
||||
// Name: the volumes names
|
||||
Name string `json:"name"`
|
||||
// ExportURI: show the volume NBD export URI
|
||||
// ExportURI: show the volumes NBD export URI
|
||||
ExportURI string `json:"export_uri"`
|
||||
// Size: the volume disk size
|
||||
// Size: the volumes disk size
|
||||
Size scw.Size `json:"size"`
|
||||
// VolumeType: the volume type
|
||||
// VolumeType: the volumes type
|
||||
//
|
||||
// Default value: l_ssd
|
||||
VolumeType VolumeVolumeType `json:"volume_type"`
|
||||
// CreationDate: the volume creation date
|
||||
// CreationDate: the volumes creation date
|
||||
CreationDate *time.Time `json:"creation_date"`
|
||||
// ModificationDate: the volume modification date
|
||||
// ModificationDate: the volumes modification date
|
||||
ModificationDate *time.Time `json:"modification_date"`
|
||||
// Organization: the volume organization ID
|
||||
// Organization: the volumes organization
|
||||
Organization string `json:"organization"`
|
||||
// Project: the volume project ID
|
||||
// Project: the volumes project ID
|
||||
Project string `json:"project"`
|
||||
// Server: the server attached to the volume
|
||||
Server *ServerSummary `json:"server"`
|
||||
// State: the volume state
|
||||
// State: the volumes state
|
||||
//
|
||||
// Default value: available
|
||||
State VolumeState `json:"state"`
|
||||
@@ -1319,12 +1315,10 @@ type VolumeTemplate struct {
|
||||
//
|
||||
// Default value: l_ssd
|
||||
VolumeType VolumeVolumeType `json:"volume_type,omitempty"`
|
||||
// Deprecated: Organization: organization ID of the volume
|
||||
// Precisely one of Organization, Project must be set.
|
||||
Organization *string `json:"organization,omitempty"`
|
||||
// Organization: organization ID of the volume
|
||||
Organization string `json:"organization,omitempty"`
|
||||
// Project: project ID of the volume
|
||||
// Precisely one of Organization, Project must be set.
|
||||
Project *string `json:"project,omitempty"`
|
||||
Project string `json:"project,omitempty"`
|
||||
}
|
||||
|
||||
type VolumeType struct {
|
||||
@@ -1524,7 +1518,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 ID
|
||||
// Organization: list only servers of this organization
|
||||
Organization *string `json:"-"`
|
||||
// Project: list only servers of this project ID
|
||||
Project *string `json:"-"`
|
||||
@@ -1542,8 +1536,6 @@ 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
|
||||
@@ -1573,7 +1565,6 @@ 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")
|
||||
@@ -1636,7 +1627,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"`
|
||||
// Deprecated: Organization: the server organization ID
|
||||
// Organization: the server organization ID
|
||||
// Precisely one of Organization, Project must be set.
|
||||
Organization *string `json:"organization,omitempty"`
|
||||
// Project: the server project ID
|
||||
@@ -1648,6 +1639,8 @@ 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
|
||||
@@ -1781,7 +1774,7 @@ type setServerRequest struct {
|
||||
ID string `json:"-"`
|
||||
// Name: the server name
|
||||
Name string `json:"name"`
|
||||
// Organization: the server organization ID
|
||||
// Organization: the server organization
|
||||
Organization string `json:"organization"`
|
||||
// Project: the server project ID
|
||||
Project string `json:"project"`
|
||||
@@ -2269,7 +2262,7 @@ type CreateImageRequest struct {
|
||||
DefaultBootscript string `json:"default_bootscript,omitempty"`
|
||||
// ExtraVolumes: additional volumes of the image
|
||||
ExtraVolumes map[string]*VolumeTemplate `json:"extra_volumes,omitempty"`
|
||||
// Deprecated: Organization: organization ID of the image
|
||||
// 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
|
||||
@@ -2527,10 +2520,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"`
|
||||
}
|
||||
@@ -2749,7 +2742,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 ID
|
||||
// Organization: filter volume by organization
|
||||
Organization *string `json:"-"`
|
||||
// Project: filter volume by project ID
|
||||
Project *string `json:"-"`
|
||||
@@ -2820,27 +2813,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"`
|
||||
// Project: the volume project ID
|
||||
// Precisely one of Organization, Project must be set.
|
||||
Project *string `json:"project,omitempty"`
|
||||
// VolumeType: the volume type
|
||||
// VolumeType:
|
||||
//
|
||||
// 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
|
||||
@@ -3097,13 +3090,13 @@ type CreateSecurityGroupRequest struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
// Description: description of the security group
|
||||
Description string `json:"description,omitempty"`
|
||||
// Deprecated: Organization: organization ID the security group belongs to
|
||||
// Organization: organization 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"`
|
||||
// Deprecated: OrganizationDefault: whether this security group becomes the default security group for new instances
|
||||
// OrganizationDefault: whether this security group becomes the default security group for new instances
|
||||
//
|
||||
// Default value: false
|
||||
// Precisely one of OrganizationDefault, ProjectDefault must be set.
|
||||
@@ -3252,38 +3245,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: the default inbound policy
|
||||
// InboundDefaultPolicy:
|
||||
//
|
||||
// Default value: accept
|
||||
InboundDefaultPolicy SecurityGroupPolicy `json:"inbound_default_policy"`
|
||||
// OutboundDefaultPolicy: the default outbound policy
|
||||
|
||||
Organization string `json:"organization"`
|
||||
|
||||
OrganizationDefault bool `json:"organization_default"`
|
||||
// OutboundDefaultPolicy:
|
||||
//
|
||||
// Default value: accept
|
||||
OutboundDefaultPolicy SecurityGroupPolicy `json:"outbound_default_policy"`
|
||||
// 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"`
|
||||
|
||||
Project string `json:"project"`
|
||||
|
||||
ProjectDefault bool `json:"project_default"`
|
||||
}
|
||||
|
||||
// setSecurityGroup: update a security group
|
||||
@@ -3644,7 +3637,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 ID
|
||||
// Organization: list only placement groups of this organization
|
||||
Organization *string `json:"-"`
|
||||
// Project: list only placement groups of this project ID
|
||||
Project *string `json:"-"`
|
||||
@@ -3718,17 +3711,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: the operating mode of the placement group
|
||||
// PolicyMode:
|
||||
//
|
||||
// Default value: optional
|
||||
PolicyMode PlacementGroupPolicyMode `json:"policy_mode"`
|
||||
// PolicyType: the policy type of the placement group
|
||||
// PolicyType:
|
||||
//
|
||||
// Default value: max_availability
|
||||
PolicyType PlacementGroupPolicyType `json:"policy_type"`
|
||||
@@ -4121,6 +4114,8 @@ 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)
|
||||
@@ -4131,8 +4126,6 @@ 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
|
||||
@@ -4150,11 +4143,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")
|
||||
@@ -4197,7 +4190,7 @@ func (r *ListIPsResponse) UnsafeAppend(res interface{}) (uint32, error) {
|
||||
|
||||
type CreateIPRequest struct {
|
||||
Zone scw.Zone `json:"-"`
|
||||
// Deprecated: Organization: the organization ID the IP is reserved in
|
||||
// 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
|
||||
|
||||
+12
-14
@@ -5,11 +5,10 @@
|
||||
Recommended config file:
|
||||
|
||||
```yaml
|
||||
# Get your credentials on https://console.scaleway.com/project/credentials
|
||||
# get your credentials on https://console.scaleway.com/account/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
|
||||
```
|
||||
@@ -21,7 +20,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`
|
||||
4. Windows home directory: `%USERPROFILE%/.config/scw/config.yaml`
|
||||
3. Windows home directory: `%USERPROFILE%/.config/scw/config.yaml`
|
||||
|
||||
## V1 config (DEPRECATED)
|
||||
|
||||
@@ -44,14 +43,13 @@ scw.NewClient(
|
||||
|
||||
## Environment variables
|
||||
|
||||
| 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 | - |
|
||||
| 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 | - |
|
||||
|
||||
+1
-1
@@ -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/project/credentials
|
||||
# Generate your token at the following address: https://console.scaleway.com/account/credentials
|
||||
|
||||
# An access key is a secret key identifier.
|
||||
{{ if .AccessKey }}access_key: {{.AccessKey}}{{ else }}# access_key: SCW11111111111111111{{ end }}
|
||||
|
||||
-8
@@ -23,8 +23,6 @@ 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 (
|
||||
@@ -33,7 +31,6 @@ var (
|
||||
ZoneFrPar1,
|
||||
ZoneFrPar2,
|
||||
ZoneNlAms1,
|
||||
ZonePlWaw1,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -71,8 +68,6 @@ 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 (
|
||||
@@ -80,7 +75,6 @@ var (
|
||||
AllRegions = []Region{
|
||||
RegionFrPar,
|
||||
RegionNlAms,
|
||||
RegionPlWaw,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -101,8 +95,6 @@ func (region Region) GetZones() []Zone {
|
||||
return []Zone{ZoneFrPar1, ZoneFrPar2}
|
||||
case RegionNlAms:
|
||||
return []Zone{ZoneNlAms1}
|
||||
case RegionPlWaw:
|
||||
return []Zone{ZonePlWaw1}
|
||||
default:
|
||||
return []Zone{}
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,6 +6,6 @@ import (
|
||||
)
|
||||
|
||||
// TODO: versioning process
|
||||
const version = "v1.0.0-beta.7"
|
||||
const version = "v1.0.0-beta.6+dev"
|
||||
|
||||
var userAgent = fmt.Sprintf("scaleway-sdk-go/%s (%s; %s; %s)", version, runtime.Version(), runtime.GOOS, runtime.GOARCH)
|
||||
|
||||
Vendored
+4
-2
@@ -406,6 +406,8 @@ 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
|
||||
@@ -452,7 +454,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 v1.0.0
|
||||
# github.com/mitchellh/panicwrap v0.0.0-20170106182340-fce601fe5557
|
||||
github.com/mitchellh/panicwrap
|
||||
# github.com/mitchellh/prefixedio v0.0.0-20151214002211-6e6954073784
|
||||
github.com/mitchellh/prefixedio
|
||||
@@ -494,7 +496,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.7
|
||||
# github.com/scaleway/scaleway-sdk-go v1.0.0-beta.6.0.20200903143645-c0ce17a0443d
|
||||
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
|
||||
|
||||
@@ -144,10 +144,6 @@ export default [
|
||||
category: 'conversion',
|
||||
content: ['can', 'convert', 'try'],
|
||||
},
|
||||
{
|
||||
category: 'kvstore',
|
||||
content: ['vault'],
|
||||
},
|
||||
],
|
||||
},
|
||||
'variables',
|
||||
|
||||
@@ -3,10 +3,9 @@ const path = require('path')
|
||||
|
||||
module.exports = withHashicorp({
|
||||
defaultLayout: true,
|
||||
transpileModules: ['is-absolute-url', '@hashicorp/react-.*'],
|
||||
transpileModules: ['is-absolute-url', '@hashicorp/react-mega-nav'],
|
||||
mdx: { resolveIncludes: path.join(__dirname, 'pages/partials') },
|
||||
})({
|
||||
svgo: { plugins: [{ removeViewBox: false }] },
|
||||
experimental: {
|
||||
modern: true,
|
||||
rewrites: () => [
|
||||
|
||||
Generated
+8
-21
@@ -1666,27 +1666,6 @@
|
||||
"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",
|
||||
@@ -1714,6 +1693,14 @@
|
||||
"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",
|
||||
|
||||
@@ -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,7 +2,7 @@ import './style.css'
|
||||
import '@hashicorp/nextjs-scripts/lib/nprogress/style.css'
|
||||
|
||||
import ProductSubnav from 'components/subnav'
|
||||
import HashiStackMenu from '@hashicorp/react-hashi-stack-menu'
|
||||
import MegaNav from '@hashicorp/react-mega-nav'
|
||||
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' },
|
||||
]}
|
||||
/>
|
||||
<HashiStackMenu />
|
||||
<MegaNav product="Packer" />
|
||||
<ProductSubnav />
|
||||
<div className="content">
|
||||
<Component {...pageProps} />
|
||||
|
||||
@@ -33,6 +33,8 @@ 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'
|
||||
@@ -47,9 +49,6 @@ 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.
|
||||
|
||||
@@ -43,11 +43,52 @@ can also be supplied to override the typical auto-generated key:
|
||||
|
||||
### Required:
|
||||
|
||||
@include 'builder/scaleway/Config-required.mdx'
|
||||
- `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`
|
||||
|
||||
### Optional:
|
||||
|
||||
@include 'builder/scaleway/Config-not-required.mdx'
|
||||
- `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`.
|
||||
|
||||
## Basic Example
|
||||
|
||||
@@ -57,12 +98,11 @@ access tokens:
|
||||
```json
|
||||
{
|
||||
"type": "scaleway",
|
||||
"project_id": "YOUR PROJECT ID",
|
||||
"access_key": "YOUR ACCESS KEY",
|
||||
"secret_key": "YOUR SECRET KEY",
|
||||
"organization_id": "YOUR ORGANIZATION ID",
|
||||
"api_token": "YOUR TOKEN",
|
||||
"image": "UUID OF THE BASE IMAGE",
|
||||
"zone": "fr-par-1",
|
||||
"commercial_type": "DEV1-S",
|
||||
"region": "par1",
|
||||
"commercial_type": "START1-S",
|
||||
"ssh_username": "root",
|
||||
"ssh_private_key_file": "~/.ssh/id_rsa"
|
||||
}
|
||||
|
||||
@@ -280,7 +280,7 @@ Minimal example of usage:
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Working With Clusters And Hosts
|
||||
## Working with Clusters
|
||||
|
||||
#### 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 And Hosts
|
||||
## Working with Clusters
|
||||
|
||||
#### 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).
|
||||
This also allows you to set specific fields.
|
||||
- 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.
|
||||
|
||||
`@include 'from-1.5/builds/example-block.mdx'`
|
||||
|
||||
|
||||
@@ -19,10 +19,10 @@ block](/docs/from-1.5/blocks/build), for example :
|
||||
|
||||
```hcl
|
||||
build {
|
||||
sources = [
|
||||
source = [
|
||||
# Here Packer will use a default ami_name when saving the image.
|
||||
"source.amazon-ebs.example",
|
||||
"source.amazon-ebs.foo",
|
||||
"sources.amazon-ebs.example",
|
||||
"sources.amazon-ebs.foo",
|
||||
]
|
||||
}
|
||||
```
|
||||
@@ -32,7 +32,7 @@ set specific source fields.
|
||||
|
||||
```hcl
|
||||
build {
|
||||
source "source.amazon-ebs.example" {
|
||||
source "sources.amazon-ebs.example" {
|
||||
# Here Packer will use the provided ami_name instead of defaulting it.
|
||||
ami_name = "specific"
|
||||
}
|
||||
|
||||
@@ -18,28 +18,14 @@ Build variables will allow you to access connection information and basic instan
|
||||
All special build variables are stored in the `build` variable:
|
||||
|
||||
```hcl
|
||||
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"]
|
||||
provisioner "shell" {
|
||||
environment_vars = ["TESTVAR=${build.PackerRunUUID}"]
|
||||
inline = ["echo $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.
|
||||
|
||||
|
||||
@@ -65,9 +65,10 @@ Whenever the distinction isn't relevant, the Packer documentation uses each
|
||||
pair of terms interchangeably (with a historical preference for "list" and
|
||||
"map").
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
### Type Conversion
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
layout: docs
|
||||
page_title: keystore - Functions - Configuration Language
|
||||
sidebar_title: Key Store Functions
|
||||
description: Overview of available keystore functions
|
||||
---
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
layout: docs
|
||||
page_title: vault - Functions - Configuration Language
|
||||
sidebar_title: vault Functions
|
||||
description: Overview of available vault functions
|
||||
---
|
||||
+2
-2
@@ -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).
|
||||
@@ -20,18 +20,13 @@ 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. If you leave out the `.pkr`
|
||||
portion of suffix, Packer will try to read your json file as a legacy Packer
|
||||
template.
|
||||
syntax for files named with a `.pkr.json` suffix.
|
||||
|
||||
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
|
||||
@@ -173,15 +168,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 `build` blocks expects a label giving the provisioner to use,
|
||||
within `source` 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 `build` block with a number
|
||||
The following native syntax example shows a `source` block with a number
|
||||
of provisioners of different types:
|
||||
|
||||
```hcl
|
||||
build {
|
||||
source "amazon-ebs" "example" {
|
||||
# (source configuration omitted for brevity)
|
||||
|
||||
provisioner "shell-local" {
|
||||
@@ -205,27 +200,29 @@ this JSON equivalent of the above:
|
||||
|
||||
```json
|
||||
{
|
||||
"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"]
|
||||
}
|
||||
"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"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -177,10 +177,71 @@ 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. Otherwise, the interpreter will assume
|
||||
that any variable set on the command line is a string.
|
||||
HCL parser understand what is being set.
|
||||
|
||||
### Variable Definitions (`.pkrvars.hcl` and `.auto.pkrvars.hcl`) Files
|
||||
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
|
||||
|
||||
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
|
||||
@@ -269,20 +330,18 @@ files.
|
||||
### Variable Definition Precedence
|
||||
|
||||
The above mechanisms for setting variables can be used together in any
|
||||
combination.
|
||||
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.
|
||||
|
||||
Packer loads variables in the following order, with later sources taking
|
||||
precedence over earlier ones:
|
||||
|
||||
- Environment variables (lowest priority)
|
||||
- Environment variables
|
||||
- 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. (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.
|
||||
provided.
|
||||
|
||||
~> **Important:** Variables with map and object values behave the same way as
|
||||
other variables: the last value found overrides the previous values.
|
||||
|
||||
@@ -25,10 +25,6 @@ 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
|
||||
@@ -579,7 +575,8 @@ 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`}}"
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -633,147 +630,6 @@ 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
|
||||
|
||||
@@ -13,22 +13,8 @@ description: |-
|
||||
|
||||
@include 'guides/hcl2-beta-note.mdx'
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
The following file :
|
||||
|
||||
@@ -157,7 +143,6 @@ repeatable blocks with the same identifier. For example:
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Becomes:
|
||||
@@ -177,19 +162,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
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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.
|
||||
-> **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.
|
||||
|
||||
@@ -18,131 +18,54 @@ Local variables can be a compound of input variables and local variables.
|
||||
|
||||
## Defining Variables and locals
|
||||
|
||||
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.
|
||||
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 <command line flags> <source directory>` to initiate a build.
|
||||
across multiple files, use `packer build <source directory>` to initiate
|
||||
a build.
|
||||
|
||||
```hcl
|
||||
// variables.pkr.hcl
|
||||
# variables.pkr.hcl
|
||||
|
||||
// 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]
|
||||
variable "access_key" {}
|
||||
variable "secret_key" {}
|
||||
variable "region" {
|
||||
default = "us-east-1"
|
||||
}
|
||||
|
||||
locals {
|
||||
ice_cream_flavor = "${var.flavor}-ice-cream"
|
||||
debian_ami_name = "${var.image_id}-debian"
|
||||
foo = "bar"
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
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`.
|
||||
|
||||
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.
|
||||
-> **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.
|
||||
|
||||
## Using Variables and locals in Configuration
|
||||
|
||||
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.
|
||||
Next, you can define a source using the variables :
|
||||
|
||||
```hcl
|
||||
// null_example.pkr.hcl
|
||||
# source.pkr.hcl
|
||||
|
||||
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
|
||||
}
|
||||
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}"
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
## Assigning Variables
|
||||
|
||||
@@ -157,18 +80,86 @@ You can set variables directly on the command-line with the
|
||||
|
||||
```shell-session
|
||||
$ packer build \
|
||||
-var 'weekday=Sunday' \
|
||||
-var 'flavor=chocolate' \
|
||||
-var 'sudo_password=hunter42' .
|
||||
-var 'access_key=foo' \
|
||||
-var 'secret_key=bar'
|
||||
# ...
|
||||
```
|
||||
|
||||
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. Otherwise it will interpret all of your
|
||||
command line variables as strings.
|
||||
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
|
||||
```
|
||||
|
||||
#### From a file
|
||||
|
||||
@@ -177,48 +168,17 @@ this file. Create a file named `variables.pkrvars.hcl` with the following
|
||||
contents:
|
||||
|
||||
```hcl
|
||||
sudo_password = "partyparrot"
|
||||
weekday = "Sunday"
|
||||
access_key = "foo"
|
||||
secret_key = "bar"
|
||||
```
|
||||
|
||||
You tell Packer to use this var file using the `-var-file` command line flag.
|
||||
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.
|
||||
|
||||
```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
|
||||
We don't recommend saving usernames and password 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
|
||||
@@ -227,7 +187,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
|
||||
@@ -236,42 +196,18 @@ 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.
|
||||
|
||||
If all of your variables have defaults, then you can call a packer build using:
|
||||
#### Unspecified values fails
|
||||
|
||||
```shell-session
|
||||
$ packer build .
|
||||
```
|
||||
If you execute `packer build` with certain variables unspecified and those are
|
||||
used somewhere, Packer will error.
|
||||
|
||||
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
|
||||
|
||||
Lists are defined either explicitly or implicitly
|
||||
|
||||
@@ -289,7 +225,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,7 +6,8 @@
|
||||
., _ 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
|
||||
@@ -18,8 +19,6 @@
|
||||
- `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
|
||||
@@ -32,9 +31,8 @@
|
||||
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.
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
<!-- 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,35 +1,79 @@
|
||||
<!-- 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 the system disk.
|
||||
See the [disk device configuration](#disk-devices-configuration) section
|
||||
for more information on options.
|
||||
Usage example:
|
||||
- `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
|
||||
|
||||
```json
|
||||
"builders": [{
|
||||
"type":"alicloud-ecs",
|
||||
"system_disk_mapping": {
|
||||
"disk_size": 50,
|
||||
"disk_name": "mydisk"
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
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_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:
|
||||
- `image_disk_mappings` ([]AlicloudDiskDevice) - Add one or more data
|
||||
disks to the image.
|
||||
|
||||
```json
|
||||
"builders": [{
|
||||
"type":"alicloud-ecs",
|
||||
"image_disk_mappings": [
|
||||
{
|
||||
"disk_snapshot_id": "someid",
|
||||
"disk_device": "dev/xvdb"
|
||||
}
|
||||
],
|
||||
...
|
||||
}
|
||||
```
|
||||
- `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.
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
<!-- 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.
|
||||
+1
-1
@@ -2,4 +2,4 @@
|
||||
|
||||
- `target_regions` ([]TargetRegion) - Target Regions
|
||||
|
||||
- `exclude_from_latest` (bool) - Exclude From Latest
|
||||
- `exlude_from_latest` (bool) - Exclude From Latest
|
||||
|
||||
@@ -136,27 +136,19 @@
|
||||
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 qemu-img).
|
||||
Each array of strings makes up a command line switch
|
||||
- `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
|
||||
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 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.
|
||||
beware of conflicting arguments causing failures of your run. For
|
||||
instance, using --no-acpi could break the ability to send power signal
|
||||
type commands (e.g., shutdown -P now) to the virtual machine, thus
|
||||
preventing proper shutdown. To see the defaults, look in the packer.log
|
||||
file and search for the qemu-system-x86 command. The arguments are all
|
||||
printed for review.
|
||||
|
||||
The following shows a sample usage:
|
||||
|
||||
|
||||
@@ -16,8 +16,9 @@
|
||||
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:
|
||||
C1, C2L, C2M, C2S, DEV1-S, DEV1-M, DEV1-L, DEV1-XL,
|
||||
GP1-XS, GP1-S, GP1-M, GP1-L, GP1-XL, RENDER-S
|
||||
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
|
||||
|
||||
@@ -4,18 +4,15 @@
|
||||
|
||||
- `folder` (string) - VM folder to create the VM in.
|
||||
|
||||
- `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.
|
||||
- `cluster` (string) - ESXi cluster where target VM is created. See
|
||||
[Working with Clusters](#working-with-clusters).
|
||||
|
||||
- `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
|
||||
[Working With Clusters And Hosts](#working-with-clusters-and-hosts)
|
||||
section above for more details.
|
||||
`Specifying 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` and `.auto.pkrvars.hcl`) files,
|
||||
either specified on the command line or automatically loaded.
|
||||
- In variable definitions (`.pkrvars.hcl`) files, either specified on the
|
||||
command line or automatically loaded.
|
||||
- As environment variables, for example: `PKR_VAR_foo=bar`
|
||||
|
||||
@@ -5,7 +5,6 @@ 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
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
@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';
|
||||
|
||||
Reference in New Issue
Block a user