diff --git a/.circleci/config.yml b/.circleci/config.yml index 3e352f023..a424fc681 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,7 +5,7 @@ env: &env MODULE_GCP_CI_VERSION: v0.1.1 MODULE_CI_CIRCLECI_HELPER_VERSION: v0.56.0 TERRAFORM_VERSION: 1.5.7 - PACKER_VERSION: 1.7.4 + PACKER_VERSION: 1.10.0 TERRAGRUNT_VERSION: v0.52.0 OPA_VERSION: v0.33.1 GO_VERSION: 1.21.1 diff --git a/examples/packer-docker-example/build.pkr.hcl b/examples/packer-docker-example/build.pkr.hcl index afedc3279..f55003731 100644 --- a/examples/packer-docker-example/build.pkr.hcl +++ b/examples/packer-docker-example/build.pkr.hcl @@ -4,6 +4,10 @@ packer { version = ">=v1.0.0" source = "github.com/hashicorp/amazon" } + docker = { + version = ">=v1.0.1" + source = "github.com/hashicorp/docker" + } } } diff --git a/examples/packer-docker-example/configure-sinatra-app.sh b/examples/packer-docker-example/configure-sinatra-app.sh index 0e954665d..683ba806c 100755 --- a/examples/packer-docker-example/configure-sinatra-app.sh +++ b/examples/packer-docker-example/configure-sinatra-app.sh @@ -11,7 +11,7 @@ sudo apt-get update sudo apt-get install -y make zlib1g-dev build-essential ruby ruby-dev echo "Installing Sinatra" -sudo gem install sinatra json +sudo gem install sinatra json rackup echo "Moving $APP_RB_SRC to $APP_RB_DST" mkdir -p "$(dirname "$APP_RB_DST")" diff --git a/examples/terraform-aws-lambda-example/main.tf b/examples/terraform-aws-lambda-example/main.tf index 702d16b81..ff3489a7d 100644 --- a/examples/terraform-aws-lambda-example/main.tf +++ b/examples/terraform-aws-lambda-example/main.tf @@ -28,8 +28,8 @@ resource "aws_lambda_function" "lambda" { source_code_hash = data.archive_file.zip.output_base64sha256 function_name = var.function_name role = aws_iam_role.lambda.arn - handler = "lambda" - runtime = "go1.x" + handler = "bootstrap" + runtime = "provided.al2023" } resource "aws_iam_role" "lambda" { diff --git a/examples/terraform-aws-lambda-example/src/README.md b/examples/terraform-aws-lambda-example/src/README.md index 4add532d5..520d38e56 100644 --- a/examples/terraform-aws-lambda-example/src/README.md +++ b/examples/terraform-aws-lambda-example/src/README.md @@ -3,5 +3,5 @@ The lambda executable `handler` was built using ``` shell -go build lambda.go +go build bootstrap.go ``` diff --git a/examples/terraform-aws-lambda-example/src/bootstrap b/examples/terraform-aws-lambda-example/src/bootstrap new file mode 100755 index 000000000..a3165435f Binary files /dev/null and b/examples/terraform-aws-lambda-example/src/bootstrap differ diff --git a/examples/terraform-aws-lambda-example/src/lambda.go b/examples/terraform-aws-lambda-example/src/bootstrap.go similarity index 73% rename from examples/terraform-aws-lambda-example/src/lambda.go rename to examples/terraform-aws-lambda-example/src/bootstrap.go index 5ee99337e..fa4029f69 100644 --- a/examples/terraform-aws-lambda-example/src/lambda.go +++ b/examples/terraform-aws-lambda-example/src/bootstrap.go @@ -13,7 +13,10 @@ type Event struct { } // Fails if ShouldFail is `true`, otherwise echos the input. -func HandleRequest(ctx context.Context, evnt Event) (string, error) { +func HandleRequest(ctx context.Context, evnt *Event) (string, error) { + if evnt == nil { + return "", fmt.Errorf("received nil event") + } if evnt.ShouldFail { return "", fmt.Errorf("Failed to handle %#v", evnt) } diff --git a/examples/terraform-aws-lambda-example/src/lambda b/examples/terraform-aws-lambda-example/src/lambda deleted file mode 100755 index 119d14496..000000000 Binary files a/examples/terraform-aws-lambda-example/src/lambda and /dev/null differ diff --git a/examples/terraform-ssh-password-example/user_data.sh b/examples/terraform-ssh-password-example/user_data.sh index dde876b26..c50045594 100644 --- a/examples/terraform-ssh-password-example/user_data.sh +++ b/examples/terraform-ssh-password-example/user_data.sh @@ -13,7 +13,7 @@ adduser --disabled-password --gecos "" terratest echo "terratest:${terratest_password}" | chpasswd # Enable password auth on the SSH service -sed -i 's/^PasswordAuthentication no$/PasswordAuthentication yes/g' /etc/ssh/sshd_config +echo "PasswordAuthentication yes" > /etc/ssh/sshd_config.d/01-password-auth.conf # Bounce the service to apply the config change service ssh restart diff --git a/modules/aws/rds_test.go b/modules/aws/rds_test.go index f9b92ca17..0800da7bf 100644 --- a/modules/aws/rds_test.go +++ b/modules/aws/rds_test.go @@ -23,8 +23,8 @@ func TestGetRecommendedRdsInstanceTypeHappyPath(t *testing.T) { region: "us-east-2", databaseEngine: "mysql", engineMajorVersion: "8.0", - instanceTypes: []string{"db.t2.micro", "db.t3.micro", "db.t3.small"}, - expected: "db.t2.micro", + instanceTypes: []string{"db.t4g.micro", "db.t4g.small"}, + expected: "db.t4g.micro", }, { name: "EU region, postgres, 2nd offering available based on region", @@ -121,7 +121,7 @@ func TestGetRecommendedRdsInstanceTypeErrors(t *testing.T) { name: "No instance type available for engine", region: "us-east-1", databaseEngine: "oracle-ee", - databaseEngineVersion: "19.0.0.0.ru-2021-01.rur-2021-01.r1", + databaseEngineVersion: "19.0.0.0.ru-2024-04.rur-2024-04.r1", instanceTypes: []string{"db.r5a.large"}, }, { diff --git a/modules/helm/template.go b/modules/helm/template.go index 0cebe0bb1..9ed474938 100644 --- a/modules/helm/template.go +++ b/modules/helm/template.go @@ -77,7 +77,7 @@ func RenderTemplateE(t testing.TestingT, options *Options, chartDir string, rele return RunHelmCommandAndGetStdOutE(t, options, "template", args...) } -// RenderTemplate runs `helm template` to render a *remote* chart given the provided options and returns stdout/stderr from +// RenderRemoteTemplate runs `helm template` to render a *remote* chart given the provided options and returns stdout/stderr from // the template command. If you pass in templateFiles, this will only render those templates. This function will fail // the test if there is an error rendering the template. func RenderRemoteTemplate(t testing.TestingT, options *Options, chartURL string, releaseName string, templateFiles []string, extraHelmArgs ...string) string { @@ -86,7 +86,7 @@ func RenderRemoteTemplate(t testing.TestingT, options *Options, chartURL string, return out } -// RenderTemplate runs `helm template` to render a *remote* helm chart given the provided options and returns stdout/stderr from +// RenderRemoteTemplateE runs `helm template` to render a *remote* helm chart given the provided options and returns stdout/stderr from // the template command. If you pass in templateFiles, this will only render those templates. func RenderRemoteTemplateE(t testing.TestingT, options *Options, chartURL string, releaseName string, templateFiles []string, extraHelmArgs ...string) (string, error) { // Now construct the args diff --git a/modules/helm/template_test.go b/modules/helm/template_test.go index 8de17575d..97ed8478e 100644 --- a/modules/helm/template_test.go +++ b/modules/helm/template_test.go @@ -71,11 +71,33 @@ func TestRemoteChartRender(t *testing.T) { // Test that we can dump all the manifest locally a remote chart (e.g bitnami/nginx) // so that I can use them later to compare between two versions of the same chart for example func TestRemoteChartRenderDump(t *testing.T) { + t.Parallel() + renderChartDump(t, "13.2.20", t.TempDir()) +} + +// Test that we can diff all the manifest to a local snapshot using a remote chart (e.g bitnami/nginx) +func TestRemoteChartRenderDiff(t *testing.T) { + t.Parallel() + + initialSnapshot := t.TempDir() + updatedSnapshot := t.TempDir() + renderChartDump(t, "5.0.0", initialSnapshot) + output := renderChartDump(t, "5.1.0", updatedSnapshot) + + options := &Options{ + Logger: logger.Default, + SnapshotPath: initialSnapshot, + } + // diff in: spec.initContainers.preserve-logs-symlinks.imag, spec.containers.nginx.image, tls certificates + require.Equal(t, 5, DiffAgainstSnapshot(t, options, output, "nginx")) +} + +// render chart dump and return the rendered output +func renderChartDump(t *testing.T, remoteChartVersion, snapshotDir string) string { const ( - remoteChartSource = "https://charts.bitnami.com/bitnami" - remoteChartName = "nginx" - remoteChartVersion = "13.2.20" - // need to set a fix name for the namespace so it is not flag as a difference + remoteChartSource = "https://charts.bitnami.com/bitnami" + remoteChartName = "nginx" + // need to set a fix name for the namespace, so it is not flag as a difference namespaceName = "dump-ns" ) @@ -106,42 +128,8 @@ func TestRemoteChartRenderDump(t *testing.T) { // write chart manifest to a local filesystem directory options = &Options{ Logger: logger.Default, - SnapshotPath: "__chart_manifests_snapshot__", + SnapshotPath: snapshotDir, } UpdateSnapshot(t, options, output, releaseName) -} - -// Test that we can diff all the manifest to a local snapshot using a remote chart (e.g bitnami/nginx) -func TestRemoteChartRenderDiff(t *testing.T) { - const ( - remoteChartSource = "https://charts.bitnami.com/bitnami" - remoteChartName = "nginx" - remoteChartVersion = "13.2.24" - // need to set a fix name for the namespace so it is not flag as a difference - namespaceName = "dump-ns" - ) - - releaseName := remoteChartName - options := &Options{ - SetValues: map[string]string{ - "image.repository": remoteChartName, - "image.registry": "", - "image.tag": remoteChartVersion, - }, - KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), - Logger: logger.Discard, - SnapshotPath: "__chart_manifests_snapshot__", - } - - // Run RenderTemplate to render the template and capture the output. Note that we use the version without `E`, since - // we want to assert that the template renders without any errors. - output := RenderRemoteTemplate(t, options, remoteChartSource, releaseName, []string{}) - - // Now we use kubernetes/client-go library to render the template output into the Deployment struct. This will - // ensure the Deployment resource is rendered correctly. - var deployment appsv1.Deployment - UnmarshalK8SYaml(t, output, &deployment) - - // run the diff and assert there is only one difference: the image name - require.Equal(t, 1, DiffAgainstSnapshot(t, options, output, releaseName)) + return output } diff --git a/modules/packer/packer.go b/modules/packer/packer.go index 4045c0f99..45aeefbdc 100644 --- a/modules/packer/packer.go +++ b/modules/packer/packer.go @@ -186,10 +186,11 @@ func hasPackerInit(t testing.TestingT, options *Options) (bool, error) { Env: options.Env, WorkingDir: options.WorkingDir, } - localVersion, err := shell.RunCommandAndGetOutputE(t, cmd) + versionCmdOutput, err := shell.RunCommandAndGetOutputE(t, cmd) if err != nil { return false, err } + localVersion := trimPackerVersion(versionCmdOutput) thisVersion, err := version.NewVersion(localVersion) if err != nil { return false, err @@ -262,3 +263,13 @@ func formatPackerArgs(options *Options) []string { return append(args, options.Template) } + +// From packer 1.10 the -version command output is prefixed with Packer v +func trimPackerVersion(versionCmdOutput string) string { + re := regexp.MustCompile(`(?:Packer v?|)(\d+\.\d+\.\d+)`) + matches := re.FindStringSubmatch(versionCmdOutput) + if len(matches) > 1 { + return matches[1] + } + return "" +} diff --git a/modules/packer/packer_test.go b/modules/packer/packer_test.go index 3c76cb922..24a1f1276 100644 --- a/modules/packer/packer_test.go +++ b/modules/packer/packer_test.go @@ -174,3 +174,35 @@ func TestFormatPackerArgs(t *testing.T) { assert.Equal(t, strings.Join(args, " "), test.expected) } } + +func TestTrimPackerVersion(t *testing.T) { + t.Parallel() + + tests := []struct { + versionOutput string + expected string + }{ + { + // Pre 1.10 output + versionOutput: "1.7.0", + expected: "1.7.0", + }, + { + // From 1.10 matches the output of packer version + versionOutput: "Packer v1.10.0", + expected: "1.10.0", + }, + { + // From 1.10 matches the output of packer version + versionOutput: "Packer v1.10.0\n\nYour version of Packer is out of date! The latest version\nis 1.10.3. You can update by downloading from www.packer.io/downloads\n", + expected: "1.10.0", + }, + } + + for _, test := range tests { + t.Run(test.versionOutput, func(t *testing.T) { + out := trimPackerVersion(test.versionOutput) + assert.Equal(t, test.expected, out) + }) + } +} diff --git a/test/terraform_aws_lambda_example_test.go b/test/terraform_aws_lambda_example_test.go index 036f59748..94ceb40ce 100644 --- a/test/terraform_aws_lambda_example_test.go +++ b/test/terraform_aws_lambda_example_test.go @@ -63,7 +63,7 @@ func TestTerraformAwsLambdaExample(t *testing.T) { assert.Contains(t, string(functionError.Payload), "Failed to handle") } -// Annother example of how to test the Terraform module in +// Another example of how to test the Terraform module in // examples/terraform-aws-lambda-example using Terratest, this time with // the aws.InvokeFunctionWithParams. func TestTerraformAwsLambdaWithParamsExample(t *testing.T) {