From e94835101bb5da4a0021d7bcba81199972686647 Mon Sep 17 00:00:00 2001 From: Martin Grogan Date: Tue, 11 Feb 2025 12:20:00 -0500 Subject: [PATCH 1/2] hcl: add packer_registry at root schema --- hcl2template/parser.go | 36 +++++++++++++++++++++-------- hcl2template/types.packer_config.go | 3 +++ 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/hcl2template/parser.go b/hcl2template/parser.go index d6ae4ecb97a..d63a64ed774 100644 --- a/hcl2template/parser.go +++ b/hcl2template/parser.go @@ -20,15 +20,16 @@ import ( ) const ( - packerLabel = "packer" - sourceLabel = "source" - variablesLabel = "variables" - variableLabel = "variable" - localsLabel = "locals" - localLabel = "local" - dataSourceLabel = "data" - buildLabel = "build" - communicatorLabel = "communicator" + packerLabel = "packer" + sourceLabel = "source" + variablesLabel = "variables" + variableLabel = "variable" + localsLabel = "locals" + localLabel = "local" + dataSourceLabel = "data" + buildLabel = "build" + hcpPackerRegistryLabel = "hcp_packer_registry" + communicatorLabel = "communicator" ) var configSchema = &hcl.BodySchema{ @@ -41,6 +42,7 @@ var configSchema = &hcl.BodySchema{ {Type: localLabel, LabelNames: []string{"name"}}, {Type: dataSourceLabel, LabelNames: []string{"type", "name"}}, {Type: buildLabel}, + {Type: hcpPackerRegistryLabel}, {Type: communicatorLabel, LabelNames: []string{"type", "name"}}, }, } @@ -549,6 +551,22 @@ func (p *Parser) parseConfig(f *hcl.File, cfg *PackerConfig) hcl.Diagnostics { for _, block := range content.Blocks { switch block.Type { + + case buildHCPPackerRegistryLabel: + if cfg.HCPPackerRegistry != nil { + diags = append(diags, &hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: fmt.Sprintf("Only one " + buildHCPPackerRegistryLabel + " is allowed"), + Subject: block.DefRange.Ptr(), + }) + continue + } + hcpPackerRegistry, moreDiags := p.decodeHCPRegistry(block, cfg) + diags = append(diags, moreDiags...) + if moreDiags.HasErrors() { + continue + } + cfg.HCPPackerRegistry = hcpPackerRegistry case sourceLabel: source, moreDiags := p.decodeSource(block) diags = append(diags, moreDiags...) diff --git a/hcl2template/types.packer_config.go b/hcl2template/types.packer_config.go index bf0e9636c70..859fda48153 100644 --- a/hcl2template/types.packer_config.go +++ b/hcl2template/types.packer_config.go @@ -55,6 +55,9 @@ type PackerConfig struct { // Builds is the list of Build blocks defined in the config files. Builds Builds + // HCPPackerRegistry contains the configuration for publishing the artifacts to the HCP Packer Registry. + HCPPackerRegistry *HCPPackerRegistryBlock + // HCPVars is the list of HCP-set variables for use later in a template HCPVars map[string]cty.Value From 6e166b6ed409e7a9a48dfe4a5de3f040898ebe11 Mon Sep 17 00:00:00 2001 From: Martin Grogan Date: Tue, 11 Feb 2025 15:37:21 -0500 Subject: [PATCH 2/2] hcl: support for top level hcp registry config --- internal/hcp/registry/hcl.go | 80 +++++++++++++++++++-------- internal/hcp/registry/hcp.go | 3 + internal/hcp/registry/types.bucket.go | 30 ++++++++-- 3 files changed, 86 insertions(+), 27 deletions(-) diff --git a/internal/hcp/registry/hcl.go b/internal/hcp/registry/hcl.go index d512e3c0d01..ca405cb200e 100644 --- a/internal/hcp/registry/hcl.go +++ b/internal/hcp/registry/hcl.go @@ -69,7 +69,8 @@ func (h *HCLRegistry) StartBuild(ctx context.Context, build sdkpacker.Build) err name := build.Name() cb, ok := build.(*packer.CoreBuild) if ok { - name = cb.Type + // We prepend type with builder block name to prevent conflict + name = prependIfNotEmpty(cb.BuildName, cb.Type) } return h.bucket.startBuild(ctx, name) @@ -85,7 +86,8 @@ func (h *HCLRegistry) CompleteBuild( buildName := build.Name() cb, ok := build.(*packer.CoreBuild) if ok { - buildName = cb.Type + // We prepend type with builder block name to prevent conflict + buildName = prependIfNotEmpty(cb.BuildName, cb.Type) } buildMetadata, envMetadata := cb.GetMetadata(), h.metadata @@ -103,32 +105,21 @@ func (h *HCLRegistry) VersionStatusSummary() { func NewHCLRegistry(config *hcl2template.PackerConfig, ui sdkpacker.Ui) (*HCLRegistry, hcl.Diagnostics) { var diags hcl.Diagnostics - if len(config.Builds) > 1 { + + if len(config.Builds) > 1 && config.HCPPackerRegistry == nil { diags = append(diags, &hcl.Diagnostic{ Severity: hcl.DiagError, Summary: "Multiple " + buildLabel + " blocks", Detail: fmt.Sprintf("For HCP Packer Registry enabled builds, only one " + buildLabel + - " block can be defined. Please remove any additional " + buildLabel + - " block(s). If this " + buildLabel + " is not meant for the HCP Packer registry please " + - "clear any HCP_PACKER_* environment variables."), + " block can be defined. Please declare HCP registry configuration at root level "), }) return nil, diags } - withHCLBucketConfiguration := func(bb *hcl2template.BuildBlock) bucketConfigurationOpts { + withHCLBucketConfiguration := func(cfg *hcl2template.PackerConfig) bucketConfigurationOpts { return func(bucket *Bucket) hcl.Diagnostics { - bucket.ReadFromHCLBuildBlock(bb) - // If at this point the bucket.Name is still empty, - // last try is to use the build.Name if present - if bucket.Name == "" && bb.Name != "" { - bucket.Name = bb.Name - } - - // If the description is empty, use the one from the build block - if bucket.Description == "" && bb.Description != "" { - bucket.Description = bb.Description - } + bucket.ReadFromHCLRoot(cfg) return nil } } @@ -139,11 +130,10 @@ func NewHCLRegistry(config *hcl2template.PackerConfig, ui sdkpacker.Ui) (*HCLReg diags = append(diags, dsDiags...) } - build := config.Builds[0] bucket, bucketDiags := createConfiguredBucket( config.Basedir, withPackerEnvConfiguration, - withHCLBucketConfiguration(build), + withHCLBucketConfiguration(config), withDeprecatedDatasourceConfiguration(vals, ui), withDatasourceConfiguration(vals), ) @@ -154,9 +144,48 @@ func NewHCLRegistry(config *hcl2template.PackerConfig, ui sdkpacker.Ui) (*HCLReg if diags.HasErrors() { return nil, diags } + buildNames := make(map[string]struct{}) + + for _, build := range config.Builds { + if config.HCPPackerRegistry != nil && build.HCPPackerRegistry != nil { + var diags hcl.Diagnostics + diags = append(diags, &hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Ambiguous HCP Packer registry configuration", + Detail: "Cannot use root declared HCP Packer configuration at the same time " + + "as build block nested HCP Packer configuration", + }) - for _, source := range build.Sources { - bucket.RegisterBuildForComponent(source.String()) + return nil, diags + + } + if build.HCPPackerRegistry != nil { + diags = append(diags, &hcl.Diagnostic{ + Severity: hcl.DiagWarning, + Summary: buildLabel + " HCP registry configuration is deprecated", + Detail: "Please use root level HCP registry configuration", + }) + + } + for _, source := range build.Sources { + + // We prepend each source with builder block name to prevent conflict + buildName := prependIfNotEmpty(build.Name, source.String()) + if _, ok := buildNames[buildName]; ok { + + diags = append(diags, &hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Ambiguous build name", + Detail: "build name " + + "Two or more build blocks resolve to the same build name (" + buildName + ") " + + "Please use the Name attribute in the build block to fix this", + }) + + return nil, diags + } + buildNames[buildName] = struct{}{} + bucket.RegisterBuildForComponent(buildName) + } } ui.Say(fmt.Sprintf("Tracking build on HCP Packer with fingerprint %q", bucket.Version.Fingerprint)) @@ -172,3 +201,10 @@ func NewHCLRegistry(config *hcl2template.PackerConfig, ui sdkpacker.Ui) (*HCLReg func (h *HCLRegistry) Metadata() Metadata { return h.metadata } + +func prependIfNotEmpty(prefix string, suffix string) string { + if prefix != "" { + return fmt.Sprintf("%s.%s", prefix, suffix) + } + return suffix +} diff --git a/internal/hcp/registry/hcp.go b/internal/hcp/registry/hcp.go index d0d249f25c6..d2b4393d631 100644 --- a/internal/hcp/registry/hcp.go +++ b/internal/hcp/registry/hcp.go @@ -39,6 +39,9 @@ func IsHCPEnabled(cfg packer.Handler) bool { switch config := cfg.(type) { case *hcl2template.PackerConfig: + if config.HCPPackerRegistry != nil { + mode = HCPConfigEnabled + } for _, build := range config.Builds { if build.HCPPackerRegistry != nil { mode = HCPConfigEnabled diff --git a/internal/hcp/registry/types.bucket.go b/internal/hcp/registry/types.bucket.go index 1e06439c487..6d6869108fc 100644 --- a/internal/hcp/registry/types.bucket.go +++ b/internal/hcp/registry/types.bucket.go @@ -93,6 +93,27 @@ func (bucket *Bucket) ReadFromHCLBuildBlock(build *hcl2template.BuildBlock) { } } +// ReadFromRoot reads the information for initialising a Bucket from a HCL2 root +func (bucket *Bucket) ReadFromHCLRoot(cfg *hcl2template.PackerConfig) { + if bucket == nil { + return + } + + registryBlock := cfg.HCPPackerRegistry + if registryBlock == nil { + return + } + + bucket.Description = registryBlock.Description + bucket.BucketLabels = registryBlock.BucketLabels + bucket.BuildLabels = registryBlock.BuildLabels + // 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 != "" { + bucket.Name = registryBlock.Slug + } +} + // connect initializes a client connection to a remote HCP Packer Registry service on HCP. // Upon a successful connection the initialized client is persisted on the Bucket b for later usage. func (bucket *Bucket) connect() error { @@ -132,16 +153,15 @@ func (bucket *Bucket) Initialize( return bucket.initializeVersion(ctx, templateType) } -func (bucket *Bucket) RegisterBuildForComponent(sourceName string) { +func (bucket *Bucket) RegisterBuildForComponent(buildName string) { if bucket == nil { return } - if ok := bucket.Version.HasBuild(sourceName); ok { + if ok := bucket.Version.HasBuild(buildName); ok { return } - - bucket.Version.expectedBuilds = append(bucket.Version.expectedBuilds, sourceName) + bucket.Version.expectedBuilds = append(bucket.Version.expectedBuilds, buildName) } // CreateInitialBuildForVersion will create a build entry on the HCP Packer Registry for the named componentType. @@ -658,7 +678,7 @@ func (bucket *Bucket) doCompleteBuild( ctx context.Context, buildName string, packerSDKArtifacts []packerSDK.Artifact, - buildErr error, + _ error, ) ([]packerSDK.Artifact, error) { for _, art := range packerSDKArtifacts { var sdkImages []packerSDKRegistry.Image