diff --git a/builder/cloudstack/builder.go b/builder/cloudstack/builder.go index fe376125f..dc1dace69 100644 --- a/builder/cloudstack/builder.go +++ b/builder/cloudstack/builder.go @@ -75,6 +75,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack Debug: b.config.PackerDebug, }, &stepSetupNetworking{}, + &stepDetachIso{}, &communicator.StepConnect{ Config: &b.config.Comm, Host: communicator.CommHost(b.config.Comm.SSHHost, "ipaddress"), diff --git a/builder/cloudstack/config.go b/builder/cloudstack/config.go index 00f79618b..7b975a618 100644 --- a/builder/cloudstack/config.go +++ b/builder/cloudstack/config.go @@ -20,12 +20,14 @@ type Config struct { common.HTTPConfig `mapstructure:",squash"` Comm communicator.Config `mapstructure:",squash"` - APIURL string `mapstructure:"api_url"` - APIKey string `mapstructure:"api_key"` - SecretKey string `mapstructure:"secret_key"` - AsyncTimeout time.Duration `mapstructure:"async_timeout"` - HTTPGetOnly bool `mapstructure:"http_get_only"` - SSLNoVerify bool `mapstructure:"ssl_no_verify"` + APIURL string `mapstructure:"api_url"` + APIKey string `mapstructure:"api_key"` + SecretKey string `mapstructure:"secret_key"` + AsyncTimeout time.Duration `mapstructure:"async_timeout"` + HTTPGetOnly bool `mapstructure:"http_get_only"` + SSLNoVerify bool `mapstructure:"ssl_no_verify"` + EjectISO bool `mapstructure:"eject_iso"` + EjectISODelay time.Duration `mapstructure:"eject_iso_delay"` CIDRList []string `mapstructure:"cidr_list"` CreateSecurityGroup bool `mapstructure:"create_security_group"` diff --git a/builder/cloudstack/step_detach_iso.go b/builder/cloudstack/step_detach_iso.go new file mode 100644 index 000000000..444293c2c --- /dev/null +++ b/builder/cloudstack/step_detach_iso.go @@ -0,0 +1,60 @@ +package cloudstack + +import ( + "context" + "fmt" + "time" + + "github.com/hashicorp/packer/helper/multistep" + "github.com/hashicorp/packer/packer" + "github.com/xanzy/go-cloudstack/cloudstack" +) + +type stepDetachIso struct{} + +// Detaches currently ISO file attached to a virtual machine if any. +func (s *stepDetachIso) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { + ui := state.Get("ui").(packer.Ui) + config := state.Get("config").(*Config) + + // Check if state uses iso file and has need to eject it + if !config.EjectISO || config.SourceISO == "" { + return multistep.ActionContinue + } + + ui.Say("Checking attached iso...") + + // Wait to make call detachIso + if config.EjectISODelay > 0 { + ui.Message(fmt.Sprintf("Waiting for %v before detaching ISO from virtual machine...", config.EjectISODelay)) + time.Sleep(config.EjectISODelay) + } + + client := state.Get("client").(*cloudstack.CloudStackClient) + + instanceID, ok := state.Get("instance_id").(string) + if !ok || instanceID == "" { + err := fmt.Errorf("Could not retrieve instance_id from state") + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + ui.Message("Detaching iso from virtual machine...") + + // Get a new DetachIsoParams and detaches Iso file from given virtualMachine instance + detachIsoParams := client.ISO.NewDetachIsoParams(instanceID) + response, err := client.ISO.DetachIso(detachIsoParams) + if err != nil || response == nil { + err := fmt.Errorf("Error detaching ISO from virtual machine: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + return multistep.ActionContinue +} + +func (s *stepDetachIso) Cleanup(state multistep.StateBag) { + // Nothing to cleanup for this step. +}