From e8470a2c6577ee3b761b2ac8257c098b45720fe1 Mon Sep 17 00:00:00 2001 From: Wilken Rivera Date: Thu, 20 Jul 2023 20:03:43 +0000 Subject: [PATCH] backport of commit 777c8163176961214cc13ab8396f354cf1f8523e --- internal/hcp/api/client.go | 48 ++++++++++++------- internal/hcp/api/client_test.go | 83 --------------------------------- 2 files changed, 31 insertions(+), 100 deletions(-) diff --git a/internal/hcp/api/client.go b/internal/hcp/api/client.go index 89d4a39b4..f28999d57 100644 --- a/internal/hcp/api/client.go +++ b/internal/hcp/api/client.go @@ -11,6 +11,7 @@ import ( "os" "time" + "github.com/hashicorp/hcp-sdk-go/clients/cloud-packer-service/stable/2021-04-30/client/packer_service" packerSvc "github.com/hashicorp/hcp-sdk-go/clients/cloud-packer-service/stable/2021-04-30/client/packer_service" organizationSvc "github.com/hashicorp/hcp-sdk-go/clients/cloud-resource-manager/preview/2019-12-10/client/organization_service" projectSvc "github.com/hashicorp/hcp-sdk-go/clients/cloud-resource-manager/preview/2019-12-10/client/project_service" @@ -67,7 +68,12 @@ func NewClient() (*Client, error) { Organization: organizationSvc.New(cl, nil), Project: projectSvc.New(cl, nil), } - //if both HCP_ORGANIZATION_ID and HCP_PROJECT_ID are set via env variables the hcpConfig may have all we need already. + // A client.Config.hcpConfig is set when calling Canonicalize on basic HCP httpclient, as on line 52. + // If a user sets HCP_* env. variables they will be loaded into the client via the SDK and used for any client calls. + // For HCP_ORGANIZATION_ID and HCP_PROJECT_ID if they are both set via env. variables the call to hcpClientCfg.Connicalize() + // will automatically loaded them using the FromEnv configOption. + // + // If both values are set we should have all that we need to continue so we can returned the configured client. if hcpClientCfg.Profile().OrganizationID != "" && hcpClientCfg.Profile().ProjectID != "" { client.OrganizationID = hcpClientCfg.Profile().OrganizationID client.ProjectID = hcpClientCfg.Profile().ProjectID @@ -94,14 +100,11 @@ func NewClient() (*Client, error) { } } } + return client, nil } func (c *Client) loadOrganizationID() error { - if c.OrganizationID != "" { - return nil - } - if env.HasOrganizationID() { c.OrganizationID = os.Getenv(env.HCPOrganizationID) return nil @@ -121,11 +124,12 @@ func (c *Client) loadOrganizationID() error { } func (c *Client) loadProjectID() error { - if c.ProjectID != "" { - return nil - } if env.HasProjectID() { c.ProjectID = os.Getenv(env.HCPProjectID) + err := c.ValidateRegistryForProject() + if err != nil { + return fmt.Errorf("project validation for id %q responded in error: %v", c.ProjectID, err) + } return nil } // Get the project using the organization ID. @@ -136,15 +140,15 @@ func (c *Client) loadProjectID() error { listProjResp, err := c.Project.ProjectServiceList(listProjParams, nil) if err != nil { - //For permission errors our service principle may not have the perms - // to see all projects for an Org; this is the case for project-level service principles. + //For permission errors, our service principal may not have the ability + // to see all projects for an Org; this is the case for project-level service principals. serviceErr, ok := err.(*projectSvc.ProjectServiceListDefault) if !ok { return fmt.Errorf("unable to fetch project list: %v", err) } if serviceErr.Code() == http.StatusForbidden { return fmt.Errorf("unable to fetch project\n\n"+ - "If the provided credentials are tied to a specific project trying setting the %s environment variable to one you want to use.", env.HCPProjectID) + "If the provided credentials are tied to a specific project try setting the %s environment variable to one you want to use.", env.HCPProjectID) } } @@ -179,12 +183,22 @@ func getOldestProject(projects []*models.HashicorpCloudResourcemanagerProject) ( return oldestProj, nil } -func findProjectByID(projID string, projs []*models.HashicorpCloudResourcemanagerProject) (*models.HashicorpCloudResourcemanagerProject, error) { - for _, proj := range projs { - if proj.ID == projID { - return proj, nil - } +// ValidateRegistryForProject validates that there is an active registry associated to the configured organization and project ids. +// A successful validation will result in a nil response. All other response represent an invalid registry error request or a registry not found error. +func (client *Client) ValidateRegistryForProject() error { + params := packer_service.NewPackerServiceGetRegistryParams() + params.LocationOrganizationID = client.OrganizationID + params.LocationProjectID = client.ProjectID + + resp, err := client.Packer.PackerServiceGetRegistry(params, nil) + if err != nil { + return err } - return nil, fmt.Errorf("No project %q found", projID) + if resp.GetPayload().Registry == nil { + return fmt.Errorf("No active HCP Packer registry was found for the organization %q and project %q", client.OrganizationID, client.ProjectID) + } + + return nil + } diff --git a/internal/hcp/api/client_test.go b/internal/hcp/api/client_test.go index e68e03a34..85bf5df3d 100644 --- a/internal/hcp/api/client_test.go +++ b/internal/hcp/api/client_test.go @@ -8,89 +8,6 @@ import ( "github.com/hashicorp/hcp-sdk-go/clients/cloud-resource-manager/preview/2019-12-10/models" ) -func TestFindProjectID(t *testing.T) { - testcases := []struct { - Name string - ProjectID string - ProjectList []*models.HashicorpCloudResourcemanagerProject - ExpectProjectID string - ExpectErr bool - }{ - { - "Only one project, project exists, success", - "test-project-exists", - []*models.HashicorpCloudResourcemanagerProject{ - { - ID: "test-project-exists", - }, - }, - "test-project-exists", - false, - }, - { - "Multiple projects, project exists, success", - "test-project-exists", - []*models.HashicorpCloudResourcemanagerProject{ - { - ID: "other-project-exists", - }, - { - ID: "test-project-exists", - }, - }, - "test-project-exists", - false, - }, - { - "One project, no id match, fail", - "test-project-exists", - []*models.HashicorpCloudResourcemanagerProject{ - { - ID: "other-project-exists", - }, - }, - "", - true, - }, - { - "Multiple projects, no id match, fail", - "test-project-exists", - []*models.HashicorpCloudResourcemanagerProject{ - { - ID: "other-project-exists", - }, - { - ID: "yet-another-project-exists", - }, - }, - "", - true, - }, - { - "No projects, no id match, fail", - "test-project-exists", - []*models.HashicorpCloudResourcemanagerProject{}, - "", - true, - }, - } - - for _, tt := range testcases { - t.Run(tt.Name, func(t *testing.T) { - proj, err := findProjectByID(tt.ProjectID, tt.ProjectList) - if (err != nil) != tt.ExpectErr { - t.Errorf("test findProjectByID, expected %t, got %t", - tt.ExpectErr, - err != nil) - } - - if proj != nil && proj.ID != tt.ExpectProjectID { - t.Errorf("expected to select project %q, got %q", tt.ExpectProjectID, proj.ID) - } - }) - } -} - func TestGetOldestProject(t *testing.T) { testcases := []struct { Name string