|
|
|
|
@ -2,7 +2,6 @@ package command
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"os"
|
|
|
|
|
"path/filepath"
|
|
|
|
|
|
|
|
|
|
"github.com/hashicorp/hcl/v2"
|
|
|
|
|
@ -17,6 +16,15 @@ import (
|
|
|
|
|
"github.com/zclconf/go-cty/cty/gocty"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type HCPConfigMode int
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
// HCPConfigMode types
|
|
|
|
|
HCPConfigUnset HCPConfigMode = iota
|
|
|
|
|
HCPConfigEnabled
|
|
|
|
|
HCPEnvEnabled
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
// Known HCP Packer Image Datasource, whose id is the SourceImageId for some build.
|
|
|
|
|
hcpImageDatasourceType string = "hcp-packer-image"
|
|
|
|
|
@ -24,8 +32,8 @@ const (
|
|
|
|
|
buildLabel string = "build"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// TrySetupHCP attempts to setup the HCP-related structures if HCP is enabled
|
|
|
|
|
// for the command
|
|
|
|
|
// TrySetupHCP attempts to configure the HCP-related structures if
|
|
|
|
|
// Packer has been configured to publish to a HCP Packer registry.
|
|
|
|
|
func TrySetupHCP(cfg packer.Handler) hcl.Diagnostics {
|
|
|
|
|
switch cfg := cfg.(type) {
|
|
|
|
|
case *hcl2template.PackerConfig:
|
|
|
|
|
@ -38,7 +46,7 @@ func TrySetupHCP(cfg packer.Handler) hcl.Diagnostics {
|
|
|
|
|
&hcl.Diagnostic{
|
|
|
|
|
Severity: hcl.DiagError,
|
|
|
|
|
Summary: "unknown Handler type",
|
|
|
|
|
Detail: "SetupRegistry called with an unknown Handler. " +
|
|
|
|
|
Detail: "TrySetupHCP called with an unknown Handler. " +
|
|
|
|
|
"This is a Packer bug and should be brought to the attention " +
|
|
|
|
|
"of the Packer team, please consider opening an issue for this.",
|
|
|
|
|
},
|
|
|
|
|
@ -46,33 +54,32 @@ func TrySetupHCP(cfg packer.Handler) hcl.Diagnostics {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func setupRegistryForPackerConfig(pc *hcl2template.PackerConfig) hcl.Diagnostics {
|
|
|
|
|
var diags hcl.Diagnostics
|
|
|
|
|
|
|
|
|
|
// HCP_PACKER_REGISTRY is explicitly turned off
|
|
|
|
|
if env.IsHCPDisabled() {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hasHCP := false
|
|
|
|
|
mode := HCPConfigUnset
|
|
|
|
|
|
|
|
|
|
// TODO move into ConfigCheck
|
|
|
|
|
for _, build := range pc.Builds {
|
|
|
|
|
if build.HCPPackerRegistry != nil {
|
|
|
|
|
hasHCP = true
|
|
|
|
|
mode = HCPConfigEnabled
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if env.HasPackerRegistryBucket() {
|
|
|
|
|
hasHCP = true
|
|
|
|
|
// HCP_PACKER_BUCKET_NAME is set or HCP_PACKER_REGISTRY not toggled off
|
|
|
|
|
if mode == HCPConfigUnset && (env.HasPackerRegistryBucket() || env.IsHCPExplicitelyEnabled()) {
|
|
|
|
|
mode = HCPEnvEnabled
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if env.IsHCPExplicitelyEnabled() {
|
|
|
|
|
hasHCP = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !hasHCP {
|
|
|
|
|
if mode == HCPConfigUnset {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if hasHCP && len(pc.Builds) > 1 {
|
|
|
|
|
var diags hcl.Diagnostics
|
|
|
|
|
if len(pc.Builds) > 1 {
|
|
|
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
|
|
|
Severity: hcl.DiagError,
|
|
|
|
|
Summary: "Multiple " + buildLabel + " blocks",
|
|
|
|
|
@ -81,73 +88,42 @@ func setupRegistryForPackerConfig(pc *hcl2template.PackerConfig) hcl.Diagnostics
|
|
|
|
|
" block(s). If this " + buildLabel + " is not meant for the Packer registry please " +
|
|
|
|
|
"clear any HCP_PACKER_* environment variables."),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var err error
|
|
|
|
|
pc.Bucket, err = registry.NewBucketWithIteration(registry.IterationOptions{
|
|
|
|
|
TemplateBaseDir: pc.Basedir,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
|
|
|
Summary: "Unable to create a valid bucket object for HCP Packer Registry",
|
|
|
|
|
Detail: fmt.Sprintf("%s", err),
|
|
|
|
|
Severity: hcl.DiagError,
|
|
|
|
|
})
|
|
|
|
|
return diags
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Configure HCP Packer Registry destination
|
|
|
|
|
bucketSlug := os.Getenv(env.HCPPackerBucket)
|
|
|
|
|
|
|
|
|
|
if pc.Bucket != nil {
|
|
|
|
|
pc.Bucket.LoadDefaultSettingsFromEnv()
|
|
|
|
|
|
|
|
|
|
pc.Bucket.Slug = bucketSlug
|
|
|
|
|
|
|
|
|
|
for _, build := range pc.Builds {
|
|
|
|
|
build.HCPPackerRegistry.WriteToBucketConfig(pc.Bucket)
|
|
|
|
|
bucketSlug = pc.Bucket.Slug
|
|
|
|
|
|
|
|
|
|
WithHCLBucketConfigurtationOpts := func(bb *hcl2template.BuildBlock) func(*registry.Bucket) {
|
|
|
|
|
return func(bucket *registry.Bucket) {
|
|
|
|
|
bb.HCPPackerRegistry.WriteToBucketConfig(bucket)
|
|
|
|
|
// If at this point the bucket.Slug is still empty,
|
|
|
|
|
// last try is to use the build.Name if present
|
|
|
|
|
if bucketSlug == "" && build.Name != "" {
|
|
|
|
|
bucketSlug = build.Name
|
|
|
|
|
if bucket.Slug == "" && bb.Name != "" {
|
|
|
|
|
bucket.Slug = bb.Name
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the description is empty, use the one from the build block
|
|
|
|
|
if pc.Bucket.Description == "" {
|
|
|
|
|
pc.Bucket.Description = build.Description
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, source := range build.Sources {
|
|
|
|
|
pc.Bucket.RegisterBuildForComponent(source.String())
|
|
|
|
|
if bucket.Description == "" && bb.Description != "" {
|
|
|
|
|
bucket.Description = bb.Description
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !env.HasHCPCredentials() {
|
|
|
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
|
|
|
Summary: "HCP authentication information required",
|
|
|
|
|
Detail: fmt.Sprintf("The client authentication requires both %s and %s environment "+
|
|
|
|
|
"variables to be set for authenticating with HCP.",
|
|
|
|
|
env.HCPClientID,
|
|
|
|
|
env.HCPClientSecret),
|
|
|
|
|
Severity: hcl.DiagError,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
build := pc.Builds[0]
|
|
|
|
|
pc.Bucket, diags = createConfiguredBucket(
|
|
|
|
|
pc.Basedir,
|
|
|
|
|
WithPackerEnvConfigurationOpts,
|
|
|
|
|
WithHCLBucketConfigurtationOpts(build),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if bucketSlug == "" {
|
|
|
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
|
|
|
Summary: "bucket name cannot be empty",
|
|
|
|
|
Detail: "empty bucket name, please set it with the HCP_PACKER_BUCKET_NAME environment variable, or in a `hcp_packer_registry` block",
|
|
|
|
|
Severity: hcl.DiagError,
|
|
|
|
|
})
|
|
|
|
|
if diags.HasErrors() {
|
|
|
|
|
return diags
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if pc.Bucket != nil {
|
|
|
|
|
pc.Bucket.Slug = bucketSlug
|
|
|
|
|
for _, source := range build.Sources {
|
|
|
|
|
pc.Bucket.RegisterBuildForComponent(source.String())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Lets Move this
|
|
|
|
|
vals, dsDiags := pc.Datasources.Values()
|
|
|
|
|
if dsDiags != nil {
|
|
|
|
|
diags = append(diags, dsDiags...)
|
|
|
|
|
@ -163,6 +139,7 @@ func setupRegistryForPackerConfig(pc *hcl2template.PackerConfig) hcl.Diagnostics
|
|
|
|
|
|
|
|
|
|
iterations := map[string]iterds.DatasourceOutput{}
|
|
|
|
|
|
|
|
|
|
var err error
|
|
|
|
|
if iterOK {
|
|
|
|
|
hcpData := map[string]cty.Value{}
|
|
|
|
|
err = gocty.FromCtyValue(iterDS, &hcpData)
|
|
|
|
|
@ -225,6 +202,90 @@ func setupRegistryForPackerConfig(pc *hcl2template.PackerConfig) hcl.Diagnostics
|
|
|
|
|
return diags
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func setupRegistryForPackerCore(cfg *CoreWrapper) hcl.Diagnostics {
|
|
|
|
|
if env.IsHCPDisabled() {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !env.HasPackerRegistryBucket() && !env.IsHCPExplicitelyEnabled() {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
core := cfg.Core
|
|
|
|
|
bucket, diags := createConfiguredBucket(
|
|
|
|
|
filepath.Dir(core.Template.Path),
|
|
|
|
|
WithPackerEnvConfigurationOpts,
|
|
|
|
|
)
|
|
|
|
|
if diags.HasErrors() {
|
|
|
|
|
return diags
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
core.Bucket = bucket
|
|
|
|
|
for _, b := range core.Template.Builders {
|
|
|
|
|
// Get all builds slated within config ignoring any only or exclude flags.
|
|
|
|
|
core.Bucket.RegisterBuildForComponent(b.Name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return diags
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func createConfiguredBucket(templateDir string, opts ...func(*registry.Bucket)) (*registry.Bucket, hcl.Diagnostics) {
|
|
|
|
|
var diags hcl.Diagnostics
|
|
|
|
|
|
|
|
|
|
if !env.HasHCPCredentials() {
|
|
|
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
|
|
|
Summary: "HCP authentication information required",
|
|
|
|
|
Detail: fmt.Sprintf("The client authentication requires both %s and %s environment "+
|
|
|
|
|
"variables to be set for authenticating with HCP.",
|
|
|
|
|
env.HCPClientID,
|
|
|
|
|
env.HCPClientSecret),
|
|
|
|
|
Severity: hcl.DiagError,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bucket, err := registry.NewBucketWithIteration(registry.IterationOptions{
|
|
|
|
|
TemplateBaseDir: templateDir,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// This error needs to be reworded.
|
|
|
|
|
if err != nil {
|
|
|
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
|
|
|
Summary: "Unable to create a valid bucket object for HCP Packer Registry",
|
|
|
|
|
Detail: fmt.Sprintf("%s", err),
|
|
|
|
|
Severity: hcl.DiagError,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return nil, diags
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, opt := range opts {
|
|
|
|
|
opt(bucket)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if bucket.Slug == "" {
|
|
|
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
|
|
|
Summary: "bucket name cannot be empty",
|
|
|
|
|
Detail: "empty bucket name, please set it with the HCP_PACKER_BUCKET_NAME environment variable, or in a `hcp_packer_registry` block",
|
|
|
|
|
Severity: hcl.DiagError,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return nil, diags
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return bucket, diags
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func WithPackerEnvConfigurationOpts(pc *registry.Bucket) {
|
|
|
|
|
// Add default values for Packer settings configured via EnvVars.
|
|
|
|
|
// TODO look to break this up to be more explicit on what is loaded here.
|
|
|
|
|
pc.LoadDefaultSettingsFromEnv()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// load handler
|
|
|
|
|
// validate HCP Mode is on
|
|
|
|
|
// Validate we have all the bits to connect
|
|
|
|
|
// Build a connected client
|
|
|
|
|
|
|
|
|
|
func imageValueToDSOutput(imageVal map[string]cty.Value) imgds.DatasourceOutput {
|
|
|
|
|
dso := imgds.DatasourceOutput{}
|
|
|
|
|
for k, v := range imageVal {
|
|
|
|
|
@ -289,61 +350,3 @@ func iterValueToDSOutput(iterVal map[string]cty.Value) iterds.DatasourceOutput {
|
|
|
|
|
}
|
|
|
|
|
return dso
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func setupRegistryForPackerCore(cfg *CoreWrapper) hcl.Diagnostics {
|
|
|
|
|
if env.IsHCPDisabled() {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !env.HasPackerRegistryBucket() && !env.IsHCPExplicitelyEnabled() {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var diags hcl.Diagnostics
|
|
|
|
|
|
|
|
|
|
if !env.HasHCPCredentials() {
|
|
|
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
|
|
|
Summary: "missing authentication information",
|
|
|
|
|
Detail: fmt.Sprintf("the client authentication requires both %s and %s environment variables to be set", env.HCPClientID, env.HCPClientSecret),
|
|
|
|
|
Severity: hcl.DiagError,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
|
|
core := cfg.Core
|
|
|
|
|
|
|
|
|
|
core.Bucket, err = registry.NewBucketWithIteration(registry.IterationOptions{
|
|
|
|
|
TemplateBaseDir: filepath.Dir(core.Template.Path),
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
|
|
|
Summary: "bucket creation failure",
|
|
|
|
|
Detail: fmt.Sprintf("failed to create Bucket: %s", err),
|
|
|
|
|
Severity: hcl.DiagError,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Configure HCP Packer Registry destination
|
|
|
|
|
bucketSlug := os.Getenv(env.HCPPackerBucket)
|
|
|
|
|
|
|
|
|
|
if bucketSlug == "" {
|
|
|
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
|
|
|
Summary: "bucket name cannot be empty",
|
|
|
|
|
Detail: "empty bucket name, please set it with the HCP_PACKER_BUCKET_NAME environment variable",
|
|
|
|
|
Severity: hcl.DiagError,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if core.Bucket != nil {
|
|
|
|
|
core.Bucket.Slug = bucketSlug
|
|
|
|
|
core.Bucket.LoadDefaultSettingsFromEnv()
|
|
|
|
|
|
|
|
|
|
for _, b := range core.Template.Builders {
|
|
|
|
|
// Get all builds slated within config ignoring any only or exclude flags.
|
|
|
|
|
core.Bucket.RegisterBuildForComponent(b.Name)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return diags
|
|
|
|
|
}
|
|
|
|
|
|