Compare commits

..

178 Commits

Author SHA1 Message Date
Adrien Delorme 780f9c8b41 empty commit 2021-03-24 11:22:30 +01:00
Adrien Delorme 3629aeaa01 Merge remote-tracking branch 'origin/master' into azr_implicit_requried_plugin 2021-03-24 11:08:05 +01:00
Adrien Delorme c207e4acad Update init.mdx 2021-03-24 10:49:03 +01:00
Adrien Delorme 519dfa1959 Update init.mdx
improve Implicit required plugin section
2021-03-24 10:45:18 +01:00
Wilken Rivera 70ceed1110 Update vendor modules 2021-03-23 17:41:43 -04:00
Wilken Rivera 82eedc8f02 Update packer docs to latest (#10814) 2021-03-23 17:02:44 -04:00
Wilken Rivera 1d53080625 Update script to exit on immediate failure (#10815) 2021-03-23 16:44:21 -04:00
Zachary Shilton 89931d0f2a website: fixes and tweaks for plugin docs (#10812)
* website: sort nested plugin docs files

* website: allow ignored .md files in plugin docs folders

* website: allow plugin docs/README.md only as extra file

* website: fix issue with latest link for plugin docs.zip
2021-03-23 16:06:50 -04:00
Wilken Rivera 5e17dbeff2 Fix up regex in test 2021-03-23 14:39:45 -04:00
Wilken Rivera d0512c6edd docs/amazon: Updated generated docs 2021-03-23 14:14:59 -04:00
Adrien Delorme 51024ed507 Update website/content/docs/commands/init.mdx
Co-authored-by: Sylvia Moss <moss@hashicorp.com>
2021-03-23 13:35:05 +01:00
Adrien Delorme a060cd81a5 Update init.mdx 2021-03-23 13:26:26 +01:00
Adrien Delorme 4ab0d14f8c Update init.mdx 2021-03-23 13:12:22 +01:00
Adrien Delorme 4cd4616641 Update init.mdx 2021-03-23 13:12:05 +01:00
Adrien Delorme e470ec0ffc Merge remote-tracking branch 'origin/master' into azr_implicit_requried_plugin 2021-03-23 13:09:41 +01:00
Adrien Delorme e976c30964 Update init.mdx 2021-03-23 13:09:16 +01:00
Adrien Delorme 7ed9e672a9 Update command/init.go
clearer and shorter warning ( using docs link )
2021-03-23 13:07:59 +01:00
Adrien Delorme ff5b5221c4 Update init.mdx 2021-03-23 13:06:20 +01:00
Adrien Delorme b345a44a07 Update init.mdx 2021-03-23 13:05:16 +01:00
Adrien Delorme 7732f7998c Add http_content func to serve variables from HTTP @ preseed (#10801)
This imports hashicorp/packer-plugin-sdk#43

* code generate things
* update docs
* update guides
* update examples

We want to add a new guide.
2021-03-23 12:31:13 +01:00
Adrien Delorme ff01e6715a HCL2: add templatefile function (#10776)
* tests
* docs
2021-03-23 12:02:05 +01:00
Megan Marsh edc19eb859 Merge pull request #10806 from onlydole/bugfix/hashicorp-typo
Update 'Hashicorp' to 'HashiCorp' in the Amazon Documentation
2021-03-22 11:20:53 -07:00
Taylor Dolezal 1bb5c455aa Update 'Hashicorp' to 'HashiCorp' 2021-03-22 11:05:42 -07:00
Bryce Kalow 8c61ca174f feat: adds should-build website script (#10779) 2021-03-22 10:21:59 -04:00
Kyle MacDonald ef6093c4c3 Merge pull request #10764 from zchsh/zs.remote-plugin-zip-approach
website: Implement RFC MKTG-033
2021-03-22 09:59:38 -04:00
Marcus Weiner 4d9fb629c6 Allow using API tokens for Proxmox authentication (#10797) 2021-03-22 11:48:31 +01:00
Megan Marsh 0993c976fa hcl2_upgrade escaped quotes fix (#10794)
* clean up extra quoting that can cause text template failures. when everyone else abandons you, regex will always be there.

* LINTING
2021-03-22 10:56:30 +01:00
outscale-mgo 1e312ebc21 Fix description that was ignored in Osc builder (#10792)
Signed-off-by: Matthias Gatto <matthias.gatto@outscale.com>
2021-03-22 09:05:10 +01:00
Zach Shilton b780da5750 website: run plugin docs check also on schedule 2021-03-20 21:59:34 -04:00
Zach Shilton 565ca6627c website: revert test of plugin docs config validation 2021-03-20 21:51:42 -04:00
Zach Shilton c100b56d44 website: clarify error message in plugin config check 2021-03-20 21:50:20 -04:00
Zach Shilton 55012937a9 website: add comments to duo of plugin docs zip fns 2021-03-20 21:45:40 -04:00
Zach Shilton 15d467eaf1 website: fix outdated comment 2021-03-20 21:45:12 -04:00
Zach Shilton ce896351b9 website: temporary change to double-check validation 2021-03-20 21:37:21 -04:00
Zach Shilton fb0886b724 website: Implement basic validation for plugin docs config 2021-03-20 21:35:46 -04:00
Megan Marsh 667f930d3d Merge pull request #10793 from hashicorp/update-changelog-plugin-extraction-notes
update CHANGELOG
2021-03-19 13:42:54 -07:00
Wilken Rivera f2f65607eb update CHANGELOG 2021-03-19 14:32:05 -04:00
Megan Marsh ecaff88af9 Merge pull request #10780 from hashicorp/fix_10728
add legacy_isotime hcl function
2021-03-19 09:51:24 -07:00
Megan Marsh a40a782408 remove escaped dir 2021-03-19 09:28:30 -07:00
Brian Farrell 80f807de4d Fix issue with test breaking default value when client_cert_token_timeout is missing (#10783) 2021-03-19 15:17:41 +01:00
Wilken Rivera ac7c0f2f04 Update link in issue migrator config (#10791) 2021-03-19 09:48:58 -04:00
Adrien Delorme e2e6bce4c4 Update hcl2_upgrade_test.go
show diffs with strings
2021-03-19 13:56:41 +01:00
jhawk28 9f647ba2bb try to retype key if an error is received (#10541) 2021-03-19 13:27:05 +01:00
Wilken Rivera 7c6c399a38 Add hashibot configuration for transferring issues (#10785)
The added configuration will allow us to transfer open remote-plugin/* issues from
hashicorp/packer to their new respective repos. HashiBot issue transfer
only works with orgs it has write access to. Which is similar to how
GitHub's issue transfer feature works.
2021-03-19 12:47:32 +01:00
Adrien Delorme d5ccf73e91 oci builder: Show key_file errors (#10774) 2021-03-19 11:59:10 +01:00
Adrien Delorme d8cbfcc075 Update website/content/docs/commands/init.mdx 2021-03-19 11:36:12 +01:00
Adrien Delorme eba081a155 Update types.required_plugins.go
more comments
2021-03-19 11:18:39 +01:00
Adrien Delorme 7ccfe38475 Update types.required_plugins.go
up comment
2021-03-19 11:16:13 +01:00
Adrien Delorme dacf52b5b3 check for pre-existing component definition first 2021-03-19 11:13:43 +01:00
Megan Marsh 502708b86a Refactor hcl2_upgrade (#10787) 2021-03-19 10:24:49 +01:00
Zach Shilton 1d485988ea website: bump timeout for vercel build polling 2021-03-18 15:31:04 -04:00
Zach Shilton de12cd318d website: remove outdated comment on plugin config entries 2021-03-18 15:10:02 -04:00
Zachary Shilton 597dcce2ab website: fix tag vs version reference in README
Co-authored-by: Wilken Rivera <dev@wilkenrivera.com>
2021-03-18 15:06:42 -04:00
Zachary Shilton 0f8a658a23 website: clarify tag vs version in error msg
Co-authored-by: Wilken Rivera <dev@wilkenrivera.com>
2021-03-18 15:05:52 -04:00
Megan Marsh 4242cf3151 fix tests 2021-03-18 10:02:27 -07:00
Zach Shilton 618a3d42c6 website: clarify purpose of sourceUrl 2021-03-18 12:31:24 -04:00
Zach Shilton 203900e403 website: delete unused plugin-docs utilities 2021-03-18 12:26:27 -04:00
Zach Shilton bece5c3c69 website: fix minor style issue in PluginTier component 2021-03-18 12:26:16 -04:00
Zach Shilton 9e03647ad7 website: update readme to reflect revised nav-data and plugin docs 2021-03-18 12:26:03 -04:00
Zach Shilton e68e736b6c website: add indexing for plugin docs content 2021-03-18 12:25:49 -04:00
Zach Shilton 26a572270d website: add github action to flag plugin-docs issues 2021-03-18 12:25:36 -04:00
Zach Shilton 8b3e7e6f2f website: use revised remote-plugin-docs server implementation
- also bumps to stable docs-page, and makes related api changes for intro and guides routes
2021-03-18 12:24:36 -04:00
Zach Shilton 341308c582 website: add refactored remote-plugin-docs utilities 2021-03-18 12:21:53 -04:00
Ace Eldeib 3227d3da43 clean up azure temporary managed os disk (#10713)
* clean up temporary managed os disk

* improve message for skipping disk deletion

Co-authored-by: Wilken Rivera <dev@wilkenrivera.com>

* re-arrange osdisk/additional disk cleanup

Co-authored-by: Wilken Rivera <dev@wilkenrivera.com>

* remove additional disk cleanup

* add some validation on scenarios

* alway clean up resources inside template cleanup

* tidy to master

* clarify naming and comments

Co-authored-by: Wilken Rivera <dev@wilkenrivera.com>

* test: add acceptance testing for azure cleanup

* revert template changes

* fix err check

* delete resources in parallel with retry to avoid serial deletion

* nit: improve log message for transient deletion errors

* fix: typo

* remove unused func to make lint happy

Co-authored-by: Wilken Rivera <dev@wilkenrivera.com>
2021-03-18 12:09:57 -04:00
Adrien Delorme 1926fd6176 Update command/init.go
better warning

Co-authored-by: Sylvia Moss <moss@hashicorp.com>
2021-03-18 16:43:29 +01:00
Sylvia Moss 0f541aaf5e Update CONTRIBUTING.md (#10782) 2021-03-18 16:24:34 +01:00
Megan Marsh 0ecc4b5e52 add annotation warning to isotime func usage 2021-03-17 16:06:19 -07:00
Megan Marsh 6986fb0e81 make upgrade set isotime func properly 2021-03-17 15:52:22 -07:00
Megan Marsh a6f907c688 tests 2021-03-17 10:48:55 -07:00
Adrien Delorme 3e8641e30e Delete formatted.pkr.hcl (#10775) 2021-03-17 14:41:46 +01:00
Sylvia Moss d0737dcd17 skip DownloadPathKey and ShouldUploadISO on mapstructure-to-hcl2 (#10772) 2021-03-17 14:26:38 +01:00
Adrien Delorme 15f4b93cd2 init.mdx: add short text on implicit plugin requirements 2021-03-17 11:46:42 +01:00
Adrien Delorme 46b6a21a9f Update types.required_plugins.go
better comments
2021-03-17 11:24:37 +01:00
Adrien Delorme 53dc1eb87b better comments 2021-03-17 11:03:42 +01:00
Adrien Delorme 0c45f75bf6 better comments 2021-03-17 11:02:20 +01:00
Adrien Delorme 9b41474ab5 better comments 2021-03-17 10:59:55 +01:00
Adrien Delorme 2f4c5c0a24 test that already defined components won't create implicit required plugins 2021-03-17 10:30:37 +01:00
Adrien Delorme 85aef9d3a6 skip a implictly requiring a plugin if the plugin name of the plugin is being defined in a required_plugin 2021-03-17 10:17:03 +01:00
Adrien Delorme ad21a101c8 add comments 2021-03-17 10:16:24 +01:00
Adrien Delorme ef974dd75c add comments 2021-03-17 09:56:00 +01:00
Adrien Delorme 69de942647 requirePluginImplicitly => decodeImplicitRequiredPluginsBlock 2021-03-17 09:54:45 +01:00
Adrien Delorme 2e9307de3f define ComponentKind that help enumerate what kind of components exist in hcl 2021-03-17 09:53:26 +01:00
Adrien Delorme 27fb9b2525 rimplify requirePluginImplicitly a little 2021-03-17 09:52:59 +01:00
Adrien Delorme 47fa09a9c9 hcl2template: Rename Datasource type to DatasourceBlock 2021-03-17 09:42:47 +01:00
Adrien Delorme 7e4948502f add test for a forked plugin 2021-03-17 09:29:36 +01:00
Adrien Delorme f00ea7a166 more docs 2021-03-17 09:19:14 +01:00
Megan Marsh f12c89bd84 add legacy_isotime function to hcl funcs 2021-03-16 13:33:43 -07:00
Adrien Delorme bdc8ac2813 document redirects 2021-03-16 17:59:55 +01:00
Megan Marsh 0b5f8901cc changelog 2021-03-16 09:59:49 -07:00
Adrien Delorme 7ce5a2b9cf comment redirects for now 2021-03-16 17:59:47 +01:00
Adrien Delorme 2c48e04f1f add all plugins that we plan on moving out 2021-03-16 17:29:29 +01:00
Adrien Delorme dba5171fa2 improve wording some more 2021-03-16 13:59:24 +01:00
Adrien Delorme a1de1559bf improve implicit plugin wording 2021-03-16 13:55:01 +01:00
Adrien Delorme 5497139f2a better init wording 2021-03-16 13:36:42 +01:00
Megan Marsh 64a3219f69 fix error messaging in wrappedmain. Stderr gets eaten by panicwrap, so we need to write to stdout, which then gets unpacked into error and output messages using the ErrorPrefix and OutputPrefix (#10766) 2021-03-16 11:21:00 +01:00
Megan Marsh 60c961c021 Merge pull request #10457 from teddylear/feature/recursivefmt-2
Adding recursive flag to formatter to format subdirectories
2021-03-15 11:01:01 -07:00
Adrien Delorme 172cec7223 better wording for implicitly required plugins 2021-03-15 17:13:58 +01:00
Adrien Delorme f32b67c3bb Simplify error message when config file can't be "stat'd" (#10763)
* remove confusing message when a stat error happens while trying to list HCL2 files

* leave early if our first GetHCL2Files has errors
2021-03-15 14:07:07 +01:00
Adrien Delorme 160d932cce remove weir "Cannot tell wether " + path + " is a directory" error 2021-03-15 12:04:16 +01:00
Adrien Delorme e0fe579837 un-remove tests 2021-03-15 12:00:19 +01:00
Adrien Delorme fe21ff905d test that folders containing a - file won't hang forever 2021-03-15 11:51:21 +01:00
Adrien Delorme 8ee8420408 simplify return 2021-03-15 11:49:03 +01:00
Adrien Delorme 25ee6a19a6 flatten if a little 2021-03-15 11:48:13 +01:00
Adrien Delorme a6321ac137 remove debug line 2021-03-15 11:46:07 +01:00
Adrien Delorme 832c0f2b2a actually run fmt tests and then remove debug statements 2021-03-15 11:41:14 +01:00
Kyle 33cf6bf454 Fix logic for checking for KMS keys (#10754) 2021-03-15 11:37:13 +01:00
teddylear 22d373c279 Adding more debug logic 2021-03-15 11:36:10 +01:00
Dom Del Nano 77ce2b39d8 Fix the version parsing in ChecksumFileEntry.init() so that plugins whose name contain v's can packer init (#10760)
* fix
* test
2021-03-15 11:31:21 +01:00
Shane Lee 4bbeec4733 Update urls for the bootstrap scripts used by salt-masterless provider (#10755)
* Fix salt masterless url. Use saltproject.io

* Specify Tls12
2021-03-12 14:59:34 -05:00
Sylvia Moss 7ae42bbb21 Update PULL_REQUEST_TEMPLATE.md (#10758) 2021-03-12 17:10:11 +01:00
finchr d1254a5e48 Fix for issue #7413 - Allow non-zero exit codes for inspec provisioner (#10723) 2021-03-12 16:47:21 +01:00
Wilken Rivera cf65b7b494 Remove remote plugin docs for exoscale (#10757)
* Remove remote plugin docs for exoscale

* Add link to github repo for Exoscale components
2021-03-12 10:13:52 -05:00
Adrien Delorme be7d7313c5 add tests for piping fmt 2021-03-12 11:25:10 +01:00
Adrien Delorme 7d30a5d79d remove duplicate tests 2021-03-12 11:18:38 +01:00
Adrien Delorme a115b428ac simplify fmt test case a little 2021-03-12 11:07:26 +01:00
Adrien Delorme 4e22147909 Merge remote-tracking branch 'origin/master' into pr/teddylear/10457 2021-03-12 10:38:04 +01:00
Megan Marsh f1017a19d3 update changelog 2021-03-11 16:58:02 -08:00
Megan Marsh 3ced522659 Merge pull request #10750 from hashicorp/azr-plugin-real-world-examples
Give a list of working projects to checkout
2021-03-11 16:43:00 -08:00
Megan Marsh 6c8e997d19 Update website/content/docs/plugins/creation/index.mdx 2021-03-11 16:42:55 -08:00
Megan Marsh 44f0be2314 Merge pull request #10748 from hashicorp/fix_virtualbox_winrmhost
make Packer respect winrm_host flag in virtualbox connect func
2021-03-11 16:41:37 -08:00
Wilken Rivera bf9bb7b5c7 Merge pull request #10738 from twiggy/patch-1
Wrap more than one extra var in quotes.
2021-03-11 18:43:49 -05:00
Thomas Dreibholz 1a5678dd86 Added VirtualBox ISO builder option to create additional disks (#10674) 2021-03-11 16:09:30 +01:00
Adrien Delorme b2d692c33d Give a list of working projects to checkout 2021-03-11 11:48:23 +01:00
Megan Marsh e8b3a0e3bf make virtualbox, hyperv, openstack, and parallels builders respect winrm_host by correctly passing communicator config Host() func to commhost instead of just SSHHost 2021-03-10 15:36:19 -08:00
Megan Marsh 9944031580 Merge pull request #10743 from hashicorp/fix_10547
modify logging to make overrides clearer in face of vagrant always st…
2021-03-10 09:49:26 -08:00
Megan Marsh 35604a98a7 actually use the partials created in code generation inside the digitalocean docs page (#10742) 2021-03-10 13:24:00 +01:00
Megan Marsh 8bb3df7121 modify logging to make overrides clearer in face of vagrant always streaming to stdout. Add tests for config override. Make sure that user overrides of ssh_host and ssh_port are respected. 2021-03-09 16:40:49 -08:00
Megan Marsh d2ec658e78 Merge pull request #10724 from jkl73/image-project-update
Update public GCP image project as gce-uefi-images is be deprecated
2021-03-09 14:42:03 -08:00
Megan Marsh bb54b8bf10 Merge pull request #10709 from hashicorp/stubout-post-processor-exoscale-import
Shim "exoscale-import" post-processor
2021-03-09 13:14:39 -08:00
Wilken Rivera 1e27138857 plugins: Update Packer plugin documentation with details for remote plugin docs (#10718)
* Add instructions for registering remote plugin documentation

* Add documentation to plugins page about tiers and namespaces

* Update tiers

* Update website/content/docs/plugins/creation/index.mdx

Co-authored-by: Megan Marsh <megan@hashicorp.com>

* Add missing section for single-component install

Co-authored-by: Megan Marsh <megan@hashicorp.com>
2021-03-09 13:06:11 -05:00
Adrien Delorme 08b0884521 Vet command/init.go 2021-03-09 16:16:08 +01:00
Adrien Delorme 3224438a34 vet 2021-03-09 16:16:08 +01:00
Adrien Delorme 2b4812837a Update main.go
show where to add maps
2021-03-09 16:16:07 +01:00
Adrien Delorme 123517aec1 add warning with what to when calling init on an implicitly required plugin 2021-03-09 16:16:07 +01:00
Adrien Delorme c4535b2552 Update types.required_plugins_test.go 2021-03-09 16:16:07 +01:00
Adrien Delorme 1d10da1126 better docs 2021-03-09 16:16:07 +01:00
Adrien Delorme 8f7b148cbb Update types.required_plugins.go 2021-03-09 16:16:07 +01:00
Adrien Delorme 924fb0f8f8 make sure renamed plugins don't match if not defined 2021-03-09 16:16:07 +01:00
Adrien Delorme df4c5a1314 actually parse hcl blocks 2021-03-09 16:16:07 +01:00
Adrien Delorme 37e494a6e8 add basic inferImplicitRequiredPluginFromBlocks + tests
this is not done; I think testing with an actual parsing will be better
2021-03-09 16:16:06 +01:00
Wilken Rivera 3c282de6c3 Add maps for statically vendored components
This change adds a new set of maps for builders, provisioners, and
post-processors that store reference to components that were once part
of Packer and are now vendored. This file acts as a single place for
defining this vendored components, which are then merged into the main
components maps to be used in Packer.

Quick test to ensure the exoscale-import post-processor is still loaded
```
// Validate that exoscale-import is in the know post-procoessors list
~>  packer.test build docker_centos_shell_provisioner.pkr.hcl
Error: Unknown post-processor type "badlynamed-import"

  on docker_centos_shell_provisioner.pkr.hcl line 18:
  (source code not available)

known post-processors: [ucloud-import digitalocean-import docker-push
googlecompute-export manifest vsphere-template docker-tag vsphere checksum
docker-import exoscale-import yandex-export compress googlecompute-import
yandex-import vagrant-cloud alicloud-import amazon-import artifice shell-local
docker-save vagrant]

// Validate that exoscale-import get loaded
~>  packer.test build docker_centos_shell_provisioner.pkr.hcl
Error: Failed preparing post-processor-block "exoscale-import" ""

  on docker_centos_shell_provisioner.pkr.hcl line 18:
  (source code not available)

4 error(s) occurred:

* api_key must be set
* api_secret must be set
* image_bucket must be set
* template_zone must be set

==> Wait completed after 2 microseconds

==> Builds finished but no artifacts were created.
```
2021-03-09 10:09:13 -05:00
Wilken Rivera beceace7b7 Move to remote plugin docs for exoscale 2021-03-09 10:04:04 -05:00
Wilken Rivera 6f23bc0d97 Vendor exoscale-import plugin
This change will vendor the new version of the exoscale-import
post-processor component, but remove all of its code from Packer. After
the v1.8.0 release this change should be removed entirely.

This vendor process is being used as a workaround for decoupling the
exoscale-import component without causing a breaking change in Packer.

Users of Exoscale are encouraged to leverage `packer init` for
installing the latest version of packer-plugin-exoscale.
2021-03-09 10:02:30 -05:00
Wilken Rivera edd4567096 Remove plugin registration generation step
This change removes the generation of command/plugin.go so that plugin
registration can be managed manually. As we begin to break out plugins
we will need to begin modifying this file, possibly with stubs to allow
for the removal of plugins without breaking Packer's backwards
  compatibility with 1.7.0. After 1.8.0 is released we should be able to
  revet these changes so that we can continue to generate the plugin
  file for those plugins core to Packer.
2021-03-09 10:02:02 -05:00
Marc Falzon 9a1f2d0c97 fixup! Remove "exoscale-import" post-processor 2021-03-09 10:01:38 -05:00
Marc Falzon 125a2f1f76 Remove "exoscale-import" post-processor
This change removes the `exoscale-import` post-processor from the
upstream Packer repository, following extraction as a standalone plugin
in a dedicated repository (https://github.com/exoscale/packer-post-processor-exoscale-import)
2021-03-09 10:01:05 -05:00
Wilken Rivera 3ac5046260 Merge pull request #10727 from tasha-marreiros/feature/gcp-windows-password-timeout-#10717
#10717 make googlecompute windows password timeout configurable
2021-03-09 09:40:51 -05:00
Tasha Marreiros 8c18f8fa6d amend email 2021-03-09 09:01:07 +00:00
Megan Marsh 0ea92f6369 Merge pull request #10736 from dreibh/dreibh/virtualbox-options-2
More options for VirtualBox builder: nested virtualisation and RTC time base
2021-03-08 14:48:17 -08:00
twiggy bf1046e970 Wrap more than one extra var in quotes.
When multiple extra vars are passed the list of vars must be wrapped in "s. At least with ansible-local it will not parse correctly leading to an error stating the second extra var is a playbook file that cannot be found.
2021-03-08 11:29:33 -06:00
Kris Fremen de50cadb5c docs: fix post-processor(checksum) hcl example. (#10734) 2021-03-08 13:03:39 +01:00
Thomas Dreibholz 4f2f9f8a1e Formatting fix. 2021-03-08 12:37:00 +01:00
Thomas Dreibholz 68f810891f Ran "make generate". 2021-03-08 12:29:00 +01:00
Thomas Dreibholz be8b2968bd Added options for VRAM size, 3D acceleration and EFI screen size. 2021-03-08 12:29:00 +01:00
Thomas Dreibholz 4c9f3eb9ca Added options for nested virtualisation and RTC time base. 2021-03-08 12:29:00 +01:00
Kennith Leung f4caf5978f doc: fix sources typo (#10733) 2021-03-08 10:34:05 +01:00
Megan Marsh cd93957225 Merge pull request #10695 from hashicorp/docker_vendoring
Initial docker extraction
2021-03-05 16:26:55 -08:00
Megan Marsh 71b815a5fd reword commits 2021-03-05 16:07:32 -08:00
Wilken Rivera 79481ed7ec Add vendored components map as opposed to removing code generation for command/plugin.go 2021-03-05 15:44:04 -05:00
Wilken Rivera a101d46589 update modules.txt 2021-03-05 15:33:35 -05:00
Wilken Rivera 3058c437a3 Register remote plugins docs with https://packer.io 2021-03-05 15:33:34 -05:00
Wilken Rivera 10e1573930 Remove docker documentation from website 2021-03-05 15:33:34 -05:00
Megan Marsh c3e48ebb71 add vendored files 2021-03-05 15:33:34 -05:00
Megan Marsh 04cbcd7ae9 add docker vendoring to modules.txt 2021-03-05 15:33:34 -05:00
Megan Marsh 1c3c1f17d9 stop generating plugins file to make it possible to vendor plugins 2021-03-05 15:33:34 -05:00
Megan Marsh 9331afcf80 revendor 2021-03-05 15:33:34 -05:00
Megan Marsh a5b0e37d7e docker extraction POC 2021-03-05 15:33:34 -05:00
Hosh 6b5a3dacd4 Fix multiple files downloading overwrites same file (#10711) 2021-03-05 18:06:47 +01:00
Jiankun Lu 22cb31cb7b Update public GCP image project as gce-uefi-images is be deprecated 2021-03-03 16:12:25 -08:00
teddylear 0637601eda Fixing recursive formatting tests to work on all platforms 2021-02-11 22:08:36 -05:00
teddylear d85286e228 Merging in master 2021-02-10 17:44:11 -05:00
teddylear d3754e3021 Updating recursive formatter tests to be cleaner and table driven 2021-02-06 18:02:26 -05:00
Adrien Delorme ab7e89781a empty commit to check if I can push 2021-02-06 18:02:26 -05:00
teddylear 40a97e29db Clean up recursive format tests to be more accurate 2021-02-06 18:02:26 -05:00
teddylear 93df53a275 Refactor recursive formatting test cases to be table driven 2021-02-06 18:02:26 -05:00
teddylear 6adf1f6659 Fixing recursive fmt tests syntax and adding test case when recursive
option is off
2021-02-06 18:02:26 -05:00
teddylear 261abe0cae Setting recursive fmt to false, updatting recursive fmt test to validate
formatted files
2021-02-06 18:02:26 -05:00
teddylear ab4b3a8465 Adding recursive flag to formatter to format subdirectories 2021-02-06 18:02:23 -05:00
521 changed files with 61024 additions and 17609 deletions
+1
View File
@@ -6,6 +6,7 @@
*.mdx text eol=lf
*.ps1 text eol=lf
*.hcl text eol=lf
*.tmpl text eol=lf
*.txt text eol=lf
go.mod text eol=lf
go.sum text eol=lf
+6
View File
@@ -11,6 +11,12 @@ contribute to the project, read on. This document will cover what we're looking
for. By addressing all the points we're looking for, it raises the chances we
can quickly merge or address your contributions.
When contributing in any way to the Packer project (new issue, PR, etc), please
be aware that our team identifies with many gender pronouns. Please remember to
use nonbinary pronouns (they/them) and gender neutral language ("Hello folks")
when addressing our team. For more reading on our code of conduct, please see the
[HashiCorp community guidelines](https://www.hashicorp.com/community-guidelines).
## Issues
### Reporting an Issue
+1 -1
View File
@@ -10,7 +10,7 @@ Describe the change you are making here!
Please include tests. Check out these examples:
- https://github.com/hashicorp/packer/blob/master/builder/virtualbox/common/ssh_config_test.go#L19-L37
- https://github.com/hashicorp/packer/blob/master/builder/parallels/common/ssh_config_test.go#L34
- https://github.com/hashicorp/packer/blob/master/post-processor/compress/post-processor_test.go#L153-L182
If your PR resolves any open issue(s), please indicate them like this so they will be closed when your PR is merged:
+77
View File
@@ -0,0 +1,77 @@
const fs = require("fs");
const path = require("path");
const fetchPluginDocs = require("../../website/components/remote-plugin-docs/utils/fetch-plugin-docs");
const COLOR_RESET = "\x1b[0m";
const COLOR_GREEN = "\x1b[32m";
const COLOR_BLUE = "\x1b[34m";
const COLOR_RED = "\x1b[31m";
async function checkPluginDocs() {
const failureMessages = [];
const pluginsPath = "website/data/docs-remote-plugins.json";
const pluginsFile = fs.readFileSync(path.join(process.cwd(), pluginsPath));
const pluginEntries = JSON.parse(pluginsFile);
const entriesCount = pluginEntries.length;
console.log(`\nResolving plugin docs from ${entriesCount} repositories …`);
for (var i = 0; i < entriesCount; i++) {
const pluginEntry = pluginEntries[i];
const { title, repo, version } = pluginEntry;
console.log(`\n${COLOR_BLUE}${repo}${COLOR_RESET} | ${title}`);
console.log(`Fetching docs from release "${version}" …`);
try {
const undefinedProps = ["title", "repo", "version", "path"].filter(
(key) => typeof pluginEntry[key] == "undefined"
);
if (undefinedProps.length > 0) {
throw new Error(
`Failed to validate plugin docs config. Undefined configuration properties ${JSON.stringify(
undefinedProps
)} found for "${
title || pluginEntry.path || repo
}". In "website/data/docs-remote-plugins.json", please ensure the missing properties ${JSON.stringify(
undefinedProps
)} are defined. Additional information on this configuration can be found in "website/README.md".`
);
}
const docsMdxFiles = await fetchPluginDocs({ repo, tag: version });
const mdxFilesByComponent = docsMdxFiles.reduce((acc, mdxFile) => {
const componentType = mdxFile.filePath.split("/")[1];
if (!acc[componentType]) acc[componentType] = [];
acc[componentType].push(mdxFile);
return acc;
}, {});
console.log(`${COLOR_GREEN}Found valid docs:${COLOR_RESET}`);
Object.keys(mdxFilesByComponent).forEach((component) => {
const componentFiles = mdxFilesByComponent[component];
console.log(` ${component}`);
componentFiles.forEach(({ filePath }) => {
const pathFromComponent = filePath.split("/").slice(2).join("/");
console.log(` ├── ${pathFromComponent}`);
});
});
} catch (err) {
console.log(`${COLOR_RED}${err}${COLOR_RESET}`);
failureMessages.push(`\n${COLOR_RED}× ${repo}: ${COLOR_RESET}${err}`);
}
}
if (failureMessages.length === 0) {
console.log(
`\n---\n\n${COLOR_GREEN}Summary: Successfully resolved all plugin docs.`
);
pluginEntries.forEach((e) =>
console.log(`${COLOR_GREEN}${e.repo}${COLOR_RESET}`)
);
console.log("");
} else {
console.log(
`\n---\n\n${COLOR_RED}Summary: Failed to fetch docs for ${failureMessages.length} plugin(s):`
);
failureMessages.forEach((err) => console.log(err));
console.log("");
process.exit(1);
}
}
checkPluginDocs();
+29
View File
@@ -0,0 +1,29 @@
#
# This GitHub action checks plugin repositories for valid docs.
#
# This provides a quick assessment on PRs of whether
# there might be issues with docs in plugin repositories.
#
# This is intended to help debug Vercel build issues, which
# may or may not be related to docs in plugin repositories.
name: "website: Check plugin docs"
on:
pull_request:
paths:
- "website/**"
schedule:
- cron: "45 0 * * *"
jobs:
check-plugin-docs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup Node
uses: actions/setup-node@v1
- name: Install Dependencies
run: npm i isomorphic-unfetch adm-zip gray-matter
- name: Fetch and validate plugin docs
run: node .github/workflows/check-plugin-docs.js
+1 -1
View File
@@ -7,7 +7,7 @@ name: Check markdown links on modified website files
jobs:
vercel-deployment-poll:
runs-on: ubuntu-latest
timeout-minutes: 3 #cancel job if no deployment is found within x minutes
timeout-minutes: 5 #cancel job if no deployment is found within x minutes
outputs:
url: ${{ steps.waitForVercelPreviewDeployment.outputs.url }}
steps:
+18
View File
@@ -22,3 +22,21 @@ poll "closed_issue_locker" "locker" {
If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.
EOF
}
poll "label_issue_migrater" "remote_plugin_migrater" {
schedule = "0 20 * * * *"
new_owner = "hashicorp"
repo_prefix = "packer-plugin-"
label_prefix = "remote-plugin/"
excluded_label_prefixes = ["communicator/"]
excluded_labels = ["build", "core", "new-plugin-contribution", "website"]
issue_header = <<-EOF
_This issue was originally opened by @${var.user} as ${var.repository}#${var.issue_number}. It was migrated here as a result of the [Packer plugin split](https://github.com/hashicorp/packer/issues/8610#issuecomment-770034737). The original body of the issue is below._
<hr>
EOF
migrated_comment = "This issue has been automatically migrated to ${var.repository}#${var.issue_number} because it looks like an issue with that plugin. If you believe this is _not_ an issue with the plugin, please reply to ${var.repository}#${var.issue_number}."
}
+89 -2
View File
@@ -1,18 +1,105 @@
## 1.7.1 (Upcoming)
### FEATURES
### NOTES:
* builder/docker: Has been vendored in this release and will no longer be
updated with Packer core. In Packer v1.8.0 the plugin will be removed
entirely. The `docker` builder will continue to work as expected until
then, but for the latest offerings of the Docker plugin, users are
encourage to use the `packer init` command to install the latest release
version. For more details see [Installing Packer
Plugins](https://www.packer.io/docs/plugins#installing- plugins)
* post-processor/docker-\*: Have been vendored in this release and will no
longer be updated with Packer core. In Packer v1.8.0 the plugin will be
removed entirely. The `docker` builder will continue to work as expected
until then, but for the latest offerings of the Docker plugin, users are
encourage to use the `packer init` command to install the latest release
version. For more details see [Installing Packer
Plugins](https://www.packer.io/docs/plugins#installing- plugins)
* post-processor/exoscale-import: Has been vendored in this release and will no
longer be updated with Packer core. In Packer v1.8.0 the plugin will be
removed entirely. The `exoscale-import` post-processor will continue to
work as expected until then, but for the latest offerings of the Exoscale
plugin, users are encourage to use the `packer init` command to install the
latest release version. For more details see [Exoscale Plugin
Repostiroy](https://github.com/exoscale/packer-plugin-exoscale). [GH-10709]
### IMPROVEMENTS
* builder/amazon: allow creation of ebs snapshots wihtout volumes. [GH-9591]
* builder/amazon: Fix issue for multi-region AMI build that fail when
encrypting with KMS and sharing across accounts. [GH-10754]
* builder/azure: Add client_cert_token_timeout option. [GH-10528]
* builder/google: Make Windows password timeout configurable. [GH-10727]
* builder/google: Update public GCP image project as gce-uefi-images are
deprecated. [GH-10724]
* builder/qemu: Added firmware option. [GH-10683]
* builder/scaleway: add support for timeout in shutdown step. [GH-10503]
* builder/vagrant: Fix logging to be clearer when Vagrant builder overrides
values retrieved from vagrant's ssh_config call. [GH-10743]
* builder/virtualbox: Added ISO builder option to create additional disks.
[GH-10674]
* builder/virtualbox: Add options for nested virtualisation and RTC time base.
[GH-10736]
* builder/virtualbox: Add template options for chipset, firmware, nic, graphics
controller, and audio controller. [GH-10671]
* builder/virtualbox: Support for "virtio" storage and ISO drive. [GH-10632]
* builder/vmware: Added "attach_snapshot" parameter to vmware vmx builder.
[GH-10651]
* command/fmt: Adding recursive flag to formatter to format subdirectories.
[GH-10457]
* core: Change template parsing error to include warning about file extensions.
[GH-10652]
* core: Update to gopsutil v3.21.1 to allow builds to work for darwin arm64.
[GH-10697]
* hcl2_upgrade: hcl2_upgrade command can now upgrade json var-files [GH-10676]
### BUG FIXES
* buider/azure: Update builder to ensure a proper clean up Azure temporary
managed Os disks. [GH-10713]
* builder/amazon: Update amazon SDK to fix an SSO login issue. [GH-10668]
* builder/azure: Don't overwrite subscription id if unset. [GH-10659]
* builder/azure: Set default for the parameter client_cert_token_timeout
[GH-10783]
* builder/google: Add new configuration field `windows_password_timeout` to
allow user to set configurable timeouts. [GH-10727]
* builder/hyperv: Make Packer respect winrm_host flag in winrm connect func.
[GH-10748]
* builder/openstack: Make Packer respect winrm_host flag in winrm connect func.
[GH-10748]
* builder/oracle-oci: Update Oracle Go SDK to fix issue with reading key file.
[GH-10560]
[GH-10560] [GH-10774]
* builder/parallels: Make Packer respect winrm_host flag in winrm connect func.
[GH-10748]
* builder/proxmox: Fixes issue when using `additional_iso_files` in HCL enabled
templates. [GH-10772]
* builder/qemu: Make Packer respect winrm_host flag in winrm connect func.
[GH-10748]
* builder/virtualbox: Make Packer respect winrm_host flag in winrm connect
func. [GH-10748]
* builder/vmware: Added a fallback file check when trying to determine the
network-mapping configuration. [GH-10543]
* builder/vsphere: Fix issue where boot command would fail the build do to a
key typing error. This change will now retry to type the key on error
before giving up. [GH-10541]
* core/hcl2_upgrade: Check for nil config map when provisioner/post-processor
doesn't have config. [GH-10730]
* core/hcl2_upgrade: Make hcl2_upgrade command correctly translate
pause_before. [GH-10654]
* core/hcl2_upgrade: Make json variables using template engines get stored as
locals so they can be properly interpolated. [GH-10685]
* core/init: Fixes issue where `packer init` was failing to install valid
plugins containing a 'v' within its name. [GH-10760]
* core: Packer will now show a proper error message when failing to load the
contents of PACKER_CONFIG. [GH-10766]
* core: Pin Packer to Golang 1.16 to fix code generation issues. [GH-10702]
* core: Templates previously could not interpolate the environment variable
PACKER_LOG_PATH. [GH-10660]
* provisioner/chef-solo: HCL2 templates can support the json_string option.
[GH-10655]
* provisioner/inspec: Add new configuration field `valid_exit_codes` to allow
for non-zero exit codes. [GH-10723]
* provisioner/salt-masterless: Update urls for the bootstrap scripts used by
salt-masterless provide. [GH-10755]
## 1.7.0 (February 17, 2021)
+1 -1
View File
@@ -150,7 +150,7 @@ type AccessConfig struct {
// environmental variable.
Token string `mapstructure:"token" required:"false"`
session *session.Session
// Get credentials from Hashicorp Vault's aws secrets engine. You must
// Get credentials from HashiCorp Vault's aws secrets engine. You must
// already have created a role to use. For more information about
// generating credentials via the Vault engine, see the [Vault
// docs.](https://www.vaultproject.io/api/secret/aws#generate-credentials)
+1 -1
View File
@@ -172,7 +172,7 @@ func (c *AMIConfig) Prepare(accessConfig *AccessConfig, ctx *interpolate.Context
// Prevent sharing of default KMS key encrypted volumes with other aws users
if len(c.AMIUsers) > 0 {
if len(c.AMIKmsKeyId) == 0 && c.AMIEncryptBootVolume.True() {
if len(c.AMIKmsKeyId) == 0 && len(c.AMIRegionKMSKeyIDs) == 0 && c.AMIEncryptBootVolume.True() {
errs = append(errs, fmt.Errorf("Cannot share AMI encrypted with default KMS key"))
}
if len(c.AMIRegionKMSKeyIDs) > 0 {
+115 -7
View File
@@ -20,12 +20,18 @@ package arm
// go test -v -timeout 90m -run TestBuilderAcc_.*
import (
"testing"
"bytes"
"context"
"errors"
"fmt"
"os"
"strings"
"testing"
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/azure/auth"
builderT "github.com/hashicorp/packer-plugin-sdk/acctest"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
)
const DeviceLoginAcceptanceTest = "DEVICELOGIN_TEST"
@@ -96,10 +102,15 @@ func TestBuilderAcc_ManagedDisk_Linux_AzureCLI(t *testing.T) {
return
}
var b Builder
builderT.Test(t, builderT.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Builder: &Builder{},
PreCheck: func() { testAuthPreCheck(t) },
Builder: &b,
Template: testBuilderAccManagedDiskLinuxAzureCLI,
Check: func([]packersdk.Artifact) error {
checkTemporaryGroupDeleted(t, &b)
return nil
},
})
}
@@ -112,15 +123,108 @@ func TestBuilderAcc_Blob_Windows(t *testing.T) {
}
func TestBuilderAcc_Blob_Linux(t *testing.T) {
var b Builder
builderT.Test(t, builderT.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Builder: &Builder{},
PreCheck: func() { testAuthPreCheck(t) },
Builder: &b,
Template: testBuilderAccBlobLinux,
Check: func([]packersdk.Artifact) error {
checkUnmanagedVHDDeleted(t, &b)
return nil
},
})
}
func testAccPreCheck(*testing.T) {}
func testAuthPreCheck(t *testing.T) {
_, err := auth.NewAuthorizerFromEnvironment()
if err != nil {
t.Fatalf("failed to auth to azure: %s", err)
}
}
func checkTemporaryGroupDeleted(t *testing.T, b *Builder) {
ui := testUi()
spnCloud, spnKeyVault, err := b.getServicePrincipalTokens(ui.Say)
if err != nil {
t.Fatalf("failed getting azure tokens: %s", err)
}
ui.Message("Creating test Azure Resource Manager (ARM) client ...")
azureClient, err := NewAzureClient(
b.config.ClientConfig.SubscriptionID,
b.config.SharedGalleryDestination.SigDestinationSubscription,
b.config.ResourceGroupName,
b.config.StorageAccount,
b.config.ClientConfig.CloudEnvironment(),
b.config.SharedGalleryTimeout,
b.config.PollingDurationTimeout,
spnCloud,
spnKeyVault)
if err != nil {
t.Fatalf("failed to create azure client: %s", err)
}
// Validate resource group has been deleted
_, err = azureClient.GroupsClient.Get(context.Background(), b.config.tmpResourceGroupName)
if err == nil || !resourceNotFound(err) {
t.Fatalf("failed validating resource group deletion: %s", err)
}
}
func checkUnmanagedVHDDeleted(t *testing.T, b *Builder) {
ui := testUi()
spnCloud, spnKeyVault, err := b.getServicePrincipalTokens(ui.Say)
if err != nil {
t.Fatalf("failed getting azure tokens: %s", err)
}
azureClient, err := NewAzureClient(
b.config.ClientConfig.SubscriptionID,
b.config.SharedGalleryDestination.SigDestinationSubscription,
b.config.ResourceGroupName,
b.config.StorageAccount,
b.config.ClientConfig.CloudEnvironment(),
b.config.SharedGalleryTimeout,
b.config.PollingDurationTimeout,
spnCloud,
spnKeyVault)
if err != nil {
t.Fatalf("failed to create azure client: %s", err)
}
// validate temporary os blob was deleted
blob := azureClient.BlobStorageClient.GetContainerReference("images").GetBlobReference(b.config.tmpOSDiskName)
_, err = blob.BreakLease(nil)
if err != nil && !strings.Contains(err.Error(), "BlobNotFound") {
t.Fatalf("failed validating deletion of unmanaged vhd: %s", err)
}
// Validate resource group has been deleted
_, err = azureClient.GroupsClient.Get(context.Background(), b.config.tmpResourceGroupName)
if err == nil || !resourceNotFound(err) {
t.Fatalf("failed validating resource group deletion: %s", err)
}
}
func resourceNotFound(err error) bool {
derr := autorest.DetailedError{}
return errors.As(err, &derr) && derr.StatusCode == 404
}
func testUi() *packersdk.BasicUi {
return &packersdk.BasicUi{
Reader: new(bytes.Buffer),
Writer: new(bytes.Buffer),
ErrorWriter: new(bytes.Buffer),
}
}
const testBuilderAccManagedDiskWindows = `
{
"variables": {
@@ -155,6 +259,7 @@ const testBuilderAccManagedDiskWindows = `
}]
}
`
const testBuilderAccManagedDiskWindowsBuildResourceGroup = `
{
"variables": {
@@ -287,6 +392,7 @@ const testBuilderAccManagedDiskLinux = `
}]
}
`
const testBuilderAccManagedDiskLinuxDeviceLogin = `
{
"variables": {
@@ -379,6 +485,7 @@ const testBuilderAccBlobLinux = `
}]
}
`
const testBuilderAccManagedDiskLinuxAzureCLI = `
{
"builders": [{
@@ -388,7 +495,8 @@ const testBuilderAccManagedDiskLinuxAzureCLI = `
"managed_image_resource_group_name": "packer-acceptance-test",
"managed_image_name": "testBuilderAccManagedDiskLinuxAzureCLI-{{timestamp}}",
"temp_resource_group_name": "packer-acceptance-test-managed-cli",
"os_type": "Linux",
"image_publisher": "Canonical",
"image_offer": "UbuntuServer",
+78 -43
View File
@@ -6,6 +6,7 @@ import (
"fmt"
"net/url"
"strings"
"sync"
"time"
"github.com/hashicorp/packer-plugin-sdk/multistep"
@@ -15,16 +16,17 @@ import (
)
type StepDeployTemplate struct {
client *AzureClient
deploy func(ctx context.Context, resourceGroupName string, deploymentName string) error
delete func(ctx context.Context, deploymentName, resourceGroupName string) error
disk func(ctx context.Context, resourceGroupName string, computeName string) (string, string, error)
deleteDisk func(ctx context.Context, imageType string, imageName string, resourceGroupName string) error
say func(message string)
error func(e error)
config *Config
factory templateFactoryFunc
name string
client *AzureClient
deploy func(ctx context.Context, resourceGroupName string, deploymentName string) error
delete func(ctx context.Context, deploymentName, resourceGroupName string) error
disk func(ctx context.Context, resourceGroupName string, computeName string) (string, string, error)
deleteDisk func(ctx context.Context, imageType string, imageName string, resourceGroupName string) error
deleteDeployment func(ctx context.Context, state multistep.StateBag) error
say func(message string)
error func(e error)
config *Config
factory templateFactoryFunc
name string
}
func NewStepDeployTemplate(client *AzureClient, ui packersdk.Ui, config *Config, deploymentName string, factory templateFactoryFunc) *StepDeployTemplate {
@@ -41,6 +43,7 @@ func NewStepDeployTemplate(client *AzureClient, ui packersdk.Ui, config *Config,
step.delete = step.deleteDeploymentResources
step.disk = step.getImageDetails
step.deleteDisk = step.deleteImage
step.deleteDeployment = step.deleteDeploymentObject
return step
}
@@ -58,32 +61,45 @@ func (s *StepDeployTemplate) Run(ctx context.Context, state multistep.StateBag)
func (s *StepDeployTemplate) Cleanup(state multistep.StateBag) {
defer func() {
err := s.deleteTemplate(context.Background(), state)
err := s.deleteDeployment(context.Background(), state)
if err != nil {
s.say(s.client.LastError.Error())
s.say(err.Error())
}
}()
// Only clean up if this is an existing resource group that has been verified to exist.
// ArmIsResourceGroupCreated is set in step_create_resource_group to true, when Packer has verified that the resource group exists.
// ArmIsExistingResourceGroup is set to true when build_resource_group is set in the Packer configuration.
existingResourceGroup := state.Get(constants.ArmIsExistingResourceGroup).(bool)
resourceGroupCreated := state.Get(constants.ArmIsResourceGroupCreated).(bool)
if !existingResourceGroup || !resourceGroupCreated {
return
}
ui := state.Get("ui").(packersdk.Ui)
ui.Say("\nThe resource group was not created by Packer, deleting individual resources ...")
ui.Say("\nDeleting individual resources ...")
deploymentName := s.name
resourceGroupName := state.Get(constants.ArmResourceGroupName).(string)
err := s.deleteDeploymentResources(context.TODO(), deploymentName, resourceGroupName)
// Get image disk details before deleting the image; otherwise we won't be able to
// delete the disk as the image request will return a 404
computeName := state.Get(constants.ArmComputeName).(string)
imageType, imageName, err := s.disk(context.TODO(), resourceGroupName, computeName)
if err != nil && !strings.Contains(err.Error(), "ResourceNotFound") {
ui.Error(fmt.Sprintf("Could not retrieve OS Image details: %s", err))
}
err = s.delete(context.TODO(), deploymentName, resourceGroupName)
if err != nil {
s.reportIfError(err, resourceGroupName)
}
NewStepDeleteAdditionalDisks(s.client, ui).Run(context.TODO(), state)
// The disk was not found on the VM, this is an error.
if imageType == "" && imageName == "" {
ui.Error(fmt.Sprintf("Failed to find temporary OS disk on VM. Please delete manually.\n\n"+
"VM Name: %s\n"+
"Error: %s", computeName, err))
return
}
ui.Say(fmt.Sprintf(" Deleting -> %s : '%s'", imageType, imageName))
err = s.deleteDisk(context.TODO(), imageType, imageName, resourceGroupName)
if err != nil {
ui.Error(fmt.Sprintf("Error deleting resource. Please delete manually.\n\n"+
"Name: %s\n"+
"Error: %s", imageName, err))
}
}
func (s *StepDeployTemplate) deployTemplate(ctx context.Context, resourceGroupName string, deploymentName string) error {
@@ -106,7 +122,7 @@ func (s *StepDeployTemplate) deployTemplate(ctx context.Context, resourceGroupNa
return err
}
func (s *StepDeployTemplate) deleteTemplate(ctx context.Context, state multistep.StateBag) error {
func (s *StepDeployTemplate) deleteDeploymentObject(ctx context.Context, state multistep.StateBag) error {
deploymentName := s.name
resourceGroupName := state.Get(constants.ArmResourceGroupName).(string)
ui := state.Get("ui").(packersdk.Ui)
@@ -222,6 +238,8 @@ func (s *StepDeployTemplate) deleteDeploymentResources(ctx context.Context, depl
return err
}
resources := map[string]string{}
for deploymentOperations.NotDone() {
deploymentOperation := deploymentOperations.Value()
// Sometimes an empty operation is added to the list by Azure
@@ -233,30 +251,47 @@ func (s *StepDeployTemplate) deleteDeploymentResources(ctx context.Context, depl
resourceName := *deploymentOperation.Properties.TargetResource.ResourceName
resourceType := *deploymentOperation.Properties.TargetResource.ResourceType
s.say(fmt.Sprintf(" -> %s : '%s'", resourceType, resourceName))
err = retry.Config{
Tries: 10,
RetryDelay: (&retry.Backoff{InitialBackoff: 10 * time.Second, MaxBackoff: 600 * time.Second, Multiplier: 2}).Linear,
}.Run(ctx, func(ctx context.Context) error {
err := deleteResource(ctx, s.client,
resourceType,
resourceName,
resourceGroupName)
if err != nil {
s.reportIfError(err, resourceName)
}
return nil
})
if err != nil {
s.reportIfError(err, resourceName)
}
s.say(fmt.Sprintf("Adding to deletion queue -> %s : '%s'", resourceType, resourceName))
resources[resourceType] = resourceName
if err = deploymentOperations.Next(); err != nil {
return err
}
}
var wg sync.WaitGroup
wg.Add(len(resources))
for resourceType, resourceName := range resources {
go func(resourceType, resourceName string) {
defer wg.Done()
retryConfig := retry.Config{
Tries: 10,
RetryDelay: (&retry.Backoff{InitialBackoff: 10 * time.Second, MaxBackoff: 600 * time.Second, Multiplier: 2}).Linear,
}
err = retryConfig.Run(ctx, func(ctx context.Context) error {
s.say(fmt.Sprintf("Attempting deletion -> %s : '%s'", resourceType, resourceName))
err := deleteResource(ctx, s.client,
resourceType,
resourceName,
resourceGroupName)
if err != nil {
s.say(fmt.Sprintf("Error deleting resource. Will retry.\n"+
"Name: %s\n"+
"Error: %s\n", resourceName, err.Error()))
}
return err
})
if err != nil {
s.reportIfError(err, resourceName)
}
}(resourceType, resourceName)
}
s.say("Waiting for deletion of all resources...")
wg.Wait()
return nil
}
@@ -6,6 +6,7 @@ import (
"testing"
"github.com/hashicorp/packer-plugin-sdk/multistep"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hashicorp/packer/builder/azure/common/constants"
)
@@ -108,11 +109,97 @@ func TestStepDeployTemplateDeleteImageShouldFailWithInvalidImage(t *testing.T) {
}
}
func TestStepDeployTemplateCleanupShouldDeleteManagedOSImageInExistingResourceGroup(t *testing.T) {
var deleteDiskCounter = 0
var testSubject = createTestStepDeployTemplateDeleteOSImage(&deleteDiskCounter)
stateBag := createTestStateBagStepDeployTemplate()
stateBag.Put(constants.ArmIsManagedImage, true)
stateBag.Put(constants.ArmIsExistingResourceGroup, true)
stateBag.Put(constants.ArmIsResourceGroupCreated, true)
stateBag.Put("ui", packersdk.TestUi(t))
testSubject.Cleanup(stateBag)
if deleteDiskCounter != 1 {
t.Fatalf("Expected DeployTemplate Cleanup to invoke deleteDisk 1 time, but invoked %d times", deleteDiskCounter)
}
}
func TestStepDeployTemplateCleanupShouldDeleteManagedOSImageInTemporaryResourceGroup(t *testing.T) {
var deleteDiskCounter = 0
var testSubject = createTestStepDeployTemplateDeleteOSImage(&deleteDiskCounter)
stateBag := createTestStateBagStepDeployTemplate()
stateBag.Put(constants.ArmIsManagedImage, true)
stateBag.Put(constants.ArmIsExistingResourceGroup, false)
stateBag.Put(constants.ArmIsResourceGroupCreated, true)
stateBag.Put("ui", packersdk.TestUi(t))
testSubject.Cleanup(stateBag)
if deleteDiskCounter != 1 {
t.Fatalf("Expected DeployTemplate Cleanup to invoke deleteDisk 1 times, but invoked %d times", deleteDiskCounter)
}
}
func TestStepDeployTemplateCleanupShouldDeleteVHDOSImageInExistingResourceGroup(t *testing.T) {
var deleteDiskCounter = 0
var testSubject = createTestStepDeployTemplateDeleteOSImage(&deleteDiskCounter)
stateBag := createTestStateBagStepDeployTemplate()
stateBag.Put(constants.ArmIsManagedImage, false)
stateBag.Put(constants.ArmIsExistingResourceGroup, true)
stateBag.Put(constants.ArmIsResourceGroupCreated, true)
stateBag.Put("ui", packersdk.TestUi(t))
testSubject.Cleanup(stateBag)
if deleteDiskCounter != 1 {
t.Fatalf("Expected DeployTemplate Cleanup to invoke deleteDisk 1 time, but invoked %d times", deleteDiskCounter)
}
}
func TestStepDeployTemplateCleanupShouldVHDOSImageInTemporaryResourceGroup(t *testing.T) {
var deleteDiskCounter = 0
var testSubject = createTestStepDeployTemplateDeleteOSImage(&deleteDiskCounter)
stateBag := createTestStateBagStepDeployTemplate()
stateBag.Put(constants.ArmIsManagedImage, false)
stateBag.Put(constants.ArmIsExistingResourceGroup, false)
stateBag.Put(constants.ArmIsResourceGroupCreated, true)
stateBag.Put("ui", packersdk.TestUi(t))
testSubject.Cleanup(stateBag)
if deleteDiskCounter != 1 {
t.Fatalf("Expected DeployTemplate Cleanup to invoke deleteDisk 1 times, but invoked %d times", deleteDiskCounter)
}
}
func createTestStateBagStepDeployTemplate() multistep.StateBag {
stateBag := new(multistep.BasicStateBag)
stateBag.Put(constants.ArmDeploymentName, "Unit Test: DeploymentName")
stateBag.Put(constants.ArmResourceGroupName, "Unit Test: ResourceGroupName")
stateBag.Put(constants.ArmComputeName, "Unit Test: ComputeName")
return stateBag
}
func createTestStepDeployTemplateDeleteOSImage(deleteDiskCounter *int) *StepDeployTemplate {
return &StepDeployTemplate{
deploy: func(context.Context, string, string) error { return nil },
say: func(message string) {},
error: func(e error) {},
deleteDisk: func(ctx context.Context, imageType string, imageName string, resourceGroupName string) error {
*deleteDiskCounter++
return nil
},
disk: func(ctx context.Context, resourceGroupName, computeName string) (string, string, error) {
return "Microsoft.Compute/disks", "", nil
},
delete: func(ctx context.Context, deploymentName, resourceGroupName string) error {
return nil
},
deleteDeployment: func(ctx context.Context, state multistep.StateBag) error {
return nil
},
}
}
+1 -1
View File
@@ -165,7 +165,7 @@ func (c Config) Validate(errs *packersdk.MultiError) {
if _, err := os.Stat(c.ClientCertPath); err != nil {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("client_cert_path is not an accessible file: %v", err))
}
if c.ClientCertExpireTimeout < 5*time.Minute {
if c.ClientCertExpireTimeout != 0 && c.ClientCertExpireTimeout < 5*time.Minute {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("client_cert_token_timeout will expire within 5 minutes, please set a value greater than 5 minutes"))
}
return
+1 -6
View File
@@ -60,12 +60,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
// Build the steps.
steps := []multistep.Step{
&stepPrepareConfig{},
&commonsteps.StepHTTPServer{
HTTPDir: b.config.HTTPDir,
HTTPPortMin: b.config.HTTPPortMin,
HTTPPortMax: b.config.HTTPPortMax,
HTTPAddress: b.config.HTTPAddress,
},
commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig),
&stepKeypair{
Debug: b.config.PackerDebug,
Comm: &b.config.Comm,
+2
View File
@@ -19,6 +19,7 @@ type FlatConfig struct {
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"`
HTTPContent map[string]string `mapstructure:"http_content" cty:"http_content" hcl:"http_content"`
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"`
@@ -135,6 +136,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_content": &hcldec.AttrSpec{Name: "http_content", Type: cty.Map(cty.String), Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},
"http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false},
"http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false},
-11
View File
@@ -1,11 +0,0 @@
package docker
import (
"testing"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
)
func TestExportArtifact_impl(t *testing.T) {
var _ packersdk.Artifact = new(ExportArtifact)
}
-58
View File
@@ -1,58 +0,0 @@
package docker
import (
"errors"
"testing"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
)
func TestImportArtifact_impl(t *testing.T) {
var _ packersdk.Artifact = new(ImportArtifact)
}
func TestImportArtifactBuilderId(t *testing.T) {
a := &ImportArtifact{BuilderIdValue: "foo"}
if a.BuilderId() != "foo" {
t.Fatalf("bad: %#v", a.BuilderId())
}
}
func TestImportArtifactFiles(t *testing.T) {
a := &ImportArtifact{}
if a.Files() != nil {
t.Fatalf("bad: %#v", a.Files())
}
}
func TestImportArtifactId(t *testing.T) {
a := &ImportArtifact{IdValue: "foo"}
if a.Id() != "foo" {
t.Fatalf("bad: %#v", a.Id())
}
}
func TestImportArtifactDestroy(t *testing.T) {
d := new(MockDriver)
a := &ImportArtifact{
Driver: d,
IdValue: "foo",
}
// No error
if err := a.Destroy(); err != nil {
t.Fatalf("err: %s", err)
}
if !d.DeleteImageCalled {
t.Fatal("delete image should be called")
}
if d.DeleteImageId != "foo" {
t.Fatalf("bad: %#v", d.DeleteImageId)
}
// With an error
d.DeleteImageErr = errors.New("foo")
if err := a.Destroy(); err != d.DeleteImageErr {
t.Fatalf("err: %#v", err)
}
}
-11
View File
@@ -1,11 +0,0 @@
package docker
import (
"testing"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
)
func TestBuilder_implBuilder(t *testing.T) {
var _ packersdk.Builder = new(Builder)
}
-239
View File
@@ -1,239 +0,0 @@
package docker
import (
"crypto/sha256"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"os/exec"
"testing"
builderT "github.com/hashicorp/packer-plugin-sdk/acctest"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
)
// RenderConfig helps create dynamic packer template configs for parsing by
// builderT without having to write the config to a file.
func RenderConfig(builderConfig map[string]interface{}, provisionerConfig []map[string]interface{}) string {
// set up basic build template
t := map[string][]map[string]interface{}{
"builders": {
// Setup basic docker config
map[string]interface{}{
"type": "test",
"image": "ubuntu",
"discard": true,
},
},
"provisioners": []map[string]interface{}{},
}
// apply special builder overrides
for k, v := range builderConfig {
t["builders"][0][k] = v
}
// Apply special provisioner overrides
t["provisioners"] = append(t["provisioners"], provisionerConfig...)
j, _ := json.Marshal(t)
return string(j)
}
// TestUploadDownload verifies that basic upload / download functionality works
func TestUploadDownload(t *testing.T) {
if os.Getenv("PACKER_ACC") == "" {
t.Skip("This test is only run with PACKER_ACC=1")
}
dockerBuilderExtraConfig := map[string]interface{}{
"run_command": []string{"-d", "-i", "-t", "{{.Image}}", "/bin/sh"},
}
dockerProvisionerConfig := []map[string]interface{}{
{
"type": "file",
"source": "test-fixtures/onecakes/strawberry",
"destination": "/strawberry-cake",
},
{
"type": "file",
"source": "/strawberry-cake",
"destination": "my-strawberry-cake",
"direction": "download",
},
}
configString := RenderConfig(dockerBuilderExtraConfig, dockerProvisionerConfig)
// this should be a precheck
cmd := exec.Command("docker", "-v")
err := cmd.Run()
if err != nil {
t.Error("docker command not found; please make sure docker is installed")
}
builderT.Test(t, builderT.TestCase{
Builder: &Builder{},
Template: configString,
Check: func(a []packersdk.Artifact) error {
// Verify that the thing we downloaded is the same thing we sent up.
// Complain loudly if it isn't.
inputFile, err := ioutil.ReadFile("test-fixtures/onecakes/strawberry")
if err != nil {
return fmt.Errorf("Unable to read input file: %s", err)
}
outputFile, err := ioutil.ReadFile("my-strawberry-cake")
if err != nil {
return fmt.Errorf("Unable to read output file: %s", err)
}
if sha256.Sum256(inputFile) != sha256.Sum256(outputFile) {
return fmt.Errorf("Input and output files do not match\n"+
"Input:\n%s\nOutput:\n%s\n", inputFile, outputFile)
}
return nil
},
Teardown: func() error {
// Cleanup. Honestly I don't know why you would want to get rid
// of my strawberry cake. It's so tasty! Do you not like cake? Are you a
// cake-hater? Or are you keeping all the cake all for yourself? So selfish!
os.Remove("my-strawberry-cake")
return nil
},
})
}
// TestLargeDownload verifies that files are the appropriate size after being
// downloaded. This is to identify and fix the race condition in #2793. You may
// need to use github.com/cbednarski/rerun to verify since this problem occurs
// only intermittently.
func TestLargeDownload(t *testing.T) {
if os.Getenv("PACKER_ACC") == "" {
t.Skip("This test is only run with PACKER_ACC=1")
}
dockerProvisionerConfig := []map[string]interface{}{
{
"type": "shell",
"inline": []string{
"dd if=/dev/urandom of=/tmp/cupcake bs=1M count=2",
"dd if=/dev/urandom of=/tmp/bigcake bs=1M count=100",
"sync",
"md5sum /tmp/cupcake /tmp/bigcake",
},
},
{
"type": "file",
"source": "/tmp/cupcake",
"destination": "cupcake",
"direction": "download",
},
{
"type": "file",
"source": "/tmp/bigcake",
"destination": "bigcake",
"direction": "download",
},
}
configString := RenderConfig(map[string]interface{}{}, dockerProvisionerConfig)
// this should be a precheck
cmd := exec.Command("docker", "-v")
err := cmd.Run()
if err != nil {
t.Error("docker command not found; please make sure docker is installed")
}
builderT.Test(t, builderT.TestCase{
Builder: &Builder{},
Template: configString,
Check: func(a []packersdk.Artifact) error {
// Verify that the things we downloaded are the right size. Complain loudly
// if they are not.
//
// cupcake should be 2097152 bytes
// bigcake should be 104857600 bytes
cupcake, err := os.Stat("cupcake")
if err != nil {
t.Fatalf("Unable to stat cupcake file: %s", err)
}
cupcakeExpected := int64(2097152)
if cupcake.Size() != cupcakeExpected {
t.Errorf("Expected cupcake to be %d bytes; found %d", cupcakeExpected, cupcake.Size())
}
bigcake, err := os.Stat("bigcake")
if err != nil {
t.Fatalf("Unable to stat bigcake file: %s", err)
}
bigcakeExpected := int64(104857600)
if bigcake.Size() != bigcakeExpected {
t.Errorf("Expected bigcake to be %d bytes; found %d", bigcakeExpected, bigcake.Size())
}
// TODO if we can, calculate a sha inside the container and compare to the
// one we get after we pull it down. We will probably have to parse the log
// or ui output to do this because we use /dev/urandom to create the file.
// if sha256.Sum256(inputFile) != sha256.Sum256(outputFile) {
// t.Fatalf("Input and output files do not match\n"+
// "Input:\n%s\nOutput:\n%s\n", inputFile, outputFile)
// }
return nil
},
Teardown: func() error {
os.Remove("cupcake")
os.Remove("bigcake")
return nil
},
})
}
// TestFixUploadOwner verifies that owner of uploaded files is the user the container is running as.
func TestFixUploadOwner(t *testing.T) {
if os.Getenv("PACKER_ACC") == "" {
t.Skip("This test is only run with PACKER_ACC=1")
}
cmd := exec.Command("docker", "-v")
err := cmd.Run()
if err != nil {
t.Error("docker command not found; please make sure docker is installed")
}
dockerBuilderExtraConfig := map[string]interface{}{
"run_command": []string{"-d", "-i", "-t", "-u", "42", "{{.Image}}", "/bin/sh"},
}
testFixUploadOwnerProvisionersTemplate := []map[string]interface{}{
{
"type": "file",
"source": "test-fixtures/onecakes/strawberry",
"destination": "/tmp/strawberry-cake",
},
{
"type": "file",
"source": "test-fixtures/manycakes",
"destination": "/tmp/",
},
{
"type": "shell",
"inline": "touch /tmp/testUploadOwner",
},
{
"type": "shell",
"inline": []string{
"[ $(stat -c %u /tmp/strawberry-cake) -eq 42 ] || (echo 'Invalid owner of /tmp/strawberry-cake' && exit 1)",
"[ $(stat -c %u /tmp/testUploadOwner) -eq 42 ] || (echo 'Invalid owner of /tmp/testUploadOwner' && exit 1)",
"find /tmp/manycakes | xargs -n1 -IFILE /bin/sh -c '[ $(stat -c %u FILE) -eq 42 ] || (echo \"Invalid owner of FILE\" && exit 1)'",
},
},
}
configString := RenderConfig(dockerBuilderExtraConfig, testFixUploadOwnerProvisionersTemplate)
builderT.Test(t, builderT.TestCase{
Builder: &Builder{},
Template: configString,
})
}
-147
View File
@@ -1,147 +0,0 @@
package docker
import (
"io/ioutil"
"os"
"testing"
)
func testConfig() map[string]interface{} {
return map[string]interface{}{
"export_path": "foo",
"image": "bar",
}
}
func testConfigStruct(t *testing.T) *Config {
var c Config
warns, errs := c.Prepare(testConfig())
if len(warns) > 0 {
t.Fatalf("bad: %#v", len(warns))
}
if errs != nil {
t.Fatalf("bad: %#v", errs)
}
return &c
}
func testConfigErr(t *testing.T, warns []string, err error) {
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err == nil {
t.Fatal("should error")
}
}
func testConfigOk(t *testing.T, warns []string, err error) {
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err != nil {
t.Fatalf("bad: %s", err)
}
}
func TestConfigPrepare_exportPath(t *testing.T) {
td, err := ioutil.TempDir("", "packer")
if err != nil {
t.Fatalf("err: %s", err)
}
defer os.RemoveAll(td)
raw := testConfig()
// No export path. This is invalid. Previously this would not error during
// validation and as a result the failure would happen at build time.
delete(raw, "export_path")
var c Config
warns, errs := c.Prepare(raw)
testConfigErr(t, warns, errs)
// Good export path
raw["export_path"] = "good"
warns, errs = c.Prepare(raw)
testConfigOk(t, warns, errs)
// Bad export path (directory)
raw["export_path"] = td
warns, errs = c.Prepare(raw)
testConfigErr(t, warns, errs)
}
func TestConfigPrepare_exportPathAndCommit(t *testing.T) {
raw := testConfig()
// Export but no commit (explicit default)
raw["commit"] = false
warns, errs := (&Config{}).Prepare(raw)
testConfigOk(t, warns, errs)
// Commit AND export specified (invalid)
raw["commit"] = true
warns, errs = (&Config{}).Prepare(raw)
testConfigErr(t, warns, errs)
// Commit but no export
delete(raw, "export_path")
warns, errs = (&Config{}).Prepare(raw)
testConfigOk(t, warns, errs)
}
func TestConfigPrepare_exportDiscard(t *testing.T) {
raw := testConfig()
// Export but no discard (explicit default)
raw["discard"] = false
warns, errs := (&Config{}).Prepare(raw)
testConfigOk(t, warns, errs)
// Discard AND export (invalid)
raw["discard"] = true
warns, errs = (&Config{}).Prepare(raw)
testConfigErr(t, warns, errs)
// Discard but no export
raw["discard"] = true
delete(raw, "export_path")
warns, errs = (&Config{}).Prepare(raw)
testConfigOk(t, warns, errs)
}
func TestConfigPrepare_image(t *testing.T) {
raw := testConfig()
// No image
delete(raw, "image")
var c Config
warns, errs := c.Prepare(raw)
testConfigErr(t, warns, errs)
// Good image
raw["image"] = "path"
warns, errs = c.Prepare(raw)
testConfigOk(t, warns, errs)
}
func TestConfigPrepare_pull(t *testing.T) {
raw := testConfig()
// No pull set
delete(raw, "pull")
var c Config
warns, errs := c.Prepare(raw)
testConfigOk(t, warns, errs)
if !c.Pull {
t.Fatal("should pull by default")
}
// Pull set
raw["pull"] = false
warns, errs = c.Prepare(raw)
testConfigOk(t, warns, errs)
if c.Pull {
t.Fatal("should not pull")
}
}
-7
View File
@@ -1,7 +0,0 @@
package docker
import "testing"
func TestDockerDriver_impl(t *testing.T) {
var _ Driver = new(DockerDriver)
}
-7
View File
@@ -1,7 +0,0 @@
package docker
import "testing"
func TestMockDriver_impl(t *testing.T) {
var _ Driver = new(MockDriver)
}
-68
View File
@@ -1,68 +0,0 @@
package docker
import (
"context"
"errors"
"testing"
"github.com/hashicorp/packer-plugin-sdk/multistep"
)
func testStepCommitState(t *testing.T) multistep.StateBag {
state := testState(t)
state.Put("container_id", "foo")
return state
}
func TestStepCommit_impl(t *testing.T) {
var _ multistep.Step = new(StepCommit)
}
func TestStepCommit(t *testing.T) {
state := testStepCommitState(t)
step := new(StepCommit)
defer step.Cleanup(state)
driver := state.Get("driver").(*MockDriver)
driver.CommitImageId = "bar"
// run the step
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
t.Fatalf("bad action: %#v", action)
}
// verify we did the right thing
if !driver.CommitCalled {
t.Fatal("should've called")
}
// verify the ID is saved
idRaw, ok := state.GetOk("image_id")
if !ok {
t.Fatal("should've saved ID")
}
id := idRaw.(string)
if id != driver.CommitImageId {
t.Fatalf("bad: %#v", id)
}
}
func TestStepCommit_error(t *testing.T) {
state := testStepCommitState(t)
step := new(StepCommit)
defer step.Cleanup(state)
driver := state.Get("driver").(*MockDriver)
driver.CommitErr = errors.New("foo")
// run the step
if action := step.Run(context.Background(), state); action != multistep.ActionHalt {
t.Fatalf("bad action: %#v", action)
}
// verify the ID is not saved
if _, ok := state.GetOk("image_id"); ok {
t.Fatal("shouldn't save image ID")
}
}
-101
View File
@@ -1,101 +0,0 @@
package docker
import (
"bytes"
"context"
"errors"
"io/ioutil"
"os"
"testing"
"github.com/hashicorp/packer-plugin-sdk/multistep"
)
func testStepExportState(t *testing.T) multistep.StateBag {
state := testState(t)
state.Put("container_id", "foo")
return state
}
func TestStepExport_impl(t *testing.T) {
var _ multistep.Step = new(StepExport)
}
func TestStepExport(t *testing.T) {
state := testStepExportState(t)
step := new(StepExport)
defer step.Cleanup(state)
// Create a tempfile for our output path
tf, err := ioutil.TempFile("", "packer")
if err != nil {
t.Fatalf("err: %s", err)
}
tf.Close()
defer os.Remove(tf.Name())
config := state.Get("config").(*Config)
config.ExportPath = tf.Name()
driver := state.Get("driver").(*MockDriver)
driver.ExportReader = bytes.NewReader([]byte("data!"))
// run the step
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
t.Fatalf("bad action: %#v", action)
}
// verify we did the right thing
if !driver.ExportCalled {
t.Fatal("should've exported")
}
if driver.ExportID != "foo" {
t.Fatalf("bad: %#v", driver.ExportID)
}
// verify the data exported to the file
contents, err := ioutil.ReadFile(tf.Name())
if err != nil {
t.Fatalf("err: %s", err)
}
if string(contents) != "data!" {
t.Fatalf("bad: %#v", string(contents))
}
}
func TestStepExport_error(t *testing.T) {
state := testStepExportState(t)
step := new(StepExport)
defer step.Cleanup(state)
// Create a tempfile for our output path
tf, err := ioutil.TempFile("", "packer")
if err != nil {
t.Fatalf("err: %s", err)
}
tf.Close()
if err := os.Remove(tf.Name()); err != nil {
t.Fatalf("err: %s", err)
}
config := state.Get("config").(*Config)
config.ExportPath = tf.Name()
driver := state.Get("driver").(*MockDriver)
driver.ExportError = errors.New("foo")
// run the step
if action := step.Run(context.Background(), state); action != multistep.ActionHalt {
t.Fatalf("bad action: %#v", action)
}
// verify we have an error
if _, ok := state.GetOk("error"); !ok {
t.Fatal("should have error")
}
// verify we didn't make that file
if _, err := os.Stat(tf.Name()); err == nil {
t.Fatal("export path shouldn't exist")
}
}
-104
View File
@@ -1,104 +0,0 @@
package docker
import (
"context"
"errors"
"testing"
"github.com/hashicorp/packer-plugin-sdk/multistep"
)
func TestStepPull_impl(t *testing.T) {
var _ multistep.Step = new(StepPull)
}
func TestStepPull(t *testing.T) {
state := testState(t)
step := new(StepPull)
defer step.Cleanup(state)
config := state.Get("config").(*Config)
driver := state.Get("driver").(*MockDriver)
// run the step
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
t.Fatalf("bad action: %#v", action)
}
// verify we did the right thing
if !driver.PullCalled {
t.Fatal("should've pulled")
}
if driver.PullImage != config.Image {
t.Fatalf("bad: %#v", driver.PullImage)
}
}
func TestStepPull_error(t *testing.T) {
state := testState(t)
step := new(StepPull)
defer step.Cleanup(state)
driver := state.Get("driver").(*MockDriver)
driver.PullError = errors.New("foo")
// run the step
if action := step.Run(context.Background(), state); action != multistep.ActionHalt {
t.Fatalf("bad action: %#v", action)
}
// verify we have an error
if _, ok := state.GetOk("error"); !ok {
t.Fatal("should have error")
}
}
func TestStepPull_login(t *testing.T) {
state := testState(t)
step := new(StepPull)
defer step.Cleanup(state)
config := state.Get("config").(*Config)
driver := state.Get("driver").(*MockDriver)
config.Login = true
// run the step
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
t.Fatalf("bad action: %#v", action)
}
// verify we pulled
if !driver.PullCalled {
t.Fatal("should've pulled")
}
// verify we logged in
if !driver.LoginCalled {
t.Fatal("should've logged in")
}
if !driver.LogoutCalled {
t.Fatal("should've logged out")
}
}
func TestStepPull_noPull(t *testing.T) {
state := testState(t)
step := new(StepPull)
defer step.Cleanup(state)
config := state.Get("config").(*Config)
config.Pull = false
driver := state.Get("driver").(*MockDriver)
// run the step
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
t.Fatalf("bad action: %#v", action)
}
// verify we did the right thing
if driver.PullCalled {
t.Fatal("shouldn't have pulled")
}
}
-97
View File
@@ -1,97 +0,0 @@
package docker
import (
"context"
"errors"
"testing"
"github.com/hashicorp/packer-plugin-sdk/multistep"
)
func testStepRunState(t *testing.T) multistep.StateBag {
state := testState(t)
state.Put("temp_dir", "/foo")
return state
}
func TestStepRun_impl(t *testing.T) {
var _ multistep.Step = new(StepRun)
}
func TestStepRun(t *testing.T) {
state := testStepRunState(t)
step := new(StepRun)
defer step.Cleanup(state)
config := state.Get("config").(*Config)
driver := state.Get("driver").(*MockDriver)
driver.StartID = "foo"
// run the step
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
t.Fatalf("bad action: %#v", action)
}
// verify we did the right thing
if !driver.StartCalled {
t.Fatal("should've called")
}
if driver.StartConfig.Image != config.Image {
t.Fatalf("bad: %#v", driver.StartConfig.Image)
}
// verify the ID is saved
idRaw, ok := state.GetOk("container_id")
if !ok {
t.Fatal("should've saved ID")
}
id := idRaw.(string)
if id != "foo" {
t.Fatalf("bad: %#v", id)
}
// Verify we haven't called stop yet
if driver.KillCalled {
t.Fatal("should not have stopped")
}
// Cleanup
step.Cleanup(state)
if !driver.KillCalled {
t.Fatal("should've stopped")
}
if driver.KillID != id {
t.Fatalf("bad: %#v", driver.StopID)
}
}
func TestStepRun_error(t *testing.T) {
state := testStepRunState(t)
step := new(StepRun)
defer step.Cleanup(state)
driver := state.Get("driver").(*MockDriver)
driver.StartError = errors.New("foo")
// run the step
if action := step.Run(context.Background(), state); action != multistep.ActionHalt {
t.Fatalf("bad action: %#v", action)
}
// verify the ID is not saved
if _, ok := state.GetOk("container_id"); ok {
t.Fatal("shouldn't save container ID")
}
// Verify we haven't called stop yet
if driver.KillCalled {
t.Fatal("should not have stopped")
}
// Cleanup
step.Cleanup(state)
if driver.KillCalled {
t.Fatal("should not have stopped")
}
}
@@ -1,51 +0,0 @@
package docker
import (
"context"
"testing"
"github.com/hashicorp/packer-plugin-sdk/multistep"
"github.com/hashicorp/packer-plugin-sdk/packerbuilderdata"
)
func TestStepSetGeneratedData_Run(t *testing.T) {
state := testState(t)
step := new(StepSetGeneratedData)
step.GeneratedData = &packerbuilderdata.GeneratedData{State: state}
driver := state.Get("driver").(*MockDriver)
driver.Sha256Result = "80B3BB1B1696E73A9B19DEEF92F664F8979F948DF348088B61F9A3477655AF64"
state.Put("image_id", "12345")
if action := step.Run(context.TODO(), state); action != multistep.ActionContinue {
t.Fatalf("Should not halt")
}
if !driver.Sha256Called {
t.Fatalf("driver.SHA256 should be called")
}
if driver.Sha256Id != "12345" {
t.Fatalf("driver.SHA256 got wrong image it: %s", driver.Sha256Id)
}
genData := state.Get("generated_data").(map[string]interface{})
imgSha256 := genData["ImageSha256"].(string)
if imgSha256 != driver.Sha256Result {
t.Fatalf("Expected ImageSha256 to be %s but was %s", driver.Sha256Result, imgSha256)
}
// Image ID not implement
state = testState(t)
step.GeneratedData = &packerbuilderdata.GeneratedData{State: state}
driver = state.Get("driver").(*MockDriver)
notImplementedMsg := "ERR_IMAGE_SHA256_NOT_FOUND"
if action := step.Run(context.TODO(), state); action != multistep.ActionContinue {
t.Fatalf("Should not halt")
}
if driver.Sha256Called {
t.Fatalf("driver.SHA256 should not be called")
}
genData = state.Get("generated_data").(map[string]interface{})
imgSha256 = genData["ImageSha256"].(string)
if imgSha256 != notImplementedMsg {
t.Fatalf("Expected ImageSha256 to be %s but was %s", notImplementedMsg, imgSha256)
}
}
-52
View File
@@ -1,52 +0,0 @@
package docker
import (
"context"
"os"
"testing"
"github.com/hashicorp/packer-plugin-sdk/multistep"
)
func TestStepTempDir_impl(t *testing.T) {
var _ multistep.Step = new(StepTempDir)
}
func testStepTempDir_impl(t *testing.T) string {
state := testState(t)
step := new(StepTempDir)
defer step.Cleanup(state)
// sanity test
if _, ok := state.GetOk("temp_dir"); ok {
t.Fatalf("temp_dir should not be in state yet")
}
// run the step
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
t.Fatalf("bad action: %#v", action)
}
// Verify that we got the temp dir
dirRaw, ok := state.GetOk("temp_dir")
if !ok {
t.Fatalf("should've made temp_dir")
}
dir := dirRaw.(string)
if _, err := os.Stat(dir); err != nil {
t.Fatalf("Stat for %s failed: err: %s", err, dir)
}
// Cleanup
step.Cleanup(state)
if _, err := os.Stat(dir); err == nil {
t.Fatalf("dir should be gone")
}
return dir
}
func TestStepTempDir(t *testing.T) {
testStepTempDir_impl(t)
}
-21
View File
@@ -1,21 +0,0 @@
package docker
import (
"bytes"
"testing"
"github.com/hashicorp/packer-plugin-sdk/multistep"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
)
func testState(t *testing.T) multistep.StateBag {
state := new(multistep.BasicStateBag)
state.Put("config", testConfigStruct(t))
state.Put("driver", &MockDriver{})
state.Put("hook", &packersdk.MockHook{})
state.Put("ui", &packersdk.BasicUi{
Reader: new(bytes.Buffer),
Writer: new(bytes.Buffer),
})
return state
}
@@ -1 +0,0 @@
chocolate!
@@ -1 +0,0 @@
vanilla!
@@ -1 +0,0 @@
strawberry!
-13
View File
@@ -1,13 +0,0 @@
package version
import (
"github.com/hashicorp/packer-plugin-sdk/version"
packerVersion "github.com/hashicorp/packer/version"
)
var DigitalOceanPluginVersion *version.PluginVersion
func init() {
DigitalOceanPluginVersion = version.InitializePluginVersion(
packerVersion.Version, packerVersion.VersionPrerelease)
}
+6
View File
@@ -210,6 +210,8 @@ type Config struct {
// - The contents of the script file will be wrapped in Packer's startup script wrapper, unless `wrap_startup_script` is disabled. See `wrap_startup_script` for more details.
// - Not supported by Windows instances. See [Startup Scripts for Windows](https://cloud.google.com/compute/docs/startupscript#providing_a_startup_script_for_windows_instances) for more details.
StartupScriptFile string `mapstructure:"startup_script_file" required:"false"`
// The time to wait for windows password to be retrieved. Defaults to "3m".
WindowsPasswordTimeout time.Duration `mapstructure:"windows_password_timeout" required:"false"`
// For backwards compatibility this option defaults to `"true"` in the future it will default to `"false"`.
// If "true", the contents of `startup_script_file` or `"startup_script"` in the instance metadata
// is wrapped in a Packer specific script that tracks the execution and completion of the provided
@@ -542,6 +544,10 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
c.WrapStartupScriptFile = config.TriTrue
}
}
// Check windows password timeout is provided
if c.WindowsPasswordTimeout == 0 {
c.WindowsPasswordTimeout = 3 * time.Minute
}
// Check for any errors.
if errs != nil && len(errs.Errors) > 0 {
+2
View File
@@ -112,6 +112,7 @@ type FlatConfig struct {
SourceImageFamily *string `mapstructure:"source_image_family" required:"true" cty:"source_image_family" hcl:"source_image_family"`
SourceImageProjectId []string `mapstructure:"source_image_project_id" required:"false" cty:"source_image_project_id" hcl:"source_image_project_id"`
StartupScriptFile *string `mapstructure:"startup_script_file" required:"false" cty:"startup_script_file" hcl:"startup_script_file"`
WindowsPasswordTimeout *string `mapstructure:"windows_password_timeout" required:"false" cty:"windows_password_timeout" hcl:"windows_password_timeout"`
WrapStartupScriptFile *bool `mapstructure:"wrap_startup_script" required:"false" cty:"wrap_startup_script" hcl:"wrap_startup_script"`
Subnetwork *string `mapstructure:"subnetwork" required:"false" cty:"subnetwork" hcl:"subnetwork"`
Tags []string `mapstructure:"tags" required:"false" cty:"tags" hcl:"tags"`
@@ -236,6 +237,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"source_image_family": &hcldec.AttrSpec{Name: "source_image_family", Type: cty.String, Required: false},
"source_image_project_id": &hcldec.AttrSpec{Name: "source_image_project_id", Type: cty.List(cty.String), Required: false},
"startup_script_file": &hcldec.AttrSpec{Name: "startup_script_file", Type: cty.String, Required: false},
"windows_password_timeout": &hcldec.AttrSpec{Name: "windows_password_timeout", Type: cty.String, Required: false},
"wrap_startup_script": &hcldec.AttrSpec{Name: "wrap_startup_script", Type: cty.Bool, Required: false},
"subnetwork": &hcldec.AttrSpec{Name: "subnetwork", Type: cty.String, Required: false},
"tags": &hcldec.AttrSpec{Name: "tags", Type: cty.List(cty.String), Required: false},
+8 -7
View File
@@ -107,13 +107,14 @@ type InstanceConfig struct {
// WindowsPasswordConfig is the data structure that GCE needs to encrypt the created
// windows password.
type WindowsPasswordConfig struct {
key *rsa.PrivateKey
password string
UserName string `json:"userName"`
Modulus string `json:"modulus"`
Exponent string `json:"exponent"`
Email string `json:"email"`
ExpireOn time.Time `json:"expireOn"`
key *rsa.PrivateKey
password string
UserName string `json:"userName"`
Modulus string `json:"modulus"`
Exponent string `json:"exponent"`
Email string `json:"email"`
ExpireOn time.Time `json:"expireOn"`
WindowsPasswordTimeout time.Duration `json:"timeout"`
}
type windowsPasswordResponse struct {
+1 -2
View File
@@ -253,7 +253,6 @@ func (d *driverGCE) GetImage(name string, fromFamily bool) (*Image, error) {
"ubuntu-os-cloud",
"windows-cloud",
"windows-sql-cloud",
"gce-uefi-images",
"gce-nvme",
// misc
"google-containers",
@@ -568,7 +567,7 @@ func (d *driverGCE) createWindowsPassword(errCh chan<- error, name, zone string,
return
}
timeout := time.Now().Add(time.Minute * 3)
timeout := time.Now().Add(c.WindowsPasswordTimeout)
hash := sha1.New()
random := rand.Reader
@@ -60,12 +60,13 @@ func (s *StepCreateWindowsPassword) Run(ctx context.Context, state multistep.Sta
}
data := WindowsPasswordConfig{
key: priv,
UserName: c.Comm.WinRMUser,
Modulus: base64.StdEncoding.EncodeToString(priv.N.Bytes()),
Exponent: base64.StdEncoding.EncodeToString(buf[1:]),
Email: email,
ExpireOn: time.Now().Add(time.Minute * 5),
key: priv,
UserName: c.Comm.WinRMUser,
Modulus: base64.StdEncoding.EncodeToString(priv.N.Bytes()),
Exponent: base64.StdEncoding.EncodeToString(buf[1:]),
Email: email,
ExpireOn: time.Now().Add(time.Minute * 5),
WindowsPasswordTimeout: c.WindowsPasswordTimeout,
}
if s.Debug {
@@ -98,7 +99,7 @@ func (s *StepCreateWindowsPassword) Run(ctx context.Context, state multistep.Sta
ui.Message("Waiting for windows password to complete...")
select {
case err = <-errCh:
case <-time.After(c.StateTimeout):
case <-time.After(c.WindowsPasswordTimeout):
err = errors.New("time out while waiting for the password to be created")
}
}
+2 -7
View File
@@ -211,12 +211,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
Directories: b.config.FloppyConfig.FloppyDirectories,
Label: b.config.FloppyConfig.FloppyLabel,
},
&commonsteps.StepHTTPServer{
HTTPDir: b.config.HTTPDir,
HTTPPortMin: b.config.HTTPPortMin,
HTTPPortMax: b.config.HTTPPortMax,
HTTPAddress: b.config.HTTPAddress,
},
commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig),
&hypervcommon.StepCreateSwitch{
SwitchName: b.config.SwitchName,
},
@@ -294,7 +289,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
// configure the communicator ssh, winrm
&communicator.StepConnect{
Config: &b.config.SSHConfig.Comm,
Host: hypervcommon.CommHost(b.config.SSHConfig.Comm.SSHHost),
Host: hypervcommon.CommHost(b.config.SSHConfig.Comm.Host()),
SSHConfig: b.config.SSHConfig.Comm.SSHConfigFunc(),
},
+2
View File
@@ -19,6 +19,7 @@ type FlatConfig struct {
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"`
HTTPContent map[string]string `mapstructure:"http_content" cty:"http_content" hcl:"http_content"`
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"`
@@ -141,6 +142,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_content": &hcldec.AttrSpec{Name: "http_content", Type: cty.Map(cty.String), Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},
"http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false},
"http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false},
+2 -7
View File
@@ -251,12 +251,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
Directories: b.config.FloppyConfig.FloppyDirectories,
Label: b.config.FloppyConfig.FloppyLabel,
},
&commonsteps.StepHTTPServer{
HTTPDir: b.config.HTTPDir,
HTTPPortMin: b.config.HTTPPortMin,
HTTPPortMax: b.config.HTTPPortMax,
HTTPAddress: b.config.HTTPAddress,
},
commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig),
&hypervcommon.StepCreateSwitch{
SwitchName: b.config.SwitchName,
},
@@ -334,7 +329,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
// configure the communicator ssh, winrm
&communicator.StepConnect{
Config: &b.config.SSHConfig.Comm,
Host: hypervcommon.CommHost(b.config.SSHConfig.Comm.SSHHost),
Host: hypervcommon.CommHost(b.config.SSHConfig.Comm.Host()),
SSHConfig: b.config.SSHConfig.Comm.SSHConfigFunc(),
},
+2
View File
@@ -19,6 +19,7 @@ type FlatConfig struct {
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"`
HTTPContent map[string]string `mapstructure:"http_content" cty:"http_content" hcl:"http_content"`
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"`
@@ -143,6 +144,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_content": &hcldec.AttrSpec{Name: "http_content", Type: cty.Map(cty.String), Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},
"http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false},
"http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false},
+1 -1
View File
@@ -151,7 +151,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
&communicator.StepConnect{
Config: &b.config.RunConfig.Comm,
Host: CommHost(
b.config.RunConfig.Comm.SSHHost,
b.config.RunConfig.Comm.Host(),
computeClient,
b.config.SSHInterface,
b.config.SSHIPVersion),
+1 -1
View File
@@ -253,7 +253,7 @@ func (c *Config) Prepare(raws ...interface{}) error {
if _, err := configProvider.PrivateRSAKey(); err != nil {
errs = packersdk.MultiErrorAppend(
errs, errors.New("'key_file' must be specified"))
errs, fmt.Errorf("'key_file' must be correctly specified. %w", err))
}
c.configProvider = configProvider
+3
View File
@@ -32,6 +32,9 @@ func (s *stepCreateOMI) Run(ctx context.Context, state multistep.StateBag) multi
ImageName: omiName,
BlockDeviceMappings: config.BlockDevices.BuildOscOMIDevices(),
}
if config.OMIDescription != "" {
createOpts.Description = config.OMIDescription
}
resp, _, err := oscconn.ImageApi.CreateImage(context.Background(), &osc.CreateImageOpts{
CreateImageRequest: optional.NewInterface(createOpts),
@@ -37,6 +37,9 @@ func (s *StepRegisterOMI) Run(ctx context.Context, state multistep.StateBag) mul
BlockDeviceMappings: blockDevices,
}
if config.OMIDescription != "" {
registerOpts.Description = config.OMIDescription
}
registerResp, _, err := oscconn.ImageApi.CreateImage(context.Background(), &osc.CreateImageOpts{
CreateImageRequest: optional.NewInterface(registerOpts),
})
+4
View File
@@ -75,6 +75,10 @@ func (s *StepCreateOMI) Run(ctx context.Context, state multistep.StateBag) multi
registerOpts = buildRegisterOpts(config, image, newMappings)
}
if config.OMIDescription != "" {
registerOpts.Description = config.OMIDescription
}
registerResp, _, err := osconn.ImageApi.CreateImage(context.Background(), &osc.CreateImageOpts{
CreateImageRequest: optional.NewInterface(registerOpts),
})
+2 -7
View File
@@ -209,12 +209,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
Directories: b.config.FloppyConfig.FloppyDirectories,
Label: b.config.FloppyConfig.FloppyLabel,
},
&commonsteps.StepHTTPServer{
HTTPDir: b.config.HTTPDir,
HTTPPortMin: b.config.HTTPPortMin,
HTTPPortMax: b.config.HTTPPortMax,
HTTPAddress: b.config.HTTPAddress,
},
commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig),
new(stepCreateVM),
new(stepCreateDisk),
new(stepSetBootOrder),
@@ -238,7 +233,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
},
&communicator.StepConnect{
Config: &b.config.SSHConfig.Comm,
Host: parallelscommon.CommHost(b.config.SSHConfig.Comm.SSHHost),
Host: parallelscommon.CommHost(b.config.SSHConfig.Comm.Host()),
SSHConfig: b.config.SSHConfig.Comm.SSHConfigFunc(),
},
&parallelscommon.StepUploadVersion{
@@ -19,6 +19,7 @@ type FlatConfig struct {
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"`
HTTPContent map[string]string `mapstructure:"http_content" cty:"http_content" hcl:"http_content"`
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"`
@@ -126,6 +127,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_content": &hcldec.AttrSpec{Name: "http_content", Type: cty.Map(cty.String), Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},
"http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false},
"http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false},
+1 -1
View File
@@ -87,7 +87,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
},
&communicator.StepConnect{
Config: &b.config.SSHConfig.Comm,
Host: parallelscommon.CommHost(b.config.SSHConfig.Comm.SSHHost),
Host: parallelscommon.CommHost(b.config.SSHConfig.Comm.Host()),
SSHConfig: b.config.SSHConfig.Comm.SSHConfigFunc(),
},
&parallelscommon.StepUploadVersion{
+4
View File
@@ -20,6 +20,7 @@ type FlatConfig struct {
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"`
HTTPContent map[string]string `mapstructure:"http_content" cty:"http_content" hcl:"http_content"`
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"`
@@ -81,6 +82,7 @@ type FlatConfig struct {
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"`
Token *string `mapstructure:"token" cty:"token" hcl:"token"`
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"`
@@ -129,6 +131,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_content": &hcldec.AttrSpec{Name: "http_content", Type: cty.Map(cty.String), Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},
"http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false},
"http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false},
@@ -190,6 +193,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"insecure_skip_tls_verify": &hcldec.AttrSpec{Name: "insecure_skip_tls_verify", Type: cty.Bool, Required: false},
"username": &hcldec.AttrSpec{Name: "username", Type: cty.String, Required: false},
"password": &hcldec.AttrSpec{Name: "password", Type: cty.String, Required: false},
"token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false},
"node": &hcldec.AttrSpec{Name: "node", Type: cty.String, Required: false},
"pool": &hcldec.AttrSpec{Name: "pool", Type: cty.String, Required: false},
"vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false},
+2 -16
View File
@@ -2,7 +2,6 @@ package proxmox
import (
"context"
"crypto/tls"
"errors"
"fmt"
@@ -35,15 +34,7 @@ type Builder struct {
func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook, state multistep.StateBag) (packersdk.Artifact, error) {
var err error
tlsConfig := &tls.Config{
InsecureSkipVerify: b.config.SkipCertValidation,
}
b.proxmoxClient, err = proxmox.NewClient(b.config.proxmoxURL.String(), nil, tlsConfig)
if err != nil {
return nil, err
}
err = b.proxmoxClient.Login(b.config.Username, b.config.Password, "")
b.proxmoxClient, err = newProxmoxClient(b.config)
if err != nil {
return nil, err
}
@@ -61,12 +52,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook,
&stepStartVM{
vmCreator: b.vmCreator,
},
&commonsteps.StepHTTPServer{
HTTPDir: b.config.HTTPDir,
HTTPPortMin: b.config.HTTPPortMin,
HTTPPortMax: b.config.HTTPPortMax,
HTTPAddress: b.config.HTTPAddress,
},
commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig),
&stepTypeBootCommand{
BootConfig: b.config.BootConfig,
Ctx: b.config.Ctx,
+37
View File
@@ -0,0 +1,37 @@
package proxmox
import (
"crypto/tls"
"log"
"time"
"github.com/Telmate/proxmox-api-go/proxmox"
)
const defaultTaskTimeout = 30 * time.Second
func newProxmoxClient(config Config) (*proxmox.Client, error) {
tlsConfig := &tls.Config{
InsecureSkipVerify: config.SkipCertValidation,
}
client, err := proxmox.NewClient(config.proxmoxURL.String(), nil, tlsConfig, int(defaultTaskTimeout.Seconds()))
if err != nil {
return nil, err
}
if config.Token != "" {
// configure token auth
log.Print("using token auth")
client.SetAPIToken(config.Username, config.Token)
} else {
// fallback to login if not using tokens
log.Print("using password auth")
err = client.Login(config.Username, config.Password, "")
if err != nil {
return nil, err
}
}
return client, nil
}
+91
View File
@@ -0,0 +1,91 @@
package proxmox
import (
"encoding/json"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
"testing"
"github.com/Telmate/proxmox-api-go/proxmox"
"github.com/stretchr/testify/require"
)
func TestTokenAuth(t *testing.T) {
mockAPI := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
if req.Header.Get("Authorization") != "PVEAPIToken=dummy@vmhost!test-token=ac5293bf-15e2-477f-b04c-a6dfa7a46b80" {
rw.WriteHeader(http.StatusUnauthorized)
return
}
}))
defer mockAPI.Close()
pmURL, _ := url.Parse(mockAPI.URL)
config := Config{
proxmoxURL: pmURL,
SkipCertValidation: false,
Username: "dummy@vmhost!test-token",
Password: "not-used",
Token: "ac5293bf-15e2-477f-b04c-a6dfa7a46b80",
}
client, err := newProxmoxClient(config)
require.NoError(t, err)
ref := proxmox.NewVmRef(110)
ref.SetNode("node1")
ref.SetVmType("qemu")
err = client.Sendkey(ref, "ping")
require.NoError(t, err)
}
func TestLogin(t *testing.T) {
mockAPI := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
// mock ticketing api
if req.Method == http.MethodPost && req.URL.Path == "/access/ticket" {
body, _ := ioutil.ReadAll(req.Body)
values, _ := url.ParseQuery(string(body))
user := values.Get("username")
pass := values.Get("password")
if user != "dummy@vmhost" || pass != "correct-horse-battery-staple" {
rw.WriteHeader(http.StatusUnauthorized)
return
}
_ = json.NewEncoder(rw).Encode(map[string]interface{}{
"data": map[string]string{
"username": user,
"ticket": "dummy-ticket",
"CSRFPreventionToken": "random-token",
},
})
return
}
// validate ticket
if val, err := req.Cookie("PVEAuthCookie"); err != nil || val.Value != "dummy-ticket" {
rw.WriteHeader(http.StatusUnauthorized)
return
}
}))
defer mockAPI.Close()
pmURL, _ := url.Parse(mockAPI.URL)
config := Config{
proxmoxURL: pmURL,
SkipCertValidation: false,
Username: "dummy@vmhost",
Password: "correct-horse-battery-staple",
Token: "",
}
client, err := newProxmoxClient(config)
require.NoError(t, err)
ref := proxmox.NewVmRef(110)
ref.SetNode("node1")
ref.SetVmType("qemu")
err = client.Sendkey(ref, "ping")
require.NoError(t, err)
}
+8 -4
View File
@@ -35,6 +35,7 @@ type Config struct {
SkipCertValidation bool `mapstructure:"insecure_skip_tls_verify"`
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
Token string `mapstructure:"token"`
Node string `mapstructure:"node"`
Pool string `mapstructure:"pool"`
@@ -73,8 +74,8 @@ type additionalISOsConfig struct {
ISOFile string `mapstructure:"iso_file"`
ISOStoragePool string `mapstructure:"iso_storage_pool"`
Unmount bool `mapstructure:"unmount"`
ShouldUploadISO bool
DownloadPathKey string
ShouldUploadISO bool `mapstructure-to-hcl2:",skip"`
DownloadPathKey string `mapstructure-to-hcl2:",skip"`
}
type nicConfig struct {
@@ -135,6 +136,9 @@ func (c *Config) Prepare(upper interface{}, raws ...interface{}) ([]string, []st
if c.Password == "" {
c.Password = os.Getenv("PROXMOX_PASSWORD")
}
if c.Token == "" {
c.Token = os.Getenv("PROXMOX_TOKEN")
}
if c.BootKeyInterval == 0 && os.Getenv(bootcommand.PackerKeyEnv) != "" {
var err error
c.BootKeyInterval, err = time.ParseDuration(os.Getenv(bootcommand.PackerKeyEnv))
@@ -220,8 +224,8 @@ func (c *Config) Prepare(upper interface{}, raws ...interface{}) ([]string, []st
if c.Username == "" {
errs = packersdk.MultiErrorAppend(errs, errors.New("username must be specified"))
}
if c.Password == "" {
errs = packersdk.MultiErrorAppend(errs, errors.New("password must be specified"))
if c.Password == "" && c.Token == "" {
errs = packersdk.MultiErrorAppend(errs, errors.New("password or token must be specified"))
}
if c.ProxmoxURLRaw == "" {
errs = packersdk.MultiErrorAppend(errs, errors.New("proxmox_url must be specified"))
+4 -4
View File
@@ -19,6 +19,7 @@ type FlatConfig struct {
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"`
HTTPContent map[string]string `mapstructure:"http_content" cty:"http_content" hcl:"http_content"`
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"`
@@ -80,6 +81,7 @@ type FlatConfig struct {
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"`
Token *string `mapstructure:"token" cty:"token" hcl:"token"`
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"`
@@ -126,6 +128,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_content": &hcldec.AttrSpec{Name: "http_content", Type: cty.Map(cty.String), Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},
"http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false},
"http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false},
@@ -187,6 +190,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"insecure_skip_tls_verify": &hcldec.AttrSpec{Name: "insecure_skip_tls_verify", Type: cty.Bool, Required: false},
"username": &hcldec.AttrSpec{Name: "username", Type: cty.String, Required: false},
"password": &hcldec.AttrSpec{Name: "password", Type: cty.String, Required: false},
"token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false},
"node": &hcldec.AttrSpec{Name: "node", Type: cty.String, Required: false},
"pool": &hcldec.AttrSpec{Name: "pool", Type: cty.String, Required: false},
"vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false},
@@ -226,8 +230,6 @@ type FlatadditionalISOsConfig struct {
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.
@@ -251,8 +253,6 @@ func (*FlatadditionalISOsConfig) HCL2Spec() map[string]hcldec.Spec {
"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
}
+4
View File
@@ -20,6 +20,7 @@ type FlatConfig struct {
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"`
HTTPContent map[string]string `mapstructure:"http_content" cty:"http_content" hcl:"http_content"`
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"`
@@ -81,6 +82,7 @@ type FlatConfig struct {
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"`
Token *string `mapstructure:"token" cty:"token" hcl:"token"`
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"`
@@ -135,6 +137,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_content": &hcldec.AttrSpec{Name: "http_content", Type: cty.Map(cty.String), Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},
"http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false},
"http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false},
@@ -196,6 +199,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"insecure_skip_tls_verify": &hcldec.AttrSpec{Name: "insecure_skip_tls_verify", Type: cty.Bool, Required: false},
"username": &hcldec.AttrSpec{Name: "username", Type: cty.String, Required: false},
"password": &hcldec.AttrSpec{Name: "password", Type: cty.String, Required: false},
"token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false},
"node": &hcldec.AttrSpec{Name: "node", Type: cty.String, Required: false},
"pool": &hcldec.AttrSpec{Name: "pool", Type: cty.String, Required: false},
"vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false},
+1 -6
View File
@@ -96,12 +96,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
QemuImgArgs: b.config.QemuImgArgs,
},
new(stepHTTPIPDiscover),
&commonsteps.StepHTTPServer{
HTTPDir: b.config.HTTPDir,
HTTPPortMin: b.config.HTTPPortMin,
HTTPPortMax: b.config.HTTPPortMax,
HTTPAddress: b.config.HTTPAddress,
},
commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig),
&stepPortForward{
CommunicatorType: b.config.CommConfig.Comm.Type,
NetBridge: b.config.NetBridge,
+1
View File
@@ -48,6 +48,7 @@ func (c *CommConfig) Prepare(ctx *interpolate.Context) (warnings []string, errs
if c.Comm.SSHHost == "" && c.SkipNatMapping {
c.Comm.SSHHost = "127.0.0.1"
c.Comm.WinRMHost = "127.0.0.1"
}
if c.HostPortMin == 0 {
+2
View File
@@ -19,6 +19,7 @@ type FlatConfig struct {
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"`
HTTPContent map[string]string `mapstructure:"http_content" cty:"http_content" hcl:"http_content"`
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"`
@@ -153,6 +154,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_content": &hcldec.AttrSpec{Name: "http_content", Type: cty.Map(cty.String), Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},
"http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false},
"http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false},
+2
View File
@@ -298,6 +298,7 @@ func (s *stepRun) applyUserOverrides(defaultArgs map[string]interface{}, config
HTTPIP string
HTTPPort int
HTTPDir string
HTTPContent map[string]string
OutputDir string
Name string
SSHHostPort int
@@ -308,6 +309,7 @@ func (s *stepRun) applyUserOverrides(defaultArgs map[string]interface{}, config
HTTPIP: httpIp,
HTTPPort: httpPort,
HTTPDir: config.HTTPDir,
HTTPContent: config.HTTPContent,
OutputDir: config.OutputDir,
Name: config.VMName,
SSHHostPort: commHostPort,
+2
View File
@@ -19,6 +19,7 @@ type FlatConfig struct {
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"`
HTTPContent map[string]string `mapstructure:"http_content" cty:"http_content" hcl:"http_content"`
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"`
@@ -128,6 +129,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_content": &hcldec.AttrSpec{Name: "http_content", Type: cty.Map(cty.String), Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},
"http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false},
"http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false},
+13 -7
View File
@@ -41,17 +41,23 @@ func (s *StepSSHConfig) Run(ctx context.Context, state multistep.StateBag) multi
return multistep.ActionHalt
}
config.Comm.SSHHost = sshConfig.Hostname
port, err := strconv.Atoi(sshConfig.Port)
if err != nil {
state.Put("error", err)
return multistep.ActionHalt
if config.Comm.SSHHost == "" {
config.Comm.SSHHost = sshConfig.Hostname
}
if config.Comm.SSHPort == 0 {
port, err := strconv.Atoi(sshConfig.Port)
if err != nil {
state.Put("error", err)
return multistep.ActionHalt
}
config.Comm.SSHPort = port
}
config.Comm.SSHPort = port
if config.Comm.SSHUsername != "" {
// If user has set the username within the communicator, use the
// auth provided there.
// username, password, and/or keyfile auth provided there.
log.Printf("Overriding SSH config from Vagrant with the username, " +
"password, and private key information provided to the Packer template.")
return multistep.ActionContinue
}
log.Printf("identity file is %s", sshConfig.IdentityFile)
+78
View File
@@ -4,6 +4,7 @@ import (
"context"
"testing"
"github.com/hashicorp/packer-plugin-sdk/communicator"
"github.com/hashicorp/packer-plugin-sdk/multistep"
)
@@ -15,6 +16,83 @@ func TestStepSSHConfig_Impl(t *testing.T) {
}
}
func TestPrepStepSSHConfig_sshOverrides(t *testing.T) {
type testcase struct {
name string
inputSSHConfig communicator.SSH
expectedSSHConfig communicator.SSH
}
tcs := []testcase{
{
// defaults to overriding with the ssh config from vagrant\
name: "default",
inputSSHConfig: communicator.SSH{},
expectedSSHConfig: communicator.SSH{
SSHHost: "127.0.0.1",
SSHPort: 2222,
SSHUsername: "vagrant",
SSHPassword: "",
},
},
{
// respects SSH host and port overrides independent of credential
// overrides
name: "host_override",
inputSSHConfig: communicator.SSH{
SSHHost: "123.45.67.8",
SSHPort: 1234,
},
expectedSSHConfig: communicator.SSH{
SSHHost: "123.45.67.8",
SSHPort: 1234,
SSHUsername: "vagrant",
SSHPassword: "",
},
},
{
// respects credential overrides
name: "credential_override",
inputSSHConfig: communicator.SSH{
SSHUsername: "megan",
SSHPassword: "SoSecure",
},
expectedSSHConfig: communicator.SSH{
SSHHost: "127.0.0.1",
SSHPort: 2222,
SSHUsername: "megan",
SSHPassword: "SoSecure",
},
},
}
for _, tc := range tcs {
driver := &MockVagrantDriver{}
config := &Config{
Comm: communicator.Config{
SSH: tc.inputSSHConfig,
},
}
state := new(multistep.BasicStateBag)
state.Put("driver", driver)
state.Put("config", config)
step := StepSSHConfig{}
_ = step.Run(context.Background(), state)
if config.Comm.SSHHost != tc.expectedSSHConfig.SSHHost {
t.Fatalf("unexpected sshconfig host: name: %s, recieved %s", tc.name, config.Comm.SSHHost)
}
if config.Comm.SSHPort != tc.expectedSSHConfig.SSHPort {
t.Fatalf("unexpected sshconfig port: name: %s, recieved %d", tc.name, config.Comm.SSHPort)
}
if config.Comm.SSHUsername != tc.expectedSSHConfig.SSHUsername {
t.Fatalf("unexpected sshconfig SSHUsername: name: %s, recieved %s", tc.name, config.Comm.SSHUsername)
}
if config.Comm.SSHPassword != tc.expectedSSHConfig.SSHPassword {
t.Fatalf("unexpected sshconfig SSHUsername: name: %s, recieved %s", tc.name, config.Comm.SSHPassword)
}
}
}
func TestPrepStepSSHConfig_GlobalID(t *testing.T) {
driver := &MockVagrantDriver{}
config := &Config{}
+2 -1
View File
@@ -50,8 +50,9 @@ func (c *CommConfig) Prepare(ctx *interpolate.Context) []error {
c.SkipNatMapping = c.SSHSkipNatMapping
}
if c.Comm.SSHHost == "" {
if c.Comm.Host() == "" {
c.Comm.SSHHost = "127.0.0.1"
c.Comm.WinRMHost = "127.0.0.1"
}
if c.HostPortMin == 0 {
+26 -23
View File
@@ -8,6 +8,8 @@ import (
"github.com/hashicorp/packer-plugin-sdk/multistep"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"strconv"
)
// This step attaches the boot ISO, cd_files iso, and guest additions to the
@@ -69,49 +71,50 @@ func (s *StepAttachISOs) Run(ctx context.Context, state multistep.StateBag) mult
// We have three different potential isos we can attach, so let's
// assign each one its own spot so they don't conflict.
var controllerName, device, port string
var controllerName string
var device, port int
switch diskCategory {
case "boot_iso":
// figure out controller path
controllerName = "IDE Controller"
port = "0"
device = "1"
port = 0
device = 1
if s.ISOInterface == "sata" {
controllerName = "SATA Controller"
port = "1"
device = "0"
port = 15
device = 0
} else if s.ISOInterface == "virtio" {
controllerName = "VirtIO Controller"
port = "1"
device = "0"
port = 15
device = 0
}
ui.Message("Mounting boot ISO...")
case "guest_additions":
controllerName = "IDE Controller"
port = "1"
device = "0"
port = 1
device = 0
if s.GuestAdditionsInterface == "sata" {
controllerName = "SATA Controller"
port = "2"
device = "0"
port = 14
device = 0
} else if s.GuestAdditionsInterface == "virtio" {
controllerName = "VirtIO Controller"
port = "2"
device = "0"
port = 14
device = 0
}
ui.Message("Mounting guest additions ISO...")
case "cd_files":
controllerName = "IDE Controller"
port = "1"
device = "1"
port = 1
device = 1
if s.ISOInterface == "sata" {
controllerName = "SATA Controller"
port = "3"
device = "0"
port = 13
device = 0
} else if s.ISOInterface == "virtio" {
controllerName = "VirtIO Controller"
port = "3"
device = "0"
port = 13
device = 0
}
ui.Message("Mounting cd_files ISO...")
}
@@ -120,8 +123,8 @@ func (s *StepAttachISOs) Run(ctx context.Context, state multistep.StateBag) mult
command := []string{
"storageattach", vmName,
"--storagectl", controllerName,
"--port", port,
"--device", device,
"--port", strconv.Itoa(port),
"--device", strconv.Itoa(device),
"--type", "dvddrive",
"--medium", isoPath,
}
@@ -137,8 +140,8 @@ func (s *StepAttachISOs) Run(ctx context.Context, state multistep.StateBag) mult
unmountCommand := []string{
"storageattach", vmName,
"--storagectl", controllerName,
"--port", port,
"--device", device,
"--port", strconv.Itoa(port),
"--device", strconv.Itoa(device),
"--type", "dvddrive",
"--medium", "none",
}
+57 -7
View File
@@ -7,6 +7,7 @@ import (
"context"
"errors"
"fmt"
"regexp"
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/packer-plugin-sdk/bootcommand"
@@ -52,6 +53,14 @@ type Config struct {
// 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"`
// Nested virtualization: false or true.
// When set to true, nested virtualisation (VT-x/AMD-V) is enabled.
// When set to false, nested virtualisation is disabled. This is the default.
NestedVirt bool `mapstructure:"nested_virt" required:"false"`
// RTC time base: UTC or local.
// When set to true, the RTC is set as UTC time.
// When set to false, the RTC is set as local time. This is the default.
RTCTimeBase string `mapstructure:"rtc_time_base" 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"`
@@ -75,6 +84,17 @@ type Config struct {
// 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 VRAM size to be used. By default, this is 4 MiB.
GfxVramSize uint `mapstructure:"gfx_vram_size" required:"false"`
// 3D acceleration: true or false.
// When set to true, 3D acceleration is enabled.
// When set to false, 3D acceleration is disabled. This is the default.
GfxAccelerate3D bool `mapstructure:"gfx_accelerate_3d" required:"false"`
// Screen resolution in EFI mode: WIDTHxHEIGHT.
// When set to WIDTHxHEIGHT, it provides the given width and height as screen resolution
// to EFI, for example 1920x1080 for Full-HD resolution. By default, no screen resolution
// is set. Note, that this option only affects EFI boot, not the (default) BIOS boot.
GfxEFIResolution string `mapstructure:"gfx_efi_resolution" 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
@@ -129,6 +149,12 @@ type Config struct {
// 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"`
// Additional disks to create. Uses `vm_name` as the disk name template and
// appends `-#` where `#` is the position in the array. `#` starts at 1 since 0
// is the default disk. Each value represents the disk image size in MiB.
// Each additional disk uses the same disk parameters as the default disk.
// Unset by default.
AdditionalDiskSize []uint `mapstructure:"disk_additional_size" required:"false"`
// Set this to true if you would like to keep the VM registered with
// virtualbox. Defaults to false.
KeepRegistered bool `mapstructure:"keep_registered" required:"false"`
@@ -212,6 +238,17 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
errs, errors.New("firmware can only be bios or efi"))
}
if b.config.RTCTimeBase == "" {
b.config.RTCTimeBase = "local"
}
switch b.config.RTCTimeBase {
case "UTC", "local":
// do nothing
default:
errs = packersdk.MultiErrorAppend(
errs, errors.New("rtc_time_base can only be UTC or local"))
}
if b.config.DiskSize == 0 {
b.config.DiskSize = 40000
}
@@ -242,6 +279,24 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
errs, errors.New("Graphics controller type can only be vboxvga, vboxsvga, vmsvga, none"))
}
if b.config.GfxVramSize == 0 {
b.config.GfxVramSize = 4
} else {
if b.config.GfxVramSize < 1 || b.config.GfxVramSize > 128 {
errs = packersdk.MultiErrorAppend(
errs, errors.New("VGRAM size must be from 0 (use default) to 128"))
}
}
if b.config.GfxEFIResolution != "" {
re := regexp.MustCompile(`^[\d]+x[\d]+$`)
matched := re.MatchString(b.config.GfxEFIResolution)
if !matched {
errs = packersdk.MultiErrorAppend(
errs, errors.New("EFI resolution must be in the format WIDTHxHEIGHT, e.g. 1920x1080"))
}
}
if b.config.AudioController == "" {
b.config.AudioController = "ac97"
}
@@ -351,12 +406,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
Label: b.config.CDConfig.CDLabel,
},
new(vboxcommon.StepHTTPIPDiscover),
&commonsteps.StepHTTPServer{
HTTPDir: b.config.HTTPDir,
HTTPPortMin: b.config.HTTPPortMin,
HTTPPortMax: b.config.HTTPPortMax,
HTTPAddress: b.config.HTTPAddress,
},
commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig),
&vboxcommon.StepSshKeyPair{
Debug: b.config.PackerDebug,
DebugKeyPath: fmt.Sprintf("%s.pem", b.config.PackerBuildName),
@@ -400,7 +450,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
},
&communicator.StepConnect{
Config: &b.config.CommConfig.Comm,
Host: vboxcommon.CommHost(b.config.CommConfig.Comm.SSHHost),
Host: vboxcommon.CommHost(b.config.CommConfig.Comm.Host()),
SSHConfig: b.config.CommConfig.Comm.SSHConfigFunc(),
SSHPort: vboxcommon.CommPort,
WinRMPort: vboxcommon.CommPort,
@@ -19,6 +19,7 @@ type FlatConfig struct {
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"`
HTTPContent map[string]string `mapstructure:"http_content" cty:"http_content" hcl:"http_content"`
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"`
@@ -119,10 +120,15 @@ type FlatConfig struct {
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"`
NestedVirt *bool `mapstructure:"nested_virt" required:"false" cty:"nested_virt" hcl:"nested_virt"`
RTCTimeBase *string `mapstructure:"rtc_time_base" required:"false" cty:"rtc_time_base" hcl:"rtc_time_base"`
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"`
GfxVramSize *uint `mapstructure:"gfx_vram_size" required:"false" cty:"gfx_vram_size" hcl:"gfx_vram_size"`
GfxAccelerate3D *bool `mapstructure:"gfx_accelerate_3d" required:"false" cty:"gfx_accelerate_3d" hcl:"gfx_accelerate_3d"`
GfxEFIResolution *string `mapstructure:"gfx_efi_resolution" required:"false" cty:"gfx_efi_resolution" hcl:"gfx_efi_resolution"`
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"`
@@ -130,6 +136,7 @@ type FlatConfig struct {
NVMePortCount *int `mapstructure:"nvme_port_count" required:"false" cty:"nvme_port_count" hcl:"nvme_port_count"`
HardDriveNonrotational *bool `mapstructure:"hard_drive_nonrotational" required:"false" cty:"hard_drive_nonrotational" hcl:"hard_drive_nonrotational"`
ISOInterface *string `mapstructure:"iso_interface" required:"false" cty:"iso_interface" hcl:"iso_interface"`
AdditionalDiskSize []uint `mapstructure:"disk_additional_size" required:"false" cty:"disk_additional_size" hcl:"disk_additional_size"`
KeepRegistered *bool `mapstructure:"keep_registered" required:"false" cty:"keep_registered" hcl:"keep_registered"`
SkipExport *bool `mapstructure:"skip_export" required:"false" cty:"skip_export" hcl:"skip_export"`
VMName *string `mapstructure:"vm_name" required:"false" cty:"vm_name" hcl:"vm_name"`
@@ -156,6 +163,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_content": &hcldec.AttrSpec{Name: "http_content", Type: cty.Map(cty.String), Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},
"http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false},
"http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false},
@@ -256,10 +264,15 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"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},
"nested_virt": &hcldec.AttrSpec{Name: "nested_virt", Type: cty.Bool, Required: false},
"rtc_time_base": &hcldec.AttrSpec{Name: "rtc_time_base", 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},
"gfx_vram_size": &hcldec.AttrSpec{Name: "gfx_vram_size", Type: cty.Number, Required: false},
"gfx_accelerate_3d": &hcldec.AttrSpec{Name: "gfx_accelerate_3d", Type: cty.Bool, Required: false},
"gfx_efi_resolution": &hcldec.AttrSpec{Name: "gfx_efi_resolution", 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},
@@ -267,6 +280,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"nvme_port_count": &hcldec.AttrSpec{Name: "nvme_port_count", Type: cty.Number, Required: false},
"hard_drive_nonrotational": &hcldec.AttrSpec{Name: "hard_drive_nonrotational", Type: cty.Bool, Required: false},
"iso_interface": &hcldec.AttrSpec{Name: "iso_interface", Type: cty.String, Required: false},
"disk_additional_size": &hcldec.AttrSpec{Name: "disk_additional_size", Type: cty.List(cty.Number), Required: false},
"keep_registered": &hcldec.AttrSpec{Name: "keep_registered", Type: cty.Bool, Required: false},
"skip_export": &hcldec.AttrSpec{Name: "skip_export", Type: cty.Bool, Required: false},
"vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false},
+52 -31
View File
@@ -22,31 +22,50 @@ func (s *stepCreateDisk) Run(ctx context.Context, state multistep.StateBag) mult
driver := state.Get("driver").(vboxcommon.Driver)
ui := state.Get("ui").(packersdk.Ui)
vmName := state.Get("vmName").(string)
format := "VDI"
path := filepath.Join(config.OutputDir, fmt.Sprintf("%s.%s", config.VMName, strings.ToLower(format)))
command := []string{
"createhd",
"--filename", path,
"--size", strconv.FormatUint(uint64(config.DiskSize), 10),
"--format", format,
"--variant", "Standard",
// The main disk and additional disks
diskFullPaths := []string{}
diskSizes := []uint{config.DiskSize}
if len(config.AdditionalDiskSize) == 0 {
// If there are no additional disks, use disk naming as before
diskFullPaths = append(diskFullPaths, filepath.Join(config.OutputDir, fmt.Sprintf("%s.%s", config.VMName, strings.ToLower(format))))
} else {
// If there are additional disks, use consistent naming with numbers
diskFullPaths = append(diskFullPaths, filepath.Join(config.OutputDir, fmt.Sprintf("%s-0.%s", config.VMName, strings.ToLower(format))))
for i, diskSize := range config.AdditionalDiskSize {
path := filepath.Join(config.OutputDir, fmt.Sprintf("%s-%d.%s", config.VMName, i+1, strings.ToLower(format)))
diskFullPaths = append(diskFullPaths, path)
diskSizes = append(diskSizes, diskSize)
}
}
ui.Say("Creating hard drive...")
err := driver.VBoxManage(command...)
if err != nil {
err := fmt.Errorf("Error creating hard drive: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
// Create all required disks
for i := range diskFullPaths {
ui.Say(fmt.Sprintf("Creating hard drive %s with size %d MiB...", diskFullPaths[i], diskSizes[i]))
command := []string{
"createhd",
"--filename", diskFullPaths[i],
"--size", strconv.FormatUint(uint64(diskSizes[i]), 10),
"--format", format,
"--variant", "Standard",
}
err := driver.VBoxManage(command...)
if err != nil {
err := fmt.Errorf("Error creating hard drive: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
}
// Add the IDE controller so we can later attach the disk.
// When the hard disk controller is not IDE, this device is still used
// by VirtualBox to deliver the guest extensions.
err = driver.VBoxManage("storagectl", vmName, "--name", "IDE Controller", "--add", "ide")
err := driver.VBoxManage("storagectl", vmName, "--name", "IDE Controller", "--add", "ide")
if err != nil {
err := fmt.Errorf("Error creating disk controller: %s", err)
state.Put("error", err)
@@ -116,21 +135,23 @@ func (s *stepCreateDisk) Run(ctx context.Context, state multistep.StateBag) mult
discard = "on"
}
command = []string{
"storageattach", vmName,
"--storagectl", controllerName,
"--port", "0",
"--device", "0",
"--type", "hdd",
"--medium", path,
"--nonrotational", nonrotational,
"--discard", discard,
}
if err := driver.VBoxManage(command...); err != nil {
err := fmt.Errorf("Error attaching hard drive: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
for i := range diskFullPaths {
command := []string{
"storageattach", vmName,
"--storagectl", controllerName,
"--port", strconv.FormatUint(uint64(i), 10),
"--device", "0",
"--type", "hdd",
"--medium", diskFullPaths[i],
"--nonrotational", nonrotational,
"--discard", discard,
}
if err := driver.VBoxManage(command...); err != nil {
err := fmt.Errorf("Error attaching hard drive: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
}
return multistep.ActionContinue
+21 -2
View File
@@ -26,7 +26,7 @@ func (s *stepCreateVM) Run(ctx context.Context, state multistep.StateBag) multis
name := config.VMName
commands := make([][]string, 10)
commands := make([][]string, 14)
commands[0] = []string{
"createvm", "--name", name,
"--ostype", config.GuestOSType, "--register",
@@ -59,7 +59,26 @@ func (s *stepCreateVM) Run(ctx context.Context, state multistep.StateBag) multis
"--nictype6", config.NICType,
"--nictype7", config.NICType,
"--nictype8", config.NICType}
commands[9] = []string{"modifyvm", name, "--graphicscontroller", config.GfxController}
commands[9] = []string{"modifyvm", name, "--graphicscontroller", config.GfxController, "--vram", strconv.FormatUint(uint64(config.GfxVramSize), 10)}
if config.RTCTimeBase == "UTC" {
commands[10] = []string{"modifyvm", name, "--rtcuseutc", "on"}
} else {
commands[10] = []string{"modifyvm", name, "--rtcuseutc", "off"}
}
if config.NestedVirt == true {
commands[11] = []string{"modifyvm", name, "--nested-hw-virt", "on"}
} else {
commands[11] = []string{"modifyvm", name, "--nested-hw-virt", "off"}
}
if config.GfxAccelerate3D {
commands[12] = []string{"modifyvm", name, "--accelerate3d", "on"}
} else {
commands[12] = []string{"modifyvm", name, "--accelerate3d", "off"}
}
if config.GfxEFIResolution != "" {
commands[13] = []string{"setextradata", name, "VBoxInternal2/EfiGraphicsResolution", config.GfxEFIResolution}
}
ui.Say("Creating virtual machine...")
for _, command := range commands {
+2 -7
View File
@@ -65,12 +65,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
Label: b.config.CDConfig.CDLabel,
},
new(vboxcommon.StepHTTPIPDiscover),
&commonsteps.StepHTTPServer{
HTTPDir: b.config.HTTPDir,
HTTPPortMin: b.config.HTTPPortMin,
HTTPPortMax: b.config.HTTPPortMax,
HTTPAddress: b.config.HTTPAddress,
},
commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig),
&vboxcommon.StepSshKeyPair{
Debug: b.config.PackerDebug,
DebugKeyPath: fmt.Sprintf("%s.pem", b.config.PackerBuildName),
@@ -130,7 +125,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
},
&communicator.StepConnect{
Config: &b.config.CommConfig.Comm,
Host: vboxcommon.CommHost(b.config.CommConfig.Comm.SSHHost),
Host: vboxcommon.CommHost(b.config.CommConfig.Comm.Host()),
SSHConfig: b.config.CommConfig.Comm.SSHConfigFunc(),
SSHPort: vboxcommon.CommPort,
WinRMPort: vboxcommon.CommPort,
@@ -19,6 +19,7 @@ type FlatConfig struct {
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"`
HTTPContent map[string]string `mapstructure:"http_content" cty:"http_content" hcl:"http_content"`
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"`
@@ -138,6 +139,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_content": &hcldec.AttrSpec{Name: "http_content", Type: cty.Map(cty.String), Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},
"http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false},
"http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false},
+2 -7
View File
@@ -64,12 +64,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
KeepRegistered: b.config.KeepRegistered,
},
new(vboxcommon.StepHTTPIPDiscover),
&commonsteps.StepHTTPServer{
HTTPDir: b.config.HTTPDir,
HTTPPortMin: b.config.HTTPPortMin,
HTTPPortMax: b.config.HTTPPortMax,
HTTPAddress: b.config.HTTPAddress,
},
commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig),
&vboxcommon.StepDownloadGuestAdditions{
GuestAdditionsMode: b.config.GuestAdditionsMode,
GuestAdditionsURL: b.config.GuestAdditionsURL,
@@ -114,7 +109,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
},
&communicator.StepConnect{
Config: &b.config.CommConfig.Comm,
Host: vboxcommon.CommHost(b.config.CommConfig.Comm.SSHHost),
Host: vboxcommon.CommHost(b.config.CommConfig.Comm.Host()),
SSHConfig: b.config.CommConfig.Comm.SSHConfigFunc(),
SSHPort: vboxcommon.CommPort,
WinRMPort: vboxcommon.CommPort,
+2
View File
@@ -19,6 +19,7 @@ type FlatConfig struct {
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"`
HTTPContent map[string]string `mapstructure:"http_content" cty:"http_content" hcl:"http_content"`
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"`
@@ -136,6 +137,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_content": &hcldec.AttrSpec{Name: "http_content", Type: cty.Map(cty.String), Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},
"http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false},
"http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false},
+1 -6
View File
@@ -117,12 +117,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
},
&vmwcommon.StepSuppressMessages{},
&vmwcommon.StepHTTPIPDiscover{},
&commonsteps.StepHTTPServer{
HTTPDir: b.config.HTTPDir,
HTTPPortMin: b.config.HTTPPortMin,
HTTPPortMax: b.config.HTTPPortMax,
HTTPAddress: b.config.HTTPAddress,
},
commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig),
&vmwcommon.StepConfigureVNC{
Enabled: !b.config.DisableVNC && !b.config.VNCOverWebsocket,
VNCBindAddress: b.config.VNCBindAddress,
+2
View File
@@ -19,6 +19,7 @@ type FlatConfig struct {
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"`
HTTPContent map[string]string `mapstructure:"http_content" cty:"http_content" hcl:"http_content"`
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"`
@@ -167,6 +168,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_content": &hcldec.AttrSpec{Name: "http_content", Type: cty.Map(cty.String), Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},
"http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false},
"http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false},
+1 -6
View File
@@ -108,12 +108,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
},
&vmwcommon.StepSuppressMessages{},
&vmwcommon.StepHTTPIPDiscover{},
&commonsteps.StepHTTPServer{
HTTPDir: b.config.HTTPDir,
HTTPPortMin: b.config.HTTPPortMin,
HTTPPortMax: b.config.HTTPPortMax,
HTTPAddress: b.config.HTTPAddress,
},
commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig),
&vmwcommon.StepUploadVMX{
RemoteType: b.config.RemoteType,
},
+2
View File
@@ -19,6 +19,7 @@ type FlatConfig struct {
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"`
HTTPContent map[string]string `mapstructure:"http_content" cty:"http_content" hcl:"http_content"`
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"`
@@ -149,6 +150,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_content": &hcldec.AttrSpec{Name: "http_content", Type: cty.Map(cty.String), Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},
"http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false},
"http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false},
+1 -6
View File
@@ -89,12 +89,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
HTTPIP: b.config.BootConfig.HTTPIP,
Network: b.config.WaitIpConfig.GetIPNet(),
},
&commonsteps.StepHTTPServer{
HTTPDir: b.config.HTTPDir,
HTTPPortMin: b.config.HTTPPortMin,
HTTPPortMax: b.config.HTTPPortMax,
HTTPAddress: b.config.HTTPAddress,
},
commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig),
&common.StepSshKeyPair{
Debug: b.config.PackerDebug,
DebugKeyPath: fmt.Sprintf("%s.pem", b.config.PackerBuildName),
+2
View File
@@ -20,6 +20,7 @@ type FlatConfig struct {
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"`
HTTPContent map[string]string `mapstructure:"http_content" cty:"http_content" hcl:"http_content"`
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"`
@@ -159,6 +160,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_content": &hcldec.AttrSpec{Name: "http_content", Type: cty.Map(cty.String), Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},
"http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false},
"http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false},
+13 -1
View File
@@ -99,7 +99,19 @@ func (s *StepBootCommand) Run(ctx context.Context, state multistep.StateBag) mul
Shift: shift,
})
if err != nil {
return fmt.Errorf("error typing a boot command (code, down) `%d, %t`: %w", code, down, err)
// retry once if error
ui.Error(fmt.Errorf("error typing a boot command (code, down) `%d, %t`: %w", code, down, err).Error())
ui.Say("trying key input again")
time.Sleep(s.Config.BootGroupInterval)
_, err = vm.TypeOnKeyboard(driver.KeyInput{
Scancode: code,
Ctrl: keyCtrl,
Alt: keyAlt,
Shift: shift,
})
if err != nil {
return fmt.Errorf("error typing a boot command (code, down) `%d, %t`: %w", code, down, err)
}
}
return nil
}
+1 -6
View File
@@ -92,12 +92,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
HTTPIP: b.config.BootConfig.HTTPIP,
Network: b.config.WaitIpConfig.GetIPNet(),
},
&commonsteps.StepHTTPServer{
HTTPDir: b.config.HTTPDir,
HTTPPortMin: b.config.HTTPPortMin,
HTTPPortMax: b.config.HTTPPortMax,
HTTPAddress: b.config.HTTPAddress,
},
commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig),
&common.StepRun{
Config: &b.config.RunConfig,
SetOrder: true,
+2
View File
@@ -20,6 +20,7 @@ type FlatConfig struct {
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"`
HTTPContent map[string]string `mapstructure:"http_content" cty:"http_content" hcl:"http_content"`
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"`
@@ -161,6 +162,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
"http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false},
"http_content": &hcldec.AttrSpec{Name: "http_content", Type: cty.Map(cty.String), Required: false},
"http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false},
"http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false},
"http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false},
+8 -16
View File
@@ -389,7 +389,7 @@ func TestBuild(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
defer tt.cleanup(t)
run(t, tt.args, tt.expectedCode)
tt.fileCheck.verify(t)
tt.fileCheck.verify(t, "")
})
}
}
@@ -732,7 +732,7 @@ func TestHCL2PostProcessorForceFlag(t *testing.T) {
if code := c.Run(args); code != 0 {
fatalCommand(t, c.Meta)
}
fCheck.verify(t)
fCheck.verify(t, "")
// Second build should override previous manifest
UUID, _ = uuid.GenerateUUID()
@@ -766,7 +766,7 @@ func TestHCL2PostProcessorForceFlag(t *testing.T) {
if code := c.Run(args); code != 0 {
fatalCommand(t, c.Meta)
}
fCheck.verify(t)
fCheck.verify(t, "")
}
func TestBuildCommand_HCLOnlyExceptOptions(t *testing.T) {
@@ -887,19 +887,19 @@ func (fc fileCheck) expectedFiles() []string {
return expected
}
func (fc fileCheck) verify(t *testing.T) {
func (fc fileCheck) verify(t *testing.T, dir string) {
for _, f := range fc.expectedFiles() {
if !fileExists(f) {
t.Errorf("Expected to find %s", f)
if _, err := os.Stat(filepath.Join(dir, f)); err != nil {
t.Errorf("Expected to find %s: %v", f, err)
}
}
for _, f := range fc.notExpected {
if fileExists(f) {
if _, err := os.Stat(filepath.Join(dir, f)); err == nil {
t.Errorf("Expected to not find %s", f)
}
}
for file, expectedContent := range fc.expectedContent {
content, err := ioutil.ReadFile(file)
content, err := ioutil.ReadFile(filepath.Join(dir, file))
if err != nil {
t.Fatalf("ioutil.ReadFile: %v", err)
}
@@ -909,14 +909,6 @@ func (fc fileCheck) verify(t *testing.T) {
}
}
// fileExists returns true if the filename is found
func fileExists(filename string) bool {
if _, err := os.Stat(filename); err == nil {
return true
}
return false
}
// testCoreConfigBuilder creates a packer CoreConfig that has a file builder
// available. This allows us to test a builder that writes files to disk.
func testCoreConfigBuilder(t *testing.T) *packer.CoreConfig {
+2 -2
View File
@@ -161,12 +161,12 @@ func (va *FormatArgs) AddFlagSets(flags *flag.FlagSet) {
flags.BoolVar(&va.Check, "check", false, "check if the input is formatted")
flags.BoolVar(&va.Diff, "diff", false, "display the diff of formatting changes")
flags.BoolVar(&va.Write, "write", true, "overwrite source files instead of writing to stdout")
flags.BoolVar(&va.Recursive, "recursive", false, "Also process files in subdirectories")
va.MetaArgs.AddFlagSets(flags)
}
// FormatArgs represents a parsed cli line for `packer fmt`
type FormatArgs struct {
MetaArgs
Check, Diff, Write bool
Check, Diff, Write, Recursive bool
}
+2
View File
@@ -87,6 +87,8 @@ func TestHelperProcess(*testing.T) {
switch cmd {
case "console":
os.Exit((&ConsoleCommand{Meta: commandMeta()}).Run(args))
case "fmt":
os.Exit((&FormatCommand{Meta: commandMeta()}).Run(args))
case "inspect":
os.Exit((&InspectCommand{Meta: commandMeta()}).Run(args))
case "build":
+10 -6
View File
@@ -48,9 +48,10 @@ func (c *FormatCommand) RunContext(ctx context.Context, cla *FormatArgs) int {
}
formatter := hclutils.HCL2Formatter{
ShowDiff: cla.Diff,
Write: cla.Write,
Output: os.Stdout,
ShowDiff: cla.Diff,
Write: cla.Write,
Output: os.Stdout,
Recursive: cla.Recursive,
}
bytesModified, diags := formatter.Format(cla.Path)
@@ -90,6 +91,8 @@ Options:
-write=false Don't write to source files
(always disabled if using -check)
-recursive Also process files in subdirectories. By default, only the
given directory (or current directory) is processed.
`
return strings.TrimSpace(helpText)
@@ -105,8 +108,9 @@ func (*FormatCommand) AutocompleteArgs() complete.Predictor {
func (*FormatCommand) AutocompleteFlags() complete.Flags {
return complete.Flags{
"-check": complete.PredictNothing,
"-diff": complete.PredictNothing,
"-write": complete.PredictNothing,
"-check": complete.PredictNothing,
"-diff": complete.PredictNothing,
"-write": complete.PredictNothing,
"-recursive": complete.PredictNothing,
}
}
+124
View File
@@ -1,10 +1,15 @@
package command
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/stretchr/testify/assert"
)
@@ -50,3 +55,122 @@ func TestFmt_unfomattedTemlateDirectory(t *testing.T) {
fatalCommand(t, c.Meta)
}
}
const (
unformattedHCL = `
ami_filter_name ="amzn2-ami-hvm-*-x86_64-gp2"
ami_filter_owners =[ "137112412989" ]
`
formattedHCL = `
ami_filter_name = "amzn2-ami-hvm-*-x86_64-gp2"
ami_filter_owners = ["137112412989"]
`
)
func TestFmt_Recursive(t *testing.T) {
tests := []struct {
name string
formatArgs []string // arguments passed to format
alreadyPresentContent map[string]string
fileCheck
}{
{
name: "nested formats recursively",
formatArgs: []string{"-recursive=true"},
alreadyPresentContent: map[string]string{
"foo/bar/baz.pkr.hcl": unformattedHCL,
"foo/bar/baz/woo.pkrvars.hcl": unformattedHCL,
"potato": unformattedHCL,
"foo/bar/potato": unformattedHCL,
"bar.pkr.hcl": unformattedHCL,
"-": unformattedHCL,
},
fileCheck: fileCheck{
expectedContent: map[string]string{
"foo/bar/baz.pkr.hcl": formattedHCL,
"foo/bar/baz/woo.pkrvars.hcl": formattedHCL,
"potato": unformattedHCL,
"foo/bar/potato": unformattedHCL,
"bar.pkr.hcl": formattedHCL,
"-": unformattedHCL,
}},
},
{
name: "nested no recursive format",
formatArgs: []string{},
alreadyPresentContent: map[string]string{
"foo/bar/baz.pkr.hcl": unformattedHCL,
"foo/bar/baz/woo.pkrvars.hcl": unformattedHCL,
"bar.pkr.hcl": unformattedHCL,
"-": unformattedHCL,
},
fileCheck: fileCheck{
expectedContent: map[string]string{
"foo/bar/baz.pkr.hcl": unformattedHCL,
"foo/bar/baz/woo.pkrvars.hcl": unformattedHCL,
"bar.pkr.hcl": formattedHCL,
"-": unformattedHCL,
}},
},
}
c := &FormatCommand{
Meta: testMeta(t),
}
testDir := "test-fixtures/fmt"
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tempDirectory := mustString(ioutil.TempDir(testDir, "test-dir-*"))
defer os.RemoveAll(tempDirectory)
createFiles(tempDirectory, tt.alreadyPresentContent)
testArgs := append(tt.formatArgs, tempDirectory)
if code := c.Run(testArgs); code != 0 {
ui := c.Meta.Ui.(*packersdk.BasicUi)
out := ui.Writer.(*bytes.Buffer)
err := ui.ErrorWriter.(*bytes.Buffer)
t.Fatalf(
"Bad exit code for test case: %s.\n\nStdout:\n\n%s\n\nStderr:\n\n%s",
tt.name,
out.String(),
err.String())
}
tt.fileCheck.verify(t, tempDirectory)
})
}
}
func Test_fmt_pipe(t *testing.T) {
tc := []struct {
piped string
command []string
env []string
expected string
}{
{unformattedHCL, []string{"fmt", "-"}, nil, formattedHCL},
}
for _, tc := range tc {
t.Run(fmt.Sprintf("echo %q | packer %s", tc.piped, tc.command), func(t *testing.T) {
p := helperCommand(t, tc.command...)
p.Stdin = strings.NewReader(tc.piped)
p.Env = append(p.Env, tc.env...)
fmt.Println(fmt.Sprintf("Path: %s", p.Path))
bs, err := p.Output()
if err != nil {
t.Fatalf("Error occurred running command %v: %s", err, bs)
}
if diff := cmp.Diff(tc.expected, string(bs)); diff != "" {
t.Fatalf("Error in diff: %s", diff)
}
})
}
}
+128 -49
View File
@@ -8,7 +8,9 @@ import (
"os"
"path/filepath"
"reflect"
"regexp"
"sort"
"strconv"
"strings"
texttemplate "text/template"
@@ -120,6 +122,7 @@ var (
amazonSecretsManagerMap = map[string]map[string]interface{}{}
localsVariableMap = map[string]string{}
timestamp = false
isotime = false
)
type BlockParser interface {
@@ -269,18 +272,18 @@ func (uc UnhandleableArgumentError) Error() string {
# Visit %s for more infos.`, uc.Call, uc.Correspondance, uc.Docs)
}
func fallbackReturn(err error, s []byte) []byte {
if strings.Contains(err.Error(), "unhandled") {
return append([]byte(fmt.Sprintf("\n# %s\n", err)), s...)
}
return append([]byte(fmt.Sprintf("\n# could not parse template for following block: %q\n", err)), s...)
}
// transposeTemplatingCalls executes parts of blocks as go template files and replaces
// their result with their hcl2 variant. If something goes wrong the template
// containing the go template string is returned.
func transposeTemplatingCalls(s []byte) []byte {
fallbackReturn := func(err error) []byte {
if strings.Contains(err.Error(), "unhandled") {
return append([]byte(fmt.Sprintf("\n# %s\n", err)), s...)
}
return append([]byte(fmt.Sprintf("\n# could not parse template for following block: %q\n", err)), s...)
}
funcErrors := &multierror.Error{
ErrorFormat: func(es []error) string {
if len(es) == 1 {
@@ -336,8 +339,14 @@ func transposeTemplatingCalls(s []byte) []byte {
return "${local.timestamp}"
},
"isotime": func(a ...string) string {
timestamp = true
return "${local.timestamp}"
if len(a) == 0 {
// returns rfc3339 formatted string.
return "${timestamp()}"
}
// otherwise a valid isotime func has one input.
isotime = true
return fmt.Sprintf("${legacy_isotime(\"%s\")}", a[0])
},
"user": func(in string) string {
if _, ok := localsVariableMap[in]; ok {
@@ -430,14 +439,29 @@ func transposeTemplatingCalls(s []byte) []byte {
Parse(string(s))
if err != nil {
return fallbackReturn(err)
if strings.Contains(err.Error(), "unexpected \"\\\\\" in operand") {
// This error occurs if the operand in the text template used
// escaped quoting \" instead of bactick quoting `
// Create a regex to do a string replace on this block, to fix
// quoting.
q := fixQuoting(string(s))
unquoted := []byte(q)
tpl, err = texttemplate.New("hcl2_upgrade").
Funcs(funcMap).
Parse(string(unquoted))
if err != nil {
return fallbackReturn(err, unquoted)
}
} else {
return fallbackReturn(err, s)
}
}
str := &bytes.Buffer{}
// PASSTHROUGHS is a map of variable-specific golang text template fields
// that should remain in the text template format.
if err := tpl.Execute(str, PASSTHROUGHS); err != nil {
return fallbackReturn(err)
return fallbackReturn(err, s)
}
out := str.Bytes()
@@ -454,14 +478,6 @@ func transposeTemplatingCalls(s []byte) []byte {
// In variableTransposeTemplatingCalls the definition of aws_secretsmanager function will create a data source
// with the same name as the variable.
func variableTransposeTemplatingCalls(s []byte) (isLocal bool, body []byte) {
fallbackReturn := func(err error) []byte {
if strings.Contains(err.Error(), "unhandled") {
return append([]byte(fmt.Sprintf("\n# %s\n", err)), s...)
}
return append([]byte(fmt.Sprintf("\n# could not parse template for following block: %q\n", err)), s...)
}
setIsLocal := func(a ...string) string {
isLocal = true
return ""
@@ -503,14 +519,29 @@ func variableTransposeTemplatingCalls(s []byte) (isLocal bool, body []byte) {
Parse(string(s))
if err != nil {
return isLocal, fallbackReturn(err)
if strings.Contains(err.Error(), "unexpected \"\\\\\" in operand") {
// This error occurs if the operand in the text template used
// escaped quoting \" instead of bactick quoting `
// Create a regex to do a string replace on this block, to fix
// quoting.
q := fixQuoting(string(s))
unquoted := []byte(q)
tpl, err = texttemplate.New("hcl2_upgrade").
Funcs(funcMap).
Parse(string(unquoted))
if err != nil {
return isLocal, fallbackReturn(err, unquoted)
}
} else {
return isLocal, fallbackReturn(err, s)
}
}
str := &bytes.Buffer{}
// PASSTHROUGHS is a map of variable-specific golang text template fields
// that should remain in the text template format.
if err := tpl.Execute(str, PASSTHROUGHS); err != nil {
return isLocal, fallbackReturn(err)
return isLocal, fallbackReturn(err, s)
}
return isLocal, str.Bytes()
@@ -675,12 +706,49 @@ type VariableParser struct {
localsOut []byte
}
func makeLocal(variable *template.Variable, sensitive bool, localBody *hclwrite.Body, localsContent *hclwrite.File, hasLocals *bool) []byte {
if sensitive {
// Create Local block because this is sensitive
sensitiveLocalContent := hclwrite.NewEmptyFile()
body := sensitiveLocalContent.Body()
body.AppendNewline()
sensitiveLocalBody := body.AppendNewBlock("local", []string{variable.Key}).Body()
sensitiveLocalBody.SetAttributeValue("sensitive", cty.BoolVal(true))
sensitiveLocalBody.SetAttributeValue("expression", hcl2shim.HCL2ValueFromConfigValue(variable.Default))
localsVariableMap[variable.Key] = "local"
return sensitiveLocalContent.Bytes()
}
localBody.SetAttributeValue(variable.Key, hcl2shim.HCL2ValueFromConfigValue(variable.Default))
localsVariableMap[variable.Key] = "locals"
*hasLocals = true
return []byte{}
}
func makeVariable(variable *template.Variable, sensitive bool) []byte {
variablesContent := hclwrite.NewEmptyFile()
variablesBody := variablesContent.Body()
variablesBody.AppendNewline()
variableBody := variablesBody.AppendNewBlock("variable", []string{variable.Key}).Body()
variableBody.SetAttributeRaw("type", hclwrite.Tokens{&hclwrite.Token{Bytes: []byte("string")}})
if variable.Default != "" || !variable.Required {
shimmed := hcl2shim.HCL2ValueFromConfigValue(variable.Default)
variableBody.SetAttributeValue("default", shimmed)
}
if sensitive {
variableBody.SetAttributeValue("sensitive", cty.BoolVal(true))
}
return variablesContent.Bytes()
}
func (p *VariableParser) Parse(tpl *template.Template) error {
// OutPut Locals and Local blocks
// Output Locals and Local blocks
localsContent := hclwrite.NewEmptyFile()
localsBody := localsContent.Body()
localsBody.AppendNewline()
localBody := localsBody.AppendNewBlock("locals", nil).Body()
hasLocals := false
if len(p.variablesOut) == 0 {
p.variablesOut = []byte{}
@@ -700,47 +768,34 @@ func (p *VariableParser) Parse(tpl *template.Template) error {
})
}
hasLocals := false
for _, variable := range variables {
variablesContent := hclwrite.NewEmptyFile()
variablesBody := variablesContent.Body()
variablesBody.AppendNewline()
variableBody := variablesBody.AppendNewBlock("variable", []string{variable.Key}).Body()
variableBody.SetAttributeRaw("type", hclwrite.Tokens{&hclwrite.Token{Bytes: []byte("string")}})
// Create new HCL2 "variables" block, and populate the "value"
// field with the "Default" value from the JSON variable.
if variable.Default != "" || !variable.Required {
variableBody.SetAttributeValue("default", hcl2shim.HCL2ValueFromConfigValue(variable.Default))
}
// Interpolate Jsonval first as an hcl variable to determine if it is
// a local.
isLocal, _ := variableTransposeTemplatingCalls([]byte(variable.Default))
sensitive := false
if isSensitiveVariable(variable.Key, tpl.SensitiveVariables) {
sensitive = true
variableBody.SetAttributeValue("sensitive", cty.BoolVal(true))
}
isLocal, out := variableTransposeTemplatingCalls(variablesContent.Bytes())
// Create final HCL block and append.
if isLocal {
if sensitive {
// Create Local block because this is sensitive
localContent := hclwrite.NewEmptyFile()
body := localContent.Body()
body.AppendNewline()
localBody := body.AppendNewBlock("local", []string{variable.Key}).Body()
localBody.SetAttributeValue("sensitive", cty.BoolVal(true))
localBody.SetAttributeValue("expression", hcl2shim.HCL2ValueFromConfigValue(variable.Default))
p.localsOut = append(p.localsOut, transposeTemplatingCalls(localContent.Bytes())...)
localsVariableMap[variable.Key] = "local"
continue
sensitiveBlocks := makeLocal(variable, sensitive, localBody, localsContent, &hasLocals)
if len(sensitiveBlocks) > 0 {
p.localsOut = append(p.localsOut, transposeTemplatingCalls(sensitiveBlocks)...)
}
localBody.SetAttributeValue(variable.Key, hcl2shim.HCL2ValueFromConfigValue(variable.Default))
localsVariableMap[variable.Key] = "locals"
hasLocals = true
continue
}
varbytes := makeVariable(variable, sensitive)
_, out := variableTransposeTemplatingCalls(varbytes)
p.variablesOut = append(p.variablesOut, out...)
}
if hasLocals {
if hasLocals == true {
p.localsOut = append(p.localsOut, transposeTemplatingCalls(localsContent.Bytes())...)
}
return nil
}
@@ -771,6 +826,9 @@ func (p *LocalsParser) Write(out *bytes.Buffer) {
}
fmt.Fprintln(out, `locals { timestamp = regex_replace(timestamp(), "[- TZ:]", "") }`)
}
if isotime {
fmt.Fprintln(out, `# The "legacy_isotime" function has been provided for backwards compatability, but we recommend switching to the timestamp and formatdate functions.`)
}
if len(p.LocalsOut) > 0 {
if p.WithAnnotations {
out.Write([]byte(localsVarHeader))
@@ -1158,6 +1216,7 @@ var PASSTHROUGHS = map[string]string{"NVME_Present": "{{ .NVME_Present }}",
"WinRMPassword": "{{ .WinRMPassword }}",
"DefaultOrganizationID": "{{ .DefaultOrganizationID }}",
"HTTPDir": "{{ .HTTPDir }}",
"HTTPContent": "{{ .HTTPContent }}",
"SegmentPath": "{{ .SegmentPath }}",
"NewVHDSizeBytes": "{{ .NewVHDSizeBytes }}",
"CTyp": "{{ .CTyp }}",
@@ -1221,3 +1280,23 @@ var PASSTHROUGHS = map[string]string{"NVME_Present": "{{ .NVME_Present }}",
"ProviderVagrantfile": "{{ .ProviderVagrantfile }}",
"Sound_Present": "{{ .Sound_Present }}",
}
func fixQuoting(old string) string {
// This regex captures golang template functions that use escaped quotes:
// {{ env \"myvar\" }}
re := regexp.MustCompile(`{{\s*\w*\s*(\\".*\\")\s*}}`)
body := re.ReplaceAllFunc([]byte(old), func(s []byte) []byte {
// Get the capture group
group := re.ReplaceAllString(string(s), `$1`)
unquoted, err := strconv.Unquote(fmt.Sprintf("\"%s\"", group))
if err != nil {
return s
}
return []byte(strings.Replace(string(s), group, unquoted, 1))
})
return string(body)
}
+3 -2
View File
@@ -29,6 +29,7 @@ func Test_hcl2_upgrade(t *testing.T) {
{folder: "variables-only", flags: []string{}},
{folder: "variables-with-variables", flags: []string{}},
{folder: "complete-variables-with-template-engine", flags: []string{}},
{folder: "escaping", flags: []string{}},
}
for _, tc := range tc {
@@ -46,8 +47,8 @@ func Test_hcl2_upgrade(t *testing.T) {
if err != nil {
t.Fatalf("%v %s", err, bs)
}
expected := mustBytes(ioutil.ReadFile(expectedPath))
actual := mustBytes(ioutil.ReadFile(outputPath))
expected := string(mustBytes(ioutil.ReadFile(expectedPath)))
actual := string(mustBytes(ioutil.ReadFile(outputPath)))
if diff := cmp.Diff(expected, actual); diff != "" {
t.Fatalf("unexpected output: %s", diff)
+45 -2
View File
@@ -121,13 +121,56 @@ func (c *InitCommand) RunContext(buildCtx context.Context, cla *InitArgs) int {
Getters: getters,
})
if err != nil {
c.Ui.Error(err.Error())
ret = 1
if pluginRequirement.Implicit {
msg := fmt.Sprintf(`
Warning! At least one component used in your config file(s) has moved out of
Packer into the %q plugin.
For that reason, Packer init tried to install the latest version of the %s
plugin. Unfortunately, this failed :
%s`,
pluginRequirement.Identifier,
pluginRequirement.Identifier.Type,
err)
c.Ui.Say(msg)
} else {
c.Ui.Error(err.Error())
ret = 1
}
}
if newInstall != nil {
if pluginRequirement.Implicit {
msg := fmt.Sprintf("Installed implicitly required plugin %s %s in %q", pluginRequirement.Identifier, newInstall.Version, newInstall.BinaryPath)
ui.Say(msg)
warn := fmt.Sprintf(`
Warning, at least one component used in your config file(s) has moved out of
Packer into the %[2]q plugin and is now being implicitly required.
For more details on implicitly required plugins see https://packer.io/docs/commands/init#implicit-required-plugin
To avoid any backward incompatible changes with your
config file you may want to lock the plugin version by pasting the following to your config:
packer {
required_plugins {
%[1]s = {
source = "%[2]s"
version = "~> %[3]s"
}
}
}
`,
pluginRequirement.Identifier.Type,
pluginRequirement.Identifier,
newInstall.Version,
)
ui.Error(warn)
continue
}
msg := fmt.Sprintf("Installed plugin %s %s in %q", pluginRequirement.Identifier, newInstall.Version, newInstall.BinaryPath)
ui.Say(msg)
}
}
return ret
}
-10
View File
@@ -24,7 +24,6 @@ import (
azuredtlbuilder "github.com/hashicorp/packer/builder/azure/dtl"
cloudstackbuilder "github.com/hashicorp/packer/builder/cloudstack"
digitaloceanbuilder "github.com/hashicorp/packer/builder/digitalocean"
dockerbuilder "github.com/hashicorp/packer/builder/docker"
filebuilder "github.com/hashicorp/packer/builder/file"
googlecomputebuilder "github.com/hashicorp/packer/builder/googlecompute"
hcloudbuilder "github.com/hashicorp/packer/builder/hcloud"
@@ -73,10 +72,6 @@ import (
checksumpostprocessor "github.com/hashicorp/packer/post-processor/checksum"
compresspostprocessor "github.com/hashicorp/packer/post-processor/compress"
digitaloceanimportpostprocessor "github.com/hashicorp/packer/post-processor/digitalocean-import"
dockerimportpostprocessor "github.com/hashicorp/packer/post-processor/docker-import"
dockerpushpostprocessor "github.com/hashicorp/packer/post-processor/docker-push"
dockersavepostprocessor "github.com/hashicorp/packer/post-processor/docker-save"
dockertagpostprocessor "github.com/hashicorp/packer/post-processor/docker-tag"
googlecomputeexportpostprocessor "github.com/hashicorp/packer/post-processor/googlecompute-export"
googlecomputeimportpostprocessor "github.com/hashicorp/packer/post-processor/googlecompute-import"
manifestpostprocessor "github.com/hashicorp/packer/post-processor/manifest"
@@ -124,7 +119,6 @@ var Builders = map[string]packersdk.Builder{
"azure-dtl": new(azuredtlbuilder.Builder),
"cloudstack": new(cloudstackbuilder.Builder),
"digitalocean": new(digitaloceanbuilder.Builder),
"docker": new(dockerbuilder.Builder),
"file": new(filebuilder.Builder),
"googlecompute": new(googlecomputebuilder.Builder),
"hcloud": new(hcloudbuilder.Builder),
@@ -195,10 +189,6 @@ var PostProcessors = map[string]packersdk.PostProcessor{
"checksum": new(checksumpostprocessor.PostProcessor),
"compress": new(compresspostprocessor.PostProcessor),
"digitalocean-import": new(digitaloceanimportpostprocessor.PostProcessor),
"docker-import": new(dockerimportpostprocessor.PostProcessor),
"docker-push": new(dockerpushpostprocessor.PostProcessor),
"docker-save": new(dockersavepostprocessor.PostProcessor),
"docker-tag": new(dockertagpostprocessor.PostProcessor),
"googlecompute-export": new(googlecomputeexportpostprocessor.PostProcessor),
"googlecompute-import": new(googlecomputeimportpostprocessor.PostProcessor),
"manifest": new(manifestpostprocessor.PostProcessor),
@@ -5,6 +5,7 @@ variable "env_test" {
}
locals { timestamp = regex_replace(timestamp(), "[- TZ:]", "") }
# The "legacy_isotime" function has been provided for backwards compatability, but we recommend switching to the timestamp and formatdate functions.
# 5 errors occurred upgrading the following block:
# unhandled "lower" call:
@@ -33,7 +34,7 @@ locals { timestamp = regex_replace(timestamp(), "[- TZ:]", "") }
# Visit https://www.packer.io/docs/templates/hcl_templates/functions/string/upper for more infos.
locals {
build_timestamp = "${local.timestamp}"
iso_datetime = "${local.timestamp}"
iso_datetime = "${legacy_isotime("2006-01-02T15:04:05Z07:00")}"
lower = "{{ lower `HELLO` }}"
pwd = "${path.cwd}"
replace = "{{ replace `b` `c` `ababa` 2 }}"
@@ -198,7 +198,7 @@ build {
# 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-{{ clean_resource_name `${local.timestamp}` }}"]
inline = ["echo mybuild-{{ clean_resource_name `${timestamp()}` }}"]
}
@@ -0,0 +1,31 @@
variable "conf" {
type = string
default = "${env("ONE")}-${env("ANOTHER")}-${env("BACKTICKED")}"
}
variable "manyspaces" {
type = string
default = "${env("ASDFASDF")}"
}
variable "nospaces" {
type = string
default = "${env("SOMETHING")}"
}
locals { timestamp = regex_replace(timestamp(), "[- TZ:]", "") }
# The "legacy_isotime" function has been provided for backwards compatability, but we recommend switching to the timestamp and formatdate functions.
source "null" "autogenerated_1" {
communicator = "none"
}
build {
sources = ["source.null.autogenerated_1"]
provisioner "shell-local" {
inline = ["echo ${var.conf}-${local.timestamp}-${legacy_isotime("01-02-2006")}"]
}
}
@@ -0,0 +1,21 @@
{
"variables": {
"conf": "{{ env \"ONE\" }}-{{env \"ANOTHER\"}}-{{ env `BACKTICKED` }}",
"nospaces": "{{env \"SOMETHING\"}}",
"manyspaces": "{{ env \"ASDFASDF\"}}"
},
"builders": [
{
"type": "null",
"communicator": "none"
}
],
"provisioners": [
{
"type": "shell-local",
"inline": [
"echo {{user \"conf\"}}-{{timestamp}}-{{isotime \"01-02-2006\"}}"
]
}
]
}
@@ -151,7 +151,7 @@ build {
# 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-{{ clean_resource_name `${local.timestamp}` }}"]
inline = ["echo mybuild-{{ clean_resource_name `${timestamp()}` }}"]
}
+8
View File
@@ -39,3 +39,11 @@ func (c *configDirSingleton) dir(key string) string {
c.dirs[key] = mustString(ioutil.TempDir("", "pkr-test-cfg-dir-"+key))
return c.dirs[key]
}
// fileExists returns true if the filename is found
func fileExists(filename string) bool {
if _, err := os.Stat(filename); err == nil {
return true
}
return false
}
+60
View File
@@ -0,0 +1,60 @@
package command
import (
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
// Previously core-bundled components, split into their own plugins but
// still vendored with Packer for now. Importing as library instead of
// forcing use of packer init, until packer v1.8.0
exoscaleimportpostprocessor "github.com/exoscale/packer-plugin-exoscale/post-processor/exoscale-import"
dockerbuilder "github.com/hashicorp/packer-plugin-docker/builder/docker"
dockerimportpostprocessor "github.com/hashicorp/packer-plugin-docker/post-processor/docker-import"
dockerpushpostprocessor "github.com/hashicorp/packer-plugin-docker/post-processor/docker-push"
dockersavepostprocessor "github.com/hashicorp/packer-plugin-docker/post-processor/docker-save"
dockertagpostprocessor "github.com/hashicorp/packer-plugin-docker/post-processor/docker-tag"
)
// VendoredBuilders are builder components that were once bundled with the
// Packer core, but are now being imported from their counterpart plugin repos
var VendoredBuilders = map[string]packersdk.Builder{
"docker": new(dockerbuilder.Builder),
}
// VendoredProvisioners are provisioner components that were once bundled with the
// Packer core, but are now being imported from their counterpart plugin repos
var VendoredProvisioners = map[string]packersdk.Provisioner{}
// VendoredPostProcessors are post-processor components that were once bundled with the
// Packer core, but are now being imported from their counterpart plugin repos
var VendoredPostProcessors = map[string]packersdk.PostProcessor{
"docker-import": new(dockerimportpostprocessor.PostProcessor),
"docker-push": new(dockerpushpostprocessor.PostProcessor),
"docker-save": new(dockersavepostprocessor.PostProcessor),
"docker-tag": new(dockertagpostprocessor.PostProcessor),
"exoscale-import": new(exoscaleimportpostprocessor.PostProcessor),
}
// Upon init lets load up any plugins that were vendored manually into the default
// set of plugins.
func init() {
for k, v := range VendoredBuilders {
if _, ok := Builders[k]; ok {
continue
}
Builders[k] = v
}
for k, v := range VendoredProvisioners {
if _, ok := Provisioners[k]; ok {
continue
}
Provisioners[k] = v
}
for k, v := range VendoredPostProcessors {
if _, ok := PostProcessors[k]; ok {
continue
}
PostProcessors[k] = v
}
}

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