blob: 838350b76412a4d7dea50b5b277cad470697ff53 [file] [log] [blame]
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package registry
import (
"fmt"
git "github.com/go-git/go-git/v5"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/packer/hcl2template"
"github.com/hashicorp/packer/internal/hcp/env"
"github.com/hashicorp/packer/packer"
)
// HCPConfigMode types specify the mode in which HCP configuration
// is defined for a given Packer build execution.
type HCPConfigMode int
const (
// HCPConfigUnset mode is set when no HCP configuration has been found for the Packer execution.
HCPConfigUnset HCPConfigMode = iota
// HCPConfigEnabled mode is set when the HCP configuration is codified in the template.
HCPConfigEnabled
// HCPEnvEnabled mode is set when the HCP configuration is read from environment variables.
HCPEnvEnabled
)
type bucketConfigurationOpts func(*Bucket) hcl.Diagnostics
// IsHCPEnabled returns true if HCP integration is enabled for a build
func IsHCPEnabled(cfg packer.Handler) bool {
// HCP_PACKER_REGISTRY is explicitly turned off
if env.IsHCPDisabled() {
return false
}
mode := HCPConfigUnset
switch config := cfg.(type) {
case *hcl2template.PackerConfig:
for _, build := range config.Builds {
if build.HCPPackerRegistry != nil {
mode = HCPConfigEnabled
}
}
}
// HCP_PACKER_BUCKET_NAME is set or HCP_PACKER_REGISTRY not toggled off
if mode == HCPConfigUnset && (env.HasPackerRegistryBucket() || env.IsHCPExplicitelyEnabled()) {
mode = HCPEnvEnabled
}
return mode != HCPConfigUnset
}
// createConfiguredBucket returns a bucket that can be used for connecting to the HCP Packer registry.
// Configuration for the bucket is obtained from the base iteration setting and any addition configuration
// options passed in as opts. All errors during configuration are collected and returned as Diagnostics.
func createConfiguredBucket(templateDir string, opts ...bucketConfigurationOpts) (*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 := NewBucketWithIteration()
for _, opt := range opts {
if optDiags := opt(bucket); optDiags.HasErrors() {
diags = append(diags, optDiags...)
}
}
if bucket.Slug == "" {
diags = append(diags, &hcl.Diagnostic{
Summary: "Image bucket name required",
Detail: "You must provide an image bucket name for HCP Packer builds. " +
"You can set the HCP_PACKER_BUCKET_NAME environment variable. " +
"For HCL2 templates, the registry either uses the name of your " +
"template's build block, or you can set the bucket_name argument " +
"in an hcp_packer_registry block.",
Severity: hcl.DiagError,
})
}
err := bucket.Iteration.Initialize()
if err != nil {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Failed to initialize iteration",
Detail: fmt.Sprintf("The iteration failed to be initialized for bucket %q: %s",
bucket.Slug, err),
})
}
if err != nil {
diags = append(diags, &hcl.Diagnostic{
Summary: "Iteration initialization failed",
Detail: fmt.Sprintf("Initialization of the iteration failed with "+
"the following error message: %s", err),
Severity: hcl.DiagError,
})
}
return bucket, diags
}
func withPackerEnvConfiguration(bucket *Bucket) hcl.Diagnostics {
// Add default values for Packer settings configured via EnvVars.
// TODO look to break this up to be more explicit on what is loaded here.
bucket.LoadDefaultSettingsFromEnv()
return nil
}
// getGitSHA returns the HEAD commit for some template dir defined in baseDir.
// If the base directory is not under version control an error is returned.
func getGitSHA(baseDir string) (string, error) {
r, err := git.PlainOpenWithOptions(baseDir, &git.PlainOpenOptions{
DetectDotGit: true,
})
if err != nil {
return "", fmt.Errorf("Packer could not read the fingerprint from git.")
}
// The config can be used to retrieve user identity. for example,
// c.User.Email. Leaving in but commented because I'm not sure we care
// about this identity right now. - Megan
//
// c, err := r.ConfigScoped(config.GlobalScope)
// if err != nil {
// return "", fmt.Errorf("Error setting git scope", err)
// }
ref, err := r.Head()
if err != nil {
// If we get there, we're in a Git dir, but HEAD cannot be read.
//
// This may happen when there's no commit in the git dir.
return "", fmt.Errorf("Packer could not read a git SHA in directory %q: %s", baseDir, err)
}
// log.Printf("Author: %v, Commit: %v\n", c.User.Email, ref.Hash())
return ref.Hash().String(), nil
}