From b94afa7cef1f995e22c13555fbf4bdf6eb5aaf21 Mon Sep 17 00:00:00 2001 From: James Johnson Date: Tue, 20 Sep 2016 11:30:22 -0400 Subject: [PATCH 1/4] Expose the id of the image created by the Openstack builder --- builder/openstack/builder.go | 5 +++ builder/openstack/image_config.go | 16 +++++++- builder/openstack/step_create_image.go | 38 +++++++++++++++++++ .../source/docs/builders/openstack.html.md | 12 ++++++ 4 files changed, 69 insertions(+), 2 deletions(-) diff --git a/builder/openstack/builder.go b/builder/openstack/builder.go index d83086182d2..a9c5b4e4190 100644 --- a/builder/openstack/builder.go +++ b/builder/openstack/builder.go @@ -37,6 +37,11 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { err := config.Decode(&b.config, &config.DecodeOpts{ Interpolate: true, InterpolateContext: &b.config.ctx, + InterpolateFilter: &interpolate.RenderFilter{ + Exclude: []string{ + "image_info_content", + }, + }, }, raws...) if err != nil { return nil, err diff --git a/builder/openstack/image_config.go b/builder/openstack/image_config.go index 6a40296b1ef..c7907838bc5 100644 --- a/builder/openstack/image_config.go +++ b/builder/openstack/image_config.go @@ -8,8 +8,10 @@ import ( // ImageConfig is for common configuration related to creating Images. type ImageConfig struct { - ImageName string `mapstructure:"image_name"` - ImageMetadata map[string]string `mapstructure:"metadata"` + ImageName string `mapstructure:"image_name"` + ImageMetadata map[string]string `mapstructure:"metadata"` + ImageInfoFile string `mapstructure:"image_info_file"` + ImageInfoContent string `mapstructure:"image_info_content"` } func (c *ImageConfig) Prepare(ctx *interpolate.Context) []error { @@ -18,6 +20,16 @@ func (c *ImageConfig) Prepare(ctx *interpolate.Context) []error { errs = append(errs, fmt.Errorf("An image_name must be specified")) } + if c.ImageInfoFile == "" { + c.ImageInfoFile = "openstack-builder.json" + } + if c.ImageInfoContent == "" { + c.ImageInfoContent = "{ \"imageName\": \"{{.ImageName}}\", \"imageId\": \"{{.ImageId}}\" }\n" + } + if c.ImageInfoContent == "" { + errs = append(errs, fmt.Errorf("image_info_content must be specified")) + } + // By default, OpenStack seems to create the image with an image_type of // "snapshot", since it came from snapshotting a VM. A "snapshot" looks // slightly different in the OpenStack UI and OpenStack won't show "snapshot" diff --git a/builder/openstack/step_create_image.go b/builder/openstack/step_create_image.go index 5c39b0ffc2d..dc46daa98b6 100644 --- a/builder/openstack/step_create_image.go +++ b/builder/openstack/step_create_image.go @@ -4,9 +4,11 @@ import ( "fmt" "log" "time" + "os" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" + "github.com/mitchellh/packer/template/interpolate" "github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud/openstack/compute/v2/images" "github.com/rackspace/gophercloud/openstack/compute/v2/servers" @@ -14,6 +16,11 @@ import ( type stepCreateImage struct{} +type createImageTemplateData struct { + ImageId string + ImageName string +} + func (s *stepCreateImage) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(Config) server := state.Get("server").(*servers.Server) @@ -53,6 +60,37 @@ func (s *stepCreateImage) Run(state multistep.StateBag) multistep.StepAction { return multistep.ActionHalt } + ctx := config.ctx + ctx.Data = &createImageTemplateData{ + imageId, + config.ImageName, + } + + if config.ImageInfoFile != "" { + target, err := os.Create(config.ImageInfoFile) + if err != nil { + err := fmt.Errorf("Error creating local image information file: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + information, err := interpolate.Render(config.ImageInfoContent, &ctx) + if err != nil { + err := fmt.Errorf("Failed to process image_info_content: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + _, err = target.WriteString(information) + if err != nil { + err := fmt.Errorf("Failed to write to image_info_file: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + target.Close() + } + return multistep.ActionContinue } diff --git a/website/source/docs/builders/openstack.html.md b/website/source/docs/builders/openstack.html.md index c914e999f16..11b544d102f 100644 --- a/website/source/docs/builders/openstack.html.md +++ b/website/source/docs/builders/openstack.html.md @@ -96,6 +96,14 @@ builder. - `floating_ip_pool` (string) - The name of the floating IP pool to use to allocate a floating IP. +- `image_info_file` (string) - The name of the local file in which to write + `image_info_content`. By default this is "openstack-builder.json". + If empty, no file will be written. Use the [Artifice](https://www.packer.io/docs/post-processors/artifice.html) post-processor to make this available to + other post-processors. + +- `image_info_content` (string) - The content to write to `image_info_file`. + By default this is "{ \"imageName\": \"{{.ImageName}}\", \"imageId\": \"{{.ImageId}}\" }\n" + - `insecure` (boolean) - Whether or not the connection to OpenStack can be done over an insecure connection. By default this is false. @@ -146,6 +154,10 @@ builder. - `user_data_file` (string) - Path to a file that will be used for the user data when launching the instance. +## Template Variables + +The variables `ImageName` and `ImageId` are available for use by `image_info_content` after the builder has created the image in Openstack. + ## Basic Example: DevStack Here is a basic example. This is a example to build on DevStack running in a VM. From ada166d6bdac2ac89db3cc6b770150bdcfb593ab Mon Sep 17 00:00:00 2001 From: James Johnson Date: Tue, 20 Sep 2016 11:57:28 -0400 Subject: [PATCH 2/4] Do not default ImageInfoFile in case the user does not want it created. --- builder/openstack/image_config.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/builder/openstack/image_config.go b/builder/openstack/image_config.go index c7907838bc5..13c80bbc8ca 100644 --- a/builder/openstack/image_config.go +++ b/builder/openstack/image_config.go @@ -20,9 +20,8 @@ func (c *ImageConfig) Prepare(ctx *interpolate.Context) []error { errs = append(errs, fmt.Errorf("An image_name must be specified")) } - if c.ImageInfoFile == "" { - c.ImageInfoFile = "openstack-builder.json" - } + // ImageInfoContent is required but ImageInfoFile is not. + // The information file will only be created if ImageInfoFile is not "". if c.ImageInfoContent == "" { c.ImageInfoContent = "{ \"imageName\": \"{{.ImageName}}\", \"imageId\": \"{{.ImageId}}\" }\n" } From 3dcf1fb5ca653336f6a25fb81316ef02489de7d7 Mon Sep 17 00:00:00 2001 From: James Johnson Date: Mon, 3 Oct 2016 15:04:53 -0400 Subject: [PATCH 3/4] Set Artifact to artifact.Id() if artifact.Files() is nil. --- post-processor/shell-local/post-processor.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/post-processor/shell-local/post-processor.go b/post-processor/shell-local/post-processor.go index 45c9ddb8557..fe9efe1166c 100644 --- a/post-processor/shell-local/post-processor.go +++ b/post-processor/shell-local/post-processor.go @@ -172,7 +172,14 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac envVars[1] = fmt.Sprintf("PACKER_BUILDER_TYPE='%s'", p.config.PackerBuilderType) copy(envVars[2:], p.config.Vars) - for _, file := range artifact.Files() { + // By default, and for backward compatibility, iterate over the artifact's files. + // If there are no files, however, provide the Artifact.Id. + artifacts := artifact.Files() + if artifacts == nil { + artifacts = []string{artifact.Id()} + } + + for _, file := range artifacts { for _, script := range scripts { // Flatten the environment variables flattendVars := strings.Join(envVars, " ") From d44d8651bfb579b99acb877d99431d4b396ddcc6 Mon Sep 17 00:00:00 2001 From: James Johnson Date: Mon, 3 Oct 2016 15:15:40 -0400 Subject: [PATCH 4/4] Back out changes to Openstack builder --- builder/openstack/builder.go | 5 ---- builder/openstack/image_config.go | 15 ++-------- builder/openstack/step_create_image.go | 38 -------------------------- 3 files changed, 2 insertions(+), 56 deletions(-) diff --git a/builder/openstack/builder.go b/builder/openstack/builder.go index 91adc3460ce..2e7f00e7ff1 100644 --- a/builder/openstack/builder.go +++ b/builder/openstack/builder.go @@ -37,11 +37,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { err := config.Decode(&b.config, &config.DecodeOpts{ Interpolate: true, InterpolateContext: &b.config.ctx, - InterpolateFilter: &interpolate.RenderFilter{ - Exclude: []string{ - "image_info_content", - }, - }, }, raws...) if err != nil { return nil, err diff --git a/builder/openstack/image_config.go b/builder/openstack/image_config.go index 13c80bbc8ca..6a40296b1ef 100644 --- a/builder/openstack/image_config.go +++ b/builder/openstack/image_config.go @@ -8,10 +8,8 @@ import ( // ImageConfig is for common configuration related to creating Images. type ImageConfig struct { - ImageName string `mapstructure:"image_name"` - ImageMetadata map[string]string `mapstructure:"metadata"` - ImageInfoFile string `mapstructure:"image_info_file"` - ImageInfoContent string `mapstructure:"image_info_content"` + ImageName string `mapstructure:"image_name"` + ImageMetadata map[string]string `mapstructure:"metadata"` } func (c *ImageConfig) Prepare(ctx *interpolate.Context) []error { @@ -20,15 +18,6 @@ func (c *ImageConfig) Prepare(ctx *interpolate.Context) []error { errs = append(errs, fmt.Errorf("An image_name must be specified")) } - // ImageInfoContent is required but ImageInfoFile is not. - // The information file will only be created if ImageInfoFile is not "". - if c.ImageInfoContent == "" { - c.ImageInfoContent = "{ \"imageName\": \"{{.ImageName}}\", \"imageId\": \"{{.ImageId}}\" }\n" - } - if c.ImageInfoContent == "" { - errs = append(errs, fmt.Errorf("image_info_content must be specified")) - } - // By default, OpenStack seems to create the image with an image_type of // "snapshot", since it came from snapshotting a VM. A "snapshot" looks // slightly different in the OpenStack UI and OpenStack won't show "snapshot" diff --git a/builder/openstack/step_create_image.go b/builder/openstack/step_create_image.go index dc46daa98b6..5c39b0ffc2d 100644 --- a/builder/openstack/step_create_image.go +++ b/builder/openstack/step_create_image.go @@ -4,11 +4,9 @@ import ( "fmt" "log" "time" - "os" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" - "github.com/mitchellh/packer/template/interpolate" "github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud/openstack/compute/v2/images" "github.com/rackspace/gophercloud/openstack/compute/v2/servers" @@ -16,11 +14,6 @@ import ( type stepCreateImage struct{} -type createImageTemplateData struct { - ImageId string - ImageName string -} - func (s *stepCreateImage) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(Config) server := state.Get("server").(*servers.Server) @@ -60,37 +53,6 @@ func (s *stepCreateImage) Run(state multistep.StateBag) multistep.StepAction { return multistep.ActionHalt } - ctx := config.ctx - ctx.Data = &createImageTemplateData{ - imageId, - config.ImageName, - } - - if config.ImageInfoFile != "" { - target, err := os.Create(config.ImageInfoFile) - if err != nil { - err := fmt.Errorf("Error creating local image information file: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - information, err := interpolate.Render(config.ImageInfoContent, &ctx) - if err != nil { - err := fmt.Errorf("Failed to process image_info_content: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - _, err = target.WriteString(information) - if err != nil { - err := fmt.Errorf("Failed to write to image_info_file: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - target.Close() - } - return multistep.ActionContinue }