diff --git a/builder/oracle/classic/builder.go b/builder/oracle/classic/builder.go index d486e5fcc..253b50c14 100644 --- a/builder/oracle/classic/builder.go +++ b/builder/oracle/classic/builder.go @@ -60,7 +60,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe return nil, fmt.Errorf("Error creating OPC Compute Client: %s", err) } - runID := os.Getenv("PACKER_RUN_UUID") + runID := fmt.Sprintf("%s_%s", b.config.ImageName, os.Getenv("PACKER_RUN_UUID")) // Populate the state bag state := new(multistep.BasicStateBag) state.Put("config", b.config) @@ -73,22 +73,10 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe if b.config.IsPV() { builderCommConfig := b.config.Comm builderCommConfig.SSHPty = true + builderCommConfig.Type = "ssh" + builderCommConfig.SSHUsername = b.config.BuilderSSHUsername steps = []multistep.Step{ - &stepCreatePersistentVolume{ - VolumeSize: fmt.Sprintf("%d", b.config.PersistentVolumeSize), - VolumeName: fmt.Sprintf("master-storage_%s", runID), - ImageList: b.config.SourceImageList, - ImageListEntry: b.config.SourceImageListEntry, - Bootable: true, - }, - &stepCreatePersistentVolume{ - // We double the master volume size because we need room to - // tarball the disk image. We also need to chunk the tar ball, - // but we can remove the original disk image first. - VolumeSize: fmt.Sprintf("%d", b.config.PersistentVolumeSize*2), - VolumeName: fmt.Sprintf("builder-storage_%s", runID), - }, &ocommon.StepKeyPair{ Debug: b.config.PackerDebug, Comm: &b.config.Comm, @@ -96,10 +84,21 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe }, &stepCreateIPReservation{}, &stepAddKeysToAPI{}, - &stepSecurity{}, + &stepSecurity{ + Comm: &b.config.Comm, + SecurityListKey: "security_list_master", + }, + &stepCreatePersistentVolume{ + VolumeSize: fmt.Sprintf("%d", b.config.PersistentVolumeSize), + VolumeName: fmt.Sprintf("master-storage_%s", runID), + ImageList: b.config.SourceImageList, + ImageListEntry: b.config.SourceImageListEntry, + Bootable: true, + }, &stepCreatePVMaster{ - Name: fmt.Sprintf("master-instance_%s", runID), - VolumeName: fmt.Sprintf("master-storage_%s", runID), + Name: fmt.Sprintf("master-instance_%s", runID), + VolumeName: fmt.Sprintf("master-storage_%s", runID), + SecurityListKey: "security_list_master", }, &communicator.StepConnect{ Config: &b.config.Comm, @@ -108,9 +107,21 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe }, &common.StepProvision{}, &stepTerminatePVMaster{}, + &stepSecurity{ + SecurityListKey: "security_list_builder", + Comm: &builderCommConfig, + }, + &stepCreatePersistentVolume{ + // We double the master volume size because we need room to + // tarball the disk image. We also need to chunk the tar ball, + // but we can remove the original disk image first. + VolumeSize: fmt.Sprintf("%d", b.config.PersistentVolumeSize*2), + VolumeName: fmt.Sprintf("builder-storage_%s", runID), + }, &stepCreatePVBuilder{ Name: fmt.Sprintf("builder-instance_%s", runID), BuilderVolumeName: fmt.Sprintf("builder-storage_%s", runID), + SecurityListKey: "security_list_builder", }, &stepAttachVolume{ VolumeName: fmt.Sprintf("master-storage_%s", runID), @@ -120,7 +131,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe &communicator.StepConnect{ Config: &builderCommConfig, Host: ocommon.CommHost, - SSHConfig: b.config.Comm.SSHConfigFunc(), + SSHConfig: builderCommConfig.SSHConfigFunc(), }, &stepUploadImage{ UploadImageCommand: b.config.BuilderUploadImageCommand, @@ -141,7 +152,10 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe }, &stepCreateIPReservation{}, &stepAddKeysToAPI{}, - &stepSecurity{}, + &stepSecurity{ + SecurityListKey: "security_list", + Comm: &b.config.Comm, + }, &stepCreateInstance{}, &communicator.StepConnect{ Config: &b.config.Comm, @@ -167,7 +181,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe } // If there is no snapshot, then just return - if _, ok := state.GetOk("machine_image"); !ok { + if _, ok := state.GetOk("machine_image_name"); !ok { return nil, nil } diff --git a/builder/oracle/classic/pv_config.go b/builder/oracle/classic/pv_config.go index 623e5e917..747c35842 100644 --- a/builder/oracle/classic/pv_config.go +++ b/builder/oracle/classic/pv_config.go @@ -8,6 +8,8 @@ import ( ) const imageListDefault = "/oracle/public/OL_7.2_UEKR4_x86_64" +const usernameDefault = "opc" +const shapeDefault = "oc3" type PVConfig struct { // PersistentVolumeSize lets us control the volume size by using persistent boot storage @@ -18,6 +20,7 @@ type PVConfig struct { BuilderShape string `mapstructure:"builder_shape"` BuilderImageList string `mapstructure:"builder_image_list"` BuilderImageListEntry int `mapstructure:"builder_image_list_entry"` + BuilderSSHUsername string `mapstructure:"builder_ssh_username"` /* TODO: * Documentation * split master/builder image/connection config. i.e. build anything, master only linux @@ -44,7 +47,11 @@ func (c *PVConfig) Prepare(ctx *interpolate.Context) (errs *packer.MultiError) { } if c.BuilderShape == "" { - c.BuilderShape = "oc3" + c.BuilderShape = shapeDefault + } + + if c.BuilderSSHUsername == "" { + c.BuilderSSHUsername = usernameDefault } if c.BuilderImageList == "" { diff --git a/builder/oracle/classic/step_create_instance.go b/builder/oracle/classic/step_create_instance.go index 3edd014e9..261ff901f 100644 --- a/builder/oracle/classic/step_create_instance.go +++ b/builder/oracle/classic/step_create_instance.go @@ -82,6 +82,5 @@ func (s *stepCreateInstance) Cleanup(state multistep.StateBag) { state.Put("error", err) return } - // TODO wait for instance state to change to deleted? ui.Say("Terminated instance.") } diff --git a/builder/oracle/classic/step_create_pv_builder.go b/builder/oracle/classic/step_create_pv_builder.go index 23b03c382..7ca11464a 100644 --- a/builder/oracle/classic/step_create_pv_builder.go +++ b/builder/oracle/classic/step_create_pv_builder.go @@ -13,6 +13,7 @@ import ( type stepCreatePVBuilder struct { Name string BuilderVolumeName string + SecurityListKey string } func (s *stepCreatePVBuilder) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { @@ -23,7 +24,7 @@ func (s *stepCreatePVBuilder) Run(_ context.Context, state multistep.StateBag) m config := state.Get("config").(*Config) client := state.Get("client").(*compute.Client) ipAddName := state.Get("ipres_name").(string) - secListName := state.Get("security_list").(string) + secListName := state.Get(s.SecurityListKey).(string) // get instances client instanceClient := client.Instances() diff --git a/builder/oracle/classic/step_create_pv_master.go b/builder/oracle/classic/step_create_pv_master.go index a9d21e655..075d9f633 100644 --- a/builder/oracle/classic/step_create_pv_master.go +++ b/builder/oracle/classic/step_create_pv_master.go @@ -10,19 +10,19 @@ import ( ) type stepCreatePVMaster struct { - Name string - VolumeName string + Name string + VolumeName string + SecurityListKey string } func (s *stepCreatePVMaster) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { - // get variables from state ui := state.Get("ui").(packer.Ui) ui.Say("Creating master instance...") config := state.Get("config").(*Config) client := state.Get("client").(*compute.Client) ipAddName := state.Get("ipres_name").(string) - secListName := state.Get("security_list").(string) + secListName := state.Get(s.SecurityListKey).(string) // get instances client instanceClient := client.Instances() @@ -45,7 +45,9 @@ func (s *stepCreatePVMaster) Run(_ context.Context, state multistep.StateBag) mu }, BootOrder: []int{1}, Attributes: config.attribs, - SSHKeys: []string{config.Comm.SSHKeyPairName}, + } + if config.Comm.Type == "ssh" { + input.SSHKeys = []string{config.Comm.SSHKeyPairName} } instanceInfo, err := instanceClient.CreateInstance(input) @@ -63,8 +65,7 @@ func (s *stepCreatePVMaster) Run(_ context.Context, state multistep.StateBag) mu } func (s *stepCreatePVMaster) Cleanup(state multistep.StateBag) { - _, deleted := state.GetOk("master_instance_deleted") - if deleted { + if _, deleted := state.GetOk("master_instance_deleted"); deleted { return } diff --git a/builder/oracle/classic/step_security.go b/builder/oracle/classic/step_security.go index d85bbb1c9..054ca7b5e 100644 --- a/builder/oracle/classic/step_security.go +++ b/builder/oracle/classic/step_security.go @@ -7,31 +7,53 @@ import ( "strings" "github.com/hashicorp/go-oracle-terraform/compute" - "github.com/hashicorp/packer/common/uuid" + "github.com/hashicorp/packer/helper/communicator" "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" ) -type stepSecurity struct{} +type stepSecurity struct { + Comm *communicator.Config + SecurityListKey string + secListName string + secRuleName string +} func (s *stepSecurity) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { + /* + TODO: if both are ssh this duplicates effort. see if it still works + // Don't do anything if we've already created the security list + if _, ok := state.GetOk(s.SecRuleName); !ok { + return multistep.ActionContinue + } + if _, ok := state.GetOk(s.SecListName); !ok { + return multistep.ActionContinue + } + */ + ui := state.Get("ui").(packer.Ui) config := state.Get("config").(*Config) + runID := state.Get("run_id").(string) + client := state.Get("client").(*compute.Client) commType := "" - if config.Comm.Type == "ssh" { + if s.Comm.Type == "ssh" { commType = "SSH" - } else if config.Comm.Type == "winrm" { + } else if s.Comm.Type == "winrm" { commType = "WINRM" } + secListName := fmt.Sprintf("Packer_%s_Allow_%s", commType, runID) + + if _, ok := state.GetOk(secListName); ok { + log.Println("SecList created in earlier step, continuing") + // copy sec list name to proper key + state.Put(s.SecurityListKey, secListName) + return multistep.ActionContinue + } ui.Say(fmt.Sprintf("Configuring security lists and rules to enable %s access...", commType)) - - client := state.Get("client").(*compute.Client) - runUUID := uuid.TimeOrderedUUID() - - secListName := fmt.Sprintf("Packer_%s_Allow_%s_%s", commType, config.ImageName, runUUID) log.Println(secListName) + secListClient := client.SecurityLists() secListInput := compute.CreateSecurityListInput{ Description: fmt.Sprintf("Packer-generated security list to give packer %s access", commType), @@ -55,7 +77,7 @@ func (s *stepSecurity) Run(_ context.Context, state multistep.StateBag) multiste } else if commType == "WINRM" { // Check to see whether a winRM security application is already defined applicationClient := client.SecurityApplications() - application = fmt.Sprintf("packer_winRM_%s", runUUID) + application = fmt.Sprintf("packer_winRM_%s", runID) applicationInput := compute.CreateSecurityApplicationInput{ Description: "Allows Packer to connect to instance via winRM", DPort: "5985-5986", @@ -73,8 +95,7 @@ func (s *stepSecurity) Run(_ context.Context, state multistep.StateBag) multiste state.Put("winrm_application", application) } secRulesClient := client.SecRules() - secRuleName := fmt.Sprintf("Packer-allow-%s-Rule_%s_%s", commType, - config.ImageName, runUUID) + secRuleName := fmt.Sprintf("Packer-allow-%s-Rule_%s", commType, runID) log.Println(secRuleName) secRulesInput := compute.CreateSecRuleInput{ Action: "PERMIT", @@ -93,18 +114,15 @@ func (s *stepSecurity) Run(_ context.Context, state multistep.StateBag) multiste state.Put("error", err) return multistep.ActionHalt } - state.Put("security_rule_name", secRuleName) - state.Put("security_list", secListName) + state.Put(s.SecurityListKey, secListName) + state.Put(secListName, true) + s.secListName = secListName + s.secRuleName = secRuleName return multistep.ActionContinue } func (s *stepSecurity) Cleanup(state multistep.StateBag) { - secRuleName, ok := state.GetOk("security_rule_name") - if !ok { - return - } - secListName, ok := state.GetOk("security_list") - if !ok { + if s.secListName == "" || s.secRuleName == "" { return } @@ -116,24 +134,26 @@ func (s *stepSecurity) Cleanup(state multistep.StateBag) { // delete security rules that Packer generated secRulesClient := client.SecRules() - ruleInput := compute.DeleteSecRuleInput{Name: config.Identifier(secRuleName.(string))} + ruleInput := compute.DeleteSecRuleInput{ + Name: config.Identifier(s.secRuleName), + } err := secRulesClient.DeleteSecRule(&ruleInput) if err != nil { ui.Say(fmt.Sprintf("Error deleting the packer-generated security rule %s; "+ - "please delete manually. (error: %s)", secRuleName.(string), err.Error())) + "please delete manually. (error: %s)", s.secRuleName, err.Error())) } // delete security list that Packer generated secListClient := client.SecurityLists() - input := compute.DeleteSecurityListInput{Name: config.Identifier(secListName.(string))} + input := compute.DeleteSecurityListInput{Name: config.Identifier(s.secListName)} err = secListClient.DeleteSecurityList(&input) if err != nil { ui.Say(fmt.Sprintf("Error deleting the packer-generated security list %s; "+ - "please delete manually. (error : %s)", secListName.(string), err.Error())) + "please delete manually. (error : %s)", s.secListName, err.Error())) } // Some extra cleanup if we used the winRM communicator - if config.Comm.Type == "winrm" { + if s.Comm.Type == "winrm" { // Delete the packer-generated application application, ok := state.GetOk("winrm_application") if !ok {