github.com/hashicorp/packer@v1.14.3/internal/hcp/registry/hcp.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package registry
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/go-git/go-git/v5"
    10  	"github.com/hashicorp/hcl/v2"
    11  	"github.com/hashicorp/packer/hcl2template"
    12  	"github.com/hashicorp/packer/internal/hcp/env"
    13  	"github.com/hashicorp/packer/packer"
    14  )
    15  
    16  // HCPConfigMode types specify the mode in which HCP configuration
    17  // is defined for a given Packer build execution.
    18  type HCPConfigMode int
    19  
    20  const (
    21  	// HCPConfigUnset mode is set when no HCP configuration has been found for the Packer execution.
    22  	HCPConfigUnset HCPConfigMode = iota
    23  	// HCPConfigEnabled mode is set when the HCP configuration is codified in the template.
    24  	HCPConfigEnabled
    25  	// HCPEnvEnabled mode is set when the HCP configuration is read from environment variables.
    26  	HCPEnvEnabled
    27  )
    28  
    29  type bucketConfigurationOpts func(*Bucket) hcl.Diagnostics
    30  
    31  // IsHCPEnabled returns true if HCP integration is enabled for a build
    32  func IsHCPEnabled(cfg packer.Handler) bool {
    33  	// HCP_PACKER_REGISTRY is explicitly turned off
    34  	if env.IsHCPDisabled() {
    35  		return false
    36  	}
    37  
    38  	mode := HCPConfigUnset
    39  
    40  	switch config := cfg.(type) {
    41  	case *hcl2template.PackerConfig:
    42  		for _, build := range config.Builds {
    43  			if build.HCPPackerRegistry != nil {
    44  				mode = HCPConfigEnabled
    45  			}
    46  		}
    47  		if config.HCPPackerRegistry != nil {
    48  			mode = HCPConfigEnabled
    49  		}
    50  	}
    51  
    52  	// HCP_PACKER_BUCKET_NAME is set or HCP_PACKER_REGISTRY not toggled off
    53  	if mode == HCPConfigUnset && (env.HasPackerRegistryBucket() || env.IsHCPExplicitelyEnabled()) {
    54  		mode = HCPEnvEnabled
    55  	}
    56  
    57  	return mode != HCPConfigUnset
    58  }
    59  
    60  // createConfiguredBucket returns a bucket that can be used for connecting to the HCP Packer registry.
    61  // Configuration for the bucket is obtained from the base iteration setting and any addition configuration
    62  // options passed in as opts. All errors during configuration are collected and returned as Diagnostics.
    63  func createConfiguredBucket(templateDir string, opts ...bucketConfigurationOpts) (*Bucket, hcl.Diagnostics) {
    64  	var diags hcl.Diagnostics
    65  
    66  	hasAuth, err := env.HasHCPAuth()
    67  	if err != nil {
    68  		diags = append(diags, &hcl.Diagnostic{
    69  			Summary:  "HCP authentication check failed",
    70  			Detail:   fmt.Sprintf("Failed to check for HCP authentication, error: %s", err.Error()),
    71  			Severity: hcl.DiagError,
    72  		})
    73  	} else if !hasAuth {
    74  		diags = append(diags, &hcl.Diagnostic{
    75  			Summary:  "HCP authentication information required",
    76  			Detail:   fmt.Sprintf("HCP Authentication not configured, either set an HCP Client ID and secret using the environment variables %s and %s, place an HCP credential file in the default path (%s), or at a different path specified in the %s environment variable.", env.HCPClientID, env.HCPClientSecret, env.HCPDefaultCredFilePath, env.HCPCredFile),
    77  			Severity: hcl.DiagError,
    78  		})
    79  	}
    80  
    81  	bucket := NewBucketWithVersion()
    82  
    83  	for _, opt := range opts {
    84  		if optDiags := opt(bucket); optDiags.HasErrors() {
    85  			diags = append(diags, optDiags...)
    86  		}
    87  	}
    88  
    89  	if bucket.Name == "" {
    90  		diags = append(diags, &hcl.Diagnostic{
    91  			Summary: "Bucket name required",
    92  			Detail: "You must provide a bucket name for HCP Packer builds. " +
    93  				"You can set the HCP_PACKER_BUCKET_NAME environment variable. " +
    94  				"For HCL2 templates, the registry either uses the name of your " +
    95  				"template's build block, or you can set the bucket_name argument " +
    96  				"in an hcp_packer_registry block.",
    97  			Severity: hcl.DiagError,
    98  		})
    99  	}
   100  
   101  	err = bucket.Version.Initialize()
   102  	if err != nil {
   103  		diags = append(diags, &hcl.Diagnostic{
   104  			Summary: "Version initialization failed",
   105  			Detail: fmt.Sprintf("Initialization of the version failed with "+
   106  				"the following error message: %s", err),
   107  			Severity: hcl.DiagError,
   108  		})
   109  	}
   110  	return bucket, diags
   111  }
   112  
   113  func withPackerEnvConfiguration(bucket *Bucket) hcl.Diagnostics {
   114  	// Add default values for Packer settings configured via EnvVars.
   115  	// TODO look to break this up to be more explicit on what is loaded here.
   116  	bucket.LoadDefaultSettingsFromEnv()
   117  
   118  	return nil
   119  }
   120  
   121  // getGitSHA returns the HEAD commit for some template dir defined in baseDir.
   122  // If the base directory is not under version control an error is returned.
   123  func getGitSHA(baseDir string) (string, error) {
   124  	r, err := git.PlainOpenWithOptions(baseDir, &git.PlainOpenOptions{
   125  		DetectDotGit: true,
   126  	})
   127  
   128  	if err != nil {
   129  		return "", fmt.Errorf("Packer could not read the fingerprint from git.")
   130  	}
   131  
   132  	// The config can be used to retrieve user identity. for example,
   133  	// c.User.Email. Leaving in but commented because I'm not sure we care
   134  	// about this identity right now. - Megan
   135  	//
   136  	// c, err := r.ConfigScoped(config.GlobalScope)
   137  	// if err != nil {
   138  	//      return "", fmt.Errorf("Error setting git scope", err)
   139  	// }
   140  	ref, err := r.Head()
   141  	if err != nil {
   142  		// If we get there, we're in a Git dir, but HEAD cannot be read.
   143  		//
   144  		// This may happen when there's no commit in the git dir.
   145  		return "", fmt.Errorf("Packer could not read a git SHA in directory %q: %s", baseDir, err)
   146  	}
   147  
   148  	// log.Printf("Author: %v, Commit: %v\n", c.User.Email, ref.Hash())
   149  
   150  	return ref.Hash().String(), nil
   151  }