From dc31bad53934b564e3fde893cd77e283bc65617e Mon Sep 17 00:00:00 2001 From: Sylvia Moss Date: Thu, 30 Jan 2020 11:27:58 +0100 Subject: [PATCH] Sharing info with post-processors via artifact (#8632) --- builder/amazon/common/artifact.go | 2 +- builder/amazon/common/artifact_test.go | 7 +++ builder/amazon/ebsvolume/artifact.go | 2 +- builder/amazon/ebsvolume/artifact_test.go | 7 +++ builder/azure/arm/artifact.go | 18 +++++-- builder/azure/arm/artifact_test.go | 54 ++++++++++++++----- builder/azure/arm/builder.go | 27 ++++++++-- builder/azure/chroot/builder.go | 1 + builder/azure/common/artifact.go | 9 ++-- builder/cloudstack/artifact.go | 6 ++- builder/cloudstack/artifact_test.go | 26 +++++++++ builder/cloudstack/builder.go | 7 +-- builder/digitalocean/artifact.go | 6 ++- builder/digitalocean/artifact_test.go | 38 +++++++++++-- builder/digitalocean/builder.go | 1 + builder/docker/artifact_export.go | 5 +- builder/docker/artifact_import.go | 8 ++- builder/docker/builder.go | 6 ++- builder/googlecompute/artifact.go | 7 +++ builder/googlecompute/artifact_test.go | 26 +++++++++ builder/googlecompute/builder.go | 7 +-- builder/googlecompute/builder_test.go | 1 - builder/hcloud/artifact.go | 6 ++- builder/hcloud/artifact_test.go | 32 ++++++++++- builder/hcloud/builder.go | 1 + builder/hyperone/artifact.go | 6 ++- builder/hyperone/builder.go | 1 + builder/hyperv/common/artifact.go | 13 +++-- builder/hyperv/common/artifact_test.go | 6 ++- builder/hyperv/iso/builder.go | 4 +- builder/hyperv/vmcx/builder.go | 3 +- builder/jdcloud/artifact.go | 6 ++- builder/jdcloud/builder.go | 5 +- builder/linode/artifact.go | 8 ++- builder/linode/artifact_test.go | 32 ++++++++++- builder/linode/builder.go | 1 + builder/lxc/artifact.go | 5 +- builder/lxc/builder.go | 5 +- builder/lxc/step_provision.go | 10 +++- builder/lxd/artifact.go | 6 ++- builder/lxd/builder.go | 3 +- builder/lxd/step_provision.go | 10 +++- builder/ncloud/artifact.go | 7 +++ builder/ncloud/builder.go | 4 +- builder/oneandone/artifact.go | 6 ++- builder/oneandone/builder.go | 1 + builder/openstack/artifact.go | 6 ++- builder/openstack/artifact_test.go | 26 +++++++++ builder/openstack/builder.go | 1 + builder/oracle/classic/artifact.go | 6 ++- builder/oracle/classic/builder.go | 1 + builder/oracle/oci/artifact.go | 6 ++- builder/oracle/oci/artifact_test.go | 26 +++++++++ builder/oracle/oci/builder.go | 7 +-- builder/osc/bsu/builder.go | 1 + builder/osc/bsusurrogate/builder.go | 1 + builder/osc/bsuvolume/artifact.go | 6 ++- builder/osc/bsuvolume/builder.go | 1 + builder/osc/chroot/builder.go | 1 + builder/osc/chroot/step_chroot_provision.go | 10 +++- builder/osc/common/artifact.go | 8 +++ builder/parallels/common/artifact.go | 13 +++-- builder/parallels/common/artifact_test.go | 6 ++- builder/parallels/iso/builder.go | 3 +- builder/parallels/pvm/builder.go | 3 +- builder/profitbricks/artifact.go | 6 ++- builder/profitbricks/artifact_test.go | 29 +++++++++- builder/profitbricks/builder.go | 1 + builder/proxmox/artifact.go | 6 ++- builder/proxmox/builder.go | 1 + builder/qemu/builder.go | 1 + builder/scaleway/artifact.go | 6 ++- builder/scaleway/artifact_test.go | 32 ++++++++++- builder/scaleway/builder.go | 1 + builder/tencentcloud/cvm/artifact.go | 8 +++ builder/tencentcloud/cvm/builder.go | 1 + builder/triton/artifact.go | 6 ++- builder/triton/builder.go | 1 + builder/ucloud/common/artifact.go | 8 +++ builder/ucloud/common/artifact_test.go | 26 +++++++++ builder/ucloud/uhost/builder.go | 1 + builder/vagrant/artifact.go | 9 +++- builder/vagrant/artifact_test.go | 26 +++++++++ builder/vagrant/builder.go | 3 +- builder/virtualbox/common/artifact.go | 13 +++-- builder/virtualbox/common/artifact_test.go | 6 ++- builder/virtualbox/iso/builder.go | 3 +- builder/virtualbox/ovf/builder.go | 3 +- builder/virtualbox/vm/builder.go | 3 +- builder/vmware/common/artifact.go | 8 +++ builder/vsphere/clone/builder.go | 5 +- builder/vsphere/common/artifact.go | 6 ++- builder/vsphere/iso/builder.go | 5 +- builder/yandex/artifact.go | 8 +++ builder/yandex/artifact_test.go | 26 +++++++++ builder/yandex/builder.go | 5 +- common/chroot/step_chroot_provision.go | 4 ++ common/step_provision.go | 7 +-- .../alicloud-import/post-processor.go | 7 +++ .../amazon-import/post-processor.go | 7 +++ .../artifice/post-processor_test.go | 1 - post-processor/checksum/post-processor.go | 28 +++++----- post-processor/compress/post-processor.go | 18 +++++-- .../digitalocean-import/post-processor.go | 7 +++ .../googlecompute-import/post-processor.go | 7 +++ post-processor/shell-local/post-processor.go | 11 ++-- .../ucloud-import/post-processor.go | 7 +++ .../vagrant-cloud/post-processor.go | 21 +++++--- post-processor/vagrant/post-processor.go | 27 +++++----- 109 files changed, 847 insertions(+), 152 deletions(-) delete mode 100644 builder/googlecompute/builder_test.go delete mode 100644 post-processor/artifice/post-processor_test.go diff --git a/builder/amazon/common/artifact.go b/builder/amazon/common/artifact.go index 4b8fe1cf6..89f2ef8a5 100644 --- a/builder/amazon/common/artifact.go +++ b/builder/amazon/common/artifact.go @@ -20,7 +20,7 @@ type Artifact struct { // BuilderId is the unique ID for the builder that created this AMI BuilderIdValue string - // SateData should store data such as GeneratedData + // StateData should store data such as GeneratedData // to be shared with post-processors StateData map[string]interface{} diff --git a/builder/amazon/common/artifact_test.go b/builder/amazon/common/artifact_test.go index 808de5ee7..1add5f036 100644 --- a/builder/amazon/common/artifact_test.go +++ b/builder/amazon/common/artifact_test.go @@ -80,4 +80,11 @@ func TestArtifactState(t *testing.T) { if result != nil { t.Fatalf("Bad: State should be nil for invalid state data name") } + + // Nil StateData should not fail and should return nil + artifact = &Artifact{} + result = artifact.State("key") + if result != nil { + t.Fatalf("Bad: State should be nil for nil StateData") + } } diff --git a/builder/amazon/ebsvolume/artifact.go b/builder/amazon/ebsvolume/artifact.go index e30e9f58e..fbf7e178d 100644 --- a/builder/amazon/ebsvolume/artifact.go +++ b/builder/amazon/ebsvolume/artifact.go @@ -21,7 +21,7 @@ type Artifact struct { // BuilderId is the unique ID for the builder that created this AMI BuilderIdValue string - // SateData should store data such as GeneratedData + // StateData should store data such as GeneratedData // to be shared with post-processors StateData map[string]interface{} diff --git a/builder/amazon/ebsvolume/artifact_test.go b/builder/amazon/ebsvolume/artifact_test.go index 6bc5db6b4..1b220994d 100644 --- a/builder/amazon/ebsvolume/artifact_test.go +++ b/builder/amazon/ebsvolume/artifact_test.go @@ -19,4 +19,11 @@ func TestArtifactState(t *testing.T) { if result != nil { t.Fatalf("Bad: State should be nil for invalid state data name") } + + // Nil StateData should not fail and should return nil + artifact = &Artifact{} + result = artifact.State("key") + if result != nil { + t.Fatalf("Bad: State should be nil for nil StateData") + } } diff --git a/builder/azure/arm/artifact.go b/builder/azure/arm/artifact.go index 522e08160..6830e9172 100644 --- a/builder/azure/arm/artifact.go +++ b/builder/azure/arm/artifact.go @@ -40,9 +40,13 @@ type Artifact struct { // Additional Disks AdditionalDisks *[]AdditionalDiskArtifact + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } -func NewManagedImageArtifact(osType, resourceGroup, name, location, id, osDiskSnapshotName, dataDiskSnapshotPrefix string) (*Artifact, error) { +func NewManagedImageArtifact(osType, resourceGroup, name, location, id, osDiskSnapshotName, dataDiskSnapshotPrefix string, generatedData map[string]interface{}) (*Artifact, error) { return &Artifact{ ManagedImageResourceGroupName: resourceGroup, ManagedImageName: name, @@ -51,10 +55,11 @@ func NewManagedImageArtifact(osType, resourceGroup, name, location, id, osDiskSn OSType: osType, ManagedImageOSDiskSnapshotName: osDiskSnapshotName, ManagedImageDataDiskSnapshotPrefix: dataDiskSnapshotPrefix, + StateData: generatedData, }, nil } -func NewManagedImageArtifactWithSIGAsDestination(osType, resourceGroup, name, location, id, osDiskSnapshotName, dataDiskSnapshotPrefix, destinationSharedImageGalleryId string) (*Artifact, error) { +func NewManagedImageArtifactWithSIGAsDestination(osType, resourceGroup, name, location, id, osDiskSnapshotName, dataDiskSnapshotPrefix, destinationSharedImageGalleryId string, generatedData map[string]interface{}) (*Artifact, error) { return &Artifact{ ManagedImageResourceGroupName: resourceGroup, ManagedImageName: name, @@ -64,10 +69,11 @@ func NewManagedImageArtifactWithSIGAsDestination(osType, resourceGroup, name, lo ManagedImageOSDiskSnapshotName: osDiskSnapshotName, ManagedImageDataDiskSnapshotPrefix: dataDiskSnapshotPrefix, ManagedImageSharedImageGalleryId: destinationSharedImageGalleryId, + StateData: generatedData, }, nil } -func NewArtifact(template *CaptureTemplate, getSasUrl func(name string) string, osType string) (*Artifact, error) { +func NewArtifact(template *CaptureTemplate, getSasUrl func(name string) string, osType string, generatedData map[string]interface{}) (*Artifact, error) { if template == nil { return nil, fmt.Errorf("nil capture template") } @@ -110,6 +116,8 @@ func NewArtifact(template *CaptureTemplate, getSasUrl func(name string) string, AdditionalDisks: additional_disks, StorageAccountLocation: template.Resources[0].Location, + + StateData: generatedData, }, nil } @@ -159,6 +167,10 @@ func (a *Artifact) Id() string { } func (a *Artifact) State(name string) interface{} { + if _, ok := a.StateData[name]; ok { + return a.StateData[name] + } + switch name { case "atlas.artifact.metadata": return a.stateAtlasMetadata() diff --git a/builder/azure/arm/artifact_test.go b/builder/azure/arm/artifact_test.go index 4556b4619..73f82e626 100644 --- a/builder/azure/arm/artifact_test.go +++ b/builder/azure/arm/artifact_test.go @@ -10,6 +10,10 @@ func getFakeSasUrl(name string) string { return fmt.Sprintf("SAS-%s", name) } +func generatedData() map[string]interface{} { + return make(map[string]interface{}) +} + func TestArtifactIdVHD(t *testing.T) { template := CaptureTemplate{ Resources: []CaptureResources{ @@ -28,7 +32,7 @@ func TestArtifactIdVHD(t *testing.T) { }, } - artifact, err := NewArtifact(&template, getFakeSasUrl, "Linux") + artifact, err := NewArtifact(&template, getFakeSasUrl, "Linux", generatedData()) if err != nil { t.Fatalf("err=%s", err) } @@ -42,7 +46,7 @@ func TestArtifactIdVHD(t *testing.T) { } func TestArtifactIDManagedImage(t *testing.T) { - artifact, err := NewManagedImageArtifact("Linux", "fakeResourceGroup", "fakeName", "fakeLocation", "fakeID", "fakeOsDiskSnapshotName", "fakeDataDiskSnapshotPrefix") + artifact, err := NewManagedImageArtifact("Linux", "fakeResourceGroup", "fakeName", "fakeLocation", "fakeID", "fakeOsDiskSnapshotName", "fakeDataDiskSnapshotPrefix", generatedData()) if err != nil { t.Fatalf("err=%s", err) } @@ -65,7 +69,7 @@ ManagedImageDataDiskSnapshotPrefix: fakeDataDiskSnapshotPrefix } func TestArtifactIDManagedImageWithoutOSDiskSnapshotName(t *testing.T) { - artifact, err := NewManagedImageArtifact("Linux", "fakeResourceGroup", "fakeName", "fakeLocation", "fakeID", "", "fakeDataDiskSnapshotPrefix") + artifact, err := NewManagedImageArtifact("Linux", "fakeResourceGroup", "fakeName", "fakeLocation", "fakeID", "", "fakeDataDiskSnapshotPrefix", generatedData()) if err != nil { t.Fatalf("err=%s", err) } @@ -87,7 +91,7 @@ ManagedImageDataDiskSnapshotPrefix: fakeDataDiskSnapshotPrefix } func TestArtifactIDManagedImageWithoutDataDiskSnapshotPrefix(t *testing.T) { - artifact, err := NewManagedImageArtifact("Linux", "fakeResourceGroup", "fakeName", "fakeLocation", "fakeID", "fakeOsDiskSnapshotName", "") + artifact, err := NewManagedImageArtifact("Linux", "fakeResourceGroup", "fakeName", "fakeLocation", "fakeID", "fakeOsDiskSnapshotName", "", generatedData()) if err != nil { t.Fatalf("err=%s", err) } @@ -109,7 +113,7 @@ ManagedImageOSDiskSnapshotName: fakeOsDiskSnapshotName } func TestArtifactIDManagedImageWithSharedImageGalleryId(t *testing.T) { - artifact, err := NewManagedImageArtifactWithSIGAsDestination("Linux", "fakeResourceGroup", "fakeName", "fakeLocation", "fakeID", "fakeOsDiskSnapshotName", "fakeDataDiskSnapshotPrefix", "fakeSharedImageGallery") + artifact, err := NewManagedImageArtifactWithSIGAsDestination("Linux", "fakeResourceGroup", "fakeName", "fakeLocation", "fakeID", "fakeOsDiskSnapshotName", "fakeDataDiskSnapshotPrefix", "fakeSharedImageGallery", generatedData()) if err != nil { t.Fatalf("err=%s", err) } @@ -150,7 +154,7 @@ func TestArtifactString(t *testing.T) { }, } - artifact, err := NewArtifact(&template, getFakeSasUrl, "Linux") + artifact, err := NewArtifact(&template, getFakeSasUrl, "Linux", generatedData()) if err != nil { t.Fatalf("err=%s", err) } @@ -201,7 +205,7 @@ func TestAdditionalDiskArtifactString(t *testing.T) { }, } - artifact, err := NewArtifact(&template, getFakeSasUrl, "Linux") + artifact, err := NewArtifact(&template, getFakeSasUrl, "Linux", generatedData()) if err != nil { t.Fatalf("err=%s", err) } @@ -251,7 +255,7 @@ func TestArtifactProperties(t *testing.T) { }, } - testSubject, err := NewArtifact(&template, getFakeSasUrl, "Linux") + testSubject, err := NewArtifact(&template, getFakeSasUrl, "Linux", generatedData()) if err != nil { t.Fatalf("err=%s", err) } @@ -301,7 +305,7 @@ func TestAdditionalDiskArtifactProperties(t *testing.T) { }, } - testSubject, err := NewArtifact(&template, getFakeSasUrl, "Linux") + testSubject, err := NewArtifact(&template, getFakeSasUrl, "Linux", generatedData()) if err != nil { t.Fatalf("err=%s", err) } @@ -356,7 +360,7 @@ func TestArtifactOverHyphenatedCaptureUri(t *testing.T) { }, } - testSubject, err := NewArtifact(&template, getFakeSasUrl, "Linux") + testSubject, err := NewArtifact(&template, getFakeSasUrl, "Linux", generatedData()) if err != nil { t.Fatalf("err=%s", err) } @@ -369,7 +373,7 @@ func TestArtifactOverHyphenatedCaptureUri(t *testing.T) { func TestArtifactRejectMalformedTemplates(t *testing.T) { template := CaptureTemplate{} - _, err := NewArtifact(&template, getFakeSasUrl, "Linux") + _, err := NewArtifact(&template, getFakeSasUrl, "Linux", generatedData()) if err == nil { t.Fatalf("Expected artifact creation to fail, but it succeeded.") } @@ -392,8 +396,34 @@ func TestArtifactRejectMalformedStorageUri(t *testing.T) { }, } - _, err := NewArtifact(&template, getFakeSasUrl, "Linux") + _, err := NewArtifact(&template, getFakeSasUrl, "Linux", generatedData()) if err == nil { t.Fatalf("Expected artifact creation to fail, but it succeeded.") } } + +func TestArtifactState_StateData(t *testing.T) { + expectedData := "this is the data" + artifact := &Artifact{ + StateData: map[string]interface{}{"state_data": expectedData}, + } + + // Valid state + result := artifact.State("state_data") + if result != expectedData { + t.Fatalf("Bad: State data was %s instead of %s", result, expectedData) + } + + // Invalid state + result = artifact.State("invalid_key") + if result != nil { + t.Fatalf("Bad: State should be nil for invalid state data name") + } + + // Nil StateData should not fail and should return nil + artifact = &Artifact{} + result = artifact.State("key") + if result != nil { + t.Fatalf("Bad: State should be nil for nil StateData") + } +} diff --git a/builder/azure/arm/builder.go b/builder/azure/arm/builder.go index f1cf0fed3..7f7da7cea 100644 --- a/builder/azure/arm/builder.go +++ b/builder/azure/arm/builder.go @@ -289,13 +289,29 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack return nil, errors.New("Build was halted.") } + generatedData := map[string]interface{}{"generated_data": b.stateBag.Get("generated_data")} if b.config.isManagedImage() { managedImageID := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/images/%s", b.config.ClientConfig.SubscriptionID, b.config.ManagedImageResourceGroupName, b.config.ManagedImageName) if b.config.SharedGalleryDestination.SigDestinationGalleryName != "" { - return NewManagedImageArtifactWithSIGAsDestination(b.config.OSType, b.config.ManagedImageResourceGroupName, b.config.ManagedImageName, b.config.manageImageLocation, managedImageID, b.config.ManagedImageOSDiskSnapshotName, b.config.ManagedImageDataDiskSnapshotPrefix, b.stateBag.Get(constants.ArmManagedImageSharedGalleryId).(string)) + return NewManagedImageArtifactWithSIGAsDestination(b.config.OSType, + b.config.ManagedImageResourceGroupName, + b.config.ManagedImageName, + b.config.manageImageLocation, + managedImageID, + b.config.ManagedImageOSDiskSnapshotName, + b.config.ManagedImageDataDiskSnapshotPrefix, + b.stateBag.Get(constants.ArmManagedImageSharedGalleryId).(string), + generatedData) } - return NewManagedImageArtifact(b.config.OSType, b.config.ManagedImageResourceGroupName, b.config.ManagedImageName, b.config.manageImageLocation, managedImageID, b.config.ManagedImageOSDiskSnapshotName, b.config.ManagedImageDataDiskSnapshotPrefix) + return NewManagedImageArtifact(b.config.OSType, + b.config.ManagedImageResourceGroupName, + b.config.ManagedImageName, + b.config.manageImageLocation, + managedImageID, + b.config.ManagedImageOSDiskSnapshotName, + b.config.ManagedImageDataDiskSnapshotPrefix, + generatedData) } else if template, ok := b.stateBag.GetOk(constants.ArmCaptureTemplate); ok { return NewArtifact( template.(*CaptureTemplate), @@ -307,10 +323,13 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack sasUrl, _ := blob.GetSASURI(options) return sasUrl }, - b.config.OSType) + b.config.OSType, + generatedData) } - return &Artifact{}, nil + return &Artifact{ + StateData: generatedData, + }, nil } func (b *Builder) writeSSHPrivateKey(ui packer.Ui, debugKeyPath string) { diff --git a/builder/azure/chroot/builder.go b/builder/azure/chroot/builder.go index bc35cea7a..7d95c2097 100644 --- a/builder/azure/chroot/builder.go +++ b/builder/azure/chroot/builder.go @@ -448,6 +448,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack artifact := &azcommon.Artifact{ Resources: []string{b.config.ImageResourceID}, BuilderIdValue: BuilderId, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil diff --git a/builder/azure/common/artifact.go b/builder/azure/common/artifact.go index d74ff9b54..5c2f4ca51 100644 --- a/builder/azure/common/artifact.go +++ b/builder/azure/common/artifact.go @@ -22,6 +22,10 @@ type Artifact struct { // Azure client for performing API stuff. AzureClientSet client.AzureClientSet + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } func (a *Artifact) BuilderId() string { @@ -54,10 +58,7 @@ func (a *Artifact) String() string { } func (a *Artifact) State(name string) interface{} { - switch name { - default: - return nil - } + return a.StateData[name] } func (a *Artifact) Destroy() error { diff --git a/builder/cloudstack/artifact.go b/builder/cloudstack/artifact.go index 6dfa56ebf..e5c82eb67 100644 --- a/builder/cloudstack/artifact.go +++ b/builder/cloudstack/artifact.go @@ -13,6 +13,10 @@ type Artifact struct { client *cloudstack.CloudStackClient config *Config template *cloudstack.CreateTemplateResponse + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } // BuilderId returns the builder ID. @@ -60,5 +64,5 @@ func (a *Artifact) String() string { // State returns specific details from the artifact. func (a *Artifact) State(name string) interface{} { - return nil + return a.StateData[name] } diff --git a/builder/cloudstack/artifact_test.go b/builder/cloudstack/artifact_test.go index f1b062e5e..b930083e0 100644 --- a/builder/cloudstack/artifact_test.go +++ b/builder/cloudstack/artifact_test.go @@ -45,3 +45,29 @@ func TestArtifactString(t *testing.T) { t.Fatalf("artifact string should match: %s", expected) } } + +func TestArtifactState_StateData(t *testing.T) { + expectedData := "this is the data" + artifact := &Artifact{ + StateData: map[string]interface{}{"state_data": expectedData}, + } + + // Valid state + result := artifact.State("state_data") + if result != expectedData { + t.Fatalf("Bad: State data was %s instead of %s", result, expectedData) + } + + // Invalid state + result = artifact.State("invalid_key") + if result != nil { + t.Fatalf("Bad: State should be nil for invalid state data name") + } + + // Nil StateData should not fail and should return nil + artifact = &Artifact{} + result = artifact.State("key") + if result != nil { + t.Fatalf("Bad: State should be nil for nil StateData") + } +} diff --git a/builder/cloudstack/builder.go b/builder/cloudstack/builder.go index 7255a057b..4a147b6b3 100644 --- a/builder/cloudstack/builder.go +++ b/builder/cloudstack/builder.go @@ -109,9 +109,10 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack // Build the artifact and return it artifact := &Artifact{ - client: client, - config: &b.config, - template: state.Get("template").(*cloudstack.CreateTemplateResponse), + client: client, + config: &b.config, + template: state.Get("template").(*cloudstack.CreateTemplateResponse), + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil diff --git a/builder/digitalocean/artifact.go b/builder/digitalocean/artifact.go index d41f1522d..9f5d6b1ed 100644 --- a/builder/digitalocean/artifact.go +++ b/builder/digitalocean/artifact.go @@ -22,6 +22,10 @@ type Artifact struct { // The client for making API calls Client *godo.Client + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } func (*Artifact) BuilderId() string { @@ -42,7 +46,7 @@ func (a *Artifact) String() string { } func (a *Artifact) State(name string) interface{} { - return nil + return a.StateData[name] } func (a *Artifact) Destroy() error { diff --git a/builder/digitalocean/artifact_test.go b/builder/digitalocean/artifact_test.go index 55c00c8e1..21c373fc8 100644 --- a/builder/digitalocean/artifact_test.go +++ b/builder/digitalocean/artifact_test.go @@ -6,6 +6,10 @@ import ( "github.com/hashicorp/packer/packer" ) +func generatedData() map[string]interface{} { + return make(map[string]interface{}) +} + func TestArtifact_Impl(t *testing.T) { var raw interface{} raw = &Artifact{} @@ -15,7 +19,7 @@ func TestArtifact_Impl(t *testing.T) { } func TestArtifactId(t *testing.T) { - a := &Artifact{"packer-foobar", 42, []string{"sfo", "tor1"}, nil} + a := &Artifact{"packer-foobar", 42, []string{"sfo", "tor1"}, nil, generatedData()} expected := "sfo,tor1:42" if a.Id() != expected { @@ -24,7 +28,7 @@ func TestArtifactId(t *testing.T) { } func TestArtifactIdWithoutMultipleRegions(t *testing.T) { - a := &Artifact{"packer-foobar", 42, []string{"sfo"}, nil} + a := &Artifact{"packer-foobar", 42, []string{"sfo"}, nil, generatedData()} expected := "sfo:42" if a.Id() != expected { @@ -33,7 +37,7 @@ func TestArtifactIdWithoutMultipleRegions(t *testing.T) { } func TestArtifactString(t *testing.T) { - a := &Artifact{"packer-foobar", 42, []string{"sfo", "tor1"}, nil} + a := &Artifact{"packer-foobar", 42, []string{"sfo", "tor1"}, nil, generatedData()} expected := "A snapshot was created: 'packer-foobar' (ID: 42) in regions 'sfo,tor1'" if a.String() != expected { @@ -42,10 +46,36 @@ func TestArtifactString(t *testing.T) { } func TestArtifactStringWithoutMultipleRegions(t *testing.T) { - a := &Artifact{"packer-foobar", 42, []string{"sfo"}, nil} + a := &Artifact{"packer-foobar", 42, []string{"sfo"}, nil, generatedData()} expected := "A snapshot was created: 'packer-foobar' (ID: 42) in regions 'sfo'" if a.String() != expected { t.Fatalf("artifact string should match: %v", expected) } } + +func TestArtifactState_StateData(t *testing.T) { + expectedData := "this is the data" + artifact := &Artifact{ + StateData: map[string]interface{}{"state_data": expectedData}, + } + + // Valid state + result := artifact.State("state_data") + if result != expectedData { + t.Fatalf("Bad: State data was %s instead of %s", result, expectedData) + } + + // Invalid state + result = artifact.State("invalid_key") + if result != nil { + t.Fatalf("Bad: State should be nil for invalid state data name") + } + + // Nil StateData should not fail and should return nil + artifact = &Artifact{} + result = artifact.State("key") + if result != nil { + t.Fatalf("Bad: State should be nil for nil StateData") + } +} diff --git a/builder/digitalocean/builder.go b/builder/digitalocean/builder.go index 8dc6fdec1..3d4b07920 100644 --- a/builder/digitalocean/builder.go +++ b/builder/digitalocean/builder.go @@ -121,6 +121,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack SnapshotId: state.Get("snapshot_image_id").(int), RegionNames: state.Get("regions").([]string), Client: client, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil diff --git a/builder/docker/artifact_export.go b/builder/docker/artifact_export.go index d9eb83f67..eb26f96c3 100644 --- a/builder/docker/artifact_export.go +++ b/builder/docker/artifact_export.go @@ -9,6 +9,9 @@ import ( // exported from docker into a single flat file. type ExportArtifact struct { path string + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } func (*ExportArtifact) BuilderId() string { @@ -28,7 +31,7 @@ func (a *ExportArtifact) String() string { } func (a *ExportArtifact) State(name string) interface{} { - return nil + return a.StateData[name] } func (a *ExportArtifact) Destroy() error { diff --git a/builder/docker/artifact_import.go b/builder/docker/artifact_import.go index 6ab0fe482..acc34019d 100644 --- a/builder/docker/artifact_import.go +++ b/builder/docker/artifact_import.go @@ -10,6 +10,10 @@ type ImportArtifact struct { BuilderIdValue string Driver Driver IdValue string + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } func (a *ImportArtifact) BuilderId() string { @@ -28,8 +32,8 @@ func (a *ImportArtifact) String() string { return fmt.Sprintf("Imported Docker image: %s", a.Id()) } -func (*ImportArtifact) State(name string) interface{} { - return nil +func (a *ImportArtifact) State(name string) interface{} { + return a.StateData[name] } func (a *ImportArtifact) Destroy() error { diff --git a/builder/docker/builder.go b/builder/docker/builder.go index c309dafc1..07862491f 100644 --- a/builder/docker/builder.go +++ b/builder/docker/builder.go @@ -105,9 +105,13 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack IdValue: state.Get("image_id").(string), BuilderIdValue: BuilderIdImport, Driver: driver, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } } else { - artifact = &ExportArtifact{path: b.config.ExportPath} + artifact = &ExportArtifact{ + path: b.config.ExportPath, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, + } } return artifact, nil diff --git a/builder/googlecompute/artifact.go b/builder/googlecompute/artifact.go index 9d98d6566..2aaed8e35 100644 --- a/builder/googlecompute/artifact.go +++ b/builder/googlecompute/artifact.go @@ -10,6 +10,9 @@ type Artifact struct { image *Image driver Driver config *Config + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } // BuilderId returns the builder Id. @@ -40,6 +43,10 @@ func (a *Artifact) String() string { } func (a *Artifact) State(name string) interface{} { + if _, ok := a.StateData[name]; ok { + return a.StateData[name] + } + switch name { case "ImageName": return a.image.Name diff --git a/builder/googlecompute/artifact_test.go b/builder/googlecompute/artifact_test.go index bb803056c..43194daf9 100644 --- a/builder/googlecompute/artifact_test.go +++ b/builder/googlecompute/artifact_test.go @@ -9,3 +9,29 @@ import ( func TestArtifact_impl(t *testing.T) { var _ packer.Artifact = new(Artifact) } + +func TestArtifactState_StateData(t *testing.T) { + expectedData := "this is the data" + artifact := &Artifact{ + StateData: map[string]interface{}{"state_data": expectedData}, + } + + // Valid state + result := artifact.State("state_data") + if result != expectedData { + t.Fatalf("Bad: State data was %s instead of %s", result, expectedData) + } + + // Invalid state + result = artifact.State("invalid_key") + if result != nil { + t.Fatalf("Bad: State should be nil for invalid state data name") + } + + // Nil StateData should not fail and should return nil + artifact = &Artifact{} + result = artifact.State("key") + if result != nil { + t.Fatalf("Bad: State should be nil for nil StateData") + } +} diff --git a/builder/googlecompute/builder.go b/builder/googlecompute/builder.go index 0d31530f4..b88e0cc0f 100644 --- a/builder/googlecompute/builder.go +++ b/builder/googlecompute/builder.go @@ -96,9 +96,10 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack } artifact := &Artifact{ - image: state.Get("image").(*Image), - driver: driver, - config: &b.config, + image: state.Get("image").(*Image), + driver: driver, + config: &b.config, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil } diff --git a/builder/googlecompute/builder_test.go b/builder/googlecompute/builder_test.go deleted file mode 100644 index c85b8a2f8..000000000 --- a/builder/googlecompute/builder_test.go +++ /dev/null @@ -1 +0,0 @@ -package googlecompute diff --git a/builder/hcloud/artifact.go b/builder/hcloud/artifact.go index 52f2593f4..4bc9f4bf5 100644 --- a/builder/hcloud/artifact.go +++ b/builder/hcloud/artifact.go @@ -18,6 +18,10 @@ type Artifact struct { // The hcloudClient for making API calls hcloudClient *hcloud.Client + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } func (*Artifact) BuilderId() string { @@ -37,7 +41,7 @@ func (a *Artifact) String() string { } func (a *Artifact) State(name string) interface{} { - return nil + return a.StateData[name] } func (a *Artifact) Destroy() error { diff --git a/builder/hcloud/artifact_test.go b/builder/hcloud/artifact_test.go index f6e00e436..3e43ccda2 100644 --- a/builder/hcloud/artifact_test.go +++ b/builder/hcloud/artifact_test.go @@ -11,7 +11,8 @@ func TestArtifact_Impl(t *testing.T) { } func TestArtifactId(t *testing.T) { - a := &Artifact{"packer-foobar", 42, nil} + generatedData := make(map[string]interface{}) + a := &Artifact{"packer-foobar", 42, nil, generatedData} expected := "42" if a.Id() != expected { @@ -20,10 +21,37 @@ func TestArtifactId(t *testing.T) { } func TestArtifactString(t *testing.T) { - a := &Artifact{"packer-foobar", 42, nil} + generatedData := make(map[string]interface{}) + a := &Artifact{"packer-foobar", 42, nil, generatedData} expected := "A snapshot was created: 'packer-foobar' (ID: 42)" if a.String() != expected { t.Fatalf("artifact string should match: %v", expected) } } + +func TestArtifactState_StateData(t *testing.T) { + expectedData := "this is the data" + artifact := &Artifact{ + StateData: map[string]interface{}{"state_data": expectedData}, + } + + // Valid state + result := artifact.State("state_data") + if result != expectedData { + t.Fatalf("Bad: State data was %s instead of %s", result, expectedData) + } + + // Invalid state + result = artifact.State("invalid_key") + if result != nil { + t.Fatalf("Bad: State should be nil for invalid state data name") + } + + // Nil StateData should not fail and should return nil + artifact = &Artifact{} + result = artifact.State("key") + if result != nil { + t.Fatalf("Bad: State should be nil for nil StateData") + } +} diff --git a/builder/hcloud/builder.go b/builder/hcloud/builder.go index e360149df..be311e7bc 100644 --- a/builder/hcloud/builder.go +++ b/builder/hcloud/builder.go @@ -84,6 +84,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack snapshotName: state.Get("snapshot_name").(string), snapshotId: state.Get("snapshot_id").(int), hcloudClient: b.hcloudClient, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil diff --git a/builder/hyperone/artifact.go b/builder/hyperone/artifact.go index 5b61e5895..2d8c49d1f 100644 --- a/builder/hyperone/artifact.go +++ b/builder/hyperone/artifact.go @@ -11,6 +11,10 @@ type Artifact struct { imageName string imageID string client *openapi.APIClient + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } func (a *Artifact) BuilderId() string { @@ -30,7 +34,7 @@ func (a *Artifact) String() string { } func (a *Artifact) State(name string) interface{} { - return nil + return a.StateData[name] } func (a *Artifact) Destroy() error { diff --git a/builder/hyperone/builder.go b/builder/hyperone/builder.go index e4b1bee2a..525db4abf 100644 --- a/builder/hyperone/builder.go +++ b/builder/hyperone/builder.go @@ -108,6 +108,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack imageID: state.Get("image_id").(string), imageName: state.Get("image_name").(string), client: b.client, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil diff --git a/builder/hyperv/common/artifact.go b/builder/hyperv/common/artifact.go index 06537449d..d42070aed 100644 --- a/builder/hyperv/common/artifact.go +++ b/builder/hyperv/common/artifact.go @@ -16,11 +16,15 @@ const BuilderId = "MSOpenTech.hyperv" type artifact struct { dir string f []string + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } // NewArtifact returns a hyperv artifact containing the files // in the given directory. -func NewArtifact(dir string) (packer.Artifact, error) { +func NewArtifact(dir string, generatedData map[string]interface{}) (packer.Artifact, error) { files := make([]string, 0, 5) visit := func(path string, info os.FileInfo, err error) error { if err != nil { @@ -38,8 +42,9 @@ func NewArtifact(dir string) (packer.Artifact, error) { } return &artifact{ - dir: dir, - f: files, + dir: dir, + f: files, + StateData: generatedData, }, nil } @@ -60,7 +65,7 @@ func (a *artifact) String() string { } func (a *artifact) State(name string) interface{} { - return nil + return a.StateData[name] } func (a *artifact) Destroy() error { diff --git a/builder/hyperv/common/artifact_test.go b/builder/hyperv/common/artifact_test.go index 023d2dd44..540b0d834 100644 --- a/builder/hyperv/common/artifact_test.go +++ b/builder/hyperv/common/artifact_test.go @@ -29,7 +29,8 @@ func TestNewArtifact(t *testing.T) { t.Fatalf("err: %s", err) } - a, err := NewArtifact(td) + generatedData := map[string]interface{}{"generated_data": "data"} + a, err := NewArtifact(td, generatedData) if err != nil { t.Fatalf("err: %s", err) } @@ -40,4 +41,7 @@ func TestNewArtifact(t *testing.T) { if len(a.Files()) != 1 { t.Fatalf("should length 1: %d", len(a.Files())) } + if a.State("generated_data") != "data" { + t.Fatalf("bad: should length have generated_data: %s", a.State("generated_data")) + } } diff --git a/builder/hyperv/iso/builder.go b/builder/hyperv/iso/builder.go index 4eebfe8f6..2990ea9c6 100644 --- a/builder/hyperv/iso/builder.go +++ b/builder/hyperv/iso/builder.go @@ -340,8 +340,8 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack if _, ok := state.GetOk(multistep.StateHalted); ok { return nil, errors.New("Build was halted.") } - - return hypervcommon.NewArtifact(b.config.OutputDir) + generatedData := map[string]interface{}{"generated_data": state.Get("generated_data")} + return hypervcommon.NewArtifact(b.config.OutputDir, generatedData) } // Cancel. diff --git a/builder/hyperv/vmcx/builder.go b/builder/hyperv/vmcx/builder.go index c7c840f40..d07bf8b02 100644 --- a/builder/hyperv/vmcx/builder.go +++ b/builder/hyperv/vmcx/builder.go @@ -381,7 +381,8 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack return nil, errors.New("Build was halted.") } - return hypervcommon.NewArtifact(b.config.OutputDir) + generatedData := map[string]interface{}{"generated_data": state.Get("generated_data")} + return hypervcommon.NewArtifact(b.config.OutputDir, generatedData) } // Cancel. diff --git a/builder/jdcloud/artifact.go b/builder/jdcloud/artifact.go index a56d231b0..e90fad148 100644 --- a/builder/jdcloud/artifact.go +++ b/builder/jdcloud/artifact.go @@ -9,6 +9,10 @@ import ( type Artifact struct { ImageId string RegionID string + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } func (*Artifact) BuilderId() string { @@ -35,7 +39,7 @@ func (a *Artifact) String() string { // Plan // State and destroy function is abandoned func (a *Artifact) State(name string) interface{} { - return nil + return a.StateData[name] } func (a *Artifact) Destroy() error { diff --git a/builder/jdcloud/builder.go b/builder/jdcloud/builder.go index 063bfda1f..9e9013ca8 100644 --- a/builder/jdcloud/builder.go +++ b/builder/jdcloud/builder.go @@ -88,8 +88,9 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack } artifact := &Artifact{ - ImageId: b.config.ArtifactId, - RegionID: b.config.RegionId, + ImageId: b.config.ArtifactId, + RegionID: b.config.RegionId, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil } diff --git a/builder/linode/artifact.go b/builder/linode/artifact.go index 3e1bea96c..9fe2e9a86 100644 --- a/builder/linode/artifact.go +++ b/builder/linode/artifact.go @@ -13,6 +13,10 @@ type Artifact struct { ImageLabel string Driver *linodego.Client + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } func (a Artifact) BuilderId() string { return BuilderID } @@ -23,7 +27,9 @@ func (a Artifact) String() string { return fmt.Sprintf("Linode image: %s (%s)", a.ImageLabel, a.ImageID) } -func (a Artifact) State(name string) interface{} { return nil } +func (a Artifact) State(name string) interface{} { + return a.StateData[name] +} func (a Artifact) Destroy() error { log.Printf("Destroying image: %s (%s)", a.ImageID, a.ImageLabel) diff --git a/builder/linode/artifact_test.go b/builder/linode/artifact_test.go index e049b2310..d0e25b40e 100644 --- a/builder/linode/artifact_test.go +++ b/builder/linode/artifact_test.go @@ -15,7 +15,8 @@ func TestArtifact_Impl(t *testing.T) { } func TestArtifactId(t *testing.T) { - a := &Artifact{"private/42", "packer-foobar", nil} + generatedData := make(map[string]interface{}) + a := &Artifact{"private/42", "packer-foobar", nil, generatedData} expected := "private/42" if a.Id() != expected { @@ -24,10 +25,37 @@ func TestArtifactId(t *testing.T) { } func TestArtifactString(t *testing.T) { - a := &Artifact{"private/42", "packer-foobar", nil} + generatedData := make(map[string]interface{}) + a := &Artifact{"private/42", "packer-foobar", nil, generatedData} expected := "Linode image: packer-foobar (private/42)" if a.String() != expected { t.Fatalf("artifact string should match: %v", expected) } } + +func TestArtifactState_StateData(t *testing.T) { + expectedData := "this is the data" + artifact := &Artifact{ + StateData: map[string]interface{}{"state_data": expectedData}, + } + + // Valid state + result := artifact.State("state_data") + if result != expectedData { + t.Fatalf("Bad: State data was %s instead of %s", result, expectedData) + } + + // Invalid state + result = artifact.State("invalid_key") + if result != nil { + t.Fatalf("Bad: State should be nil for invalid state data name") + } + + // Nil StateData should not fail and should return nil + artifact = &Artifact{} + result = artifact.State("key") + if result != nil { + t.Fatalf("Bad: State should be nil for nil StateData") + } +} diff --git a/builder/linode/builder.go b/builder/linode/builder.go index e4638eb41..81da942f7 100644 --- a/builder/linode/builder.go +++ b/builder/linode/builder.go @@ -95,6 +95,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (ret ImageLabel: image.Label, ImageID: image.ID, Driver: &client, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil diff --git a/builder/lxc/artifact.go b/builder/lxc/artifact.go index 0a53f70e0..0f18d7786 100644 --- a/builder/lxc/artifact.go +++ b/builder/lxc/artifact.go @@ -8,6 +8,9 @@ import ( type Artifact struct { dir string f []string + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } func (*Artifact) BuilderId() string { @@ -27,7 +30,7 @@ func (a *Artifact) String() string { } func (a *Artifact) State(name string) interface{} { - return nil + return a.StateData[name] } func (a *Artifact) Destroy() error { diff --git a/builder/lxc/builder.go b/builder/lxc/builder.go index 0d313c7b9..ec0205f97 100644 --- a/builder/lxc/builder.go +++ b/builder/lxc/builder.go @@ -82,8 +82,9 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack } artifact := &Artifact{ - dir: b.config.OutputDir, - f: files, + dir: b.config.OutputDir, + f: files, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil diff --git a/builder/lxc/step_provision.go b/builder/lxc/step_provision.go index a3ecf8332..e1ba2874d 100644 --- a/builder/lxc/step_provision.go +++ b/builder/lxc/step_provision.go @@ -2,6 +2,7 @@ package lxc import ( "context" + "github.com/hashicorp/packer/common" "log" "github.com/hashicorp/packer/helper/multistep" @@ -26,9 +27,16 @@ func (s *StepProvision) Run(ctx context.Context, state multistep.StateBag) multi CmdWrapper: wrappedCommand, } + // Loads hook data from builder's state, if it has been set. + hookData := common.PopulateProvisionHookData(state) + + // Update state generated_data with complete hookData + // to make them accessible by post-processors + state.Put("generated_data", hookData) + // Provision log.Println("Running the provision hook") - if err := hook.Run(ctx, packer.HookProvision, ui, comm, nil); err != nil { + if err := hook.Run(ctx, packer.HookProvision, ui, comm, hookData); err != nil { state.Put("error", err) return multistep.ActionHalt } diff --git a/builder/lxd/artifact.go b/builder/lxd/artifact.go index 481f0758e..ad229a82c 100644 --- a/builder/lxd/artifact.go +++ b/builder/lxd/artifact.go @@ -6,6 +6,10 @@ import ( type Artifact struct { id string + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } func (*Artifact) BuilderId() string { @@ -25,7 +29,7 @@ func (a *Artifact) String() string { } func (a *Artifact) State(name string) interface{} { - return nil + return a.StateData[name] } func (a *Artifact) Destroy() error { diff --git a/builder/lxd/builder.go b/builder/lxd/builder.go index 4cc58d8a4..5130e8d19 100644 --- a/builder/lxd/builder.go +++ b/builder/lxd/builder.go @@ -62,7 +62,8 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack } artifact := &Artifact{ - id: state.Get("imageFingerprint").(string), + id: state.Get("imageFingerprint").(string), + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil diff --git a/builder/lxd/step_provision.go b/builder/lxd/step_provision.go index 25d85059e..ec6da8a22 100644 --- a/builder/lxd/step_provision.go +++ b/builder/lxd/step_provision.go @@ -2,6 +2,7 @@ package lxd import ( "context" + "github.com/hashicorp/packer/common" "log" "github.com/hashicorp/packer/helper/multistep" @@ -23,9 +24,16 @@ func (s *StepProvision) Run(ctx context.Context, state multistep.StateBag) multi CmdWrapper: wrappedCommand, } + // Loads hook data from builder's state, if it has been set. + hookData := common.PopulateProvisionHookData(state) + + // Update state generated_data with complete hookData + // to make them accessible by post-processors + state.Put("generated_data", hookData) + // Provision log.Println("Running the provision hook") - if err := hook.Run(ctx, packer.HookProvision, ui, comm, nil); err != nil { + if err := hook.Run(ctx, packer.HookProvision, ui, comm, hookData); err != nil { state.Put("error", err) return multistep.ActionHalt } diff --git a/builder/ncloud/artifact.go b/builder/ncloud/artifact.go index 52624e437..01553a73c 100644 --- a/builder/ncloud/artifact.go +++ b/builder/ncloud/artifact.go @@ -11,6 +11,10 @@ const BuilderID = "ncloud.server.image" type Artifact struct { ServerImage *ncloud.ServerImage + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } func (*Artifact) BuilderId() string { @@ -38,6 +42,9 @@ func (a *Artifact) String() string { } func (a *Artifact) State(name string) interface{} { + if _, ok := a.StateData[name]; ok { + return a.StateData[name] + } return a.ServerImage.MemberServerImageStatus } diff --git a/builder/ncloud/builder.go b/builder/ncloud/builder.go index 4df0ed8d4..bce48aa90 100644 --- a/builder/ncloud/builder.go +++ b/builder/ncloud/builder.go @@ -104,7 +104,9 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack } // Build the artifact and return it - artifact := &Artifact{} + artifact := &Artifact{ + StateData: map[string]interface{}{"generated_data": b.stateBag.Get("generated_data")}, + } if serverImage, ok := b.stateBag.GetOk("memberServerImage"); ok { artifact.ServerImage = serverImage.(*ncloud.ServerImage) diff --git a/builder/oneandone/artifact.go b/builder/oneandone/artifact.go index ffa922475..c32c25158 100644 --- a/builder/oneandone/artifact.go +++ b/builder/oneandone/artifact.go @@ -7,6 +7,10 @@ import ( type Artifact struct { snapshotId string snapshotName string + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } func (*Artifact) BuilderId() string { @@ -29,7 +33,7 @@ func (a *Artifact) String() string { } func (a *Artifact) State(name string) interface{} { - return nil + return a.StateData[name] } func (a *Artifact) Destroy() error { diff --git a/builder/oneandone/builder.go b/builder/oneandone/builder.go index 9ad5a643c..94c9ac31c 100644 --- a/builder/oneandone/builder.go +++ b/builder/oneandone/builder.go @@ -69,6 +69,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack artifact := &Artifact{ snapshotName: b.config.SnapshotName, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } if id, ok := state.GetOk("snapshot_id"); ok { diff --git a/builder/openstack/artifact.go b/builder/openstack/artifact.go index 5492a0df3..db2759ad5 100644 --- a/builder/openstack/artifact.go +++ b/builder/openstack/artifact.go @@ -18,6 +18,10 @@ type Artifact struct { // OpenStack connection for performing API stuff. Client *gophercloud.ServiceClient + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } func (a *Artifact) BuilderId() string { @@ -38,7 +42,7 @@ func (a *Artifact) String() string { } func (a *Artifact) State(name string) interface{} { - return nil + return a.StateData[name] } func (a *Artifact) Destroy() error { diff --git a/builder/openstack/artifact_test.go b/builder/openstack/artifact_test.go index 5cf2b5834..82aae40dd 100644 --- a/builder/openstack/artifact_test.go +++ b/builder/openstack/artifact_test.go @@ -34,3 +34,29 @@ func TestArtifactString(t *testing.T) { t.Fatalf("bad: %s", result) } } + +func TestArtifactState_StateData(t *testing.T) { + expectedData := "this is the data" + artifact := &Artifact{ + StateData: map[string]interface{}{"state_data": expectedData}, + } + + // Valid state + result := artifact.State("state_data") + if result != expectedData { + t.Fatalf("Bad: State data was %s instead of %s", result, expectedData) + } + + // Invalid state + result = artifact.State("invalid_key") + if result != nil { + t.Fatalf("Bad: State should be nil for invalid state data name") + } + + // Nil StateData should not fail and should return nil + artifact = &Artifact{} + result = artifact.State("key") + if result != nil { + t.Fatalf("Bad: State should be nil for nil StateData") + } +} diff --git a/builder/openstack/builder.go b/builder/openstack/builder.go index 57ede0103..49267afef 100644 --- a/builder/openstack/builder.go +++ b/builder/openstack/builder.go @@ -184,6 +184,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack ImageId: state.Get("image").(string), BuilderIdValue: BuilderId, Client: imageClient, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil diff --git a/builder/oracle/classic/artifact.go b/builder/oracle/classic/artifact.go index 96fea768f..7a73acec8 100644 --- a/builder/oracle/classic/artifact.go +++ b/builder/oracle/classic/artifact.go @@ -10,6 +10,10 @@ type Artifact struct { MachineImageName string MachineImageFile string ImageListVersion int + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } // BuilderId uniquely identifies the builder. @@ -36,7 +40,7 @@ func (a *Artifact) String() string { } func (a *Artifact) State(name string) interface{} { - return nil + return a.StateData[name] } // Destroy deletes the custom image associated with the artifact. diff --git a/builder/oracle/classic/builder.go b/builder/oracle/classic/builder.go index 466db5324..1594dd0e1 100644 --- a/builder/oracle/classic/builder.go +++ b/builder/oracle/classic/builder.go @@ -197,6 +197,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack ImageListVersion: state.Get("image_list_version").(int), MachineImageName: state.Get("machine_image_name").(string), MachineImageFile: state.Get("machine_image_file").(string), + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil diff --git a/builder/oracle/oci/artifact.go b/builder/oracle/oci/artifact.go index 703cd062d..cfe37c571 100644 --- a/builder/oracle/oci/artifact.go +++ b/builder/oracle/oci/artifact.go @@ -12,6 +12,10 @@ type Artifact struct { Image core.Image Region string driver Driver + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } // BuilderId uniquely identifies the builder. @@ -44,7 +48,7 @@ func (a *Artifact) String() string { // State ... func (a *Artifact) State(name string) interface{} { - return nil + return a.StateData[name] } // Destroy deletes the custom image associated with the artifact. diff --git a/builder/oracle/oci/artifact_test.go b/builder/oracle/oci/artifact_test.go index 5cfbc1cb8..f7ab5d265 100644 --- a/builder/oracle/oci/artifact_test.go +++ b/builder/oracle/oci/artifact_test.go @@ -13,3 +13,29 @@ func TestArtifactImpl(t *testing.T) { t.Fatalf("Artifact should be artifact") } } + +func TestArtifactState_StateData(t *testing.T) { + expectedData := "this is the data" + artifact := &Artifact{ + StateData: map[string]interface{}{"state_data": expectedData}, + } + + // Valid state + result := artifact.State("state_data") + if result != expectedData { + t.Fatalf("Bad: State data was %s instead of %s", result, expectedData) + } + + // Invalid state + result = artifact.State("invalid_key") + if result != nil { + t.Fatalf("Bad: State should be nil for invalid state data name") + } + + // Nil StateData should not fail and should return nil + artifact = &Artifact{} + result = artifact.State("key") + if result != nil { + t.Fatalf("Bad: State should be nil for nil StateData") + } +} diff --git a/builder/oracle/oci/builder.go b/builder/oracle/oci/builder.go index 2fe35ebc1..cf1e5249a 100644 --- a/builder/oracle/oci/builder.go +++ b/builder/oracle/oci/builder.go @@ -98,9 +98,10 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack // Build the artifact and return it artifact := &Artifact{ - Image: image.(core.Image), - Region: region, - driver: driver, + Image: image.(core.Image), + Region: region, + driver: driver, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil diff --git a/builder/osc/bsu/builder.go b/builder/osc/bsu/builder.go index 2184b5b30..0230a2751 100644 --- a/builder/osc/bsu/builder.go +++ b/builder/osc/bsu/builder.go @@ -218,6 +218,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack Omis: omis.(map[string]string), BuilderIdValue: BuilderId, Config: clientConfig, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil diff --git a/builder/osc/bsusurrogate/builder.go b/builder/osc/bsusurrogate/builder.go index e532b11e6..f15a1c505 100644 --- a/builder/osc/bsusurrogate/builder.go +++ b/builder/osc/bsusurrogate/builder.go @@ -248,6 +248,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack Omis: omis.(map[string]string), BuilderIdValue: BuilderId, Config: clientConfig, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil diff --git a/builder/osc/bsuvolume/artifact.go b/builder/osc/bsuvolume/artifact.go index 61d92b6a2..274000293 100644 --- a/builder/osc/bsuvolume/artifact.go +++ b/builder/osc/bsuvolume/artifact.go @@ -23,6 +23,10 @@ type Artifact struct { // Client connection for performing API stuff. Conn *oapi.Client + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } func (a *Artifact) BuilderId() string { @@ -56,7 +60,7 @@ func (a *Artifact) String() string { } func (a *Artifact) State(name string) interface{} { - return nil + return a.StateData[name] } func (a *Artifact) Destroy() error { diff --git a/builder/osc/bsuvolume/builder.go b/builder/osc/bsuvolume/builder.go index ffb5f13f1..052b79157 100644 --- a/builder/osc/bsuvolume/builder.go +++ b/builder/osc/bsuvolume/builder.go @@ -199,6 +199,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack Volumes: state.Get("bsuvolumes").(BsuVolumes), BuilderIdValue: BuilderId, Conn: oapiconn, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } ui.Say(fmt.Sprintf("Created Volumes: %s", artifact)) return artifact, nil diff --git a/builder/osc/chroot/builder.go b/builder/osc/chroot/builder.go index a4963deb6..225dfc18f 100644 --- a/builder/osc/chroot/builder.go +++ b/builder/osc/chroot/builder.go @@ -308,6 +308,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack Omis: state.Get("omis").(map[string]string), BuilderIdValue: BuilderId, Config: clientConfig, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil diff --git a/builder/osc/chroot/step_chroot_provision.go b/builder/osc/chroot/step_chroot_provision.go index 4545105b0..25afd6edd 100644 --- a/builder/osc/chroot/step_chroot_provision.go +++ b/builder/osc/chroot/step_chroot_provision.go @@ -2,6 +2,7 @@ package chroot import ( "context" + "github.com/hashicorp/packer/common" "log" "github.com/hashicorp/packer/helper/multistep" @@ -24,9 +25,16 @@ func (s *StepChrootProvision) Run(ctx context.Context, state multistep.StateBag) CmdWrapper: wrappedCommand, } + // Loads hook data from builder's state, if it has been set. + hookData := common.PopulateProvisionHookData(state) + + // Update state generated_data with complete hookData + // to make them accessible by post-processors + state.Put("generated_data", hookData) + // Provision log.Println("Running the provision hook") - if err := hook.Run(ctx, packer.HookProvision, ui, comm, nil); err != nil { + if err := hook.Run(ctx, packer.HookProvision, ui, comm, hookData); err != nil { state.Put("error", err) return multistep.ActionHalt } diff --git a/builder/osc/common/artifact.go b/builder/osc/common/artifact.go index 3fe329891..891c3aa64 100644 --- a/builder/osc/common/artifact.go +++ b/builder/osc/common/artifact.go @@ -22,6 +22,10 @@ type Artifact struct { // OAPI connection for performing API stuff. Config *oapi.Config + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } func (a *Artifact) BuilderId() string { @@ -55,6 +59,10 @@ func (a *Artifact) String() string { } func (a *Artifact) State(name string) interface{} { + if _, ok := a.StateData[name]; ok { + return a.StateData[name] + } + switch name { case "atlas.artifact.metadata": return a.stateAtlasMetadata() diff --git a/builder/parallels/common/artifact.go b/builder/parallels/common/artifact.go index 65920145b..2e95be358 100644 --- a/builder/parallels/common/artifact.go +++ b/builder/parallels/common/artifact.go @@ -21,11 +21,15 @@ var unnecessaryFiles = []string{"\\.log$", "\\.backup$", "\\.Backup$", "\\.app"} type artifact struct { dir string f []string + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } // NewArtifact returns a Parallels artifact containing the files // in the given directory. -func NewArtifact(dir string) (packer.Artifact, error) { +func NewArtifact(dir string, generatedData map[string]interface{}) (packer.Artifact, error) { files := make([]string, 0, 5) visit := func(path string, info os.FileInfo, err error) error { if err != nil { @@ -57,8 +61,9 @@ func NewArtifact(dir string) (packer.Artifact, error) { } return &artifact{ - dir: dir, - f: files, + dir: dir, + f: files, + StateData: generatedData, }, nil } @@ -79,7 +84,7 @@ func (a *artifact) String() string { } func (a *artifact) State(name string) interface{} { - return nil + return a.StateData[name] } func (a *artifact) Destroy() error { diff --git a/builder/parallels/common/artifact_test.go b/builder/parallels/common/artifact_test.go index cb2da6d39..398d39fb5 100644 --- a/builder/parallels/common/artifact_test.go +++ b/builder/parallels/common/artifact_test.go @@ -29,7 +29,8 @@ func TestNewArtifact(t *testing.T) { t.Fatalf("err: %s", err) } - a, err := NewArtifact(td) + generatedData := map[string]interface{}{"generated_data": "data"} + a, err := NewArtifact(td, generatedData) if err != nil { t.Fatalf("err: %s", err) } @@ -40,4 +41,7 @@ func TestNewArtifact(t *testing.T) { if len(a.Files()) != 1 { t.Fatalf("should length 1: %d", len(a.Files())) } + if a.State("generated_data") != "data" { + t.Fatalf("bad: should length have generated_data: %s", a.State("generated_data")) + } } diff --git a/builder/parallels/iso/builder.go b/builder/parallels/iso/builder.go index 31a160226..6b446bc85 100644 --- a/builder/parallels/iso/builder.go +++ b/builder/parallels/iso/builder.go @@ -291,5 +291,6 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack return nil, errors.New("Build was halted.") } - return parallelscommon.NewArtifact(b.config.OutputDir) + generatedData := map[string]interface{}{"generated_data": state.Get("generated_data")} + return parallelscommon.NewArtifact(b.config.OutputDir, generatedData) } diff --git a/builder/parallels/pvm/builder.go b/builder/parallels/pvm/builder.go index bcecbcb02..5add2b27a 100644 --- a/builder/parallels/pvm/builder.go +++ b/builder/parallels/pvm/builder.go @@ -134,7 +134,8 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack return nil, errors.New("Build was halted.") } - return parallelscommon.NewArtifact(b.config.OutputDir) + generatedData := map[string]interface{}{"generated_data": state.Get("generated_data")} + return parallelscommon.NewArtifact(b.config.OutputDir, generatedData) } // Cancel. diff --git a/builder/profitbricks/artifact.go b/builder/profitbricks/artifact.go index f277c4f0a..344033fd0 100644 --- a/builder/profitbricks/artifact.go +++ b/builder/profitbricks/artifact.go @@ -6,6 +6,10 @@ import ( type Artifact struct { snapshotData string + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } func (*Artifact) BuilderId() string { @@ -25,7 +29,7 @@ func (a *Artifact) String() string { } func (a *Artifact) State(name string) interface{} { - return nil + return a.StateData[name] } func (a *Artifact) Destroy() error { diff --git a/builder/profitbricks/artifact_test.go b/builder/profitbricks/artifact_test.go index 1760f3b6a..a57746957 100644 --- a/builder/profitbricks/artifact_test.go +++ b/builder/profitbricks/artifact_test.go @@ -15,10 +15,37 @@ func TestArtifact_Impl(t *testing.T) { } func TestArtifactString(t *testing.T) { - a := &Artifact{"packer-foobar"} + generatedData := make(map[string]interface{}) + a := &Artifact{"packer-foobar", generatedData} expected := "A snapshot was created: 'packer-foobar'" if a.String() != expected { t.Fatalf("artifact string should match: %v", expected) } } + +func TestArtifactState_StateData(t *testing.T) { + expectedData := "this is the data" + artifact := &Artifact{ + StateData: map[string]interface{}{"state_data": expectedData}, + } + + // Valid state + result := artifact.State("state_data") + if result != expectedData { + t.Fatalf("Bad: State data was %s instead of %s", result, expectedData) + } + + // Invalid state + result = artifact.State("invalid_key") + if result != nil { + t.Fatalf("Bad: State should be nil for invalid state data name") + } + + // Nil StateData should not fail and should return nil + artifact = &Artifact{} + result = artifact.State("key") + if result != nil { + t.Fatalf("Bad: State should be nil for nil StateData") + } +} diff --git a/builder/profitbricks/builder.go b/builder/profitbricks/builder.go index 99666cd58..86d9d6ca5 100644 --- a/builder/profitbricks/builder.go +++ b/builder/profitbricks/builder.go @@ -64,6 +64,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack artifact := &Artifact{ snapshotData: config.SnapshotName, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil } diff --git a/builder/proxmox/artifact.go b/builder/proxmox/artifact.go index 99d8e1a20..8b11e266d 100644 --- a/builder/proxmox/artifact.go +++ b/builder/proxmox/artifact.go @@ -12,6 +12,10 @@ import ( type Artifact struct { templateID int proxmoxClient *proxmox.Client + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } // Artifact implements packer.Artifact @@ -34,7 +38,7 @@ func (a *Artifact) String() string { } func (a *Artifact) State(name string) interface{} { - return nil + return a.StateData[name] } func (a *Artifact) Destroy() error { diff --git a/builder/proxmox/builder.go b/builder/proxmox/builder.go index 4ca1c2d07..79f51a3b1 100644 --- a/builder/proxmox/builder.go +++ b/builder/proxmox/builder.go @@ -118,6 +118,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack artifact := &Artifact{ templateID: tplID, proxmoxClient: b.proxmoxClient, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil diff --git a/builder/qemu/builder.go b/builder/qemu/builder.go index c7b4f228d..32f2402c3 100644 --- a/builder/qemu/builder.go +++ b/builder/qemu/builder.go @@ -726,6 +726,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack state: make(map[string]interface{}), } + artifact.state["generated_data"] = state.Get("generated_data") artifact.state["diskName"] = b.config.VMName diskpaths, ok := state.Get("qemu_disk_paths").([]string) if ok { diff --git a/builder/scaleway/artifact.go b/builder/scaleway/artifact.go index b5aea88da..0e103cc42 100644 --- a/builder/scaleway/artifact.go +++ b/builder/scaleway/artifact.go @@ -25,6 +25,10 @@ type Artifact struct { // The client for making API calls client *api.ScalewayAPI + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } func (*Artifact) BuilderId() string { @@ -46,7 +50,7 @@ func (a *Artifact) String() string { } func (a *Artifact) State(name string) interface{} { - return nil + return a.StateData[name] } func (a *Artifact) Destroy() error { diff --git a/builder/scaleway/artifact_test.go b/builder/scaleway/artifact_test.go index 8f158ef5f..3583fd4e3 100644 --- a/builder/scaleway/artifact_test.go +++ b/builder/scaleway/artifact_test.go @@ -15,7 +15,8 @@ func TestArtifact_Impl(t *testing.T) { } func TestArtifactId(t *testing.T) { - a := &Artifact{"packer-foobar-image", "cc586e45-5156-4f71-b223-cf406b10dd1d", "packer-foobar-snapshot", "cc586e45-5156-4f71-b223-cf406b10dd1c", "ams1", nil} + generatedData := make(map[string]interface{}) + a := &Artifact{"packer-foobar-image", "cc586e45-5156-4f71-b223-cf406b10dd1d", "packer-foobar-snapshot", "cc586e45-5156-4f71-b223-cf406b10dd1c", "ams1", nil, generatedData} expected := "ams1:cc586e45-5156-4f71-b223-cf406b10dd1d" if a.Id() != expected { @@ -24,10 +25,37 @@ func TestArtifactId(t *testing.T) { } func TestArtifactString(t *testing.T) { - a := &Artifact{"packer-foobar-image", "cc586e45-5156-4f71-b223-cf406b10dd1d", "packer-foobar-snapshot", "cc586e45-5156-4f71-b223-cf406b10dd1c", "ams1", nil} + generatedData := make(map[string]interface{}) + a := &Artifact{"packer-foobar-image", "cc586e45-5156-4f71-b223-cf406b10dd1d", "packer-foobar-snapshot", "cc586e45-5156-4f71-b223-cf406b10dd1c", "ams1", nil, generatedData} expected := "An image was created: 'packer-foobar-image' (ID: cc586e45-5156-4f71-b223-cf406b10dd1d) in region 'ams1' based on snapshot 'packer-foobar-snapshot' (ID: cc586e45-5156-4f71-b223-cf406b10dd1c)" if a.String() != expected { t.Fatalf("artifact string should match: %v", expected) } } + +func TestArtifactState_StateData(t *testing.T) { + expectedData := "this is the data" + artifact := &Artifact{ + StateData: map[string]interface{}{"state_data": expectedData}, + } + + // Valid state + result := artifact.State("state_data") + if result != expectedData { + t.Fatalf("Bad: State data was %s instead of %s", result, expectedData) + } + + // Invalid state + result = artifact.State("invalid_key") + if result != nil { + t.Fatalf("Bad: State should be nil for invalid state data name") + } + + // Nil StateData should not fail and should return nil + artifact = &Artifact{} + result = artifact.State("key") + if result != nil { + t.Fatalf("Bad: State should be nil for nil StateData") + } +} diff --git a/builder/scaleway/builder.go b/builder/scaleway/builder.go index ac5f47561..0529557e6 100644 --- a/builder/scaleway/builder.go +++ b/builder/scaleway/builder.go @@ -98,6 +98,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack snapshotID: state.Get("snapshot_id").(string), regionName: state.Get("region").(string), client: client, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil diff --git a/builder/tencentcloud/cvm/artifact.go b/builder/tencentcloud/cvm/artifact.go index b5c38f579..7db1579f9 100644 --- a/builder/tencentcloud/cvm/artifact.go +++ b/builder/tencentcloud/cvm/artifact.go @@ -15,6 +15,10 @@ type Artifact struct { TencentCloudImages map[string]string BuilderIdValue string Client *cvm.Client + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } func (a *Artifact) BuilderId() string { @@ -46,6 +50,10 @@ func (a *Artifact) String() string { } func (a *Artifact) State(name string) interface{} { + if _, ok := a.StateData[name]; ok { + return a.StateData[name] + } + switch name { case "atlas.artifact.metadata": return a.stateAtlasMetadata() diff --git a/builder/tencentcloud/cvm/builder.go b/builder/tencentcloud/cvm/builder.go index d13a09828..eb60975ac 100644 --- a/builder/tencentcloud/cvm/builder.go +++ b/builder/tencentcloud/cvm/builder.go @@ -154,6 +154,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack TencentCloudImages: state.Get("tencentcloudimages").(map[string]string), BuilderIdValue: BuilderId, Client: cvmClient, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil diff --git a/builder/triton/artifact.go b/builder/triton/artifact.go index c36f7ab5c..50696f70a 100644 --- a/builder/triton/artifact.go +++ b/builder/triton/artifact.go @@ -15,6 +15,10 @@ type Artifact struct { // SDC connection for cleanup etc Driver Driver + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } func (a *Artifact) BuilderId() string { @@ -35,7 +39,7 @@ func (a *Artifact) String() string { func (a *Artifact) State(name string) interface{} { //TODO(jen20): Figure out how to make this work with Atlas - return nil + return a.StateData[name] } func (a *Artifact) Destroy() error { diff --git a/builder/triton/builder.go b/builder/triton/builder.go index 22759406b..50d9ddd6d 100644 --- a/builder/triton/builder.go +++ b/builder/triton/builder.go @@ -96,6 +96,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack ImageID: state.Get("image").(string), BuilderIDValue: BuilderId, Driver: driver, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil diff --git a/builder/ucloud/common/artifact.go b/builder/ucloud/common/artifact.go index 4daa8f68a..ae3b3554b 100644 --- a/builder/ucloud/common/artifact.go +++ b/builder/ucloud/common/artifact.go @@ -16,6 +16,10 @@ type Artifact struct { BuilderIdValue string Client *UCloudClient + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } func (a *Artifact) BuilderId() string { @@ -48,6 +52,10 @@ func (a *Artifact) String() string { } func (a *Artifact) State(name string) interface{} { + if _, ok := a.StateData[name]; ok { + return a.StateData[name] + } + switch name { case "atlas.artifact.metadata": return a.stateAtlasMetadata() diff --git a/builder/ucloud/common/artifact_test.go b/builder/ucloud/common/artifact_test.go index 8154766e3..a28fcb535 100644 --- a/builder/ucloud/common/artifact_test.go +++ b/builder/ucloud/common/artifact_test.go @@ -64,3 +64,29 @@ func TestArtifactState_atlasMetadata(t *testing.T) { t.Fatalf("bad: %#v", actual) } } + +func TestArtifactState_StateData(t *testing.T) { + expectedData := "this is the data" + artifact := &Artifact{ + StateData: map[string]interface{}{"state_data": expectedData}, + } + + // Valid state + result := artifact.State("state_data") + if result != expectedData { + t.Fatalf("Bad: State data was %s instead of %s", result, expectedData) + } + + // Invalid state + result = artifact.State("invalid_key") + if result != nil { + t.Fatalf("Bad: State should be nil for invalid state data name") + } + + // Nil StateData should not fail and should return nil + artifact = &Artifact{} + result = artifact.State("key") + if result != nil { + t.Fatalf("Bad: State should be nil for nil StateData") + } +} diff --git a/builder/ucloud/uhost/builder.go b/builder/ucloud/uhost/builder.go index 676114a6d..ce220f125 100644 --- a/builder/ucloud/uhost/builder.go +++ b/builder/ucloud/uhost/builder.go @@ -149,6 +149,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack UCloudImages: state.Get("ucloud_images").(*ucloudcommon.ImageInfoSet), BuilderIdValue: BuilderId, Client: client, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil diff --git a/builder/vagrant/artifact.go b/builder/vagrant/artifact.go index f7b2bfa18..bfad668d3 100644 --- a/builder/vagrant/artifact.go +++ b/builder/vagrant/artifact.go @@ -16,14 +16,19 @@ type artifact struct { OutputDir string BoxName string Provider string + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } // NewArtifact returns a vagrant artifact containing the .box file -func NewArtifact(provider, dir string) packer.Artifact { +func NewArtifact(provider, dir string, generatedData map[string]interface{}) packer.Artifact { return &artifact{ OutputDir: dir, BoxName: "package.box", Provider: provider, + StateData: generatedData, } } @@ -44,7 +49,7 @@ func (a *artifact) String() string { } func (a *artifact) State(name string) interface{} { - return nil + return a.StateData[name] } func (a *artifact) Destroy() error { diff --git a/builder/vagrant/artifact_test.go b/builder/vagrant/artifact_test.go index 31f06d833..e96bdd38c 100644 --- a/builder/vagrant/artifact_test.go +++ b/builder/vagrant/artifact_test.go @@ -44,3 +44,29 @@ func TestArtifactString(t *testing.T) { t.Fatalf("artifact string should match: expected: %s received: %s", expected, a.String()) } } + +func TestArtifactState(t *testing.T) { + expectedData := "this is the data" + a := &artifact{ + StateData: map[string]interface{}{"state_data": expectedData}, + } + + // Valid state + result := a.State("state_data") + if result != expectedData { + t.Fatalf("Bad: State data was %s instead of %s", result, expectedData) + } + + // Invalid state + result = a.State("invalid_key") + if result != nil { + t.Fatalf("Bad: State should be nil for invalid state data name") + } + + // Nil StateData should not fail and should return nil + a = &artifact{} + result = a.State("key") + if result != nil { + t.Fatalf("Bad: State should be nil for nil StateData") + } +} diff --git a/builder/vagrant/builder.go b/builder/vagrant/builder.go index 198cc753d..7b0cf9e2a 100644 --- a/builder/vagrant/builder.go +++ b/builder/vagrant/builder.go @@ -323,7 +323,8 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack return nil, errors.New("Build was halted.") } - return NewArtifact(b.config.Provider, b.config.OutputDir), nil + generatedData := map[string]interface{}{"generated_data": state.Get("generated_data")} + return NewArtifact(b.config.Provider, b.config.OutputDir, generatedData), nil } // Cancel. diff --git a/builder/virtualbox/common/artifact.go b/builder/virtualbox/common/artifact.go index e560e788d..1f78a0b32 100644 --- a/builder/virtualbox/common/artifact.go +++ b/builder/virtualbox/common/artifact.go @@ -16,11 +16,15 @@ const BuilderId = "mitchellh.virtualbox" type artifact struct { dir string f []string + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } // NewArtifact returns a VirtualBox artifact containing the files // in the given directory. -func NewArtifact(dir string) (packer.Artifact, error) { +func NewArtifact(dir string, generatedData map[string]interface{}) (packer.Artifact, error) { files := make([]string, 0, 5) visit := func(path string, info os.FileInfo, err error) error { if err != nil { @@ -38,8 +42,9 @@ func NewArtifact(dir string) (packer.Artifact, error) { } return &artifact{ - dir: dir, - f: files, + dir: dir, + f: files, + StateData: generatedData, }, nil } @@ -60,7 +65,7 @@ func (a *artifact) String() string { } func (a *artifact) State(name string) interface{} { - return nil + return a.StateData[name] } func (a *artifact) Destroy() error { diff --git a/builder/virtualbox/common/artifact_test.go b/builder/virtualbox/common/artifact_test.go index 023d2dd44..540b0d834 100644 --- a/builder/virtualbox/common/artifact_test.go +++ b/builder/virtualbox/common/artifact_test.go @@ -29,7 +29,8 @@ func TestNewArtifact(t *testing.T) { t.Fatalf("err: %s", err) } - a, err := NewArtifact(td) + generatedData := map[string]interface{}{"generated_data": "data"} + a, err := NewArtifact(td, generatedData) if err != nil { t.Fatalf("err: %s", err) } @@ -40,4 +41,7 @@ func TestNewArtifact(t *testing.T) { if len(a.Files()) != 1 { t.Fatalf("should length 1: %d", len(a.Files())) } + if a.State("generated_data") != "data" { + t.Fatalf("bad: should length have generated_data: %s", a.State("generated_data")) + } } diff --git a/builder/virtualbox/iso/builder.go b/builder/virtualbox/iso/builder.go index 2e2420106..ccc3c44e5 100644 --- a/builder/virtualbox/iso/builder.go +++ b/builder/virtualbox/iso/builder.go @@ -423,5 +423,6 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack return nil, errors.New("Build was halted.") } - return vboxcommon.NewArtifact(b.config.OutputDir) + generatedData := map[string]interface{}{"generated_data": state.Get("generated_data")} + return vboxcommon.NewArtifact(b.config.OutputDir, generatedData) } diff --git a/builder/virtualbox/ovf/builder.go b/builder/virtualbox/ovf/builder.go index 760b8986e..1c820c93c 100644 --- a/builder/virtualbox/ovf/builder.go +++ b/builder/virtualbox/ovf/builder.go @@ -181,7 +181,8 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack return nil, errors.New("Build was halted.") } - return vboxcommon.NewArtifact(b.config.OutputDir) + generatedData := map[string]interface{}{"generated_data": state.Get("generated_data")} + return vboxcommon.NewArtifact(b.config.OutputDir, generatedData) } // Cancel. diff --git a/builder/virtualbox/vm/builder.go b/builder/virtualbox/vm/builder.go index 2a3774262..96ac5ad80 100644 --- a/builder/virtualbox/vm/builder.go +++ b/builder/virtualbox/vm/builder.go @@ -176,5 +176,6 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack return nil, nil } - return vboxcommon.NewArtifact(b.config.OutputDir) + generatedData := map[string]interface{}{"generated_data": state.Get("generated_data")} + return vboxcommon.NewArtifact(b.config.OutputDir, generatedData) } diff --git a/builder/vmware/common/artifact.go b/builder/vmware/common/artifact.go index e9b02237e..fedb70a84 100644 --- a/builder/vmware/common/artifact.go +++ b/builder/vmware/common/artifact.go @@ -26,6 +26,10 @@ type artifact struct { dir OutputDir f []string config map[string]string + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } func (a *artifact) BuilderId() string { @@ -45,6 +49,9 @@ func (a *artifact) String() string { } func (a *artifact) State(name string) interface{} { + if _, ok := a.StateData[name]; ok { + return a.StateData[name] + } return a.config[name] } @@ -87,5 +94,6 @@ func NewArtifact(remoteType string, format string, exportOutputPath string, vmNa dir: dir, f: files, config: config, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, }, nil } diff --git a/builder/vsphere/clone/builder.go b/builder/vsphere/clone/builder.go index 8eb7a2e2a..56462e345 100644 --- a/builder/vsphere/clone/builder.go +++ b/builder/vsphere/clone/builder.go @@ -92,8 +92,9 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack return nil, nil } artifact := &common.Artifact{ - Name: b.config.VMName, - VM: state.Get("vm").(*driver.VirtualMachine), + Name: b.config.VMName, + VM: state.Get("vm").(*driver.VirtualMachine), + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil } diff --git a/builder/vsphere/common/artifact.go b/builder/vsphere/common/artifact.go index 863e1013d..95d18abfa 100644 --- a/builder/vsphere/common/artifact.go +++ b/builder/vsphere/common/artifact.go @@ -9,6 +9,10 @@ const BuilderId = "jetbrains.vsphere" type Artifact struct { Name string VM *driver.VirtualMachine + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } func (a *Artifact) BuilderId() string { @@ -28,7 +32,7 @@ func (a *Artifact) String() string { } func (a *Artifact) State(name string) interface{} { - return nil + return a.StateData[name] } func (a *Artifact) Destroy() error { diff --git a/builder/vsphere/iso/builder.go b/builder/vsphere/iso/builder.go index d1882fa26..89131ed10 100644 --- a/builder/vsphere/iso/builder.go +++ b/builder/vsphere/iso/builder.go @@ -141,8 +141,9 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack return nil, nil } artifact := &common.Artifact{ - Name: b.config.VMName, - VM: state.Get("vm").(*driver.VirtualMachine), + Name: b.config.VMName, + VM: state.Get("vm").(*driver.VirtualMachine), + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil } diff --git a/builder/yandex/artifact.go b/builder/yandex/artifact.go index dadc45b89..119bdd916 100644 --- a/builder/yandex/artifact.go +++ b/builder/yandex/artifact.go @@ -10,6 +10,10 @@ type Artifact struct { config *Config driver Driver image *compute.Image + + // StateData should store data such as GeneratedData + // to be shared with post-processors + StateData map[string]interface{} } //revive:disable:var-naming @@ -31,6 +35,10 @@ func (a *Artifact) String() string { } func (a *Artifact) State(name string) interface{} { + if _, ok := a.StateData[name]; ok { + return a.StateData[name] + } + switch name { case "ImageID": return a.image.Id diff --git a/builder/yandex/artifact_test.go b/builder/yandex/artifact_test.go index 9d167b702..a9831cbf5 100644 --- a/builder/yandex/artifact_test.go +++ b/builder/yandex/artifact_test.go @@ -41,3 +41,29 @@ func TestArtifact_String(t *testing.T) { t.Fatalf("artifact string should match: %v", expected) } } + +func TestArtifactState(t *testing.T) { + expectedData := "this is the data" + artifact := &Artifact{ + StateData: map[string]interface{}{"state_data": expectedData}, + } + + // Valid state + result := artifact.State("state_data") + if result != expectedData { + t.Fatalf("Bad: State data was %s instead of %s", result, expectedData) + } + + // Invalid state + result = artifact.State("invalid_key") + if result != nil { + t.Fatalf("Bad: State should be nil for invalid state data name") + } + + // Nil StateData should not fail and should return nil + artifact = &Artifact{} + result = artifact.State("key") + if result != nil { + t.Fatalf("Bad: State should be nil for nil StateData") + } +} diff --git a/builder/yandex/builder.go b/builder/yandex/builder.go index d461eb525..c4b544c97 100644 --- a/builder/yandex/builder.go +++ b/builder/yandex/builder.go @@ -91,8 +91,9 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack } artifact := &Artifact{ - image: image.(*compute.Image), - config: &b.config, + image: image.(*compute.Image), + config: &b.config, + StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, } return artifact, nil } diff --git a/common/chroot/step_chroot_provision.go b/common/chroot/step_chroot_provision.go index 19a6ec8aa..5ab7182eb 100644 --- a/common/chroot/step_chroot_provision.go +++ b/common/chroot/step_chroot_provision.go @@ -28,6 +28,10 @@ func (s *StepChrootProvision) Run(ctx context.Context, state multistep.StateBag) // Loads hook data from builder's state, if it has been set. hookData := common.PopulateProvisionHookData(state) + // Update state generated_data with complete hookData + // to make them accessible by post-processors + state.Put("generated_data", hookData) + // Provision log.Println("Running the provision hook") if err := hook.Run(ctx, packer.HookProvision, ui, comm, hookData); err != nil { diff --git a/common/step_provision.go b/common/step_provision.go index 730829af1..c02192f92 100644 --- a/common/step_provision.go +++ b/common/step_provision.go @@ -36,9 +36,6 @@ func PopulateProvisionHookData(state multistep.StateBag) map[string]interface{} // Implemented in most others including digitalOcean (droplet id), // docker (container_id), and clouds which use "server" internally instead // of instance. - - // Also note that Chroot and lxc/lxd builders tend to have their own custom - // step_provision, so they won't use this code path. id, ok := state.GetOk("instance_id") if ok { hookData["ID"] = id @@ -93,6 +90,10 @@ func (s *StepProvision) runWithHook(ctx context.Context, state multistep.StateBa hookData := PopulateProvisionHookData(state) + // Update state generated_data with complete hookData + // to make them accessible by post-processors + state.Put("generated_data", hookData) + // Run the provisioner in a goroutine so we can continually check // for cancellations... if hooktype == packer.HookProvision { diff --git a/post-processor/alicloud-import/post-processor.go b/post-processor/alicloud-import/post-processor.go index a38ad7b13..fd5da203c 100644 --- a/post-processor/alicloud-import/post-processor.go +++ b/post-processor/alicloud-import/post-processor.go @@ -135,6 +135,13 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { func (p *PostProcessor) PostProcess(ctx context.Context, ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, bool, error) { var err error + generatedData := artifact.State("generated_data") + if generatedData == nil { + // Make sure it's not a nil map so we can assign to it later. + generatedData = make(map[string]interface{}) + } + p.config.ctx.Data = generatedData + // Render this key since we didn't in the configure phase p.config.OSSKey, err = interpolate.Render(p.config.OSSKey, &p.config.ctx) if err != nil { diff --git a/post-processor/amazon-import/post-processor.go b/post-processor/amazon-import/post-processor.go index f64decbe0..886dbac56 100644 --- a/post-processor/amazon-import/post-processor.go +++ b/post-processor/amazon-import/post-processor.go @@ -127,6 +127,13 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { func (p *PostProcessor) PostProcess(ctx context.Context, ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, bool, error) { var err error + generatedData := artifact.State("generated_data") + if generatedData == nil { + // Make sure it's not a nil map so we can assign to it later. + generatedData = make(map[string]interface{}) + } + p.config.ctx.Data = generatedData + session, err := p.config.Session() if err != nil { return nil, false, false, err diff --git a/post-processor/artifice/post-processor_test.go b/post-processor/artifice/post-processor_test.go deleted file mode 100644 index 7e087e3e8..000000000 --- a/post-processor/artifice/post-processor_test.go +++ /dev/null @@ -1 +0,0 @@ -package artifice diff --git a/post-processor/checksum/post-processor.go b/post-processor/checksum/post-processor.go index 3495a633f..3ad171e47 100644 --- a/post-processor/checksum/post-processor.go +++ b/post-processor/checksum/post-processor.go @@ -34,12 +34,6 @@ type PostProcessor struct { config Config } -type outputPathTemplate struct { - BuildName string - BuilderType string - ChecksumType string -} - func getHash(t string) hash.Hash { var h hash.Hash switch t { @@ -105,16 +99,26 @@ func (p *PostProcessor) PostProcess(ctx context.Context, ui packer.Ui, artifact files := artifact.Files() var h hash.Hash - newartifact := NewArtifact(artifact.Files()) - opTpl := &outputPathTemplate{ - BuildName: p.config.PackerBuildName, - BuilderType: p.config.PackerBuilderType, + var generatedData map[interface{}]interface{} + stateData := artifact.State("generated_data") + if stateData != nil { + // Make sure it's not a nil map so we can assign to it later. + generatedData = stateData.(map[interface{}]interface{}) } + // If stateData has a nil map generatedData will be nil + // and we need to make sure it's not + if generatedData == nil { + generatedData = make(map[interface{}]interface{}) + } + generatedData["BuildName"] = p.config.PackerBuildName + generatedData["BuilderType"] = p.config.PackerBuilderType + + newartifact := NewArtifact(artifact.Files()) for _, ct := range p.config.ChecksumTypes { h = getHash(ct) - opTpl.ChecksumType = ct - p.config.ctx.Data = &opTpl + generatedData["ChecksumType"] = ct + p.config.ctx.Data = generatedData for _, art := range files { checksumFile, err := interpolate.Render(p.config.OutputPath, &p.config.ctx) diff --git a/post-processor/compress/post-processor.go b/post-processor/compress/post-processor.go index 8777cab49..bc690e351 100644 --- a/post-processor/compress/post-processor.go +++ b/post-processor/compress/post-processor.go @@ -109,12 +109,22 @@ func (p *PostProcessor) PostProcess( ui packer.Ui, artifact packer.Artifact, ) (packer.Artifact, bool, bool, error) { + var generatedData map[interface{}]interface{} + stateData := artifact.State("generated_data") + if stateData != nil { + // Make sure it's not a nil map so we can assign to it later. + generatedData = stateData.(map[interface{}]interface{}) + } + // If stateData has a nil map generatedData will be nil + // and we need to make sure it's not + if generatedData == nil { + generatedData = make(map[interface{}]interface{}) + } // These are extra variables that will be made available for interpolation. - p.config.ctx.Data = map[string]string{ - "BuildName": p.config.PackerBuildName, - "BuilderType": p.config.PackerBuilderType, - } + generatedData["BuildName"] = p.config.PackerBuildName + generatedData["BuilderType"] = p.config.PackerBuilderType + p.config.ctx.Data = generatedData target, err := interpolate.Render(p.config.OutputPath, &p.config.ctx) if err != nil { diff --git a/post-processor/digitalocean-import/post-processor.go b/post-processor/digitalocean-import/post-processor.go index 50f70013a..746d7a95a 100644 --- a/post-processor/digitalocean-import/post-processor.go +++ b/post-processor/digitalocean-import/post-processor.go @@ -150,6 +150,13 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { func (p *PostProcessor) PostProcess(ctx context.Context, ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, bool, error) { var err error + generatedData := artifact.State("generated_data") + if generatedData == nil { + // Make sure it's not a nil map so we can assign to it later. + generatedData = make(map[string]interface{}) + } + p.config.ctx.Data = generatedData + p.config.ObjectName, err = interpolate.Render(p.config.ObjectName, &p.config.ctx) if err != nil { return nil, false, false, fmt.Errorf("Error rendering space_object_name template: %s", err) diff --git a/post-processor/googlecompute-import/post-processor.go b/post-processor/googlecompute-import/post-processor.go index 1eaf9f954..bca834c98 100644 --- a/post-processor/googlecompute-import/post-processor.go +++ b/post-processor/googlecompute-import/post-processor.go @@ -110,6 +110,13 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { } func (p *PostProcessor) PostProcess(ctx context.Context, ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, bool, error) { + generatedData := artifact.State("generated_data") + if generatedData == nil { + // Make sure it's not a nil map so we can assign to it later. + generatedData = make(map[string]interface{}) + } + p.config.ctx.Data = generatedData + client, err := googlecompute.NewClientGCE(p.config.account, p.config.VaultGCPOauthEngine) if err != nil { return nil, false, false, err diff --git a/post-processor/shell-local/post-processor.go b/post-processor/shell-local/post-processor.go index 5cbab3fd6..0cbf9fe71 100644 --- a/post-processor/shell-local/post-processor.go +++ b/post-processor/shell-local/post-processor.go @@ -41,10 +41,15 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { } func (p *PostProcessor) PostProcess(ctx context.Context, ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, bool, error) { - // this particular post-processor doesn't do anything with the artifact - // except to return it. + generatedData := make(map[string]interface{}) + artifactSateData := artifact.State("generated_data") + if artifactSateData != nil { + for k, v := range artifactSateData.(map[interface{}]interface{}) { + generatedData[k.(string)] = v + } + } - success, retErr := sl.Run(ctx, ui, &p.config, map[string]interface{}{}) + success, retErr := sl.Run(ctx, ui, &p.config, generatedData) if !success { return nil, false, false, retErr } diff --git a/post-processor/ucloud-import/post-processor.go b/post-processor/ucloud-import/post-processor.go index a0ec219ed..ba2490a7e 100644 --- a/post-processor/ucloud-import/post-processor.go +++ b/post-processor/ucloud-import/post-processor.go @@ -138,6 +138,13 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { func (p *PostProcessor) PostProcess(ctx context.Context, ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, bool, error) { var err error + generatedData := artifact.State("generated_data") + if generatedData == nil { + // Make sure it's not a nil map so we can assign to it later. + generatedData = make(map[string]interface{}) + } + p.config.ctx.Data = generatedData + client, err := p.config.Client() if err != nil { return nil, false, false, fmt.Errorf("Failed to connect ucloud client %s", err) diff --git a/post-processor/vagrant-cloud/post-processor.go b/post-processor/vagrant-cloud/post-processor.go index d6283e4e5..26a30cc1a 100644 --- a/post-processor/vagrant-cloud/post-processor.go +++ b/post-processor/vagrant-cloud/post-processor.go @@ -51,11 +51,6 @@ type Config struct { ctx interpolate.Context } -type boxDownloadUrlTemplate struct { - ArtifactId string - Provider string -} - type PostProcessor struct { config Config client *VagrantCloudClient @@ -154,10 +149,20 @@ func (p *PostProcessor) PostProcess(ctx context.Context, ui packer.Ui, artifact return nil, false, false, fmt.Errorf("error getting provider name: %s", err) } - p.config.ctx.Data = &boxDownloadUrlTemplate{ - ArtifactId: artifact.Id(), - Provider: providerName, + var generatedData map[interface{}]interface{} + stateData := artifact.State("generated_data") + if stateData != nil { + // Make sure it's not a nil map so we can assign to it later. + generatedData = stateData.(map[interface{}]interface{}) } + // If stateData has a nil map generatedData will be nil + // and we need to make sure it's not + if generatedData == nil { + generatedData = make(map[interface{}]interface{}) + } + generatedData["ArtifactId"] = artifact.Id() + generatedData["Provider"] = providerName + p.config.ctx.Data = generatedData boxDownloadUrl, err := interpolate.Render(p.config.BoxDownloadUrl, &p.config.ctx) if err != nil { diff --git a/post-processor/vagrant/post-processor.go b/post-processor/vagrant/post-processor.go index ea2144263..15faa0c9e 100644 --- a/post-processor/vagrant/post-processor.go +++ b/post-processor/vagrant/post-processor.go @@ -83,11 +83,22 @@ func (p *PostProcessor) PostProcessProvider(name string, provider Provider, ui p ui.Say(fmt.Sprintf("Creating Vagrant box for '%s' provider", name)) - config.ctx.Data = &outputPathTemplate{ - ArtifactId: artifact.Id(), - BuildName: config.PackerBuildName, - Provider: name, + var generatedData map[interface{}]interface{} + stateData := artifact.State("generated_data") + if stateData != nil { + // Make sure it's not a nil map so we can assign to it later. + generatedData = stateData.(map[interface{}]interface{}) } + // If stateData has a nil map generatedData will be nil + // and we need to make sure it's not + if generatedData == nil { + generatedData = make(map[interface{}]interface{}) + } + generatedData["ArtifactId"] = artifact.Id() + generatedData["BuildName"] = config.PackerBuildName + generatedData["Provider"] = name + config.ctx.Data = generatedData + outputPath, err := interpolate.Render(config.OutputPath, &config.ctx) if err != nil { return nil, false, err @@ -271,14 +282,6 @@ func providerForName(name string) Provider { } } -// OutputPathTemplate is the structure that is available within the -// OutputPath variables. -type outputPathTemplate struct { - ArtifactId string - BuildName string - Provider string -} - type vagrantfileTemplate struct { ProviderVagrantfile string CustomVagrantfile string