You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
packer/internal/registry/client.go

102 lines
3.4 KiB

package registry
import (
"fmt"
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"
rmmodels "github.com/hashicorp/hcp-sdk-go/clients/cloud-resource-manager/preview/2019-12-10/models"
"github.com/hashicorp/hcp-sdk-go/httpclient"
"github.com/hashicorp/packer/internal/registry/env"
"github.com/hashicorp/packer/version"
)
// Client is an HCP client capable of making requests on behalf of a service principal
type Client struct {
Packer packerSvc.ClientService
Organization organizationSvc.ClientService
Project projectSvc.ClientService
// OrganizationID is the organization unique identifier on HCP.
OrganizationID string
// ProjectID is the project unique identifier on HCP.
ProjectID string
}
// NewClient returns an authenticated client to a HCP Packer Registry.
// Client authentication requires the following environment variables be set HCP_CLIENT_ID and HCP_CLIENT_SECRET.
// Upon error a HCPClientError will be returned.
func NewClient() (*Client, error) {
if !env.HasHCPCredentials() {
return nil, &ClientError{
StatusCode: InvalidClientConfig,
Err: fmt.Errorf("the client authentication requires both %s and %s environment variables to be set", env.HCPClientID, env.HCPClientSecret),
}
}
cl, err := httpclient.New(httpclient.Config{
SourceChannel: fmt.Sprintf("packer/%s", version.PackerVersion.FormattedVersion()),
})
if err != nil {
return nil, &ClientError{
StatusCode: InvalidClientConfig,
Err: err,
}
}
client := &Client{
Packer: packerSvc.New(cl, nil),
Organization: organizationSvc.New(cl, nil),
Project: projectSvc.New(cl, nil),
}
if err := client.loadOrganizationID(); err != nil {
return nil, &ClientError{
StatusCode: InvalidClientConfig,
Err: err,
}
}
if err := client.loadProjectID(); err != nil {
return nil, &ClientError{
StatusCode: InvalidClientConfig,
Err: err,
}
}
return client, nil
}
func (c *Client) loadOrganizationID() error {
// Get the organization ID.
listOrgParams := organizationSvc.NewOrganizationServiceListParams()
listOrgResp, err := c.Organization.OrganizationServiceList(listOrgParams, nil)
if err != nil {
return fmt.Errorf("unable to fetch organization list: %v", err)
}
orgLen := len(listOrgResp.Payload.Organizations)
if orgLen != 1 {
return fmt.Errorf("unexpected number of organizations: expected 1, actual: %v", orgLen)
}
c.OrganizationID = listOrgResp.Payload.Organizations[0].ID
return nil
}
func (c *Client) loadProjectID() error {
// Get the project using the organization ID.
listProjParams := projectSvc.NewProjectServiceListParams()
listProjParams.ScopeID = &c.OrganizationID
scopeType := string(rmmodels.HashicorpCloudResourcemanagerResourceIDResourceTypeORGANIZATION)
listProjParams.ScopeType = &scopeType
listProjResp, err := c.Project.ProjectServiceList(listProjParams, nil)
if err != nil {
return fmt.Errorf("unable to fetch project id: %v", err)
}
if len(listProjResp.Payload.Projects) > 1 {
return fmt.Errorf("this version of Packer does not support multiple projects")
}
c.ProjectID = listProjResp.Payload.Projects[0].ID
return nil
}