diff --git a/builder/oracle/classic/config.go b/builder/oracle/classic/config.go index 4cd7c42a7..52a08cbe9 100644 --- a/builder/oracle/classic/config.go +++ b/builder/oracle/classic/config.go @@ -3,6 +3,7 @@ package classic import ( "fmt" "net/url" + "os" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/helper/communicator" @@ -27,6 +28,9 @@ type Config struct { Shape string `mapstructure:"shape"` SourceImageList string `mapstructure:"source_image_list"` DestImageList string `mapstructure:"dest_image_list"` + // Attributes and Atributes file are both optional and mutually exclusive. + Attributes string `mapstructure:"attributes"` + AttributesFile string `mapstructure:"attributes_file"` // Optional; if you don't enter anything, the image list description // will read "Packer-built image list" DestImageListDescription string `mapstructure:"image_description"` @@ -81,9 +85,21 @@ func NewConfig(raws ...interface{}) (*Config, error) { } } + if c.Attributes != "" && c.AttributesFile != "" { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("Only one of user_data or user_data_file can be specified.")) + } else if c.AttributesFile != "" { + if _, err := os.Stat(c.AttributesFile); err != nil { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("attributes_file not found: %s", c.AttributesFile)) + } + } + if es := c.Comm.Prepare(&c.ctx); len(es) > 0 { errs = packer.MultiErrorAppend(errs, es...) } + if c.Comm.Type == "winrm" { + err = fmt.Errorf("winRM is not supported with the oracle-classic builder yet.") + errs = packer.MultiErrorAppend(errs, err) + } if errs != nil && len(errs.Errors) > 0 { return nil, errs diff --git a/builder/oracle/classic/step_create_instance.go b/builder/oracle/classic/step_create_instance.go index 041889ab1..cf4b043fe 100644 --- a/builder/oracle/classic/step_create_instance.go +++ b/builder/oracle/classic/step_create_instance.go @@ -2,7 +2,9 @@ package classic import ( "context" + "encoding/json" "fmt" + "io/ioutil" "github.com/hashicorp/go-oracle-terraform/compute" "github.com/hashicorp/packer/helper/multistep" @@ -30,6 +32,33 @@ func (s *stepCreateInstance) Run(_ context.Context, state multistep.StateBag) mu // get instances client instanceClient := client.Instances() + var data map[string]interface{} + + if config.Attributes != "" { + err := json.Unmarshal([]byte(config.Attributes), &data) + if err != nil { + err = fmt.Errorf("Problem parsing json from attributes: %s", err) + ui.Error(err.Error()) + state.Put("error", err) + return multistep.ActionHalt + } + } else if config.AttributesFile != "" { + fidata, err := ioutil.ReadFile(config.AttributesFile) + if err != nil { + err = fmt.Errorf("Problem reading attributes_file: %s", err) + ui.Error(err.Error()) + state.Put("error", err) + return multistep.ActionHalt + } + err = json.Unmarshal(fidata, &data) + if err != nil { + err = fmt.Errorf("Problem parsing json from attrinutes_file: %s", err) + ui.Error(err.Error()) + state.Put("error", err) + return multistep.ActionHalt + } + } + // Instances Input input := &compute.CreateInstanceInput{ Name: config.ImageName, @@ -37,6 +66,7 @@ func (s *stepCreateInstance) Run(_ context.Context, state multistep.StateBag) mu ImageList: config.SourceImageList, SSHKeys: []string{keyName}, Networking: map[string]compute.NetworkingInfo{"eth0": netInfo}, + Attributes: data, } instanceInfo, err := instanceClient.CreateInstance(input) diff --git a/builder/oracle/classic/step_list_images.go b/builder/oracle/classic/step_list_images.go index a99612c14..247b96146 100644 --- a/builder/oracle/classic/step_list_images.go +++ b/builder/oracle/classic/step_list_images.go @@ -11,11 +11,10 @@ import ( type stepListImages struct{} -func (s *stepListImages) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { - // get variables from state - ui := state.Get("ui").(packer.Ui) - config := state.Get("config").(*Config) +func (s *stepListImages) listForSSH(state multistep.StateBag) multistep.StepAction { client := state.Get("client").(*compute.ComputeClient) + config := state.Get("config").(*Config) + ui := state.Get("ui").(packer.Ui) ui.Say("Adding image to image list...") imageListClient := client.ImageList() @@ -98,6 +97,29 @@ func (s *stepListImages) Run(_ context.Context, state multistep.StateBag) multis return multistep.ActionContinue } +func (s *stepListImages) listForWinRM(state multistep.StateBag) multistep.StepAction { + // This is a placeholder function; we will never reach this because we already + // return an error when winRM is set when validating the Packer config. + ui := state.Get("ui").(packer.Ui) + err := fmt.Errorf("The Oracle Classic builder does not currently support winRM.") + ui.Error(err.Error()) + state.Put("error", err) + return multistep.ActionHalt +} + +func (s *stepListImages) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { + // get variables from state + config := state.Get("config").(*Config) + + var action multistep.StepAction + if config.Comm.Type == "winrm" { + action = s.listForWinRM(state) + } else if config.Comm.Type == "ssh" { + action = s.listForSSH(state) + } + return action +} + func (s *stepListImages) Cleanup(state multistep.StateBag) { // Nothing to do return diff --git a/website/source/docs/builders/oracle-classic.html.md b/website/source/docs/builders/oracle-classic.html.md index f8991b968..98db5f2aa 100644 --- a/website/source/docs/builders/oracle-classic.html.md +++ b/website/source/docs/builders/oracle-classic.html.md @@ -63,6 +63,16 @@ This builder currently only works with the SSH communicator. ### Optional + - `attributes` (string) - (string) - Attributes to apply when launching the + instance. Note that you need to be careful about escaping characters due to + the templates being JSON. It is often more convenient to use + `attributes_file`, instead. You may only define either `attributes` or + `attributes_file`, not both. + + - `attributes_file` (string) - Path to a json file that will be used for the + attributes when launching the instance. You may only define either + `attributes` or `attributes_file`, not both. + - `image_description` (string) - a description for your destination image list. If you don't provide one, Packer will provide a generic description. @@ -91,7 +101,8 @@ obfuscated; you will need to add a working `username`, `password`, "api_endpoint": "https://api-###.compute.###.oraclecloud.com/", "source_image_list": "/oracle/public/OL_7.2_UEKR4_x86_64", "shape": "oc3", - "image_name": "Packer_Builder_Test_{{timestamp}}" + "image_name": "Packer_Builder_Test_{{timestamp}}", + "attributes": "{\"userdata\": {\"pre-bootstrap\": {\"script\": [\"...\"]}}}", "dest_image_list": "Packer_Builder_Test_List" } ],