From 961c1d704621f33d76cee40351fd28a09629f7cb Mon Sep 17 00:00:00 2001 From: Jenna Goldstrich Date: Thu, 26 May 2022 08:51:38 -0700 Subject: [PATCH] Migrate to internal Registry tests (#11806) * Implement HPATS in Nightly build, delete registry par test * Update .github/workflows/acceptance-test.yml * add workflow-dispatch --- .github/workflows/acceptance-test.yml | 41 ++- internal/registry/acctest/par.go | 310 ------------------ internal/registry/acctest/par_test.go | 186 ----------- .../acctest/test-fixtures/build.pkr.hcl | 27 -- .../registry/acctest/test-fixtures/ds.pkr.hcl | 29 -- 5 files changed, 32 insertions(+), 561 deletions(-) delete mode 100644 internal/registry/acctest/par.go delete mode 100644 internal/registry/acctest/par_test.go delete mode 100644 internal/registry/acctest/test-fixtures/build.pkr.hcl delete mode 100644 internal/registry/acctest/test-fixtures/ds.pkr.hcl diff --git a/.github/workflows/acceptance-test.yml b/.github/workflows/acceptance-test.yml index d9ce978b1..03793475d 100644 --- a/.github/workflows/acceptance-test.yml +++ b/.github/workflows/acceptance-test.yml @@ -9,6 +9,7 @@ on: schedule: # Runs against the default branch every day at midnight - cron: "0 0 * * *" + workflow-dispatch: jobs: get-go-version: @@ -26,7 +27,7 @@ jobs: echo "::set-output name=go-version::$(cat .go-version)" acceptance-test: runs-on: ubuntu-latest - name: Acceptance Test + name: Packer Acceptance Test needs: get-go-version env: # AWS Creds for Assume Role @@ -34,11 +35,6 @@ jobs: AWS_ACCESS_KEY_ID: ${{ secrets.TESTACC_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.TESTACC_AWS_SECRET_ACCESS_KEY }} AWS_REGION: ${{ secrets.TESTACC_AWS_REGION }} - # HCP Creds for Acceptance Tests - HCP_CLIENT_ID: ${{ secrets.HCP_CLIENT_ID }} - HCP_CLIENT_SECRET: ${{ secrets.HCP_CLIENT_SECRET }} - HCP_ORG_ID: ${{ secrets.HCP_ORG_ID }} - HCP_PROJECT_ID: ${{ secrets.HCP_PROJECT_ID }} steps: - uses: actions/checkout@v2 - uses: actions/setup-go@v2 @@ -58,13 +54,40 @@ jobs: run: | mkdir -p /tmp/test-results make dev - PACKER_ACC=1 gotestsum --format=short-verbose --junitfile /tmp/test-results/gotestsum-report.xml -- -timeout=120m -p 2 $(go list ./... | grep -v inspec | grep -v profitbricks | grep -v oneandone) - # Send a slack notification if either job defined above fails + PACKER_ACC=1 gotestsum --format=short-verbose --junitfile /tmp/test-results/gotestsum-report.xml -- -timeout=120m -p 2 $(go list ./... | grep -v inspec | grep -v profitbricks | grep -v oneandone) + hpats: + runs-on: ubuntu-latest + name: HCP Packer Acceptance Test (HPATS) + needs: get-go-version + env: + # Set HCP credentials + HCP_CLIENT_ID: ${{ secrets.HCP_CLIENT_ID }} + HCP_CLIENT_SECRET: ${{ secrets.HCP_CLIENT_SECRET }} + AUTH0_CLIENT_ID: ${{ secrets.HCP_CLIENT_ID }} + AUTH0_CLIENT_SECRET: ${{ secrets.HCP_CLIENT_SECRET }} + AUTH0_HOST: ${{ secrets.AUTH0_HOST }} + HCP_ORG_ID: ${{ secrets.HCP_ORG_ID }} + HCP_PROJECT_ID: ${{ secrets.HCP_PROJECT_ID }} + HCP_API_HOST: ${{ secrets.HCP_API_HOST }} + HPATS_API_URL: https://${{ secrets.HCP_API_HOST }} + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-go@v2 + with: + go-version: ${{ needs.get-go-version.outputs.go-version }} + - name: Clone HPATS + run: git clone git@github.com:hashicorp/hcp-packer-acceptance-tests.github && cd hcp-packer-acceptance-tests + - name: Set HCP Access Token + run: export HCP_ACCESS_TOKEN=$(make hcp/get-auth0-m2m-access-token) + - name: Run HPATS + run: make test + # Send a slack notification if one of the jobs defined above fails slack-notify: needs: - get-go-version - acceptance-test - if: always() && (needs.get-go-version.result == 'failure' || needs.acceptance-test.result == 'failure') + - hpats + if: always() && (needs.get-go-version.result == 'failure' || needs.acceptance-test.result == 'failure' || needs.hpats.result == 'failure') runs-on: ubuntu-latest steps: - name: Send slack notification on failure diff --git a/internal/registry/acctest/par.go b/internal/registry/acctest/par.go deleted file mode 100644 index 76572ad33..000000000 --- a/internal/registry/acctest/par.go +++ /dev/null @@ -1,310 +0,0 @@ -package acctest - -import ( - "context" - "fmt" - "net/http" - "os" - "testing" - - structenv "github.com/caarlos0/env/v6" - packer_service "github.com/hashicorp/hcp-sdk-go/clients/cloud-packer-service/stable/2021-04-30/client/packer_service" - "github.com/hashicorp/hcp-sdk-go/clients/cloud-packer-service/stable/2021-04-30/models" - sharedmodels "github.com/hashicorp/hcp-sdk-go/clients/cloud-shared/v1/models" - "github.com/hashicorp/packer/acctest" - "github.com/hashicorp/packer/internal/registry" - "google.golang.org/grpc/codes" -) - -type hcpConf struct { - OrgId string `env:"HCP_ORG_ID"` - ProjectId string `env:"HCP_PROJECT_ID"` - ApiHost string `env:"HCP_API_HOST"` - AuthUrl string `env:"HCP_AUTH_URL"` - ClientId string `env:"HCP_CLIENT_ID"` - ClientSecret string `env:"HCP_CLIENT_SECRET"` - UserAgent string `env:"HCP_CLIENT_USER_AGENT" envDefault:"packer-par-acc-test"` -} - -type Config struct { - *registry.Client - Loc *sharedmodels.HashicorpCloudLocationLocation - T *testing.T -} - -func NewTestConfig(t *testing.T) (*Config, error) { - checkEnvVars(t) - cfg := hcpConf{} - if err := structenv.Parse(&cfg); err != nil { - t.Errorf("%+v\n", err) - } - cli, err := registry.NewClient() - if err != nil { - return nil, err - } - - return &Config{ - Client: cli, - Loc: &sharedmodels.HashicorpCloudLocationLocation{ - OrganizationID: cli.OrganizationID, - ProjectID: cli.ProjectID, - }, - T: t, - }, nil -} - -func checkEnvVars(t *testing.T) { - t.Helper() - if os.Getenv(acctest.TestEnvVar) == "" { - t.Skip(fmt.Sprintf( - "Acceptance tests skipped unless env '%s' set", - acctest.TestEnvVar)) - return - } - if os.Getenv("HCP_CLIENT_ID") == "" { - t.Fatal("HCP_CLIENT_ID must be set for acceptance tests") - } - if os.Getenv("HCP_CLIENT_SECRET") == "" { - t.Fatal("HCP_CLIENT_SECRET must be set for acceptance tests") - } -} - -// GetIterationByID is a helper to validate that the id for a given bucketSlug returns a valid Iteration ID. -func (cfg *Config) GetIterationByID( - bucketSlug, - id string, -) string { - cfg.T.Helper() - - getItParams := packer_service.NewPackerServiceGetIterationParams() - getItParams.LocationOrganizationID = cfg.Loc.OrganizationID - getItParams.LocationProjectID = cfg.Loc.ProjectID - getItParams.BucketSlug = bucketSlug - getItParams.IterationID = &id - - ok, err := cfg.Packer.PackerServiceGetIteration(getItParams, nil) - if err != nil { - cfg.T.Fatal(err) - } - return ok.Payload.Iteration.ID -} - -// UpsertIteration creates a new iteration if it does not already exists. -func (cfg *Config) UpsertIteration( - bucketSlug, - fingerprint string, -) string { - cfg.T.Helper() - - _, err := cfg.CreateIteration(context.Background(), bucketSlug, fingerprint) - if err == nil { - return cfg.GetIterationIDFromFingerPrint(bucketSlug, fingerprint) - } - if err, ok := err.(*packer_service.PackerServiceCreateIterationDefault); ok { - switch err.Code() { - case int(codes.AlreadyExists), http.StatusConflict: - // all good here ! - return cfg.GetIterationIDFromFingerPrint(bucketSlug, fingerprint) - } - } - - cfg.T.Fatalf("unexpected CreateIteration error, expected nil or 409. Got %v", err) - return "" -} - -// MarkIterationAsDone sends an update request to mark an existing iteration as complete. -func (cfg *Config) MarkIterationAsDone( - bucketSlug, - iterID string, -) { - cfg.T.Helper() - - updateItParams := packer_service.NewPackerServiceUpdateIterationParams() - updateItParams.Body = &models.HashicorpCloudPackerUpdateIterationRequest{ - BucketSlug: bucketSlug, - IterationID: iterID, - Complete: true, - } - updateItParams.IterationID = iterID - updateItParams.LocationOrganizationID = cfg.OrganizationID - updateItParams.LocationProjectID = cfg.ProjectID - - _, err := cfg.Packer.PackerServiceUpdateIteration(updateItParams, nil) - if err == nil { - return - } - - cfg.T.Errorf("unexpected UpdateIteration error: %v", err) -} - -// GetIterationIDFromFingerPrint returns an iteration ID given its unique -// fingerprincfg.t. -func (cfg *Config) GetIterationIDFromFingerPrint( - bucketSlug, - fingerprint string, -) string { - cfg.T.Helper() - - getItParams := packer_service.NewPackerServiceGetIterationParams() - getItParams.LocationOrganizationID = cfg.Loc.OrganizationID - getItParams.LocationProjectID = cfg.Loc.ProjectID - getItParams.BucketSlug = bucketSlug - getItParams.Fingerprint = &fingerprint - - ok, err := cfg.Packer.PackerServiceGetIteration(getItParams, nil) - if err != nil { - cfg.T.Fatal(err) - } - return ok.Payload.Iteration.ID -} - -// UpsertBuild creates a new build for iteration if it does not already exists. -func (cfg *Config) UpsertBuild( - bucketSlug, - iterationFingerprint, - runUUID, - iterationID, - cloudProvider, - componentType, - region string, - imageIDs []string, -) { - - build, err := cfg.CreateBuild(context.Background(), - bucketSlug, - runUUID, - iterationID, - iterationFingerprint, - componentType, - models.HashicorpCloudPackerBuildStatusUNSET, - ) - if err, ok := err.(*packer_service.PackerServiceCreateBuildDefault); ok { - switch err.Code() { - case int(codes.Aborted), http.StatusConflict: - // all good here ! - return - default: - cfg.T.Fatalf("couldn't create build: %v", err) - } - } - - if build == nil { - cfg.T.Errorf("unexpected CreateBuild error, expected non nil build response. Got %v", err) - return - } - - // Iterations are currently only assigned an incremental version when publishing image metadata on update. - // Incremental versions are a requirement for assigning the channel. - updateBuildParams := packer_service.NewPackerServiceUpdateBuildParams() - updateBuildParams.LocationOrganizationID = cfg.Loc.OrganizationID - updateBuildParams.LocationProjectID = cfg.Loc.ProjectID - updateBuildParams.BuildID = build.Payload.Build.ID - updateBuildParams.Body = &models.HashicorpCloudPackerUpdateBuildRequest{ - Updates: &models.HashicorpCloudPackerBuildUpdates{ - CloudProvider: cloudProvider, - Status: models.HashicorpCloudPackerBuildStatusDONE, - }, - } - for _, imageID := range imageIDs { - updateBuildParams.Body.Updates.Images = append(updateBuildParams.Body.Updates.Images, &models.HashicorpCloudPackerImageCreateBody{ - ImageID: imageID, - Region: region, - }) - } - _, err = cfg.Packer.PackerServiceUpdateBuild(updateBuildParams, nil) - if err, ok := err.(*packer_service.PackerServiceUpdateBuildDefault); ok { - cfg.T.Errorf("unexpected UpdateBuild error, expected nil. Got %v", err) - } -} - -func (cfg *Config) UpsertChannel( - bucketSlug, - channelSlug, - iterationID string, -) { - cfg.T.Helper() - - createChParams := packer_service.NewPackerServiceCreateChannelParams() - createChParams.LocationOrganizationID = cfg.Loc.OrganizationID - createChParams.LocationProjectID = cfg.Loc.ProjectID - createChParams.BucketSlug = bucketSlug - createChParams.Body = &models.HashicorpCloudPackerCreateChannelRequest{ - Slug: channelSlug, - IncrementalVersion: 1, - IterationID: iterationID, - } - - _, err := cfg.Packer.PackerServiceCreateChannel(createChParams, nil) - if err == nil { - return - } - if err, ok := err.(*packer_service.PackerServiceCreateChannelDefault); ok { - switch err.Code() { - case int(codes.Aborted), http.StatusConflict: - // all good here ! - cfg.UpdateChannel(bucketSlug, channelSlug) - return - } - } - cfg.T.Errorf("unexpected CreateChannel error, expected nil. Got %v", err) -} - -func (cfg *Config) UpdateChannel( - bucketSlug, - channelSlug string, -) { - cfg.T.Helper() - - updateChParams := packer_service.NewPackerServiceUpdateChannelParams() - updateChParams.LocationOrganizationID = cfg.Loc.OrganizationID - updateChParams.LocationProjectID = cfg.Loc.ProjectID - updateChParams.BucketSlug = bucketSlug - updateChParams.Slug = channelSlug - updateChParams.Body = &models.HashicorpCloudPackerUpdateChannelRequest{ - IncrementalVersion: 1, - } - - _, err := cfg.Packer.PackerServiceUpdateChannel(updateChParams, nil) - if err == nil { - return - } - cfg.T.Errorf("unexpected UpdateChannel error, expected nil. Got %v", err) -} - -func (cfg *Config) DeleteIteration( - bucketSlug, - iterationID string, -) { - cfg.T.Helper() - - deleteItParams := packer_service.NewPackerServiceDeleteIterationParams() - deleteItParams.LocationOrganizationID = cfg.Loc.OrganizationID - deleteItParams.LocationProjectID = cfg.Loc.ProjectID - deleteItParams.BucketSlug = &bucketSlug - deleteItParams.IterationID = iterationID - - _, err := cfg.Packer.PackerServiceDeleteIteration(deleteItParams, nil) - if err == nil { - return - } - cfg.T.Errorf("unexpected DeleteIteration error, expected nil. Got %v", err) -} - -func (cfg *Config) DeleteChannel( - bucketSlug, - channelSlug string, -) { - cfg.T.Helper() - - deleteChParams := packer_service.NewPackerServiceDeleteChannelParams() - deleteChParams.LocationOrganizationID = cfg.Loc.OrganizationID - deleteChParams.LocationProjectID = cfg.Loc.ProjectID - deleteChParams.BucketSlug = bucketSlug - deleteChParams.Slug = channelSlug - - _, err := cfg.Packer.PackerServiceDeleteChannel(deleteChParams, nil) - if err == nil { - return - } - cfg.T.Errorf("unexpected DeleteChannel error, expected nil. Got %v", err) -} diff --git a/internal/registry/acctest/par_test.go b/internal/registry/acctest/par_test.go deleted file mode 100644 index a06bf1438..000000000 --- a/internal/registry/acctest/par_test.go +++ /dev/null @@ -1,186 +0,0 @@ -package acctest - -import ( - "bytes" - "context" - "os" - "regexp" - "strconv" - "strings" - "testing" - "time" - - "github.com/hashicorp/packer/command" - - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -const ( - channel = "acc" -) - -func TestAcc_PAR_service_create_and_datasource(t *testing.T) { - runUUID := "11118ff1-a860-44a3-a669-a4f1b4a12688" - os.Setenv("PACKER_RUN_UUID", runUUID) - - checkEnvVars(t) - const tmpBucket = "pkr-acctest-temp-1" - - // allow other tests to go. - t.Parallel() - - cfg, err := NewTestConfig(t) - if err != nil { - t.Fatalf("NewParConfig: %v", err) - } - - _, _ = cfg.DeleteBucket(context.Background(), tmpBucket) - defer func() { - _, err := cfg.DeleteBucket(context.Background(), tmpBucket) // Hopefully everything else is deleted too - if err != nil { - t.Fatalf("failed to delete bucket: %v", err) - } - }() - - // create our bucket, this should fail if the bucket already exists - _, err = cfg.CreateBucket(context.Background(), tmpBucket, "", nil) - if err != nil { - t.Fatalf("CreateBucket: %v", err) - } - - // insert tons of iteration - iterations := []map[string]map[string][]string{ - { - "aws": {"us-west-1": {"ami:something_1", "ami:other_thing"}}, - "gcp": {"us-west-1": {"gcp_something_1", "gcpp"}}, - "azure": {"us-west-1": {"azure_something_1", "azaz"}}, - "vmware-iso": {"": {"iso_something_1", "vmvmvm"}}, - }, - { - "aws": {"us-west-1": {"ami:something_2", "ami:other_thing"}}, - "gcp": {"us-west-1": {"gcp_something_2", "gcpp"}}, - "azure": {"us-west-1": {"azure_something_2", "azaz"}}, - "vmware-iso": {"": {"iso_something_2", "vmvmvm"}}, - }, - { - "aws": {"us-west-1": {"ami:something_3"}}, - "gcp": {"us-west-1": {"gcp_something_3", "gcpp"}}, - "azure": {"us-west-1": {"azure_something_3", "azaz"}}, - "vmware-iso": {"": {"iso_something_3", "vmvmvm"}}, - }, - } - - lastIterationID := "" - for i, builds := range iterations { - iterationFingerprint := strconv.Itoa(i) - iterationID := cfg.UpsertIteration(tmpBucket, iterationFingerprint) - - for cloud, builds := range builds { - for region, imageIDs := range builds { - cfg.UpsertBuild( - tmpBucket, - iterationFingerprint, - runUUID, - iterationID, - cloud, - cloud, - region, - imageIDs, - ) - } - } - - time.Sleep(time.Millisecond) - lastIterationID = iterationID - } - - if cfg.GetIterationByID(tmpBucket, lastIterationID) != lastIterationID { - t.Fatal("that should not be possible") - } - - cfg.UpsertChannel(tmpBucket, channel, lastIterationID) - - // now, let's try getting the datasource - - meta := command.TestMetaFile(t) - ui := meta.Ui.(*packersdk.BasicUi) - c := &command.BuildCommand{ - Meta: meta, - } - - code := c.Run([]string{"./test-fixtures/ds.pkr.hcl"}) - outW := ui.Writer.(*bytes.Buffer) - errW := ui.ErrorWriter.(*bytes.Buffer) - if code != 0 { - t.Fatalf( - "Bad exit code.\n\nStdout:\n\n%s\n\nStderr:\n\n%s", - outW.String(), - errW.String()) - } - - if !strings.Contains(outW.String(), "the artifact id is: ami:something_3, yup yup") { - t.Fatal("data source not found ?") - } -} - -func TestAcc_PAR_pkr_build(t *testing.T) { - - runUUID := "11118ff1-a860-44a3-a669-a4f1b4a12688" - os.Setenv("PACKER_RUN_UUID", runUUID) - - checkEnvVars(t) - const tmpBucket = "pkr-acctest-temp-2" - - // allow other tests to go. - t.Parallel() - - cfg, err := NewTestConfig(t) - if err != nil { - t.Fatalf("NewParConfig: %v", err) - } - - _, _ = cfg.DeleteBucket(context.Background(), tmpBucket) - defer func() { - _, err := cfg.DeleteBucket(context.Background(), tmpBucket) // Hopefully everything else is deleted too - if err != nil { - t.Fatalf("failed to delete bucket: %v", err) - } - }() - // create our bucket, this should fail if the bucket already exists - _, err = cfg.CreateBucket(context.Background(), tmpBucket, "", nil) - if err != nil { - t.Fatalf("CreateBucket: %v", err) - } - - // now, let's try building something - - meta := command.TestMetaFile(t) - ui := meta.Ui.(*packersdk.BasicUi) - c := &command.BuildCommand{ - Meta: meta, - } - - code := c.Run([]string{"./test-fixtures/build.pkr.hcl"}) - outW := ui.Writer.(*bytes.Buffer) - errW := ui.ErrorWriter.(*bytes.Buffer) - if code != 0 { - t.Fatalf( - "Bad exit code.\n\nStdout:\n\n%s\n\nStderr:\n\n%s", - outW.String(), - errW.String()) - } - - // extract id from output - re := regexp.MustCompile(`(?m)^.*packer/` + tmpBucket + `/iterations/(\S*)`) - match := re.FindStringSubmatch(outW.String()) - if len(match) != 2 { - t.Fatalf("Could not extract ID from output.\n\nStdout:\n\n%s\n\nStderr:\n\n%s", - outW.String(), - errW.String()) - } - iterationID := match[1] - - if foundID := cfg.GetIterationByID(tmpBucket, iterationID); foundID != iterationID { - t.Fatalf("could not find iteration back in service: expected %q, found %q", iterationID, foundID) - } -} diff --git a/internal/registry/acctest/test-fixtures/build.pkr.hcl b/internal/registry/acctest/test-fixtures/build.pkr.hcl deleted file mode 100644 index 988036731..000000000 --- a/internal/registry/acctest/test-fixtures/build.pkr.hcl +++ /dev/null @@ -1,27 +0,0 @@ - -variable "bkt" { - default = "pkr-acctest-temp-2" -} - -source "null" "example" { - communicator = "none" -} - -build { - hcp_packer_registry { - bucket_name = "pkr-acctest-temp-2" - description = "blah" - - build_labels = { - "foo-version" = "3.4.0" - "foo" = "bar" - } - } - - sources = [ - "source.null.example" - ] - provisioner "shell-local" { - inline = ["echo test"] - } -} diff --git a/internal/registry/acctest/test-fixtures/ds.pkr.hcl b/internal/registry/acctest/test-fixtures/ds.pkr.hcl deleted file mode 100644 index f11ea769c..000000000 --- a/internal/registry/acctest/test-fixtures/ds.pkr.hcl +++ /dev/null @@ -1,29 +0,0 @@ - -variable "bkt" { - default = "pkr-acctest-temp-1" -} - -data "hcp-packer-iteration" "acc" { - bucket_name = var.bkt - channel = "acc" -} - -data "hcp-packer-image" "acc-production" { - bucket_name = var.bkt - iteration_id = data.hcp-packer-iteration.acc.id - cloud_provider = "aws" - region = "us-west-1" -} - -source "null" "example" { - communicator = "none" -} - -build { - sources = [ - "source.null.example" - ] - provisioner "shell-local" { - inline = ["echo the artifact id is: '${data.hcp-packer-image.acc-production.id}', yup yup"] - } -}