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

Update HCP Packer build labels when re-running Packer on an incomplete build #11584

Merged
merged 10 commits into from
Feb 25, 2022

Conversation

nywilken
Copy link
Contributor

@nywilken nywilken commented Feb 22, 2022

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 ensures that any defined hcp_packer_registry.build_labels are assigned to the build before starting an actual Packer build.

Related to: #11573

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
@nywilken nywilken requested a review from a team as a code owner February 22, 2022 21:20
@nywilken nywilken changed the title wilken/fix build labels for partial builds Update HCP Packer build labels when re-running Packer on an incomplete build Feb 22, 2022
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
==================
```
@nywilken nywilken force-pushed the wilken/fix-build-labels-for-partial-builds branch from df8ae13 to c80d9e0 Compare February 23, 2022 11:06
noDiffExpected: false,
},
{
desc: "existing incomplete build with extra previously set build label",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me see if I got it right, if I rerun an incomplete iteration, can I add more build labels the second time I try building it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No wait, is it the other way around? If I'm trying to complete an existing iteration, I can't update labels?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is actually the first one, but the example is a little confusing. Right now if a user sets one build label and the build fails for whatever reason the build label will get persisted. Now lets say when they rerun the failed build they decide to add a few extra build labels the new labels will get added but the old label will not get removed.

If the value for the previous label is modified the old persisted label will get updated to reflect the new value.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh got it! I understood that aftewards. Makes sense!

log.Printf("[TRACE] build %s already exists in Packer registry, continuing...", name)
return
}

errs = multierror.Append(errs, err)
}(buildName)
wg.Wait()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did this one move inside the for?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was moved to fix a race condition that is introduced by calling CreateBuild on the MockService. By spawning off multiple routines for the CreateBuild the Mock Data is overwritten before it can be read resulting in a data race. This change makes it a bit more sequential. Maybe the correct change should be to leave it as it as and add a mutex to the Mock Client to prevent overwrites.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, now it will always wait for the goroutine before proceeding with the loop. I would either remove th goroutine here or fix the mutex. 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I updated the Mock service a little to be a bit more concurrent. It is a hack TBH but it works for the testing purposes. In doing so I found a race condition with the appending of errors so that it good.

func (b *Build) IsNotDone() bool {
hasBuildID := b.ID != ""
hasImages := len(b.Images) == 0
isNotDone := b.Status != models.HashicorpCloudPackerBuildStatusDONE
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this validation be enough?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe so. Do you think we should validate something else?

The rationale is as follows:

  1. A build without and Id has not been registered on the registry therefore it doesn't exist and not worth considering.
  2. A build that exists on the registry with no images is by the service specs not done.
  3. An image can only be set to the done status if it has at least one image.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I confused you. I was saying that this validation isNotDone := b.Status != models.HashicorpCloudPackerBuildStatusDONE I expected to be enough 🤔
I'm wanted to know if you had any other use cases that this wasn't enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah got it. This might be artifact of an edge case earlier on where we may have created or put a build in a done status without having images.But I can't recall immediately. I believe the API does not allow a build to be put in the DONE status without images so that check might not be needed

I have to review previous commits and notes before looking to remove the other conditions 😄

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.
@nywilken nywilken force-pushed the wilken/fix-build-labels-for-partial-builds branch from 112f368 to a3898f6 Compare February 23, 2022 18:53
Only append to errs if err is not nil

Co-authored-by: Sylvia Moss <moss@hashicorp.com>
Copy link
Contributor

@sylviamoss sylviamoss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

@nywilken nywilken merged commit dd525fb into master Feb 25, 2022
@nywilken nywilken deleted the wilken/fix-build-labels-for-partial-builds branch February 25, 2022 20:50
@azr
Copy link
Contributor

azr commented Feb 28, 2022

Nice one !

@github-actions
Copy link

I'm going to lock this pull request because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.
If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 31, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants