Sharing info with post-processors via artifact (#8632)

This commit is contained in:
Sylvia Moss 2020-01-30 11:27:58 +01:00 committed by GitHub
parent f5c58c8e83
commit dc31bad539
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
109 changed files with 847 additions and 152 deletions

View File

@ -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{}

View File

@ -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")
}
}

View File

@ -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{}

View File

@ -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")
}
}

View File

@ -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()

View File

@ -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")
}
}

View File

@ -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) {

View File

@ -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

View File

@ -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 {

View File

@ -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]
}

View File

@ -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")
}
}

View File

@ -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

View File

@ -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 {

View File

@ -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")
}
}

View File

@ -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

View File

@ -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 {

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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")
}
}

View File

@ -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
}

View File

@ -1 +0,0 @@
package googlecompute

View File

@ -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 {

View File

@ -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")
}
}

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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 {

View File

@ -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"))
}
}

View File

@ -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.

View File

@ -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.

View File

@ -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 {

View File

@ -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
}

View File

@ -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)

View File

@ -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")
}
}

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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
}

View File

@ -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 {

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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)

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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")
}
}

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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.

View File

@ -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")
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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()

View File

@ -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 {

View File

@ -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"))
}
}

View File

@ -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)
}

View File

@ -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.

View File

@ -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 {

View File

@ -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")
}
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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

View File

@ -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 {

View File

@ -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 {

View File

@ -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")
}
}

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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()

View File

@ -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")
}
}

View File

@ -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

View File

@ -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 {

View File

@ -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")
}
}

View File

@ -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.

View File

@ -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 {

View File

@ -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"))
}
}

View File

@ -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)
}

View File

@ -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.

View File

@ -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)
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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
}

View File

@ -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

View File

@ -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")
}
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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

Some files were not shown because too many files have changed in this diff Show More