diff --git a/hcl2template/types.build.hcp_packer_registry.go b/hcl2template/types.build.hcp_packer_registry.go index 640359aa1..2b7c1f71e 100644 --- a/hcl2template/types.build.hcp_packer_registry.go +++ b/hcl2template/types.build.hcp_packer_registry.go @@ -20,6 +20,8 @@ type HCPPackerRegistryBlock struct { BucketLabels map[string]string // Build labels BuildLabels map[string]string + // Channels + Channels []string HCL2Ref } @@ -37,6 +39,7 @@ func (p *Parser) decodeHCPRegistry(block *hcl.Block, cfg *PackerConfig) (*HCPPac Labels map[string]string `hcl:"labels,optional"` BucketLabels map[string]string `hcl:"bucket_labels,optional"` BuildLabels map[string]string `hcl:"build_labels,optional"` + Channels []string `hcl:"channels,optional"` Config hcl.Body `hcl:",remain"` } ectx := cfg.EvalContext(BuildContext, nil) @@ -69,6 +72,7 @@ func (p *Parser) decodeHCPRegistry(block *hcl.Block, cfg *PackerConfig) (*HCPPac par.Slug = b.Slug par.Description = b.Description + par.Channels = b.Channels if len(b.Labels) > 0 && len(b.BucketLabels) > 0 { diags = append(diags, &hcl.Diagnostic{ diff --git a/internal/hcp/api/service_build.go b/internal/hcp/api/service_build.go index a857192c3..51a0f37f6 100644 --- a/internal/hcp/api/service_build.go +++ b/internal/hcp/api/service_build.go @@ -118,3 +118,23 @@ func (c *Client) UploadSbom( _, err := c.Packer.PackerServiceUploadSbom(params, nil) return err } + +func (c *Client) UpdateChannel( + ctx context.Context, + bucketName, channelName string, + body *hcpPackerModels.HashicorpCloudPacker20230101UpdateChannelBody, +) (*hcpPackerAPI.PackerServiceUpdateChannelOK, error) { + + params := hcpPackerAPI.NewPackerServiceUpdateChannelParamsWithContext(ctx) + params.LocationOrganizationID = c.OrganizationID + params.LocationProjectID = c.ProjectID + params.BucketName = bucketName + params.ChannelName = channelName + params.Body = body + resp, err := c.Packer.PackerServiceUpdateChannel(params, nil) + if err != nil { + return nil, err + } + + return resp, nil +} diff --git a/internal/hcp/registry/types.bucket.go b/internal/hcp/registry/types.bucket.go index 264852492..c81f03412 100644 --- a/internal/hcp/registry/types.bucket.go +++ b/internal/hcp/registry/types.bucket.go @@ -36,6 +36,7 @@ type Bucket struct { Destination string BucketLabels map[string]string BuildLabels map[string]string + Channels []string SourceExternalIdentifierToParentVersions map[string]ParentVersion RunningBuilds map[string]chan struct{} Version *Version @@ -94,6 +95,7 @@ func (bucket *Bucket) ReadFromHCPPackerRegistryBlock(registryBlock *hcl2template bucket.Description = registryBlock.Description bucket.BucketLabels = registryBlock.BucketLabels bucket.BuildLabels = registryBlock.BuildLabels + bucket.Channels = registryBlock.Channels // If there's already a Name this was set from env variable. // In Packer, env variable overrides config values so we keep it that way for consistency. if bucket.Name == "" && registryBlock.Slug != "" { @@ -244,6 +246,30 @@ func (bucket *Bucket) uploadSbom(ctx context.Context, buildName string, sbom pac return bucket.client.UploadSbom(ctx, bucket.Name, bucket.Version.Fingerprint, buildToUpdate.ID, sbom) } +func (bucket *Bucket) updateChannels(ctx context.Context) error { + if len(bucket.Channels) == 0 { + return nil + } + + log.Printf("[INFO] Updating %d channel(s) to point to version %s", len(bucket.Channels), bucket.Version.ID) + + body := &hcpPackerModels.HashicorpCloudPacker20230101UpdateChannelBody{ + VersionFingerprint: bucket.Version.Fingerprint, + UpdateMask: "versionFingerprint", + } + + for _, channel := range bucket.Channels { + log.Printf("[INFO] Updating channel %s to version %s", channel, bucket.Version.ID) + _, err := bucket.client.UpdateChannel(ctx, bucket.Name, channel, body) + if err != nil { + log.Printf("[ERROR] Failed to update channel %s: %s", channel, err) + return fmt.Errorf("failed to update channel %s: %w", channel, err) + } + } + + return nil +} + // markBuildComplete should be called to set a build on the HCP Packer registry to DONE. // Upon a successful call markBuildComplete will publish all artifacts created by the named build, // and set the build to done. A build with no artifacts can not be set to DONE. @@ -726,6 +752,12 @@ func (bucket *Bucket) doCompleteBuild( parErr) } + // Update channels after build is marked complete + channelErr := bucket.updateChannels(ctx) + if channelErr != nil { + log.Printf("[ERROR] Failed to update channels after completing build %s: %s", buildName, channelErr) + } + return append(packerSDKArtifacts, ®istryArtifact{ BuildName: buildName, BucketName: bucket.Name, diff --git a/website/content/docs/templates/hcl_templates/blocks/build/hcp_packer_registry.mdx b/website/content/docs/templates/hcl_templates/blocks/build/hcp_packer_registry.mdx index 503ba23d4..e649e194e 100644 --- a/website/content/docs/templates/hcl_templates/blocks/build/hcp_packer_registry.mdx +++ b/website/content/docs/templates/hcl_templates/blocks/build/hcp_packer_registry.mdx @@ -10,7 +10,7 @@ This topic provides reference information about the `hcp_packer_registry` block. ## Description -The `hcp_packer_registry` block configures details about an image Packer creates or updates in the HCP Packer registry. Use the `hcp_packer_registry` block to customize the metadata Packer sends to HCP Packer Registry. +The `hcp_packer_registry` block configures details about an image Packer creates or updates in the HCP Packer registry. Use the `hcp_packer_registry` block to customize the metadata Packer sends to HCP Packer Registry. To get started with HCP Packer, refer to the [HCP Packer documentation](/hcp/docs/packer) or try the [Get Started with HCP Packer tutorials](/packer/tutorials/hcp-get-started). @@ -77,5 +77,8 @@ Some nice description about the image which artifact is being published to HCP P Packer registry. Should contain a maximum of 255 characters. Defaults to `build.description` if not set. +- `channels` ([]string) - List of channel to update to point to the new build + once the build is complete. Channels must already exist in the HCP Packer registry. + - `labels` (map[string]string) - Deprecated in Packer 1.7.9. See [`bucket_labels`](#bucket_labels) for details.