Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

POC: support for top level hcp registry block #13297

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 27 additions & 9 deletions hcl2template/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand All @@ -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"}},
},
}
Expand Down Expand Up @@ -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...)
Expand Down
3 changes: 3 additions & 0 deletions hcl2template/types.packer_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
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