diff --git a/.circleci/config.yml b/.circleci/config.yml index b4ac6e2b3..1cf3eccc2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,7 +5,7 @@ env: &env MODULE_GCP_CI_VERSION: v0.1.1 TERRAFORM_VERSION: 1.0.3 TERRAGRUNT_VERSION: v0.28.24 - PACKER_VERSION: 1.6.6 + PACKER_VERSION: 1.7.4 GO_VERSION: 1.16.3 GO111MODULE: auto K8S_VERSION: v1.15.0 # Same as EKS diff --git a/examples/packer-basic-example/README.md b/examples/packer-basic-example/README.md index 2f3508206..a105de181 100644 --- a/examples/packer-basic-example/README.md +++ b/examples/packer-basic-example/README.md @@ -14,16 +14,19 @@ Terratest. For slightly more complicated, real-world examples of Packer template - -## Building the Packer template manually - +## Installation steps 1. Sign up for [AWS](https://aws.amazon.com/). 1. Configure your AWS credentials using one of the [supported methods for AWS CLI tools](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html), such as setting the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables. 1. Install [Packer](https://www.packer.io/) and make sure it's on your `PATH`. -1. Run `packer build build.json`. +## Building the Packer template manually (Packer >= 1.7.0) +1. Run `packer init build.pkr.hcl`. # Use build-gcp.pkr.hcl if using GCP +1. Run `packer build build.pkr.hcl`. # Use build-gcp.pkr.hcl if using GCP + +## Building the Packer template manually (Packer < 1.7.0) +1. Run `packer build build.json`. @@ -61,7 +64,7 @@ Terratest. For slightly more complicated, real-world examples of Packer template 1. Sign up for [OCI](https://cloud.oracle.com/cloud-infrastructure). 1. Configure your OCI credentials via [CLI Configuration Information](https://docs.cloud.oracle.com/iaas/Content/API/Concepts/sdkconfig.htm). -1. Create [VCN](https://docs.cloud.oracle.com/iaas/Content/GSG/Tasks/creatingnetwork.htm) and subnet +1. Create [VCN](https://docs.cloud.oracle.com/iaas/Content/GSG/Tasks/creatingnetwork.htm) and subnet resources in your tenancy (a.k.a. a root compartment). 1. (Optional) Create `TF_VAR_pass_phrase` environment property with the pass phrase for decrypting of the OCI [API signing key](https://docs.cloud.oracle.com/iaas/Content/API/Concepts/apisigningkey.htm) (can be omitted diff --git a/examples/packer-basic-example/build-gcp.pkr.hcl b/examples/packer-basic-example/build-gcp.pkr.hcl new file mode 100644 index 000000000..59c462969 --- /dev/null +++ b/examples/packer-basic-example/build-gcp.pkr.hcl @@ -0,0 +1,40 @@ +packer { + required_plugins { + googlecompute = { + version = ">=v1.0.0" + source = "github.com/hashicorp/googlecompute" + } + } +} + +variable "gcp_project_id" { + type = string + default = "" +} + +variable "gcp_zone" { + type = string + default = "us-central1-a" +} + +source "googlecompute" "ubuntu-bionic" { + image_family = "terratest" + image_name = "terratest-packer-example-${formatdate("YYYYMMDD-hhmm", timestamp())}" + project_id = var.gcp_project_id + source_image_family = "ubuntu-1804-lts" + ssh_username = "ubuntu" + zone = var.gcp_zone +} + + +build { + sources = [ + "source.googlecompute.ubuntu-bionic" + ] + + provisioner "shell" { + inline = ["sudo DEBIAN_FRONTEND=noninteractive apt-get update", "sudo DEBIAN_FRONTEND=noninteractive apt-get upgrade -y"] + pause_before = "30s" + } + +} diff --git a/examples/packer-basic-example/build.json b/examples/packer-basic-example/build.json deleted file mode 100644 index 97c5bc8c6..000000000 --- a/examples/packer-basic-example/build.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "min_packer_version": "1.0.4", - "variables": { - "aws_region": "us-east-1", - "ami_base_name": "", - "gcp_project_id": "", - "gcp_zone": "us-central1-a", - "oci_availability_domain": "", - "oci_base_image_ocid": "", - "oci_compartment_ocid": "", - "oci_pass_phrase": "", - "oci_subnet_ocid": "", - "instance_type": "t2.micro" - }, - "builders": [{ - "type": "amazon-ebs", - "ami_name": "{{user `ami_base_name`}}-terratest-packer-example", - "ami_description": "An example of how to create a custom AMI on top of Ubuntu", - "instance_type": "{{user `instance_type`}}", - "region": "{{user `aws_region`}}", - "source_ami_filter": { - "filters": { - "virtualization-type": "hvm", - "architecture": "x86_64", - "name": "*ubuntu-xenial-16.04-amd64-server-*", - "block-device-mapping.volume-type": "gp2", - "root-device-type": "ebs" - }, - "owners": ["099720109477"], - "most_recent": true - }, - "ssh_username": "ubuntu", - "encrypt_boot": false - }, { - "type": "googlecompute", - "image_name": "terratest-packer-example-{{isotime | clean_resource_name}}", - "image_family": "terratest", - "project_id": "{{user `gcp_project_id`}}", - "source_image_family": "ubuntu-1804-lts", - "zone": "{{user `gcp_zone`}}", - "ssh_username": "ubuntu" - }, { - "type": "oracle-oci", - "image_name": "terratest-packer-example-{{isotime}}", - "availability_domain": "{{user `oci_availability_domain`}}", - "base_image_ocid": "{{user `oci_base_image_ocid`}}", - "compartment_ocid": "{{user `oci_compartment_ocid`}}", - "pass_phrase": "{{user `oci_pass_phrase`}}", - "shape": "VM.Standard2.1", - "ssh_username": "ubuntu", - "subnet_ocid": "{{user `oci_subnet_ocid`}}" - }], - "provisioners": [{ - "type": "shell", - "inline": [ - "sudo DEBIAN_FRONTEND=noninteractive apt-get update", - "sudo DEBIAN_FRONTEND=noninteractive apt-get upgrade -y" - ], - "pause_before": "30s" - }] -} diff --git a/examples/packer-basic-example/build.pkr.hcl b/examples/packer-basic-example/build.pkr.hcl new file mode 100644 index 000000000..a38de4b81 --- /dev/null +++ b/examples/packer-basic-example/build.pkr.hcl @@ -0,0 +1,98 @@ +packer { + required_plugins { + amazon = { + version = ">=v1.0.0" + source = "github.com/hashicorp/amazon" + } + oracle = { + version = ">=v1.0.0" + source = "github.com/hashicorp/oracle" + } + } +} + +variable "ami_base_name" { + type = string + default = "" +} + +variable "aws_region" { + type = string + default = "us-east-1" +} + +variable "instance_type" { + type = string + default = "t2.micro" +} + +variable "oci_availability_domain" { + type = string + default = "" +} + +variable "oci_base_image_ocid" { + type = string + default = "" +} + +variable "oci_compartment_ocid" { + type = string + default = "" +} + +variable "oci_pass_phrase" { + type = string + default = "" +} + +variable "oci_subnet_ocid" { + type = string + default = "" +} + +data "amazon-ami" "ubuntu-xenial" { + filters = { + architecture = "x86_64" + "block-device-mapping.volume-type" = "gp2" + name = "*ubuntu-xenial-16.04-amd64-server-*" + root-device-type = "ebs" + virtualization-type = "hvm" + } + most_recent = true + owners = ["099720109477"] + region = var.aws_region +} + +source "amazon-ebs" "ubuntu-example" { + ami_description = "An example of how to create a custom AMI on top of Ubuntu" + ami_name = "${var.ami_base_name}-terratest-packer-example" + encrypt_boot = false + instance_type = var.instance_type + region = var.aws_region + source_ami = data.amazon-ami.ubuntu-xenial.id + ssh_username = "ubuntu" +} + +source "oracle-oci" "oracle-example" { + availability_domain = var.oci_availability_domain + base_image_ocid = var.oci_base_image_ocid + compartment_ocid = var.oci_compartment_ocid + image_name = "terratest-packer-example-${formatdate("YYYYMMDD-hhmm", timestamp())}" + pass_phrase = var.oci_pass_phrase + shape = "VM.Standard2.1" + ssh_username = "ubuntu" + subnet_ocid = var.oci_subnet_ocid +} + +build { + sources = [ + "source.amazon-ebs.ubuntu-example", + "source.oracle-oci.oracle-example" + ] + + provisioner "shell" { + inline = ["sudo DEBIAN_FRONTEND=noninteractive apt-get update", "sudo DEBIAN_FRONTEND=noninteractive apt-get upgrade -y"] + pause_before = "30s" + } +} diff --git a/examples/packer-docker-example/README.md b/examples/packer-docker-example/README.md index 2610c2b62..4bc95d0e0 100644 --- a/examples/packer-docker-example/README.md +++ b/examples/packer-docker-example/README.md @@ -14,13 +14,21 @@ The Docker-based tests in this folder are in some sense "unit tests" for the Pac [terraform-packer-example](/examples/terraform-packer-example). +## Installation steps +1. Install [Packer](https://www.packer.io/) and make sure it's on your `PATH`. +1. Install [Docker](https://www.docker.com/) and make sure it's on your `PATH`. -## Building a Docker image for local testing +## Building a Docker image for local testing (Packer >= 1.7.0) +1. Run `packer init build.pkr.hcl`. +1. Run `packer build build.pkr.hcl`. -1. Install [Packer](https://www.packer.io/) and make sure it's on your `PATH`. -1. Install [Docker](https://www.docker.com/) and make sure it's on your `PATH`. -1. Run `packer build -only=ubuntu-docker build.json`. + +## Building a Docker image for local testing (Packer < 1.7.0) +1. Run `packer build build.json`. + + +## Run the container 1. Run `docker-compose up`. 1. You should now be able to access the sample web app at http://localhost:8080 @@ -53,4 +61,4 @@ The Docker-based tests in this folder are in some sense "unit tests" for the Pac ## Running automated tests in AWS against this Packer template -See [terraform-packer-example](/examples/terraform-packer-example). \ No newline at end of file +See [terraform-packer-example](/examples/terraform-packer-example). diff --git a/examples/packer-docker-example/build.pkr.hcl b/examples/packer-docker-example/build.pkr.hcl new file mode 100644 index 000000000..50e36495b --- /dev/null +++ b/examples/packer-docker-example/build.pkr.hcl @@ -0,0 +1,76 @@ +packer { + required_plugins { + amazon = { + version = ">=v1.0.0" + source = "github.com/hashicorp/amazon" + } + } +} + +variable "ami_name_base" { + type = string + default = "terratest-packer-docker-example" +} + +variable "aws_region" { + type = string + default = "us-east-1" +} + +variable "instance_type" { + type = string + default = "t2.micro" +} + +data "amazon-ami" "aws" { + filters = { + architecture = "x86_64" + "block-device-mapping.volume-type" = "gp2" + name = "*ubuntu-xenial-16.04-amd64-server-*" + root-device-type = "ebs" + virtualization-type = "hvm" + } + most_recent = true + owners = ["099720109477"] + region = var.aws_region +} + +source "amazon-ebs" "ubuntu-ami" { + ami_description = "An example of how to create a custom AMI with a simple web app on top of Ubuntu" + ami_name = "${var.ami_name_base}-${formatdate("YYYYMMDD-hhmm", timestamp())}" + encrypt_boot = false + instance_type = var.instance_type + region = var.aws_region + source_ami = data.amazon-ami.aws.id + ssh_username = "ubuntu" +} + +source "docker" "ubuntu-docker" { + changes = ["ENTRYPOINT [\"\"]"] + commit = true + image = "gruntwork/ubuntu-test:16.04" +} + +build { + sources = ["source.amazon-ebs.ubuntu-ami", "source.docker.ubuntu-docker"] + + provisioner "shell" { + inline = ["echo 'Sleeping for a few seconds to give Ubuntu time to boot up'", "sleep 30"] + only = ["amazon-ebs.ubuntu-ami"] + } + + provisioner "file" { + destination = "/tmp/packer-docker-example" + source = path.root + } + + provisioner "shell" { + inline = ["/tmp/packer-docker-example/configure-sinatra-app.sh"] + } + + post-processor "docker-tag" { + only = ["docker.ubuntu-docker"] + repository = "gruntwork/packer-docker-example" + tag = ["latest"] + } +} diff --git a/examples/packer-docker-example/docker-compose.yml b/examples/packer-docker-example/docker-compose.yml index 4d2244027..5ea8e5f83 100644 --- a/examples/packer-docker-example/docker-compose.yml +++ b/examples/packer-docker-example/docker-compose.yml @@ -4,7 +4,7 @@ version: '3' services: web_app: - # The name we use for the Docker image in build.json + # The name we use for the Docker image in build.json (or build.pkr.hcl) image: gruntwork/packer-docker-example # Run the sample web app on port 8080 diff --git a/examples/packer-hello-world-example/README.md b/examples/packer-hello-world-example/README.md index be4afc2ff..313f6212e 100644 --- a/examples/packer-hello-world-example/README.md +++ b/examples/packer-hello-world-example/README.md @@ -1,23 +1,29 @@ # Packer "Hello, World" Example This folder contains the simplest possible Packer template—one that builds a Docker image with a text file that says -"Hello, World"!—to demonstrate how you can use Terratest to write automated tests for your Packer templates. +"Hello, World"!—to demonstrate how you can use Terratest to write automated tests for your Packer templates. Check out [test/packer_hello_world_example_test.go](/test/packer_hello_world_example_test.go) to see how you can write automated tests for this simple template. +## Installation steps +1. Install [Packer](https://www.packer.io/) and make sure it's on your `PATH`. +1. Install [Docker](https://www.docker.com/) and make sure it's on your `PATH`. -## Building the Packer template +## Building the Packer template (Packer >= 1.7.0) +1. Run `packer init build.pkr.hcl`. +1. Run `packer build build.pkr.hcl`. -1. Install [Packer](https://www.packer.io/) and make sure it's on your `PATH`. -1. Install [Docker](https://www.docker.com/) and make sure it's on your `PATH`. + +## Building the Packer template (Packer < 1.7.0) 1. Run `packer build build.json`. -1. Run `docker run -it --rm gruntwork/packer-hello-world-example cat /test.txt`. -1. You should see the text "Hello, World!" +## Run Docker +1. Run `docker run -it --rm gruntwork/packer-hello-world-example cat /test.txt`. +1. You should see the text "Hello, World!" ## Running automated tests against the Packer template diff --git a/examples/packer-hello-world-example/build.json b/examples/packer-hello-world-example/build.json deleted file mode 100644 index 4947b931a..000000000 --- a/examples/packer-hello-world-example/build.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "builders": [{ - "name": "ubuntu-docker", - "type": "docker", - "image": "gruntwork/ubuntu-test:16.04", - "commit": true, - "changes": ["ENTRYPOINT [\"\"]"] - }], - "provisioners": [{ - "type": "shell", - "inline": ["echo 'Hello, World!' > /test.txt"] - }], - "post-processors": [{ - "type": "docker-tag", - "repository": "gruntwork/packer-hello-world-example", - "tag": "latest" - }] -} diff --git a/examples/packer-hello-world-example/build.pkr.hcl b/examples/packer-hello-world-example/build.pkr.hcl new file mode 100644 index 000000000..96c6832a8 --- /dev/null +++ b/examples/packer-hello-world-example/build.pkr.hcl @@ -0,0 +1,27 @@ +packer { + required_plugins { + docker = { + version = ">=v1.0.1" + source = "github.com/hashicorp/docker" + } + } +} + +source "docker" "ubuntu-docker" { + changes = ["ENTRYPOINT [\"\"]"] + commit = true + image = "gruntwork/ubuntu-test:16.04" +} + +build { + sources = ["source.docker.ubuntu-docker"] + + provisioner "shell" { + inline = ["echo 'Hello, World!' > /test.txt"] + } + + post-processor "docker-tag" { + repository = "gruntwork/packer-hello-world-example" + tag = ["latest"] + } +} diff --git a/examples/terraform-packer-example/user-data/user-data.sh b/examples/terraform-packer-example/user-data/user-data.sh index da1699ec1..e197deacc 100644 --- a/examples/terraform-packer-example/user-data/user-data.sh +++ b/examples/terraform-packer-example/user-data/user-data.sh @@ -1,7 +1,7 @@ #!/bin/bash # This script is meant to be run in the User Data of an EC2 Instance while it's booting. It starts a Ruby web app. -# This script assumes it is running in an AMI built from the Packer template -# in examples/packer-docker-example/build.json. +# This script assumes it is running in an AMI built from the Packer templates in examples/packer-docker-example +# (either build.json or build.pkr.hcl). set -e diff --git a/examples/terraform-packer-example/variables.tf b/examples/terraform-packer-example/variables.tf index cb1f3b96e..ee7133857 100644 --- a/examples/terraform-packer-example/variables.tf +++ b/examples/terraform-packer-example/variables.tf @@ -12,7 +12,7 @@ # --------------------------------------------------------------------------------------------------------------------- variable "ami_id" { - description = "The ID of the AMI to run on each EC2 Instance. Should be an AMI built from the Packer template in examples/packer-docker-example/build.json." + description = "The ID of the AMI to run on each EC2 Instance. Should be an AMI built from the Packer templates in examples/packer-docker-example (build.json or build.pkr.hcl)." type = string } diff --git a/go.mod b/go.mod index 731224d57..4a9052483 100644 --- a/go.mod +++ b/go.mod @@ -22,13 +22,14 @@ require ( github.com/google/uuid v1.1.1 github.com/gruntwork-io/go-commons v0.8.0 github.com/hashicorp/go-multierror v1.1.0 + github.com/hashicorp/go-version v1.3.0 github.com/hashicorp/hcl/v2 v2.8.2 github.com/hashicorp/terraform-json v0.12.0 github.com/imdario/mergo v0.3.7 // indirect github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a github.com/jstemmer/go-junit-report v0.9.1 github.com/magiconair/properties v1.8.0 - github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 // indirect + github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 github.com/miekg/dns v1.1.31 github.com/mitchellh/go-homedir v1.1.0 github.com/oracle/oci-go-sdk v7.1.0+incompatible diff --git a/go.sum b/go.sum index 43ca0c598..f7982af01 100644 --- a/go.sum +++ b/go.sum @@ -258,6 +258,8 @@ github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/U github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-version v1.3.0 h1:McDWVJIU/y+u1BRV06dPaLfLCaT7fUTJLp5r04x7iNw= +github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= diff --git a/modules/aws/s3_test.go b/modules/aws/s3_test.go index 2d4ad117a..947fd4b80 100644 --- a/modules/aws/s3_test.go +++ b/modules/aws/s3_test.go @@ -147,7 +147,7 @@ func TestAssertS3BucketPolicyExists(t *testing.T) { } func testEmptyBucket(t *testing.T, s3Client *s3.S3, region string, s3BucketName string) { - expectedFileCount := rand.Intn(10000) + expectedFileCount := rand.Intn(1000) logger.Logf(t, "Uploading %s files to bucket %s", strconv.Itoa(expectedFileCount), s3BucketName) deleted := 0 diff --git a/modules/packer/packer.go b/modules/packer/packer.go index 879878d8d..dd1f418ce 100644 --- a/modules/packer/packer.go +++ b/modules/packer/packer.go @@ -4,31 +4,36 @@ package packer import ( "errors" "fmt" + "io/ioutil" + "os" "regexp" "sync" "time" "github.com/gruntwork-io/terratest/modules/retry" "github.com/hashicorp/go-multierror" + "github.com/stretchr/testify/require" "github.com/gruntwork-io/terratest/modules/logger" "github.com/gruntwork-io/terratest/modules/shell" "github.com/gruntwork-io/terratest/modules/testing" + "github.com/hashicorp/go-version" ) // Options are the options for Packer. type Options struct { - Template string // The path to the Packer template - Vars map[string]string // The custom vars to pass when running the build command - VarFiles []string // Var file paths to pass Packer using -var-file option - Only string // If specified, only run the build of this name - Except string // Runs the build excluding the specified builds and post-processors - Env map[string]string // Custom environment variables to set when running Packer - RetryableErrors map[string]string // If packer build fails with one of these (transient) errors, retry. The keys are a regexp to match against the error and the message is what to display to a user if that error is matched. - MaxRetries int // Maximum number of times to retry errors matching RetryableErrors - TimeBetweenRetries time.Duration // The amount of time to wait between retries - WorkingDir string // The directory to run packer in - Logger *logger.Logger // If set, use a non-default logger + Template string // The path to the Packer template + Vars map[string]string // The custom vars to pass when running the build command + VarFiles []string // Var file paths to pass Packer using -var-file option + Only string // If specified, only run the build of this name + Except string // Runs the build excluding the specified builds and post-processors + Env map[string]string // Custom environment variables to set when running Packer + RetryableErrors map[string]string // If packer build fails with one of these (transient) errors, retry. The keys are a regexp to match against the error and the message is what to display to a user if that error is matched. + MaxRetries int // Maximum number of times to retry errors matching RetryableErrors + TimeBetweenRetries time.Duration // The amount of time to wait between retries + WorkingDir string // The directory to run packer in + Logger *logger.Logger // If set, use a non-default logger + DisableTemporaryPluginPath bool // If set, do not use a temporary directory for Packer plugins. } // BuildArtifacts can take a map of identifierName <-> Options and then parallelize @@ -92,6 +97,28 @@ func BuildArtifact(t testing.TestingT, options *Options) string { func BuildArtifactE(t testing.TestingT, options *Options) (string, error) { options.Logger.Logf(t, "Running Packer to generate a custom artifact for template %s", options.Template) + // By default, we download packer plugins to a temporary directory rather than use the global plugin path. + // This prevents race conditions when multiple tests are running in parallel and each of them attempt + // to download the same plugin at the same time to the global path. + // Set DisableTemporaryPluginPath to disable this behavior. + if !options.DisableTemporaryPluginPath { + // The built-in env variable defining where plugins are downloaded + const packerPluginPathEnvVar = "PACKER_PLUGIN_PATH" + options.Logger.Logf(t, "Creating a temporary directory for Packer plugins") + pluginDir, err := ioutil.TempDir("", "terratest-packer-") + require.NoError(t, err) + if len(options.Env) == 0 { + options.Env = make(map[string]string) + } + options.Env[packerPluginPathEnvVar] = pluginDir + defer os.RemoveAll(pluginDir) + } + + err := packerInit(t, options) + if err != nil { + return "", err + } + cmd := shell.Command{ Command: "packer", Args: formatPackerArgs(options), @@ -145,6 +172,67 @@ func extractArtifactID(packerLogOutput string) (string, error) { return "", errors.New("Could not find Artifact ID pattern in Packer output") } +// Check if the local version of Packer has init +func hasPackerInit(t testing.TestingT, options *Options) (bool, error) { + // The init command was introduced in Packer 1.7.0 + const packerInitVersion = "1.7.0" + minInitVersion, err := version.NewVersion(packerInitVersion) + if err != nil { + return false, err + } + + cmd := shell.Command{ + Command: "packer", + Args: []string{"-version"}, + Env: options.Env, + WorkingDir: options.WorkingDir, + } + localVersion, err := shell.RunCommandAndGetOutputE(t, cmd) + if err != nil { + return false, err + } + thisVersion, err := version.NewVersion(localVersion) + if err != nil { + return false, err + } + + if thisVersion.LessThan(minInitVersion) { + return false, nil + } + + return true, nil +} + +// packerInit runs 'packer init' if it is supported by the local packer +func packerInit(t testing.TestingT, options *Options) error { + hasInit, err := hasPackerInit(t, options) + if err != nil { + return err + } + if !hasInit { + options.Logger.Logf(t, "Skipping 'packer init' because it is not present in this version") + return nil + } + + cmd := shell.Command{ + Command: "packer", + Args: []string{"init", options.Template}, + Env: options.Env, + WorkingDir: options.WorkingDir, + } + + description := "Running Packer init" + _, err = retry.DoWithRetryableErrorsE(t, description, options.RetryableErrors, options.MaxRetries, options.TimeBetweenRetries, func() (string, error) { + return shell.RunCommandAndGetOutputE(t, cmd) + }) + + if err != nil { + return err + } + + return nil +} + // Convert the inputs to a format palatable to packer. The build command should have the format: // // packer build [OPTIONS] template diff --git a/test/gcp/packer_gcp_basic_example_test.go b/test/gcp/packer_gcp_basic_example_test.go index 99c6729a1..bfc3b35b2 100644 --- a/test/gcp/packer_gcp_basic_example_test.go +++ b/test/gcp/packer_gcp_basic_example_test.go @@ -36,7 +36,7 @@ func TestPackerGCPBasicExample(t *testing.T) { packerOptions := &packer.Options{ // The path to where the Packer template is located - Template: "../../examples/packer-basic-example/build.json", + Template: "../../examples/packer-basic-example/build-gcp.pkr.hcl", // Variables to pass to our Packer build using -var options Vars: map[string]string{ @@ -45,7 +45,7 @@ func TestPackerGCPBasicExample(t *testing.T) { }, // Only build the Google Compute Image - Only: "googlecompute", + Only: "googlecompute.ubuntu-bionic", // Configure retries for intermittent errors RetryableErrors: DefaultRetryablePackerErrors, diff --git a/test/packer_basic_example_test.go b/test/packer_basic_example_test.go index 418177e7a..37558ed9c 100644 --- a/test/packer_basic_example_test.go +++ b/test/packer_basic_example_test.go @@ -40,7 +40,7 @@ func TestPackerBasicExample(t *testing.T) { // website::tag::1::Read Packer's template and set AWS Region variable. packerOptions := &packer.Options{ // The path to where the Packer template is located - Template: "../examples/packer-basic-example/build.json", + Template: "../examples/packer-basic-example/build.pkr.hcl", // Variables to pass to our Packer build using -var options Vars: map[string]string{ @@ -50,7 +50,7 @@ func TestPackerBasicExample(t *testing.T) { }, // Only build the AWS AMI - Only: "amazon-ebs", + Only: "amazon-ebs.ubuntu-example", // Configure retries for intermittent errors RetryableErrors: DefaultRetryablePackerErrors, @@ -108,15 +108,20 @@ func TestPackerBasicExampleWithVarFile(t *testing.T) { packerOptions := &packer.Options{ // The path to where the Packer template is located - Template: "../examples/packer-basic-example/build.json", + Template: "../examples/packer-basic-example/build.pkr.hcl", // Variable file to to pass to our Packer build using -var-file option VarFiles: []string{ varFile.Name(), }, + // Environment settings to avoid plugin conflicts + Env: map[string]string{ + "PACKER_PLUGIN_PATH": "../examples/packer-basic-example/.packer.d/plugins", + }, + // Only build the AWS AMI - Only: "amazon-ebs", + Only: "amazon-ebs.ubuntu-example", // Configure retries for intermittent errors RetryableErrors: DefaultRetryablePackerErrors, @@ -161,7 +166,7 @@ func TestPackerMultipleConcurrentAmis(t *testing.T) { packerOptions := &packer.Options{ // The path to where the Packer template is located - Template: "../examples/packer-basic-example/build.json", + Template: "../examples/packer-basic-example/build.pkr.hcl", // Variables to pass to our Packer build using -var options Vars: map[string]string{ @@ -171,7 +176,7 @@ func TestPackerMultipleConcurrentAmis(t *testing.T) { }, // Only build the AWS AMI - Only: "amazon-ebs", + Only: "amazon-ebs.ubuntu-example", // Configure retries for intermittent errors RetryableErrors: DefaultRetryablePackerErrors, diff --git a/test/packer_docker_example_test.go b/test/packer_docker_example_test.go index 34a547ab3..f038d753a 100644 --- a/test/packer_docker_example_test.go +++ b/test/packer_docker_example_test.go @@ -21,10 +21,10 @@ func TestPackerDockerExampleLocal(t *testing.T) { // website::tag::1::Configure Packer to build Docker image. packerOptions := &packer.Options{ // The path to where the Packer template is located - Template: "../examples/packer-docker-example/build.json", + Template: "../examples/packer-docker-example/build.pkr.hcl", // Only build the Docker image for local testing - Only: "ubuntu-docker", + Only: "docker.ubuntu-docker", // Configure retries for intermittent errors RetryableErrors: DefaultRetryablePackerErrors, diff --git a/test/packer_hello_world_example_test.go b/test/packer_hello_world_example_test.go index 56aacafc7..515050861 100644 --- a/test/packer_hello_world_example_test.go +++ b/test/packer_hello_world_example_test.go @@ -11,7 +11,7 @@ import ( func TestPackerHelloWorldExample(t *testing.T) { packerOptions := &packer.Options{ // website::tag::1:: The path to where the Packer template is located - Template: "../examples/packer-hello-world-example/build.json", + Template: "../examples/packer-hello-world-example/build.pkr.hcl", } // website::tag::2:: Build the Packer template. This template will create a Docker image. diff --git a/test/packer_oci_example_test.go b/test/packer_oci_example_test.go index 46ab46c1b..801dfcb8a 100644 --- a/test/packer_oci_example_test.go +++ b/test/packer_oci_example_test.go @@ -26,7 +26,7 @@ func TestPackerOciExample(t *testing.T) { packerOptions := &packer.Options{ // The path to where the Packer template is located - Template: "../examples/packer-basic-example/build.json", + Template: "../examples/packer-basic-example/build.pkr.hcl", // Variables to pass to our Packer build using -var options Vars: map[string]string{ diff --git a/test/terraform_packer_example_test.go b/test/terraform_packer_example_test.go index ec82247db..74bea07a7 100644 --- a/test/terraform_packer_example_test.go +++ b/test/terraform_packer_example_test.go @@ -71,10 +71,10 @@ func buildAMI(t *testing.T, awsRegion string, workingDir string) { packerOptions := &packer.Options{ // The path to where the Packer template is located - Template: "../examples/packer-docker-example/build.json", + Template: "../examples/packer-docker-example/build.pkr.hcl", // Only build the AMI - Only: "ubuntu-ami", + Only: "amazon-ebs.ubuntu-ami", // Variables to pass to our Packer build using -var options Vars: map[string]string{ @@ -92,7 +92,7 @@ func buildAMI(t *testing.T, awsRegion string, workingDir string) { test_structure.SavePackerOptions(t, workingDir, packerOptions) // Build the AMI - amiID := packer.BuildAmi(t, packerOptions) + amiID := packer.BuildArtifact(t, packerOptions) // Save the AMI ID so future test stages can use them test_structure.SaveAmiId(t, workingDir, amiID)