mirror of https://github.com/hashicorp/packer
parent
f0d0a0e6c5
commit
f3e4c2c3bb
@ -1,4 +1,4 @@
|
||||
package packer
|
||||
package registry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -1,102 +0,0 @@
|
||||
package packer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/hcp-sdk-go/clients/cloud-packer-service/stable/2021-04-30/models"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
registryimage "github.com/hashicorp/packer-plugin-sdk/packer/registry/image"
|
||||
packerregistry "github.com/hashicorp/packer/internal/registry"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
type RegistryBuilder struct {
|
||||
Name string
|
||||
ArtifactMetadataPublisher *packerregistry.Bucket
|
||||
packersdk.Builder
|
||||
}
|
||||
|
||||
func (b *RegistryBuilder) Prepare(raws ...interface{}) ([]string, []string, error) {
|
||||
return b.Builder.Prepare(raws...)
|
||||
}
|
||||
|
||||
// Run is where the actual build should take place. It takes a Build and a Ui.
|
||||
func (b *RegistryBuilder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) (packersdk.Artifact, error) {
|
||||
|
||||
if !b.ArtifactMetadataPublisher.IsExpectingBuildForComponent(b.Name) {
|
||||
ui.Error(fmt.Sprintf("The build for %q in iteration %q has already been marked as DONE; Skipping build to prevent drift.", b.Name, b.ArtifactMetadataPublisher.Iteration.ID))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
runCompleted := make(chan struct{})
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
log.Printf("[TRACE] marking build %q as cancelled in HCP Packer registry", b.Name)
|
||||
if err := b.ArtifactMetadataPublisher.UpdateBuildStatus(context.TODO(), b.Name, models.HashicorpCloudPackerBuildStatusCANCELLED); err != nil {
|
||||
log.Printf("[TRACE] failed to update HCP Packer registry status for %q: %s", b.Name, err)
|
||||
}
|
||||
return
|
||||
case <-runCompleted:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if err := b.ArtifactMetadataPublisher.UpdateBuildStatus(ctx, b.Name, models.HashicorpCloudPackerBuildStatusRUNNING); err != nil {
|
||||
log.Printf("[TRACE] failed to update HCP Packer registry status for %q: %s", b.Name, err)
|
||||
}
|
||||
|
||||
cleanupHeartbeat, err := b.ArtifactMetadataPublisher.HeartbeatBuild(ctx, b.Name)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] failed to start heartbeat function")
|
||||
}
|
||||
if cleanupHeartbeat != nil {
|
||||
defer cleanupHeartbeat()
|
||||
}
|
||||
|
||||
ui.Say(fmt.Sprintf("Publishing build details for %s to the HCP Packer registry", b.Name))
|
||||
artifact, err := b.Builder.Run(ctx, ui, hook)
|
||||
if err != nil {
|
||||
if parErr := b.ArtifactMetadataPublisher.UpdateBuildStatus(ctx, b.Name, models.HashicorpCloudPackerBuildStatusFAILED); parErr != nil {
|
||||
log.Printf("[TRACE] failed to update HCP Packer registry status for %q: %s", b.Name, parErr)
|
||||
}
|
||||
}
|
||||
|
||||
// close chan to mark completion
|
||||
close(runCompleted)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if artifact == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var images []registryimage.Image
|
||||
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
||||
Result: &images,
|
||||
WeaklyTypedInput: true,
|
||||
ErrorUnused: false,
|
||||
})
|
||||
if err != nil {
|
||||
return artifact, fmt.Errorf("failed to create decoder for HCP Packer registry image: %w", err)
|
||||
}
|
||||
|
||||
state := artifact.State(registryimage.ArtifactStateURI)
|
||||
err = decoder.Decode(state)
|
||||
if err != nil {
|
||||
return artifact, fmt.Errorf("failed to obtain HCP Packer registry image from build artifact: %w", err)
|
||||
}
|
||||
|
||||
err = b.ArtifactMetadataPublisher.UpdateImageForBuild(b.Name, images...)
|
||||
if err != nil {
|
||||
return artifact, fmt.Errorf("failed to add image artifact for %q: %s", b.Name, err)
|
||||
}
|
||||
|
||||
return artifact, nil
|
||||
}
|
||||
@ -1,106 +0,0 @@
|
||||
package packer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/hcl/v2/hcldec"
|
||||
"github.com/hashicorp/hcp-sdk-go/clients/cloud-packer-service/stable/2021-04-30/models"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
registryimage "github.com/hashicorp/packer-plugin-sdk/packer/registry/image"
|
||||
packerregistry "github.com/hashicorp/packer/internal/registry"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
type RegistryPostProcessor struct {
|
||||
BuilderType string
|
||||
ArtifactMetadataPublisher *packerregistry.Bucket
|
||||
packersdk.PostProcessor
|
||||
}
|
||||
|
||||
func (p *RegistryPostProcessor) ConfigSpec() hcldec.ObjectSpec {
|
||||
if p.PostProcessor == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return p.PostProcessor.ConfigSpec()
|
||||
}
|
||||
|
||||
func (p *RegistryPostProcessor) Configure(raws ...interface{}) error {
|
||||
if p.PostProcessor == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return p.PostProcessor.Configure(raws...)
|
||||
}
|
||||
|
||||
func (p *RegistryPostProcessor) PostProcess(ctx context.Context, ui packersdk.Ui, source packersdk.Artifact) (packersdk.Artifact, bool, bool, error) {
|
||||
// This is a bit of a hack for now to denote that this pp should just update the state of a build in the Packer registry.
|
||||
// TODO create an actual post-processor that we can embed here that will do the updating and printing.
|
||||
if p.PostProcessor == nil {
|
||||
if parErr := p.ArtifactMetadataPublisher.CompleteBuild(ctx, p.BuilderType); parErr != nil {
|
||||
err := fmt.Errorf("[TRACE] failed to update Packer registry with image artifacts for %q: %s", p.BuilderType, parErr)
|
||||
return nil, false, true, err
|
||||
}
|
||||
|
||||
r := &RegistryArtifact{
|
||||
BuildName: p.BuilderType,
|
||||
BucketSlug: p.ArtifactMetadataPublisher.Slug,
|
||||
IterationID: p.ArtifactMetadataPublisher.Iteration.ID,
|
||||
}
|
||||
|
||||
return r, true, false, nil
|
||||
}
|
||||
|
||||
// Bump build status first so we don't end-up chaining post-processors
|
||||
// that don't heartbeat, hence letting too long happen between two
|
||||
// refreshes, and letting the build go to the FAILED status.
|
||||
err := p.ArtifactMetadataPublisher.UpdateBuildStatus(
|
||||
ctx,
|
||||
p.BuilderType,
|
||||
models.HashicorpCloudPackerBuildStatusRUNNING,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("[TRACE] failed to heartbeat running build %s: %s", p.BuilderType, err)
|
||||
}
|
||||
|
||||
cleanupHeartbeat, err := p.ArtifactMetadataPublisher.HeartbeatBuild(ctx, p.BuilderType)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] failed to start heartbeat function")
|
||||
}
|
||||
if cleanupHeartbeat != nil {
|
||||
defer cleanupHeartbeat()
|
||||
}
|
||||
|
||||
source, keep, override, err := p.PostProcessor.PostProcess(ctx, ui, source)
|
||||
if err != nil {
|
||||
if parErr := p.ArtifactMetadataPublisher.UpdateBuildStatus(ctx, p.BuilderType, models.HashicorpCloudPackerBuildStatusFAILED); parErr != nil {
|
||||
log.Printf("[TRACE] failed to update Packer registry with image artifacts for %q: %s", p.BuilderType, parErr)
|
||||
}
|
||||
return source, false, false, err
|
||||
}
|
||||
|
||||
var images []registryimage.Image
|
||||
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
||||
Result: &images,
|
||||
WeaklyTypedInput: true,
|
||||
ErrorUnused: false,
|
||||
})
|
||||
if err != nil {
|
||||
return source, false, false, fmt.Errorf("failed to create decoder for HCP Packer registry image: %w", err)
|
||||
}
|
||||
|
||||
state := source.State(registryimage.ArtifactStateURI)
|
||||
err = decoder.Decode(state)
|
||||
if err != nil {
|
||||
return source, false, false, fmt.Errorf("failed to obtain HCP Packer registry image from post-processor artifact: %w", err)
|
||||
}
|
||||
err = p.ArtifactMetadataPublisher.UpdateImageForBuild(p.BuilderType, images...)
|
||||
|
||||
if err != nil {
|
||||
return source, keep, override, fmt.Errorf("[TRACE] failed to add image artifact for %q: %s", p.BuilderType, err)
|
||||
}
|
||||
|
||||
return source, keep, override, nil
|
||||
}
|
||||
Loading…
Reference in new issue