Merge branch 'master' into local-vsphere-template

This commit is contained in:
Matthew Hooker 2018-02-09 11:18:13 -08:00 committed by GitHub
commit 975b50005b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
984 changed files with 63844 additions and 6549 deletions

View File

@ -6,9 +6,9 @@ sudo: false
language: go
go:
- 1.7.4
- 1.8.3
- 1.9
- 1.7.x
- 1.8.x
- 1.x
install:
- make deps

View File

@ -1,24 +1,139 @@
## (UNRELEASED)
### IMRPOVEMENTS:
### BACKWARDS INCOMPATIBILITIES:
* core: Affects Windows guests: User variables containing Powershell special characters no longer need to be escaped.[GH-5376]
* provisioner/powershell: Regression from v1.1.1 forcing extra escaping of environment variables in the non-elevated provisioner has been fixed. [GH-5515]
* 3rd party plugins: We have moved internal dependencies, meaning your 3rd party plugins will no longer compile (however existing builds will still work fine); the work to fix them is minimal and documented in GH-5810. [GH-5810]
* provisioner/file: We've made destination semantics more consistent across the various communicators. In general, if the destination is a directory, files will be uploaded into the directory instead of failing. This mirrors the behavior of `rsync`. There's a chance some users might be depending on the previous buggy behavior, so it's worth ensuring your configuration is correct. [GH-5426]
* builder/openstack: Extension support has been removed. To use OpenStack builder with the OpenStack Newton (Oct 2016) or earlier, we recommend you use Packer v1.1.2 or earlier version.
* builder/amazon: The `ssh_private_ip` option has been removed. Instead, please use `"ssh_interface": "private"`. A fixer has been written for this, which can be invoked with `packer fix`. [GH-5876]
* post-processor/docker-push: Add `aws_profile` option to control the aws profile for ECR. [GH-5470]
* builder/docker: Add `aws_profile` option to control the aws profile for ECR. [GH-5470]
* post-processor/vsphere: Properly capture `ovftool` output. [GH-5499]
* builder/hyper-v: Also disable automatic checkpoints for gen 2 VMs. [GH-5517]
* builder/hyper-v: Add `disk_additional_size` option to allow for up to 64 additional disks. [GH-5491]
* builder/amazon: correctly deregister AMIs when `force_deregister` is set. [GH-5525]
* builder/digitalocean: Add `ipv6` option to enable on droplet. [GH-5534]
* builder/triton: Add `source_machine_image_filter` option to select an image ID based on a variety of parameters. [GH-5538]
* communicator/ssh: Add socks 5 proxy support. [GH-5439]
* builder/lxc: Add new `publish_properties` field to set image properties. [GH-5475]
* builder/virtualbox-ovf: Retry while removing VM to solve for transient errors. [GH-5512]
### IMPROVEMENTS:
* **New builder:** `scaleway` - The Scaleway Packer builder is able to create new images for use with Scaleway BareMetal and Virtual cloud server. [GH-4770]
* **New builder:** `ncloud` for building server images using the NAVER Cloud Platform. [GH-5791]
* **New builder:** `oci-classic` for building new custom images for use with Oracle Cloud Infrastructure Classic Compute. [GH-5819]
* builder/docker: Remove credentials from being shown in the log. [GH-5666]
* builder/triton: Triton RBAC is now supported. [GH-5741]
* provisioner/ansible: Improve user retrieval. [GH-5758]
* post-processor/docker: Remove credentials from being shown in the log. [GH-5666]
* builder/amazon: Warn during prepare if we didn't get both an access key and a secret key when we were expecting one. [GH-5762]
* builder/amazon: Replace `InstanceStatusOK` check with `InstanceReady`. This reduces build times universally while still working for all instance types. [GH-5678]
* builder/amazon: Add `kms_key_id` option to block device mappings. [GH-5774]
* builder/hyper-v: New option to use differential disks and Inline disk creation to improve build time and reduce disk usage [GH-5631]
* post-processor/vagrant: Add vagrant post-processor support for Google [GH-5732]
* provisioner/chef: Added Policyfile support to chef-client provisioner. [GH-5831]
* builder/qemu: Add Intel HAXM support to QEMU builder [GH-5738]
* communicator/ssh: Add session-level keep-alives [GH-5830]
* post-processor/amazon-import: Allow user to specify role name in amazon-import [GH-5817]
* provisioner/chef: Add support for 'trusted_certs_dir' chef-client configuration option [GH-5790]
* builder/triton: Updated triton-go dependencies, allowing better error handling. [GH-5795]
* core: Improved error logging in floppy file handling. [GH-5802]
* provisioner/amazon: Use Amazon SDK's InstanceRunning waiter instead of InstanceStatusOK waiter [GH-5773]
* builder/amazon: Add Paris region (eu-west-3) [GH-5718]
* builder/azure: Add validation for incorrect VHD URLs [GH-5695]
* builder/amazon: Remove Session Token (STS) from being shown in the log. [GH-5665]
### BUG FIXES:
* builder/docker: Remove `login_email`, which no longer exists in the docker client. [GH-5511]
* builder/triton: Fix a bug where partially created images can be reported as complete. [GH-5566]
* builder/amazon: region is set from profile, if profile is set, rather than being overridden by metadata [GH-5562]
* builder/alicloud-ecs: Attach keypair before starting instance in alicloud builder [GH-5739]
* builder/vmware: Fixed file handle leak that may have caused race conditions in vmware builder [GH-5767]
* provisioner/powershell: Regression from v1.1.1 forcing extra escaping of environment variables in the non-elevated provisioner has been fixed. [GH-5515]
* provisioner/ansible: The "default extra variables" feature added in Packer v1.0.1 caused the ansible-local provisioner to fail when an --extra-vars argument was specified in the extra_arguments configuration option; this has been fixed. [GH-5335]
* communicator/ssh: Add deadline to SSH connection to prevent Packer hangs after script provisioner reboots vm [GH-4684]
* builder/virtualbox: Fix regression affecting users running Packer on a Windows host that kept Packer from finding Virtualbox guest additions if Packer ran on a different drive from the one where the guest additions were stored. [GH-5761]
* builder/virtualbox: Fix interpolation ordering so that edge cases around guest_additions_url are handled correctly [GH-5757]
* builder/amazon: NewSession now inherits MaxRetries and other settings. [GH-5719]
## 1.1.3 (December 8, 2017)
### IMPROVEMENTS:
* builder/alicloud-ecs: Add security token support and set TLS handshake
timeout through environment variable. [GH-5641]
* builder/amazon: Add a new parameter `ssh_interface`. Valid values include
`public_ip`, `private_ip`, `public_dns` or `private_dns`. [GH-5630]
* builder/azure: Add sanity checks for resource group names [GH-5599]
* builder/azure: Allow users to specify an existing resource group to use,
instead of creating a new one for every run. [GH-5548]
* builder/hyper-v: Add support for differencing disk. [GH-5458]
* builder/vmware-iso: Improve logging of network errors. [GH-5456]
* core: Add new `packer_version` template engine. [GH-5619]
* core: Improve logic checking for downloaded ISOs in case where user has
provided more than one URL in `iso_urls` [GH-5632]
* provisioner/ansible-local: Add ability to clean staging directory. [GH-5618]
### BUG FIXES:
* builder/amazon: Allow `region` to appear in `ami_regions`. [GH-5660]
* builder/amazon: `C5` instance types now build more reliably. [GH-5678]
* builder/amazon: Correctly set AWS region if given in template along with a
profile. [GH-5676]
* builder/amazon: Prevent `sriov_support` and `ena_support` from being used
with spot instances, which would cause a build failure. [GH-5679]
* builder/hyper-v: Fix interpolation context for user variables in
`boot_command` [GH-5547]
* builder/qemu: Set default disk size to 40960 MB to prevent boot failures.
[GH-5588]
* builder/vmware: Correctly detect Windows boot on vmware workstation.
[GH-5672]
* core: Fix windows path regression when downloading ISOs. [GH-5591]
* provisioner/chef: Fix chef installs on Windows. [GH-5649]
## 1.1.2 (November 15, 2017)
### IMPROVEMENTS:
* builder/amazon: Correctly deregister AMIs when `force_deregister` is set.
[GH-5525]
* builder/digitalocean: Add `ipv6` option to enable on droplet. [GH-5534]
* builder/docker: Add `aws_profile` option to control the aws profile for ECR.
[GH-5470]
* builder/google: Add `clean_image_name` template engine. [GH-5463]
* builder/google: Allow selecting container optimized images. [GH-5576]
* builder/google: Interpolate network and subnetwork values, rather than
relying on an API call that packer may not have permission for. [GH-5343]
* builder/hyper-v: Add `disk_additional_size` option to allow for up to 64
additional disks. [GH-5491]
* builder/hyper-v: Also disable automatic checkpoints for gen 2 VMs. [GH-5517]
* builder/lxc: Add new `publish_properties` field to set image properties.
[GH-5475]
* builder/lxc: Add three new configuration option categories to LXC builder:
`create_options`, `start_options`, and `attach_options`. [GH-5530]
* builder/triton: Add `source_machine_image_filter` option to select an image
ID based on a variety of parameters. [GH-5538]
* builder/virtualbox-ovf: Error during prepare if source path doesn't exist.
[GH-5573]
* builder/virtualbox-ovf: Retry while removing VM to solve for transient
errors. [GH-5512]
* communicator/ssh: Add socks 5 proxy support. [GH-5439]
* core/iso_config: Support relative paths in checksum file. [GH-5578]
* core: Rewrite vagrantfile code to make cross-platform development easier.
[GH-5539]
* post-processor/docker-push: Add `aws_profile` option to control the aws
profile for ECR. [GH-5470]
* post-processor/vsphere: Properly capture `ovftool` output. [GH-5499]
### BUG FIXES:
* builder/amazon: Add a delay option to security group waiter. [GH-5536]
* builder/amazon: Fix regressions relating to spot instances and EBS volumes.
[GH-5495]
* builder/amazon: Set region from profile, if profile is set, rather than being
overridden by metadata. [GH-5562]
* builder/docker: Remove `login_email`, which no longer exists in the docker
client. [GH-5511]
* builder/hyperv: Fix admin check that was causing powershell failures.
[GH-5510]
* builder/oracle: Defaulting of OCI builder region will first check the packer
template and the OCI config file. [GH-5407]
* builder/triton: Fix a bug where partially created images can be reported as
complete. [GH-5566]
* post-processor/vsphere: Use the vm disk path information to re-create the vmx
datastore path. [GH-5567]
* provisioner/windows-restart: Wait for restart no longer endlessly loops if
user specifies a custom restart check command. [GH-5563]
## 1.1.1 (October 13, 2017)
@ -227,7 +342,7 @@
* core: Remove logging that shouldn't be there when running commands. [GH-5042]
* provisioner/shell: Fix bug where scripts were being run under `sh`. [GH-5043]
### IMRPOVEMENTS:
### IMPROVEMENTS:
* provisioner/windows-restart: make it clear that timeouts come from the
provisioner, not winrm. [GH-5040]

View File

@ -13,6 +13,7 @@
/builder/oracle/ @prydie @owainlewis
/builder/profitbricks/ @jasmingacic
/builder/triton/ @jen20 @sean-
/builder/ncloud/ @YuSungDuk
# provisioners

View File

@ -1,46 +1,46 @@
# Contributing to Packer
**First:** if you're unsure or afraid of _anything_, just ask
or submit the issue or pull request anyways. You won't be yelled at for
giving your best effort. The worst that can happen is that you'll be
politely asked to change something. We appreciate any sort of contributions,
and don't want a wall of rules to get in the way of that.
**First:** if you're unsure or afraid of _anything_, just ask or submit the
issue or pull request anyways. You won't be yelled at for giving your best
effort. The worst that can happen is that you'll be politely asked to change
something. We appreciate any sort of contributions, and don't want a wall of
rules to get in the way of that.
However, for those individuals who want a bit more guidance on the
best way to 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.
However, for those individuals who want a bit more guidance on the best way to
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.
## Issues
### Reporting an Issue
* Make sure you test against the latest released version. It is possible
we already fixed the bug you're experiencing.
* Make sure you test against the latest released version. It is possible we
already fixed the bug you're experiencing.
* Run the command with debug ouput with the environment variable
`PACKER_LOG`. For example: `PACKER_LOG=1 packer build template.json`. Take
the *entire* output and create a [gist](https://gist.github.com) for linking
to in your issue. Packer should strip sensitive keys from the output,
but take a look through just in case.
* Run the command with debug output with the environment variable `PACKER_LOG`.
For example: `PACKER_LOG=1 packer build template.json`. Take the _entire_
output and create a [gist](https://gist.github.com) for linking to in your
issue. Packer should strip sensitive keys from the output, but take a look
through just in case.
* Provide a reproducible test case. If a contributor can't reproduce an
issue, then it dramatically lowers the chances it'll get fixed. And in
some cases, the issue will eventually be closed.
* Provide a reproducible test case. If a contributor can't reproduce an issue,
then it dramatically lowers the chances it'll get fixed. And in some cases,
the issue will eventually be closed.
* Respond promptly to any questions made by the Packer team to your issue.
Stale issues will be closed.
* Respond promptly to any questions made by the Packer team to your issue. Stale
issues will be closed.
### Issue Lifecycle
1. The issue is reported.
2. The issue is verified and categorized by a Packer collaborator.
Categorization is done via tags. For example, bugs are marked as "bugs"
and easy fixes are marked as "easy".
Categorization is done via tags. For example, bugs are marked as "bugs" and
easy fixes are marked as "easy".
3. Unless it is critical, the issue is left for a period of time (sometimes
many weeks), giving outside contributors a chance to address the issue.
3. Unless it is critical, the issue is left for a period of time (sometimes many
weeks), giving outside contributors a chance to address the issue.
4. The issue is addressed in a pull request or commit. The issue will be
referenced in the commit message so that the code that fixes it is clearly
@ -50,86 +50,108 @@ it raises the chances we can quickly merge or address your contributions.
## Setting up Go to work on Packer
If you have never worked with Go before, you will have to complete the
following steps in order to be able to compile and test Packer. These instructions target POSIX-like environments (Mac OS X, Linux, Cygwin, etc.) so you may need to adjust them for Windows or other shells.
If you have never worked with Go before, you will have to complete the following
steps in order to be able to compile and test Packer. These instructions target
POSIX-like environments (Mac OS X, Linux, Cygwin, etc.) so you may need to
adjust them for Windows or other shells.
1. [Download](https://golang.org/dl) and install Go. The instructions below
are for go 1.7. Earlier versions of Go are no longer supported.
1. [Download](https://golang.org/dl) and install Go. The instructions below are
for go 1.7. Earlier versions of Go are no longer supported.
2. Set and export the `GOPATH` environment variable and update your `PATH`. For
example, you can add to your `.bash_profile`.
example, you can add the following to your `.bash_profile` (or comparable
shell startup scripts):
```
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin
```
```
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin
```
3. Download the Packer source (and its dependencies) by running `go get
github.com/hashicorp/packer`. This will download the Packer source to
3. Download the Packer source (and its dependencies) by running
`go get github.com/hashicorp/packer`. This will download the Packer source to
`$GOPATH/src/github.com/hashicorp/packer`.
4. When working on packer `cd $GOPATH/src/github.com/hashicorp/packer` so you
can run `make` and easily access other files. Run `make help` to get
4. When working on Packer, first `cd $GOPATH/src/github.com/hashicorp/packer`
so you can run `make` and easily access other files. Run `make help` to get
information about make targets.
5. Make your changes to the Packer source. You can run `make` in
`$GOPATH/src/github.com/hashicorp/packer` to run tests and build the packer
`$GOPATH/src/github.com/hashicorp/packer` to run tests and build the Packer
binary. Any compilation errors will be shown when the binaries are
rebuilding. If you don't have `make` you can simply run `go build -o bin/packer .` from the project root.
rebuilding. If you don't have `make` you can simply run
`go build -o bin/packer .` from the project root.
6. After running building packer successfully, use
6. After running building Packer successfully, use
`$GOPATH/src/github.com/hashicorp/packer/bin/packer` to build a machine and
verify your changes work. For instance: `$GOPATH/src/github.com/hashicorp/packer/bin/packer build template.json`.
verify your changes work. For instance:
`$GOPATH/src/github.com/hashicorp/packer/bin/packer build template.json`.
7. If everything works well and the tests pass, run `go fmt` on your code
before submitting a pull-request.
7. If everything works well and the tests pass, run `go fmt` on your code before
submitting a pull-request.
### Opening an Pull Request
When you are ready to open a pull-request, you will need to [fork packer](https://github.com/hashicorp/packer#fork-destination-box), push your changes to your fork, and then open a pull-request.
When you are ready to open a pull-request, you will need to
[fork Packer](https://github.com/hashicorp/packer#fork-destination-box), push
your changes to your fork, and then open a pull-request.
For example, my github username is `cbednarski` so I would do the following:
For example, my github username is `cbednarski`, so I would do the following:
git checkout -b f-my-feature
// develop a patch
git push https://github.com/cbednarski/packer f-my-feature
```
git checkout -b f-my-feature
# Develop a patch.
git push https://github.com/cbednarski/Packer f-my-feature
```
From there, open your fork in your browser to open a new pull-request.
**Note** Go infers package names from their filepaths. This means `go build` will break if you `git clone` your fork instead of using `go get` on the main packer project.
**Note:** Go infers package names from their file paths. This means `go build`
will break if you `git clone` your fork instead of using `go get` on the main
Packer project.
### Tips for Working on Packer
#### Working on forks
The easiest way to work on a fork is to set it as a remote of the packer project. After following the steps in "Setting up Go to work on Packer":
The easiest way to work on a fork is to set it as a remote of the Packer
project. After following the steps in "Setting up Go to work on Packer":
1. Navigate to $GOPATH/src/github.com/hashicorp/packer
2. Add the remote `git remote add <name of remote> <github url of fork>`. For example `git remote add mwhooker https://github.com/mwhooker/packer.git`.
1. Navigate to `$GOPATH/src/github.com/hashicorp/packer`
2. Add the remote by running
`git remote add <name of remote> <github url of fork>`. For example:
`git remote add mwhooker https://github.com/mwhooker/packer.git`.
3. Checkout a feature branch: `git checkout -b new-feature`
4. Make changes
5. (Optional) Push your changes to the fork: `git push -u <name of remote> new-feature`
5. (Optional) Push your changes to the fork:
`git push -u <name of remote> new-feature`
This way you can push to your fork to create a PR, but the code on disk still lives in the spot where the go cli tools are expecting to find it.
This way you can push to your fork to create a PR, but the code on disk still
lives in the spot where the go cli tools are expecting to find it.
#### Govendor
If you are submitting a change that requires new or updated dependencies, please include them in `vendor/vendor.json` and in the `vendor/` folder. This helps everything get tested properly in CI.
If you are submitting a change that requires new or updated dependencies, please
include them in `vendor/vendor.json` and in the `vendor/` folder. This helps
everything get tested properly in CI.
Note that you will need to use [govendor](https://github.com/kardianos/govendor) to do this. This step is recommended but not required; if you don't use govendor please indicate in your PR which dependencies have changed and to what versions.
Note that you will need to use [govendor](https://github.com/kardianos/govendor)
to do this. This step is recommended but not required; if you don't use govendor
please indicate in your PR which dependencies have changed and to what versions.
Use `govendor fetch <project>` to add dependencies to the project. See
[govendor quick
start](https://github.com/kardianos/govendor#quick-start-also-see-the-faq) for
examples.
[govendor quick start](https://github.com/kardianos/govendor#quick-start-also-see-the-faq)
for examples.
Please only apply the minimal vendor changes to get your PR to work. Packer does not attempt to track the latest version for each dependency.
Please only apply the minimal vendor changes to get your PR to work. Packer does
not attempt to track the latest version for each dependency.
#### Running Unit Tests
You can run tests for individual packages using commands like this:
$ make test TEST=./builder/amazon/...
```
make test TEST=./builder/amazon/...
```
#### Running Acceptance Tests
@ -137,21 +159,34 @@ Packer has [acceptance tests](https://en.wikipedia.org/wiki/Acceptance_testing)
for various builders. These typically require an API key (AWS, GCE), or
additional software to be installed on your computer (VirtualBox, VMware).
If you're working on a new builder or builder feature and want verify it is functioning (and also hasn't broken anything else), we recommend running the
If you're working on a new builder or builder feature and want verify it is
functioning (and also hasn't broken anything else), we recommend running the
acceptance tests.
**Warning:** The acceptance tests create/destroy/modify *real resources*, which
may incur costs for real money. In the presence of a bug, it is possible that resources may be left behind, which can cost money even though you were not using them. We recommend running tests in an account used only for that purpose so it is easy to see if there are any dangling resources, and so production resources are not accidentally destroyed or overwritten during testing.
**Warning:** The acceptance tests create/destroy/modify _real resources_, which
may incur costs for real money. In the presence of a bug, it is possible that
resources may be left behind, which can cost money even though you were not
using them. We recommend running tests in an account used only for that purpose
so it is easy to see if there are any dangling resources, and so production
resources are not accidentally destroyed or overwritten during testing.
To run the acceptance tests, invoke `make testacc`:
$ make testacc TEST=./builder/amazon/ebs
...
```
make testacc TEST=./builder/amazon/ebs
...
```
The `TEST` variable lets you narrow the scope of the acceptance tests to a
specific package / folder. The `TESTARGS` variable is recommended to filter
down to a specific resource to test, since testing all of them at once can
sometimes take a very long time.
specific package / folder. The `TESTARGS` variable is recommended to filter down
to a specific resource to test, since testing all of them at once can sometimes
take a very long time.
To run only a specific test, use the `-run` argument:
```
make testacc TEST=./builder/amazon/ebs TESTARGS="-run TestBuilderAcc_forceDeleteSnapshot"
```
Acceptance tests typically require other environment variables to be set for
things such as API tokens and keys. Each test should error and tell you which

View File

@ -38,6 +38,7 @@ comes out of the box with support for the following platforms:
* Parallels
* ProfitBricks
* QEMU. Both KVM and Xen images.
* Scaleway
* Triton (Joyent Public Cloud)
* VMware
* VirtualBox

5
Vagrantfile vendored
View File

@ -69,11 +69,6 @@ def configureProviders(vmCfg, cpus: "2", memory: "2048")
end
end
vmCfg.vm.provider "virtualbox" do |v|
v.memory = memory
v.cpus = cpus
end
return vmCfg
end

View File

@ -15,6 +15,7 @@ type AlicloudAccessConfig struct {
AlicloudSecretKey string `mapstructure:"secret_key"`
AlicloudRegion string `mapstructure:"region"`
AlicloudSkipValidation bool `mapstructure:"skip_region_validation"`
SecurityToken string `mapstructure:"security_token"`
}
// Client for AlicloudClient
@ -22,7 +23,12 @@ func (c *AlicloudAccessConfig) Client() (*ecs.Client, error) {
if err := c.loadAndValidate(); err != nil {
return nil, err
}
client := ecs.NewECSClient(c.AlicloudAccessKey, c.AlicloudSecretKey, common.Region(c.AlicloudRegion))
if c.SecurityToken == "" {
c.SecurityToken = os.Getenv("SECURITY_TOKEN")
}
client := ecs.NewECSClientWithSecurityToken(c.AlicloudAccessKey, c.AlicloudSecretKey,
c.SecurityToken, common.Region(c.AlicloudRegion))
client.SetBusinessInfo("Packer")
if _, err := client.DescribeRegions(); err != nil {
return nil, err

View File

@ -6,12 +6,13 @@ import (
"log"
"fmt"
"github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/config"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
"github.com/mitchellh/multistep"
)
// The unique ID for this builder
@ -146,9 +147,9 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
})
}
steps = append(steps,
&stepAttachKeyPar{},
&stepRunAlicloudInstance{},
&stepMountAlicloudDisk{},
&stepAttachKeyPar{},
&communicator.StepConnect{
Config: &b.config.RunConfig.Comm,
Host: SSHHost(

View File

@ -3,10 +3,11 @@ package ecs
import (
"fmt"
"github.com/denverdino/aliyungo/common"
"github.com/hashicorp/packer/template/interpolate"
"regexp"
"strings"
"github.com/denverdino/aliyungo/common"
"github.com/hashicorp/packer/template/interpolate"
)
type AlicloudDiskDevice struct {

View File

@ -3,8 +3,8 @@ package ecs
import (
"fmt"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
func message(state multistep.StateBag, module string) {

View File

@ -7,7 +7,7 @@ import (
"time"
packerssh "github.com/hashicorp/packer/communicator/ssh"
"github.com/mitchellh/multistep"
"github.com/hashicorp/packer/helper/multistep"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
)

View File

@ -1,19 +1,21 @@
package ecs
import (
"context"
"fmt"
"time"
"github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/ecs"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
"time"
)
type stepAttachKeyPar struct {
}
func (s *stepAttachKeyPar) Run(state multistep.StateBag) multistep.StepAction {
func (s *stepAttachKeyPar) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
keyPairName := state.Get("keyPair").(string)
if keyPairName == "" {
return multistep.ActionContinue

View File

@ -1,19 +1,20 @@
package ecs
import (
"context"
"fmt"
"github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/ecs"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type stepCheckAlicloudSourceImage struct {
SourceECSImageId string
}
func (s *stepCheckAlicloudSourceImage) Run(state multistep.StateBag) multistep.StepAction {
func (s *stepCheckAlicloudSourceImage) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
client := state.Get("client").(*ecs.Client)
config := state.Get("config").(Config)
ui := state.Get("ui").(packer.Ui)

View File

@ -1,12 +1,13 @@
package ecs
import (
"context"
"fmt"
"github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/ecs"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type setpConfigAlicloudEIP struct {
@ -16,7 +17,7 @@ type setpConfigAlicloudEIP struct {
allocatedId string
}
func (s *setpConfigAlicloudEIP) Run(state multistep.StateBag) multistep.StepAction {
func (s *setpConfigAlicloudEIP) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
client := state.Get("client").(*ecs.Client)
ui := state.Get("ui").(packer.Ui)
instance := state.Get("instance").(*ecs.InstanceAttributesType)

View File

@ -1,6 +1,7 @@
package ecs
import (
"context"
"fmt"
"io/ioutil"
"os"
@ -8,8 +9,8 @@ import (
"github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/ecs"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type StepConfigAlicloudKeyPair struct {
@ -24,7 +25,7 @@ type StepConfigAlicloudKeyPair struct {
keyName string
}
func (s *StepConfigAlicloudKeyPair) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepConfigAlicloudKeyPair) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
if s.PrivateKeyFile != "" {

View File

@ -1,11 +1,12 @@
package ecs
import (
"context"
"fmt"
"github.com/denverdino/aliyungo/ecs"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type stepConfigAlicloudPublicIP struct {
@ -13,7 +14,7 @@ type stepConfigAlicloudPublicIP struct {
RegionId string
}
func (s *stepConfigAlicloudPublicIP) Run(state multistep.StateBag) multistep.StepAction {
func (s *stepConfigAlicloudPublicIP) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
client := state.Get("client").(*ecs.Client)
ui := state.Get("ui").(packer.Ui)
instance := state.Get("instance").(*ecs.InstanceAttributesType)

View File

@ -1,14 +1,15 @@
package ecs
import (
"context"
"errors"
"fmt"
"time"
"github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/ecs"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type stepConfigAlicloudSecurityGroup struct {
@ -20,7 +21,7 @@ type stepConfigAlicloudSecurityGroup struct {
isCreate bool
}
func (s *stepConfigAlicloudSecurityGroup) Run(state multistep.StateBag) multistep.StepAction {
func (s *stepConfigAlicloudSecurityGroup) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
client := state.Get("client").(*ecs.Client)
ui := state.Get("ui").(packer.Ui)
networkType := state.Get("networktype").(InstanceNetWork)

View File

@ -1,14 +1,15 @@
package ecs
import (
"context"
"errors"
"fmt"
"time"
"github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/ecs"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type stepConfigAlicloudVPC struct {
@ -18,7 +19,7 @@ type stepConfigAlicloudVPC struct {
isCreate bool
}
func (s *stepConfigAlicloudVPC) Run(state multistep.StateBag) multistep.StepAction {
func (s *stepConfigAlicloudVPC) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(Config)
client := state.Get("client").(*ecs.Client)
ui := state.Get("ui").(packer.Ui)

View File

@ -1,14 +1,15 @@
package ecs
import (
"context"
"errors"
"fmt"
"time"
"github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/ecs"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type stepConfigAlicloudVSwitch struct {
@ -19,7 +20,7 @@ type stepConfigAlicloudVSwitch struct {
VSwitchName string
}
func (s *stepConfigAlicloudVSwitch) Run(state multistep.StateBag) multistep.StepAction {
func (s *stepConfigAlicloudVSwitch) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
client := state.Get("client").(*ecs.Client)
ui := state.Get("ui").(packer.Ui)
vpcId := state.Get("vpcid").(string)

View File

@ -1,19 +1,20 @@
package ecs
import (
"context"
"fmt"
"github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/ecs"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type stepCreateAlicloudImage struct {
image *ecs.ImageType
}
func (s *stepCreateAlicloudImage) Run(state multistep.StateBag) multistep.StepAction {
func (s *stepCreateAlicloudImage) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(Config)
client := state.Get("client").(*ecs.Client)
ui := state.Get("ui").(packer.Ui)

View File

@ -1,14 +1,15 @@
package ecs
import (
"context"
"fmt"
"io/ioutil"
"log"
"github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/ecs"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type stepCreateAlicloudInstance struct {
@ -25,7 +26,7 @@ type stepCreateAlicloudInstance struct {
instance *ecs.InstanceAttributesType
}
func (s *stepCreateAlicloudInstance) Run(state multistep.StateBag) multistep.StepAction {
func (s *stepCreateAlicloudInstance) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
client := state.Get("client").(*ecs.Client)
config := state.Get("config").(Config)
ui := state.Get("ui").(packer.Ui)

View File

@ -1,13 +1,14 @@
package ecs
import (
"context"
"fmt"
"log"
"github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/ecs"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type stepDeleteAlicloudImageSnapshots struct {
@ -16,7 +17,7 @@ type stepDeleteAlicloudImageSnapshots struct {
AlicloudImageName string
}
func (s *stepDeleteAlicloudImageSnapshots) Run(state multistep.StateBag) multistep.StepAction {
func (s *stepDeleteAlicloudImageSnapshots) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
client := state.Get("client").(*ecs.Client)
ui := state.Get("ui").(packer.Ui)
config := state.Get("config").(Config)

View File

@ -1,17 +1,18 @@
package ecs
import (
"context"
"fmt"
"github.com/denverdino/aliyungo/ecs"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type stepMountAlicloudDisk struct {
}
func (s *stepMountAlicloudDisk) Run(state multistep.StateBag) multistep.StepAction {
func (s *stepMountAlicloudDisk) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
client := state.Get("client").(*ecs.Client)
config := state.Get("config").(Config)
ui := state.Get("ui").(packer.Ui)

View File

@ -1,12 +1,13 @@
package ecs
import (
"context"
"fmt"
"github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/ecs"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type stepPreValidate struct {
@ -14,7 +15,7 @@ type stepPreValidate struct {
ForceDelete bool
}
func (s *stepPreValidate) Run(state multistep.StateBag) multistep.StepAction {
func (s *stepPreValidate) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
if s.ForceDelete {
ui.Say("Force delete flag found, skipping prevalidating image name.")

View File

@ -1,12 +1,13 @@
package ecs
import (
"context"
"fmt"
"github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/ecs"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type setpRegionCopyAlicloudImage struct {
@ -15,7 +16,7 @@ type setpRegionCopyAlicloudImage struct {
RegionId string
}
func (s *setpRegionCopyAlicloudImage) Run(state multistep.StateBag) multistep.StepAction {
func (s *setpRegionCopyAlicloudImage) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
if len(s.AlicloudImageDestinationRegions) == 0 {
return multistep.ActionContinue
}

View File

@ -1,17 +1,18 @@
package ecs
import (
"context"
"fmt"
"github.com/denverdino/aliyungo/ecs"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type stepRunAlicloudInstance struct {
}
func (s *stepRunAlicloudInstance) Run(state multistep.StateBag) multistep.StepAction {
func (s *stepRunAlicloudInstance) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
client := state.Get("client").(*ecs.Client)
ui := state.Get("ui").(packer.Ui)
instance := state.Get("instance").(*ecs.InstanceAttributesType)

View File

@ -1,12 +1,13 @@
package ecs
import (
"context"
"fmt"
"github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/ecs"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type setpShareAlicloudImage struct {
@ -15,7 +16,7 @@ type setpShareAlicloudImage struct {
RegionId string
}
func (s *setpShareAlicloudImage) Run(state multistep.StateBag) multistep.StepAction {
func (s *setpShareAlicloudImage) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
client := state.Get("client").(*ecs.Client)
ui := state.Get("ui").(packer.Ui)
alicloudImages := state.Get("alicloudimages").(map[string]string)

View File

@ -1,18 +1,19 @@
package ecs
import (
"context"
"fmt"
"github.com/denverdino/aliyungo/ecs"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type stepStopAlicloudInstance struct {
ForceStop bool
}
func (s *stepStopAlicloudInstance) Run(state multistep.StateBag) multistep.StepAction {
func (s *stepStopAlicloudInstance) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
client := state.Get("client").(*ecs.Client)
instance := state.Get("instance").(*ecs.InstanceAttributesType)
ui := state.Get("ui").(packer.Ui)

View File

@ -13,9 +13,9 @@ import (
awscommon "github.com/hashicorp/packer/builder/amazon/common"
"github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/config"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
"github.com/mitchellh/multistep"
)
// The unique ID for this builder
@ -173,7 +173,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
return warns, errs
}
log.Println(common.ScrubConfig(b.config, b.config.AccessKey, b.config.SecretKey))
log.Println(common.ScrubConfig(b.config, b.config.AccessKey, b.config.SecretKey, b.config.Token))
return warns, nil
}
@ -198,6 +198,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
state := new(multistep.BasicStateBag)
state.Put("config", &b.config)
state.Put("ec2", ec2conn)
state.Put("awsSession", session)
state.Put("hook", hook)
state.Put("ui", ui)
state.Put("wrappedCommand", CommandWrapper(wrappedCommand))
@ -305,7 +306,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
artifact := &awscommon.Artifact{
Amis: state.Get("amis").(map[string]string),
BuilderIdValue: BuilderId,
Conn: ec2conn,
Session: session,
}
return artifact, nil

View File

@ -71,11 +71,16 @@ func TestBuilderPrepare_ChrootMounts(t *testing.T) {
if err != nil {
t.Errorf("err: %s", err)
}
}
func TestBuilderPrepare_ChrootMountsBadDefaults(t *testing.T) {
b := &Builder{}
config := testConfig()
config["chroot_mounts"] = [][]string{
{"bad"},
}
warnings, err = b.Prepare(config)
warnings, err := b.Prepare(config)
if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings)
}
@ -135,9 +140,14 @@ func TestBuilderPrepare_CopyFiles(t *testing.T) {
if len(b.config.CopyFiles) != 1 && b.config.CopyFiles[0] != "/etc/resolv.conf" {
t.Errorf("Was expecting default value for copy_files.")
}
}
func TestBuilderPrepare_CopyFilesNoDefault(t *testing.T) {
b := &Builder{}
config := testConfig()
config["copy_files"] = []string{}
warnings, err = b.Prepare(config)
warnings, err := b.Prepare(config)
if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings)
}

View File

@ -1,7 +1,7 @@
package chroot
import (
"github.com/mitchellh/multistep"
"github.com/hashicorp/packer/helper/multistep"
)
// Cleanup is an interface that some steps implement for early cleanup.

View File

@ -1,8 +1,9 @@
package chroot
import (
"github.com/hashicorp/packer/packer"
"testing"
"github.com/hashicorp/packer/packer"
)
func TestCommunicator_ImplementsCommunicator(t *testing.T) {

View File

@ -0,0 +1,10 @@
package chroot
import "testing"
func TestDevicePrefixMatch(t *testing.T) {
/*
if devicePrefixMatch("nvme0n1") != "" {
}
*/
}

View File

@ -1,6 +1,7 @@
package chroot
import (
"context"
"errors"
"fmt"
"strings"
@ -8,8 +9,8 @@ import (
"github.com/aws/aws-sdk-go/service/ec2"
awscommon "github.com/hashicorp/packer/builder/amazon/common"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
// StepAttachVolume attaches the previously created volume to an
@ -23,7 +24,7 @@ type StepAttachVolume struct {
volumeId string
}
func (s *StepAttachVolume) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepAttachVolume) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ec2conn := state.Get("ec2").(*ec2.EC2)
device := state.Get("device").(string)
instance := state.Get("instance").(*ec2.Instance)

View File

@ -1,17 +1,18 @@
package chroot
import (
"context"
"fmt"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
// StepCheckRootDevice makes sure the root device on the AMI is EBS-backed.
type StepCheckRootDevice struct{}
func (s *StepCheckRootDevice) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepCheckRootDevice) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
image := state.Get("source_image").(*ec2.Image)
ui := state.Get("ui").(packer.Ui)

View File

@ -1,17 +1,18 @@
package chroot
import (
"context"
"log"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
// StepChrootProvision provisions the instance within a chroot.
type StepChrootProvision struct {
}
func (s *StepChrootProvision) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepChrootProvision) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
hook := state.Get("hook").(packer.Hook)
mountPath := state.Get("mount_path").(string)
ui := state.Get("ui").(packer.Ui)

View File

@ -2,11 +2,13 @@ package chroot
import (
"bytes"
"context"
"fmt"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
"log"
"path/filepath"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
// StepCopyFiles copies some files from the host into the chroot environment.
@ -18,7 +20,7 @@ type StepCopyFiles struct {
files []string
}
func (s *StepCopyFiles) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepCopyFiles) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config)
mountPath := state.Get("mount_path").(string)
ui := state.Get("ui").(packer.Ui)

View File

@ -1,14 +1,15 @@
package chroot
import (
"context"
"fmt"
"log"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
awscommon "github.com/hashicorp/packer/builder/amazon/common"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
// StepCreateVolume creates a new volume from the snapshot of the root
@ -21,7 +22,7 @@ type StepCreateVolume struct {
RootVolumeSize int64
}
func (s *StepCreateVolume) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepCreateVolume) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config)
ec2conn := state.Get("ec2").(*ec2.EC2)
instance := state.Get("instance").(*ec2.Instance)

View File

@ -1,17 +1,19 @@
package chroot
import (
"context"
"fmt"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
"log"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
// StepEarlyCleanup performs some of the cleanup steps early in order to
// prepare for snapshotting and creating an AMI.
type StepEarlyCleanup struct{}
func (s *StepEarlyCleanup) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepEarlyCleanup) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
cleanupKeys := []string{
"copy_files_cleanup",

View File

@ -1,16 +1,18 @@
package chroot
import (
"context"
"fmt"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
"log"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
// StepEarlyUnflock unlocks the flock.
type StepEarlyUnflock struct{}
func (s *StepEarlyUnflock) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepEarlyUnflock) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
cleanup := state.Get("flock_cleanup").(Cleanup)
ui := state.Get("ui").(packer.Ui)

View File

@ -1,12 +1,14 @@
package chroot
import (
"context"
"fmt"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
"log"
"os"
"path/filepath"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
// StepFlock provisions the instance within a chroot.
@ -17,7 +19,7 @@ type StepFlock struct {
fh *os.File
}
func (s *StepFlock) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepFlock) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
lockfile := "/var/lock/packer-chroot/lock"

View File

@ -1,28 +1,29 @@
package chroot
import (
"context"
"fmt"
"log"
"github.com/aws/aws-sdk-go/aws/ec2metadata"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
// StepInstanceInfo verifies that this builder is running on an EC2 instance.
type StepInstanceInfo struct{}
func (s *StepInstanceInfo) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepInstanceInfo) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ec2conn := state.Get("ec2").(*ec2.EC2)
session := state.Get("awsSession").(*session.Session)
ui := state.Get("ui").(packer.Ui)
// Get our own instance ID
ui.Say("Gathering information about this EC2 instance...")
sess := session.New()
ec2meta := ec2metadata.New(sess)
ec2meta := ec2metadata.New(session)
identity, err := ec2meta.GetInstanceIdentityDocument()
if err != nil {
err := fmt.Errorf(

View File

@ -2,6 +2,7 @@ package chroot
import (
"bytes"
"context"
"fmt"
"log"
"os"
@ -9,9 +10,9 @@ import (
"strings"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
"github.com/mitchellh/multistep"
)
type mountPathData struct {
@ -30,7 +31,7 @@ type StepMountDevice struct {
mountPath string
}
func (s *StepMountDevice) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepMountDevice) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config)
ui := state.Get("ui").(packer.Ui)
device := state.Get("device").(string)

View File

@ -2,12 +2,14 @@ package chroot
import (
"bytes"
"context"
"fmt"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
"os"
"os/exec"
"syscall"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
// StepMountExtra mounts the attached device.
@ -18,7 +20,7 @@ type StepMountExtra struct {
mounts []string
}
func (s *StepMountExtra) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepMountExtra) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config)
mountPath := state.Get("mount_path").(string)
ui := state.Get("ui").(packer.Ui)

View File

@ -1,8 +1,10 @@
package chroot
import (
"context"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type postMountCommandsData struct {
@ -16,7 +18,7 @@ type StepPostMountCommands struct {
Commands []string
}
func (s *StepPostMountCommands) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepPostMountCommands) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config)
device := state.Get("device").(string)
mountPath := state.Get("mount_path").(string)

View File

@ -1,8 +1,10 @@
package chroot
import (
"context"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type preMountCommandsData struct {
@ -14,7 +16,7 @@ type StepPreMountCommands struct {
Commands []string
}
func (s *StepPreMountCommands) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepPreMountCommands) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config)
device := state.Get("device").(string)
ui := state.Get("ui").(packer.Ui)

View File

@ -1,19 +1,20 @@
package chroot
import (
"context"
"fmt"
"log"
"os"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
// StepPrepareDevice finds an available device and sets it.
type StepPrepareDevice struct {
}
func (s *StepPrepareDevice) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepPrepareDevice) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config)
ui := state.Get("ui").(packer.Ui)

View File

@ -1,13 +1,14 @@
package chroot
import (
"context"
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
awscommon "github.com/hashicorp/packer/builder/amazon/common"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
// StepRegisterAMI creates the AMI.
@ -17,7 +18,7 @@ type StepRegisterAMI struct {
EnableAMISriovNetSupport bool
}
func (s *StepRegisterAMI) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepRegisterAMI) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config)
ec2conn := state.Get("ec2").(*ec2.EC2)
snapshotId := state.Get("snapshot_id").(string)

View File

@ -1,14 +1,15 @@
package chroot
import (
"context"
"errors"
"fmt"
"time"
"github.com/aws/aws-sdk-go/service/ec2"
awscommon "github.com/hashicorp/packer/builder/amazon/common"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
// StepSnapshot creates a snapshot of the created volume.
@ -19,7 +20,7 @@ type StepSnapshot struct {
snapshotId string
}
func (s *StepSnapshot) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepSnapshot) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ec2conn := state.Get("ec2").(*ec2.EC2)
ui := state.Get("ui").(packer.Ui)
volumeId := state.Get("volume_id").(string)

View File

@ -1,13 +1,17 @@
package common
import (
"errors"
"fmt"
"log"
"os"
"strings"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
"github.com/aws/aws-sdk-go/aws/ec2metadata"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/hashicorp/go-cleanhttp"
@ -16,15 +20,16 @@ import (
// AccessConfig is for common configuration related to AWS access
type AccessConfig struct {
AccessKey string `mapstructure:"access_key"`
CustomEndpointEc2 string `mapstructure:"custom_endpoint_ec2"`
MFACode string `mapstructure:"mfa_code"`
ProfileName string `mapstructure:"profile"`
RawRegion string `mapstructure:"region"`
SecretKey string `mapstructure:"secret_key"`
SkipValidation bool `mapstructure:"skip_region_validation"`
Token string `mapstructure:"token"`
session *session.Session
AccessKey string `mapstructure:"access_key"`
CustomEndpointEc2 string `mapstructure:"custom_endpoint_ec2"`
MFACode string `mapstructure:"mfa_code"`
ProfileName string `mapstructure:"profile"`
RawRegion string `mapstructure:"region"`
SecretKey string `mapstructure:"secret_key"`
SkipValidation bool `mapstructure:"skip_region_validation"`
SkipMetadataApiCheck bool `mapstructure:"skip_metadata_api_check"`
Token string `mapstructure:"token"`
session *session.Session
}
// Config returns a valid aws.Config object for access to AWS services, or
@ -34,13 +39,79 @@ func (c *AccessConfig) Session() (*session.Session, error) {
return c.session, nil
}
config := aws.NewConfig().WithMaxRetries(11).WithCredentialsChainVerboseErrors(true)
// build a chain provider, lazy-evaluated by aws-sdk
providers := []credentials.Provider{
&credentials.StaticProvider{Value: credentials.Value{
AccessKeyID: c.AccessKey,
SecretAccessKey: c.SecretKey,
SessionToken: c.Token,
}},
&credentials.EnvProvider{},
&credentials.SharedCredentialsProvider{
Filename: "",
Profile: c.ProfileName,
},
}
if c.ProfileName != "" {
if err := os.Setenv("AWS_PROFILE", c.ProfileName); err != nil {
return nil, fmt.Errorf("Set env error: %s", err)
// Build isolated HTTP client to avoid issues with globally-shared settings
client := cleanhttp.DefaultClient()
// Keep the default timeout (100ms) low as we don't want to wait in non-EC2 environments
client.Timeout = 100 * time.Millisecond
const userTimeoutEnvVar = "AWS_METADATA_TIMEOUT"
userTimeout := os.Getenv(userTimeoutEnvVar)
if userTimeout != "" {
newTimeout, err := time.ParseDuration(userTimeout)
if err == nil {
if newTimeout.Nanoseconds() > 0 {
client.Timeout = newTimeout
} else {
log.Printf("[WARN] Non-positive value of %s (%s) is meaningless, ignoring", userTimeoutEnvVar, newTimeout.String())
}
} else {
log.Printf("[WARN] Error converting %s to time.Duration: %s", userTimeoutEnvVar, err)
}
} else if c.RawRegion != "" {
}
log.Printf("[INFO] Setting AWS metadata API timeout to %s", client.Timeout.String())
cfg := &aws.Config{
HTTPClient: client,
}
if !c.SkipMetadataApiCheck {
// Real AWS should reply to a simple metadata request.
// We check it actually does to ensure something else didn't just
// happen to be listening on the same IP:Port
metadataClient := ec2metadata.New(session.New(cfg))
if metadataClient.Available() {
providers = append(providers, &ec2rolecreds.EC2RoleProvider{
Client: metadataClient,
})
log.Print("[INFO] AWS EC2 instance detected via default metadata" +
" API endpoint, EC2RoleProvider added to the auth chain")
} else {
log.Printf("[INFO] Ignoring AWS metadata API endpoint " +
"as it doesn't return any instance-id")
}
}
creds := credentials.NewChainCredentials(providers)
cp, err := creds.Get()
if err != nil {
if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NoCredentialProviders" {
return nil, errors.New("No valid credential sources found for AWS Builder. " +
"Please see https://www.packer.io/docs/builders/amazon.html#specifying-amazon-credentials " +
"for more information on providing credentials for the AWS Builder.")
}
return nil, fmt.Errorf("Error loading credentials for AWS Provider: %s", err)
}
log.Printf("[INFO] AWS Auth provider used: %q", cp.ProviderName)
config := aws.NewConfig().WithMaxRetries(11).WithCredentialsChainVerboseErrors(true)
config = config.WithCredentials(creds)
if c.RawRegion != "" {
config = config.WithRegion(c.RawRegion)
} else if region := c.metadataRegion(); region != "" {
config = config.WithRegion(region)
@ -50,20 +121,6 @@ func (c *AccessConfig) Session() (*session.Session, error) {
config = config.WithEndpoint(c.CustomEndpointEc2)
}
if c.AccessKey != "" {
creds := credentials.NewChainCredentials(
[]credentials.Provider{
&credentials.StaticProvider{
Value: credentials.Value{
AccessKeyID: c.AccessKey,
SecretAccessKey: c.SecretKey,
SessionToken: c.Token,
},
},
})
config = config.WithCredentials(creds)
}
opts := session.Options{
SharedConfigState: session.SharedConfigEnable,
Config: *config,
@ -87,6 +144,21 @@ func (c *AccessConfig) Session() (*session.Session, error) {
return c.session, nil
}
func (c *AccessConfig) SessionRegion() string {
if c.session == nil {
panic("access config session should be set.")
}
return aws.StringValue(c.session.Config.Region)
}
func (c *AccessConfig) IsGovCloud() bool {
return strings.HasPrefix(c.SessionRegion(), "us-gov-")
}
func (c *AccessConfig) IsChinaCloud() bool {
return strings.HasPrefix(c.SessionRegion(), "cn-")
}
// metadataRegion returns the region from the metadata service
func (c *AccessConfig) metadataRegion() string {
@ -108,6 +180,14 @@ func (c *AccessConfig) metadataRegion() string {
func (c *AccessConfig) Prepare(ctx *interpolate.Context) []error {
var errs []error
// Either both access and secret key must be set or neither of them should
// be.
if (len(c.AccessKey) > 0) != (len(c.SecretKey) > 0) {
errs = append(errs,
fmt.Errorf("`access_key` and `secret_key` must both be either set or not set."))
}
if c.RawRegion != "" && !c.SkipValidation {
if valid := ValidateRegion(c.RawRegion); !valid {
errs = append(errs, fmt.Errorf("Unknown region: %s", c.RawRegion))

View File

@ -2,6 +2,9 @@ package common
import (
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
)
func testAccessConfig() *AccessConfig {
@ -38,3 +41,20 @@ func TestAccessConfigPrepare_Region(t *testing.T) {
c.SkipValidation = false
}
func TestAccessConfigPrepare_RegionRestrictd(t *testing.T) {
c := testAccessConfig()
// Create a Session with a custom region
c.session = session.Must(session.NewSession(&aws.Config{
Region: aws.String("us-gov-west-1"),
}))
if err := c.Prepare(nil); err != nil {
t.Fatalf("shouldn't have err: %s", err)
}
if !c.IsGovCloud() {
t.Fatal("We should be in gov region.")
}
}

View File

@ -2,6 +2,7 @@ package common
import (
"fmt"
"log"
"github.com/hashicorp/packer/template/interpolate"
)
@ -16,7 +17,7 @@ type AMIConfig struct {
AMIProductCodes []string `mapstructure:"ami_product_codes"`
AMIRegions []string `mapstructure:"ami_regions"`
AMISkipRegionValidation bool `mapstructure:"skip_region_validation"`
AMITags map[string]string `mapstructure:"tags"`
AMITags TagMap `mapstructure:"tags"`
AMIENASupport bool `mapstructure:"ena_support"`
AMISriovNetSupport bool `mapstructure:"sriov_support"`
AMIForceDeregister bool `mapstructure:"force_deregister"`
@ -24,7 +25,7 @@ type AMIConfig struct {
AMIEncryptBootVolume bool `mapstructure:"encrypt_boot"`
AMIKmsKeyId string `mapstructure:"kms_key_id"`
AMIRegionKMSKeyIDs map[string]string `mapstructure:"region_kms_key_ids"`
SnapshotTags map[string]string `mapstructure:"snapshot_tags"`
SnapshotTags TagMap `mapstructure:"snapshot_tags"`
SnapshotUsers []string `mapstructure:"snapshot_users"`
SnapshotGroups []string `mapstructure:"snapshot_groups"`
}
@ -41,22 +42,20 @@ func stringInSlice(s []string, searchstr string) bool {
func (c *AMIConfig) Prepare(accessConfig *AccessConfig, ctx *interpolate.Context) []error {
var errs []error
if accessConfig != nil {
session, err := accessConfig.Session()
if err != nil {
errs = append(errs, err)
} else {
region := *session.Config.Region
if stringInSlice(c.AMIRegions, region) {
errs = append(errs, fmt.Errorf("Cannot copy AMI to AWS session region '%s', please remove it from `ami_regions`.", region))
}
}
}
if c.AMIName == "" {
errs = append(errs, fmt.Errorf("ami_name must be specified"))
}
// Make sure that if we have region_kms_key_ids defined,
// the regions in region_kms_key_ids are also in ami_regions
if len(c.AMIRegionKMSKeyIDs) > 0 {
for kmsKeyRegion := range c.AMIRegionKMSKeyIDs {
if !stringInSlice(c.AMIRegions, kmsKeyRegion) {
errs = append(errs, fmt.Errorf("Region %s is in region_kms_key_ids but not in ami_regions", kmsKeyRegion))
}
}
}
if len(c.AMIRegions) > 0 {
regionSet := make(map[string]struct{})
regions := make([]string, 0, len(c.AMIRegions))
@ -84,21 +83,17 @@ func (c *AMIConfig) Prepare(accessConfig *AccessConfig, ctx *interpolate.Context
errs = append(errs, fmt.Errorf("Region %s is in ami_regions but not in region_kms_key_ids", region))
}
}
if (accessConfig != nil) && (region == accessConfig.RawRegion) {
// make sure we don't try to copy to the region we originally
// create the AMI in.
log.Printf("Cannot copy AMI to AWS session region '%s', deleting it from `ami_regions`.", region)
continue
}
regions = append(regions, region)
}
c.AMIRegions = regions
}
// Make sure that if we have region_kms_key_ids defined,
// the regions in region_kms_key_ids are also in ami_regions
if len(c.AMIRegionKMSKeyIDs) > 0 {
for kmsKeyRegion := range c.AMIRegionKMSKeyIDs {
if !stringInSlice(c.AMIRegions, kmsKeyRegion) {
errs = append(errs, fmt.Errorf("Region %s is in region_kms_key_ids but not in ami_regions", kmsKeyRegion))
}
}
}
if len(c.AMIUsers) > 0 && c.AMIEncryptBootVolume {
errs = append(errs, fmt.Errorf("Cannot share AMI with encrypted boot volume"))

View File

@ -11,6 +11,12 @@ func testAMIConfig() *AMIConfig {
}
}
func getFakeAccessConfig(region string) *AccessConfig {
return &AccessConfig{
RawRegion: region,
}
}
func TestAMIConfigPrepare_name(t *testing.T) {
c := testAMIConfig()
if err := c.Prepare(nil, nil); err != nil {
@ -118,6 +124,15 @@ func TestAMIConfigPrepare_regions(t *testing.T) {
if err := c.Prepare(nil, nil); err == nil {
t.Fatal("should have error b/c theres a region in in ami_regions that isn't in the key map")
}
// allow rawregion to exist in ami_regions list.
accessConf := getFakeAccessConfig("us-east-1")
c.AMIRegions = []string{"us-east-1", "us-west-1", "us-east-2"}
c.AMIRegionKMSKeyIDs = nil
if err := c.Prepare(accessConf, nil); err != nil {
t.Fatal("should allow user to have the raw region in ami_regions")
}
}
func TestAMIConfigPrepare_Share_EncryptedBoot(t *testing.T) {

View File

@ -21,7 +21,7 @@ type Artifact struct {
BuilderIdValue string
// EC2 connection for performing API stuff.
Conn *ec2.EC2
Session *session.Session
}
func (a *Artifact) BuilderId() string {
@ -69,15 +69,9 @@ func (a *Artifact) Destroy() error {
for region, imageId := range a.Amis {
log.Printf("Deregistering image ID (%s) from region (%s)", imageId, region)
regionConfig := &aws.Config{
Credentials: a.Conn.Config.Credentials,
Region: aws.String(region),
}
session, err := session.NewSession(regionConfig)
if err != nil {
return err
}
regionConn := ec2.New(session)
regionConn := ec2.New(a.Session, &aws.Config{
Region: aws.String(region),
})
// Get image metadata
imageResp, err := regionConn.DescribeImages(&ec2.DescribeImagesInput{

View File

@ -1,6 +1,7 @@
package common
import (
"fmt"
"strings"
"github.com/aws/aws-sdk-go/aws"
@ -19,6 +20,7 @@ type BlockDevice struct {
VirtualName string `mapstructure:"virtual_name"`
VolumeType string `mapstructure:"volume_type"`
VolumeSize int64 `mapstructure:"volume_size"`
KmsKeyId string `mapstructure:"kms_key_id"`
}
type BlockDevices struct {
@ -73,6 +75,10 @@ func buildBlockDevices(b []BlockDevice) []*ec2.BlockDeviceMapping {
ebsBlockDevice.Encrypted = aws.Bool(blockDevice.Encrypted)
}
if blockDevice.KmsKeyId != "" {
ebsBlockDevice.KmsKeyId = aws.String(blockDevice.KmsKeyId)
}
mapping.Ebs = ebsBlockDevice
}
@ -81,10 +87,29 @@ func buildBlockDevices(b []BlockDevice) []*ec2.BlockDeviceMapping {
return blockDevices
}
func (b *BlockDevices) Prepare(ctx *interpolate.Context) []error {
func (b *BlockDevice) Prepare(ctx *interpolate.Context) error {
// Warn that encrypted must be true when setting kms_key_id
if b.KmsKeyId != "" && b.Encrypted == false {
return fmt.Errorf("The device %v, must also have `encrypted: "+
"true` when setting a kms_key_id.", b.DeviceName)
}
return nil
}
func (b *BlockDevices) Prepare(ctx *interpolate.Context) (errs []error) {
for _, d := range b.AMIMappings {
if err := d.Prepare(ctx); err != nil {
errs = append(errs, fmt.Errorf("AMIMapping: %s", err.Error()))
}
}
for _, d := range b.LaunchMappings {
if err := d.Prepare(ctx); err != nil {
errs = append(errs, fmt.Errorf("LaunchMapping: %s", err.Error()))
}
}
return errs
}
func (b *AMIBlockDevices) BuildAMIDevices() []*ec2.BlockDeviceMapping {
return buildBlockDevices(b.AMIMappings)
}

View File

@ -84,6 +84,27 @@ func TestBlockDevice(t *testing.T) {
},
},
},
{
Config: &BlockDevice{
DeviceName: "/dev/sdb",
VolumeType: "gp2",
VolumeSize: 8,
DeleteOnTermination: true,
Encrypted: true,
KmsKeyId: "2Fa48a521f-3aff-4b34-a159-376ac5d37812",
},
Result: &ec2.BlockDeviceMapping{
DeviceName: aws.String("/dev/sdb"),
Ebs: &ec2.EbsBlockDevice{
VolumeType: aws.String("gp2"),
VolumeSize: aws.Int64(8),
DeleteOnTermination: aws.Bool(true),
Encrypted: aws.Bool(true),
KmsKeyId: aws.String("2Fa48a521f-3aff-4b34-a159-376ac5d37812"),
},
},
},
{
Config: &BlockDevice{
DeviceName: "/dev/sdb",

View File

@ -12,6 +12,7 @@ func listEC2Regions() []string {
"eu-central-1",
"eu-west-1",
"eu-west-2",
"eu-west-3",
"sa-east-1",
"us-east-1",
"us-east-2",

View File

@ -53,7 +53,7 @@ type RunConfig struct {
// Communicator settings
Comm communicator.Config `mapstructure:",squash"`
SSHKeyPairName string `mapstructure:"ssh_keypair_name"`
SSHPrivateIp bool `mapstructure:"ssh_private_ip"`
SSHInterface string `mapstructure:"ssh_interface"`
}
func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
@ -77,11 +77,21 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
// Validation
errs := c.Comm.Prepare(ctx)
// Valadating ssh_interface
if c.SSHInterface != "public_ip" &&
c.SSHInterface != "private_ip" &&
c.SSHInterface != "public_dns" &&
c.SSHInterface != "private_dns" &&
c.SSHInterface != "" {
errs = append(errs, errors.New(fmt.Sprintf("Unknown interface type: %s", c.SSHInterface)))
}
if c.SSHKeyPairName != "" {
if c.Comm.Type == "winrm" && c.Comm.WinRMPassword == "" && c.Comm.SSHPrivateKey == "" {
errs = append(errs, errors.New("A private_key_file must be provided to retrieve the winrm password when using ssh_keypair_name."))
errs = append(errs, errors.New("ssh_private_key_file must be provided to retrieve the winrm password when using ssh_keypair_name."))
} else if c.Comm.SSHPrivateKey == "" && !c.Comm.SSHAgentAuth {
errs = append(errs, errors.New("A private_key_file must be provided or ssh_agent_auth enabled when ssh_keypair_name is specified."))
errs = append(errs, errors.New("ssh_private_key_file must be provided or ssh_agent_auth enabled when ssh_keypair_name is specified."))
}
}
@ -133,3 +143,7 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
return errs
}
func (c *RunConfig) IsSpotInstance() bool {
return c.SpotPrice != "" && c.SpotPrice != "0"
}

View File

@ -9,7 +9,7 @@ import (
"github.com/aws/aws-sdk-go/service/ec2"
packerssh "github.com/hashicorp/packer/communicator/ssh"
"github.com/mitchellh/multistep"
"github.com/hashicorp/packer/helper/multistep"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
)
@ -25,21 +25,40 @@ var (
// SSHHost returns a function that can be given to the SSH communicator
// for determining the SSH address based on the instance DNS name.
func SSHHost(e ec2Describer, private bool) func(multistep.StateBag) (string, error) {
func SSHHost(e ec2Describer, sshInterface string) func(multistep.StateBag) (string, error) {
return func(state multistep.StateBag) (string, error) {
const tries = 2
// <= with current structure to check result of describing `tries` times
for j := 0; j <= tries; j++ {
var host string
i := state.Get("instance").(*ec2.Instance)
if i.VpcId != nil && *i.VpcId != "" {
if i.PublicIpAddress != nil && *i.PublicIpAddress != "" && !private {
if sshInterface != "" {
switch sshInterface {
case "public_ip":
if i.PublicIpAddress != nil {
host = *i.PublicIpAddress
}
case "private_ip":
if i.PrivateIpAddress != nil {
host = *i.PrivateIpAddress
}
case "public_dns":
if i.PublicDnsName != nil {
host = *i.PublicDnsName
}
case "private_dns":
if i.PrivateDnsName != nil {
host = *i.PrivateDnsName
}
default:
panic(fmt.Sprintf("Unknown interface type: %s", sshInterface))
}
} else if i.VpcId != nil && *i.VpcId != "" {
if i.PublicIpAddress != nil && *i.PublicIpAddress != "" {
host = *i.PublicIpAddress
} else if i.PrivateIpAddress != nil && *i.PrivateIpAddress != "" {
host = *i.PrivateIpAddress
}
} else if private && i.PrivateIpAddress != nil && *i.PrivateIpAddress != "" {
host = *i.PrivateIpAddress
} else if i.PublicDnsName != nil && *i.PublicDnsName != "" {
host = *i.PublicDnsName
}
@ -63,7 +82,7 @@ func SSHHost(e ec2Describer, private bool) func(multistep.StateBag) (string, err
time.Sleep(sshHostSleepDuration)
}
return "", errors.New("couldn't determine IP address for instance")
return "", errors.New("couldn't determine address for instance")
}
}

View File

@ -5,13 +5,14 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mitchellh/multistep"
"github.com/hashicorp/packer/helper/multistep"
)
const (
privateIP = "10.0.0.1"
publicIP = "192.168.1.1"
publicDNS = "public.dns.test"
privateIP = "10.0.0.1"
publicIP = "192.168.1.1"
privateDNS = "private.dns.test"
publicDNS = "public.dns.test"
)
func TestSSHHost(t *testing.T) {
@ -20,44 +21,54 @@ func TestSSHHost(t *testing.T) {
sshHostSleepDuration = 0
var cases = []struct {
allowTries int
vpcId string
private bool
allowTries int
vpcId string
sshInterface string
ok bool
wantHost string
}{
{1, "", false, true, publicDNS},
{1, "", true, true, privateIP},
{1, "vpc-id", false, true, publicIP},
{1, "vpc-id", true, true, privateIP},
{2, "", false, true, publicDNS},
{2, "", true, true, privateIP},
{2, "vpc-id", false, true, publicIP},
{2, "vpc-id", true, true, privateIP},
{3, "", false, false, ""},
{3, "", true, false, ""},
{3, "vpc-id", false, false, ""},
{3, "vpc-id", true, false, ""},
{1, "", "", true, publicDNS},
{1, "", "private_ip", true, privateIP},
{1, "vpc-id", "", true, publicIP},
{1, "vpc-id", "private_ip", true, privateIP},
{1, "vpc-id", "private_dns", true, privateDNS},
{1, "vpc-id", "public_dns", true, publicDNS},
{1, "vpc-id", "public_ip", true, publicIP},
{2, "", "", true, publicDNS},
{2, "", "private_ip", true, privateIP},
{2, "vpc-id", "", true, publicIP},
{2, "vpc-id", "private_ip", true, privateIP},
{2, "vpc-id", "private_dns", true, privateDNS},
{2, "vpc-id", "public_dns", true, publicDNS},
{2, "vpc-id", "public_ip", true, publicIP},
{3, "", "", false, ""},
{3, "", "private_ip", false, ""},
{3, "vpc-id", "", false, ""},
{3, "vpc-id", "private_ip", false, ""},
{3, "vpc-id", "private_dns", false, ""},
{3, "vpc-id", "public_dns", false, ""},
{3, "vpc-id", "public_ip", false, ""},
}
for _, c := range cases {
testSSHHost(t, c.allowTries, c.vpcId, c.private, c.ok, c.wantHost)
testSSHHost(t, c.allowTries, c.vpcId, c.sshInterface, c.ok, c.wantHost)
}
}
func testSSHHost(t *testing.T, allowTries int, vpcId string, private, ok bool, wantHost string) {
t.Logf("allowTries=%d vpcId=%s private=%t ok=%t wantHost=%q", allowTries, vpcId, private, ok, wantHost)
func testSSHHost(t *testing.T, allowTries int, vpcId string, sshInterface string, ok bool, wantHost string) {
t.Logf("allowTries=%d vpcId=%s sshInterface=%s ok=%t wantHost=%q", allowTries, vpcId, sshInterface, ok, wantHost)
e := &fakeEC2Describer{
allowTries: allowTries,
vpcId: vpcId,
privateIP: privateIP,
publicIP: publicIP,
privateDNS: privateDNS,
publicDNS: publicDNS,
}
f := SSHHost(e, private)
f := SSHHost(e, sshInterface)
st := &multistep.BasicStateBag{}
st.Put("instance", &ec2.Instance{
InstanceId: aws.String("instance-id"),
@ -85,8 +96,8 @@ type fakeEC2Describer struct {
allowTries int
tries int
vpcId string
privateIP, publicIP, publicDNS string
vpcId string
privateIP, publicIP, privateDNS, publicDNS string
}
func (d *fakeEC2Describer) DescribeInstances(in *ec2.DescribeInstancesInput) (*ec2.DescribeInstancesOutput, error) {
@ -104,6 +115,7 @@ func (d *fakeEC2Describer) DescribeInstances(in *ec2.DescribeInstancesInput) (*e
instance.PublicIpAddress = aws.String(d.publicIP)
instance.PrivateIpAddress = aws.String(d.privateIP)
instance.PublicDnsName = aws.String(d.publicDNS)
instance.PrivateDnsName = aws.String(d.privateDNS)
}
out := &ec2.DescribeInstancesOutput{

View File

@ -12,7 +12,7 @@ import (
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mitchellh/multistep"
"github.com/hashicorp/packer/helper/multistep"
)
// StateRefreshFunc is a function type used for StateChangeConf that is

View File

@ -1,14 +1,15 @@
package common
import (
"context"
"fmt"
"sync"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type StepAMIRegionCopy struct {
@ -19,7 +20,7 @@ type StepAMIRegionCopy struct {
Name string
}
func (s *StepAMIRegionCopy) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepAMIRegionCopy) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ec2conn := state.Get("ec2").(*ec2.EC2)
ui := state.Get("ui").(packer.Ui)
amis := state.Get("amis").(map[string]string)

View File

@ -1,6 +1,7 @@
package common
import (
"context"
"fmt"
"github.com/aws/aws-sdk-go/aws"
@ -8,19 +9,20 @@ import (
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2"
retry "github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
"github.com/mitchellh/multistep"
)
type StepCreateTags struct {
Tags map[string]string
SnapshotTags map[string]string
Tags TagMap
SnapshotTags TagMap
Ctx interpolate.Context
}
func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepCreateTags) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ec2conn := state.Get("ec2").(*ec2.EC2)
session := state.Get("awsSession").(*session.Session)
ui := state.Get("ui").(packer.Ui)
amis := state.Get("amis").(map[string]string)
@ -31,7 +33,7 @@ func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction {
sourceAMI = ""
}
if len(s.Tags) == 0 && len(s.SnapshotTags) == 0 {
if !s.Tags.IsSet() && !s.SnapshotTags.IsSet() {
return multistep.ActionContinue
}
@ -39,23 +41,13 @@ func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction {
for region, ami := range amis {
ui.Say(fmt.Sprintf("Adding tags to AMI (%s)...", ami))
// Declare list of resources to tag
awsConfig := aws.Config{
Credentials: ec2conn.Config.Credentials,
Region: aws.String(region),
}
session, err := session.NewSession(&awsConfig)
if err != nil {
err := fmt.Errorf("Error creating AWS session: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
regionconn := ec2.New(session)
regionConn := ec2.New(session, &aws.Config{
Region: aws.String(region),
})
// Retrieve image list for given AMI
resourceIds := []*string{&ami}
imageResp, err := regionconn.DescribeImages(&ec2.DescribeImagesInput{
imageResp, err := regionConn.DescribeImages(&ec2.DescribeImagesInput{
ImageIds: resourceIds,
})
@ -87,27 +79,27 @@ func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction {
// Convert tags to ec2.Tag format
ui.Say("Creating AMI tags")
amiTags, err := ConvertToEC2Tags(s.Tags, *ec2conn.Config.Region, sourceAMI, s.Ctx)
amiTags, err := s.Tags.EC2Tags(s.Ctx, *ec2conn.Config.Region, sourceAMI)
if err != nil {
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
ReportTags(ui, amiTags)
amiTags.Report(ui)
ui.Say("Creating snapshot tags")
snapshotTags, err := ConvertToEC2Tags(s.SnapshotTags, *ec2conn.Config.Region, sourceAMI, s.Ctx)
snapshotTags, err := s.SnapshotTags.EC2Tags(s.Ctx, *ec2conn.Config.Region, sourceAMI)
if err != nil {
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
ReportTags(ui, snapshotTags)
snapshotTags.Report(ui)
// Retry creating tags for about 2.5 minutes
err = retry.Retry(0.2, 30, 11, func(_ uint) (bool, error) {
// Tag images and snapshots
_, err := regionconn.CreateTags(&ec2.CreateTagsInput{
_, err := regionConn.CreateTags(&ec2.CreateTagsInput{
Resources: resourceIds,
Tags: amiTags,
})
@ -120,7 +112,7 @@ func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction {
// Override tags on snapshots
if len(snapshotTags) > 0 {
_, err = regionconn.CreateTags(&ec2.CreateTagsInput{
_, err = regionConn.CreateTags(&ec2.CreateTagsInput{
Resources: snapshotIds,
Tags: snapshotTags,
})
@ -150,36 +142,3 @@ func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepCreateTags) Cleanup(state multistep.StateBag) {
// No cleanup...
}
func ReportTags(ui packer.Ui, tags []*ec2.Tag) {
for _, tag := range tags {
ui.Message(fmt.Sprintf("Adding tag: \"%s\": \"%s\"",
aws.StringValue(tag.Key), aws.StringValue(tag.Value)))
}
}
func ConvertToEC2Tags(tags map[string]string, region, sourceAmiId string, ctx interpolate.Context) ([]*ec2.Tag, error) {
var ec2Tags []*ec2.Tag
for key, value := range tags {
ctx.Data = &BuildInfoTemplate{
SourceAMI: sourceAmiId,
BuildRegion: region,
}
interpolatedKey, err := interpolate.Render(key, &ctx)
if err != nil {
return ec2Tags, fmt.Errorf("Error processing tag: %s:%s - %s", key, value, err)
}
interpolatedValue, err := interpolate.Render(value, &ctx)
if err != nil {
return ec2Tags, fmt.Errorf("Error processing tag: %s:%s - %s", key, value, err)
}
ec2Tags = append(ec2Tags, &ec2.Tag{
Key: aws.String(interpolatedKey),
Value: aws.String(interpolatedValue),
})
}
return ec2Tags, nil
}

View File

@ -1,12 +1,13 @@
package common
import (
"context"
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type StepDeregisterAMI struct {
@ -17,7 +18,7 @@ type StepDeregisterAMI struct {
Regions []string
}
func (s *StepDeregisterAMI) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepDeregisterAMI) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
// Check for force deregister
if !s.ForceDeregister {
return multistep.ActionContinue

View File

@ -1,13 +1,14 @@
package common
import (
"context"
"fmt"
"log"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type StepCreateEncryptedAMICopy struct {
@ -18,7 +19,7 @@ type StepCreateEncryptedAMICopy struct {
AMIMappings []BlockDevice
}
func (s *StepCreateEncryptedAMICopy) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepCreateEncryptedAMICopy) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ec2conn := state.Get("ec2").(*ec2.EC2)
ui := state.Get("ui").(packer.Ui)
kmsKeyId := s.KeyID

View File

@ -1,6 +1,7 @@
package common
import (
"context"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
@ -12,8 +13,8 @@ import (
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
// StepGetPassword reads the password from a Windows server and sets it
@ -24,7 +25,7 @@ type StepGetPassword struct {
Timeout time.Duration
}
func (s *StepGetPassword) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepGetPassword) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
// Skip if we're not using winrm

View File

@ -1,14 +1,15 @@
package common
import (
"context"
"fmt"
"io/ioutil"
"os"
"runtime"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type StepKeyPair struct {
@ -22,7 +23,7 @@ type StepKeyPair struct {
doCleanup bool
}
func (s *StepKeyPair) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepKeyPair) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
if s.PrivateKeyFile != "" {

View File

@ -1,14 +1,15 @@
package common
import (
"context"
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
"github.com/mitchellh/multistep"
)
type StepModifyAMIAttributes struct {
@ -21,8 +22,9 @@ type StepModifyAMIAttributes struct {
Ctx interpolate.Context
}
func (s *StepModifyAMIAttributes) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepModifyAMIAttributes) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ec2conn := state.Get("ec2").(*ec2.EC2)
session := state.Get("awsSession").(*session.Session)
ui := state.Get("ui").(packer.Ui)
amis := state.Get("amis").(map[string]string)
@ -152,22 +154,13 @@ func (s *StepModifyAMIAttributes) Run(state multistep.StateBag) multistep.StepAc
// Modifying image attributes
for region, ami := range amis {
ui.Say(fmt.Sprintf("Modifying attributes on AMI (%s)...", ami))
awsConfig := aws.Config{
Credentials: ec2conn.Config.Credentials,
Region: aws.String(region),
}
session, err := session.NewSession(&awsConfig)
if err != nil {
err := fmt.Errorf("Error creating AWS session: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
regionconn := ec2.New(session)
regionConn := ec2.New(session, &aws.Config{
Region: aws.String(region),
})
for name, input := range options {
ui.Message(fmt.Sprintf("Modifying: %s", name))
input.ImageId = &ami
_, err := regionconn.ModifyImageAttribute(input)
_, err := regionConn.ModifyImageAttribute(input)
if err != nil {
err := fmt.Errorf("Error modify AMI attributes: %s", err)
state.Put("error", err)
@ -181,16 +174,13 @@ func (s *StepModifyAMIAttributes) Run(state multistep.StateBag) multistep.StepAc
for region, region_snapshots := range snapshots {
for _, snapshot := range region_snapshots {
ui.Say(fmt.Sprintf("Modifying attributes on snapshot (%s)...", snapshot))
awsConfig := aws.Config{
Credentials: ec2conn.Config.Credentials,
Region: aws.String(region),
}
session := session.New(&awsConfig)
regionconn := ec2.New(session)
regionConn := ec2.New(session, &aws.Config{
Region: aws.String(region),
})
for name, input := range snapshotOptions {
ui.Message(fmt.Sprintf("Modifying: %s", name))
input.SnapshotId = &snapshot
_, err := regionconn.ModifySnapshotAttribute(input)
_, err := regionConn.ModifySnapshotAttribute(input)
if err != nil {
err := fmt.Errorf("Error modify snapshot attributes: %s", err)
state.Put("error", err)

View File

@ -1,12 +1,13 @@
package common
import (
"context"
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type StepModifyEBSBackedInstance struct {
@ -14,7 +15,7 @@ type StepModifyEBSBackedInstance struct {
EnableAMISriovNetSupport bool
}
func (s *StepModifyEBSBackedInstance) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepModifyEBSBackedInstance) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ec2conn := state.Get("ec2").(*ec2.EC2)
instance := state.Get("instance").(*ec2.Instance)
ui := state.Get("ui").(packer.Ui)

View File

@ -1,12 +1,13 @@
package common
import (
"context"
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
// StepPreValidate provides an opportunity to pre-validate any configuration for
@ -17,7 +18,7 @@ type StepPreValidate struct {
ForceDeregister bool
}
func (s *StepPreValidate) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepPreValidate) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
if s.ForceDeregister {
ui.Say("Force Deregister flag found, skipping prevalidating AMI Name")

View File

@ -1,41 +1,45 @@
package common
import (
"context"
"encoding/base64"
"fmt"
"io/ioutil"
"log"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/ec2"
retry "github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
"github.com/mitchellh/multistep"
)
type StepRunSourceInstance struct {
AssociatePublicIpAddress bool
AvailabilityZone string
BlockDevices BlockDevices
Ctx interpolate.Context
Debug bool
EbsOptimized bool
ExpectedRootDevice string
IamInstanceProfile string
InstanceInitiatedShutdownBehavior string
InstanceType string
IsRestricted bool
SourceAMI string
SubnetId string
Tags map[string]string
VolumeTags map[string]string
Tags TagMap
UserData string
UserDataFile string
Ctx interpolate.Context
VolumeTags TagMap
instanceId string
}
func (s *StepRunSourceInstance) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepRunSourceInstance) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ec2conn := state.Get("ec2").(*ec2.EC2)
var keyName string
if name, ok := state.GetOk("keyPair"); ok {
@ -84,16 +88,15 @@ func (s *StepRunSourceInstance) Run(state multistep.StateBag) multistep.StepActi
s.Tags["Name"] = "Packer Builder"
}
ec2Tags, err := ConvertToEC2Tags(s.Tags, *ec2conn.Config.Region, s.SourceAMI, s.Ctx)
ec2Tags, err := s.Tags.EC2Tags(s.Ctx, *ec2conn.Config.Region, s.SourceAMI)
if err != nil {
err := fmt.Errorf("Error tagging source instance: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
ReportTags(ui, ec2Tags)
volTags, err := ConvertToEC2Tags(s.VolumeTags, *ec2conn.Config.Region, s.SourceAMI, s.Ctx)
volTags, err := s.VolumeTags.EC2Tags(s.Ctx, *ec2conn.Config.Region, s.SourceAMI)
if err != nil {
err := fmt.Errorf("Error tagging volumes: %s", err)
state.Put("error", err)
@ -113,6 +116,7 @@ func (s *StepRunSourceInstance) Run(state multistep.StateBag) multistep.StepActi
EbsOptimized: &s.EbsOptimized,
}
// Collect tags for tagging on resource creation
var tagSpecs []*ec2.TagSpecification
if len(ec2Tags) > 0 {
@ -133,8 +137,11 @@ func (s *StepRunSourceInstance) Run(state multistep.StateBag) multistep.StepActi
tagSpecs = append(tagSpecs, runVolTags)
}
if len(tagSpecs) > 0 {
// If our region supports it, set tag specifications
if len(tagSpecs) > 0 && !s.IsRestricted {
runOpts.SetTagSpecifications(tagSpecs)
ec2Tags.Report(ui)
volTags.Report(ui)
}
if keyName != "" {
@ -174,21 +181,26 @@ func (s *StepRunSourceInstance) Run(state multistep.StateBag) multistep.StepActi
ui.Message(fmt.Sprintf("Instance ID: %s", instanceId))
ui.Say(fmt.Sprintf("Waiting for instance (%v) to become ready...", instanceId))
stateChange := StateChangeConf{
Pending: []string{"pending"},
Target: "running",
Refresh: InstanceStateRefreshFunc(ec2conn, instanceId),
StepState: state,
describeInstance := &ec2.DescribeInstancesInput{
InstanceIds: []*string{aws.String(instanceId)},
}
latestInstance, err := WaitForState(&stateChange)
if err != nil {
if err := ec2conn.WaitUntilInstanceRunning(describeInstance); err != nil {
err := fmt.Errorf("Error waiting for instance (%s) to become ready: %s", instanceId, err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
instance := latestInstance.(*ec2.Instance)
r, err := ec2conn.DescribeInstances(describeInstance)
if err != nil || len(r.Reservations) == 0 || len(r.Reservations[0].Instances) == 0 {
err := fmt.Errorf("Error finding source instance.")
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
instance := r.Reservations[0].Instances[0]
if s.Debug {
if instance.PublicDnsName != nil && *instance.PublicDnsName != "" {
@ -206,6 +218,70 @@ func (s *StepRunSourceInstance) Run(state multistep.StateBag) multistep.StepActi
state.Put("instance", instance)
// If we're in a region that doesn't support tagging on instance creation,
// do that now.
if s.IsRestricted {
ec2Tags.Report(ui)
// Retry creating tags for about 2.5 minutes
err = retry.Retry(0.2, 30, 11, func(_ uint) (bool, error) {
_, err := ec2conn.CreateTags(&ec2.CreateTagsInput{
Tags: ec2Tags,
Resources: []*string{instance.InstanceId},
})
if err == nil {
return true, nil
}
if awsErr, ok := err.(awserr.Error); ok {
if awsErr.Code() == "InvalidInstanceID.NotFound" {
return false, nil
}
}
return true, err
})
if err != nil {
err := fmt.Errorf("Error tagging source instance: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
// Now tag volumes
volumeIds := make([]*string, 0)
for _, v := range instance.BlockDeviceMappings {
if ebs := v.Ebs; ebs != nil {
volumeIds = append(volumeIds, ebs.VolumeId)
}
}
if len(volumeIds) > 0 && s.VolumeTags.IsSet() {
ui.Say("Adding tags to source EBS Volumes")
volumeTags, err := s.VolumeTags.EC2Tags(s.Ctx, *ec2conn.Config.Region, s.SourceAMI)
if err != nil {
err := fmt.Errorf("Error tagging source EBS Volumes on %s: %s", *instance.InstanceId, err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
volumeTags.Report(ui)
_, err = ec2conn.CreateTags(&ec2.CreateTagsInput{
Resources: volumeIds,
Tags: volumeTags,
})
if err != nil {
err := fmt.Errorf("Error tagging source EBS Volumes on %s: %s", *instance.InstanceId, err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
}
}
return multistep.ActionContinue
}

View File

@ -1,6 +1,7 @@
package common
import (
"context"
"encoding/base64"
"fmt"
"io/ioutil"
@ -13,9 +14,9 @@ import (
"github.com/aws/aws-sdk-go/service/ec2"
retry "github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
"github.com/mitchellh/multistep"
)
type StepRunSpotInstance struct {
@ -32,8 +33,8 @@ type StepRunSpotInstance struct {
SpotPrice string
SpotPriceProduct string
SubnetId string
Tags map[string]string
VolumeTags map[string]string
Tags TagMap
VolumeTags TagMap
UserData string
UserDataFile string
Ctx interpolate.Context
@ -42,7 +43,7 @@ type StepRunSpotInstance struct {
spotRequest *ec2.SpotInstanceRequest
}
func (s *StepRunSpotInstance) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepRunSpotInstance) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ec2conn := state.Get("ec2").(*ec2.EC2)
var keyName string
if name, ok := state.GetOk("keyPair"); ok {
@ -142,14 +143,14 @@ func (s *StepRunSpotInstance) Run(state multistep.StateBag) multistep.StepAction
s.Tags["Name"] = "Packer Builder"
}
ec2Tags, err := ConvertToEC2Tags(s.Tags, *ec2conn.Config.Region, s.SourceAMI, s.Ctx)
ec2Tags, err := s.Tags.EC2Tags(s.Ctx, *ec2conn.Config.Region, s.SourceAMI)
if err != nil {
err := fmt.Errorf("Error tagging source instance: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
ReportTags(ui, ec2Tags)
ec2Tags.Report(ui)
ui.Message(fmt.Sprintf(
"Requesting spot instance '%s' for: %s",
@ -231,21 +232,26 @@ func (s *StepRunSpotInstance) Run(state multistep.StateBag) multistep.StepAction
ui.Message(fmt.Sprintf("Instance ID: %s", instanceId))
ui.Say(fmt.Sprintf("Waiting for instance (%v) to become ready...", instanceId))
stateChangeSpot := StateChangeConf{
Pending: []string{"pending"},
Target: "running",
Refresh: InstanceStateRefreshFunc(ec2conn, instanceId),
StepState: state,
describeInstance := &ec2.DescribeInstancesInput{
InstanceIds: []*string{aws.String(instanceId)},
}
latestInstance, err := WaitForState(&stateChangeSpot)
if err != nil {
if err := ec2conn.WaitUntilInstanceRunning(describeInstance); err != nil {
err := fmt.Errorf("Error waiting for instance (%s) to become ready: %s", instanceId, err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
instance := latestInstance.(*ec2.Instance)
r, err := ec2conn.DescribeInstances(&ec2.DescribeInstancesInput{
InstanceIds: []*string{aws.String(instanceId)},
})
if err != nil || len(r.Reservations) == 0 || len(r.Reservations[0].Instances) == 0 {
err := fmt.Errorf("Error finding source instance.")
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
instance := r.Reservations[0].Instances[0]
// Retry creating tags for about 2.5 minutes
err = retry.Retry(0.2, 30, 11, func(_ uint) (bool, error) {
@ -278,21 +284,21 @@ func (s *StepRunSpotInstance) Run(state multistep.StateBag) multistep.StepAction
}
}
if len(volumeIds) > 0 && len(s.VolumeTags) > 0 {
if len(volumeIds) > 0 && s.VolumeTags.IsSet() {
ui.Say("Adding tags to source EBS Volumes")
tags, err := ConvertToEC2Tags(s.VolumeTags, *ec2conn.Config.Region, s.SourceAMI, s.Ctx)
volumeTags, err := s.VolumeTags.EC2Tags(s.Ctx, *ec2conn.Config.Region, s.SourceAMI)
if err != nil {
err := fmt.Errorf("Error tagging source EBS Volumes on %s: %s", *instance.InstanceId, err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
ReportTags(ui, tags)
volumeTags.Report(ui)
_, err = ec2conn.CreateTags(&ec2.CreateTagsInput{
Resources: volumeIds,
Tags: tags,
Tags: volumeTags,
})
if err != nil {

View File

@ -1,6 +1,7 @@
package common
import (
"context"
"fmt"
"log"
"time"
@ -10,8 +11,8 @@ import (
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/packer/common/uuid"
"github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type StepSecurityGroup struct {
@ -23,7 +24,7 @@ type StepSecurityGroup struct {
createdGroupId string
}
func (s *StepSecurityGroup) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepSecurityGroup) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ec2conn := state.Get("ec2").(*ec2.EC2)
ui := state.Get("ui").(packer.Ui)

View File

@ -1,14 +1,15 @@
package common
import (
"context"
"fmt"
"log"
"sort"
"time"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
// StepSourceAMIInfo extracts critical information from the source AMI
@ -52,7 +53,7 @@ func mostRecentAmi(images []*ec2.Image) *ec2.Image {
return sortedImages[len(sortedImages)-1]
}
func (s *StepSourceAMIInfo) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepSourceAMIInfo) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ec2conn := state.Get("ec2").(*ec2.EC2)
ui := state.Get("ui").(packer.Ui)

View File

@ -1,13 +1,14 @@
package common
import (
"context"
"fmt"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type StepStopEBSBackedInstance struct {
@ -15,7 +16,7 @@ type StepStopEBSBackedInstance struct {
DisableStopInstance bool
}
func (s *StepStopEBSBackedInstance) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepStopEBSBackedInstance) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ec2conn := state.Get("ec2").(*ec2.EC2)
instance := state.Get("instance").(*ec2.Instance)
ui := state.Get("ui").(packer.Ui)
@ -75,15 +76,12 @@ func (s *StepStopEBSBackedInstance) Run(state multistep.StateBag) multistep.Step
ui.Say("Automatic instance stop disabled. Please stop instance manually.")
}
// Wait for the instance to actual stop
// Wait for the instance to actually stop
ui.Say("Waiting for the instance to stop...")
stateChange := StateChangeConf{
Pending: []string{"running", "pending", "stopping"},
Target: "stopped",
Refresh: InstanceStateRefreshFunc(ec2conn, *instance.InstanceId),
StepState: state,
}
_, err = WaitForState(&stateChange)
err = ec2conn.WaitUntilInstanceStopped(&ec2.DescribeInstancesInput{
InstanceIds: []*string{instance.InstanceId},
})
if err != nil {
err := fmt.Errorf("Error waiting for instance to stop: %s", err)
state.Put("error", err)

View File

@ -0,0 +1,47 @@
package common
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
)
type TagMap map[string]string
type EC2Tags []*ec2.Tag
func (t EC2Tags) Report(ui packer.Ui) {
for _, tag := range t {
ui.Message(fmt.Sprintf("Adding tag: \"%s\": \"%s\"",
aws.StringValue(tag.Key), aws.StringValue(tag.Value)))
}
}
func (t TagMap) IsSet() bool {
return len(t) > 0
}
func (t TagMap) EC2Tags(ctx interpolate.Context, region, sourceAMIID string) (EC2Tags, error) {
var ec2Tags []*ec2.Tag
ctx.Data = &BuildInfoTemplate{
SourceAMI: sourceAMIID,
BuildRegion: region,
}
for key, value := range t {
interpolatedKey, err := interpolate.Render(key, &ctx)
if err != nil {
return nil, fmt.Errorf("Error processing tag: %s:%s - %s", key, value, err)
}
interpolatedValue, err := interpolate.Render(value, &ctx)
if err != nil {
return nil, fmt.Errorf("Error processing tag: %s:%s - %s", key, value, err)
}
ec2Tags = append(ec2Tags, &ec2.Tag{
Key: aws.String(interpolatedKey),
Value: aws.String(interpolatedValue),
})
}
return ec2Tags, nil
}

View File

@ -14,9 +14,9 @@ import (
"github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/config"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
"github.com/mitchellh/multistep"
)
// The unique ID for this builder
@ -28,7 +28,7 @@ type Config struct {
awscommon.AMIConfig `mapstructure:",squash"`
awscommon.BlockDevices `mapstructure:",squash"`
awscommon.RunConfig `mapstructure:",squash"`
VolumeRunTags map[string]string `mapstructure:"run_volume_tags"`
VolumeRunTags awscommon.TagMap `mapstructure:"run_volume_tags"`
ctx interpolate.Context
}
@ -69,11 +69,18 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
errs = packer.MultiErrorAppend(errs, b.config.BlockDevices.Prepare(&b.config.ctx)...)
errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...)
if b.config.IsSpotInstance() && (b.config.AMIENASupport || b.config.AMISriovNetSupport) {
errs = packer.MultiErrorAppend(errs,
fmt.Errorf("Spot instances do not support modification, which is required "+
"when either `ena_support` or `sriov_support` are set. Please ensure "+
"you use an AMI that already has either SR-IOV or ENA enabled."))
}
if errs != nil && len(errs.Errors) > 0 {
return nil, errs
}
log.Println(common.ScrubConfig(b.config, b.config.AccessKey, b.config.SecretKey))
log.Println(common.ScrubConfig(b.config, b.config.AccessKey, b.config.SecretKey, b.config.Token))
return nil, nil
}
@ -106,51 +113,52 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
state := new(multistep.BasicStateBag)
state.Put("config", b.config)
state.Put("ec2", ec2conn)
state.Put("awsSession", session)
state.Put("hook", hook)
state.Put("ui", ui)
var instanceStep multistep.Step
isSpotInstance := b.config.SpotPrice != "" && b.config.SpotPrice != "0"
if isSpotInstance {
if b.config.IsSpotInstance() {
instanceStep = &awscommon.StepRunSpotInstance{
Debug: b.config.PackerDebug,
ExpectedRootDevice: "ebs",
SpotPrice: b.config.SpotPrice,
SpotPriceProduct: b.config.SpotPriceAutoProduct,
InstanceType: b.config.InstanceType,
UserData: b.config.UserData,
UserDataFile: b.config.UserDataFile,
SourceAMI: b.config.SourceAmi,
IamInstanceProfile: b.config.IamInstanceProfile,
SubnetId: b.config.SubnetId,
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
EbsOptimized: b.config.EbsOptimized,
AvailabilityZone: b.config.AvailabilityZone,
BlockDevices: b.config.BlockDevices,
Tags: b.config.RunTags,
VolumeTags: b.config.VolumeRunTags,
Ctx: b.config.ctx,
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
AvailabilityZone: b.config.AvailabilityZone,
BlockDevices: b.config.BlockDevices,
Ctx: b.config.ctx,
Debug: b.config.PackerDebug,
EbsOptimized: b.config.EbsOptimized,
ExpectedRootDevice: "ebs",
IamInstanceProfile: b.config.IamInstanceProfile,
InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior,
InstanceType: b.config.InstanceType,
SourceAMI: b.config.SourceAmi,
SpotPrice: b.config.SpotPrice,
SpotPriceProduct: b.config.SpotPriceAutoProduct,
SubnetId: b.config.SubnetId,
Tags: b.config.RunTags,
UserData: b.config.UserData,
UserDataFile: b.config.UserDataFile,
VolumeTags: b.config.VolumeRunTags,
}
} else {
instanceStep = &awscommon.StepRunSourceInstance{
Debug: b.config.PackerDebug,
ExpectedRootDevice: "ebs",
InstanceType: b.config.InstanceType,
UserData: b.config.UserData,
UserDataFile: b.config.UserDataFile,
SourceAMI: b.config.SourceAmi,
IamInstanceProfile: b.config.IamInstanceProfile,
SubnetId: b.config.SubnetId,
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
EbsOptimized: b.config.EbsOptimized,
AvailabilityZone: b.config.AvailabilityZone,
BlockDevices: b.config.BlockDevices,
Tags: b.config.RunTags,
VolumeTags: b.config.VolumeRunTags,
Ctx: b.config.ctx,
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
AvailabilityZone: b.config.AvailabilityZone,
BlockDevices: b.config.BlockDevices,
Ctx: b.config.ctx,
Debug: b.config.PackerDebug,
EbsOptimized: b.config.EbsOptimized,
ExpectedRootDevice: "ebs",
IamInstanceProfile: b.config.IamInstanceProfile,
InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior,
InstanceType: b.config.InstanceType,
IsRestricted: b.config.IsChinaCloud() || b.config.IsGovCloud(),
SourceAMI: b.config.SourceAmi,
SubnetId: b.config.SubnetId,
Tags: b.config.RunTags,
UserData: b.config.UserData,
UserDataFile: b.config.UserDataFile,
VolumeTags: b.config.VolumeRunTags,
}
}
@ -193,7 +201,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
Config: &b.config.RunConfig.Comm,
Host: awscommon.SSHHost(
ec2conn,
b.config.SSHPrivateIp),
b.config.SSHInterface),
SSHConfig: awscommon.SSHConfig(
b.config.RunConfig.Comm.SSHAgentAuth,
b.config.RunConfig.Comm.SSHUsername,
@ -201,7 +209,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
},
&common.StepProvision{},
&awscommon.StepStopEBSBackedInstance{
Skip: isSpotInstance,
Skip: b.config.IsSpotInstance(),
DisableStopInstance: b.config.DisableStopInstance,
},
&awscommon.StepModifyEBSBackedInstance{
@ -263,7 +271,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
artifact := &awscommon.Artifact{
Amis: state.Get("amis").(map[string]string),
BuilderIdValue: BuilderId,
Conn: ec2conn,
Session: session,
}
return artifact, nil

View File

@ -1,8 +1,11 @@
/*
Deregister the test image with
aws ec2 deregister-image --image-id $(aws ec2 describe-images --output text --filters "Name=name,Values=packer-test-packer-test-dereg" --query 'Images[*].{ID:ImageId}')
*/
package ebs
import (
"fmt"
"os"
"testing"
"github.com/aws/aws-sdk-go/aws"
@ -58,14 +61,14 @@ func TestBuilderAcc_forceDeleteSnapshot(t *testing.T) {
// Get image data by AMI name
ec2conn, _ := testEC2Conn()
imageResp, _ := ec2conn.DescribeImages(
&ec2.DescribeImagesInput{Filters: []*ec2.Filter{
{
Name: aws.String("name"),
Values: []*string{aws.String(amiName)},
},
}},
)
describeInput := &ec2.DescribeImagesInput{Filters: []*ec2.Filter{
{
Name: aws.String("name"),
Values: []*string{aws.String(amiName)},
},
}}
ec2conn.WaitUntilImageExists(describeInput)
imageResp, _ := ec2conn.DescribeImages(describeInput)
image := imageResp.Images[0]
// Get snapshot ids for image
@ -243,13 +246,6 @@ func checkBootEncrypted() builderT.TestCheckFunc {
}
func testAccPreCheck(t *testing.T) {
if v := os.Getenv("AWS_ACCESS_KEY_ID"); v == "" {
t.Fatal("AWS_ACCESS_KEY_ID must be set for acceptance tests")
}
if v := os.Getenv("AWS_SECRET_ACCESS_KEY"); v == "" {
t.Fatal("AWS_SECRET_ACCESS_KEY must be set for acceptance tests")
}
}
func testEC2Conn() (*ec2.EC2, error) {
@ -298,7 +294,7 @@ const testBuilderAccForceDeregister = `
"source_ami": "ami-76b2a71e",
"ssh_username": "ubuntu",
"force_deregister": "%s",
"ami_name": "packer-test-%s"
"ami_name": "%s"
}]
}
`
@ -313,7 +309,7 @@ const testBuilderAccForceDeleteSnapshot = `
"ssh_username": "ubuntu",
"force_deregister": "%s",
"force_delete_snapshot": "%s",
"ami_name": "packer-test-%s"
"ami_name": "%s"
}]
}
`

View File

@ -1,13 +1,14 @@
package ebs
import (
"context"
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/packer/builder/amazon/common"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
// stepCleanupVolumes cleans up any orphaned volumes that were not designated to
@ -17,7 +18,7 @@ type stepCleanupVolumes struct {
BlockDevices common.BlockDevices
}
func (s *stepCleanupVolumes) Run(state multistep.StateBag) multistep.StepAction {
func (s *stepCleanupVolumes) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
// stepCleanupVolumes is for Cleanup only
return multistep.ActionContinue
}

View File

@ -1,19 +1,20 @@
package ebs
import (
"context"
"fmt"
"github.com/aws/aws-sdk-go/service/ec2"
awscommon "github.com/hashicorp/packer/builder/amazon/common"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type stepCreateAMI struct {
image *ec2.Image
}
func (s *stepCreateAMI) Run(state multistep.StateBag) multistep.StepAction {
func (s *stepCreateAMI) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(Config)
ec2conn := state.Get("ec2").(*ec2.EC2)
instance := state.Get("instance").(*ec2.Instance)

View File

@ -12,9 +12,9 @@ import (
"github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/config"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
"github.com/mitchellh/multistep"
)
const BuilderId = "mitchellh.amazon.ebssurrogate"
@ -26,8 +26,8 @@ type Config struct {
awscommon.BlockDevices `mapstructure:",squash"`
awscommon.AMIConfig `mapstructure:",squash"`
RootDevice RootBlockDevice `mapstructure:"ami_root_device"`
VolumeRunTags map[string]string `mapstructure:"run_volume_tags"`
RootDevice RootBlockDevice `mapstructure:"ami_root_device"`
VolumeRunTags awscommon.TagMap `mapstructure:"run_volume_tags"`
ctx interpolate.Context
}
@ -84,11 +84,18 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("no volume with name '%s' is found", b.config.RootDevice.SourceDeviceName))
}
if b.config.IsSpotInstance() && (b.config.AMIENASupport || b.config.AMISriovNetSupport) {
errs = packer.MultiErrorAppend(errs,
fmt.Errorf("Spot instances do not support modification, which is required "+
"when either `ena_support` or `sriov_support` are set. Please ensure "+
"you use an AMI that already has either SR-IOV or ENA enabled."))
}
if errs != nil && len(errs.Errors) > 0 {
return nil, errs
}
log.Println(common.ScrubConfig(b.config, b.config.AccessKey, b.config.SecretKey))
log.Println(common.ScrubConfig(b.config, b.config.AccessKey, b.config.SecretKey, b.config.Token))
return nil, nil
}
@ -120,51 +127,52 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
state := new(multistep.BasicStateBag)
state.Put("config", &b.config)
state.Put("ec2", ec2conn)
state.Put("awsSession", session)
state.Put("hook", hook)
state.Put("ui", ui)
var instanceStep multistep.Step
isSpotInstance := b.config.SpotPrice != "" && b.config.SpotPrice != "0"
if isSpotInstance {
if b.config.IsSpotInstance() {
instanceStep = &awscommon.StepRunSpotInstance{
Debug: b.config.PackerDebug,
ExpectedRootDevice: "ebs",
SpotPrice: b.config.SpotPrice,
SpotPriceProduct: b.config.SpotPriceAutoProduct,
InstanceType: b.config.InstanceType,
UserData: b.config.UserData,
UserDataFile: b.config.UserDataFile,
SourceAMI: b.config.SourceAmi,
IamInstanceProfile: b.config.IamInstanceProfile,
SubnetId: b.config.SubnetId,
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
EbsOptimized: b.config.EbsOptimized,
AvailabilityZone: b.config.AvailabilityZone,
BlockDevices: b.config.BlockDevices,
Tags: b.config.RunTags,
VolumeTags: b.config.VolumeRunTags,
Ctx: b.config.ctx,
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
AvailabilityZone: b.config.AvailabilityZone,
BlockDevices: b.config.BlockDevices,
Ctx: b.config.ctx,
Debug: b.config.PackerDebug,
EbsOptimized: b.config.EbsOptimized,
ExpectedRootDevice: "ebs",
IamInstanceProfile: b.config.IamInstanceProfile,
InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior,
InstanceType: b.config.InstanceType,
SourceAMI: b.config.SourceAmi,
SpotPrice: b.config.SpotPrice,
SpotPriceProduct: b.config.SpotPriceAutoProduct,
SubnetId: b.config.SubnetId,
Tags: b.config.RunTags,
UserData: b.config.UserData,
UserDataFile: b.config.UserDataFile,
VolumeTags: b.config.VolumeRunTags,
}
} else {
instanceStep = &awscommon.StepRunSourceInstance{
Debug: b.config.PackerDebug,
ExpectedRootDevice: "ebs",
InstanceType: b.config.InstanceType,
UserData: b.config.UserData,
UserDataFile: b.config.UserDataFile,
SourceAMI: b.config.SourceAmi,
IamInstanceProfile: b.config.IamInstanceProfile,
SubnetId: b.config.SubnetId,
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
EbsOptimized: b.config.EbsOptimized,
AvailabilityZone: b.config.AvailabilityZone,
BlockDevices: b.config.BlockDevices,
Tags: b.config.RunTags,
VolumeTags: b.config.VolumeRunTags,
Ctx: b.config.ctx,
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
AvailabilityZone: b.config.AvailabilityZone,
BlockDevices: b.config.BlockDevices,
Ctx: b.config.ctx,
Debug: b.config.PackerDebug,
EbsOptimized: b.config.EbsOptimized,
ExpectedRootDevice: "ebs",
IamInstanceProfile: b.config.IamInstanceProfile,
InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior,
InstanceType: b.config.InstanceType,
IsRestricted: b.config.IsChinaCloud() || b.config.IsGovCloud(),
SourceAMI: b.config.SourceAmi,
SubnetId: b.config.SubnetId,
Tags: b.config.RunTags,
UserData: b.config.UserData,
UserDataFile: b.config.UserDataFile,
VolumeTags: b.config.VolumeRunTags,
}
}
@ -204,7 +212,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
Config: &b.config.RunConfig.Comm,
Host: awscommon.SSHHost(
ec2conn,
b.config.SSHPrivateIp),
b.config.SSHInterface),
SSHConfig: awscommon.SSHConfig(
b.config.RunConfig.Comm.SSHAgentAuth,
b.config.RunConfig.Comm.SSHUsername,
@ -212,7 +220,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
},
&common.StepProvision{},
&awscommon.StepStopEBSBackedInstance{
Skip: isSpotInstance,
Skip: b.config.IsSpotInstance(),
DisableStopInstance: b.config.DisableStopInstance,
},
&awscommon.StepModifyEBSBackedInstance{
@ -277,7 +285,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
artifact := &awscommon.Artifact{
Amis: amis.(map[string]string),
BuilderIdValue: BuilderId,
Conn: ec2conn,
Session: session,
}
return artifact, nil

View File

@ -2,6 +2,7 @@ package ebssurrogate
import (
"errors"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/packer/template/interpolate"

View File

@ -1,13 +1,14 @@
package ebssurrogate
import (
"context"
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
awscommon "github.com/hashicorp/packer/builder/amazon/common"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
// StepRegisterAMI creates the AMI.
@ -19,7 +20,7 @@ type StepRegisterAMI struct {
image *ec2.Image
}
func (s *StepRegisterAMI) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepRegisterAMI) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config)
ec2conn := state.Get("ec2").(*ec2.EC2)
snapshotId := state.Get("snapshot_id").(string)

View File

@ -1,14 +1,15 @@
package ebssurrogate
import (
"context"
"errors"
"fmt"
"time"
"github.com/aws/aws-sdk-go/service/ec2"
awscommon "github.com/hashicorp/packer/builder/amazon/common"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
// StepSnapshotNewRootVolume creates a snapshot of the created volume.
@ -20,7 +21,7 @@ type StepSnapshotNewRootVolume struct {
snapshotId string
}
func (s *StepSnapshotNewRootVolume) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepSnapshotNewRootVolume) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ec2conn := state.Get("ec2").(*ec2.EC2)
ui := state.Get("ui").(packer.Ui)
instance := state.Get("instance").(*ec2.Instance)

View File

@ -7,7 +7,7 @@ import (
type BlockDevice struct {
awscommon.BlockDevice `mapstructure:"-,squash"`
Tags map[string]string `mapstructure:"tags"`
Tags awscommon.TagMap `mapstructure:"tags"`
}
func commonBlockDevices(mappings []BlockDevice, ctx *interpolate.Context) (awscommon.BlockDevices, error) {

View File

@ -11,9 +11,9 @@ import (
"github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/config"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
"github.com/mitchellh/multistep"
)
const BuilderId = "mitchellh.amazon.ebsvolume"
@ -56,17 +56,31 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
var errs *packer.MultiError
errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(&b.config.ctx)...)
errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...)
errs = packer.MultiErrorAppend(errs, b.config.launchBlockDevices.Prepare(&b.config.ctx)...)
for _, d := range b.config.VolumeMappings {
if err := d.Prepare(&b.config.ctx); err != nil {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("AMIMapping: %s", err.Error()))
}
}
b.config.launchBlockDevices, err = commonBlockDevices(b.config.VolumeMappings, &b.config.ctx)
if err != nil {
errs = packer.MultiErrorAppend(errs, err)
}
if b.config.IsSpotInstance() && (b.config.AMIENASupport || b.config.AMISriovNetSupport) {
errs = packer.MultiErrorAppend(errs,
fmt.Errorf("Spot instances do not support modification, which is required "+
"when either `ena_support` or `sriov_support` are set. Please ensure "+
"you use an AMI that already has either SR-IOV or ENA enabled."))
}
if errs != nil && len(errs.Errors) > 0 {
return nil, errs
}
log.Println(common.ScrubConfig(b.config, b.config.AccessKey, b.config.SecretKey))
log.Println(common.ScrubConfig(b.config, b.config.AccessKey, b.config.SecretKey, b.config.Token))
return nil, nil
}
@ -103,45 +117,44 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
var instanceStep multistep.Step
isSpotInstance := b.config.SpotPrice != "" && b.config.SpotPrice != "0"
if isSpotInstance {
if b.config.IsSpotInstance() {
instanceStep = &awscommon.StepRunSpotInstance{
Debug: b.config.PackerDebug,
ExpectedRootDevice: "ebs",
SpotPrice: b.config.SpotPrice,
SpotPriceProduct: b.config.SpotPriceAutoProduct,
InstanceType: b.config.InstanceType,
UserData: b.config.UserData,
UserDataFile: b.config.UserDataFile,
SourceAMI: b.config.SourceAmi,
IamInstanceProfile: b.config.IamInstanceProfile,
SubnetId: b.config.SubnetId,
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
EbsOptimized: b.config.EbsOptimized,
AvailabilityZone: b.config.AvailabilityZone,
BlockDevices: b.config.launchBlockDevices,
Tags: b.config.RunTags,
Ctx: b.config.ctx,
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
AvailabilityZone: b.config.AvailabilityZone,
BlockDevices: b.config.launchBlockDevices,
Ctx: b.config.ctx,
Debug: b.config.PackerDebug,
EbsOptimized: b.config.EbsOptimized,
ExpectedRootDevice: "ebs",
IamInstanceProfile: b.config.IamInstanceProfile,
InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior,
InstanceType: b.config.InstanceType,
SourceAMI: b.config.SourceAmi,
SpotPrice: b.config.SpotPrice,
SpotPriceProduct: b.config.SpotPriceAutoProduct,
SubnetId: b.config.SubnetId,
Tags: b.config.RunTags,
UserData: b.config.UserData,
UserDataFile: b.config.UserDataFile,
}
} else {
instanceStep = &awscommon.StepRunSourceInstance{
Debug: b.config.PackerDebug,
ExpectedRootDevice: "ebs",
InstanceType: b.config.InstanceType,
UserData: b.config.UserData,
UserDataFile: b.config.UserDataFile,
SourceAMI: b.config.SourceAmi,
IamInstanceProfile: b.config.IamInstanceProfile,
SubnetId: b.config.SubnetId,
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
EbsOptimized: b.config.EbsOptimized,
AvailabilityZone: b.config.AvailabilityZone,
BlockDevices: b.config.launchBlockDevices,
Tags: b.config.RunTags,
Ctx: b.config.ctx,
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
AvailabilityZone: b.config.AvailabilityZone,
BlockDevices: b.config.launchBlockDevices,
Ctx: b.config.ctx,
Debug: b.config.PackerDebug,
EbsOptimized: b.config.EbsOptimized,
ExpectedRootDevice: "ebs",
IamInstanceProfile: b.config.IamInstanceProfile,
InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior,
InstanceType: b.config.InstanceType,
IsRestricted: b.config.IsChinaCloud() || b.config.IsGovCloud(),
SourceAMI: b.config.SourceAmi,
SubnetId: b.config.SubnetId,
Tags: b.config.RunTags,
UserData: b.config.UserData,
UserDataFile: b.config.UserDataFile,
}
}
@ -181,7 +194,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
Config: &b.config.RunConfig.Comm,
Host: awscommon.SSHHost(
ec2conn,
b.config.SSHPrivateIp),
b.config.SSHInterface),
SSHConfig: awscommon.SSHConfig(
b.config.RunConfig.Comm.SSHAgentAuth,
b.config.RunConfig.Comm.SSHUsername,
@ -189,7 +202,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
},
&common.StepProvision{},
&awscommon.StepStopEBSBackedInstance{
Skip: isSpotInstance,
Skip: b.config.IsSpotInstance(),
DisableStopInstance: b.config.DisableStopInstance,
},
&awscommon.StepModifyEBSBackedInstance{

View File

@ -1,13 +1,13 @@
package ebsvolume
import (
"context"
"fmt"
"github.com/aws/aws-sdk-go/service/ec2"
awscommon "github.com/hashicorp/packer/builder/amazon/common"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
"github.com/mitchellh/multistep"
)
type stepTagEBSVolumes struct {
@ -15,7 +15,7 @@ type stepTagEBSVolumes struct {
Ctx interpolate.Context
}
func (s *stepTagEBSVolumes) Run(state multistep.StateBag) multistep.StepAction {
func (s *stepTagEBSVolumes) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ec2conn := state.Get("ec2").(*ec2.EC2)
instance := state.Get("instance").(*ec2.Instance)
sourceAMI := state.Get("source_image").(*ec2.Image)
@ -43,14 +43,14 @@ func (s *stepTagEBSVolumes) Run(state multistep.StateBag) multistep.StepAction {
continue
}
tags, err := awscommon.ConvertToEC2Tags(mapping.Tags, *ec2conn.Config.Region, *sourceAMI.ImageId, s.Ctx)
tags, err := mapping.Tags.EC2Tags(s.Ctx, *ec2conn.Config.Region, *sourceAMI.ImageId)
if err != nil {
err := fmt.Errorf("Error tagging device %s with %s", mapping.DeviceName, err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
awscommon.ReportTags(ui, tags)
tags.Report(ui)
for _, v := range instance.BlockDeviceMappings {
if *v.DeviceName == mapping.DeviceName {

View File

@ -14,9 +14,9 @@ import (
"github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/config"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
"github.com/mitchellh/multistep"
)
// The unique ID for this builder
@ -155,11 +155,18 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
errs, fmt.Errorf("x509_key_path points to bad file: %s", err))
}
if b.config.IsSpotInstance() && (b.config.AMIENASupport || b.config.AMISriovNetSupport) {
errs = packer.MultiErrorAppend(errs,
fmt.Errorf("Spot instances do not support modification, which is required "+
"when either `ena_support` or `sriov_support` are set. Please ensure "+
"you use an AMI that already has either SR-IOV or ENA enabled."))
}
if errs != nil && len(errs.Errors) > 0 {
return nil, errs
}
log.Println(common.ScrubConfig(b.config, b.config.AccessKey, b.config.SecretKey))
log.Println(common.ScrubConfig(b.config, b.config.AccessKey, b.config.SecretKey, b.config.Token))
return nil, nil
}
@ -191,44 +198,46 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
state := new(multistep.BasicStateBag)
state.Put("config", &b.config)
state.Put("ec2", ec2conn)
state.Put("awsSession", session)
state.Put("hook", hook)
state.Put("ui", ui)
var instanceStep multistep.Step
if b.config.SpotPrice == "" || b.config.SpotPrice == "0" {
instanceStep = &awscommon.StepRunSourceInstance{
Debug: b.config.PackerDebug,
InstanceType: b.config.InstanceType,
UserData: b.config.UserData,
UserDataFile: b.config.UserDataFile,
SourceAMI: b.config.SourceAmi,
IamInstanceProfile: b.config.IamInstanceProfile,
SubnetId: b.config.SubnetId,
if b.config.IsSpotInstance() {
instanceStep = &awscommon.StepRunSpotInstance{
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
EbsOptimized: b.config.EbsOptimized,
AvailabilityZone: b.config.AvailabilityZone,
BlockDevices: b.config.BlockDevices,
Tags: b.config.RunTags,
Ctx: b.config.ctx,
}
} else {
instanceStep = &awscommon.StepRunSpotInstance{
Debug: b.config.PackerDebug,
EbsOptimized: b.config.EbsOptimized,
IamInstanceProfile: b.config.IamInstanceProfile,
InstanceType: b.config.InstanceType,
SourceAMI: b.config.SourceAmi,
SpotPrice: b.config.SpotPrice,
SpotPriceProduct: b.config.SpotPriceAutoProduct,
InstanceType: b.config.InstanceType,
SubnetId: b.config.SubnetId,
Tags: b.config.RunTags,
UserData: b.config.UserData,
UserDataFile: b.config.UserDataFile,
SourceAMI: b.config.SourceAmi,
IamInstanceProfile: b.config.IamInstanceProfile,
SubnetId: b.config.SubnetId,
}
} else {
instanceStep = &awscommon.StepRunSourceInstance{
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
EbsOptimized: b.config.EbsOptimized,
AvailabilityZone: b.config.AvailabilityZone,
BlockDevices: b.config.BlockDevices,
Tags: b.config.RunTags,
Ctx: b.config.ctx,
Debug: b.config.PackerDebug,
EbsOptimized: b.config.EbsOptimized,
IamInstanceProfile: b.config.IamInstanceProfile,
InstanceType: b.config.InstanceType,
IsRestricted: b.config.IsChinaCloud() || b.config.IsGovCloud(),
SourceAMI: b.config.SourceAmi,
SubnetId: b.config.SubnetId,
Tags: b.config.RunTags,
UserData: b.config.UserData,
UserDataFile: b.config.UserDataFile,
}
}
@ -268,7 +277,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
Config: &b.config.RunConfig.Comm,
Host: awscommon.SSHHost(
ec2conn,
b.config.SSHPrivateIp),
b.config.SSHInterface),
SSHConfig: awscommon.SSHConfig(
b.config.RunConfig.Comm.SSHAgentAuth,
b.config.RunConfig.Comm.SSHUsername,
@ -334,7 +343,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
artifact := &awscommon.Artifact{
Amis: state.Get("amis").(map[string]string),
BuilderIdValue: BuilderId,
Conn: ec2conn,
Session: session,
}
return artifact, nil

View File

@ -1,10 +1,11 @@
package instance
import (
"github.com/hashicorp/packer/packer"
"io/ioutil"
"os"
"testing"
"github.com/hashicorp/packer/packer"
)
func testConfig() map[string]interface{} {

View File

@ -1,12 +1,13 @@
package instance
import (
"context"
"fmt"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
"github.com/mitchellh/multistep"
)
type bundleCmdData struct {
@ -23,7 +24,7 @@ type StepBundleVolume struct {
Debug bool
}
func (s *StepBundleVolume) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepBundleVolume) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
comm := state.Get("communicator").(packer.Communicator)
config := state.Get("config").(*Config)
instance := state.Get("instance").(*ec2.Instance)

View File

@ -1,13 +1,14 @@
package instance
import (
"context"
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
awscommon "github.com/hashicorp/packer/builder/amazon/common"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type StepRegisterAMI struct {
@ -15,7 +16,7 @@ type StepRegisterAMI struct {
EnableAMISriovNetSupport bool
}
func (s *StepRegisterAMI) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepRegisterAMI) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config)
ec2conn := state.Get("ec2").(*ec2.EC2)
manifestPath := state.Get("remote_manifest_path").(string)

View File

@ -1,11 +1,12 @@
package instance
import (
"context"
"fmt"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
"github.com/mitchellh/multistep"
)
type uploadCmdData struct {
@ -22,7 +23,7 @@ type StepUploadBundle struct {
Debug bool
}
func (s *StepUploadBundle) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepUploadBundle) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
comm := state.Get("communicator").(packer.Communicator)
config := state.Get("config").(*Config)
manifestName := state.Get("manifest_name").(string)

View File

@ -1,15 +1,17 @@
package instance
import (
"context"
"fmt"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
"os"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
type StepUploadX509Cert struct{}
func (s *StepUploadX509Cert) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepUploadX509Cert) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
comm := state.Get("communicator").(packer.Communicator)
config := state.Get("config").(*Config)
ui := state.Get("ui").(packer.Ui)

View File

@ -1,8 +1,9 @@
package arm
import (
"github.com/Azure/go-autorest/autorest/azure"
"testing"
"github.com/Azure/go-autorest/autorest/azure"
)
// Behavior is the most important thing to assert for ServicePrincipalToken, but

View File

@ -10,6 +10,7 @@ import (
"strconv"
"github.com/Azure/azure-sdk-for-go/arm/compute"
"github.com/Azure/azure-sdk-for-go/arm/disk"
"github.com/Azure/azure-sdk-for-go/arm/network"
"github.com/Azure/azure-sdk-for-go/arm/resources/resources"
armStorage "github.com/Azure/azure-sdk-for-go/arm/storage"
@ -32,6 +33,7 @@ var (
type AzureClient struct {
storage.BlobStorageClient
resources.DeploymentsClient
resources.DeploymentOperationsClient
resources.GroupsClient
network.PublicIPAddressesClient
network.InterfacesClient
@ -41,10 +43,12 @@ type AzureClient struct {
compute.VirtualMachinesClient
common.VaultClient
armStorage.AccountsClient
disk.DisksClient
InspectorMaxLength int
Template *CaptureTemplate
LastError azureErrorResponse
VaultClientDelete common.VaultClient
}
func getCaptureResponse(body string) *CaptureTemplate {
@ -135,6 +139,18 @@ func NewAzureClient(subscriptionID, resourceGroupName, storageAccountName string
azureClient.DeploymentsClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient))
azureClient.DeploymentsClient.UserAgent += packerUserAgent
azureClient.DeploymentOperationsClient = resources.NewDeploymentOperationsClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID)
azureClient.DeploymentOperationsClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken)
azureClient.DeploymentOperationsClient.RequestInspector = withInspection(maxlen)
azureClient.DeploymentOperationsClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient))
azureClient.DeploymentOperationsClient.UserAgent += packerUserAgent
azureClient.DisksClient = disk.NewDisksClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID)
azureClient.DisksClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken)
azureClient.DisksClient.RequestInspector = withInspection(maxlen)
azureClient.DisksClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient))
azureClient.DisksClient.UserAgent += packerUserAgent
azureClient.GroupsClient = resources.NewGroupsClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID)
azureClient.GroupsClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken)
azureClient.GroupsClient.RequestInspector = withInspection(maxlen)
@ -194,6 +210,20 @@ func NewAzureClient(subscriptionID, resourceGroupName, storageAccountName string
azureClient.VaultClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient))
azureClient.VaultClient.UserAgent += packerUserAgent
// TODO(boumenot) - SDK still does not have a full KeyVault client.
// There are two ways that KeyVault has to be accessed, and each one has their own SPN. An authenticated SPN
// is tied to the URL, and the URL associated with getting the secret is different than the URL
// associated with deleting the KeyVault. As a result, I need to have *two* different clients to
// access KeyVault. I did not want to split it into two separate files, so I am starting with this.
//
// I do not like this implementation. It is getting long in the tooth, and should be re-examined now
// that we have a "working" solution.
azureClient.VaultClientDelete = common.NewVaultClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID)
azureClient.VaultClientDelete.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken)
azureClient.VaultClientDelete.RequestInspector = withInspection(maxlen)
azureClient.VaultClientDelete.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient))
azureClient.VaultClientDelete.UserAgent += packerUserAgent
// If this is a managed disk build, this should be ignored.
if resourceGroupName != "" && storageAccountName != "" {
accountKeys, err := azureClient.AccountsClient.ListKeys(resourceGroupName, storageAccountName)

View File

@ -1,10 +1,11 @@
package arm
import (
"github.com/approvals/go-approval-tests"
"github.com/hashicorp/packer/common/json"
"strings"
"testing"
"github.com/approvals/go-approval-tests"
"github.com/hashicorp/packer/common/json"
)
const AzureErrorSimple = `{"error":{"code":"ResourceNotFound","message":"The Resource 'Microsoft.Compute/images/PackerUbuntuImage' under resource group 'packer-test00' was not found."}}`

View File

@ -18,8 +18,8 @@ import (
"github.com/Azure/go-autorest/autorest/adal"
packerCommon "github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type Builder struct {
@ -103,6 +103,15 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
}
}
if b.config.BuildResourceGroupName != "" {
group, err := azureClient.GroupsClient.Get(b.config.BuildResourceGroupName)
if err != nil {
return nil, fmt.Errorf("Cannot locate the existing build resource resource group %s.", b.config.BuildResourceGroupName)
}
b.config.Location = *group.Location
}
if b.config.StorageAccount != "" {
account, err := b.getBlobAccount(azureClient, b.config.ResourceGroupName, b.config.StorageAccount)
if err != nil {
@ -127,11 +136,13 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
b.setImageParameters(b.stateBag)
var steps []multistep.Step
deploymentName := b.stateBag.Get(constants.ArmDeploymentName).(string)
if b.config.OSType == constants.Target_Linux {
steps = []multistep.Step{
NewStepCreateResourceGroup(azureClient, ui),
NewStepValidateTemplate(azureClient, ui, b.config, GetVirtualMachineDeployment),
NewStepDeployTemplate(azureClient, ui, b.config, GetVirtualMachineDeployment),
NewStepDeployTemplate(azureClient, ui, b.config, deploymentName, GetVirtualMachineDeployment),
NewStepGetIPAddress(azureClient, ui, endpointConnectType),
&communicator.StepConnectSSH{
Config: &b.config.Comm,
@ -146,14 +157,15 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
NewStepDeleteOSDisk(azureClient, ui),
}
} else if b.config.OSType == constants.Target_Windows {
keyVaultDeploymentName := b.stateBag.Get(constants.ArmKeyVaultDeploymentName).(string)
steps = []multistep.Step{
NewStepCreateResourceGroup(azureClient, ui),
NewStepValidateTemplate(azureClient, ui, b.config, GetKeyVaultDeployment),
NewStepDeployTemplate(azureClient, ui, b.config, GetKeyVaultDeployment),
NewStepDeployTemplate(azureClient, ui, b.config, keyVaultDeploymentName, GetKeyVaultDeployment),
NewStepGetCertificate(azureClient, ui),
NewStepSetCertificate(b.config, ui),
NewStepValidateTemplate(azureClient, ui, b.config, GetVirtualMachineDeployment),
NewStepDeployTemplate(azureClient, ui, b.config, GetVirtualMachineDeployment),
NewStepDeployTemplate(azureClient, ui, b.config, deploymentName, GetVirtualMachineDeployment),
NewStepGetIPAddress(azureClient, ui, endpointConnectType),
&communicator.StepConnectWinRM{
Config: &b.config.Comm,
@ -283,11 +295,22 @@ func (b *Builder) configureStateBag(stateBag multistep.StateBag) {
stateBag.Put(constants.ArmTags, &b.config.AzureTags)
stateBag.Put(constants.ArmComputeName, b.config.tmpComputeName)
stateBag.Put(constants.ArmDeploymentName, b.config.tmpDeploymentName)
if b.config.OSType == constants.Target_Windows {
stateBag.Put(constants.ArmKeyVaultDeploymentName, fmt.Sprintf("kv%s", b.config.tmpDeploymentName))
}
stateBag.Put(constants.ArmKeyVaultName, b.config.tmpKeyVaultName)
stateBag.Put(constants.ArmLocation, b.config.Location)
stateBag.Put(constants.ArmNicName, DefaultNicName)
stateBag.Put(constants.ArmPublicIPAddressName, DefaultPublicIPAddressName)
stateBag.Put(constants.ArmResourceGroupName, b.config.tmpResourceGroupName)
if b.config.TempResourceGroupName != "" && b.config.BuildResourceGroupName != "" {
stateBag.Put(constants.ArmDoubleResourceGroupNameSet, true)
}
if b.config.tmpResourceGroupName != "" {
stateBag.Put(constants.ArmResourceGroupName, b.config.tmpResourceGroupName)
stateBag.Put(constants.ArmIsExistingResourceGroup, false)
} else {
stateBag.Put(constants.ArmResourceGroupName, b.config.BuildResourceGroupName)
stateBag.Put(constants.ArmIsExistingResourceGroup, true)
}
stateBag.Put(constants.ArmStorageAccountName, b.config.StorageAccount)
stateBag.Put(constants.ArmIsManagedImage, b.config.isManagedImage())
@ -297,6 +320,7 @@ func (b *Builder) configureStateBag(stateBag multistep.StateBag) {
// Parameters that are only known at runtime after querying Azure.
func (b *Builder) setRuntimeParameters(stateBag multistep.StateBag) {
stateBag.Put(constants.ArmLocation, b.config.Location)
stateBag.Put(constants.ArmManagedImageLocation, b.config.manageImageLocation)
}

View File

@ -20,7 +20,6 @@ func TestStateBagShouldBePopulatedExpectedValues(t *testing.T) {
constants.ArmTags,
constants.ArmComputeName,
constants.ArmDeploymentName,
constants.ArmLocation,
constants.ArmNicName,
constants.ArmResourceGroupName,
constants.ArmStorageAccountName,

View File

@ -38,9 +38,23 @@ const (
DefaultVMSize = "Standard_A1"
)
const (
// https://docs.microsoft.com/en-us/azure/architecture/best-practices/naming-conventions#naming-rules-and-restrictions
// Regular expressions in Go are not expressive enough, such that the regular expression returned by Azure
// can be used (no backtracking).
//
// -> ^[^_\W][\w-._]{0,79}(?<![-.])$
//
// This is not an exhaustive match, but it should be extremely close.
validResourceGroupNameRe = "^[^_\\W][\\w-._\\(\\)]{0,63}$"
validManagedDiskName = "^[^_\\W][\\w-._)]{0,79}$"
)
var (
reCaptureContainerName = regexp.MustCompile("^[a-z0-9][a-z0-9\\-]{2,62}$")
reCaptureNamePrefix = regexp.MustCompile("^[A-Za-z0-9][A-Za-z0-9_\\-\\.]{0,23}$")
reManagedDiskName = regexp.MustCompile(validManagedDiskName)
reResourceGroupName = regexp.MustCompile(validResourceGroupNameRe)
)
type Config struct {
@ -83,6 +97,7 @@ type Config struct {
StorageAccount string `mapstructure:"storage_account"`
TempComputeName string `mapstructure:"temp_compute_name"`
TempResourceGroupName string `mapstructure:"temp_resource_group_name"`
BuildResourceGroupName string `mapstructure:"build_resource_group_name"`
storageAccountBlobEndpoint string
CloudEnvironmentName string `mapstructure:"cloud_environment_name"`
cloudEnvironment *azure.Environment
@ -129,7 +144,13 @@ type keyVaultCertificate struct {
}
func (c *Config) toVMID() string {
return fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/virtualMachines/%s", c.SubscriptionID, c.tmpResourceGroupName, c.tmpComputeName)
var resourceGroupName string
if c.tmpResourceGroupName != "" {
resourceGroupName = c.tmpResourceGroupName
} else {
resourceGroupName = c.BuildResourceGroupName
}
return fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/virtualMachines/%s", c.SubscriptionID, resourceGroupName, c.tmpComputeName)
}
func (c *Config) isManagedImage() bool {
@ -328,9 +349,10 @@ func setRuntimeValues(c *Config) {
c.tmpComputeName = c.TempComputeName
}
c.tmpDeploymentName = tempName.DeploymentName
if c.TempResourceGroupName == "" {
// Only set tmpResourceGroupName if no name has been specified
if c.TempResourceGroupName == "" && c.BuildResourceGroupName == "" {
c.tmpResourceGroupName = tempName.ResourceGroupName
} else {
} else if c.TempResourceGroupName != "" && c.BuildResourceGroupName == "" {
c.tmpResourceGroupName = c.TempResourceGroupName
}
c.tmpOSDiskName = tempName.OSDiskName
@ -511,6 +533,10 @@ func assertRequiredParametersSet(c *Config, errs *packer.MultiError) {
}
}
if c.TempResourceGroupName != "" && c.BuildResourceGroupName != "" {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("The settings temp_resource_group_name and build_resource_group_name cannot both be defined. Please define one or neither."))
}
/////////////////////////////////////////////
// Compute
toInt := func(b bool) int {
@ -564,10 +590,6 @@ func assertRequiredParametersSet(c *Config, errs *packer.MultiError) {
}
}
if c.Location == "" {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("A location must be specified"))
}
/////////////////////////////////////////////
// Deployment
xor := func(a, b bool) bool {
@ -578,6 +600,10 @@ func assertRequiredParametersSet(c *Config, errs *packer.MultiError) {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("Specify either a VHD (storage_account and resource_group_name) or Managed Image (managed_image_resource_group_name and managed_image_name) output"))
}
if !xor(c.Location != "", c.BuildResourceGroupName != "") {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("Must specify either a location to create the resource group in or an existing build_resource_group_name."))
}
if c.ManagedImageName == "" && c.ManagedImageResourceGroupName == "" {
if c.StorageAccount == "" {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("A storage_account must be specified"))
@ -587,6 +613,30 @@ func assertRequiredParametersSet(c *Config, errs *packer.MultiError) {
}
}
if c.TempResourceGroupName != "" {
if ok, err := assertResourceGroupName(c.TempResourceGroupName, "temp_resource_group_name"); !ok {
errs = packer.MultiErrorAppend(errs, err)
}
}
if c.BuildResourceGroupName != "" {
if ok, err := assertResourceGroupName(c.BuildResourceGroupName, "build_resource_group_name"); !ok {
errs = packer.MultiErrorAppend(errs, err)
}
}
if c.ManagedImageResourceGroupName != "" {
if ok, err := assertResourceGroupName(c.ManagedImageResourceGroupName, "managed_image_resource_group_name"); !ok {
errs = packer.MultiErrorAppend(errs, err)
}
}
if c.ManagedImageName != "" {
if ok, err := assertManagedImageName(c.ManagedImageName, "managed_image_name"); !ok {
errs = packer.MultiErrorAppend(errs, err)
}
}
if c.VirtualNetworkName == "" && c.VirtualNetworkResourceGroupName != "" {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("If virtual_network_resource_group_name is specified, so must virtual_network_name"))
}
@ -615,3 +665,23 @@ func assertRequiredParametersSet(c *Config, errs *packer.MultiError) {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("The managed_image_storage_account_type %q is invalid", c.ManagedImageStorageAccountType))
}
}
func assertManagedImageName(name, setting string) (bool, error) {
if !isValidAzureName(reManagedDiskName, name) {
return false, fmt.Errorf("The setting %s must match the regular expression %q, and not end with a '-' or '.'.", setting, validManagedDiskName)
}
return true, nil
}
func assertResourceGroupName(rgn, setting string) (bool, error) {
if !isValidAzureName(reResourceGroupName, rgn) {
return false, fmt.Errorf("The setting %s must match the regular expression %q, and not end with a '-' or '.'.", setting, validResourceGroupNameRe)
}
return true, nil
}
func isValidAzureName(re *regexp.Regexp, rgn string) bool {
return re.Match([]byte(rgn)) &&
!strings.HasSuffix(rgn, ".") &&
!strings.HasSuffix(rgn, "-")
}

View File

@ -899,6 +899,164 @@ func TestConfigShouldAcceptManagedImageStorageAccountTypes(t *testing.T) {
}
}
func TestConfigShouldRejectTempAndBuildResourceGroupName(t *testing.T) {
config := map[string]interface{}{
"capture_name_prefix": "ignore",
"capture_container_name": "ignore",
"image_offer": "ignore",
"image_publisher": "ignore",
"image_sku": "ignore",
"location": "ignore",
"storage_account": "ignore",
"resource_group_name": "ignore",
"subscription_id": "ignore",
"communicator": "none",
// custom may define one or the other, but not both
"temp_resource_group_name": "rgn00",
"build_resource_group_name": "rgn00",
}
_, _, err := newConfig(config, getPackerConfiguration())
if err == nil {
t.Fatal("expected config to reject the use of both temp_resource_group_name and build_resource_group_name")
}
}
func TestConfigShouldRejectInvalidResourceGroupNames(t *testing.T) {
config := map[string]interface{}{
"capture_name_prefix": "ignore",
"capture_container_name": "ignore",
"image_offer": "ignore",
"image_publisher": "ignore",
"image_sku": "ignore",
"location": "ignore",
"storage_account": "ignore",
"resource_group_name": "ignore",
"subscription_id": "ignore",
"communicator": "none",
"os_type": "linux",
}
tests := []struct {
name string
ok bool
}{
// The Good
{"packer-Resource-Group-jt2j3fc", true},
{"My", true},
{"My-(with-parens)-Resource-Group", true},
// The Bad
{"My Resource Group", false},
{"My-Resource-Group-", false},
{"My.Resource.Group.", false},
// The Ugly
{"My!@#!@#%$%yM", false},
{" ", false},
{"My10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", false},
}
settings := []string{"temp_resource_group_name", "build_resource_group_name"}
for _, x := range settings {
for _, y := range tests {
config[x] = y.name
_, _, err := newConfig(config, getPackerConfiguration())
if !y.ok && err == nil {
t.Errorf("expected config to reject %q for setting %q", y.name, x)
} else if y.ok && err != nil {
t.Errorf("expected config to accept %q for setting %q", y.name, x)
}
}
delete(config, "location") // not valid for build_resource_group_name
delete(config, x)
}
}
func TestConfigShouldRejectManagedDiskNames(t *testing.T) {
config := map[string]interface{}{
"image_offer": "ignore",
"image_publisher": "ignore",
"image_sku": "ignore",
"location": "ignore",
"subscription_id": "ignore",
"communicator": "none",
"os_type": "linux",
"managed_image_name": "ignore",
"managed_image_resource_group_name": "ignore",
}
testsResourceGroupNames := []struct {
name string
ok bool
}{
// The Good
{"packer-Resource-Group-jt2j3fc", true},
{"My", true},
{"My-(with-parens)-Resource-Group", true},
// The Bad
{"My Resource Group", false},
{"My-Resource-Group-", false},
{"My.Resource.Group.", false},
// The Ugly
{"My!@#!@#%$%yM", false},
{" ", false},
{"My10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", false},
}
settingUnderTest := "managed_image_resource_group_name"
for _, y := range testsResourceGroupNames {
config[settingUnderTest] = y.name
_, _, err := newConfig(config, getPackerConfiguration())
if !y.ok && err == nil {
t.Errorf("expected config to reject %q for setting %q", y.name, settingUnderTest)
} else if y.ok && err != nil {
t.Errorf("expected config to accept %q for setting %q", y.name, settingUnderTest)
}
}
config["managed_image_resource_group_name"] = "ignored"
testNames := []struct {
name string
ok bool
}{
// The Good
{"ManagedDiskName", true},
{"Managed-Disk-Name", true},
{"My33", true},
// The Bad
{"Managed Disk Name", false},
{"Managed-Disk-Name-", false},
{"Managed.Disk.Name.", false},
// The Ugly
{"My!@#!@#%$%yM", false},
{" ", false},
{"My10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", false},
}
settingUnderTest = "managed_image_name"
for _, y := range testNames {
config[settingUnderTest] = y.name
_, _, err := newConfig(config, getPackerConfiguration())
if !y.ok && err == nil {
t.Logf("expected config to reject %q for setting %q", y.name, settingUnderTest)
} else if y.ok && err != nil {
t.Logf("expected config to accept %q for setting %q", y.name, settingUnderTest)
}
}
}
func getArmBuilderConfiguration() map[string]string {
m := make(map[string]string)
for _, v := range requiredConfigValues {

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