Compare commits

...

170 Commits

Author SHA1 Message Date
Megan Marsh a416158371 see if this works for 1.15 2021-02-25 16:26:10 -08:00
Megan Marsh fbe6ebebf1 Merge pull request #10693 from hashicorp/docs-update-multi-component-bin-name
Update plugin location docs
2021-02-24 12:01:52 -08:00
Wilken Rivera e441733cbd Update plugin location docs
This change updates the multi-component name to reflect the name
generated by the goreleaser configuration in packer-plugin-scaffolding.

It also adds a small call out about the SHA256SUM file that needs to be
present for binaries installed via `packer init` in case maintainers
want to test packer init locally without having to call out to GitHub.
2021-02-24 13:33:08 -05:00
Megan Marsh b4b0df44b4 Merge pull request #9591 from Timdawson264/ebs-volume-snapshot
ebsvolume snapshot
2021-02-23 15:47:27 -08:00
Megan Marsh 25920b2bd3 remove unused mock fields 2021-02-23 10:38:15 -08:00
Megan Marsh 74a6c1987c change name of singular block device in loop to be less confusing; fix snapshot tests 2021-02-23 10:30:55 -08:00
Megan Marsh 160be7e773 refactor aws test tooling so we can apply common test function helpers to ebsvolume tests 2021-02-23 09:24:03 -08:00
Sylvia Moss fc23eb9241 add missing provisioner override hcl docs (#10684) 2021-02-23 12:00:02 -05:00
Sylvia Moss ff5b55b560 chef-solo: json_string to HCL2 templates compatibility (#10655) 2021-02-23 11:17:32 +01:00
Megan Marsh 95fb13209a Merge pull request #10680 from bbigras/patch-1
fix typo in website/content/docs/plugins/index.mdx
2021-02-22 15:57:55 -08:00
Bruno Bigras 5515d7293f fix typo in website/content/docs/plugins/index.mdx 2021-02-22 23:30:11 +00:00
Megan Marsh 6107aa51ef Merge pull request #10676 from hashicorp/hcl2_upgrade_variables_only
Allows hcl2_upgrade variables json file
2021-02-22 15:05:02 -08:00
Megan Marsh d398487afd Merge pull request #10671 from dreibh/dreibh/virtualbox-options
More options for the VirtualBox ISO builder
2021-02-22 14:45:19 -08:00
Tim Black 0f86c66f8b Fix wrong link in post-processor docs (#10678) 2021-02-22 17:35:27 -05:00
Megan Marsh 822dcf93af Merge pull request #10543 from arizvisa/GH-10009
Added a fallback to both the player and workstation drivers from the vmware builder when trying to determine the network-mapping configuration
2021-02-22 09:34:39 -08:00
Megan Marsh 11a7b4f74e Merge pull request #10670 from mr-evilbit/patch-1
Update vagrant.mdx
2021-02-22 09:30:50 -08:00
Megan Marsh ae1069d3df Merge pull request #10503 from remyleone/timeout
scaleway: add support for timeout in shutdown step
2021-02-22 09:26:05 -08:00
sylviamoss a1a5cf0113 upgrade variables with other variables 2021-02-22 17:16:19 +01:00
sylviamoss 60017822e0 add docs 2021-02-22 16:19:55 +01:00
sylviamoss 2016d6baec Fix panic on upgrading variables json file 2021-02-22 16:07:37 +01:00
Rémy Léone 2967fccfd7 Fix 2021-02-22 14:10:31 +01:00
Rémy Léone 95e8263280 Fix 2021-02-22 12:18:43 +01:00
Rémy Léone 1f4971f5ac Fix 2021-02-22 12:18:43 +01:00
Rémy Léone 44d19f160a fix 2021-02-22 12:18:43 +01:00
Rémy Léone 557bffc94a scaleway: add support for timeout in shutdown step 2021-02-22 12:18:42 +01:00
Megan Marsh 08fd0a7e33 add a brief explanation of the difference between vars and locals in the docs for vars and locals (#10664) 2021-02-22 11:33:20 +01:00
Megan Marsh 079786f8d0 remove this logline -- it is spammy and seems like a leftover dev debug line (#10665) 2021-02-22 11:20:44 +01:00
Megan Marsh 9a11fd4136 Update amazon sdk (#10668) 2021-02-22 11:18:48 +01:00
Ali Rizvi-Santiago c7545c37dd Fixed an issue identified by @SwampDragons when checking if the networkmapper configuration file exists. 2021-02-21 05:32:30 -06:00
Thomas Dreibholz 2b35873dd9 Formatting fix. 2021-02-20 20:31:09 +01:00
Thomas Dreibholz 8226bc9d9f Ran "make generate". 2021-02-20 20:23:47 +01:00
Thomas Dreibholz ffa8b7de8a Added option for the graphics controller. 2021-02-20 20:21:57 +01:00
Thomas Dreibholz e9936cf0da Added option for audio controller. 2021-02-20 20:09:16 +01:00
Thomas Dreibholz eb4a6f30a0 Added option for NIC type. 2021-02-20 19:59:39 +01:00
Thomas Dreibholz fa844543ec Added options for chipset and firmware. 2021-02-20 19:59:06 +01:00
mr-evilbit e8ccd5304b Update vagrant.mdx
Add newbie friendly reminder that just running a 'vagrant up' in the Packer Vagrant builder output directory does not run the newly built and provisioned .box file.
2021-02-20 12:07:19 -05:00
Megan Marsh fca92b1953 Merge pull request #10632 from dreibh/dreibh/virtualbox-virtio
VirtualBox builder: support for "virtio" storage and ISO drive
2021-02-20 07:41:05 -08:00
Thomas Dreibholz a29075d6c1 Ran "make generate". 2021-02-20 15:29:37 +01:00
Thomas Dreibholz 7ad99c2c85 Added documentation comments. 2021-02-20 15:09:38 +01:00
Thomas Dreibholz 5385275836 Fixed formatting. 2021-02-20 15:09:38 +01:00
Thomas Dreibholz 591b1c2637 VirtualBox: added support for "virtio" ISO interface. 2021-02-20 15:09:38 +01:00
Thomas Dreibholz f48d7e3990 VirtualBox: added support for "virtio" storage. 2021-02-20 15:09:38 +01:00
Megan Marsh c9c65383e9 Merge pull request #10651 from sparshev/vmware_attach_snapshot
Added "attach_snapshot" parameter to vmware vmx builder
2021-02-19 15:14:35 -08:00
Megan Marsh 1ddbe4d9ce update changelog 2021-02-19 10:43:31 -08:00
Megan Marsh dd167925d7 add machine readable to the cli help func and docs (#10658) 2021-02-19 11:17:47 +01:00
Taylor Chaparro 317e2da000 azure client sig fix: don't overwrite subscription id if unset (#10659) 2021-02-19 11:16:31 +01:00
Megan Marsh c4a22e9a56 fix packer interpolation of packer log path (#10660) 2021-02-19 11:08:17 +01:00
Tim Dawson aef74cd059 Fixed up after rebaseing 2021-02-19 14:09:23 +13:00
Sergei Parshev b3b4559434 Added "attach_snapshot" parameter to vmware vmx builder 2021-02-18 15:16:28 -08:00
Tim Dawson ac2ce0097c Fixed formatting 2021-02-19 11:09:55 +13:00
Tim Dawson ca0b11028e Started instramenting some functions and building out unit tests for snapshot step.
Added some basic config tests.
2021-02-19 11:09:55 +13:00
Tim Dawson b199ce9a22 Added snapshots to artifacts
Increased Snapshot wait timeout
2021-02-19 10:58:03 +13:00
Tim Dawson 0f83ba6ee6 Removed Rouge refrence to AMI creation in volume builder 2021-02-19 10:58:03 +13:00
Tim Dawson 3e754c9f3f Using new Polling config for snapshot step 2021-02-19 10:58:03 +13:00
Tim Dawson 7f0b41bb0e Refactored SnapshotConfig
Added Group and user permission to each snapshot
2021-02-19 10:58:03 +13:00
Tim Dawson 482a2c8232 Adding ebs-volume snapshot creation 2021-02-19 10:06:04 +13:00
Megan Marsh 3d55fa51d8 Merge pull request #10560 from trown/bump-oci-go-sdk
Update Oracle Go SDK
2021-02-18 11:46:02 -08:00
Sylvia Moss 37d05c85ff upgrade pause_before (#10654) 2021-02-18 15:05:12 +01:00
dreic ab89df9a88 Update Config-not-required.mdx (#10527) 2021-02-18 11:47:40 +01:00
Megan Marsh 00e503388e change template parsing error to include warning about file extensions (#10652) 2021-02-18 09:59:30 +01:00
Adrien Delorme bf5b4d63da tweak docs to trigger a re-release 2021-02-17 17:29:16 +01:00
packer-ci 21c6811334 Putting source back into Dev Mode 2021-02-17 16:12:20 +00:00
packer-ci 7ea4a779af Cut version 1.7.0 2021-02-17 11:13:51 +00:00
packer-ci a939671abb cut version 1.7.0 2021-02-17 11:13:50 +00:00
packer-ci c6c047905d update changelog 2021-02-17 11:13:50 +00:00
Adrien Delorme c6c8c88b74 Update CHANGELOG.md 2021-02-17 11:24:52 +01:00
Adrien Delorme 3b40127cb0 Update CHANGELOG.md 2021-02-17 11:24:31 +01:00
Adrien Delorme 993ae765e5 Prepare release (#10646)
* get github.com/hashicorp/packer-plugin-sdk@v0.0.14

* Update CHANGELOG.md

* Update CHANGELOG.md

* Update CHANGELOG.md
2021-02-17 11:22:08 +01:00
Sylvia Moss 201869d627 Update HCL2 and JSON example for amazon builders (#10645)
* move hcl2 example up over json to amazon-ebs
* switch hcl and json templates for all amazon builders
* fix json format
2021-02-17 10:32:13 +01:00
Megan Marsh 6ea7edf4e9 update changelog 2021-02-16 16:17:47 -08:00
Megan Marsh 99087d71bc Merge pull request #10641 from zchsh/zs.bump-components
Bump components to remove md processing, fix theme
2021-02-16 14:33:17 -08:00
Megan Marsh 1710590418 Merge pull request #10633 from hashicorp/azr_init_no_magic_host
Packer init: remove host and namespace guessing
2021-02-16 14:32:20 -08:00
Megan Marsh 10d32bda6d Merge pull request #10591 from neumayer/retry
Add retry strategies to oci calls
2021-02-16 13:59:26 -08:00
Megan Marsh 0d14df3020 Merge pull request #10635 from hashicorp/docs_small_changes
Docs small updates
2021-02-16 13:58:32 -08:00
Megan Marsh 2065de0b4f Merge pull request #10642 from hashicorp/wilken_init_no_magic_host
github/getter: Adds a hostname check to Get function
2021-02-16 11:27:11 -08:00
Wilken Rivera 728c5a217d Add test case for non-github hostname
Tests results on current branch; install succeeded which was not expected
```
2021/02/16 14:02:24 ui: Installed plugin example.com/sylviamoss/comment v0.2.19 in "/tmp/pkr-test-cfg-dir-6_pkr_config458005728/example.com/sylviamoss/comment/packer-plugin-comment_v0.2.19_x5.0_linux_amd64"
    init_test.go:361: InitCommand.Run() = 0, want 1
    init_test.go:381: unexpected dir hash after init:   string(
        -       "h1:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
        +       "h1:iVtzkl/nVm2KiLvlz8rH56ME8QEqRxq8+XT2Lo6bzGU=",
          )
--- FAIL: TestInitCommand_Run (6.39s)
    --- PASS: TestInitCommand_Run/already-installed-no-op (0.01s)
        --- PASS: TestInitCommand_Run/already-installed-no-op/-subtest-0 (0.00s)
    --- PASS: TestInitCommand_Run/already-installed-upgrade (2.30s)
        --- PASS: TestInitCommand_Run/already-installed-upgrade/-subtest-0 (0.06s)
    --- PASS: TestInitCommand_Run/release-with-no-binary (0.17s)
    --- PASS: TestInitCommand_Run/manually-installed-single-component-plugin-works (1.32s)
        --- PASS: TestInitCommand_Run/manually-installed-single-component-plugin-works/-subtest-0 (0.01s)
    --- PASS: TestInitCommand_Run/manually-installed-single-component-plugin-old-api-fails (1.42s)
        --- PASS: TestInitCommand_Run/manually-installed-single-component-plugin-old-api-fails/-subtest-0 (0.01s)
    --- FAIL: TestInitCommand_Run/unsupported-non-github-source-address (1.18s)
```

Tests results after change with change in this branch
```
2021/02/16 14:03:14 [TRACE] getting available versions for the example.com/sylviamoss/comment plugin
2021/02/16 14:03:14 [TRACE] &{%!q(*github.Client=<nil>) "packer-getter-github-1.7.0-dev"} getter could not get release: example.com/sylviamoss/comment doesn't appear to be a valid github.com source address; check source and try again.
2021/02/16 14:03:14 [DEBUG] will try to install: []
2021/02/16 14:03:14 ui error: no release version found for the example.com/sylviamoss/comment plugin matching the constraint(s): "v0.2.19"
--- PASS: TestInitCommand_Run (5.38s)
    --- PASS: TestInitCommand_Run/already-installed-no-op (0.01s)
        --- PASS: TestInitCommand_Run/already-installed-no-op/-subtest-0 (0.00s)
    --- PASS: TestInitCommand_Run/already-installed-upgrade (2.08s)
        --- PASS: TestInitCommand_Run/already-installed-upgrade/-subtest-0 (0.07s)
    --- PASS: TestInitCommand_Run/release-with-no-binary (0.21s)
    --- PASS: TestInitCommand_Run/manually-installed-single-component-plugin-works (1.20s)
        --- PASS: TestInitCommand_Run/manually-installed-single-component-plugin-works/-subtest-0 (0.01s)
    --- PASS: TestInitCommand_Run/manually-installed-single-component-plugin-old-api-fails (1.88s)
        --- PASS: TestInitCommand_Run/manually-installed-single-component-plugin-old-api-fails/-subtest-0 (0.01s)
    --- PASS: TestInitCommand_Run/unsupported-non-github-source-address (0.00s)
```
2021-02-16 14:03:29 -05:00
Wilken Rivera f48583c57e github/getter: Adds a hostname check to Get function
This change adds a simple hostname validation check to validate that a
plugins source address is github.com before continuing with the Get
call. An issue was encountered when using a hostname different from
github.com, where the getter would continue to pull a plugin from GitHub
even if the hostname was something like "example.com". See log details
below.

Before change
```
2021/02/16 12:49:41 [TRACE] fetching checksums file for the "0.0.2" version of the example.com/hashicorp/docker plugin in
"/home/wilken/.packer.d/plugins/example.com/hashicorp/docker"...

2021/02/16 12:49:41 [DEBUG] github-getter: getting "https://github.com/hashicorp/packer-plugin-docker/releases/download/v0.0.2/packer-plugin-docker_v0.0.2_SHA256SUMS"
2021/02/16 12:49:42 [TRACE] Ignoring remote binary packer-plugin-docker_v0.0.2_x5.0_linux_arm64.zip, wrong system, expected
2021/02/16 12:49:42 [TRACE] About to get: packer-plugin-docker_v0.0.2_x5.0_linux_amd64.zip
2021/02/16 12:49:42 [DEBUG] github-getter: getting "https://github.com/hashicorp/packer-plugin-docker/releases/download/v0.0.2/packer-plugin-docker_v0.0.2_x5.0_linux_amd64.zip"
```

After change
```
2021/02/16 13:36:32 [TRACE] for plugin example.com/hashicorp/docker found 0 matching installation(s)
2021/02/16 13:36:32 [TRACE] getting available versions for the the example.com/hashicorp/docker plugin
2021/02/16 13:36:32 [TRACE] &{%!q(*github.Client=<nil>) "packer-getter-github-1.7.0-dev"} getter could not get release: example.com/hashicorp/docker doesn't appear to be a valid github.com source address; check source and try again.
2021/02/16 13:36:32 [DEBUG] will try to install: []
2021/02/16 13:36:32 [INFO] (telemetry) Finalizing.  no release version found for the example.com/hashicorp/docker plugin matching the constraint(s): ">=v0.0.2"
2021/02/16 13:36:32 waiting for all plugin processes to complete...
```
2021-02-16 13:38:57 -05:00
Zach Shilton 6cc3933c77 Bump components to remove md processing, fix theme 2021-02-16 12:55:09 -05:00
Adrien Delorme 4409991887 add emojis to version table 2021-02-16 14:37:24 +01:00
sylviamoss 6e195f92e8 update components docs 2021-02-16 14:31:05 +01:00
Sylvia Moss 715fe51517 Update website/content/docs/commands/fix.mdx
Co-authored-by: Adrien Delorme <azr@users.noreply.github.com>
2021-02-16 14:09:32 +01:00
Adrien Delorme d2a8408577 update "how to comment in json" guide 2021-02-16 13:57:33 +01:00
Adrien Delorme 192e85951f packer build template.pkr.hcl in .github/CONTRIBUTING.md 2021-02-16 13:54:49 +01:00
Adrien Delorme e2a337e0ea packer build template.pkr.hcl 2021-02-16 13:49:13 +01:00
sylviamoss c29b9f957d reorder terminology 2021-02-16 12:51:49 +01:00
Sylvia Moss 514be931be Update website/content/partials/guides/hcl2-beta-note.mdx
Co-authored-by: Adrien Delorme <azr@users.noreply.github.com>
2021-02-16 12:48:39 +01:00
Sylvia Moss 1049db4f98 Update website/content/docs/commands/fix.mdx
Co-authored-by: Adrien Delorme <azr@users.noreply.github.com>
2021-02-16 12:48:33 +01:00
sylviamoss 9ce9f49f4d fix types and add text to templates index 2021-02-16 12:48:07 +01:00
sylviamoss 47adccabf2 swtichs the sidebar order of HCL and JSON templates 2021-02-16 10:13:05 +01:00
sylviamoss 1a20146993 update command section 2021-02-16 10:08:47 +01:00
Glenn McDonald 496e3ed07b Fix invalid link for env function docs (#10637) 2021-02-16 09:15:15 +01:00
sylviamoss 9718af4982 update hcl guides 2021-02-15 18:17:39 +01:00
Sylvia Moss e0557f84e9 Add access config to generated amazon ami data source (#10634) 2021-02-15 17:35:03 +01:00
Adrien Delorme f7ee3f8ead Update website/content/guides/1.7-template-upgrade.mdx
Co-authored-by: Sylvia Moss <moss@hashicorp.com>
2021-02-15 17:24:56 +01:00
Adrien Delorme 8208f425c8 addrs: remove Plugin.ForDisplay func, the String one does the job
to make things less confusing
2021-02-15 15:32:42 +01:00
Adrien Delorme 516e919c5e Update init.mdx 2021-02-15 15:15:00 +01:00
Adrien Delorme 13b34e2c73 Update 1.7-template-upgrade.mdx 2021-02-15 15:13:36 +01:00
Adrien Delorme ba87656273 Update CHANGELOG.md 2021-02-15 14:20:50 +01:00
Adrien Delorme 429262030f fix paths for windows ! 2021-02-15 14:11:00 +01:00
Adrien Delorme 4487152d1e cosmetic commit 2021-02-15 14:07:22 +01:00
Adrien Delorme 72e4dc4cb5 update docs to remove 'magic' required_plugin block usages 2021-02-15 13:58:58 +01:00
Adrien Delorme 7809242f41 quote template example 2021-02-15 13:47:40 +01:00
Adrien Delorme 632e918c52 Update plugins_test.go 2021-02-15 13:47:40 +01:00
Adrien Delorme 4cb94a67b0 Update types.variables.go 2021-02-15 13:47:40 +01:00
Adrien Delorme 029729225d tests and fixes 2021-02-15 13:47:39 +01:00
Adrien Delorme aeecfcd422 show version constrain error in case it's handy 2021-02-15 13:47:39 +01:00
Adrien Delorme 9f545c28fe required_plugins: prevent using plugin = "version", and show an example 2021-02-15 13:47:39 +01:00
Adrien Delorme fe12d53e77 addr: remove support for defaulting plugin namespace and host 2021-02-15 13:47:39 +01:00
Sylvia Moss 00fce3c46f Add v1.7.0 template upgrade guide (#10615) 2021-02-15 11:38:11 +01:00
Megan Marsh bd7b31853e Multi plugin naming (#10608) 2021-02-15 11:10:43 +01:00
Megan Marsh cac6b04546 update help text for hcl2_upgrade (#10624) 2021-02-15 11:03:44 +01:00
Megan Marsh 80ed988ffe Hcl2 upgrade fix (#10625)
* fix random nil pointer dereference I found while debugging hcl2_upgrade issues

* fix hcl2_upgrade command by creating passthroughs for all text template fields
2021-02-15 10:40:21 +01:00
Megan Marsh b20dea6aec Merge pull request #10614 from hashicorp/azr_acc_test_old_single_component_plugins
Acc test "old style" single component plugins
2021-02-12 14:22:29 -08:00
Megan Marsh 4f5af3b919 Merge pull request #10619 from hashicorp/hcl2_upgrade_annotations
Add -with-annotation flag to hcl2_upgrade command
2021-02-12 14:17:10 -08:00
sylviamoss e69410b633 fix lint 2021-02-12 15:38:44 +01:00
sylviamoss 855ba9775a add docs 2021-02-12 15:31:13 +01:00
sylviamoss 76e3d57cae add with-annotation flag to hcl2_upgrade 2021-02-12 15:18:53 +01:00
Adrien Delorme 7089e0854a rename setup func to avoid name conflict 2021-02-11 18:00:18 +01:00
Adrien Delorme 40c2b2a153 add manually-installed-single-component-plugin-old-api-fails 2021-02-11 16:55:30 +01:00
Adrien Delorme 3677069010 test: manually-installed-single-component-plugin-works 2021-02-11 16:35:08 +01:00
Adrien Delorme b321c64c1e Update init_test.go 2021-02-11 15:26:33 +01:00
Adrien Delorme ad0ce49cec fix tmpdir creation 2021-02-11 15:17:05 +01:00
Adrien Delorme 021044e963 put name first 2021-02-11 14:56:42 +01:00
Adrien Delorme ba8484ee6b tests: pre make dir in case nothing happens 2021-02-11 14:49:52 +01:00
Adrien Delorme 3052e3c5d5 tests 2021-02-11 14:46:53 +01:00
Sylvia Moss c5fca1f876 Make template documentation visible from components docs (#10611) 2021-02-11 14:21:06 +01:00
Adrien Delorme 915372c73d get packer plugin sdk version 0.0.12 (#10612) 2021-02-11 14:14:04 +01:00
Adrien Delorme 37769c2b95 Change PKR_GITHUB_API_TOKEN to PACKER_GITHUB_API_TOKEN to stay consistent with other env var settings (#10588) 2021-02-11 13:54:25 +01:00
Trond Isak 2c08479825 add AWS API call retries on AMIGetFilteredImage (#10610) 2021-02-11 11:58:56 +01:00
Sylvia Moss 774c5903f6 Add error-cleanup-provisioner to HCL2 (#10604) 2021-02-11 10:23:15 +01:00
Megan Marsh fd8e76636a Merge pull request #10599 from hashicorp/extending-packer-updates
Extending packer updates
2021-02-10 16:05:56 -08:00
Robert Neumayer 50a6732859 Use http constants and use switch instead of if 2021-02-10 16:46:00 +01:00
Wilken Rivera 4e2d2961b6 Update with suggestion from review 2021-02-10 10:37:24 -05:00
Wilken Rivera 926e287025 Apply suggestions from code review
Co-authored-by: Megan Marsh <megan@hashicorp.com>
Co-authored-by: Adrien Delorme <azr@users.noreply.github.com>
2021-02-10 10:33:01 -05:00
Sylvia Moss d28e6fe009 write timestamp local only when necessary (#10602) 2021-02-10 14:54:19 +01:00
Sylvia Moss 1e889078fd add regex and regexall functions (#10601) 2021-02-10 11:58:20 +01:00
Calle Pettersson 6c77d28537 proxmox: Fix additional_iso_files (#10586) 2021-02-10 10:59:44 +01:00
Megan Marsh 92f384b52f update changelog 2021-02-09 14:08:27 -08:00
Wilken Rivera 29beb051c5 Fix borken URL 2021-02-09 15:37:03 -05:00
Wilken Rivera bb03a321f2 Add distributing migrated plugins section 2021-02-09 15:28:03 -05:00
Wilken Rivera 25b2ab9082 guides/1-7-plugin-upgrade: Update migration guide
* Add text to call out the packer-sdk-migrator tool.
* Add text around the naming conventions for registering multi-plugins
2021-02-09 14:23:44 -05:00
Wilken Rivera 9986834a62 website/commands/init: Add blurb on plugin selection
This change adds text around how plugin selection for plugins defined in
a require_plugins block work. It also adds a small call out to users
that third party plugins are not verified by HashiCorp.
2021-02-09 12:19:15 -05:00
Sylvia Moss 368ccfe7c9 add profitbricks code owners (#10596) 2021-02-09 11:29:24 -05:00
Adrien Delorme ffbb110167 Test running plugins with fake and fresh plugins (#10595)
* show error as to why plugin discovery failed
* allow to run more manual tests after a plugin installation
* test that a freshly installed external plugin can run
2021-02-09 17:07:59 +01:00
mflorin 9afaa5a21f Profitbricks builder fixes (#10549) 2021-02-09 16:56:06 +01:00
Robert Neumayer bcd60c3895 Improve retry policy 2021-02-09 16:16:10 +01:00
Sylvia Moss f5006d0842 fix empty locals and source name with blank space (#10593) 2021-02-09 14:57:42 +01:00
Jessi 88c516b2d5 Add IMDSv2 support for AWS EBS builder (#10546) 2021-02-09 11:47:54 +01:00
Robert Neumayer 6b947edd04 Add retry strategies to oci calls
The oci api returns 429, among others in case a per-user rate limit is
hit. Currently our only mechanism to deal with this is to wait 5s
between the requests that poll for image availability (and export).

With a custom retry strategy we can handle more error situations while
putting less load on the api.
2021-02-09 09:33:43 +01:00
Bryce Kalow d7bb60ea86 website: update next and nextjs-scripts (#10570)
website: update next and nextjs-scripts
2021-02-08 14:48:35 -06:00
Megan Marsh 08e67f8990 Merge pull request #10587 from hashicorp/azr_doc_init_less_highlights
Document init with less highlights
2021-02-08 11:09:04 -08:00
Wilken Rivera 8c3b3ca00f Update website/content/docs/commands/init.mdx 2021-02-08 13:34:14 -05:00
Bryce Kalow 4a686ef66d chore: upgrade nextjs-scripts & next 2021-02-08 17:47:18 +00:00
Sylvia Moss f616955ebc Fix issue when loading datasource single plugin type (#10589) 2021-02-08 13:58:35 +01:00
Adrien Delorme a1b2e71005 Update website/content/docs/commands/init.mdx
Co-authored-by: Sylvia Moss <moss@hashicorp.com>
2021-02-08 13:53:29 +01:00
Sylvia Moss d53488db68 Add aws_secretsmanager transformation to hcl2_upgrade (#10553) 2021-02-08 11:28:26 +01:00
Adrien Delorme b6cfe16444 Document the PKR_GITHUB_API_TOKEN setting in /configure#env vars 2021-02-08 10:59:04 +01:00
Adrien Delorme 4c02123142 init documentation: have less highlights and more text 2021-02-08 10:58:14 +01:00
Megan Marsh 13320650f0 document builder id of artifact for each builder's output on website (#10580)
* document builder id of artifact for each builder's output on website

* document postprocessor artifact ids on website

* Fix links to new communicator page

Co-authored-by: Wilken Rivera <dev@wilkenrivera.com>
2021-02-05 19:49:28 -05:00
Megan Marsh 2324f433f7 Merge pull request #10579 from hashicorp/fix-single-plugin-loading
Fix issue when loading single plugin type `packer-provisioner-comment` built with latest SDK
2021-02-05 14:06:27 -08:00
Megan Marsh ece5e94c3d remove dev line (#10578) 2021-02-05 16:47:41 -05:00
Wilken Rivera ad239bd2b9 Fix markdown link checker issues (#10575)
* Remove exclusions for docs on master

* Update extending redirects with new page locations

* Update documentation links for SaltStack
2021-02-05 16:46:53 -05:00
Wilken Rivera 39d550054d Fix lint errors 2021-02-05 16:46:24 -05:00
Wilken Rivera ef4d35097b Fix issue when loading single plugin type
This changes wraps the plugin client start call with an anonymous function so that Packer starts a
new plugin for each occurrence of a particular plugin block.

Before only one subprocess was being created causing subsquent calls to fail as it was trying start
an already started plugin subprocess.

Before Change
```
???????: failed loading comment: error dial unix /tmp/packer-plugin358226172: connect: no such file or directory
2021/02/05 16:09:13 On error:
2021/02/05 16:09:13 Waiting on builds to complete...

2021/02/05 16:09:13 Starting build run: null.basic-example
2021/02/05 16:09:13 Running builder:
2021/02/05 16:09:13 [INFO] (telemetry) Starting builder
  on examples/basic-example.pkr.hcl line 29:
  (source code not available)

dial unix /tmp/packer-plugin358226172: connect: no such file or directory

???????: failed loading comment: error dial unix /tmp/packer-plugin358226172: connect: no such file or directory

2021/02/05 16:09:13 packer.test plugin: [INFO] communicator disabled, will not connect
2021/02/05 16:09:13 packer.test plugin: Unable to load communicator config from state to populate provisionHookData
  on examples/basic-example.pkr.hcl line 38:
2021/02/05 16:09:13 packer.test plugin: Running the provision hook
  (source code not available)

dial unix /tmp/packer-plugin358226172: connect: no such file or directory

???????: failed loading comment: error dial unix /tmp/packer-plugin358226172: connect: no such file or directory

  on examples/basic-example.pkr.hcl line 42:
  (source code not available)

2021/02/05 16:09:13 [INFO] (telemetry) Starting provisioner comment
dial unix /tmp/packer-plugin358226172: connect: no such file or directory
```

After change
```

null.basic-example: output will be in this color.

==> null.basic-example:   ____                   _
==> null.basic-example:  | __ )    ___    __ _  (_)  _ __
==> null.basic-example:  |  _ \   / _ \  / _` | | | | '_ \
==> null.basic-example:  | |_) | |  __/ | (_| | | | | | | |
==> null.basic-example:  |____/   \___|  \__, | |_| |_| |_|
==> null.basic-example:                  |___/
==> null.basic-example:
==> null.basic-example: Running local shell script: /tmp/packer-shell646549657
    null.basic-example: This is a shell script
==> null.basic-example: Pausing at breakpoint provisioner.
==> null.basic-example: Press enter to continue.
==> null.basic-example: In the middle of Provisioning run
==> null.basic-example: Running local shell script: /tmp/packer-shell177279484
    null.basic-example: This is another shell script
==> null.basic-example:   _____               _
==> null.basic-example:  | ____|  _ __     __| |
==> null.basic-example:  |  _|   | '_ \   / _` |
==> null.basic-example:  | |___  | | | | | (_| |
==> null.basic-example:  |_____| |_| |_|  \__,_|
==> null.basic-example:
Build 'null.basic-example' finished after 1 second 32 milliseconds.

==> Wait completed after 1 second 32 milliseconds

==> Builds finished. The artifacts of successful builds are:
--> null.basic-example: Did not export anything. This is the null builder
 Please enter the commit message for your changes. Lines starting
```
2021-02-05 16:35:01 -05:00
Megan Marsh a63ad19b0c Merge pull request #10577 from hashicorp/fix_build_run_diags
plugin loading failure should be considered an error so build will no…
2021-02-05 13:31:40 -08:00
Megan Marsh ca123721a6 plugin loading failure should be considered an error so build will not try to run 2021-02-05 11:06:52 -08:00
Alex Chan 540effbbc0 Correct the spelling of heirarchical/hierarchical (#10576) 2021-02-05 16:32:28 +01:00
John Trowbridge 30b0229fb4 Fix vendor 2021-02-03 12:26:24 -05:00
John Trowbridge 34b86c0228 Update Oracle Go SDK
Currently, the oracle-oci builder is broken, because it is unable
to read the key file provide by Oracle cloud. Updating to the
latest oci-go-sdk fixes the issue.
2021-02-03 10:44:12 -05:00
Ali Rizvi-Santiago 9b1d31cee7 Added a fallback to the vmware builder when trying to determine the networkmapping configuration.
Some instances of VMWare will not generate the networkmapping configuration (netmap.conf)
at the time of installation. To deal with this issue, we check for the networkmapping file
first, and then fallback to the networking file which also might exist and contain the
interface information that we require.

This fixes issue #10009.
2021-01-05 11:24:50 -06:00
541 changed files with 50106 additions and 71688 deletions
+2 -2
View File
@@ -19,7 +19,7 @@ can quickly merge or address your contributions.
already fixed the bug you're experiencing.
- Run the command with debug output with the environment variable `PACKER_LOG`.
For example: `PACKER_LOG=1 packer build template.json`. Take the _entire_
For example: `PACKER_LOG=1 packer build template.pkr.hcl`. Take the _entire_
output and create a [gist](https://gist.github.com) for linking to in your
issue. Packer should strip sensitive keys from the output, but take a look
through just in case.
@@ -91,7 +91,7 @@ The instructions below are for go 1.7. or later.
4. After running building Packer successfully, use
`$GOPATH/src/github.com/hashicorp/packer/bin/packer` to build a machine and
verify your changes work. For instance:
`$GOPATH/src/github.com/hashicorp/packer/bin/packer build template.json`.
`$GOPATH/src/github.com/hashicorp/packer/bin/packer build template.pkr.hcl`.
5. If everything works well and the tests pass, run `go fmt` on your code before
submitting a pull-request.
+87 -3
View File
@@ -1,15 +1,99 @@
## 1.7.0 (Upcoming)
## 1.7.1 (Upcoming)
### FEATURES
### IMPROVEMENTS
* core: Change template parsing error to include warning about file extensions.
[GH-10652]
### BUG FIXES
* builder/azure: Don't overwrite subscription id if unset. [GH-10659]
* builder/oracle-oci: Update Oracle Go SDK to fix issue with reading key file.
[GH-10560]
* core/hcl2_upgrade: Make hcl2_upgrade command correctly translate
pause_before. [GH-10654]
* core: Templates previously could not interpolate the environment variable
PACKER_LOG_PATH. [GH-10660]
## 1.7.0 (February 17, 2021)
### FEATURES
* **New Command** (HCL only) `packer init` command will download plugins defined
in a new `required_plugins` block [GH-10304] [GH-10633].
* **New Plugin Type** Data sources can be implemented (blog post forthcoming).
[GH-10440]
* **New Plugin** Aws Secrets Manager data source [GH-10505] [GH-10467]
### BACKWARDS INCOMPATIBILITIES
* core: The API that the Packer core uses to communicate with community plugins
has changed; maintainers of community plugins will need to upgrade their
plugins in order to make them compatible with v1.7.0. An upgrade guide will
be available on our guides page https://www.packer.io/guides.
### IMPROVEMENTS
* builder/amazon: Add `skip_create_ami` option for testing and situations where
artifact is not the ami. [GH-10531]
* builder/amazon: Add IMDSv2 support for AWS EBS builder. [GH-10546]
* builder/amazon: Add resource tags in the launch template used to request spot
instances. [GH-10456]
* builder/openstack: Add `skip_create_image` option for testing and situations
where artifact is not the image. [GH-10496]
* builder/oracle-oci: Add retry strategies to oci calls [GH-10591]
* core/fmt: The `packer fmt` can now read from stdin. [GH-10500]
* core/hcl: Add regex and regexall hcl2 template functions. [GH-10601]
* core/hcl: Templates now support "sensitive" locals. [GH-10509]
* core/hcl: Templates now support error-cleanup-provisioner. [GH-10604]
* hcl2_upgrade: Command now comes with a flag so you can control whether output
templates are annotated with helpful comments. [GH-10619]
* hcl2_upgrade: Command now gracefully handles options with template engine
interpolations. [GH-10625]
* hcl2_upgrade: Command will convert amazon filters to use the ami data source.
[GH-10491]
### BUG FIXES
* amazon/ebssurrogate: Apply snapshot tags at same time as when taking
snapshot. [GH-10150]
* builder/amazon: Fix bug where validation fails if optional iops value is
unset. [GH-10518]
* builder/amazon: Wrap API call to get filtered image in a retry. [GH-10610]
* builder/bsusurrogate: override bsu when omi root device is set. [GH-10490]
* builder/google: Fix bug where Packer would fail when run by users who do not
have permission to access the metadata, even though the metadata is not
necessary to the run. [GH-10458]
* builder/profitbricks: Profitbricks builder could not connect using SSH
communicator. [GH-10549]
* builder/proxmox: Ensure ISOs in additional_iso_files are mounted during VM
creation. [GH-10586]
* builder/proxmox: Improve cloud init error logging for proxmox builder.
[GH-10499]
* builder/qemu: Fix bug where vnc_min_port set to value greater then 5900 could
prevent Packer from connecting to QEMU. [GH-10450] [GH-10451]
* builder/qemu: Fix regression with cd indexing when disk_interface is `ide`.
[GH-10519]
* builder/vmware-esx: Skip credential validation, which requires ovftool to be
installed, if we are not exporting an image. [GH-10520]
* builder/yandex: Fix cloud-init config for ubuntu 20.04. [GH-10522]
* builder/yandex: Fix incorrect access to `instance_id`. [GH-10522]
* core/hcl: Fix bug where []uint8 types could not be passed to plugins.
* core/hcl: fix bug where HCL core could not handle passing []uint8 to plugins.
[GH-10516]
* core/hcl: Fix force flag for hcl2 provisioners and post-processors.
[GH-10571]
* post-processor/vsphere: Fix regression where Packer would not check the exit
status after streaming UI from the ovftool command. [GH-10468]
* post-processor/yandex-export: Changed dhclient command and supported
configuring disk for exportupdate-dump-method. Also added support for
`file` builder. [GH-10488]
## 1.6.6 (December 16, 2020)
### FEATURES:
### FEATURES
* **New command** `fmt` allows users to format existing HCL2 configuration
files into a canonical style. Please see [fmt command
docs](https://packer.io/docs/commands/fmt) for more details. [GH-10225]
[GH-10377]
* **New function** `env` allows users to set the default value of a variable to
the value of an environment variable. Please see [env function
docs](https://www.packer.io/docs/templates/hcl_templates/functions/contextual/env") for
docs](https://www.packer.io/docs/templates/hcl_templates/functions/contextual/env) for
more details. [GH-10240]
* **Future Scaffolding** This release contains a large number of no-op
refactoring changes. The Packer team at HashiCorp is preparing to split the
+2 -2
View File
@@ -37,8 +37,8 @@
/builder/oracle/ @prydie @owainlewis
/website/pages/docs/builders/oracle* @prydie @owainlewis
/builder/profitbricks/ @jasmingacic
/website/pages/docs/builders/profitbricks* @jasmingacic
/builder/profitbricks/ @LiviusP @mflorin
/website/pages/docs/builders/profitbricks* @LiviusP @mflorin
/builder/triton/ @sean-
/website/pages/docs/builders/triton* @sean-
+10 -10
View File
@@ -174,6 +174,16 @@ type AccessConfig struct {
// credential types) and GetFederationToken (for federation\_token
// credential types) for more details.
//
// HCL2 example:
//
// ```hcl
// vault_aws_engine {
// name = "myrole"
// role_arn = "myarn"
// ttl = "3600s"
// }
// ```
//
// JSON example:
//
// ```json
@@ -185,16 +195,6 @@ type AccessConfig struct {
// }
// }
// ```
//
// HCL2 example:
//
// ```hcl
// vault_aws_engine {
// name = "myrole"
// role_arn = "myarn"
// ttl = "3600s"
// }
// ```
VaultAWSEngine VaultAWSEngineOptions `mapstructure:"vault_aws_engine" required:"false"`
// [Polling configuration](#polling-configuration) for the AWS waiter. Configures the waiter that checks
// resource state.
+2 -12
View File
@@ -5,20 +5,10 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
)
func testAccessConfig() *AccessConfig {
return &AccessConfig{
getEC2Connection: func() ec2iface.EC2API {
return &mockEC2Client{}
},
PollingConfig: new(AWSPollingConfig),
}
}
func TestAccessConfigPrepare_Region(t *testing.T) {
c := testAccessConfig()
c := FakeAccessConfig()
c.RawRegion = "us-east-12"
err := c.ValidateRegion(c.RawRegion)
@@ -40,7 +30,7 @@ func TestAccessConfigPrepare_Region(t *testing.T) {
}
func TestAccessConfigPrepare_RegionRestricted(t *testing.T) {
c := testAccessConfig()
c := FakeAccessConfig()
// Create a Session with a custom region
c.session = session.Must(session.NewSession(&aws.Config{
+2 -20
View File
@@ -135,26 +135,8 @@ type AMIConfig struct {
// the intermediary AMI into any regions provided in `ami_regions`, then
// delete the intermediary AMI. Default `false`.
AMISkipBuildRegion bool `mapstructure:"skip_save_build_region"`
// Key/value pair tags to apply to snapshot. They will override AMI tags if
// already applied to snapshot. This is a [template
// engine](/docs/templates/legacy_json_templates/engine), see [Build template
// data](#build-template-data) for more information.
SnapshotTags map[string]string `mapstructure:"snapshot_tags" required:"false"`
// Same as [`snapshot_tags`](#snapshot_tags) but defined as a singular
// repeatable block containing a `key` and a `value` field. In HCL2 mode the
// [`dynamic_block`](/docs/templates/hcl_templates/expressions#dynamic-blocks)
// will allow you to create those programatically.
SnapshotTag config.KeyValues `mapstructure:"snapshot_tag" required:"false"`
// A list of account IDs that have
// access to create volumes from the snapshot(s). By default no additional
// users other than the user creating the AMI has permissions to create
// volumes from the backing snapshot(s).
SnapshotUsers []string `mapstructure:"snapshot_users" required:"false"`
// A list of groups that have access to
// create volumes from the snapshot(s). By default no groups have permission
// to create volumes from the snapshot(s). all will make the snapshot
// publicly accessible.
SnapshotGroups []string `mapstructure:"snapshot_groups" required:"false"`
SnapshotConfig `mapstructure:",squash"`
}
func stringInSlice(s []string, searchstr string) bool {
+6 -11
View File
@@ -7,7 +7,6 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
"github.com/hashicorp/packer-plugin-sdk/template/config"
)
@@ -18,14 +17,14 @@ func testAMIConfig() *AMIConfig {
}
func getFakeAccessConfig(region string) *AccessConfig {
c := testAccessConfig()
c := FakeAccessConfig()
c.RawRegion = region
return c
}
func TestAMIConfigPrepare_name(t *testing.T) {
c := testAMIConfig()
accessConf := testAccessConfig()
accessConf := FakeAccessConfig()
if err := c.Prepare(accessConf, nil); err != nil {
t.Fatalf("shouldn't have err: %s", err)
}
@@ -36,10 +35,6 @@ func TestAMIConfigPrepare_name(t *testing.T) {
}
}
type mockEC2Client struct {
ec2iface.EC2API
}
func (m *mockEC2Client) DescribeRegions(*ec2.DescribeRegionsInput) (*ec2.DescribeRegionsOutput, error) {
return &ec2.DescribeRegionsOutput{
Regions: []*ec2.Region{
@@ -56,7 +51,7 @@ func TestAMIConfigPrepare_regions(t *testing.T) {
var errs []error
var err error
accessConf := testAccessConfig()
accessConf := FakeAccessConfig()
mockConn := &mockEC2Client{}
if errs = c.prepareRegions(accessConf); len(errs) > 0 {
t.Fatalf("shouldn't have err: %#v", errs)
@@ -163,7 +158,7 @@ func TestAMIConfigPrepare_Share_EncryptedBoot(t *testing.T) {
c.AMIUsers = []string{"testAccountID"}
c.AMIEncryptBootVolume = config.TriTrue
accessConf := testAccessConfig()
accessConf := FakeAccessConfig()
c.AMIKmsKeyId = ""
if err := c.Prepare(accessConf, nil); err == nil {
@@ -179,7 +174,7 @@ func TestAMIConfigPrepare_ValidateKmsKey(t *testing.T) {
c := testAMIConfig()
c.AMIEncryptBootVolume = config.TriTrue
accessConf := testAccessConfig()
accessConf := FakeAccessConfig()
validCases := []string{
"abcd1234-e567-890f-a12b-a123b4cd56ef",
@@ -215,7 +210,7 @@ func TestAMIConfigPrepare_ValidateKmsKey(t *testing.T) {
func TestAMINameValidation(t *testing.T) {
c := testAMIConfig()
accessConf := testAccessConfig()
accessConf := FakeAccessConfig()
c.AMIName = "aa"
if err := c.Prepare(accessConf, nil); err == nil {
+4 -1
View File
@@ -51,7 +51,10 @@ func (d *AmiFilterOptions) GetFilteredImage(params *ec2.DescribeImagesInput, ec2
}
log.Printf("Using AMI Filters %v", params)
imageResp, err := ec2conn.DescribeImages(params)
req, imageResp := ec2conn.DescribeImagesRequest(params)
req.RetryCount = 11
err := req.Send()
if err != nil {
err := fmt.Errorf("Error querying AMI: %s", err)
return nil, err
+11 -12
View File
@@ -30,18 +30,6 @@ const (
// The following mapping will tell Packer to encrypt the root volume of the
// build instance at launch using a specific non-default kms key:
//
// JSON example:
//
// ```json
// launch_block_device_mappings: [
// {
// "device_name": "/dev/sda1",
// "encrypted": true,
// "kms_key_id": "1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d"
// }
// ]
// ```
//
// HCL2 example:
//
// ```hcl
@@ -52,6 +40,17 @@ const (
// }
// ```
//
// JSON example:
// ```json
// launch_block_device_mappings: [
// {
// "device_name": "/dev/sda1",
// "encrypted": true,
// "kms_key_id": "1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d"
// }
// ]
// ```
//
// Please note that the kms_key_id option in this example exists for
// launch_block_device_mappings but not ami_block_device_mappings.
//
+117 -57
View File
@@ -1,5 +1,5 @@
//go:generate struct-markdown
//go:generate mapstructure-to-hcl2 -type AmiFilterOptions,SecurityGroupFilterOptions,SubnetFilterOptions,VpcFilterOptions,PolicyDocument,Statement
//go:generate mapstructure-to-hcl2 -type AmiFilterOptions,SecurityGroupFilterOptions,SubnetFilterOptions,VpcFilterOptions,PolicyDocument,Statement,MetadataOptions
package common
@@ -44,6 +44,20 @@ type SecurityGroupFilterOptions struct {
config.NameValueFilter `mapstructure:",squash"`
}
// Configures the metadata options.
// See [Configure IMDS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html) for details.
type MetadataOptions struct {
// A string to enable or disble the IMDS endpoint for an instance. Defaults to enabled.
// Accepts either "enabled" or "disabled"
HttpEndpoint string `mapstructure:"http_endpoint" required:"false"`
// A string to either set the use of IMDSv2 for the instance to optional or required. Defaults to "optional".
// Accepts either "optional" or "required"
HttpTokens string `mapstructure:"http_tokens" required:"false"`
// A numerical value to set an upper limit for the amount of hops allowed when communicating with IMDS endpoints.
// Defaults to 1.
HttpPutResponseHopLimit int64 `mapstructure:"http_put_response_hop_limit" required:"false"`
}
// RunConfig contains configuration for running an instance from a source
// AMI and details on how to access that launched image.
type RunConfig struct {
@@ -118,8 +132,21 @@ type RunConfig struct {
// Whether or not to check if the IAM instance profile exists. Defaults to false
SkipProfileValidation bool `mapstructure:"skip_profile_validation" required:"false"`
// Temporary IAM instance profile policy document
// If IamInstanceProfile is specified it will be used instead. Example:
// If IamInstanceProfile is specified it will be used instead.
//
// HCL2 example:
// ```hcl
//temporary_iam_instance_profile_policy_document {
// Statement {
// Action = ["logs:*"]
// Effect = "Allow"
// Resource = "*"
// }
// Version = "2012-10-17"
//}
// ```
//
// JSON example:
// ```json
//{
// "Version": "2012-10-17",
@@ -143,17 +170,7 @@ type RunConfig struct {
// The EC2 instance type to use while building the
// AMI, such as t2.small.
InstanceType string `mapstructure:"instance_type" required:"true"`
// Filters used to populate the `security_group_ids` field. JSON Example:
//
// ```json
// {
// "security_group_filter": {
// "filters": {
// "tag:Class": "packer"
// }
// }
// }
// ```
// Filters used to populate the `security_group_ids` field.
//
// HCL2 Example:
//
@@ -165,6 +182,17 @@ type RunConfig struct {
// }
// ```
//
// JSON Example:
// ```json
// {
// "security_group_filter": {
// "filters": {
// "tag:Class": "packer"
// }
// }
// }
// ```
//
// This selects the SG's with tag `Class` with the value `packer`.
//
// - `filters` (map of strings) - filters used to select a
@@ -199,8 +227,24 @@ type RunConfig struct {
// AMI with a root volume snapshot that you have access to.
SourceAmi string `mapstructure:"source_ami" required:"true"`
// Filters used to populate the `source_ami`
// field. JSON Example:
// field.
//
// HCL2 example:
// ```hcl
// source "amazon-ebs" "basic-example" {
// 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
// }
// }
// ```
//
// JSON Example:
// ```json
// "builders" [
// {
@@ -217,21 +261,6 @@ type RunConfig struct {
// }
// ]
// ```
// HCL2 example:
//
// ```hcl
// source "amazon-ebs" "basic-example" {
// source_ami_filter {
// filters = {
// virtualization-type = "hvm"
// name = "ubuntu/images/\*ubuntu-xenial-16.04-amd64-server-\*"
// root-device-type = "ebs"
// }
// owners = ["099720109477"]
// most_recent = true
// }
// }
// ```
//
// This selects the most recent Ubuntu 16.04 HVM EBS AMI from Canonical. NOTE:
// This will fail unless *exactly* one AMI is returned. In the above example,
@@ -299,8 +328,22 @@ type RunConfig struct {
// will allow you to create those programatically.
SpotTag config.KeyValues `mapstructure:"spot_tag" required:"false"`
// Filters used to populate the `subnet_id` field.
// JSON Example:
//
// HCL2 example:
//
// ```hcl
// source "amazon-ebs" "basic-example" {
// subnet_filter {
// filters = {
// "tag:Class": "build"
// }
// most_free = true
// random = false
// }
// }
// ```
//
// JSON Example:
// ```json
// "builders" [
// {
@@ -315,19 +358,6 @@ type RunConfig struct {
// }
// ]
// ```
// HCL2 example:
//
// ```hcl
// source "amazon-ebs" "basic-example" {
// subnet_filter {
// filters = {
// "tag:Class": "build"
// }
// most_free = true
// random = false
// }
// }
// ```
//
// This selects the Subnet with tag `Class` with the value `build`, which has
// the most free IP addresses. NOTE: This will fail unless *exactly* one
@@ -374,8 +404,21 @@ type RunConfig struct {
// data when launching the instance.
UserDataFile string `mapstructure:"user_data_file" required:"false"`
// Filters used to populate the `vpc_id` field.
// JSON Example:
//
// HCL2 example:
// ```hcl
// source "amazon-ebs" "basic-example" {
// vpc_filter {
// filters = {
// "tag:Class": "build",
// "isDefault": "false",
// "cidr": "/24"
// }
// }
// }
// ```
//
// JSON Example:
// ```json
// "builders" [
// {
@@ -390,19 +433,6 @@ type RunConfig struct {
// }
// ]
// ```
// HCL2 example:
//
// ```hcl
// source "amazon-ebs" "basic-example" {
// vpc_filter {
// filters = {
// "tag:Class": "build",
// "isDefault": "false",
// "cidr": "/24"
// }
// }
// }
// ```
//
// This selects the VPC with tag `Class` with the value `build`, which is not
// the default VPC, and have a IPv4 CIDR block of `/24`. NOTE: This will fail
@@ -426,6 +456,9 @@ type RunConfig struct {
// 10m
WindowsPasswordTimeout time.Duration `mapstructure:"windows_password_timeout" required:"false"`
// [Metadata Settings](#metadata-settings)
Metadata MetadataOptions `mapstructure:"metadata_options" required:"false"`
// Communicator settings
Comm communicator.Config `mapstructure:",squash"`
@@ -486,6 +519,33 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
// Validation
errs := c.Comm.Prepare(ctx)
if c.Metadata.HttpEndpoint == "" {
c.Metadata.HttpEndpoint = "enabled"
}
if c.Metadata.HttpTokens == "" {
c.Metadata.HttpTokens = "optional"
}
if c.Metadata.HttpPutResponseHopLimit == 0 {
c.Metadata.HttpPutResponseHopLimit = 1
}
if c.Metadata.HttpEndpoint != "enabled" && c.Metadata.HttpEndpoint != "disabled" {
msg := fmt.Errorf("http_endpoint requires either disabled or enabled as its value")
errs = append(errs, msg)
}
if c.Metadata.HttpTokens != "optional" && c.Metadata.HttpTokens != "required" {
msg := fmt.Errorf("http_tokens requires either optional or required as its value")
errs = append(errs, msg)
}
if c.Metadata.HttpPutResponseHopLimit < 1 || c.Metadata.HttpPutResponseHopLimit > 64 {
msg := fmt.Errorf("http_put_response_hop_limit requires a number between 1 and 64")
errs = append(errs, msg)
}
// Copy singular tag maps
errs = append(errs, c.RunTag.CopyOn(&c.RunTags)...)
errs = append(errs, c.SpotTag.CopyOn(&c.SpotTags)...)
+28 -1
View File
@@ -1,4 +1,4 @@
// Code generated by "mapstructure-to-hcl2 -type AmiFilterOptions,SecurityGroupFilterOptions,SubnetFilterOptions,VpcFilterOptions,PolicyDocument,Statement"; DO NOT EDIT.
// Code generated by "mapstructure-to-hcl2 -type AmiFilterOptions,SecurityGroupFilterOptions,SubnetFilterOptions,VpcFilterOptions,PolicyDocument,Statement,MetadataOptions"; DO NOT EDIT.
package common
@@ -35,6 +35,33 @@ func (*FlatAmiFilterOptions) HCL2Spec() map[string]hcldec.Spec {
return s
}
// FlatMetadataOptions is an auto-generated flat version of MetadataOptions.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatMetadataOptions struct {
HttpEndpoint *string `mapstructure:"http_endpoint" required:"false" cty:"http_endpoint" hcl:"http_endpoint"`
HttpTokens *string `mapstructure:"http_tokens" required:"false" cty:"http_tokens" hcl:"http_tokens"`
HttpPutResponseHopLimit *int64 `mapstructure:"http_put_response_hop_limit" required:"false" cty:"http_put_response_hop_limit" hcl:"http_put_response_hop_limit"`
}
// FlatMapstructure returns a new FlatMetadataOptions.
// FlatMetadataOptions is an auto-generated flat version of MetadataOptions.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*MetadataOptions) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatMetadataOptions)
}
// HCL2Spec returns the hcl spec of a MetadataOptions.
// This spec is used by HCL to read the fields of MetadataOptions.
// The decoded values from this spec will then be applied to a FlatMetadataOptions.
func (*FlatMetadataOptions) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{
"http_endpoint": &hcldec.AttrSpec{Name: "http_endpoint", Type: cty.String, Required: false},
"http_tokens": &hcldec.AttrSpec{Name: "http_tokens", Type: cty.String, Required: false},
"http_put_response_hop_limit": &hcldec.AttrSpec{Name: "http_put_response_hop_limit", Type: cty.Number, Required: false},
}
return s
}
// FlatPolicyDocument is an auto-generated flat version of PolicyDocument.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatPolicyDocument struct {
+29
View File
@@ -0,0 +1,29 @@
//go:generate struct-markdown
package common
import "github.com/hashicorp/packer-plugin-sdk/template/config"
// SnapshotConfig is for common configuration related to creating AMIs.
type SnapshotConfig struct {
// Key/value pair tags to apply to snapshot. They will override AMI tags if
// already applied to snapshot. This is a [template
// engine](/docs/templates/legacy_json_templates/engine), see [Build template
// data](#build-template-data) for more information.
SnapshotTags map[string]string `mapstructure:"snapshot_tags" required:"false"`
// Same as [`snapshot_tags`](#snapshot_tags) but defined as a singular
// repeatable block containing a `key` and a `value` field. In HCL2 mode the
// [`dynamic_block`](/docs/templates/hcl_templates/expressions#dynamic-blocks)
// will allow you to create those programatically.
SnapshotTag config.KeyValues `mapstructure:"snapshot_tag" required:"false"`
// A list of account IDs that have
// access to create volumes from the snapshot(s). By default no additional
// users other than the user creating the AMI has permissions to create
// volumes from the backing snapshot(s).
SnapshotUsers []string `mapstructure:"snapshot_users" required:"false"`
// A list of groups that have access to
// create volumes from the snapshot(s). By default no groups have permission
// to create volumes from the snapshot(s). all will make the snapshot
// publicly accessible.
SnapshotGroups []string `mapstructure:"snapshot_groups" required:"false"`
}
+17 -12
View File
@@ -42,17 +42,8 @@ type StateChangeConf struct {
// Polling configuration for the AWS waiter. Configures the waiter for resources creation or actions like attaching
// volumes or importing image.
// Usage example:
//
// In JSON:
// ```json
// "aws_polling" : {
// "delay_seconds": 30,
// "max_attempts": 50
// }
// ```
//
// In HCL2:
// HCL2 example:
// ```hcl
// aws_polling {
// delay_seconds = 30
@@ -60,6 +51,13 @@ type StateChangeConf struct {
// }
// ```
//
// JSON example:
// ```json
// "aws_polling" : {
// "delay_seconds": 30,
// "max_attempts": 50
// }
// ```
type AWSPollingConfig struct {
// Specifies the maximum number of attempts the waiter will check for resource state.
// This value can also be set via the AWS_MAX_ATTEMPTS.
@@ -151,15 +149,22 @@ func (w *AWSPollingConfig) WaitUntilVolumeAvailable(ctx aws.Context, conn *ec2.E
return err
}
func (w *AWSPollingConfig) WaitUntilSnapshotDone(ctx aws.Context, conn *ec2.EC2, snapshotID string) error {
func (w *AWSPollingConfig) WaitUntilSnapshotDone(ctx aws.Context, conn ec2iface.EC2API, snapshotID string) error {
snapInput := ec2.DescribeSnapshotsInput{
SnapshotIds: []*string{&snapshotID},
}
waitOpts := w.getWaiterOptions()
if len(waitOpts) == 0 {
// Bump this default to 30 minutes.
// Large snapshots can take a long time for the copy to s3
waitOpts = append(waitOpts, request.WithWaiterMaxAttempts(120))
}
err := conn.WaitUntilSnapshotCompletedWithContext(
ctx,
&snapInput,
w.getWaiterOptions()...)
waitOpts...)
return err
}
@@ -105,7 +105,7 @@ func TestStepAMIRegionCopy_duplicates(t *testing.T) {
// ------------------------------------------------------------------------
stepAMIRegionCopy := StepAMIRegionCopy{
AccessConfig: testAccessConfig(),
AccessConfig: FakeAccessConfig(),
Regions: []string{"us-east-1"},
AMIKmsKeyId: "12345",
// Original region key in regionkeyids is different than in amikmskeyid
@@ -131,7 +131,7 @@ func TestStepAMIRegionCopy_duplicates(t *testing.T) {
// the ami is only copied once.
stepAMIRegionCopy = StepAMIRegionCopy{
AccessConfig: testAccessConfig(),
AccessConfig: FakeAccessConfig(),
Regions: []string{"us-east-1"},
Name: "fake-ami-name",
OriginalRegion: "us-east-1",
@@ -152,7 +152,7 @@ func TestStepAMIRegionCopy_duplicates(t *testing.T) {
// the ami is only copied once.
stepAMIRegionCopy = StepAMIRegionCopy{
AccessConfig: testAccessConfig(),
AccessConfig: FakeAccessConfig(),
Regions: []string{"us-east-1"},
EncryptBootVolume: config.TriFalse,
Name: "fake-ami-name",
@@ -174,7 +174,7 @@ func TestStepAMIRegionCopy_duplicates(t *testing.T) {
// ------------------------------------------------------------------------
stepAMIRegionCopy = StepAMIRegionCopy{
AccessConfig: testAccessConfig(),
AccessConfig: FakeAccessConfig(),
// Many duplicates for only 3 actual values
Regions: []string{"us-east-1", "us-west-2", "us-west-2", "ap-east-1", "ap-east-1", "ap-east-1"},
AMIKmsKeyId: "IlikePancakes",
@@ -203,7 +203,7 @@ func TestStepAMIRegionCopy_duplicates(t *testing.T) {
// ------------------------------------------------------------------------
stepAMIRegionCopy = StepAMIRegionCopy{
AccessConfig: testAccessConfig(),
AccessConfig: FakeAccessConfig(),
// Many duplicates for only 3 actual values
Regions: []string{"us-east-1", "us-west-2", "us-west-2", "ap-east-1", "ap-east-1", "ap-east-1"},
Name: "fake-ami-name",
@@ -223,7 +223,7 @@ func TestStepAMIRegionCopy_duplicates(t *testing.T) {
func TestStepAmiRegionCopy_nil_encryption(t *testing.T) {
// create step
stepAMIRegionCopy := StepAMIRegionCopy{
AccessConfig: testAccessConfig(),
AccessConfig: FakeAccessConfig(),
Regions: make([]string, 0),
AMIKmsKeyId: "",
RegionKeyIds: make(map[string]string),
@@ -249,7 +249,7 @@ func TestStepAmiRegionCopy_nil_encryption(t *testing.T) {
func TestStepAmiRegionCopy_true_encryption(t *testing.T) {
// create step
stepAMIRegionCopy := StepAMIRegionCopy{
AccessConfig: testAccessConfig(),
AccessConfig: FakeAccessConfig(),
Regions: make([]string, 0),
AMIKmsKeyId: "",
RegionKeyIds: make(map[string]string),
@@ -275,7 +275,7 @@ func TestStepAmiRegionCopy_true_encryption(t *testing.T) {
func TestStepAmiRegionCopy_nil_intermediary(t *testing.T) {
// create step
stepAMIRegionCopy := StepAMIRegionCopy{
AccessConfig: testAccessConfig(),
AccessConfig: FakeAccessConfig(),
Regions: make([]string, 0),
AMIKmsKeyId: "",
RegionKeyIds: make(map[string]string),
@@ -303,7 +303,7 @@ func TestStepAmiRegionCopy_AMISkipBuildRegion(t *testing.T) {
// ------------------------------------------------------------------------
stepAMIRegionCopy := StepAMIRegionCopy{
AccessConfig: testAccessConfig(),
AccessConfig: FakeAccessConfig(),
Regions: []string{"us-west-1"},
AMIKmsKeyId: "",
RegionKeyIds: map[string]string{"us-west-1": "abcde"},
@@ -329,7 +329,7 @@ func TestStepAmiRegionCopy_AMISkipBuildRegion(t *testing.T) {
// skip build region is false.
// ------------------------------------------------------------------------
stepAMIRegionCopy = StepAMIRegionCopy{
AccessConfig: testAccessConfig(),
AccessConfig: FakeAccessConfig(),
Regions: []string{"us-west-1"},
AMIKmsKeyId: "",
RegionKeyIds: make(map[string]string),
@@ -354,7 +354,7 @@ func TestStepAmiRegionCopy_AMISkipBuildRegion(t *testing.T) {
// skip build region is false, but encrypt is true
// ------------------------------------------------------------------------
stepAMIRegionCopy = StepAMIRegionCopy{
AccessConfig: testAccessConfig(),
AccessConfig: FakeAccessConfig(),
Regions: []string{"us-west-1"},
AMIKmsKeyId: "",
RegionKeyIds: map[string]string{"us-west-1": "abcde"},
@@ -380,7 +380,7 @@ func TestStepAmiRegionCopy_AMISkipBuildRegion(t *testing.T) {
// skip build region is true, and encrypt is true
// ------------------------------------------------------------------------
stepAMIRegionCopy = StepAMIRegionCopy{
AccessConfig: testAccessConfig(),
AccessConfig: FakeAccessConfig(),
Regions: []string{"us-west-1"},
AMIKmsKeyId: "",
RegionKeyIds: map[string]string{"us-west-1": "abcde"},
@@ -29,6 +29,9 @@ type StepRunSourceInstance struct {
EbsOptimized bool
EnableT2Unlimited bool
ExpectedRootDevice string
HttpEndpoint string
HttpTokens string
HttpPutResponseHopLimit int64
InstanceInitiatedShutdownBehavior string
InstanceType string
IsRestricted bool
@@ -144,6 +147,10 @@ func (s *StepRunSourceInstance) Run(ctx context.Context, state multistep.StateBa
runOpts.CreditSpecification = &ec2.CreditSpecificationRequest{CpuCredits: &creditOption}
}
if s.HttpEndpoint == "enabled" {
runOpts.MetadataOptions = &ec2.InstanceMetadataOptionsRequest{HttpEndpoint: &s.HttpEndpoint, HttpTokens: &s.HttpTokens, HttpPutResponseHopLimit: &s.HttpPutResponseHopLimit}
}
// Collect tags for tagging on resource creation
var tagSpecs []*ec2.TagSpecification
@@ -251,7 +258,7 @@ func (s *StepRunSourceInstance) Run(ctx context.Context, state multistep.StateBa
if resp, e := ec2conn.DescribeInstances(describeInstance); e == nil {
if len(resp.Reservations) > 0 && len(resp.Reservations[0].Instances) > 0 {
instance := resp.Reservations[0].Instances[0]
if instance.StateTransitionReason != nil && instance.StateReason.Message != nil {
if instance.StateTransitionReason != nil && instance.StateReason != nil && instance.StateReason.Message != nil {
ui.Error(fmt.Sprintf("Instance state change details: %s: %s",
*instance.StateTransitionReason, *instance.StateReason.Message))
}
@@ -34,6 +34,9 @@ type StepRunSpotInstance struct {
Comm *communicator.Config
EbsOptimized bool
ExpectedRootDevice string
HttpEndpoint string
HttpTokens string
HttpPutResponseHopLimit int64
InstanceInitiatedShutdownBehavior string
InstanceType string
Region string
@@ -51,6 +54,24 @@ type StepRunSpotInstance struct {
instanceId string
}
// The EbsBlockDevice and LaunchTemplateEbsBlockDeviceRequest structs are
// nearly identical except for the struct's name and one extra field in
// EbsBlockDeviceResuest, which unfortunately means you can't just cast one
// into the other. THANKS AMAZON.
func castBlockDeviceToRequest(bd *ec2.EbsBlockDevice) *ec2.LaunchTemplateEbsBlockDeviceRequest {
out := &ec2.LaunchTemplateEbsBlockDeviceRequest{
DeleteOnTermination: bd.DeleteOnTermination,
Encrypted: bd.Encrypted,
Iops: bd.Iops,
KmsKeyId: bd.KmsKeyId,
SnapshotId: bd.SnapshotId,
Throughput: bd.Throughput,
VolumeSize: bd.VolumeSize,
VolumeType: bd.VolumeType,
}
return out
}
func (s *StepRunSpotInstance) CreateTemplateData(userData *string, az string,
state multistep.StateBag, marketOptions *ec2.LaunchTemplateInstanceMarketOptionsRequest) *ec2.RequestLaunchTemplateData {
blockDeviceMappings := s.LaunchMappings.BuildEC2BlockDeviceMappings()
@@ -58,15 +79,12 @@ func (s *StepRunSpotInstance) CreateTemplateData(userData *string, az string,
// LaunchTemplateBlockDeviceMappingRequest. These structs are identical,
// except for the EBS field -- on one, that field contains a
// LaunchTemplateEbsBlockDeviceRequest, and on the other, it contains an
// EbsBlockDevice. The EbsBlockDevice and
// LaunchTemplateEbsBlockDeviceRequest structs are themselves
// identical except for the struct's name, so you can cast one directly
// into the other.
// EbsBlockDevice.
var launchMappingRequests []*ec2.LaunchTemplateBlockDeviceMappingRequest
for _, mapping := range blockDeviceMappings {
launchRequest := &ec2.LaunchTemplateBlockDeviceMappingRequest{
DeviceName: mapping.DeviceName,
Ebs: (*ec2.LaunchTemplateEbsBlockDeviceRequest)(mapping.Ebs),
Ebs: castBlockDeviceToRequest(mapping.Ebs),
VirtualName: mapping.VirtualName,
}
launchMappingRequests = append(launchMappingRequests, launchRequest)
@@ -127,6 +145,10 @@ func (s *StepRunSpotInstance) CreateTemplateData(userData *string, az string,
}
if s.HttpEndpoint == "enabled" {
templateData.MetadataOptions = &ec2.LaunchTemplateInstanceMetadataOptionsRequest{HttpEndpoint: &s.HttpEndpoint, HttpTokens: &s.HttpTokens, HttpPutResponseHopLimit: &s.HttpPutResponseHopLimit}
}
// If instance type is not set, we'll just pick the lowest priced instance
// available.
if s.InstanceType != "" {
@@ -0,0 +1,25 @@
package common
import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
)
type mockEC2Client struct {
ec2iface.EC2API
}
func FakeAccessConfig() *AccessConfig {
accessConfig := AccessConfig{
getEC2Connection: func() ec2iface.EC2API {
return &mockEC2Client{}
},
PollingConfig: new(AWSPollingConfig),
}
accessConfig.session = session.Must(session.NewSession(&aws.Config{
Region: aws.String("us-west-1"),
}))
return &accessConfig
}
+6
View File
@@ -187,6 +187,9 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
Debug: b.config.PackerDebug,
EbsOptimized: b.config.EbsOptimized,
ExpectedRootDevice: "ebs",
HttpEndpoint: b.config.Metadata.HttpEndpoint,
HttpTokens: b.config.Metadata.HttpTokens,
HttpPutResponseHopLimit: b.config.Metadata.HttpPutResponseHopLimit,
InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior,
InstanceType: b.config.InstanceType,
Region: *ec2conn.Config.Region,
@@ -211,6 +214,9 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
EbsOptimized: b.config.EbsOptimized,
EnableT2Unlimited: b.config.EnableT2Unlimited,
ExpectedRootDevice: "ebs",
HttpEndpoint: b.config.Metadata.HttpEndpoint,
HttpTokens: b.config.Metadata.HttpTokens,
HttpPutResponseHopLimit: b.config.Metadata.HttpPutResponseHopLimit,
InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior,
InstanceType: b.config.InstanceType,
IsRestricted: b.config.IsChinaCloud() || b.config.IsGovCloud(),
+2
View File
@@ -90,6 +90,7 @@ type FlatConfig struct {
VpcFilter *common.FlatVpcFilterOptions `mapstructure:"vpc_filter" required:"false" cty:"vpc_filter" hcl:"vpc_filter"`
VpcId *string `mapstructure:"vpc_id" required:"false" cty:"vpc_id" hcl:"vpc_id"`
WindowsPasswordTimeout *string `mapstructure:"windows_password_timeout" required:"false" cty:"windows_password_timeout" hcl:"windows_password_timeout"`
Metadata *common.FlatMetadataOptions `mapstructure:"metadata_options" required:"false" cty:"metadata_options" hcl:"metadata_options"`
Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"`
PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"`
SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"`
@@ -240,6 +241,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"vpc_filter": &hcldec.BlockSpec{TypeName: "vpc_filter", Nested: hcldec.ObjectSpec((*common.FlatVpcFilterOptions)(nil).HCL2Spec())},
"vpc_id": &hcldec.AttrSpec{Name: "vpc_id", Type: cty.String, Required: false},
"windows_password_timeout": &hcldec.AttrSpec{Name: "windows_password_timeout", Type: cty.String, Required: false},
"metadata_options": &hcldec.BlockSpec{TypeName: "metadata_options", Nested: hcldec.ObjectSpec((*common.FlatMetadataOptions)(nil).HCL2Spec())},
"communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false},
"pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false},
"ssh_host": &hcldec.AttrSpec{Name: "ssh_host", Type: cty.String, Required: false},
+6
View File
@@ -207,6 +207,9 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
Debug: b.config.PackerDebug,
EbsOptimized: b.config.EbsOptimized,
ExpectedRootDevice: "ebs",
HttpEndpoint: b.config.Metadata.HttpEndpoint,
HttpTokens: b.config.Metadata.HttpTokens,
HttpPutResponseHopLimit: b.config.Metadata.HttpPutResponseHopLimit,
InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior,
InstanceType: b.config.InstanceType,
Region: *ec2conn.Config.Region,
@@ -230,6 +233,9 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
EbsOptimized: b.config.EbsOptimized,
EnableT2Unlimited: b.config.EnableT2Unlimited,
ExpectedRootDevice: "ebs",
HttpEndpoint: b.config.Metadata.HttpEndpoint,
HttpTokens: b.config.Metadata.HttpTokens,
HttpPutResponseHopLimit: b.config.Metadata.HttpPutResponseHopLimit,
InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior,
InstanceType: b.config.InstanceType,
IsRestricted: b.config.IsChinaCloud() || b.config.IsGovCloud(),
@@ -113,6 +113,7 @@ type FlatConfig struct {
VpcFilter *common.FlatVpcFilterOptions `mapstructure:"vpc_filter" required:"false" cty:"vpc_filter" hcl:"vpc_filter"`
VpcId *string `mapstructure:"vpc_id" required:"false" cty:"vpc_id" hcl:"vpc_id"`
WindowsPasswordTimeout *string `mapstructure:"windows_password_timeout" required:"false" cty:"windows_password_timeout" hcl:"windows_password_timeout"`
Metadata *common.FlatMetadataOptions `mapstructure:"metadata_options" required:"false" cty:"metadata_options" hcl:"metadata_options"`
Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"`
PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"`
SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"`
@@ -263,6 +264,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"vpc_filter": &hcldec.BlockSpec{TypeName: "vpc_filter", Nested: hcldec.ObjectSpec((*common.FlatVpcFilterOptions)(nil).HCL2Spec())},
"vpc_id": &hcldec.AttrSpec{Name: "vpc_id", Type: cty.String, Required: false},
"windows_password_timeout": &hcldec.AttrSpec{Name: "windows_password_timeout", Type: cty.String, Required: false},
"metadata_options": &hcldec.BlockSpec{TypeName: "metadata_options", Nested: hcldec.ObjectSpec((*common.FlatMetadataOptions)(nil).HCL2Spec())},
"communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false},
"pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false},
"ssh_host": &hcldec.AttrSpec{Name: "ssh_host", Type: cty.String, Required: false},
+14 -2
View File
@@ -13,11 +13,15 @@ import (
// map of region to list of volume IDs
type EbsVolumes map[string][]string
// map of region to list of snapshot IDs
type EbsSnapshots map[string][]string
// Artifact is an artifact implementation that contains built AMIs.
type Artifact struct {
// A map of regions to EBS Volume IDs.
Volumes EbsVolumes
// A map of regions to EBS Snapshot IDs.
Snapshots EbsSnapshots
// BuilderId is the unique ID for the builder that created this AMI
BuilderIdValue string
@@ -40,13 +44,21 @@ func (*Artifact) Files() []string {
// returns a sorted list of region:ID pairs
func (a *Artifact) idList() []string {
parts := make([]string, 0, len(a.Volumes))
parts := make([]string, 0, len(a.Volumes)+len(a.Snapshots))
for region, volumeIDs := range a.Volumes {
for _, volumeID := range volumeIDs {
parts = append(parts, fmt.Sprintf("%s:%s", region, volumeID))
}
}
for region, snapshotIDs := range a.Snapshots {
for _, snapshotID := range snapshotIDs {
parts = append(parts, fmt.Sprintf("%s:%s", region, snapshotID))
}
}
sort.Strings(parts)
return parts
}
+6
View File
@@ -20,6 +20,11 @@ type BlockDevice struct {
// [`dynamic_block`](/docs/templates/hcl_templates/expressions#dynamic-blocks)
// will allow you to create those programatically.
Tag config.KeyValues `mapstructure:"tag" required:"false"`
// Create a Snapshot of this Volume.
SnapshotVolume bool `mapstructure:"snapshot_volume" required:"false"`
awscommon.SnapshotConfig `mapstructure:",squash"`
}
type BlockDevices []BlockDevice
@@ -38,6 +43,7 @@ func (bds BlockDevices) Prepare(ctx *interpolate.Context) (errs []error) {
for _, block := range bds {
errs = append(errs, block.Tag.CopyOn(&block.Tags)...)
errs = append(errs, block.SnapshotTag.CopyOn(&block.SnapshotTags)...)
if err := block.Prepare(ctx); err != nil {
errs = append(errs, err)
+15 -6
View File
@@ -123,16 +123,12 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
// Accumulate any errors
var errs *packersdk.MultiError
var warns []string
errs = packersdk.MultiErrorAppend(errs, b.config.VolumeRunTag.CopyOn(&b.config.VolumeRunTags)...)
errs = packersdk.MultiErrorAppend(errs, b.config.AccessConfig.Prepare()...)
errs = packersdk.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...)
errs = packersdk.MultiErrorAppend(errs, b.config.launchBlockDevices.Prepare(&b.config.ctx)...)
for _, d := range b.config.VolumeMappings {
if err := d.Prepare(&b.config.ctx); err != nil {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("AMIMapping: %s", err.Error()))
}
}
errs = packersdk.MultiErrorAppend(errs, b.config.VolumeMappings.Prepare(&b.config.ctx)...)
b.config.launchBlockDevices = b.config.VolumeMappings
if err != nil {
@@ -195,6 +191,9 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
Debug: b.config.PackerDebug,
EbsOptimized: b.config.EbsOptimized,
ExpectedRootDevice: "ebs",
HttpEndpoint: b.config.Metadata.HttpEndpoint,
HttpTokens: b.config.Metadata.HttpTokens,
HttpPutResponseHopLimit: b.config.Metadata.HttpPutResponseHopLimit,
InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior,
InstanceType: b.config.InstanceType,
Region: *ec2conn.Config.Region,
@@ -218,6 +217,9 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
EbsOptimized: b.config.EbsOptimized,
EnableT2Unlimited: b.config.EnableT2Unlimited,
ExpectedRootDevice: "ebs",
HttpEndpoint: b.config.Metadata.HttpEndpoint,
HttpTokens: b.config.Metadata.HttpTokens,
HttpPutResponseHopLimit: b.config.Metadata.HttpPutResponseHopLimit,
InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior,
InstanceType: b.config.InstanceType,
IsRestricted: b.config.IsChinaCloud() || b.config.IsGovCloud(),
@@ -312,6 +314,12 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
EnableAMISriovNetSupport: b.config.AMISriovNetSupport,
EnableAMIENASupport: b.config.AMIENASupport,
},
&stepSnapshotEBSVolumes{
PollingConfig: b.config.PollingConfig,
VolumeMapping: b.config.VolumeMappings,
AccessConfig: &b.config.AccessConfig,
Ctx: b.config.ctx,
},
}
// Run!
@@ -326,6 +334,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
// Build the artifact and return it
artifact := &Artifact{
Volumes: state.Get("ebsvolumes").(EbsVolumes),
Snapshots: state.Get("ebssnapshots").(EbsSnapshots),
BuilderIdValue: BuilderId,
Conn: ec2conn,
StateData: map[string]interface{}{"generated_data": state.Get("generated_data")},
@@ -25,6 +25,11 @@ type FlatBlockDevice struct {
KmsKeyId *string `mapstructure:"kms_key_id" required:"false" cty:"kms_key_id" hcl:"kms_key_id"`
Tags map[string]string `mapstructure:"tags" required:"false" cty:"tags" hcl:"tags"`
Tag []config.FlatKeyValue `mapstructure:"tag" required:"false" cty:"tag" hcl:"tag"`
SnapshotVolume *bool `mapstructure:"snapshot_volume" required:"false" cty:"snapshot_volume" hcl:"snapshot_volume"`
SnapshotTags map[string]string `mapstructure:"snapshot_tags" required:"false" cty:"snapshot_tags" hcl:"snapshot_tags"`
SnapshotTag []config.FlatKeyValue `mapstructure:"snapshot_tag" required:"false" cty:"snapshot_tag" hcl:"snapshot_tag"`
SnapshotUsers []string `mapstructure:"snapshot_users" required:"false" cty:"snapshot_users" hcl:"snapshot_users"`
SnapshotGroups []string `mapstructure:"snapshot_groups" required:"false" cty:"snapshot_groups" hcl:"snapshot_groups"`
}
// FlatMapstructure returns a new FlatBlockDevice.
@@ -52,6 +57,11 @@ func (*FlatBlockDevice) HCL2Spec() map[string]hcldec.Spec {
"kms_key_id": &hcldec.AttrSpec{Name: "kms_key_id", Type: cty.String, Required: false},
"tags": &hcldec.AttrSpec{Name: "tags", Type: cty.Map(cty.String), Required: false},
"tag": &hcldec.BlockListSpec{TypeName: "tag", Nested: hcldec.ObjectSpec((*config.FlatKeyValue)(nil).HCL2Spec())},
"snapshot_volume": &hcldec.AttrSpec{Name: "snapshot_volume", Type: cty.Bool, Required: false},
"snapshot_tags": &hcldec.AttrSpec{Name: "snapshot_tags", Type: cty.Map(cty.String), Required: false},
"snapshot_tag": &hcldec.BlockListSpec{TypeName: "snapshot_tag", Nested: hcldec.ObjectSpec((*config.FlatKeyValue)(nil).HCL2Spec())},
"snapshot_users": &hcldec.AttrSpec{Name: "snapshot_users", Type: cty.List(cty.String), Required: false},
"snapshot_groups": &hcldec.AttrSpec{Name: "snapshot_groups", Type: cty.List(cty.String), Required: false},
}
return s
}
@@ -115,6 +125,7 @@ type FlatConfig struct {
VpcFilter *common.FlatVpcFilterOptions `mapstructure:"vpc_filter" required:"false" cty:"vpc_filter" hcl:"vpc_filter"`
VpcId *string `mapstructure:"vpc_id" required:"false" cty:"vpc_id" hcl:"vpc_id"`
WindowsPasswordTimeout *string `mapstructure:"windows_password_timeout" required:"false" cty:"windows_password_timeout" hcl:"windows_password_timeout"`
Metadata *common.FlatMetadataOptions `mapstructure:"metadata_options" required:"false" cty:"metadata_options" hcl:"metadata_options"`
Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"`
PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"`
SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"`
@@ -242,6 +253,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"vpc_filter": &hcldec.BlockSpec{TypeName: "vpc_filter", Nested: hcldec.ObjectSpec((*common.FlatVpcFilterOptions)(nil).HCL2Spec())},
"vpc_id": &hcldec.AttrSpec{Name: "vpc_id", Type: cty.String, Required: false},
"windows_password_timeout": &hcldec.AttrSpec{Name: "windows_password_timeout", Type: cty.String, Required: false},
"metadata_options": &hcldec.BlockSpec{TypeName: "metadata_options", Nested: hcldec.ObjectSpec((*common.FlatMetadataOptions)(nil).HCL2Spec())},
"communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false},
"pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false},
"ssh_host": &hcldec.AttrSpec{Name: "ssh_host", Type: cty.String, Required: false},
+41 -3
View File
@@ -104,9 +104,6 @@ func TestBuilderPrepare_ReturnGeneratedData(t *testing.T) {
if len(generatedData) == 0 {
t.Fatalf("Generated data should not be empty")
}
if len(generatedData) == 0 {
t.Fatalf("Generated data should not be empty")
}
if generatedData[0] != "SourceAMIName" {
t.Fatalf("Generated data should contain SourceAMIName")
}
@@ -126,3 +123,44 @@ func TestBuilderPrepare_ReturnGeneratedData(t *testing.T) {
t.Fatalf("Generated data should contain SourceAMIOwnerName")
}
}
func TestBuidler_ConfigBlockdevicemapping(t *testing.T) {
var b Builder
config := testConfig()
//Set some snapshot settings
config["ebs_volumes"] = []map[string]interface{}{
{
"device_name": "/dev/xvdb",
"volume_size": "32",
"delete_on_termination": true,
},
{
"device_name": "/dev/xvdc",
"volume_size": "32",
"delete_on_termination": true,
"snapshot_tags": map[string]string{
"Test_Tag": "tag_value",
"another tag": "another value",
},
"snapshot_users": []string{
"123", "456",
},
},
}
generatedData, warnings, err := b.Prepare(config)
if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings)
}
if err != nil {
t.Fatalf("should not have error: %s", err)
}
if len(generatedData) == 0 {
t.Fatalf("Generated data should not be empty")
}
t.Logf("Test gen %+v", b.config.VolumeMappings)
}
@@ -0,0 +1,167 @@
package ebsvolume
import (
"context"
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
"github.com/hashicorp/packer-plugin-sdk/multistep"
"github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hashicorp/packer-plugin-sdk/template/interpolate"
awscommon "github.com/hashicorp/packer/builder/amazon/common"
)
type stepSnapshotEBSVolumes struct {
PollingConfig *awscommon.AWSPollingConfig
AccessConfig *awscommon.AccessConfig
VolumeMapping []BlockDevice
//Map of SnapshotID: BlockDevice, Where *BlockDevice is in VolumeMapping
snapshotMap map[string]*BlockDevice
Ctx interpolate.Context
}
func (s *stepSnapshotEBSVolumes) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
ec2conn := state.Get("ec2").(ec2iface.EC2API)
instance := state.Get("instance").(*ec2.Instance)
ui := state.Get("ui").(packer.Ui)
s.snapshotMap = make(map[string]*BlockDevice)
for _, instanceBlockDevice := range instance.BlockDeviceMappings {
for _, configVolumeMapping := range s.VolumeMapping {
//Find the config entry for the instance blockDevice
if configVolumeMapping.DeviceName == *instanceBlockDevice.DeviceName {
//Skip Volumes that are not set to create snapshot
if configVolumeMapping.SnapshotVolume != true {
continue
}
ui.Message(fmt.Sprintf("Compiling list of tags to apply to snapshot from Volume %s...", *instanceBlockDevice.DeviceName))
tags, err := awscommon.TagMap(configVolumeMapping.SnapshotTags).EC2Tags(s.Ctx, s.AccessConfig.SessionRegion(), state)
if err != nil {
err := fmt.Errorf("Error generating tags for snapshot %s: %s", *instanceBlockDevice.DeviceName, err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
tags.Report(ui)
tagSpec := &ec2.TagSpecification{
ResourceType: aws.String("snapshot"),
Tags: tags,
}
input := &ec2.CreateSnapshotInput{
VolumeId: aws.String(*instanceBlockDevice.Ebs.VolumeId),
TagSpecifications: []*ec2.TagSpecification{tagSpec},
}
//Dont try to set an empty tag spec
if len(tags) == 0 {
input.TagSpecifications = nil
}
ui.Message(fmt.Sprintf("Requesting snapshot of volume: %s...", *instanceBlockDevice.Ebs.VolumeId))
snapshot, err := ec2conn.CreateSnapshot(input)
if err != nil || snapshot == nil {
err := fmt.Errorf("Error generating snapsot for volume %s: %s", *instanceBlockDevice.Ebs.VolumeId, err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
ui.Message(fmt.Sprintf("Requested Snapshot of Volume %s: %s", *instanceBlockDevice.Ebs.VolumeId, *snapshot.SnapshotId))
s.snapshotMap[*snapshot.SnapshotId] = &configVolumeMapping
}
}
}
ui.Say("Waiting for Snapshots to become ready...")
for snapID := range s.snapshotMap {
ui.Message(fmt.Sprintf("Waiting for %s to be ready.", snapID))
err := s.PollingConfig.WaitUntilSnapshotDone(ctx, ec2conn, snapID)
if err != nil {
err = fmt.Errorf("Error waiting for snapsot to become ready %s", err)
state.Put("error", err)
ui.Error(err.Error())
ui.Message("Failed to wait")
return multistep.ActionHalt
}
ui.Message(fmt.Sprintf("Snapshot Ready: %s", snapID))
}
//Attach User and Group permissions to snapshots
ui.Say("Setting User/Group Permissions for Snapshots...")
for snapID, bd := range s.snapshotMap {
snapshotOptions := make(map[string]*ec2.ModifySnapshotAttributeInput)
if len(bd.SnapshotGroups) > 0 {
groups := make([]*string, len(bd.SnapshotGroups))
addsSnapshot := make([]*ec2.CreateVolumePermission, len(bd.SnapshotGroups))
addSnapshotGroups := &ec2.ModifySnapshotAttributeInput{
CreateVolumePermission: &ec2.CreateVolumePermissionModifications{},
}
for i, g := range bd.SnapshotGroups {
groups[i] = aws.String(g)
addsSnapshot[i] = &ec2.CreateVolumePermission{
Group: aws.String(g),
}
}
addSnapshotGroups.GroupNames = groups
addSnapshotGroups.CreateVolumePermission.Add = addsSnapshot
snapshotOptions["groups"] = addSnapshotGroups
}
if len(bd.SnapshotUsers) > 0 {
users := make([]*string, len(bd.SnapshotUsers))
addsSnapshot := make([]*ec2.CreateVolumePermission, len(bd.SnapshotUsers))
for i, u := range bd.SnapshotUsers {
users[i] = aws.String(u)
addsSnapshot[i] = &ec2.CreateVolumePermission{UserId: aws.String(u)}
}
snapshotOptions["users"] = &ec2.ModifySnapshotAttributeInput{
UserIds: users,
CreateVolumePermission: &ec2.CreateVolumePermissionModifications{
Add: addsSnapshot,
},
}
}
//Todo: Copy to other regions and repeat this block in all regions.
for name, input := range snapshotOptions {
ui.Message(fmt.Sprintf("Modifying: %s", name))
input.SnapshotId = &snapID
_, err := ec2conn.ModifySnapshotAttribute(input)
if err != nil {
err := fmt.Errorf("Error modify snapshot attributes: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
}
}
//Record all snapshots in current Region.
snapshots := make(EbsSnapshots)
currentregion := s.AccessConfig.SessionRegion()
for snapID := range s.snapshotMap {
snapshots[currentregion] = append(
snapshots[currentregion],
snapID)
}
//Records artifacts
state.Put("ebssnapshots", snapshots)
return multistep.ActionContinue
}
func (s *stepSnapshotEBSVolumes) Cleanup(state multistep.StateBag) {
// No cleanup...
}
@@ -0,0 +1,170 @@
package ebsvolume
import (
"bytes"
"context"
"fmt"
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/request"
//"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
"github.com/hashicorp/packer-plugin-sdk/multistep"
"github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hashicorp/packer/builder/amazon/common"
)
// Define a mock struct to be used in unit tests for common aws steps.
type mockEC2Conn struct {
ec2iface.EC2API
Config *aws.Config
}
func (m *mockEC2Conn) CreateSnapshot(input *ec2.CreateSnapshotInput) (*ec2.Snapshot, error) {
snap := &ec2.Snapshot{
// This isn't typical amazon format, but injecting the volume id into
// this field lets us verify that the right volume was snapshotted with
// a simple string comparison
SnapshotId: aws.String(fmt.Sprintf("snap-of-%s", *input.VolumeId)),
}
return snap, nil
}
func (m *mockEC2Conn) WaitUntilSnapshotCompletedWithContext(aws.Context, *ec2.DescribeSnapshotsInput, ...request.WaiterOption) error {
return nil
}
func getMockConn(config *common.AccessConfig, target string) (ec2iface.EC2API, error) {
mockConn := &mockEC2Conn{
Config: aws.NewConfig(),
}
return mockConn, nil
}
// Create statebag for running test
func tState(t *testing.T) multistep.StateBag {
state := new(multistep.BasicStateBag)
state.Put("ui", &packer.BasicUi{
Reader: new(bytes.Buffer),
Writer: new(bytes.Buffer),
})
// state.Put("amis", map[string]string{"us-east-1": "ami-12345"})
// state.Put("snapshots", map[string][]string{"us-east-1": {"snap-0012345"}})
conn, _ := getMockConn(&common.AccessConfig{}, "us-east-2")
state.Put("ec2", conn)
// Store a fake instance that contains a block device that matches the
// volumes defined in the config above
state.Put("instance", &ec2.Instance{
InstanceId: aws.String("instance-id"),
BlockDeviceMappings: []*ec2.InstanceBlockDeviceMapping{
{
DeviceName: aws.String("/dev/xvda"),
Ebs: &ec2.EbsInstanceBlockDevice{
VolumeId: aws.String("vol-1234"),
},
},
{
DeviceName: aws.String("/dev/xvdb"),
Ebs: &ec2.EbsInstanceBlockDevice{
VolumeId: aws.String("vol-5678"),
},
},
},
})
return state
}
func TestStepSnapshot_run_simple(t *testing.T) {
var b Builder
config := testConfig() //from builder_test
//Set some snapshot settings
config["ebs_volumes"] = []map[string]interface{}{
{
"device_name": "/dev/xvdb",
"volume_size": "32",
"delete_on_termination": true,
"snapshot_volume": true,
},
}
generatedData, warnings, err := b.Prepare(config)
if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings)
}
if err != nil {
t.Fatalf("should not have error: %s", err)
}
if len(generatedData) == 0 {
t.Fatalf("Generated data should not be empty")
}
state := tState(t)
accessConfig := common.FakeAccessConfig()
step := stepSnapshotEBSVolumes{
PollingConfig: new(common.AWSPollingConfig),
AccessConfig: accessConfig,
VolumeMapping: b.config.VolumeMappings,
Ctx: b.config.ctx,
}
step.Run(context.Background(), state)
if len(step.snapshotMap) != 1 {
t.Fatalf("Missing Snapshot from step")
}
if volmapping := step.snapshotMap["snap-of-vol-5678"]; volmapping == nil {
t.Fatalf("Didn't snapshot correct volume: Map is %#v", step.snapshotMap)
}
}
func TestStepSnapshot_run_no_snaps(t *testing.T) {
var b Builder
config := testConfig() //from builder_test
//Set some snapshot settings
config["ebs_volumes"] = []map[string]interface{}{
{
"device_name": "/dev/xvdb",
"volume_size": "32",
"delete_on_termination": true,
"snapshot_volume": false,
},
}
generatedData, warnings, err := b.Prepare(config)
if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings)
}
if err != nil {
t.Fatalf("should not have error: %s", err)
}
if len(generatedData) == 0 {
t.Fatalf("Generated data should not be empty")
}
state := tState(t)
accessConfig := common.FakeAccessConfig()
step := stepSnapshotEBSVolumes{
PollingConfig: new(common.AWSPollingConfig),
AccessConfig: accessConfig,
VolumeMapping: b.config.VolumeMappings,
Ctx: b.config.ctx,
}
step.Run(context.Background(), state)
if len(step.snapshotMap) != 0 {
t.Fatalf("Shouldn't have snapshotted any volumes")
}
}
@@ -90,6 +90,7 @@ type FlatConfig struct {
VpcFilter *common.FlatVpcFilterOptions `mapstructure:"vpc_filter" required:"false" cty:"vpc_filter" hcl:"vpc_filter"`
VpcId *string `mapstructure:"vpc_id" required:"false" cty:"vpc_id" hcl:"vpc_id"`
WindowsPasswordTimeout *string `mapstructure:"windows_password_timeout" required:"false" cty:"windows_password_timeout" hcl:"windows_password_timeout"`
Metadata *common.FlatMetadataOptions `mapstructure:"metadata_options" required:"false" cty:"metadata_options" hcl:"metadata_options"`
Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"`
PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"`
SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"`
@@ -245,6 +246,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"vpc_filter": &hcldec.BlockSpec{TypeName: "vpc_filter", Nested: hcldec.ObjectSpec((*common.FlatVpcFilterOptions)(nil).HCL2Spec())},
"vpc_id": &hcldec.AttrSpec{Name: "vpc_id", Type: cty.String, Required: false},
"windows_password_timeout": &hcldec.AttrSpec{Name: "windows_password_timeout", Type: cty.String, Required: false},
"metadata_options": &hcldec.BlockSpec{TypeName: "metadata_options", Nested: hcldec.ObjectSpec((*common.FlatMetadataOptions)(nil).HCL2Spec())},
"communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false},
"pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false},
"ssh_host": &hcldec.AttrSpec{Name: "ssh_host", Type: cty.String, Required: false},
+6 -2
View File
@@ -233,7 +233,9 @@ func NewAzureClient(subscriptionID, sigSubscriptionID, resourceGroupName, storag
azureClient.GalleryImageVersionsClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient))
azureClient.GalleryImageVersionsClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.GalleryImageVersionsClient.UserAgent)
azureClient.GalleryImageVersionsClient.Client.PollingDuration = sharedGalleryTimeout
azureClient.GalleryImageVersionsClient.SubscriptionID = sigSubscriptionID
if sigSubscriptionID != "" {
azureClient.GalleryImageVersionsClient.SubscriptionID = sigSubscriptionID
}
azureClient.GalleryImagesClient = newCompute.NewGalleryImagesClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID)
azureClient.GalleryImagesClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken)
@@ -241,7 +243,9 @@ func NewAzureClient(subscriptionID, sigSubscriptionID, resourceGroupName, storag
azureClient.GalleryImagesClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient))
azureClient.GalleryImagesClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.GalleryImagesClient.UserAgent)
azureClient.GalleryImagesClient.Client.PollingDuration = pollingDuration
azureClient.GalleryImagesClient.SubscriptionID = sigSubscriptionID
if sigSubscriptionID != "" {
azureClient.GalleryImagesClient.SubscriptionID = sigSubscriptionID
}
keyVaultURL, err := url.Parse(cloud.KeyVaultEndpoint)
if err != nil {
+61 -10
View File
@@ -4,9 +4,14 @@ import (
"context"
"errors"
"fmt"
"math"
"math/rand"
"net/http"
"regexp"
"sync/atomic"
"time"
"github.com/oracle/oci-go-sdk/common"
core "github.com/oracle/oci-go-sdk/core"
)
@@ -19,6 +24,31 @@ type driverOCI struct {
context context.Context
}
var retryPolicy = &common.RetryPolicy{
MaximumNumberAttempts: 10,
ShouldRetryOperation: func(res common.OCIOperationResponse) bool {
var e common.ServiceError
if errors.As(res.Error, &e) {
switch e.GetHTTPStatusCode() {
case http.StatusTooManyRequests, http.StatusInternalServerError, http.StatusServiceUnavailable:
return true
}
}
return false
},
NextDuration: func(res common.OCIOperationResponse) time.Duration {
x := uint64(res.AttemptNumber)
d := time.Duration(math.Pow(2, float64(atomic.LoadUint64(&x)))) * time.Second
j := time.Duration(rand.Float64()*(2000)) * time.Millisecond
w := d + j
return w
},
}
var requestMetadata = common.RequestMetadata{
RetryPolicy: retryPolicy,
}
// NewDriverOCI Creates a new driverOCI with a connected compute client and a connected vcn client.
func NewDriverOCI(cfg *Config) (Driver, error) {
coreClient, err := core.NewComputeClientWithConfigurationProvider(cfg.configProvider)
@@ -80,6 +110,7 @@ func (d *driverOCI) CreateInstance(ctx context.Context, publicKey string) (strin
LifecycleState: "AVAILABLE",
SortBy: "TIMECREATED",
SortOrder: "DESC",
RequestMetadata: requestMetadata,
})
if err != nil {
return "", err
@@ -127,7 +158,10 @@ func (d *driverOCI) CreateInstance(ctx context.Context, publicKey string) (strin
Metadata: metadata,
}
instance, err := d.computeClient.LaunchInstance(context.TODO(), core.LaunchInstanceRequest{LaunchInstanceDetails: instanceDetails})
instance, err := d.computeClient.LaunchInstance(context.TODO(), core.LaunchInstanceRequest{
LaunchInstanceDetails: instanceDetails,
RequestMetadata: requestMetadata,
})
if err != nil {
return "", err
@@ -145,7 +179,9 @@ func (d *driverOCI) CreateImage(ctx context.Context, id string) (core.Image, err
FreeformTags: d.cfg.Tags,
DefinedTags: d.cfg.DefinedTags,
LaunchMode: core.CreateImageDetailsLaunchModeEnum(d.cfg.LaunchMode),
}})
},
RequestMetadata: requestMetadata,
})
if err != nil {
return core.Image{}, err
@@ -156,15 +192,19 @@ func (d *driverOCI) CreateImage(ctx context.Context, id string) (core.Image, err
// DeleteImage deletes a custom image.
func (d *driverOCI) DeleteImage(ctx context.Context, id string) error {
_, err := d.computeClient.DeleteImage(ctx, core.DeleteImageRequest{ImageId: &id})
_, err := d.computeClient.DeleteImage(ctx, core.DeleteImageRequest{
ImageId: &id,
RequestMetadata: requestMetadata,
})
return err
}
// GetInstanceIP returns the public or private IP corresponding to the given instance id.
func (d *driverOCI) GetInstanceIP(ctx context.Context, id string) (string, error) {
vnics, err := d.computeClient.ListVnicAttachments(ctx, core.ListVnicAttachmentsRequest{
InstanceId: &id,
CompartmentId: &d.cfg.CompartmentID,
InstanceId: &id,
CompartmentId: &d.cfg.CompartmentID,
RequestMetadata: requestMetadata,
})
if err != nil {
return "", err
@@ -174,7 +214,10 @@ func (d *driverOCI) GetInstanceIP(ctx context.Context, id string) (string, error
return "", errors.New("instance has zero VNICs")
}
vnic, err := d.vcnClient.GetVnic(ctx, core.GetVnicRequest{VnicId: vnics.Items[0].VnicId})
vnic, err := d.vcnClient.GetVnic(ctx, core.GetVnicRequest{
VnicId: vnics.Items[0].VnicId,
RequestMetadata: requestMetadata,
})
if err != nil {
return "", fmt.Errorf("Error getting VNIC details: %s", err)
}
@@ -192,7 +235,8 @@ func (d *driverOCI) GetInstanceIP(ctx context.Context, id string) (string, error
func (d *driverOCI) GetInstanceInitialCredentials(ctx context.Context, id string) (string, string, error) {
credentials, err := d.computeClient.GetWindowsInstanceInitialCredentials(ctx, core.GetWindowsInstanceInitialCredentialsRequest{
InstanceId: &id,
InstanceId: &id,
RequestMetadata: requestMetadata,
})
if err != nil {
return "", "", err
@@ -204,7 +248,8 @@ func (d *driverOCI) GetInstanceInitialCredentials(ctx context.Context, id string
// TerminateInstance terminates a compute instance.
func (d *driverOCI) TerminateInstance(ctx context.Context, id string) error {
_, err := d.computeClient.TerminateInstance(ctx, core.TerminateInstanceRequest{
InstanceId: &id,
InstanceId: &id,
RequestMetadata: requestMetadata,
})
return err
}
@@ -214,7 +259,10 @@ func (d *driverOCI) TerminateInstance(ctx context.Context, id string) error {
func (d *driverOCI) WaitForImageCreation(ctx context.Context, id string) error {
return waitForResourceToReachState(
func(string) (string, error) {
image, err := d.computeClient.GetImage(ctx, core.GetImageRequest{ImageId: &id})
image, err := d.computeClient.GetImage(ctx, core.GetImageRequest{
ImageId: &id,
RequestMetadata: requestMetadata,
})
if err != nil {
return "", err
}
@@ -233,7 +281,10 @@ func (d *driverOCI) WaitForImageCreation(ctx context.Context, id string) error {
func (d *driverOCI) WaitForInstanceState(ctx context.Context, id string, waitStates []string, terminalState string) error {
return waitForResourceToReachState(
func(string) (string, error) {
instance, err := d.computeClient.GetInstance(ctx, core.GetInstanceRequest{InstanceId: &id})
instance, err := d.computeClient.GetInstance(ctx, core.GetInstanceRequest{
InstanceId: &id,
RequestMetadata: requestMetadata,
})
if err != nil {
return "", err
}
+9 -4
View File
@@ -22,8 +22,11 @@ func (s *stepCreateServer) Run(ctx context.Context, state multistep.StateBag) mu
profitbricks.SetAuth(c.PBUsername, c.PBPassword)
profitbricks.SetDepth("5")
if sshkey, ok := state.GetOk("publicKey"); ok {
c.SSHKey = sshkey.(string)
if c.Comm.SSHPublicKey != nil {
c.SSHKey = string(c.Comm.SSHPublicKey)
} else {
ui.Error("No ssh private key set; ssh authentication won't be possible. Please specify your private key in the ssh_private_key_file configuration key.")
return multistep.ActionHalt
}
ui.Say("Creating Virtual Data Center...")
img := s.getImageId(c.Image, c)
@@ -204,7 +207,7 @@ func (d *stepCreateServer) setPB(username string, password string, url string) {
func (d *stepCreateServer) checkForErrors(instance profitbricks.Resp) error {
if instance.StatusCode > 299 {
return errors.New(fmt.Sprintf("Error occurred %s", string(instance.Body)))
return fmt.Errorf("Error occurred %s", string(instance.Body))
}
return nil
}
@@ -261,7 +264,9 @@ func (d *stepCreateServer) getImageAlias(imageAlias string, location string, ui
func parseErrorMessage(raw string) (toreturn string) {
var tmp map[string]interface{}
json.Unmarshal([]byte(raw), &tmp)
if json.Unmarshal([]byte(raw), &tmp) != nil {
return ""
}
for _, v := range tmp["messages"].([]interface{}) {
for index, i := range v.(map[string]interface{}) {
+125 -7
View File
@@ -3,6 +3,9 @@ package profitbricks
import (
"context"
"encoding/json"
"errors"
"fmt"
"strings"
"time"
"github.com/hashicorp/packer-plugin-sdk/multistep"
@@ -22,9 +25,32 @@ func (s *stepTakeSnapshot) Run(ctx context.Context, state multistep.StateBag) mu
dcId := state.Get("datacenter_id").(string)
volumeId := state.Get("volume_id").(string)
serverId := state.Get("instance_id").(string)
comm, _ := state.Get("communicator").(packersdk.Communicator)
if comm == nil {
ui.Error("no communicator found")
return multistep.ActionHalt
}
/* sync fs changes from the provisioning step */
os, err := s.getOs(dcId, serverId)
if err != nil {
ui.Error(fmt.Sprintf("an error occurred while getting the server os: %s", err.Error()))
return multistep.ActionHalt
}
ui.Say(fmt.Sprintf("Server OS is %s", os))
switch strings.ToLower(os) {
case "linux":
ui.Say("syncing file system changes")
if err := s.syncFs(ctx, comm); err != nil {
ui.Error(fmt.Sprintf("error syncing fs changes: %s", err.Error()))
return multistep.ActionHalt
}
}
snapshot := profitbricks.CreateSnapshot(dcId, volumeId, c.SnapshotName, "")
state.Put("snapshotname", c.SnapshotName)
if snapshot.StatusCode > 299 {
@@ -42,31 +68,123 @@ func (s *stepTakeSnapshot) Run(ctx context.Context, state multistep.StateBag) mu
return multistep.ActionHalt
}
s.waitTillProvisioned(snapshot.Headers.Get("Location"), *c)
ui.Say(fmt.Sprintf("Creating a snapshot for %s/volumes/%s", dcId, volumeId))
err = s.waitForRequest(snapshot.Headers.Get("Location"), *c, ui)
if err != nil {
ui.Error(fmt.Sprintf("An error occurred while waiting for the request to be done: %s", err.Error()))
return multistep.ActionHalt
}
err = s.waitTillSnapshotAvailable(snapshot.Id, *c, ui)
if err != nil {
ui.Error(fmt.Sprintf("An error occurred while waiting for the snapshot to be created: %s", err.Error()))
return multistep.ActionHalt
}
return multistep.ActionContinue
}
func (s *stepTakeSnapshot) Cleanup(state multistep.StateBag) {
func (s *stepTakeSnapshot) Cleanup(_ multistep.StateBag) {
}
func (d *stepTakeSnapshot) waitTillProvisioned(path string, config Config) {
d.setPB(config.PBUsername, config.PBPassword, config.PBUrl)
func (s *stepTakeSnapshot) waitForRequest(path string, config Config, ui packersdk.Ui) error {
ui.Say(fmt.Sprintf("Watching request %s", path))
s.setPB(config.PBUsername, config.PBPassword, config.PBUrl)
waitCount := 50
var waitInterval = 10 * time.Second
if config.Retries > 0 {
waitCount = config.Retries
}
done := false
for i := 0; i < waitCount; i++ {
request := profitbricks.GetRequestStatus(path)
ui.Say(fmt.Sprintf("request status = %s", request.Metadata.Status))
if request.Metadata.Status == "DONE" {
done = true
break
}
time.Sleep(10 * time.Second)
if request.Metadata.Status == "FAILED" {
return fmt.Errorf("Request failed: %s", request.Response)
}
time.Sleep(waitInterval)
i++
}
if done == false {
return fmt.Errorf("request not fulfilled after waiting %d seconds",
int64(waitCount)*int64(waitInterval)/int64(time.Second))
}
return nil
}
func (d *stepTakeSnapshot) setPB(username string, password string, url string) {
func (s *stepTakeSnapshot) waitTillSnapshotAvailable(id string, config Config, ui packersdk.Ui) error {
s.setPB(config.PBUsername, config.PBPassword, config.PBUrl)
waitCount := 50
var waitInterval = 10 * time.Second
if config.Retries > 0 {
waitCount = config.Retries
}
done := false
ui.Say(fmt.Sprintf("waiting for snapshot %s to become available", id))
for i := 0; i < waitCount; i++ {
snap := profitbricks.GetSnapshot(id)
ui.Say(fmt.Sprintf("snapshot status = %s", snap.Metadata.State))
if snap.StatusCode != 200 {
return fmt.Errorf("%s", snap.Response)
}
if snap.Metadata.State == "AVAILABLE" {
done = true
break
}
time.Sleep(waitInterval)
i++
ui.Say(fmt.Sprintf("... still waiting, %d seconds have passed", int64(waitInterval)*int64(i)))
}
if done == false {
return fmt.Errorf("snapshot not created after waiting %d seconds",
int64(waitCount)*int64(waitInterval)/int64(time.Second))
}
ui.Say("snapshot created")
return nil
}
func (s *stepTakeSnapshot) syncFs(ctx context.Context, comm packersdk.Communicator) error {
cmd := &packersdk.RemoteCmd{
Command: "sync",
}
if err := comm.Start(ctx, cmd); err != nil {
return err
}
if cmd.Wait() != 0 {
return fmt.Errorf("sync command exited with code %d", cmd.ExitStatus())
}
return nil
}
func (s *stepTakeSnapshot) getOs(dcId string, serverId string) (string, error) {
server := profitbricks.GetServer(dcId, serverId)
if server.StatusCode != 200 {
return "", errors.New(server.Response)
}
if server.Properties.BootVolume == nil {
return "", errors.New("no boot volume found on server")
}
volumeId := server.Properties.BootVolume.Id
volume := profitbricks.GetVolume(dcId, volumeId)
if volume.StatusCode != 200 {
return "", errors.New(volume.Response)
}
return volume.Properties.LicenceType, nil
}
func (s *stepTakeSnapshot) setPB(username string, password string, url string) {
profitbricks.SetAuth(username, password)
profitbricks.SetEndpoint(url)
}
+96 -96
View File
@@ -11,101 +11,101 @@ import (
// FlatConfig is an auto-generated flat version of Config.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatConfig struct {
PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"`
PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"`
PackerCoreVersion *string `mapstructure:"packer_core_version" cty:"packer_core_version" hcl:"packer_core_version"`
PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"`
PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"`
PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"`
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
HTTPDir *string `mapstructure:"http_directory" cty:"http_directory" hcl:"http_directory"`
HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min" hcl:"http_port_min"`
HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"`
HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"`
HTTPInterface *string `mapstructure:"http_interface" undocumented:"true" cty:"http_interface" hcl:"http_interface"`
BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval" hcl:"boot_keygroup_interval"`
BootWait *string `mapstructure:"boot_wait" cty:"boot_wait" hcl:"boot_wait"`
BootCommand []string `mapstructure:"boot_command" cty:"boot_command" hcl:"boot_command"`
BootKeyInterval *string `mapstructure:"boot_key_interval" cty:"boot_key_interval" hcl:"boot_key_interval"`
Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"`
PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"`
SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"`
SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"`
SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"`
SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"`
SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"`
SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"`
SSHTemporaryKeyPairType *string `mapstructure:"temporary_key_pair_type" cty:"temporary_key_pair_type" hcl:"temporary_key_pair_type"`
SSHTemporaryKeyPairBits *int `mapstructure:"temporary_key_pair_bits" cty:"temporary_key_pair_bits" hcl:"temporary_key_pair_bits"`
SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"`
SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"`
SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"`
SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"`
SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"`
SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"`
SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"`
SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"`
SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"`
SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"`
SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"`
SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"`
SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"`
SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"`
SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"`
SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"`
SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"`
SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"`
SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"`
SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"`
SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"`
SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"`
SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"`
SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"`
SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"`
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"`
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"`
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"`
SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"`
SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"`
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"`
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"`
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"`
WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"`
WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"`
WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"`
WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"`
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"`
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"`
ProxmoxURLRaw *string `mapstructure:"proxmox_url" cty:"proxmox_url" hcl:"proxmox_url"`
SkipCertValidation *bool `mapstructure:"insecure_skip_tls_verify" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"`
Username *string `mapstructure:"username" cty:"username" hcl:"username"`
Password *string `mapstructure:"password" cty:"password" hcl:"password"`
Node *string `mapstructure:"node" cty:"node" hcl:"node"`
Pool *string `mapstructure:"pool" cty:"pool" hcl:"pool"`
VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"`
VMID *int `mapstructure:"vm_id" cty:"vm_id" hcl:"vm_id"`
Boot *string `mapstructure:"boot" cty:"boot" hcl:"boot"`
Memory *int `mapstructure:"memory" cty:"memory" hcl:"memory"`
Cores *int `mapstructure:"cores" cty:"cores" hcl:"cores"`
CPUType *string `mapstructure:"cpu_type" cty:"cpu_type" hcl:"cpu_type"`
Sockets *int `mapstructure:"sockets" cty:"sockets" hcl:"sockets"`
OS *string `mapstructure:"os" cty:"os" hcl:"os"`
VGA *proxmox.FlatvgaConfig `mapstructure:"vga" cty:"vga" hcl:"vga"`
NICs []proxmox.FlatnicConfig `mapstructure:"network_adapters" cty:"network_adapters" hcl:"network_adapters"`
Disks []proxmox.FlatdiskConfig `mapstructure:"disks" cty:"disks" hcl:"disks"`
Agent *bool `mapstructure:"qemu_agent" cty:"qemu_agent" hcl:"qemu_agent"`
SCSIController *string `mapstructure:"scsi_controller" cty:"scsi_controller" hcl:"scsi_controller"`
Onboot *bool `mapstructure:"onboot" cty:"onboot" hcl:"onboot"`
DisableKVM *bool `mapstructure:"disable_kvm" cty:"disable_kvm" hcl:"disable_kvm"`
TemplateName *string `mapstructure:"template_name" cty:"template_name" hcl:"template_name"`
TemplateDescription *string `mapstructure:"template_description" cty:"template_description" hcl:"template_description"`
CloudInit *bool `mapstructure:"cloud_init" cty:"cloud_init" hcl:"cloud_init"`
CloudInitStoragePool *string `mapstructure:"cloud_init_storage_pool" cty:"cloud_init_storage_pool" hcl:"cloud_init_storage_pool"`
AdditionalISOFiles []proxmox.FlatstorageConfig `mapstructure:"additional_iso_files" cty:"additional_iso_files" hcl:"additional_iso_files"`
VMInterface *string `mapstructure:"vm_interface" cty:"vm_interface" hcl:"vm_interface"`
CloneVM *string `mapstructure:"clone_vm" cty:"clone_vm" hcl:"clone_vm"`
FullClone *bool `mapstructure:"full_clone" required:"false" cty:"full_clone" hcl:"full_clone"`
PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"`
PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"`
PackerCoreVersion *string `mapstructure:"packer_core_version" cty:"packer_core_version" hcl:"packer_core_version"`
PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"`
PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"`
PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"`
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
HTTPDir *string `mapstructure:"http_directory" cty:"http_directory" hcl:"http_directory"`
HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min" hcl:"http_port_min"`
HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"`
HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"`
HTTPInterface *string `mapstructure:"http_interface" undocumented:"true" cty:"http_interface" hcl:"http_interface"`
BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval" hcl:"boot_keygroup_interval"`
BootWait *string `mapstructure:"boot_wait" cty:"boot_wait" hcl:"boot_wait"`
BootCommand []string `mapstructure:"boot_command" cty:"boot_command" hcl:"boot_command"`
BootKeyInterval *string `mapstructure:"boot_key_interval" cty:"boot_key_interval" hcl:"boot_key_interval"`
Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"`
PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"`
SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"`
SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"`
SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"`
SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"`
SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"`
SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"`
SSHTemporaryKeyPairType *string `mapstructure:"temporary_key_pair_type" cty:"temporary_key_pair_type" hcl:"temporary_key_pair_type"`
SSHTemporaryKeyPairBits *int `mapstructure:"temporary_key_pair_bits" cty:"temporary_key_pair_bits" hcl:"temporary_key_pair_bits"`
SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"`
SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"`
SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"`
SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"`
SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"`
SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"`
SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"`
SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"`
SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"`
SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"`
SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"`
SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"`
SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"`
SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"`
SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"`
SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"`
SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"`
SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"`
SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"`
SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"`
SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"`
SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"`
SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"`
SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"`
SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"`
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"`
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"`
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"`
SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"`
SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"`
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"`
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"`
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"`
WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"`
WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"`
WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"`
WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"`
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"`
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"`
ProxmoxURLRaw *string `mapstructure:"proxmox_url" cty:"proxmox_url" hcl:"proxmox_url"`
SkipCertValidation *bool `mapstructure:"insecure_skip_tls_verify" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"`
Username *string `mapstructure:"username" cty:"username" hcl:"username"`
Password *string `mapstructure:"password" cty:"password" hcl:"password"`
Node *string `mapstructure:"node" cty:"node" hcl:"node"`
Pool *string `mapstructure:"pool" cty:"pool" hcl:"pool"`
VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"`
VMID *int `mapstructure:"vm_id" cty:"vm_id" hcl:"vm_id"`
Boot *string `mapstructure:"boot" cty:"boot" hcl:"boot"`
Memory *int `mapstructure:"memory" cty:"memory" hcl:"memory"`
Cores *int `mapstructure:"cores" cty:"cores" hcl:"cores"`
CPUType *string `mapstructure:"cpu_type" cty:"cpu_type" hcl:"cpu_type"`
Sockets *int `mapstructure:"sockets" cty:"sockets" hcl:"sockets"`
OS *string `mapstructure:"os" cty:"os" hcl:"os"`
VGA *proxmox.FlatvgaConfig `mapstructure:"vga" cty:"vga" hcl:"vga"`
NICs []proxmox.FlatnicConfig `mapstructure:"network_adapters" cty:"network_adapters" hcl:"network_adapters"`
Disks []proxmox.FlatdiskConfig `mapstructure:"disks" cty:"disks" hcl:"disks"`
Agent *bool `mapstructure:"qemu_agent" cty:"qemu_agent" hcl:"qemu_agent"`
SCSIController *string `mapstructure:"scsi_controller" cty:"scsi_controller" hcl:"scsi_controller"`
Onboot *bool `mapstructure:"onboot" cty:"onboot" hcl:"onboot"`
DisableKVM *bool `mapstructure:"disable_kvm" cty:"disable_kvm" hcl:"disable_kvm"`
TemplateName *string `mapstructure:"template_name" cty:"template_name" hcl:"template_name"`
TemplateDescription *string `mapstructure:"template_description" cty:"template_description" hcl:"template_description"`
CloudInit *bool `mapstructure:"cloud_init" cty:"cloud_init" hcl:"cloud_init"`
CloudInitStoragePool *string `mapstructure:"cloud_init_storage_pool" cty:"cloud_init_storage_pool" hcl:"cloud_init_storage_pool"`
AdditionalISOFiles []proxmox.FlatadditionalISOsConfig `mapstructure:"additional_iso_files" cty:"additional_iso_files" hcl:"additional_iso_files"`
VMInterface *string `mapstructure:"vm_interface" cty:"vm_interface" hcl:"vm_interface"`
CloneVM *string `mapstructure:"clone_vm" cty:"clone_vm" hcl:"clone_vm"`
FullClone *bool `mapstructure:"full_clone" required:"false" cty:"full_clone" hcl:"full_clone"`
}
// FlatMapstructure returns a new FlatConfig.
@@ -211,7 +211,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"template_description": &hcldec.AttrSpec{Name: "template_description", Type: cty.String, Required: false},
"cloud_init": &hcldec.AttrSpec{Name: "cloud_init", Type: cty.Bool, Required: false},
"cloud_init_storage_pool": &hcldec.AttrSpec{Name: "cloud_init_storage_pool", Type: cty.String, Required: false},
"additional_iso_files": &hcldec.BlockListSpec{TypeName: "additional_iso_files", Nested: hcldec.ObjectSpec((*proxmox.FlatstorageConfig)(nil).HCL2Spec())},
"additional_iso_files": &hcldec.BlockListSpec{TypeName: "additional_iso_files", Nested: hcldec.ObjectSpec((*proxmox.FlatadditionalISOsConfig)(nil).HCL2Spec())},
"vm_interface": &hcldec.AttrSpec{Name: "vm_interface", Type: cty.String, Required: false},
"clone_vm": &hcldec.AttrSpec{Name: "clone_vm", Type: cty.String, Required: false},
"full_clone": &hcldec.AttrSpec{Name: "full_clone", Type: cty.Bool, Required: false},
+14 -1
View File
@@ -84,7 +84,20 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook,
&stepFinalizeTemplateConfig{},
&stepSuccess{},
}
steps := append(b.preSteps, coreSteps...)
preSteps := b.preSteps
for idx := range b.config.AdditionalISOFiles {
preSteps = append(preSteps, &commonsteps.StepDownload{
Checksum: b.config.AdditionalISOFiles[idx].ISOChecksum,
Description: "additional ISO",
Extension: b.config.AdditionalISOFiles[idx].TargetExtension,
ResultKey: b.config.AdditionalISOFiles[idx].DownloadPathKey,
TargetPath: b.config.AdditionalISOFiles[idx].DownloadPathKey,
Url: b.config.AdditionalISOFiles[idx].ISOUrls,
})
}
preSteps = append(preSteps, &stepUploadAdditionalISOs{})
steps := append(preSteps, coreSteps...)
steps = append(steps, b.postSteps...)
// Run the steps
b.runner = commonsteps.NewRunner(steps, b.config.PackerConfig, ui)
+57 -4
View File
@@ -1,4 +1,4 @@
//go:generate mapstructure-to-hcl2 -type Config,nicConfig,diskConfig,vgaConfig,storageConfig
//go:generate mapstructure-to-hcl2 -type Config,nicConfig,diskConfig,vgaConfig,additionalISOsConfig
package proxmox
@@ -8,6 +8,7 @@ import (
"log"
"net/url"
"os"
"strconv"
"strings"
"time"
@@ -60,13 +61,13 @@ type Config struct {
CloudInit bool `mapstructure:"cloud_init"`
CloudInitStoragePool string `mapstructure:"cloud_init_storage_pool"`
AdditionalISOFiles []storageConfig `mapstructure:"additional_iso_files"`
VMInterface string `mapstructure:"vm_interface"`
AdditionalISOFiles []additionalISOsConfig `mapstructure:"additional_iso_files"`
VMInterface string `mapstructure:"vm_interface"`
Ctx interpolate.Context `mapstructure-to-hcl2:",skip"`
}
type storageConfig struct {
type additionalISOsConfig struct {
commonsteps.ISOConfig `mapstructure:",squash"`
Device string `mapstructure:"device"`
ISOFile string `mapstructure:"iso_file"`
@@ -250,6 +251,58 @@ func (c *Config) Prepare(upper interface{}, raws ...interface{}) ([]string, []st
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("disks[%d].storage_pool_type must be specified", idx))
}
}
for idx := range c.AdditionalISOFiles {
// Check AdditionalISO config
// Either a pre-uploaded ISO should be referenced in iso_file, OR a URL
// (possibly to a local file) to an ISO file that will be downloaded and
// then uploaded to Proxmox.
if c.AdditionalISOFiles[idx].ISOFile != "" {
c.AdditionalISOFiles[idx].ShouldUploadISO = false
} else {
c.AdditionalISOFiles[idx].DownloadPathKey = "downloaded_additional_iso_path_" + strconv.Itoa(idx)
isoWarnings, isoErrors := c.AdditionalISOFiles[idx].ISOConfig.Prepare(&c.Ctx)
errs = packersdk.MultiErrorAppend(errs, isoErrors...)
warnings = append(warnings, isoWarnings...)
c.AdditionalISOFiles[idx].ShouldUploadISO = true
}
if c.AdditionalISOFiles[idx].Device == "" {
log.Printf("AdditionalISOFile %d Device not set, using default 'ide3'", idx)
c.AdditionalISOFiles[idx].Device = "ide3"
}
if strings.HasPrefix(c.AdditionalISOFiles[idx].Device, "ide") {
busnumber, err := strconv.Atoi(c.AdditionalISOFiles[idx].Device[3:])
if err != nil {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("%s is not a valid bus index", c.AdditionalISOFiles[idx].Device[3:]))
}
if busnumber == 2 {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("IDE bus 2 is used by boot ISO"))
}
if busnumber > 3 {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("IDE bus index can't be higher than 3"))
}
}
if strings.HasPrefix(c.AdditionalISOFiles[idx].Device, "sata") {
busnumber, err := strconv.Atoi(c.AdditionalISOFiles[idx].Device[4:])
if err != nil {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("%s is not a valid bus index", c.AdditionalISOFiles[idx].Device[4:]))
}
if busnumber > 5 {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("SATA bus index can't be higher than 5"))
}
}
if strings.HasPrefix(c.AdditionalISOFiles[idx].Device, "scsi") {
busnumber, err := strconv.Atoi(c.AdditionalISOFiles[idx].Device[4:])
if err != nil {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("%s is not a valid bus index", c.AdditionalISOFiles[idx].Device[4:]))
}
if busnumber > 30 {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("SCSI bus index can't be higher than 30"))
}
}
if (c.AdditionalISOFiles[idx].ISOFile == "" && len(c.AdditionalISOFiles[idx].ISOConfig.ISOUrls) == 0) || (c.AdditionalISOFiles[idx].ISOFile != "" && len(c.AdditionalISOFiles[idx].ISOConfig.ISOUrls) != 0) {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("either iso_file or iso_url, but not both, must be specified for AdditionalISO file %s", c.AdditionalISOFiles[idx].Device))
}
}
if errs != nil && len(errs.Errors) > 0 {
return nil, warnings, errs
+138 -138
View File
@@ -1,4 +1,4 @@
// Code generated by "mapstructure-to-hcl2 -type Config,nicConfig,diskConfig,vgaConfig,storageConfig"; DO NOT EDIT.
// Code generated by "mapstructure-to-hcl2 -type Config,nicConfig,diskConfig,vgaConfig,additionalISOsConfig"; DO NOT EDIT.
package proxmox
@@ -10,99 +10,99 @@ import (
// FlatConfig is an auto-generated flat version of Config.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatConfig struct {
PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"`
PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"`
PackerCoreVersion *string `mapstructure:"packer_core_version" cty:"packer_core_version" hcl:"packer_core_version"`
PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"`
PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"`
PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"`
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
HTTPDir *string `mapstructure:"http_directory" cty:"http_directory" hcl:"http_directory"`
HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min" hcl:"http_port_min"`
HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"`
HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"`
HTTPInterface *string `mapstructure:"http_interface" undocumented:"true" cty:"http_interface" hcl:"http_interface"`
BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval" hcl:"boot_keygroup_interval"`
BootWait *string `mapstructure:"boot_wait" cty:"boot_wait" hcl:"boot_wait"`
BootCommand []string `mapstructure:"boot_command" cty:"boot_command" hcl:"boot_command"`
BootKeyInterval *string `mapstructure:"boot_key_interval" cty:"boot_key_interval" hcl:"boot_key_interval"`
Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"`
PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"`
SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"`
SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"`
SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"`
SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"`
SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"`
SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"`
SSHTemporaryKeyPairType *string `mapstructure:"temporary_key_pair_type" cty:"temporary_key_pair_type" hcl:"temporary_key_pair_type"`
SSHTemporaryKeyPairBits *int `mapstructure:"temporary_key_pair_bits" cty:"temporary_key_pair_bits" hcl:"temporary_key_pair_bits"`
SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"`
SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"`
SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"`
SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"`
SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"`
SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"`
SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"`
SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"`
SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"`
SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"`
SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"`
SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"`
SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"`
SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"`
SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"`
SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"`
SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"`
SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"`
SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"`
SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"`
SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"`
SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"`
SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"`
SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"`
SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"`
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"`
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"`
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"`
SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"`
SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"`
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"`
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"`
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"`
WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"`
WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"`
WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"`
WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"`
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"`
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"`
ProxmoxURLRaw *string `mapstructure:"proxmox_url" cty:"proxmox_url" hcl:"proxmox_url"`
SkipCertValidation *bool `mapstructure:"insecure_skip_tls_verify" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"`
Username *string `mapstructure:"username" cty:"username" hcl:"username"`
Password *string `mapstructure:"password" cty:"password" hcl:"password"`
Node *string `mapstructure:"node" cty:"node" hcl:"node"`
Pool *string `mapstructure:"pool" cty:"pool" hcl:"pool"`
VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"`
VMID *int `mapstructure:"vm_id" cty:"vm_id" hcl:"vm_id"`
Boot *string `mapstructure:"boot" cty:"boot" hcl:"boot"`
Memory *int `mapstructure:"memory" cty:"memory" hcl:"memory"`
Cores *int `mapstructure:"cores" cty:"cores" hcl:"cores"`
CPUType *string `mapstructure:"cpu_type" cty:"cpu_type" hcl:"cpu_type"`
Sockets *int `mapstructure:"sockets" cty:"sockets" hcl:"sockets"`
OS *string `mapstructure:"os" cty:"os" hcl:"os"`
VGA *FlatvgaConfig `mapstructure:"vga" cty:"vga" hcl:"vga"`
NICs []FlatnicConfig `mapstructure:"network_adapters" cty:"network_adapters" hcl:"network_adapters"`
Disks []FlatdiskConfig `mapstructure:"disks" cty:"disks" hcl:"disks"`
Agent *bool `mapstructure:"qemu_agent" cty:"qemu_agent" hcl:"qemu_agent"`
SCSIController *string `mapstructure:"scsi_controller" cty:"scsi_controller" hcl:"scsi_controller"`
Onboot *bool `mapstructure:"onboot" cty:"onboot" hcl:"onboot"`
DisableKVM *bool `mapstructure:"disable_kvm" cty:"disable_kvm" hcl:"disable_kvm"`
TemplateName *string `mapstructure:"template_name" cty:"template_name" hcl:"template_name"`
TemplateDescription *string `mapstructure:"template_description" cty:"template_description" hcl:"template_description"`
CloudInit *bool `mapstructure:"cloud_init" cty:"cloud_init" hcl:"cloud_init"`
CloudInitStoragePool *string `mapstructure:"cloud_init_storage_pool" cty:"cloud_init_storage_pool" hcl:"cloud_init_storage_pool"`
AdditionalISOFiles []FlatstorageConfig `mapstructure:"additional_iso_files" cty:"additional_iso_files" hcl:"additional_iso_files"`
VMInterface *string `mapstructure:"vm_interface" cty:"vm_interface" hcl:"vm_interface"`
PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"`
PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"`
PackerCoreVersion *string `mapstructure:"packer_core_version" cty:"packer_core_version" hcl:"packer_core_version"`
PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"`
PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"`
PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"`
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
HTTPDir *string `mapstructure:"http_directory" cty:"http_directory" hcl:"http_directory"`
HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min" hcl:"http_port_min"`
HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"`
HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"`
HTTPInterface *string `mapstructure:"http_interface" undocumented:"true" cty:"http_interface" hcl:"http_interface"`
BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval" hcl:"boot_keygroup_interval"`
BootWait *string `mapstructure:"boot_wait" cty:"boot_wait" hcl:"boot_wait"`
BootCommand []string `mapstructure:"boot_command" cty:"boot_command" hcl:"boot_command"`
BootKeyInterval *string `mapstructure:"boot_key_interval" cty:"boot_key_interval" hcl:"boot_key_interval"`
Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"`
PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"`
SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"`
SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"`
SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"`
SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"`
SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"`
SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"`
SSHTemporaryKeyPairType *string `mapstructure:"temporary_key_pair_type" cty:"temporary_key_pair_type" hcl:"temporary_key_pair_type"`
SSHTemporaryKeyPairBits *int `mapstructure:"temporary_key_pair_bits" cty:"temporary_key_pair_bits" hcl:"temporary_key_pair_bits"`
SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"`
SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"`
SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"`
SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"`
SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"`
SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"`
SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"`
SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"`
SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"`
SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"`
SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"`
SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"`
SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"`
SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"`
SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"`
SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"`
SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"`
SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"`
SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"`
SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"`
SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"`
SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"`
SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"`
SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"`
SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"`
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"`
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"`
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"`
SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"`
SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"`
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"`
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"`
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"`
WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"`
WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"`
WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"`
WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"`
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"`
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"`
ProxmoxURLRaw *string `mapstructure:"proxmox_url" cty:"proxmox_url" hcl:"proxmox_url"`
SkipCertValidation *bool `mapstructure:"insecure_skip_tls_verify" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"`
Username *string `mapstructure:"username" cty:"username" hcl:"username"`
Password *string `mapstructure:"password" cty:"password" hcl:"password"`
Node *string `mapstructure:"node" cty:"node" hcl:"node"`
Pool *string `mapstructure:"pool" cty:"pool" hcl:"pool"`
VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"`
VMID *int `mapstructure:"vm_id" cty:"vm_id" hcl:"vm_id"`
Boot *string `mapstructure:"boot" cty:"boot" hcl:"boot"`
Memory *int `mapstructure:"memory" cty:"memory" hcl:"memory"`
Cores *int `mapstructure:"cores" cty:"cores" hcl:"cores"`
CPUType *string `mapstructure:"cpu_type" cty:"cpu_type" hcl:"cpu_type"`
Sockets *int `mapstructure:"sockets" cty:"sockets" hcl:"sockets"`
OS *string `mapstructure:"os" cty:"os" hcl:"os"`
VGA *FlatvgaConfig `mapstructure:"vga" cty:"vga" hcl:"vga"`
NICs []FlatnicConfig `mapstructure:"network_adapters" cty:"network_adapters" hcl:"network_adapters"`
Disks []FlatdiskConfig `mapstructure:"disks" cty:"disks" hcl:"disks"`
Agent *bool `mapstructure:"qemu_agent" cty:"qemu_agent" hcl:"qemu_agent"`
SCSIController *string `mapstructure:"scsi_controller" cty:"scsi_controller" hcl:"scsi_controller"`
Onboot *bool `mapstructure:"onboot" cty:"onboot" hcl:"onboot"`
DisableKVM *bool `mapstructure:"disable_kvm" cty:"disable_kvm" hcl:"disable_kvm"`
TemplateName *string `mapstructure:"template_name" cty:"template_name" hcl:"template_name"`
TemplateDescription *string `mapstructure:"template_description" cty:"template_description" hcl:"template_description"`
CloudInit *bool `mapstructure:"cloud_init" cty:"cloud_init" hcl:"cloud_init"`
CloudInitStoragePool *string `mapstructure:"cloud_init_storage_pool" cty:"cloud_init_storage_pool" hcl:"cloud_init_storage_pool"`
AdditionalISOFiles []FlatadditionalISOsConfig `mapstructure:"additional_iso_files" cty:"additional_iso_files" hcl:"additional_iso_files"`
VMInterface *string `mapstructure:"vm_interface" cty:"vm_interface" hcl:"vm_interface"`
}
// FlatMapstructure returns a new FlatConfig.
@@ -208,12 +208,55 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"template_description": &hcldec.AttrSpec{Name: "template_description", Type: cty.String, Required: false},
"cloud_init": &hcldec.AttrSpec{Name: "cloud_init", Type: cty.Bool, Required: false},
"cloud_init_storage_pool": &hcldec.AttrSpec{Name: "cloud_init_storage_pool", Type: cty.String, Required: false},
"additional_iso_files": &hcldec.BlockListSpec{TypeName: "additional_iso_files", Nested: hcldec.ObjectSpec((*FlatstorageConfig)(nil).HCL2Spec())},
"additional_iso_files": &hcldec.BlockListSpec{TypeName: "additional_iso_files", Nested: hcldec.ObjectSpec((*FlatadditionalISOsConfig)(nil).HCL2Spec())},
"vm_interface": &hcldec.AttrSpec{Name: "vm_interface", Type: cty.String, Required: false},
}
return s
}
// FlatadditionalISOsConfig is an auto-generated flat version of additionalISOsConfig.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatadditionalISOsConfig struct {
ISOChecksum *string `mapstructure:"iso_checksum" required:"true" cty:"iso_checksum" hcl:"iso_checksum"`
RawSingleISOUrl *string `mapstructure:"iso_url" required:"true" cty:"iso_url" hcl:"iso_url"`
ISOUrls []string `mapstructure:"iso_urls" cty:"iso_urls" hcl:"iso_urls"`
TargetPath *string `mapstructure:"iso_target_path" cty:"iso_target_path" hcl:"iso_target_path"`
TargetExtension *string `mapstructure:"iso_target_extension" cty:"iso_target_extension" hcl:"iso_target_extension"`
Device *string `mapstructure:"device" cty:"device" hcl:"device"`
ISOFile *string `mapstructure:"iso_file" cty:"iso_file" hcl:"iso_file"`
ISOStoragePool *string `mapstructure:"iso_storage_pool" cty:"iso_storage_pool" hcl:"iso_storage_pool"`
Unmount *bool `mapstructure:"unmount" cty:"unmount" hcl:"unmount"`
ShouldUploadISO *bool `cty:"should_upload_iso" hcl:"should_upload_iso"`
DownloadPathKey *string `cty:"download_path_key" hcl:"download_path_key"`
}
// FlatMapstructure returns a new FlatadditionalISOsConfig.
// FlatadditionalISOsConfig is an auto-generated flat version of additionalISOsConfig.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*additionalISOsConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatadditionalISOsConfig)
}
// HCL2Spec returns the hcl spec of a additionalISOsConfig.
// This spec is used by HCL to read the fields of additionalISOsConfig.
// The decoded values from this spec will then be applied to a FlatadditionalISOsConfig.
func (*FlatadditionalISOsConfig) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{
"iso_checksum": &hcldec.AttrSpec{Name: "iso_checksum", Type: cty.String, Required: false},
"iso_url": &hcldec.AttrSpec{Name: "iso_url", Type: cty.String, Required: false},
"iso_urls": &hcldec.AttrSpec{Name: "iso_urls", Type: cty.List(cty.String), Required: false},
"iso_target_path": &hcldec.AttrSpec{Name: "iso_target_path", Type: cty.String, Required: false},
"iso_target_extension": &hcldec.AttrSpec{Name: "iso_target_extension", Type: cty.String, Required: false},
"device": &hcldec.AttrSpec{Name: "device", Type: cty.String, Required: false},
"iso_file": &hcldec.AttrSpec{Name: "iso_file", Type: cty.String, Required: false},
"iso_storage_pool": &hcldec.AttrSpec{Name: "iso_storage_pool", Type: cty.String, Required: false},
"unmount": &hcldec.AttrSpec{Name: "unmount", Type: cty.Bool, Required: false},
"should_upload_iso": &hcldec.AttrSpec{Name: "should_upload_iso", Type: cty.Bool, Required: false},
"download_path_key": &hcldec.AttrSpec{Name: "download_path_key", Type: cty.String, Required: false},
}
return s
}
// FlatdiskConfig is an auto-generated flat version of diskConfig.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatdiskConfig struct {
@@ -282,49 +325,6 @@ func (*FlatnicConfig) HCL2Spec() map[string]hcldec.Spec {
return s
}
// FlatstorageConfig is an auto-generated flat version of storageConfig.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatstorageConfig struct {
ISOChecksum *string `mapstructure:"iso_checksum" required:"true" cty:"iso_checksum" hcl:"iso_checksum"`
RawSingleISOUrl *string `mapstructure:"iso_url" required:"true" cty:"iso_url" hcl:"iso_url"`
ISOUrls []string `mapstructure:"iso_urls" cty:"iso_urls" hcl:"iso_urls"`
TargetPath *string `mapstructure:"iso_target_path" cty:"iso_target_path" hcl:"iso_target_path"`
TargetExtension *string `mapstructure:"iso_target_extension" cty:"iso_target_extension" hcl:"iso_target_extension"`
Device *string `mapstructure:"device" cty:"device" hcl:"device"`
ISOFile *string `mapstructure:"iso_file" cty:"iso_file" hcl:"iso_file"`
ISOStoragePool *string `mapstructure:"iso_storage_pool" cty:"iso_storage_pool" hcl:"iso_storage_pool"`
Unmount *bool `mapstructure:"unmount" cty:"unmount" hcl:"unmount"`
ShouldUploadISO *bool `cty:"should_upload_iso" hcl:"should_upload_iso"`
DownloadPathKey *string `cty:"download_path_key" hcl:"download_path_key"`
}
// FlatMapstructure returns a new FlatstorageConfig.
// FlatstorageConfig is an auto-generated flat version of storageConfig.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*storageConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatstorageConfig)
}
// HCL2Spec returns the hcl spec of a storageConfig.
// This spec is used by HCL to read the fields of storageConfig.
// The decoded values from this spec will then be applied to a FlatstorageConfig.
func (*FlatstorageConfig) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{
"iso_checksum": &hcldec.AttrSpec{Name: "iso_checksum", Type: cty.String, Required: false},
"iso_url": &hcldec.AttrSpec{Name: "iso_url", Type: cty.String, Required: false},
"iso_urls": &hcldec.AttrSpec{Name: "iso_urls", Type: cty.List(cty.String), Required: false},
"iso_target_path": &hcldec.AttrSpec{Name: "iso_target_path", Type: cty.String, Required: false},
"iso_target_extension": &hcldec.AttrSpec{Name: "iso_target_extension", Type: cty.String, Required: false},
"device": &hcldec.AttrSpec{Name: "device", Type: cty.String, Required: false},
"iso_file": &hcldec.AttrSpec{Name: "iso_file", Type: cty.String, Required: false},
"iso_storage_pool": &hcldec.AttrSpec{Name: "iso_storage_pool", Type: cty.String, Required: false},
"unmount": &hcldec.AttrSpec{Name: "unmount", Type: cty.Bool, Required: false},
"should_upload_iso": &hcldec.AttrSpec{Name: "should_upload_iso", Type: cty.Bool, Required: false},
"download_path_key": &hcldec.AttrSpec{Name: "download_path_key", Type: cty.String, Required: false},
}
return s
}
// FlatvgaConfig is an auto-generated flat version of vgaConfig.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatvgaConfig struct {
@@ -80,6 +80,30 @@ func (s *stepFinalizeTemplateConfig) Run(ctx context.Context, state multistep.St
}
}
if len(c.AdditionalISOFiles) > 0 {
vmParams, err := client.GetVmConfig(vmRef)
if err != nil {
err := fmt.Errorf("Error fetching template config: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
for idx := range c.AdditionalISOFiles {
cdrom := c.AdditionalISOFiles[idx].Device
if c.AdditionalISOFiles[idx].Unmount {
if vmParams[cdrom] == nil || !strings.Contains(vmParams[cdrom].(string), "media=cdrom") {
err := fmt.Errorf("Cannot eject ISO from cdrom drive, %s is not present or not a cdrom media", cdrom)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
changes[cdrom] = "none,media=cdrom"
} else {
changes[cdrom] = c.AdditionalISOFiles[idx].ISOFile + ",media=cdrom"
}
}
}
if len(changes) > 0 {
_, err := client.SetVmConfig(vmRef, changes)
if err != nil {
+26 -13
View File
@@ -3,7 +3,6 @@ package proxmox
import (
"context"
"fmt"
"log"
"strconv"
"github.com/Telmate/proxmox-api-go/proxmox"
@@ -22,10 +21,15 @@ type stepStartVM struct {
type ProxmoxVMCreator interface {
Create(*proxmox.VmRef, proxmox.ConfigQemu, multistep.StateBag) error
}
type vmStarter interface {
GetNextID(int) (int, error)
StartVm(*proxmox.VmRef) (string, error)
SetVmConfig(*proxmox.VmRef, map[string]interface{}) (interface{}, error)
}
func (s *stepStartVM) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packersdk.Ui)
client := state.Get("proxmoxClient").(*proxmox.Client)
client := state.Get("proxmoxClient").(vmStarter)
c := state.Get("config").(*Config)
agent := 1
@@ -59,21 +63,14 @@ func (s *stepStartVM) Run(ctx context.Context, state multistep.StateBag) multist
if c.VMID == 0 {
ui.Say("No VM ID given, getting next free from Proxmox")
for n := 0; n < 5; n++ {
id, err := proxmox.MaxVmId(client)
if err != nil {
log.Printf("Error getting max used VM ID: %v (attempt %d/5)", err, n+1)
continue
}
c.VMID = id + 1
break
}
if c.VMID == 0 {
err := fmt.Errorf("Failed to get free VM ID")
id, err := client.GetNextID(0)
if err != nil {
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
c.VMID = id
config.VmID = id
}
vmRef := proxmox.NewVmRef(c.VMID)
vmRef.SetNode(c.Node)
@@ -89,6 +86,22 @@ func (s *stepStartVM) Run(ctx context.Context, state multistep.StateBag) multist
return multistep.ActionHalt
}
// proxmox-api-go assumes all QemuDisks are actually hard disks, not cd
// drives, so we need to add them via a config update
if len(c.AdditionalISOFiles) > 0 {
addISOConfig := make(map[string]interface{})
for _, iso := range c.AdditionalISOFiles {
addISOConfig[iso.Device] = fmt.Sprintf("%s,media=cdrom", iso.ISOFile)
}
_, err := client.SetVmConfig(vmRef, addISOConfig)
if err != nil {
err := fmt.Errorf("Error updating template: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
}
// Store the vm id for later
state.Put("vmRef", vmRef)
// instance_id is the generic term used so that users can have access to the
@@ -1,6 +1,7 @@
package proxmox
import (
"context"
"fmt"
"testing"
@@ -106,3 +107,80 @@ func TestCleanupStartVM(t *testing.T) {
})
}
}
type startVMMock struct {
create func(*proxmox.VmRef, proxmox.ConfigQemu, multistep.StateBag) error
startVm func(*proxmox.VmRef) (string, error)
setVmConfig func(*proxmox.VmRef, map[string]interface{}) (interface{}, error)
}
func (m *startVMMock) Create(vmRef *proxmox.VmRef, config proxmox.ConfigQemu, state multistep.StateBag) error {
return m.create(vmRef, config, state)
}
func (m *startVMMock) StartVm(vmRef *proxmox.VmRef) (string, error) {
return m.startVm(vmRef)
}
func (m *startVMMock) SetVmConfig(vmRef *proxmox.VmRef, config map[string]interface{}) (interface{}, error) {
return m.setVmConfig(vmRef, config)
}
func (m *startVMMock) GetNextID(int) (int, error) {
return 1, nil
}
func TestStartVM(t *testing.T) {
// TODO: proxmox-api-go does a lot of manipulation on the input and does not
// give any way to access the actual data it sends to the Proxmox server,
// which means writing good tests here is quite hard. This test is mainly a
// stub to revisit when we can write better tests.
cs := []struct {
name string
config *Config
expectedAction multistep.StepAction
}{
{
name: "Example config from documentation works",
config: &Config{
Disks: []diskConfig{
{
Type: "sata",
Size: "10G",
StoragePool: "local",
StoragePoolType: "lvm",
},
},
NICs: []nicConfig{
{
Bridge: "vmbr0",
},
},
},
expectedAction: multistep.ActionContinue,
},
}
for _, c := range cs {
t.Run(c.name, func(t *testing.T) {
mock := &startVMMock{
create: func(vmRef *proxmox.VmRef, config proxmox.ConfigQemu, state multistep.StateBag) error {
return nil
},
startVm: func(*proxmox.VmRef) (string, error) {
return "", nil
},
setVmConfig: func(*proxmox.VmRef, map[string]interface{}) (interface{}, error) {
return nil, nil
},
}
state := new(multistep.BasicStateBag)
state.Put("ui", packersdk.TestUi(t))
state.Put("config", c.config)
state.Put("proxmoxClient", mock)
s := stepStartVM{vmCreator: mock}
action := s.Run(context.TODO(), state)
if action != c.expectedAction {
t.Errorf("Expected action %s, got %s", c.expectedAction, action)
}
})
}
}
@@ -1,8 +1,9 @@
package proxmoxiso
package proxmox
import (
"context"
"fmt"
"io"
"os"
"path/filepath"
@@ -15,12 +16,16 @@ import (
// to the VM
type stepUploadAdditionalISOs struct{}
type uploader interface {
Upload(node string, storage string, contentType string, filename string, file io.Reader) error
}
var _ uploader = &proxmox.Client{}
func (s *stepUploadAdditionalISOs) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packersdk.Ui)
client := state.Get("proxmoxClient").(uploader)
c := state.Get("iso-config").(*Config)
c := state.Get("config").(*Config)
for idx := range c.AdditionalISOFiles {
if !c.AdditionalISOFiles[idx].ShouldUploadISO {
-11
View File
@@ -43,19 +43,8 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
Url: b.config.ISOUrls,
},
}
for idx := range b.config.AdditionalISOFiles {
preSteps = append(preSteps, &commonsteps.StepDownload{
Checksum: b.config.AdditionalISOFiles[idx].ISOChecksum,
Description: "additional ISO",
Extension: b.config.AdditionalISOFiles[idx].TargetExtension,
ResultKey: b.config.AdditionalISOFiles[idx].DownloadPathKey,
TargetPath: b.config.AdditionalISOFiles[idx].DownloadPathKey,
Url: b.config.AdditionalISOFiles[idx].ISOUrls,
})
}
preSteps = append(preSteps,
&stepUploadISO{},
&stepUploadAdditionalISOs{},
)
postSteps := []multistep.Step{
&stepFinalizeISOTemplate{},
+1 -61
View File
@@ -1,13 +1,9 @@
//go:generate mapstructure-to-hcl2 -type Config,nicConfig,diskConfig,vgaConfig
//go:generate mapstructure-to-hcl2 -type Config,nicConfig,diskConfig,vgaConfig,additionalISOsConfig
package proxmoxiso
import (
"errors"
"fmt"
"log"
"strconv"
"strings"
"github.com/hashicorp/packer-plugin-sdk/multistep/commonsteps"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
@@ -51,62 +47,6 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, []string, error) {
errs = packersdk.MultiErrorAppend(errs, errors.New("when specifying iso_url, iso_storage_pool must also be specified"))
}
for idx := range c.AdditionalISOFiles {
// Check AdditionalISO config
// Either a pre-uploaded ISO should be referenced in iso_file, OR a URL
// (possibly to a local file) to an ISO file that will be downloaded and
// then uploaded to Proxmox.
if c.AdditionalISOFiles[idx].ISOFile != "" {
c.AdditionalISOFiles[idx].ShouldUploadISO = false
} else {
c.AdditionalISOFiles[idx].DownloadPathKey = "downloaded_additional_iso_path_" + strconv.Itoa(idx)
isoWarnings, isoErrors := c.AdditionalISOFiles[idx].ISOConfig.Prepare(&c.Ctx)
errs = packersdk.MultiErrorAppend(errs, isoErrors...)
warnings = append(warnings, isoWarnings...)
c.AdditionalISOFiles[idx].ShouldUploadISO = true
}
if c.AdditionalISOFiles[idx].Device == "" {
log.Printf("AdditionalISOFile %d Device not set, using default 'ide3'", idx)
c.AdditionalISOFiles[idx].Device = "ide3"
}
if strings.HasPrefix(c.AdditionalISOFiles[idx].Device, "ide") {
busnumber, err := strconv.Atoi(c.AdditionalISOFiles[idx].Device[3:])
if err != nil {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("%s is not a valid bus index", c.AdditionalISOFiles[idx].Device[3:]))
}
if busnumber == 2 {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("IDE bus 2 is used by boot ISO"))
}
if busnumber > 3 {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("IDE bus index can't be higher than 3"))
}
}
if strings.HasPrefix(c.AdditionalISOFiles[idx].Device, "sata") {
busnumber, err := strconv.Atoi(c.AdditionalISOFiles[idx].Device[4:])
if err != nil {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("%s is not a valid bus index", c.AdditionalISOFiles[idx].Device[4:]))
}
if busnumber > 5 {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("SATA bus index can't be higher than 5"))
}
}
if strings.HasPrefix(c.AdditionalISOFiles[idx].Device, "scsi") {
busnumber, err := strconv.Atoi(c.AdditionalISOFiles[idx].Device[4:])
if err != nil {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("%s is not a valid bus index", c.AdditionalISOFiles[idx].Device[4:]))
}
if busnumber > 30 {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("SCSI bus index can't be higher than 30"))
}
}
if (c.AdditionalISOFiles[idx].ISOFile == "" && len(c.AdditionalISOFiles[idx].ISOConfig.ISOUrls) == 0) || (c.AdditionalISOFiles[idx].ISOFile != "" && len(c.AdditionalISOFiles[idx].ISOConfig.ISOUrls) != 0) {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("either iso_file or iso_url, but not both, must be specified for AdditionalISO file %s", c.AdditionalISOFiles[idx].Device))
}
if len(c.ISOConfig.ISOUrls) != 0 && c.ISOStoragePool == "" {
errs = packersdk.MultiErrorAppend(errs, errors.New("when specifying iso_url, iso_storage_pool must also be specified"))
}
}
if errs != nil && len(errs.Errors) > 0 {
return nil, warnings, errs
}
+103 -103
View File
@@ -1,4 +1,4 @@
// Code generated by "mapstructure-to-hcl2 -type Config,nicConfig,diskConfig,vgaConfig"; DO NOT EDIT.
// Code generated by "mapstructure-to-hcl2 -type Config,nicConfig,diskConfig,vgaConfig,additionalISOsConfig"; DO NOT EDIT.
package proxmoxiso
@@ -11,107 +11,107 @@ import (
// FlatConfig is an auto-generated flat version of Config.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatConfig struct {
PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"`
PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"`
PackerCoreVersion *string `mapstructure:"packer_core_version" cty:"packer_core_version" hcl:"packer_core_version"`
PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"`
PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"`
PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"`
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
HTTPDir *string `mapstructure:"http_directory" cty:"http_directory" hcl:"http_directory"`
HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min" hcl:"http_port_min"`
HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"`
HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"`
HTTPInterface *string `mapstructure:"http_interface" undocumented:"true" cty:"http_interface" hcl:"http_interface"`
BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval" hcl:"boot_keygroup_interval"`
BootWait *string `mapstructure:"boot_wait" cty:"boot_wait" hcl:"boot_wait"`
BootCommand []string `mapstructure:"boot_command" cty:"boot_command" hcl:"boot_command"`
BootKeyInterval *string `mapstructure:"boot_key_interval" cty:"boot_key_interval" hcl:"boot_key_interval"`
Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"`
PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"`
SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"`
SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"`
SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"`
SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"`
SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"`
SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"`
SSHTemporaryKeyPairType *string `mapstructure:"temporary_key_pair_type" cty:"temporary_key_pair_type" hcl:"temporary_key_pair_type"`
SSHTemporaryKeyPairBits *int `mapstructure:"temporary_key_pair_bits" cty:"temporary_key_pair_bits" hcl:"temporary_key_pair_bits"`
SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"`
SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"`
SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"`
SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"`
SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"`
SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"`
SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"`
SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"`
SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"`
SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"`
SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"`
SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"`
SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"`
SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"`
SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"`
SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"`
SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"`
SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"`
SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"`
SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"`
SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"`
SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"`
SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"`
SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"`
SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"`
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"`
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"`
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"`
SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"`
SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"`
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"`
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"`
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"`
WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"`
WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"`
WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"`
WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"`
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"`
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"`
ProxmoxURLRaw *string `mapstructure:"proxmox_url" cty:"proxmox_url" hcl:"proxmox_url"`
SkipCertValidation *bool `mapstructure:"insecure_skip_tls_verify" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"`
Username *string `mapstructure:"username" cty:"username" hcl:"username"`
Password *string `mapstructure:"password" cty:"password" hcl:"password"`
Node *string `mapstructure:"node" cty:"node" hcl:"node"`
Pool *string `mapstructure:"pool" cty:"pool" hcl:"pool"`
VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"`
VMID *int `mapstructure:"vm_id" cty:"vm_id" hcl:"vm_id"`
Boot *string `mapstructure:"boot" cty:"boot" hcl:"boot"`
Memory *int `mapstructure:"memory" cty:"memory" hcl:"memory"`
Cores *int `mapstructure:"cores" cty:"cores" hcl:"cores"`
CPUType *string `mapstructure:"cpu_type" cty:"cpu_type" hcl:"cpu_type"`
Sockets *int `mapstructure:"sockets" cty:"sockets" hcl:"sockets"`
OS *string `mapstructure:"os" cty:"os" hcl:"os"`
VGA *proxmox.FlatvgaConfig `mapstructure:"vga" cty:"vga" hcl:"vga"`
NICs []proxmox.FlatnicConfig `mapstructure:"network_adapters" cty:"network_adapters" hcl:"network_adapters"`
Disks []proxmox.FlatdiskConfig `mapstructure:"disks" cty:"disks" hcl:"disks"`
Agent *bool `mapstructure:"qemu_agent" cty:"qemu_agent" hcl:"qemu_agent"`
SCSIController *string `mapstructure:"scsi_controller" cty:"scsi_controller" hcl:"scsi_controller"`
Onboot *bool `mapstructure:"onboot" cty:"onboot" hcl:"onboot"`
DisableKVM *bool `mapstructure:"disable_kvm" cty:"disable_kvm" hcl:"disable_kvm"`
TemplateName *string `mapstructure:"template_name" cty:"template_name" hcl:"template_name"`
TemplateDescription *string `mapstructure:"template_description" cty:"template_description" hcl:"template_description"`
CloudInit *bool `mapstructure:"cloud_init" cty:"cloud_init" hcl:"cloud_init"`
CloudInitStoragePool *string `mapstructure:"cloud_init_storage_pool" cty:"cloud_init_storage_pool" hcl:"cloud_init_storage_pool"`
AdditionalISOFiles []proxmox.FlatstorageConfig `mapstructure:"additional_iso_files" cty:"additional_iso_files" hcl:"additional_iso_files"`
VMInterface *string `mapstructure:"vm_interface" cty:"vm_interface" hcl:"vm_interface"`
ISOChecksum *string `mapstructure:"iso_checksum" required:"true" cty:"iso_checksum" hcl:"iso_checksum"`
RawSingleISOUrl *string `mapstructure:"iso_url" required:"true" cty:"iso_url" hcl:"iso_url"`
ISOUrls []string `mapstructure:"iso_urls" cty:"iso_urls" hcl:"iso_urls"`
TargetPath *string `mapstructure:"iso_target_path" cty:"iso_target_path" hcl:"iso_target_path"`
TargetExtension *string `mapstructure:"iso_target_extension" cty:"iso_target_extension" hcl:"iso_target_extension"`
ISOFile *string `mapstructure:"iso_file" cty:"iso_file" hcl:"iso_file"`
ISOStoragePool *string `mapstructure:"iso_storage_pool" cty:"iso_storage_pool" hcl:"iso_storage_pool"`
UnmountISO *bool `mapstructure:"unmount_iso" cty:"unmount_iso" hcl:"unmount_iso"`
PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"`
PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"`
PackerCoreVersion *string `mapstructure:"packer_core_version" cty:"packer_core_version" hcl:"packer_core_version"`
PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"`
PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"`
PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"`
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
HTTPDir *string `mapstructure:"http_directory" cty:"http_directory" hcl:"http_directory"`
HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min" hcl:"http_port_min"`
HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"`
HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"`
HTTPInterface *string `mapstructure:"http_interface" undocumented:"true" cty:"http_interface" hcl:"http_interface"`
BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval" hcl:"boot_keygroup_interval"`
BootWait *string `mapstructure:"boot_wait" cty:"boot_wait" hcl:"boot_wait"`
BootCommand []string `mapstructure:"boot_command" cty:"boot_command" hcl:"boot_command"`
BootKeyInterval *string `mapstructure:"boot_key_interval" cty:"boot_key_interval" hcl:"boot_key_interval"`
Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"`
PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"`
SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"`
SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"`
SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"`
SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"`
SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"`
SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"`
SSHTemporaryKeyPairType *string `mapstructure:"temporary_key_pair_type" cty:"temporary_key_pair_type" hcl:"temporary_key_pair_type"`
SSHTemporaryKeyPairBits *int `mapstructure:"temporary_key_pair_bits" cty:"temporary_key_pair_bits" hcl:"temporary_key_pair_bits"`
SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"`
SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"`
SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"`
SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"`
SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"`
SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"`
SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"`
SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"`
SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"`
SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"`
SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"`
SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"`
SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"`
SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"`
SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"`
SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"`
SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"`
SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"`
SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"`
SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"`
SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"`
SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"`
SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"`
SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"`
SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"`
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"`
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"`
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"`
SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"`
SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"`
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"`
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"`
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"`
WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"`
WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"`
WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"`
WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"`
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"`
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"`
ProxmoxURLRaw *string `mapstructure:"proxmox_url" cty:"proxmox_url" hcl:"proxmox_url"`
SkipCertValidation *bool `mapstructure:"insecure_skip_tls_verify" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"`
Username *string `mapstructure:"username" cty:"username" hcl:"username"`
Password *string `mapstructure:"password" cty:"password" hcl:"password"`
Node *string `mapstructure:"node" cty:"node" hcl:"node"`
Pool *string `mapstructure:"pool" cty:"pool" hcl:"pool"`
VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"`
VMID *int `mapstructure:"vm_id" cty:"vm_id" hcl:"vm_id"`
Boot *string `mapstructure:"boot" cty:"boot" hcl:"boot"`
Memory *int `mapstructure:"memory" cty:"memory" hcl:"memory"`
Cores *int `mapstructure:"cores" cty:"cores" hcl:"cores"`
CPUType *string `mapstructure:"cpu_type" cty:"cpu_type" hcl:"cpu_type"`
Sockets *int `mapstructure:"sockets" cty:"sockets" hcl:"sockets"`
OS *string `mapstructure:"os" cty:"os" hcl:"os"`
VGA *proxmox.FlatvgaConfig `mapstructure:"vga" cty:"vga" hcl:"vga"`
NICs []proxmox.FlatnicConfig `mapstructure:"network_adapters" cty:"network_adapters" hcl:"network_adapters"`
Disks []proxmox.FlatdiskConfig `mapstructure:"disks" cty:"disks" hcl:"disks"`
Agent *bool `mapstructure:"qemu_agent" cty:"qemu_agent" hcl:"qemu_agent"`
SCSIController *string `mapstructure:"scsi_controller" cty:"scsi_controller" hcl:"scsi_controller"`
Onboot *bool `mapstructure:"onboot" cty:"onboot" hcl:"onboot"`
DisableKVM *bool `mapstructure:"disable_kvm" cty:"disable_kvm" hcl:"disable_kvm"`
TemplateName *string `mapstructure:"template_name" cty:"template_name" hcl:"template_name"`
TemplateDescription *string `mapstructure:"template_description" cty:"template_description" hcl:"template_description"`
CloudInit *bool `mapstructure:"cloud_init" cty:"cloud_init" hcl:"cloud_init"`
CloudInitStoragePool *string `mapstructure:"cloud_init_storage_pool" cty:"cloud_init_storage_pool" hcl:"cloud_init_storage_pool"`
AdditionalISOFiles []proxmox.FlatadditionalISOsConfig `mapstructure:"additional_iso_files" cty:"additional_iso_files" hcl:"additional_iso_files"`
VMInterface *string `mapstructure:"vm_interface" cty:"vm_interface" hcl:"vm_interface"`
ISOChecksum *string `mapstructure:"iso_checksum" required:"true" cty:"iso_checksum" hcl:"iso_checksum"`
RawSingleISOUrl *string `mapstructure:"iso_url" required:"true" cty:"iso_url" hcl:"iso_url"`
ISOUrls []string `mapstructure:"iso_urls" cty:"iso_urls" hcl:"iso_urls"`
TargetPath *string `mapstructure:"iso_target_path" cty:"iso_target_path" hcl:"iso_target_path"`
TargetExtension *string `mapstructure:"iso_target_extension" cty:"iso_target_extension" hcl:"iso_target_extension"`
ISOFile *string `mapstructure:"iso_file" cty:"iso_file" hcl:"iso_file"`
ISOStoragePool *string `mapstructure:"iso_storage_pool" cty:"iso_storage_pool" hcl:"iso_storage_pool"`
UnmountISO *bool `mapstructure:"unmount_iso" cty:"unmount_iso" hcl:"unmount_iso"`
}
// FlatMapstructure returns a new FlatConfig.
@@ -217,7 +217,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"template_description": &hcldec.AttrSpec{Name: "template_description", Type: cty.String, Required: false},
"cloud_init": &hcldec.AttrSpec{Name: "cloud_init", Type: cty.Bool, Required: false},
"cloud_init_storage_pool": &hcldec.AttrSpec{Name: "cloud_init_storage_pool", Type: cty.String, Required: false},
"additional_iso_files": &hcldec.BlockListSpec{TypeName: "additional_iso_files", Nested: hcldec.ObjectSpec((*proxmox.FlatstorageConfig)(nil).HCL2Spec())},
"additional_iso_files": &hcldec.BlockListSpec{TypeName: "additional_iso_files", Nested: hcldec.ObjectSpec((*proxmox.FlatadditionalISOsConfig)(nil).HCL2Spec())},
"vm_interface": &hcldec.AttrSpec{Name: "vm_interface", Type: cty.String, Required: false},
"iso_checksum": &hcldec.AttrSpec{Name: "iso_checksum", Type: cty.String, Required: false},
"iso_url": &hcldec.AttrSpec{Name: "iso_url", Type: cty.String, Required: false},
-23
View File
@@ -46,29 +46,6 @@ func (s *stepFinalizeISOTemplate) Run(ctx context.Context, state multistep.State
}
changes["ide2"] = "none,media=cdrom"
}
if len(c.AdditionalISOFiles) > 0 {
vmParams, err := client.GetVmConfig(vmRef)
if err != nil {
err := fmt.Errorf("Error fetching template config: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
for idx := range c.AdditionalISOFiles {
cdrom := c.AdditionalISOFiles[idx].Device
if c.AdditionalISOFiles[idx].Unmount {
if vmParams[cdrom] == nil || !strings.Contains(vmParams[cdrom].(string), "media=cdrom") {
err := fmt.Errorf("Cannot eject ISO from cdrom drive, %s is not present or not a cdrom media", cdrom)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
changes[cdrom] = "none,media=cdrom"
} else {
changes[cdrom] = c.AdditionalISOFiles[idx].ISOFile + ",media=cdrom"
}
}
}
if len(changes) > 0 {
_, err := client.SetVmConfig(vmRef, changes)
+8 -2
View File
@@ -74,8 +74,10 @@ type Config struct {
RemoveVolume bool `mapstructure:"remove_volume"`
UserAgent string `mapstructure-to-hcl2:",skip"`
ctx interpolate.Context
// Shutdown timeout. Default to 5m
ShutdownTimeout string `mapstructure:"shutdown_timeout" required:"false"`
UserAgent string `mapstructure-to-hcl2:",skip"`
ctx interpolate.Context
// Deprecated configs
@@ -255,6 +257,10 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
errs, errors.New("image is required"))
}
if c.ShutdownTimeout == "" {
c.ShutdownTimeout = "5m"
}
if errs != nil && len(errs.Errors) > 0 {
return warnings, errs
}
+2
View File
@@ -80,6 +80,7 @@ type FlatConfig struct {
Bootscript *string `mapstructure:"bootscript" required:"false" cty:"bootscript" hcl:"bootscript"`
BootType *string `mapstructure:"boottype" required:"false" cty:"boottype" hcl:"boottype"`
RemoveVolume *bool `mapstructure:"remove_volume" cty:"remove_volume" hcl:"remove_volume"`
ShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout" hcl:"shutdown_timeout"`
Token *string `mapstructure:"api_token" required:"false" cty:"api_token" hcl:"api_token"`
Organization *string `mapstructure:"organization_id" required:"false" cty:"organization_id" hcl:"organization_id"`
Region *string `mapstructure:"region" required:"false" cty:"region" hcl:"region"`
@@ -167,6 +168,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"bootscript": &hcldec.AttrSpec{Name: "bootscript", Type: cty.String, Required: false},
"boottype": &hcldec.AttrSpec{Name: "boottype", Type: cty.String, Required: false},
"remove_volume": &hcldec.AttrSpec{Name: "remove_volume", Type: cty.Bool, Required: false},
"shutdown_timeout": &hcldec.AttrSpec{Name: "shutdown_timeout", Type: cty.String, Required: false},
"api_token": &hcldec.AttrSpec{Name: "api_token", Type: cty.String, Required: false},
"organization_id": &hcldec.AttrSpec{Name: "organization_id", Type: cty.String, Required: false},
"region": &hcldec.AttrSpec{Name: "region", Type: cty.String, Required: false},
+17 -2
View File
@@ -3,6 +3,7 @@ package scaleway
import (
"context"
"fmt"
"time"
"github.com/hashicorp/packer-plugin-sdk/multistep"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
@@ -30,9 +31,23 @@ func (s *stepShutdown) Run(ctx context.Context, state multistep.StateBag) multis
return multistep.ActionHalt
}
instanceResp, err := instanceAPI.WaitForServer(&instance.WaitForServerRequest{
waitRequest := &instance.WaitForServerRequest{
ServerID: serverID,
})
}
c := state.Get("config").(*Config)
timeout := c.ShutdownTimeout
duration, err := time.ParseDuration(timeout)
if err != nil {
err := fmt.Errorf("error: %s could not parse string %s as a duration", err, timeout)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
if timeout != "" {
waitRequest.Timeout = scw.TimeDurationPtr(duration)
}
instanceResp, err := instanceAPI.WaitForServer(waitRequest)
if err != nil {
err := fmt.Errorf("Error shutting down server: %s", err)
state.Put("error", err)
+3
View File
@@ -22,6 +22,9 @@ type Driver interface {
// Create a SCSI controller.
CreateSCSIController(vm string, controller string) error
// Create a VirtIO controller.
CreateVirtIOController(vm string, controller string) error
// Create an NVME controller
CreateNVMeController(vm string, controller string, portcount int) error
+11 -1
View File
@@ -64,7 +64,6 @@ func (d *VBox42Driver) CreateNVMeController(vmName string, name string, portcoun
}
func (d *VBox42Driver) CreateSCSIController(vmName string, name string) error {
command := []string{
"storagectl", vmName,
"--name", name,
@@ -75,6 +74,17 @@ func (d *VBox42Driver) CreateSCSIController(vmName string, name string) error {
return d.VBoxManage(command...)
}
func (d *VBox42Driver) CreateVirtIOController(vmName string, name string) error {
command := []string{
"storagectl", vmName,
"--name", name,
"--add", "VirtIO",
"--controller", "VirtIO",
}
return d.VBoxManage(command...)
}
func (d *VBox42Driver) RemoveFloppyControllers(vmName string) error {
var stdout bytes.Buffer
+10
View File
@@ -13,6 +13,10 @@ type DriverMock struct {
CreateSCSIControllerController string
CreateSCSIControllerErr error
CreateVirtIOControllerVM string
CreateVirtIOControllerController string
CreateVirtIOControllerErr error
CreateNVMeControllerVM string
CreateNVMeControllerController string
CreateNVMeControllerErr error
@@ -78,6 +82,12 @@ func (d *DriverMock) CreateSCSIController(vm string, controller string) error {
return d.CreateSCSIControllerErr
}
func (d *DriverMock) CreateVirtIOController(vm string, controller string) error {
d.CreateVirtIOControllerVM = vm
d.CreateVirtIOControllerController = vm
return d.CreateVirtIOControllerErr
}
func (d *DriverMock) CreateNVMeController(vm string, controller string, portcount int) error {
d.CreateNVMeControllerVM = vm
d.CreateNVMeControllerController = vm
@@ -80,6 +80,10 @@ func (s *StepAttachISOs) Run(ctx context.Context, state multistep.StateBag) mult
controllerName = "SATA Controller"
port = "1"
device = "0"
} else if s.ISOInterface == "virtio" {
controllerName = "VirtIO Controller"
port = "1"
device = "0"
}
ui.Message("Mounting boot ISO...")
case "guest_additions":
@@ -90,6 +94,10 @@ func (s *StepAttachISOs) Run(ctx context.Context, state multistep.StateBag) mult
controllerName = "SATA Controller"
port = "2"
device = "0"
} else if s.GuestAdditionsInterface == "virtio" {
controllerName = "VirtIO Controller"
port = "2"
device = "0"
}
ui.Message("Mounting guest additions ISO...")
case "cd_files":
@@ -100,6 +108,10 @@ func (s *StepAttachISOs) Run(ctx context.Context, state multistep.StateBag) mult
controllerName = "SATA Controller"
port = "3"
device = "0"
} else if s.ISOInterface == "virtio" {
controllerName = "VirtIO Controller"
port = "3"
device = "0"
}
ui.Message("Mounting cd_files ISO...")
}
+89 -4
View File
@@ -44,9 +44,37 @@ type Config struct {
vboxcommon.VBoxVersionConfig `mapstructure:",squash"`
vboxcommon.VBoxBundleConfig `mapstructure:",squash"`
vboxcommon.GuestAdditionsConfig `mapstructure:",squash"`
// The chipset to be used: PIIX3 or ICH9.
// When set to piix3, the firmare is PIIX3. This is the default.
// When set to ich9, the firmare is ICH9.
Chipset string `mapstructure:"chipset" required:"false"`
// The firmware to be used: BIOS or EFI.
// When set to bios, the firmare is BIOS. This is the default.
// When set to efi, the firmare is EFI.
Firmware string `mapstructure:"firmware" required:"false"`
// The size, in megabytes, of the hard disk to create for the VM. By
// default, this is 40000 (about 40 GB).
DiskSize uint `mapstructure:"disk_size" required:"false"`
// The NIC type to be used for the network interfaces.
// When set to 82540EM, the NICs are Intel PRO/1000 MT Desktop (82540EM). This is the default.
// When set to 82543GC, the NICs are Intel PRO/1000 T Server (82543GC).
// When set to 82545EM, the NICs are Intel PRO/1000 MT Server (82545EM).
// When set to Am79C970A, the NICs are AMD PCNet-PCI II network card (Am79C970A).
// When set to Am79C973, the NICs are AMD PCNet-FAST III network card (Am79C973).
// When set to Am79C960, the NICs are AMD PCnet-ISA/NE2100 (Am79C960).
// When set to virtio, the NICs are VirtIO.
NICType string `mapstructure:"nic_type" required:"false"`
// The audio controller type to be used.
// When set to ac97, the audio controller is ICH AC97. This is the default.
// When set to hda, the audio controller is Intel HD Audio.
// When set to sb16, the audio controller is SoundBlaster 16.
AudioController string `mapstructure:"audio_controller" required:"false"`
// The graphics controller type to be used.
// When set to vboxvga, the graphics controller is VirtualBox VGA. This is the default.
// When set to vboxsvga, the graphics controller is VirtualBox SVGA.
// When set to vmsvga, the graphics controller is VMware SVGA.
// When set to none, the graphics controller is disabled.
GfxController string `mapstructure:"gfx_controller" required:"false"`
// The guest OS type being installed. By default this is other, but you can
// get dramatic performance improvements by setting this to the proper
// value. To view all available values for this run VBoxManage list
@@ -62,6 +90,7 @@ type Config struct {
// defaults to ide. When set to sata, the drive is attached to an AHCI SATA
// controller. When set to scsi, the drive is attached to an LsiLogic SCSI
// controller. When set to pcie, the drive is attached to an NVMe
// controller. When set to virtio, the drive is attached to a VirtIO
// controller. Please note that when you use "pcie", you'll need to have
// Virtualbox 6, install an [extension
// pack](https://www.virtualbox.org/wiki/Downloads#VirtualBox6.0.14OracleVMVirtualBoxExtensionPack)
@@ -98,6 +127,7 @@ type Config struct {
HardDriveNonrotational bool `mapstructure:"hard_drive_nonrotational" required:"false"`
// The type of controller that the ISO is attached to, defaults to ide.
// When set to sata, the drive is attached to an AHCI SATA controller.
// When set to virtio, the drive is attached to a VirtIO controller.
ISOInterface string `mapstructure:"iso_interface" required:"false"`
// Set this to true if you would like to keep the VM registered with
// virtualbox. Defaults to false.
@@ -160,6 +190,28 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
errs = packersdk.MultiErrorAppend(errs, b.config.BootConfig.Prepare(&b.config.ctx)...)
errs = packersdk.MultiErrorAppend(errs, b.config.GuestAdditionsConfig.Prepare(b.config.CommConfig.Comm.Type)...)
if b.config.Chipset == "" {
b.config.Chipset = "piix3"
}
switch b.config.Chipset {
case "piix3", "ich9":
// do nothing
default:
errs = packersdk.MultiErrorAppend(
errs, errors.New("chipset can only be piix3 or ich9"))
}
if b.config.Firmware == "" {
b.config.Firmware = "bios"
}
switch b.config.Firmware {
case "bios", "efi":
// do nothing
default:
errs = packersdk.MultiErrorAppend(
errs, errors.New("firmware can only be bios or efi"))
}
if b.config.DiskSize == 0 {
b.config.DiskSize = 40000
}
@@ -168,6 +220,39 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
b.config.HardDriveInterface = "ide"
}
if b.config.NICType == "" {
b.config.NICType = "82540EM"
}
switch b.config.NICType {
case "82540EM", "82543GC", "82545EM", "Am79C970A", "Am79C973", "Am79C960", "virtio":
// do nothing
default:
errs = packersdk.MultiErrorAppend(
errs, errors.New("NIC type can only be 82540EM, 82543GC, 82545EM, Am79C970A, Am79C973, Am79C960 or virtio"))
}
if b.config.GfxController == "" {
b.config.GfxController = "vboxvga"
}
switch b.config.GfxController {
case "vboxvga", "vboxsvga", "vmsvga", "none":
// do nothing
default:
errs = packersdk.MultiErrorAppend(
errs, errors.New("Graphics controller type can only be vboxvga, vboxsvga, vmsvga, none"))
}
if b.config.AudioController == "" {
b.config.AudioController = "ac97"
}
switch b.config.AudioController {
case "ac97", "hda", "sb16":
// do nothing
default:
errs = packersdk.MultiErrorAppend(
errs, errors.New("Audio controller type can only be ac97, hda or sb16"))
}
if b.config.GuestOSType == "" {
b.config.GuestOSType = "Other"
}
@@ -186,11 +271,11 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
}
switch b.config.HardDriveInterface {
case "ide", "sata", "scsi", "pcie":
case "ide", "sata", "scsi", "pcie", "virtio":
// do nothing
default:
errs = packersdk.MultiErrorAppend(
errs, errors.New("hard_drive_interface can only be ide, sata, pcie or scsi"))
errs, errors.New("hard_drive_interface can only be ide, sata, pcie, scsi or virtio"))
}
if b.config.SATAPortCount == 0 {
@@ -211,9 +296,9 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
errs, errors.New("nvme_port_count cannot be greater than 255"))
}
if b.config.ISOInterface != "ide" && b.config.ISOInterface != "sata" {
if b.config.ISOInterface != "ide" && b.config.ISOInterface != "sata" && b.config.ISOInterface != "virtio" {
errs = packersdk.MultiErrorAppend(
errs, errors.New("iso_interface can only be ide or sata"))
errs, errors.New("iso_interface can only be ide, sata or virtio"))
}
// Warnings
@@ -117,7 +117,12 @@ type FlatConfig struct {
GuestAdditionsPath *string `mapstructure:"guest_additions_path" cty:"guest_additions_path" hcl:"guest_additions_path"`
GuestAdditionsSHA256 *string `mapstructure:"guest_additions_sha256" cty:"guest_additions_sha256" hcl:"guest_additions_sha256"`
GuestAdditionsURL *string `mapstructure:"guest_additions_url" required:"false" cty:"guest_additions_url" hcl:"guest_additions_url"`
Chipset *string `mapstructure:"chipset" required:"false" cty:"chipset" hcl:"chipset"`
Firmware *string `mapstructure:"firmware" required:"false" cty:"firmware" hcl:"firmware"`
DiskSize *uint `mapstructure:"disk_size" required:"false" cty:"disk_size" hcl:"disk_size"`
NICType *string `mapstructure:"nic_type" required:"false" cty:"nic_type" hcl:"nic_type"`
AudioController *string `mapstructure:"audio_controller" required:"false" cty:"audio_controller" hcl:"audio_controller"`
GfxController *string `mapstructure:"gfx_controller" required:"false" cty:"gfx_controller" hcl:"gfx_controller"`
GuestOSType *string `mapstructure:"guest_os_type" required:"false" cty:"guest_os_type" hcl:"guest_os_type"`
HardDriveDiscard *bool `mapstructure:"hard_drive_discard" required:"false" cty:"hard_drive_discard" hcl:"hard_drive_discard"`
HardDriveInterface *string `mapstructure:"hard_drive_interface" required:"false" cty:"hard_drive_interface" hcl:"hard_drive_interface"`
@@ -249,7 +254,12 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"guest_additions_path": &hcldec.AttrSpec{Name: "guest_additions_path", Type: cty.String, Required: false},
"guest_additions_sha256": &hcldec.AttrSpec{Name: "guest_additions_sha256", Type: cty.String, Required: false},
"guest_additions_url": &hcldec.AttrSpec{Name: "guest_additions_url", Type: cty.String, Required: false},
"chipset": &hcldec.AttrSpec{Name: "chipset", Type: cty.String, Required: false},
"firmware": &hcldec.AttrSpec{Name: "firmware", Type: cty.String, Required: false},
"disk_size": &hcldec.AttrSpec{Name: "disk_size", Type: cty.Number, Required: false},
"nic_type": &hcldec.AttrSpec{Name: "nic_type", Type: cty.String, Required: false},
"audio_controller": &hcldec.AttrSpec{Name: "audio_controller", Type: cty.String, Required: false},
"gfx_controller": &hcldec.AttrSpec{Name: "gfx_controller", Type: cty.String, Required: false},
"guest_os_type": &hcldec.AttrSpec{Name: "guest_os_type", Type: cty.String, Required: false},
"hard_drive_discard": &hcldec.AttrSpec{Name: "hard_drive_discard", Type: cty.Bool, Required: false},
"hard_drive_interface": &hcldec.AttrSpec{Name: "hard_drive_interface", Type: cty.String, Required: false},
+16 -6
View File
@@ -66,6 +66,18 @@ func (s *stepCreateDisk) Run(ctx context.Context, state multistep.StateBag) mult
}
}
// Add a VirtIO controller if we were asked to use VirtIO. We still attach
// the VirtIO controller above because some other things (disks) require
// that.
if config.HardDriveInterface == "virtio" || config.ISOInterface == "virtio" {
if err := driver.CreateVirtIOController(vmName, "VirtIO Controller"); err != nil {
err := fmt.Errorf("Error creating disk controller: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
}
if config.HardDriveInterface == "scsi" {
if err := driver.CreateSCSIController(vmName, "SCSI Controller"); err != nil {
err := fmt.Errorf("Error creating disk controller: %s", err)
@@ -86,13 +98,11 @@ func (s *stepCreateDisk) Run(ctx context.Context, state multistep.StateBag) mult
controllerName := "IDE Controller"
if config.HardDriveInterface == "sata" {
controllerName = "SATA Controller"
}
if config.HardDriveInterface == "scsi" {
} else if config.HardDriveInterface == "scsi" {
controllerName = "SCSI Controller"
}
if config.HardDriveInterface == "pcie" {
} else if config.HardDriveInterface == "virtio" {
controllerName = "VirtIO Controller"
} else if config.HardDriveInterface == "pcie" {
controllerName = "NVMe Controller"
}
+19 -3
View File
@@ -26,7 +26,7 @@ func (s *stepCreateVM) Run(ctx context.Context, state multistep.StateBag) multis
name := config.VMName
commands := make([][]string, 6)
commands := make([][]string, 10)
commands[0] = []string{
"createvm", "--name", name,
"--ostype", config.GuestOSType, "--register",
@@ -40,11 +40,27 @@ func (s *stepCreateVM) Run(ctx context.Context, state multistep.StateBag) multis
commands[4] = []string{"modifyvm", name, "--usb", map[bool]string{true: "on", false: "off"}[config.HWConfig.USB]}
if strings.ToLower(config.HWConfig.Sound) == "none" {
commands[5] = []string{"modifyvm", name, "--audio", config.HWConfig.Sound}
commands[5] = []string{"modifyvm", name, "--audio", config.HWConfig.Sound,
"--audiocontroller", config.AudioController}
} else {
commands[5] = []string{"modifyvm", name, "--audio", config.HWConfig.Sound, "--audioin", "on", "--audioout", "on"}
commands[5] = []string{"modifyvm", name, "--audio", config.HWConfig.Sound, "--audioin", "on", "--audioout", "on",
"--audiocontroller", config.AudioController}
}
commands[6] = []string{"modifyvm", name, "--chipset", config.Chipset}
commands[7] = []string{"modifyvm", name, "--firmware", config.Firmware}
// Set the configured NIC type for all 8 possible NICs
commands[8] = []string{"modifyvm", name,
"--nictype1", config.NICType,
"--nictype2", config.NICType,
"--nictype3", config.NICType,
"--nictype4", config.NICType,
"--nictype5", config.NICType,
"--nictype6", config.NICType,
"--nictype7", config.NICType,
"--nictype8", config.NICType}
commands[9] = []string{"modifyvm", name, "--graphicscontroller", config.GfxController}
ui.Say("Creating virtual machine...")
for _, command := range commands {
err := driver.VBoxManage(command...)
+1 -1
View File
@@ -23,7 +23,7 @@ type Driver interface {
// Clone clones the VMX and the disk to the destination path. The
// destination is a path to the VMX file. The disk will be copied
// to that same directory.
Clone(dst string, src string, cloneType bool) error
Clone(dst string, src string, cloneType bool, snapshot string) error
// CompactDisk compacts a virtual disk.
CompactDisk(string) error
+1 -1
View File
@@ -112,7 +112,7 @@ func NewESX5Driver(dconfig *DriverConfig, config *SSHConfig, vmName string) (Dri
}, nil
}
func (d *ESX5Driver) Clone(dst, src string, linked bool) error {
func (d *ESX5Driver) Clone(dst, src string, linked bool, snapshot string) error {
linesToArray := func(lines string) []string { return strings.Split(strings.Trim(lines, "\r\n"), "\n") }
+1 -1
View File
@@ -31,7 +31,7 @@ func NewFusion5Driver(dconfig *DriverConfig, config *SSHConfig) Driver {
}
}
func (d *Fusion5Driver) Clone(dst, src string, linked bool) error {
func (d *Fusion5Driver) Clone(dst, src string, linked bool, snapshot string) error {
return errors.New("Cloning is not supported with Fusion 5. Please use Fusion 6+.")
}
+6 -5
View File
@@ -27,7 +27,7 @@ func NewFusion6Driver(dconfig *DriverConfig, config *SSHConfig) Driver {
}
}
func (d *Fusion6Driver) Clone(dst, src string, linked bool) error {
func (d *Fusion6Driver) Clone(dst, src string, linked bool, snapshot string) error {
var cloneType string
if linked {
@@ -36,10 +36,11 @@ func (d *Fusion6Driver) Clone(dst, src string, linked bool) error {
cloneType = "full"
}
cmd := exec.Command(d.vmrunPath(),
"-T", "fusion",
"clone", src, dst,
cloneType)
args := []string{"-T", "fusion", "clone", src, dst, cloneType}
if snapshot != "" {
args = append(args, "-snapshot", snapshot)
}
cmd := exec.Command(d.vmrunPath(), args...)
if _, _, err := runAndLog(cmd); err != nil {
if strings.Contains(err.Error(), "parameters was invalid") {
return fmt.Errorf(
+3 -1
View File
@@ -14,6 +14,7 @@ type DriverMock struct {
CloneDst string
CloneSrc string
Linked bool
Snapshot string
CloneErr error
CompactDiskCalled bool
@@ -113,11 +114,12 @@ func (m NetworkMapperMock) DeviceIntoName(device string) (string, error) {
return "", nil
}
func (d *DriverMock) Clone(dst string, src string, linked bool) error {
func (d *DriverMock) Clone(dst string, src string, linked bool, snapshot string) error {
d.CloneCalled = true
d.CloneDst = dst
d.CloneSrc = src
d.Linked = linked
d.Snapshot = snapshot
return d.CloneErr
}
+26 -6
View File
@@ -31,7 +31,7 @@ func NewPlayer5Driver(config *SSHConfig) Driver {
}
}
func (d *Player5Driver) Clone(dst, src string, linked bool) error {
func (d *Player5Driver) Clone(dst, src string, linked bool, snapshot string) error {
return errors.New("Cloning is not supported with VMWare Player version 5. Please use VMWare Player version 6, or greater.")
}
@@ -204,12 +204,32 @@ func (d *Player5Driver) Verify() error {
d.VmwareDriver.NetworkMapper = func() (NetworkNameMapper, error) {
pathNetmap := playerNetmapConfPath()
if _, err := os.Stat(pathNetmap); err != nil {
return nil, fmt.Errorf("Could not find netmap conf file: %s", pathNetmap)
}
log.Printf("Located networkmapper configuration file using Player: %s", pathNetmap)
return ReadNetmapConfig(pathNetmap)
// If we were able to find the file (no error), then we can proceed with reading
// the networkmapper configuration.
if _, err := os.Stat(pathNetmap); err == nil {
log.Printf("Located networkmapper configuration file using Player: %s", pathNetmap)
return ReadNetmapConfig(pathNetmap)
}
// If we weren't able to find the networkmapper configuration file, then fall back
// to the networking file which might also be in the configuration directory.
libpath, _ := playerVMwareRoot()
pathNetworking := filepath.Join(libpath, "networking")
if _, err := os.Stat(pathNetworking); err != nil {
return nil, fmt.Errorf("Could not determine network mappings from files in path: %s", libpath)
}
// We were able to successfully stat the file.. So, now we can open a handle to it.
log.Printf("Located networking configuration file using Player: %s", pathNetworking)
fd, err := os.Open(pathNetworking)
if err != nil {
return nil, err
}
defer fd.Close()
// Then we pass the handle to the networking configuration parser.
return ReadNetworkingConfig(fd)
}
return nil
}
+6 -6
View File
@@ -21,7 +21,7 @@ func NewPlayer6Driver(config *SSHConfig) Driver {
}
}
func (d *Player6Driver) Clone(dst, src string, linked bool) error {
func (d *Player6Driver) Clone(dst, src string, linked bool, snapshot string) error {
// TODO(rasa) check if running player+, not just player
var cloneType string
@@ -31,11 +31,11 @@ func (d *Player6Driver) Clone(dst, src string, linked bool) error {
cloneType = "full"
}
cmd := exec.Command(d.Player5Driver.VmrunPath,
"-T", "ws",
"clone", src, dst,
cloneType)
args := []string{"-T", "ws", "clone", src, dst, cloneType}
if snapshot != "" {
args = append(args, "-snapshot", snapshot)
}
cmd := exec.Command(d.Player5Driver.VmrunPath, args...)
if _, _, err := runAndLog(cmd); err != nil {
return err
}
@@ -21,7 +21,7 @@ func NewWorkstation10Driver(config *SSHConfig) Driver {
}
}
func (d *Workstation10Driver) Clone(dst, src string, linked bool) error {
func (d *Workstation10Driver) Clone(dst, src string, linked bool, snapshot string) error {
var cloneType string
if linked {
@@ -30,11 +30,11 @@ func (d *Workstation10Driver) Clone(dst, src string, linked bool) error {
cloneType = "full"
}
cmd := exec.Command(d.Workstation9Driver.VmrunPath,
"-T", "ws",
"clone", src, dst,
cloneType)
args := []string{"-T", "ws", "clone", src, dst, cloneType}
if snapshot != "" {
args = append(args, "-snapshot", snapshot)
}
cmd := exec.Command(d.Workstation9Driver.VmrunPath, args...)
if _, _, err := runAndLog(cmd); err != nil {
return err
}
+26 -6
View File
@@ -30,7 +30,7 @@ func NewWorkstation9Driver(config *SSHConfig) Driver {
}
}
func (d *Workstation9Driver) Clone(dst, src string, linked bool) error {
func (d *Workstation9Driver) Clone(dst, src string, linked bool, snapshot string) error {
return errors.New("Cloning is not supported with VMware WS version 9. Please use VMware WS version 10, or greater.")
}
@@ -165,12 +165,32 @@ func (d *Workstation9Driver) Verify() error {
d.VmwareDriver.NetworkMapper = func() (NetworkNameMapper, error) {
pathNetmap := workstationNetmapConfPath()
if _, err := os.Stat(pathNetmap); err != nil {
return nil, fmt.Errorf("Could not find netmap conf file: %s", pathNetmap)
}
log.Printf("Located networkmapper configuration file using Workstation: %s", pathNetmap)
return ReadNetmapConfig(pathNetmap)
// Check that the file for the networkmapper configuration exists. If there's no
// error, then the file exists and we can proceed to read the configuration out of it.
if _, err := os.Stat(pathNetmap); err == nil {
log.Printf("Located networkmapper configuration file using Workstation: %s", pathNetmap)
return ReadNetmapConfig(pathNetmap)
}
// If we weren't able to find the networkmapper configuration file, then fall back
// to the networking file which might also be in the configuration directory.
libpath, _ := workstationVMwareRoot()
pathNetworking := filepath.Join(libpath, "networking")
if _, err := os.Stat(pathNetworking); err != nil {
return nil, fmt.Errorf("Could not determine network mappings from files in path: %s", libpath)
}
// We were able to successfully stat the file.. So, now we can open a handle to it.
log.Printf("Located networking configuration file using Workstation: %s", pathNetworking)
fd, err := os.Open(pathNetworking)
if err != nil {
return nil, err
}
defer fd.Close()
// Then we pass the handle to the networking configuration parser.
return ReadNetworkingConfig(fd)
}
return nil
}
+1
View File
@@ -97,6 +97,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
OutputDir: &b.config.OutputDir,
VMName: b.config.VMName,
Linked: b.config.Linked,
Snapshot: b.config.AttachSnapshot,
},
&vmwcommon.StepConfigureVMX{
CustomData: b.config.VMXData,
+5
View File
@@ -47,6 +47,11 @@ type Config struct {
// scenarios. Most users will wish to create a full clone instead. Defaults
// to false.
Linked bool `mapstructure:"linked" required:"false"`
// Default to `null/empty`. The name of an
// **existing** snapshot to which the builder shall attach the VM before
// starting it. If no snapshot is specified the builder will simply start the
// VM from it's current state i.e. snapshot.
AttachSnapshot string `mapstructure:"attach_snapshot" required:"false"`
// Path to the source VMX file to clone. If
// remote_type is enabled then this specifies a path on the remote_host.
SourcePath string `mapstructure:"source_path" required:"true"`
+2
View File
@@ -123,6 +123,7 @@ type FlatConfig struct {
DiskName *string `mapstructure:"vmdk_name" required:"false" cty:"vmdk_name" hcl:"vmdk_name"`
DiskTypeId *string `mapstructure:"disk_type_id" required:"false" cty:"disk_type_id" hcl:"disk_type_id"`
Linked *bool `mapstructure:"linked" required:"false" cty:"linked" hcl:"linked"`
AttachSnapshot *string `mapstructure:"attach_snapshot" required:"false" cty:"attach_snapshot" hcl:"attach_snapshot"`
SourcePath *string `mapstructure:"source_path" required:"true" cty:"source_path" hcl:"source_path"`
VMName *string `mapstructure:"vm_name" required:"false" cty:"vm_name" hcl:"vm_name"`
}
@@ -252,6 +253,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"vmdk_name": &hcldec.AttrSpec{Name: "vmdk_name", Type: cty.String, Required: false},
"disk_type_id": &hcldec.AttrSpec{Name: "disk_type_id", Type: cty.String, Required: false},
"linked": &hcldec.AttrSpec{Name: "linked", Type: cty.Bool, Required: false},
"attach_snapshot": &hcldec.AttrSpec{Name: "attach_snapshot", Type: cty.String, Required: false},
"source_path": &hcldec.AttrSpec{Name: "source_path", Type: cty.String, Required: false},
"vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false},
}
+2 -1
View File
@@ -20,6 +20,7 @@ type StepCloneVMX struct {
Path string
VMName string
Linked bool
Snapshot string
tempDir string
}
@@ -38,7 +39,7 @@ func (s *StepCloneVMX) Run(ctx context.Context, state multistep.StateBag) multis
log.Printf("Cloning from: %s", s.Path)
log.Printf("Cloning to: %s", vmxPath)
if err := driver.Clone(vmxPath, s.Path, s.Linked); err != nil {
if err := driver.Clone(vmxPath, s.Path, s.Linked, s.Snapshot); err != nil {
return halt(err)
}
+3 -3
View File
@@ -5,7 +5,7 @@ package common
import (
"fmt"
"os"
"io/fs"
"path/filepath"
"github.com/hashicorp/packer-plugin-sdk/common"
@@ -27,7 +27,7 @@ type OutputConfig struct {
// leading zero such as "0755" in JSON file, because JSON does not support
// octal value. In Unix-like OS, the actual permission may differ from
// this value because of umask.
DirPerm os.FileMode `mapstructure:"directory_permission" required:"false"`
DirPerm fs.FileMode `mapstructure:"directory_permission" required:"false"`
}
func (c *OutputConfig) Prepare(ctx *interpolate.Context, pc *common.PackerConfig) []error {
@@ -45,7 +45,7 @@ func (c *OutputConfig) Prepare(ctx *interpolate.Context, pc *common.PackerConfig
func (c *OutputConfig) ListFiles() ([]string, error) {
files := make([]string, 0, 10)
visit := func(path string, info os.FileInfo, err error) error {
visit := func(path string, info fs.FileInfo, err error) error {
if err != nil {
return err
}
@@ -3,7 +3,7 @@
package common
import (
"os"
"io/fs"
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/zclconf/go-cty/cty"
@@ -13,7 +13,7 @@ import (
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatOutputConfig struct {
OutputDir *string `mapstructure:"output_directory" required:"false" cty:"output_directory" hcl:"output_directory"`
DirPerm *os.FileMode `mapstructure:"directory_permission" required:"false" cty:"directory_permission" hcl:"directory_permission"`
DirPerm *fs.FileMode `mapstructure:"directory_permission" required:"false" cty:"directory_permission" hcl:"directory_permission"`
}
// FlatMapstructure returns a new FlatOutputConfig.
@@ -3,7 +3,7 @@
package common
import (
"os"
"io/fs"
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/zclconf/go-cty/cty"
@@ -17,7 +17,7 @@ type FlatExportConfig struct {
Images *bool `mapstructure:"images" cty:"images" hcl:"images"`
Manifest *string `mapstructure:"manifest" cty:"manifest" hcl:"manifest"`
OutputDir *string `mapstructure:"output_directory" required:"false" cty:"output_directory" hcl:"output_directory"`
DirPerm *os.FileMode `mapstructure:"directory_permission" required:"false" cty:"directory_permission" hcl:"directory_permission"`
DirPerm *fs.FileMode `mapstructure:"directory_permission" required:"false" cty:"directory_permission" hcl:"directory_permission"`
Options []string `mapstructure:"options" cty:"options" hcl:"options"`
}
+1 -1
View File
@@ -109,7 +109,7 @@ func checkPluginName(name string) error {
strings.HasPrefix(name, "packer-post-processor-") {
fmt.Printf("\n[WARNING] Plugin is named with old prefix `packer-[builder|provisioner|post-processor]-{name})`. " +
"These will be detected but Packer cannot install them automatically. " +
"The plugin must be a multi-plugin named packer-plugin-{name} to be installable through the `packer init` command.\n")
"The plugin must be a multi-component plugin named packer-plugin-{name} to be installable through the `packer init` command.\n")
return nil
}
return fmt.Errorf("plugin's name is not valid")
+5 -1
View File
@@ -126,7 +126,11 @@ func (m *Meta) GetConfigFromJSON(cla *MetaArgs) (packer.Handler, int) {
}
if err != nil {
m.Ui.Error(fmt.Sprintf("Failed to parse template: %s", err))
m.Ui.Error(fmt.Sprintf("Failed to parse file as legacy JSON template: "+
"if you are using an HCL template, check your file extensions; they "+
"should be either *.pkr.hcl or *.pkr.json; see the docs for more "+
"details: https://www.packer.io/docs/templates/hcl_templates. \n"+
"Original error: %s", err))
return nil, 1
}
+3 -1
View File
@@ -145,6 +145,7 @@ type InspectArgs struct {
func (va *HCL2UpgradeArgs) AddFlagSets(flags *flag.FlagSet) {
flags.StringVar(&va.OutputFile, "output-file", "", "File where to put the hcl2 generated config. Defaults to JSON_TEMPLATE.pkr.hcl")
flags.BoolVar(&va.WithAnnotations, "with-annotations", false, "Adds helper annotations with information about the generated HCL2 blocks.")
va.MetaArgs.AddFlagSets(flags)
}
@@ -152,7 +153,8 @@ func (va *HCL2UpgradeArgs) AddFlagSets(flags *flag.FlagSet) {
// HCL2UpgradeArgs represents a parsed cli line for a `packer hcl2_upgrade`
type HCL2UpgradeArgs struct {
MetaArgs
OutputFile string
OutputFile string
WithAnnotations bool
}
func (va *FormatArgs) AddFlagSets(flags *flag.FlagSet) {
+7
View File
@@ -0,0 +1,7 @@
// +build darwin freebsd linux netbsd openbsd solaris
package command
const (
defaultConfigDir = ".packer.d"
)
+7
View File
@@ -0,0 +1,7 @@
// +build windows
package command
const (
defaultConfigDir = "packer.d"
)
+772 -216
View File
File diff suppressed because it is too large Load Diff
+17 -4
View File
@@ -18,16 +18,29 @@ func Test_hcl2_upgrade(t *testing.T) {
tc := []struct {
folder string
flags []string
}{
{"hcl2_upgrade_basic"},
{folder: "complete", flags: []string{"-with-annotations"}},
{folder: "without-annotations", flags: []string{}},
{folder: "minimal", flags: []string{"-with-annotations"}},
{folder: "source-name", flags: []string{"-with-annotations"}},
{folder: "error-cleanup-provisioner", flags: []string{"-with-annotations"}},
{folder: "aws-access-config", flags: []string{}},
{folder: "variables-only", flags: []string{}},
{folder: "variables-with-variables", flags: []string{}},
}
for _, tc := range tc {
t.Run(tc.folder, func(t *testing.T) {
inputPath := filepath.Join(testFixture(tc.folder, "input.json"))
inputPath := filepath.Join(testFixture("hcl2_upgrade", tc.folder, "input.json"))
outputPath := inputPath + ".pkr.hcl"
expectedPath := filepath.Join(testFixture(tc.folder, "expected.pkr.hcl"))
p := helperCommand(t, "hcl2_upgrade", inputPath)
expectedPath := filepath.Join(testFixture("hcl2_upgrade", tc.folder, "expected.pkr.hcl"))
args := []string{"hcl2_upgrade"}
if len(tc.flags) > 0 {
args = append(args, tc.flags...)
}
args = append(args, inputPath)
p := helperCommand(t, args...)
bs, err := p.CombinedOutput()
if err != nil {
t.Fatalf("%v %s", err, bs)
+2 -2
View File
@@ -109,7 +109,7 @@ func (c *InitCommand) RunContext(buildCtx context.Context, cla *InitArgs) int {
return 1
}
log.Printf("[TRACE] for plugin %s found %d matching installation(s)", pluginRequirement.Identifier.ForDisplay(), len(installs))
log.Printf("[TRACE] for plugin %s found %d matching installation(s)", pluginRequirement.Identifier, len(installs))
if len(installs) > 0 && cla.Upgrade == false {
continue
@@ -125,7 +125,7 @@ func (c *InitCommand) RunContext(buildCtx context.Context, cla *InitArgs) int {
ret = 1
}
if newInstall != nil {
msg := fmt.Sprintf("Installed plugin %s %s in %q", pluginRequirement.Identifier.ForDisplay(), newInstall.Version, newInstall.BinaryPath)
msg := fmt.Sprintf("Installed plugin %s %s in %q", pluginRequirement.Identifier, newInstall.Version, newInstall.BinaryPath)
ui.Say(msg)
}
}
+272 -73
View File
@@ -1,7 +1,8 @@
package command
import (
"io/ioutil"
"context"
"fmt"
"log"
"os"
"path/filepath"
@@ -10,39 +11,60 @@ import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/go-getter/v2"
"github.com/hashicorp/packer-plugin-sdk/acctest"
"golang.org/x/mod/sumdb/dirhash"
)
type testCaseInit struct {
name string
setup []func(*testing.T, testCaseInit)
Meta Meta
inPluginFolder map[string]string
expectedPackerConfigDirHashBeforeInit string
inConfigFolder map[string]string
packerConfigDir string
packerUserFolder string
want int
dirFiles []string
expectedPackerConfigDirHashAfterInit string
moreTests []func(*testing.T, testCaseInit)
}
type testBuild struct {
want int
}
func (tb testBuild) fn(t *testing.T, tc testCaseInit) {
bc := BuildCommand{
Meta: tc.Meta,
}
args := []string{tc.packerUserFolder}
want := tb.want
if got := bc.Run(args); got != want {
t.Errorf("BuildCommand.Run() = %v, want %v", got, want)
}
}
func TestInitCommand_Run(t *testing.T) {
// These tests will try to optimise for doing the least amount of github api
// requests whilst testing the max amount of things at once. Hopefully they
// don't require a GH token just yet. Acc tests are run on linux, darwin and
// windows, so requests are done 3 times.
type testCase struct {
checkSkip func(*testing.T)
name string
inPluginFolder map[string]string
expectedPackerConfigDirHashBeforeInit string
hclFile string
packerConfigDir string
want int
dirFiles []string
expectedPackerConfigDirHashAfterInit string
}
cfg := &configDirSingleton{map[string]string{}}
tests := []testCase{
tests := []testCaseInit{
{
nil,
// here we pre-write plugins with valid checksums, Packer will
// see those as valid installations it did.
// the directory hash before and after init should be the same,
// that's a no-op. This also should do no GH query, so it is best
// to always run it.
"already-installed-no-op",
nil,
testMetaFile(t),
map[string]string{
"github.com/sylviamoss/comment/packer-plugin-comment_v0.2.18_x5.0_darwin_amd64": "1",
"github.com/sylviamoss/comment/packer-plugin-comment_v0.2.18_x5.0_darwin_amd64_SHA256SUM": "6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b",
@@ -52,30 +74,37 @@ func TestInitCommand_Run(t *testing.T) {
"github.com/sylviamoss/comment/packer-plugin-comment_v0.2.18_x5.0_linux_amd64_SHA256SUM": "59031c50e0dfeedfde2b4e9445754804dce3f29e4efa737eead0ca9b4f5b85a5",
},
"h1:Q5qyAOdD43hL3CquQdVfaHpOYGf0UsZ/+wVA9Ry6cbA=",
`# cfg.pkr.hcl
packer {
required_plugins {
comment = {
source = "github.com/sylviamoss/comment"
version = "v0.2.018"
}
}
}`,
cfg.dir("1"),
map[string]string{
`cfg.pkr.hcl`: `
packer {
required_plugins {
comment = {
source = "github.com/sylviamoss/comment"
version = "v0.2.018"
}
}
}`,
},
cfg.dir("1_pkr_config"),
cfg.dir("1_pkr_user_folder"),
0,
nil,
"h1:Q5qyAOdD43hL3CquQdVfaHpOYGf0UsZ/+wVA9Ry6cbA=",
[]func(t *testing.T, tc testCaseInit){
// test that a build will not work since plugins are broken for
// this tests (they are not binaries).
testBuild{want: 1}.fn,
},
},
{
func(t *testing.T) {
if os.Getenv(acctest.TestEnvVar) == "" {
t.Skipf("Acceptance test skipped unless env '%s' set", acctest.TestEnvVar)
}
},
// here we pre-write plugins with valid checksums, Packer will
// see those as valid installations it did.
// But because we require version 0.2.19, we will upgrade.
"already-installed-upgrade",
[]func(t *testing.T, tc testCaseInit){
skipInitTestUnlessEnVar(acctest.TestEnvVar).fn,
},
testMetaFile(t),
map[string]string{
"github.com/sylviamoss/comment/packer-plugin-comment_v0.2.18_x5.0_darwin_amd64": "1",
"github.com/sylviamoss/comment/packer-plugin-comment_v0.2.18_x5.0_darwin_amd64_SHA256SUM": "6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b",
@@ -85,16 +114,34 @@ func TestInitCommand_Run(t *testing.T) {
"github.com/sylviamoss/comment/packer-plugin-comment_v0.2.18_x5.0_linux_amd64_SHA256SUM": "59031c50e0dfeedfde2b4e9445754804dce3f29e4efa737eead0ca9b4f5b85a5",
},
"h1:Q5qyAOdD43hL3CquQdVfaHpOYGf0UsZ/+wVA9Ry6cbA=",
`# cfg.pkr.hcl
packer {
required_plugins {
comment = {
source = "github.com/sylviamoss/comment"
version = "v0.2.019"
map[string]string{
`cfg.pkr.hcl`: `
packer {
required_plugins {
comment = {
source = "github.com/sylviamoss/comment"
version = "v0.2.019"
}
}
}`,
`source.pkr.hcl`: `
source "null" "test" {
communicator = "none"
}
`,
`build.pkr.hcl`: `
build {
sources = ["source.null.test"]
provisioner "comment" {
comment = "Begin ¡"
ui = true
bubble_text = true
}
}
}`,
cfg.dir("2"),
`,
},
cfg.dir("2_pkr_config"),
cfg.dir("2_pkr_user_folder"),
0,
[]string{
"github.com/sylviamoss/comment/packer-plugin-comment_v0.2.18_x5.0_darwin_amd64",
@@ -119,68 +166,194 @@ func TestInitCommand_Run(t *testing.T) {
"linux": "h1:CGym0+Nd0LEANgzqL0wx/LDjRL8bYwlpZ0HajPJo/hs=",
"windows": "h1:ag0/C1YjP7KoEDYOiJHE0K+lhFgs0tVgjriWCXVT1fg=",
}[runtime.GOOS],
[]func(t *testing.T, tc testCaseInit){
// test that a build will work as the plugin was just installed
testBuild{want: 0}.fn,
},
},
{
func(t *testing.T) {
if os.Getenv(acctest.TestEnvVar) == "" {
t.Skipf("Acceptance test skipped unless env '%s' set", acctest.TestEnvVar)
}
},
"release-with-no-binary",
[]func(t *testing.T, tc testCaseInit){
skipInitTestUnlessEnVar(acctest.TestEnvVar).fn,
},
testMetaFile(t),
nil,
"h1:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
`# cfg.pkr.hcl
packer {
required_plugins {
comment = {
source = "github.com/sylviamoss/comment"
version = "v0.2.20"
}
}
}`,
cfg.dir("3"),
map[string]string{
`cfg.pkr.hcl`: `
packer {
required_plugins {
comment = {
source = "github.com/sylviamoss/comment"
version = "v0.2.20"
}
}
}`,
},
cfg.dir("3_pkr_config"),
cfg.dir("3_pkr_user_folder"),
1,
nil,
"h1:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
nil,
},
{
"manually-installed-single-component-plugin-works",
[]func(t *testing.T, tc testCaseInit){
skipInitTestUnlessEnVar(acctest.TestEnvVar).fn,
initTestGoGetPlugin{
Src: "https://github.com/azr/packer-provisioner-comment/releases/download/v1.0.0/" +
"packer-provisioner-comment_v1.0.0_" + runtime.GOOS + "_" + runtime.GOARCH + ".zip",
Dst: filepath.Join(cfg.dir("4_pkr_config"), defaultConfigDir, "plugins"),
}.fn,
},
testMetaFile(t),
nil,
map[string]string{
"darwin": "h1:nVebbXToeehPUASRbvV9M4qaA9+UgoR5AMp7LjTrSBk=",
"linux": "h1:/U5vdeMtOpRKNu0ld8+qf4t6WC+BsfCQ6JRo9Dh/khI=",
"windows": "h1:0nkdNCjtTHTgBNkzVKG++/VYmWAvq/o236GGTxrIf/Q=",
}[runtime.GOOS],
map[string]string{
`source.pkr.hcl`: `
source "null" "test" {
communicator = "none"
}
`,
`build.pkr.hcl`: `
build {
sources = ["source.null.test"]
provisioner "comment" {
comment = "Begin ¡"
ui = true
bubble_text = true
}
}
`,
},
cfg.dir("4_pkr_config"),
cfg.dir("4_pkr_user_folder"),
0,
nil,
map[string]string{
"darwin": "h1:nVebbXToeehPUASRbvV9M4qaA9+UgoR5AMp7LjTrSBk=",
"linux": "h1:/U5vdeMtOpRKNu0ld8+qf4t6WC+BsfCQ6JRo9Dh/khI=",
"windows": "h1:0nkdNCjtTHTgBNkzVKG++/VYmWAvq/o236GGTxrIf/Q=",
}[runtime.GOOS],
[]func(*testing.T, testCaseInit){
testBuild{want: 0}.fn,
},
},
{
"manually-installed-single-component-plugin-old-api-fails",
[]func(t *testing.T, tc testCaseInit){
skipInitTestUnlessEnVar(acctest.TestEnvVar).fn,
initTestGoGetPlugin{
Src: "https://github.com/azr/packer-provisioner-comment/releases/download/v0.0.0/" +
"packer-provisioner-comment_v0.0.0_" + runtime.GOOS + "_" + runtime.GOARCH + ".zip",
Dst: filepath.Join(cfg.dir("5_pkr_config"), defaultConfigDir, "plugins"),
}.fn,
},
testMetaFile(t),
nil,
map[string]string{
"darwin": "h1:gW4gzpDXeu3cDrXgHJj9iWAN7Pyak626Gq8Bu2LG1kY=",
"linux": "h1:wQ2H5+J7VXwQzqR9DgpWtjhw9OVEFbcKQL6dgm/+zwo=",
"windows": "h1:BqRdW3c5H1PZ2Q4DOaKWja21v3nDlY5Nn8kqahhHGSw=",
}[runtime.GOOS],
map[string]string{
`source.pkr.hcl`: `
source "null" "test" {
communicator = "none"
}
`,
`build.pkr.hcl`: `
build {
sources = ["source.null.test"]
provisioner "comment" {
comment = "Begin ¡"
ui = true
bubble_text = true
}
}
`,
},
cfg.dir("5_pkr_config"),
cfg.dir("5_pkr_user_folder"),
0,
nil,
map[string]string{
"darwin": "h1:gW4gzpDXeu3cDrXgHJj9iWAN7Pyak626Gq8Bu2LG1kY=",
"linux": "h1:wQ2H5+J7VXwQzqR9DgpWtjhw9OVEFbcKQL6dgm/+zwo=",
"windows": "h1:BqRdW3c5H1PZ2Q4DOaKWja21v3nDlY5Nn8kqahhHGSw=",
}[runtime.GOOS],
[]func(*testing.T, testCaseInit){
testBuild{want: 1}.fn,
},
},
{
"unsupported-non-github-source-address",
[]func(t *testing.T, tc testCaseInit){
skipInitTestUnlessEnVar(acctest.TestEnvVar).fn,
},
testMetaFile(t),
nil,
"h1:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
map[string]string{
`cfg.pkr.hcl`: `
packer {
required_plugins {
comment = {
source = "example.com/sylviamoss/comment"
version = "v0.2.19"
}
}
}`,
},
cfg.dir("6_pkr_config"),
cfg.dir("6_pkr_user_folder"),
1,
nil,
"h1:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.checkSkip != nil {
tt.checkSkip(t)
log.Printf("starting %s", tt.name)
log.Printf("%#v", tt)
t.Cleanup(func() {
_ = os.RemoveAll(tt.packerConfigDir)
})
t.Cleanup(func() {
_ = os.RemoveAll(tt.packerUserFolder)
})
os.Setenv("PACKER_CONFIG_DIR", tt.packerConfigDir)
for _, init := range tt.setup {
init(t, tt)
if t.Skipped() {
return
}
}
log.Printf("starting %s", tt.name)
createFiles(tt.packerConfigDir, tt.inPluginFolder)
t.Cleanup(func() {
_ = os.RemoveAll(tt.packerConfigDir)
})
createFiles(tt.packerUserFolder, tt.inConfigFolder)
hash, err := dirhash.HashDir(tt.packerConfigDir, "", dirhash.DefaultHash)
if err != nil {
t.Fatalf("HashDir: %v", err)
}
if diff := cmp.Diff(tt.expectedPackerConfigDirHashBeforeInit, hash); diff != "" {
t.Errorf("unexpected dir hash before init: %s", diff)
t.Errorf("unexpected dir hash before init: +found -expected %s", diff)
}
cfgDir, err := ioutil.TempDir("", "pkr-test-init-file-folder")
if err != nil {
t.Fatalf("TempDir: %v", err)
}
if err := ioutil.WriteFile(filepath.Join(cfgDir, "cfg.pkr.hcl"), []byte(tt.hclFile), 0666); err != nil {
t.Fatalf("WriteFile: %v", err)
}
t.Cleanup(func() {
_ = os.RemoveAll(cfgDir)
})
args := []string{cfgDir}
args := []string{tt.packerUserFolder}
c := &InitCommand{
Meta: testMetaFile(t),
Meta: tt.Meta,
}
if err := c.CoreConfig.Components.PluginConfig.Discover(); err != nil {
t.Fatalf("Failed to discover plugins: %s", err)
}
c.CoreConfig.Components.PluginConfig.KnownPluginFolders = []string{tt.packerConfigDir}
@@ -207,6 +380,32 @@ func TestInitCommand_Run(t *testing.T) {
if diff := cmp.Diff(tt.expectedPackerConfigDirHashAfterInit, hash); diff != "" {
t.Errorf("unexpected dir hash after init: %s", diff)
}
for i, subTest := range tt.moreTests {
t.Run(fmt.Sprintf("-subtest-%d", i), func(t *testing.T) {
subTest(t, tt)
})
}
})
}
}
type skipInitTestUnlessEnVar string
func (key skipInitTestUnlessEnVar) fn(t *testing.T, tc testCaseInit) {
// always run acc tests for now
// if os.Getenv(string(key)) == "" {
// t.Skipf("Acceptance test skipped unless env '%s' set", key)
// }
}
type initTestGoGetPlugin struct {
Src string
Dst string
}
func (opts initTestGoGetPlugin) fn(t *testing.T, _ testCaseInit) {
if _, err := getter.Get(context.Background(), opts.Dst, opts.Src); err != nil {
t.Fatalf("get: %v", err)
}
}
@@ -0,0 +1,72 @@
packer {
required_version = ">= 1.6.0"
}
variable "aws_access_key" {
type = string
default = ""
sensitive = true
}
variable "aws_region" {
type = string
}
variable "aws_secret_key" {
type = string
default = ""
sensitive = true
}
data "amazon-ami" "autogenerated_1" {
access_key = "NJDBFASJDbsajhbda5487"
filters = {
name = "ubuntu/images/*/ubuntu-xenial-16.04-amd64-server-*"
root-device-type = "ebs"
virtualization-type = "hvm"
}
most_recent = true
owners = ["099720109477"]
region = "us-west-2"
secret_key = "ASEfewdsfAWASTT51874"
}
data "amazon-ami" "autogenerated_2" {
access_key = "${var.aws_access_key}"
filters = {
name = "ubuntu/images/*/ubuntu-xenial-16.04-amd64-server-*"
root-device-type = "ebs"
virtualization-type = "hvm"
}
most_recent = true
owners = ["099720109477"]
region = "${var.aws_region}"
secret_key = "${var.aws_secret_key}"
}
locals { timestamp = regex_replace(timestamp(), "[- TZ:]", "") }
source "amazon-ebs" "autogenerated_1" {
access_key = "NJDBFASJDbsajhbda5487"
ami_name = "ubuntu-16-04-test-${local.timestamp}"
region = "us-west-2"
secret_key = "ASEfewdsfAWASTT51874"
source_ami = "${data.amazon-ami.autogenerated_1.id}"
ssh_interface = "session_manager"
ssh_username = "ubuntu"
}
source "amazon-ebs" "named_builder" {
access_key = "${var.aws_access_key}"
ami_name = "ubuntu-16-04-test-${local.timestamp}"
region = "${var.aws_region}"
secret_key = "${var.aws_secret_key}"
source_ami = "${data.amazon-ami.autogenerated_2.id}"
ssh_interface = "session_manager"
ssh_username = "ubuntu"
}
build {
sources = ["source.amazon-ebs.autogenerated_1", "source.amazon-ebs.named_builder"]
}
@@ -0,0 +1,55 @@
{
"min_packer_version": "1.6.0",
"variables": {
"aws_region": null,
"aws_secret_key": "",
"aws_access_key": ""
},
"sensitive-variables": [
"aws_secret_key",
"aws_access_key"
],
"builders": [
{
"type": "amazon-ebs",
"region": "us-west-2",
"secret_key": "ASEfewdsfAWASTT51874",
"access_key": "NJDBFASJDbsajhbda5487",
"ami_name": "ubuntu-16-04-test-{{ timestamp }}",
"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
},
"ssh_username": "ubuntu",
"ssh_interface": "session_manager"
},
{
"type": "amazon-ebs",
"name": "named_builder",
"region": "{{ user `aws_region` }}",
"secret_key": "{{ user `aws_secret_key` }}",
"access_key": "{{ user `aws_access_key` }}",
"ami_name": "ubuntu-16-04-test-{{ timestamp }}",
"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
},
"ssh_username": "ubuntu",
"ssh_interface": "session_manager"
}
]
}
@@ -47,14 +47,38 @@ variable "secret_account" {
sensitive = true
}
# "timestamp" template function replacement
locals { timestamp = regex_replace(timestamp(), "[- TZ:]", "") }
# The amazon-secretsmanager data block is generated from your aws_secretsmanager template function; a data
# from this block can be referenced in source and locals blocks.
# Read the documentation for data blocks here:
# https://www.packer.io/docs/templates/hcl_templates/blocks/data
# Read the documentation for the Amazon Secrets Manager Data Source here:
# https://www.packer.io/docs/datasources/amazon/secretsmanager
data "amazon-secretsmanager" "autogenerated_1" {
name = "sample/app/password"
}
data "amazon-secretsmanager" "autogenerated_2" {
key = "api_key"
name = "sample/app/passwords"
}
data "amazon-secretsmanager" "autogenerated_3" {
name = "some_secret"
}
data "amazon-secretsmanager" "autogenerated_4" {
key = "with_key"
name = "some_secret"
}
# The amazon-ami data block is generated from your amazon builder source_ami_filter; a data
# from this block can be referenced in source and locals blocks.
# Read the documentation for data blocks here:
# https://www.packer.io/docs/templates/hcl_templates/blocks/data
# Read the documentation for the Amazon AMI Data Source here:
# https://www.packer.io/docs/datasources/amazon/ami
data "amazon-ami" "autogenerated_1" {
access_key = "${var.aws_access_key}"
filters = {
name = "ubuntu/images/*/ubuntu-xenial-16.04-amd64-server-*"
root-device-type = "ebs"
@@ -62,6 +86,24 @@ data "amazon-ami" "autogenerated_1" {
}
most_recent = true
owners = ["099720109477"]
region = "${var.aws_region}"
secret_key = "${var.aws_secret_key}"
}
# "timestamp" template function replacement
locals { timestamp = regex_replace(timestamp(), "[- TZ:]", "") }
# All locals variables are generated from variables that uses expressions
# that are not allowed in HCL2 variables.
# Read the documentation for locals blocks here:
# https://www.packer.io/docs/templates/hcl_templates/blocks/locals
local "password" {
sensitive = true
expression = "${data.amazon-secretsmanager.autogenerated_1.value}"
}
locals {
password_key = "MY_KEY_${data.amazon-secretsmanager.autogenerated_2.value}"
}
# source blocks are generated from your builders; a source can be referenced in
@@ -136,6 +178,15 @@ build {
max_retries = "5"
}
provisioner "shell" {
inline = ["echo ${local.password}", "echo ${data.amazon-secretsmanager.autogenerated_1.value}", "echo ${local.password_key}", "echo ${data.amazon-secretsmanager.autogenerated_2.value}"]
}
provisioner "shell" {
inline = ["echo ${data.amazon-secretsmanager.autogenerated_3.value}", "echo ${data.amazon-secretsmanager.autogenerated_4.value}"]
}
# template: hcl2_upgrade:2:38: executing "hcl2_upgrade" at <clean_resource_name>: error calling clean_resource_name: unhandled "clean_resource_name" call:
# there is no way to automatically upgrade the "clean_resource_name" call.
# Please manually upgrade to use custom validation rules, `replace(string, substring, replacement)` or `regex_replace(string, substring, replacement)`
@@ -144,6 +195,7 @@ build {
inline = ["echo mybuild-{{isotime | clean_resource_name}}"]
}
# template: hcl2_upgrade:2:35: executing "hcl2_upgrade" at <lower>: error calling lower: unhandled "lower" call:
# there is no way to automatically upgrade the "lower" call.
# Please manually upgrade to `lower(var.example)`
@@ -152,6 +204,7 @@ build {
inline = ["echo {{ `SOMETHING` | lower }}"]
}
# template: hcl2_upgrade:2:35: executing "hcl2_upgrade" at <upper>: error calling upper: unhandled "upper" call:
# there is no way to automatically upgrade the "upper" call.
# Please manually upgrade to `upper(var.example)`
@@ -160,6 +213,7 @@ build {
inline = ["echo {{ `something` | upper }}"]
}
# template: hcl2_upgrade:2:21: executing "hcl2_upgrade" at <split `some-string` `-` 0>: error calling split: unhandled "split" call:
# there is no way to automatically upgrade the "split" call.
# Please manually upgrade to `split(separator, string)`
@@ -168,6 +222,7 @@ build {
inline = ["echo {{ split `some-string` `-` 0 }}"]
}
# template: hcl2_upgrade:2:21: executing "hcl2_upgrade" at <replace_all `-` `/` build_name>: error calling replace_all: unhandled "replace_all" call:
# there is no way to automatically upgrade the "replace_all" call.
# Please manually upgrade to `replace(string, substring, replacement)` or `regex_replace(string, substring, replacement)`
@@ -176,6 +231,7 @@ build {
inline = ["echo {{ replace_all `-` `/` build_name }}"]
}
# template: hcl2_upgrade:2:21: executing "hcl2_upgrade" at <replace `some-string` `-` `/` 1>: error calling replace: unhandled "replace" call:
# there is no way to automatically upgrade the "replace" call.
# Please manually upgrade to `replace(string, substring, replacement)` or `regex_replace(string, substring, replacement)`
@@ -183,11 +239,14 @@ build {
provisioner "shell" {
inline = ["echo {{ replace `some-string` `-` `/` 1 }}"]
}
provisioner "shell-local" {
inline = ["sleep 100000"]
only = ["amazon-ebs"]
timeout = "5s"
inline = ["sleep 100000"]
only = ["amazon-ebs"]
pause_before = "5s"
timeout = "5s"
}
post-processor "amazon-import" {
format = "vmdk"
license_type = "BYOL"
@@ -0,0 +1,236 @@
{
"min_packer_version": "1.6.0",
"variables": {
"secret_account": "🤷",
"aws_region": null,
"aws_secondary_region": "{{ env `AWS_DEFAULT_REGION` }}",
"aws_secret_key": "",
"aws_access_key": "",
"password": "{{ aws_secretsmanager `sample/app/password` }}",
"password_key": "MY_KEY_{{ aws_secretsmanager `sample/app/passwords` `api_key` }}"
},
"sensitive-variables": [
"aws_secret_key",
"aws_access_key",
"secret_account",
"potato",
"password"
],
"builders": [
{
"type": "amazon-ebs",
"region": "{{ user `aws_region` }}",
"secret_key": "{{ user `aws_secret_key` }}",
"access_key": "{{ user `aws_access_key` }}",
"ami_name": "ubuntu-16-04-test-{{ timestamp }}",
"ami_description": "Ubuntu 16.04 LTS - expand root partition",
"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
},
"launch_block_device_mappings": [
{
"delete_on_termination": true,
"device_name": "/dev/sda1",
"volume_type": "gp2",
"volume_size": 48
}
],
"spot_price": "0.0075",
"spot_instance_types": [
"t2.small",
"t2.medium",
"t2.large"
],
"encrypt_boot": true,
"ssh_username": "ubuntu",
"temporary_iam_instance_profile_policy_document": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"*"
],
"Resource": ["*"]
}
]
},
"ssh_interface": "session_manager"
},
{
"type": "amazon-ebs",
"name": "named_builder",
"region": "{{ user `aws_region` }}",
"secret_key": "{{ user `aws_secret_key` }}",
"access_key": "{{ user `aws_access_key` }}",
"ami_name": "ubuntu-16-04-test-{{ timestamp }}",
"ami_description": "Ubuntu 16.04 LTS - expand root partition",
"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
},
"launch_block_device_mappings": [
{
"delete_on_termination": true,
"device_name": "/dev/sda1",
"volume_type": "gp2",
"volume_size": 48
}
],
"spot_price": "0.0075",
"spot_instance_types": [
"t2.small",
"t2.medium",
"t2.large"
],
"encrypt_boot": true,
"ssh_username": "ubuntu",
"temporary_iam_instance_profile_policy_document": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"*"
],
"Resource": ["*"]
}
]
},
"ssh_interface": "session_manager"
}
],
"provisioners": [
{
"type": "shell",
"except": [
"amazon-ebs"
],
"max_retries": 5,
"inline": [
"echo {{ user `secret_account` }}",
"echo {{ build `ID` }}",
"echo {{ build `SSHPublicKey` }} | head -c 14",
"echo {{ template_dir }} is not {{ pwd }}",
"echo {{ packer_version }}",
"echo {{ uuid }}"
]
},
{
"type": "shell",
"inline": [
"echo {{ user `password` }}",
"echo {{ aws_secretsmanager `sample/app/password` }}",
"echo {{ user `password_key` }}",
"echo {{ aws_secretsmanager `sample/app/passwords` `api_key` }}"
]
},
{
"type": "shell",
"inline": [
"echo {{ aws_secretsmanager `some_secret` }}",
"echo {{ aws_secretsmanager `some_secret` `with_key` }}"
]
},
{
"type": "shell",
"inline": [
"echo mybuild-{{isotime | clean_resource_name}}"
]
},
{
"type": "shell",
"inline": [
"echo {{ `SOMETHING` | lower }}"
]
},
{
"type": "shell",
"inline": [
"echo {{ `something` | upper }}"
]
},
{
"type": "shell",
"inline": [
"echo {{ split `some-string` `-` 0 }}"
]
},
{
"type": "shell",
"inline": [
"echo {{ replace_all `-` `/` build_name }}"
]
},
{
"type": "shell",
"inline": [
"echo {{ replace `some-string` `-` `/` 1 }}"
]
},
{
"type": "shell-local",
"only": [
"amazon-ebs"
],
"timeout": "5s",
"pause_before": "5s",
"inline": [
"sleep 100000"
]
}
],
"post-processors": [
[
{
"type": "amazon-import",
"region": "eu-west-3",
"s3_bucket_name": "hashicorp.adrien",
"license_type": "BYOL",
"format": "vmdk",
"tags": {
"Description": "packer amazon-import {{timestamp}}"
}
}
],
[
{
"only": [
"amazon-ebs"
],
"files": [
"path/something.ova"
],
"keep_input_artifact": true,
"name": "very_special_artifice_post-processor",
"type": "artifice"
},
{
"except": [
"amazon-ebs"
],
"type": "amazon-import",
"s3_bucket_name": "hashicorp.adrien",
"license_type": "BYOL",
"tags": {
"Description": "packer amazon-import {{timestamp}}"
}
}
]
]
}
@@ -0,0 +1,36 @@
# This file was autogenerated by the '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
# moved to their own 'variables.pkr.hcl' file, etc. Those files need to be
# suffixed with '.pkr.hcl' to be visible to Packer. To use multiple files at
# once they also need to be in the same folder. 'packer inspect folder/'
# will describe to you what is in that folder.
# Avoid mixing go templating calls ( for example ```{{ upper(`string`) }}``` )
# and HCL2 calls (for example '${ var.string_value_example }' ). They won't be
# executed together and the outcome will be unknown.
# 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
# source. Read the documentation for source blocks here:
# https://www.packer.io/docs/templates/hcl_templates/blocks/source
source "null" "autogenerated_1" {
communicator = "none"
}
# a build block invokes sources and runs provisioning steps on them. The
# documentation for build blocks can be found here:
# https://www.packer.io/docs/templates/hcl_templates/blocks/build
build {
sources = ["source.null.autogenerated_1"]
provisioner "shell-local" {
inline = ["exit 2"]
}
error-cleanup-provisioner "shell-local" {
inline = ["echo 'rubber ducky'> ducky.txt"]
}
}
@@ -0,0 +1,18 @@
{
"builders": [
{
"type": "null",
"communicator": "none"
}
],
"provisioners": [
{
"type": "shell-local",
"inline": ["exit 2"]
}
],
"error-cleanup-provisioner": {
"type": "shell-local",
"inline": ["echo 'rubber ducky'> ducky.txt"]
}
}
@@ -0,0 +1,75 @@
# This file was autogenerated by the '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
# moved to their own 'variables.pkr.hcl' file, etc. Those files need to be
# suffixed with '.pkr.hcl' to be visible to Packer. To use multiple files at
# once they also need to be in the same folder. 'packer inspect folder/'
# will describe to you what is in that folder.
# Avoid mixing go templating calls ( for example ```{{ upper(`string`) }}``` )
# and HCL2 calls (for example '${ var.string_value_example }' ). They won't be
# executed together and the outcome will be unknown.
# See https://www.packer.io/docs/templates/hcl_templates/blocks/packer for more info
packer {
required_version = ">= 1.6.0"
}
# All generated input variables will be of 'string' type as this is how Packer JSON
# views them; you can change their type later on. Read the variables type
# constraints documentation
# https://www.packer.io/docs/templates/hcl_templates/variables#type-constraints for more info.
variable "aws_access_key" {
type = string
default = ""
}
variable "aws_region" {
type = string
}
variable "aws_secret_key" {
type = string
default = ""
}
# 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
# source. Read the documentation for source blocks here:
# https://www.packer.io/docs/templates/hcl_templates/blocks/source
source "amazon-ebs" "autogenerated_1" {
access_key = "${var.aws_access_key}"
ami_description = "Ubuntu 16.04 LTS - expand root partition"
ami_name = "ubuntu-16-04-test"
encrypt_boot = true
launch_block_device_mappings {
delete_on_termination = true
device_name = "/dev/sda1"
volume_size = 48
volume_type = "gp2"
}
region = "${var.aws_region}"
secret_key = "${var.aws_secret_key}"
source_ami = "ami1234567"
spot_instance_types = ["t2.small", "t2.medium", "t2.large"]
spot_price = "0.0075"
ssh_interface = "session_manager"
ssh_username = "ubuntu"
temporary_iam_instance_profile_policy_document {
Statement {
Action = ["*"]
Effect = "Allow"
Resource = ["*"]
}
Version = "2012-10-17"
}
}
# a build block invokes sources and runs provisioning steps on them. The
# documentation for build blocks can be found here:
# https://www.packer.io/docs/templates/hcl_templates/blocks/build
build {
sources = ["source.amazon-ebs.autogenerated_1"]
}
@@ -0,0 +1,48 @@
{
"min_packer_version": "1.6.0",
"variables": {
"aws_region": null,
"aws_secret_key": "",
"aws_access_key": ""
},
"builders": [
{
"type": "amazon-ebs",
"region": "{{ user `aws_region` }}",
"secret_key": "{{ user `aws_secret_key` }}",
"access_key": "{{ user `aws_access_key` }}",
"ami_name": "ubuntu-16-04-test",
"ami_description": "Ubuntu 16.04 LTS - expand root partition",
"source_ami": "ami1234567",
"launch_block_device_mappings": [
{
"delete_on_termination": true,
"device_name": "/dev/sda1",
"volume_type": "gp2",
"volume_size": 48
}
],
"spot_price": "0.0075",
"spot_instance_types": [
"t2.small",
"t2.medium",
"t2.large"
],
"encrypt_boot": true,
"ssh_username": "ubuntu",
"temporary_iam_instance_profile_policy_document": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"*"
],
"Resource": ["*"]
}
]
},
"ssh_interface": "session_manager"
}
]
}
@@ -0,0 +1,78 @@
# This file was autogenerated by the '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
# moved to their own 'variables.pkr.hcl' file, etc. Those files need to be
# suffixed with '.pkr.hcl' to be visible to Packer. To use multiple files at
# once they also need to be in the same folder. 'packer inspect folder/'
# will describe to you what is in that folder.
# Avoid mixing go templating calls ( for example ```{{ upper(`string`) }}``` )
# and HCL2 calls (for example '${ var.string_value_example }' ). They won't be
# executed together and the outcome will be unknown.
# See https://www.packer.io/docs/templates/hcl_templates/blocks/packer for more info
packer {
required_version = ">= 1.6.0"
}
# All generated input variables will be of 'string' type as this is how Packer JSON
# views them; you can change their type later on. Read the variables type
# constraints documentation
# https://www.packer.io/docs/templates/hcl_templates/variables#type-constraints for more info.
variable "aws_access_key" {
type = string
default = ""
}
variable "aws_region" {
type = string
}
variable "aws_secret_key" {
type = string
default = ""
}
# "timestamp" template function replacement
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
# source. Read the documentation for source blocks here:
# https://www.packer.io/docs/templates/hcl_templates/blocks/source
source "amazon-ebs" "party_parrot" {
access_key = "${var.aws_access_key}"
ami_description = "Ubuntu 16.04 LTS - expand root partition"
ami_name = "ubuntu-16-04-test-${local.timestamp}"
encrypt_boot = true
launch_block_device_mappings {
delete_on_termination = true
device_name = "/dev/sda1"
volume_size = 48
volume_type = "gp2"
}
region = "${var.aws_region}"
secret_key = "${var.aws_secret_key}"
source_ami = "ami1234567"
spot_instance_types = ["t2.small", "t2.medium", "t2.large"]
spot_price = "0.0075"
ssh_interface = "session_manager"
ssh_username = "ubuntu"
temporary_iam_instance_profile_policy_document {
Statement {
Action = ["*"]
Effect = "Allow"
Resource = ["*"]
}
Version = "2012-10-17"
}
}
# a build block invokes sources and runs provisioning steps on them. The
# documentation for build blocks can be found here:
# https://www.packer.io/docs/templates/hcl_templates/blocks/build
build {
sources = ["source.amazon-ebs.party_parrot"]
}
@@ -0,0 +1,49 @@
{
"min_packer_version": "1.6.0",
"variables": {
"aws_region": null,
"aws_secret_key": "",
"aws_access_key": ""
},
"builders": [
{
"type": "amazon-ebs",
"name": " party parrot ",
"region": "{{ user `aws_region` }}",
"secret_key": "{{ user `aws_secret_key` }}",
"access_key": "{{ user `aws_access_key` }}",
"ami_name": "ubuntu-16-04-test-{{ timestamp }}",
"ami_description": "Ubuntu 16.04 LTS - expand root partition",
"source_ami": "ami1234567",
"launch_block_device_mappings": [
{
"delete_on_termination": true,
"device_name": "/dev/sda1",
"volume_type": "gp2",
"volume_size": 48
}
],
"spot_price": "0.0075",
"spot_instance_types": [
"t2.small",
"t2.medium",
"t2.large"
],
"encrypt_boot": true,
"ssh_username": "ubuntu",
"temporary_iam_instance_profile_policy_document": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"*"
],
"Resource": ["*"]
}
]
},
"ssh_interface": "session_manager"
}
]
}
@@ -0,0 +1,45 @@
variable "aws_access_key" {
type = string
default = ""
sensitive = true
}
variable "aws_region" {
type = string
}
variable "aws_secondary_region" {
type = string
default = "${env("AWS_DEFAULT_REGION")}"
}
variable "aws_secret_key" {
type = string
default = ""
sensitive = true
}
variable "secret_account" {
type = string
default = "🤷"
sensitive = true
}
data "amazon-secretsmanager" "autogenerated_1" {
name = "sample/app/password"
}
data "amazon-secretsmanager" "autogenerated_2" {
key = "api_key"
name = "sample/app/passwords"
}
local "password" {
sensitive = true
expression = "${data.amazon-secretsmanager.autogenerated_1.value}"
}
locals {
password_key = "MY_KEY_${data.amazon-secretsmanager.autogenerated_2.value}"
}
@@ -0,0 +1,18 @@
{
"variables": {
"secret_account": "🤷",
"aws_region": null,
"aws_secondary_region": "{{ env `AWS_DEFAULT_REGION` }}",
"aws_secret_key": "",
"aws_access_key": "",
"password": "{{ aws_secretsmanager `sample/app/password` }}",
"password_key": "MY_KEY_{{ aws_secretsmanager `sample/app/passwords` `api_key` }}"
},
"sensitive-variables": [
"aws_secret_key",
"aws_access_key",
"secret_account",
"potato",
"password"
]
}
@@ -0,0 +1,25 @@
variable "aws_access_key" {
type = string
default = ""
sensitive = true
}
variable "aws_region" {
type = string
}
variable "aws_secret_key" {
type = string
default = ""
sensitive = true
}
local "password" {
sensitive = true
expression = "${var.aws_secret_key}-${var.aws_access_key}"
}
locals {
aws_secondary_region = "${var.aws_region}"
}
@@ -0,0 +1,14 @@
{
"variables": {
"aws_region": null,
"aws_secondary_region": "{{ user `aws_region` }}",
"aws_secret_key": "",
"aws_access_key": "",
"password": "{{ user `aws_secret_key` }}-{{ user `aws_access_key` }}"
},
"sensitive-variables": [
"aws_secret_key",
"aws_access_key",
"password"
]
}
@@ -0,0 +1,232 @@
packer {
required_version = ">= 1.6.0"
}
variable "aws_access_key" {
type = string
default = ""
sensitive = true
}
variable "aws_region" {
type = string
}
variable "aws_secondary_region" {
type = string
default = "${env("AWS_DEFAULT_REGION")}"
}
variable "aws_secret_key" {
type = string
default = ""
sensitive = true
}
variable "secret_account" {
type = string
default = "🤷"
sensitive = true
}
data "amazon-secretsmanager" "autogenerated_1" {
name = "sample/app/password"
}
data "amazon-secretsmanager" "autogenerated_2" {
key = "api_key"
name = "sample/app/passwords"
}
data "amazon-secretsmanager" "autogenerated_3" {
name = "some_secret"
}
data "amazon-secretsmanager" "autogenerated_4" {
key = "with_key"
name = "some_secret"
}
data "amazon-ami" "autogenerated_1" {
access_key = "${var.aws_access_key}"
filters = {
name = "ubuntu/images/*/ubuntu-xenial-16.04-amd64-server-*"
root-device-type = "ebs"
virtualization-type = "hvm"
}
most_recent = true
owners = ["099720109477"]
region = "${var.aws_region}"
secret_key = "${var.aws_secret_key}"
}
locals { timestamp = regex_replace(timestamp(), "[- TZ:]", "") }
local "password" {
sensitive = true
expression = "${data.amazon-secretsmanager.autogenerated_1.value}"
}
locals {
password_key = "MY_KEY_${data.amazon-secretsmanager.autogenerated_2.value}"
}
source "amazon-ebs" "autogenerated_1" {
access_key = "${var.aws_access_key}"
ami_description = "Ubuntu 16.04 LTS - expand root partition"
ami_name = "ubuntu-16-04-test-${local.timestamp}"
encrypt_boot = true
launch_block_device_mappings {
delete_on_termination = true
device_name = "/dev/sda1"
volume_size = 48
volume_type = "gp2"
}
region = "${var.aws_region}"
secret_key = "${var.aws_secret_key}"
source_ami = "${data.amazon-ami.autogenerated_1.id}"
spot_instance_types = ["t2.small", "t2.medium", "t2.large"]
spot_price = "0.0075"
ssh_interface = "session_manager"
ssh_username = "ubuntu"
temporary_iam_instance_profile_policy_document {
Statement {
Action = ["*"]
Effect = "Allow"
Resource = ["*"]
}
Version = "2012-10-17"
}
}
source "amazon-ebs" "named_builder" {
access_key = "${var.aws_access_key}"
ami_description = "Ubuntu 16.04 LTS - expand root partition"
ami_name = "ubuntu-16-04-test-${local.timestamp}"
encrypt_boot = true
launch_block_device_mappings {
delete_on_termination = true
device_name = "/dev/sda1"
volume_size = 48
volume_type = "gp2"
}
region = "${var.aws_region}"
secret_key = "${var.aws_secret_key}"
source_ami = "${data.amazon-ami.autogenerated_1.id}"
spot_instance_types = ["t2.small", "t2.medium", "t2.large"]
spot_price = "0.0075"
ssh_interface = "session_manager"
ssh_username = "ubuntu"
temporary_iam_instance_profile_policy_document {
Statement {
Action = ["*"]
Effect = "Allow"
Resource = ["*"]
}
Version = "2012-10-17"
}
}
build {
sources = ["source.amazon-ebs.autogenerated_1", "source.amazon-ebs.named_builder"]
provisioner "shell" {
except = ["amazon-ebs"]
inline = ["echo ${var.secret_account}", "echo ${build.ID}", "echo ${build.SSHPublicKey} | head -c 14", "echo ${path.root} is not ${path.cwd}", "echo ${packer.version}", "echo ${uuidv4()}"]
max_retries = "5"
}
provisioner "shell" {
inline = ["echo ${local.password}", "echo ${data.amazon-secretsmanager.autogenerated_1.value}", "echo ${local.password_key}", "echo ${data.amazon-secretsmanager.autogenerated_2.value}"]
}
provisioner "shell" {
inline = ["echo ${data.amazon-secretsmanager.autogenerated_3.value}", "echo ${data.amazon-secretsmanager.autogenerated_4.value}"]
}
# template: hcl2_upgrade:2:38: executing "hcl2_upgrade" at <clean_resource_name>: error calling clean_resource_name: unhandled "clean_resource_name" call:
# there is no way to automatically upgrade the "clean_resource_name" call.
# Please manually upgrade to use custom validation rules, `replace(string, substring, replacement)` or `regex_replace(string, substring, replacement)`
# Visit https://packer.io/docs/templates/hcl_templates/variables#custom-validation-rules , https://www.packer.io/docs/templates/hcl_templates/functions/string/replace or https://www.packer.io/docs/templates/hcl_templates/functions/string/regex_replace for more infos.
provisioner "shell" {
inline = ["echo mybuild-{{isotime | clean_resource_name}}"]
}
# template: hcl2_upgrade:2:35: executing "hcl2_upgrade" at <lower>: error calling lower: unhandled "lower" call:
# there is no way to automatically upgrade the "lower" call.
# Please manually upgrade to `lower(var.example)`
# Visit https://www.packer.io/docs/templates/hcl_templates/functions/string/lower for more infos.
provisioner "shell" {
inline = ["echo {{ `SOMETHING` | lower }}"]
}
# template: hcl2_upgrade:2:35: executing "hcl2_upgrade" at <upper>: error calling upper: unhandled "upper" call:
# there is no way to automatically upgrade the "upper" call.
# Please manually upgrade to `upper(var.example)`
# Visit https://www.packer.io/docs/templates/hcl_templates/functions/string/upper for more infos.
provisioner "shell" {
inline = ["echo {{ `something` | upper }}"]
}
# template: hcl2_upgrade:2:21: executing "hcl2_upgrade" at <split `some-string` `-` 0>: error calling split: unhandled "split" call:
# there is no way to automatically upgrade the "split" call.
# Please manually upgrade to `split(separator, string)`
# Visit https://www.packer.io/docs/templates/hcl_templates/functions/string/split for more infos.
provisioner "shell" {
inline = ["echo {{ split `some-string` `-` 0 }}"]
}
# template: hcl2_upgrade:2:21: executing "hcl2_upgrade" at <replace_all `-` `/` build_name>: error calling replace_all: unhandled "replace_all" call:
# there is no way to automatically upgrade the "replace_all" call.
# Please manually upgrade to `replace(string, substring, replacement)` or `regex_replace(string, substring, replacement)`
# Visit https://www.packer.io/docs/templates/hcl_templates/functions/string/replace or https://www.packer.io/docs/templates/hcl_templates/functions/string/regex_replace for more infos.
provisioner "shell" {
inline = ["echo {{ replace_all `-` `/` build_name }}"]
}
# template: hcl2_upgrade:2:21: executing "hcl2_upgrade" at <replace `some-string` `-` `/` 1>: error calling replace: unhandled "replace" call:
# there is no way to automatically upgrade the "replace" call.
# Please manually upgrade to `replace(string, substring, replacement)` or `regex_replace(string, substring, replacement)`
# Visit https://www.packer.io/docs/templates/hcl_templates/functions/string/replace or https://www.packer.io/docs/templates/hcl_templates/functions/string/regex_replace for more infos.
provisioner "shell" {
inline = ["echo {{ replace `some-string` `-` `/` 1 }}"]
}
provisioner "shell-local" {
inline = ["sleep 100000"]
only = ["amazon-ebs"]
timeout = "5s"
}
post-processor "amazon-import" {
format = "vmdk"
license_type = "BYOL"
region = "eu-west-3"
s3_bucket_name = "hashicorp.adrien"
tags = {
Description = "packer amazon-import ${local.timestamp}"
}
}
post-processors {
post-processor "artifice" {
keep_input_artifact = true
files = ["path/something.ova"]
name = "very_special_artifice_post-processor"
only = ["amazon-ebs"]
}
post-processor "amazon-import" {
except = ["amazon-ebs"]
license_type = "BYOL"
s3_bucket_name = "hashicorp.adrien"
tags = {
Description = "packer amazon-import ${local.timestamp}"
}
}
}
}
@@ -5,13 +5,16 @@
"aws_region": null,
"aws_secondary_region": "{{ env `AWS_DEFAULT_REGION` }}",
"aws_secret_key": "",
"aws_access_key": ""
"aws_access_key": "",
"password": "{{ aws_secretsmanager `sample/app/password` }}",
"password_key": "MY_KEY_{{ aws_secretsmanager `sample/app/passwords` `api_key` }}"
},
"sensitive-variables": [
"aws_secret_key",
"aws_access_key",
"secret_account",
"potato"
"potato",
"password"
],
"builders": [
{
@@ -128,6 +131,22 @@
"echo {{ uuid }}"
]
},
{
"type": "shell",
"inline": [
"echo {{ user `password` }}",
"echo {{ aws_secretsmanager `sample/app/password` }}",
"echo {{ user `password_key` }}",
"echo {{ aws_secretsmanager `sample/app/passwords` `api_key` }}"
]
},
{
"type": "shell",
"inline": [
"echo {{ aws_secretsmanager `some_secret` }}",
"echo {{ aws_secretsmanager `some_secret` `with_key` }}"
]
},
{
"type": "shell",
"inline": [
+7 -5
View File
@@ -92,6 +92,7 @@ Options:
-syntax-only Only check syntax. Do not verify config of the template.
-except=foo,bar,baz Validate all builds other than these.
-machine-readable Produce machine-readable output.
-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.
@@ -110,10 +111,11 @@ func (*ValidateCommand) AutocompleteArgs() complete.Predictor {
func (*ValidateCommand) AutocompleteFlags() complete.Flags {
return complete.Flags{
"-syntax-only": complete.PredictNothing,
"-except": complete.PredictNothing,
"-only": complete.PredictNothing,
"-var": complete.PredictNothing,
"-var-file": complete.PredictNothing,
"-syntax-only": complete.PredictNothing,
"-except": complete.PredictNothing,
"-only": complete.PredictNothing,
"-var": complete.PredictNothing,
"-machine-readable": complete.PredictNothing,
"-var-file": complete.PredictNothing,
}
}
+3 -6
View File
@@ -17,7 +17,7 @@ require (
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20170113022742-e6dbea820a9f
github.com/antihax/optional v1.0.0
github.com/approvals/go-approval-tests v0.0.0-20160714161514-ad96e53bea43
github.com/aws/aws-sdk-go v1.36.5
github.com/aws/aws-sdk-go v1.37.15
github.com/biogo/hts v0.0.0-20160420073057-50da7d4131a3
github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee
github.com/cheggaaa/pb v1.0.27
@@ -50,7 +50,7 @@ require (
github.com/hashicorp/go-uuid v1.0.2
github.com/hashicorp/go-version v1.2.0
github.com/hashicorp/hcl/v2 v2.8.0
github.com/hashicorp/packer-plugin-sdk v0.0.11
github.com/hashicorp/packer-plugin-sdk v0.0.14
github.com/hashicorp/vault/api v1.0.4
github.com/hetznercloud/hcloud-go v1.15.1
github.com/hyperonecom/h1-client-go v0.0.0-20191203060043-b46280e4c4a4
@@ -68,7 +68,7 @@ require (
github.com/mitchellh/prefixedio v0.0.0-20151214002211-6e6954073784
github.com/mitchellh/reflectwalk v1.0.0
github.com/olekukonko/tablewriter v0.0.0-20180105111133-96aac992fc8b
github.com/oracle/oci-go-sdk v18.0.0+incompatible
github.com/oracle/oci-go-sdk v24.3.0+incompatible
github.com/outscale/osc-sdk-go/osc v0.0.0-20200722135656-d654809d0699
github.com/pierrec/lz4 v2.0.5+incompatible
github.com/pkg/errors v0.9.1
@@ -76,7 +76,6 @@ require (
github.com/profitbricks/profitbricks-sdk-go v4.0.2+incompatible
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7
github.com/shirou/gopsutil v2.18.12+incompatible
github.com/smartystreets/goconvey v1.6.4 // indirect
github.com/stretchr/testify v1.6.1
github.com/tencentcloud/tencentcloud-sdk-go v3.0.222+incompatible
github.com/ucloud/ucloud-sdk-go v0.16.3
@@ -100,6 +99,4 @@ require (
google.golang.org/grpc v1.32.0
)
// replace github.com/hashicorp/packer-plugin-sdk => /Users/azr/go/src/github.com/hashicorp/packer-plugin-sdk
go 1.13
+15
View File
@@ -129,6 +129,8 @@ github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU
github.com/aws/aws-sdk-go v1.36.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
github.com/aws/aws-sdk-go v1.36.5 h1:SouM2ar1A8f+3DYWW622sDdqkkZAO3ha4j8GQjiPLFg=
github.com/aws/aws-sdk-go v1.36.5/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
github.com/aws/aws-sdk-go v1.37.15 h1:W7l7gLLMcYRlg6a+uvf3Zz4jYwdqYzhe5ymqwWoOhp4=
github.com/aws/aws-sdk-go v1.37.15/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
@@ -393,6 +395,8 @@ github.com/hashicorp/packer v1.6.7-0.20210112155033-1bc89e34714f/go.mod h1:sKsux
github.com/hashicorp/packer v1.6.7-0.20210120105538-140685fb4f8b/go.mod h1:Yaw0q8brThFN2PKMWMRcuhQBuwPVDJRHHioNuMJTS7Q=
github.com/hashicorp/packer v1.6.7-0.20210125170305-539638b0f951/go.mod h1:Z3eunaxVQ3XgQ+rW7TEH0T/PRQzCUSyCBUTkm/VL7io=
github.com/hashicorp/packer v1.6.7-0.20210126105722-aef4ced967ec/go.mod h1:2+Vo/c/fA+TD9yFc/h9jQMFm4yG+IymQIr0OdJJOPiE=
github.com/hashicorp/packer v1.6.7-0.20210208125835-f616955ebcb6/go.mod h1:7f5ZpTTRG53rQ58BcTADuTnpiBcB3wapuxl4sF2sGMM=
github.com/hashicorp/packer v1.6.7-0.20210217093213-201869d627bf/go.mod h1:+EWPPcqee4h8S/y913Dnta1eJkgiqsGXBQgB75A2qV0=
github.com/hashicorp/packer-plugin-sdk v0.0.6 h1:BN2G4APXSMvDURFdnk+6DspwsU83pZeMsbEur7NmGsA=
github.com/hashicorp/packer-plugin-sdk v0.0.6/go.mod h1:Nvh28f+Jmpp2rcaN79bULTouNkGNDRfHckhHKTAXtyU=
github.com/hashicorp/packer-plugin-sdk v0.0.6/go.mod h1:Nvh28f+Jmpp2rcaN79bULTouNkGNDRfHckhHKTAXtyU=
@@ -405,6 +409,10 @@ github.com/hashicorp/packer-plugin-sdk v0.0.10-0.20210126105622-8e1648006d93 h1:
github.com/hashicorp/packer-plugin-sdk v0.0.10-0.20210126105622-8e1648006d93/go.mod h1:AtWQLNfpn7cgH2SmZ1PTedwqNOhiPvzcuKfH5sDvIQ0=
github.com/hashicorp/packer-plugin-sdk v0.0.11 h1:nUurEGaJtpVDyg94bKC2xOXWf1TqQ+++GovFUnP5REI=
github.com/hashicorp/packer-plugin-sdk v0.0.11/go.mod h1:GNb0WNs7zibb8vzUZce1As64z2AW0FEMwhe2J7/NW5I=
github.com/hashicorp/packer-plugin-sdk v0.0.12 h1:eagxsrborfhc0E8zvDVCiRE9pQkjBw/6jm23jp0D8RU=
github.com/hashicorp/packer-plugin-sdk v0.0.12/go.mod h1:hs82OYeufirGG6KRENMpjBWomnIlte99X6wXAPThJ5I=
github.com/hashicorp/packer-plugin-sdk v0.0.14 h1:42WOZLmIbAYYC1WXxtlrQZN+fFdysVvTmj3jtoI6gOU=
github.com/hashicorp/packer-plugin-sdk v0.0.14/go.mod h1:tNb3XzJPnjMl3QuUdKmF47B5ImerdTakalHzUAvW0aw=
github.com/hashicorp/serf v0.8.2 h1:YZ7UKsJv+hKjqGVUUbtE3HNj79Eln2oQ75tniF6iPt0=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hashicorp/serf v0.9.2 h1:yJoyfZXo4Pk2p/M/viW+YLibBFiIbKoP79gu7kDAFP0=
@@ -530,6 +538,7 @@ 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 h1:x0jD3dcHk9a9xPSDN6YEL4xL6Qz0dvNYm8yZqui5chI=
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=
@@ -560,6 +569,8 @@ github.com/olekukonko/tablewriter v0.0.0-20180105111133-96aac992fc8b/go.mod h1:v
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/oracle/oci-go-sdk v18.0.0+incompatible h1:FLV4KixsVfF3rwyVTMI6Ryp/Q+OSb9sR5TawbfjFLN4=
github.com/oracle/oci-go-sdk v18.0.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
github.com/oracle/oci-go-sdk v24.3.0+incompatible h1:x4mcfb4agelf1O4/1/auGlZ1lr97jXRSSN5MxTgG/zU=
github.com/oracle/oci-go-sdk v24.3.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
github.com/outscale/osc-sdk-go/osc v0.0.0-20200722135656-d654809d0699 h1:SHe9i7h5cHe+cB77fQ6lsEgIwKg3ckNU90P03CjGMnI=
github.com/outscale/osc-sdk-go/osc v0.0.0-20200722135656-d654809d0699/go.mod h1:5AqqNH1X8zCHescKVlpSHRzrat1KCKDXqZoQPe8fY3A=
github.com/packer-community/winrmcp v0.0.0-20180921204643-0fd363d6159a h1:A3QMuteviunoaY/8ex+RKFqwhcZJ/Cf3fCW3IwL2wx4=
@@ -637,6 +648,10 @@ github.com/ufilesdk-dev/ufile-gosdk v0.0.0-20190830075812-b4dbc4ef43a6 h1:FAWNiq
github.com/ufilesdk-dev/ufile-gosdk v0.0.0-20190830075812-b4dbc4ef43a6/go.mod h1:R5FMQxkQ+QK/9Vz+jfnJP4rZIktYrRcWmuAnbOSkROI=
github.com/ugorji/go v0.0.0-20151218193438-646ae4a518c1 h1:U6ufy3mLDgg9RYupntOvAF7xCmNNquyKaYaaVHo1Nnk=
github.com/ugorji/go v0.0.0-20151218193438-646ae4a518c1/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
github.com/ugorji/go v1.2.4 h1:cTciPbZ/VSOzCLKclmssnfQ/jyoVyOcJ3aoJyUV1Urc=
github.com/ugorji/go v1.2.4/go.mod h1:EuaSCk8iZMdIspsu6HXH7X2UGKw1ezO4wCfGszGmmo4=
github.com/ugorji/go/codec v1.2.4 h1:C5VurWRRCKjuENsbM6GYVw8W++WVW9rSxoACKIvxzz8=
github.com/ugorji/go/codec v1.2.4/go.mod h1:bWBu1+kIRWcF8uMklKaJrR6fTWQOwAlrIzX22pHwryA=
github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok=
github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=

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