mirror of
https://github.com/hashicorp/packer.git
synced 2026-10-31 10:28:23 -04:00
* Update HCP Packer build labels argument Previously when running a partial build on multi-cloud build template it was found that build labels were only being applied at the creation for the partially executed build. Leaving all other completed builds with no HCP Packer build labels. This updates how incomplete builds are loaded from the registry and ensure that any defined hcp_packer_registry.build_labels are assigned to the build before starting an actual Packer build. Related to: #11573 * Add test case for overwriting build labels * Update tests to call CreateInitialBuild for non-existing builds * Rename test case to TestBucket_PopulateIteration * Fix data race in PopulateIteration against mock service Before Change ``` WARNING: DATA RACE Write at 0x00c0005421b0 by goroutine 47: github.com/hashicorp/packer/internal/registry.(*MockPackerClientService).PackerServiceCreateBuild() /Users/scrubbed/Development/packer/internal/registry/mock_service.go:173 +0x2b6 github.com/hashicorp/packer/internal/registry.(*Client).CreateBuild() /Users/scrubbed/Development/packer/internal/registry/service.go:169 +0x592 github.com/hashicorp/packer/internal/registry.(*Bucket).CreateInitialBuildForIteration() /Users/scrubbed/Development/packer/internal/registry/types.bucket.go:107 +0x204 github.com/hashicorp/packer/internal/registry.(*Bucket).PopulateIteration.func1() /Users/scrubbed/Development/packer/internal/registry/types.bucket.go:368 +0x14e github.com/hashicorp/packer/internal/registry.(*Bucket).PopulateIteration·dwrap·1() /Users/scrubbed/Development/packer/internal/registry/types.bucket.go:376 +0x58 Previous write at 0x00c0005421b0 by goroutine 46: github.com/hashicorp/packer/internal/registry.(*MockPackerClientService).PackerServiceCreateBuild() /Users/scrubbed/Development/packer/internal/registry/mock_service.go:173 +0x2b6 github.com/hashicorp/packer/internal/registry.(*Client).CreateBuild() /Users/scrubbed/Development/packer/internal/registry/service.go:169 +0x592 github.com/hashicorp/packer/internal/registry.(*Bucket).CreateInitialBuildForIteration() /Users/scrubbed/Development/packer/internal/registry/types.bucket.go:107 +0x204 github.com/hashicorp/packer/internal/registry.(*Bucket).PopulateIteration.func1() /Users/scrubbed/Development/packer/internal/registry/types.bucket.go:368 +0x14e github.com/hashicorp/packer/internal/registry.(*Bucket).PopulateIteration·dwrap·1() /Users/scrubbed/Development/packer/internal/registry/types.bucket.go:376 +0x58 Goroutine 47 (running) created at: github.com/hashicorp/packer/internal/registry.(*Bucket).PopulateIteration() /Users/scrubbed/Development/packer/internal/registry/types.bucket.go:362 +0x5c7 github.com/hashicorp/packer/internal/registry.TestBucket_UpdateLabelsForBuild_withMultipleBuilds() /Users/scrubbed/Development/packer/internal/registry/types.bucket_test.go:179 +0xf7 testing.tRunner() /usr/local/go/src/testing/testing.go:1259 +0x22f testing.(*T).Run·dwrap·21() /usr/local/go/src/testing/testing.go:1306 +0x47 Goroutine 46 (finished) created at: github.com/hashicorp/packer/internal/registry.(*Bucket).PopulateIteration() /Users/scrubbed/Development/packer/internal/registry/types.bucket.go:362 +0x5c7 github.com/hashicorp/packer/internal/registry.TestBucket_UpdateLabelsForBuild_withMultipleBuilds() /Users/scrubbed/Development/packer/internal/registry/types.bucket_test.go:179 +0xf7 testing.tRunner() /usr/local/go/src/testing/testing.go:1259 +0x22f testing.(*T).Run·dwrap·21() /usr/local/go/src/testing/testing.go:1306 +0x47 ================== ``` * Add methods for managing builds on an Iteration * Update Mock Service to be a bit more concurrent It is a simple set of changes to make it work for the current testing use cases. If we need to we can move the Called fields to counters or re-architect the mock. This change also fixes a race condition when appending to the Slice of errs when calling PopulateIteration. * Update test case descriptions * Apply suggestions from code review Only append to errs if err is not nil Co-authored-by: Sylvia Moss <[email protected]> * Fix linting issues Co-authored-by: Sylvia Moss <[email protected]>
140 lines
4.0 KiB
Go
140 lines
4.0 KiB
Go
package registry
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"sync"
|
|
|
|
git "github.com/go-git/go-git/v5"
|
|
registryimage "github.com/hashicorp/packer-plugin-sdk/packer/registry/image"
|
|
)
|
|
|
|
type Iteration struct {
|
|
ID string
|
|
AncestorSlug string
|
|
Fingerprint string
|
|
RunUUID string
|
|
Labels map[string]string
|
|
builds sync.Map
|
|
expectedBuilds []string
|
|
}
|
|
|
|
type IterationOptions struct {
|
|
TemplateBaseDir string
|
|
}
|
|
|
|
// NewIteration returns a pointer to an Iteration that can be used for storing Packer build details needed by PAR.
|
|
func NewIteration(opts IterationOptions) (*Iteration, error) {
|
|
i := Iteration{
|
|
expectedBuilds: make([]string, 0),
|
|
}
|
|
|
|
// By default we try to load a Fingerprint from the environment variable.
|
|
// If no variable is defined we should try to load a fingerprint from Git, or other VCS.
|
|
i.Fingerprint = os.Getenv("HCP_PACKER_BUILD_FINGERPRINT")
|
|
|
|
// get a Git SHA
|
|
if i.Fingerprint != "" {
|
|
return &i, nil
|
|
}
|
|
|
|
fp, err := GetGitFingerprint(opts)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
i.Fingerprint = fp
|
|
return &i, nil
|
|
}
|
|
|
|
// GetGitFingerprint returns the HEAD commit for some template dir defined in opt.TemplateBaseDir.
|
|
// If the base directory is not under version control an error is returned.
|
|
func GetGitFingerprint(opts IterationOptions) (string, error) {
|
|
r, err := git.PlainOpenWithOptions(opts.TemplateBaseDir, &git.PlainOpenOptions{
|
|
DetectDotGit: true,
|
|
})
|
|
|
|
if err != nil {
|
|
return "", fmt.Errorf("Packer was unable to load a git sha. "+
|
|
"If your Packer template is not in a git repo, please add a unique "+
|
|
"template fingerprint using the env var HCP_PACKER_BUILD_FINGERPRINT. "+
|
|
"Error: %s", err)
|
|
}
|
|
|
|
// 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 {
|
|
return "", fmt.Errorf("Packer encountered an issue reading the git info for the path %q.\n"+
|
|
"If your Packer template is not in a git repo, please add a unique "+
|
|
"template fingerprint using the env var HCP_PACKER_BUILD_FINGERPRINT. "+
|
|
"Error: %s", opts.TemplateBaseDir, err)
|
|
}
|
|
|
|
// log.Printf("Author: %v, Commit: %v\n", c.User.Email, ref.Hash())
|
|
|
|
return ref.Hash().String(), nil
|
|
}
|
|
|
|
//StoreBuild stores a build for buildName to an active iteration.
|
|
func (i *Iteration) StoreBuild(buildName string, build *Build) {
|
|
i.builds.Store(buildName, build)
|
|
}
|
|
|
|
//Build gets the store build associated with buildName in the active iteration.
|
|
func (i *Iteration) Build(buildName string) (*Build, error) {
|
|
build, ok := i.builds.Load(buildName)
|
|
if !ok {
|
|
return nil, errors.New("no associated build found for the name " + buildName)
|
|
}
|
|
|
|
b, ok := build.(*Build)
|
|
if !ok {
|
|
return nil, fmt.Errorf("the build for the component %q does not appear to be a valid registry Build", buildName)
|
|
}
|
|
|
|
return b, nil
|
|
}
|
|
|
|
//HasBuild checks if iteration has a stored build associated with buildName.
|
|
func (i *Iteration) HasBuild(buildName string) bool {
|
|
_, ok := i.builds.Load(buildName)
|
|
|
|
return ok
|
|
}
|
|
|
|
// AddImageToBuild appends one or more images artifacts to the build referred to by buildName.
|
|
func (i *Iteration) AddImageToBuild(buildName string, images ...registryimage.Image) error {
|
|
build, err := i.Build(buildName)
|
|
if err != nil {
|
|
return fmt.Errorf("AddImageToBuild: %w", err)
|
|
}
|
|
|
|
err = build.AddImages(images...)
|
|
if err != nil {
|
|
return fmt.Errorf("AddImageToBuild: %w", err)
|
|
}
|
|
|
|
i.StoreBuild(buildName, build)
|
|
return nil
|
|
}
|
|
|
|
// AddLabelsToBuild merges the contents of data to the labels associated with the build referred to by buildName.
|
|
func (i *Iteration) AddLabelsToBuild(buildName string, data map[string]string) error {
|
|
build, err := i.Build(buildName)
|
|
if err != nil {
|
|
return fmt.Errorf("AddLabelsToBuild: %w", err)
|
|
}
|
|
|
|
build.MergeLabels(data)
|
|
|
|
i.StoreBuild(buildName, build)
|
|
return nil
|
|
}
|