Skip to content

Commit

Permalink
hcl: support for top level hcp registry config
Browse files Browse the repository at this point in the history
  • Loading branch information
mogrogan committed Feb 11, 2025
1 parent f0154fd commit b36d3eb
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 27 deletions.
80 changes: 58 additions & 22 deletions internal/hcp/registry/hcl.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand All @@ -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
}
}
Expand All @@ -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),
)
Expand All @@ -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))
Expand All @@ -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
}
3 changes: 3 additions & 0 deletions internal/hcp/registry/hcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
30 changes: 25 additions & 5 deletions internal/hcp/registry/types.bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit b36d3eb

Please sign in to comment.