From f8581f565d664d76f9ba3903da816efadd2bda59 Mon Sep 17 00:00:00 2001 From: Dongyu Zheng Date: Wed, 26 Oct 2016 11:55:25 -0700 Subject: [PATCH 1/2] Added step to configure number of disk drives --- builder/xenserver/common/common_config.go | 9 +- .../common/step_configure_disk_drives.go | 103 ++++++++++++++++++ builder/xenserver/iso/builder.go | 1 + builder/xenserver/xva/builder.go | 1 + docs/builders/xenserver-iso.html.markdown | 3 + 5 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 builder/xenserver/common/step_configure_disk_drives.go diff --git a/builder/xenserver/common/common_config.go b/builder/xenserver/common/common_config.go index 71ea9b67..4f33d055 100644 --- a/builder/xenserver/common/common_config.go +++ b/builder/xenserver/common/common_config.go @@ -50,10 +50,11 @@ type CommonConfig struct { RawSSHWaitTimeout string `mapstructure:"ssh_wait_timeout"` SSHWaitTimeout time.Duration - OutputDir string `mapstructure:"output_directory"` - Format string `mapstructure:"format"` - KeepVM string `mapstructure:"keep_vm"` - IPGetter string `mapstructure:"ip_getter"` + OutputDir string `mapstructure:"output_directory"` + Format string `mapstructure:"format"` + DiskDrives uint `mapstructure:"disk_drives"` + KeepVM string `mapstructure:"keep_vm"` + IPGetter string `mapstructure:"ip_getter"` } func (c *CommonConfig) Prepare(ctx *interpolate.Context, pc *common.PackerConfig) []error { diff --git a/builder/xenserver/common/step_configure_disk_drives.go b/builder/xenserver/common/step_configure_disk_drives.go new file mode 100644 index 00000000..0e76dc2e --- /dev/null +++ b/builder/xenserver/common/step_configure_disk_drives.go @@ -0,0 +1,103 @@ +package common + +import ( + "fmt" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + "github.com/nilshell/xmlrpc" + xsclient "github.com/xenserver/go-xenserver-client" + "strings" +) + +type StepConfigureDiskDrives struct{} + +func (self *StepConfigureDiskDrives) Run(state multistep.StateBag) multistep.StepAction { + ui := state.Get("ui").(packer.Ui) + config := state.Get("commonconfig").(CommonConfig) + client := state.Get("client").(xsclient.XenAPIClient) + ui.Say("Step: Configure disk drives") + + uuid := state.Get("instance_uuid").(string) + instance, err := client.GetVMByUuid(uuid) + if err != nil { + ui.Error(fmt.Sprintf("Unable to get VM from UUID '%s': %s", uuid, err.Error())) + return multistep.ActionHalt + } + + vbds, err := instance.GetVBDs() + if err != nil { + ui.Error(fmt.Sprintf("Error getting VBDs: %s", err.Error())) + return multistep.ActionHalt + } + + var current_number_of_disk_drives uint = 0 + for _, vbd := range vbds { + vbd_rec, err := vbd.GetRecord() + if err != nil { + ui.Error(fmt.Sprintf("Error getting VBD record: %s", err.Error())) + return multistep.ActionHalt + } + if vbd_rec["type"].(string) == "CD" { + if current_number_of_disk_drives < config.DiskDrives { + ui.Say("Ejecting disk drive") + err = vbd.Eject() + if err != nil && !strings.Contains(err.Error(), "VBD_IS_EMPTY") { + ui.Error(fmt.Sprintf("Error ejecting VBD: %s", err.Error())) + return multistep.ActionHalt + } + current_number_of_disk_drives++ + } else { + ui.Say("Destroying excess disk drive") + _ = vbd.Eject() + _ = vbd.Unplug() + err = vbd.Destroy() + if err != nil { + ui.Error(fmt.Sprintf("Error destroying VBD: %s", err.Error())) + return multistep.ActionHalt + } + } + } + } + + if current_number_of_disk_drives < config.DiskDrives { + vbd_rec := make(xmlrpc.Struct) + vbd_rec["VM"] = instance.Ref + vbd_rec["VDI"] = "OpaqueRef:NULL" + vbd_rec["userdevice"] = "autodetect" + vbd_rec["empty"] = true + vbd_rec["other_config"] = make(xmlrpc.Struct) + vbd_rec["qos_algorithm_type"] = "" + vbd_rec["qos_algorithm_params"] = make(xmlrpc.Struct) + vbd_rec["mode"] = "RO" + vbd_rec["bootable"] = true + vbd_rec["unpluggable"] = false + vbd_rec["type"] = "CD" + for current_number_of_disk_drives < config.DiskDrives { + ui.Say("Creating disk drive") + + result := xsclient.APIResult{} + err := client.APICall(&result, "VBD.create", vbd_rec) + + if err != nil { + ui.Error("Error creating disk drive. Retrying...") + continue + } + + vbd_ref := result.Value.(string) + + result = xsclient.APIResult{} + err = client.APICall(&result, "VBD.get_uuid", vbd_ref) + + if err != nil { + ui.Error("Error verifying disk drive. Retrying...") + continue + } + + current_number_of_disk_drives++ + } + } + + return multistep.ActionContinue +} + +func (self *StepConfigureDiskDrives) Cleanup(state multistep.StateBag) {} diff --git a/builder/xenserver/iso/builder.go b/builder/xenserver/iso/builder.go index 03f26cf7..121b0fc1 100644 --- a/builder/xenserver/iso/builder.go +++ b/builder/xenserver/iso/builder.go @@ -317,6 +317,7 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa &xscommon.StepDetachVdi{ VdiUuidKey: "floppy_vdi_uuid", }, + new(xscommon.StepConfigureDiskDrives), new(xscommon.StepExport), } diff --git a/builder/xenserver/xva/builder.go b/builder/xenserver/xva/builder.go index 22be43c0..2e09eae8 100644 --- a/builder/xenserver/xva/builder.go +++ b/builder/xenserver/xva/builder.go @@ -180,6 +180,7 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa &xscommon.StepDetachVdi{ VdiUuidKey: "tools_vdi_uuid", }, + new(xscommon.StepConfigureDiskDrives), new(xscommon.StepExport), } diff --git a/docs/builders/xenserver-iso.html.markdown b/docs/builders/xenserver-iso.html.markdown index bc7c00e3..c6e2bc3a 100644 --- a/docs/builders/xenserver-iso.html.markdown +++ b/docs/builders/xenserver-iso.html.markdown @@ -100,6 +100,9 @@ each category, the available options are alphabetized and described. run `xe template-list`. Setting the correct value hints to XenServer how to optimize the virtual hardware to work best with that operating system. +* `disk_drives` (integer) - How many DVD drives to keep on the exported VM. + Default is 0. + * `disk_size` (integer) - The size, in megabytes, of the hard disk to create for the VM. By default, this is 40000 (about 40 GB). From 923dc8b876be4d105a17fe24e40ef5c73dc34e8a Mon Sep 17 00:00:00 2001 From: Dongyu Zheng Date: Fri, 28 Oct 2016 11:55:05 -0700 Subject: [PATCH 2/2] Changed disk to disc, fixed infinite loop bugs --- builder/xenserver/common/common_config.go | 6 ++- ...rives.go => step_configure_disc_drives.go} | 47 ++++++++++++------- builder/xenserver/iso/builder.go | 2 +- builder/xenserver/xva/builder.go | 2 +- docs/builders/xenserver-iso.html.markdown | 2 +- 5 files changed, 38 insertions(+), 21 deletions(-) rename builder/xenserver/common/{step_configure_disk_drives.go => step_configure_disc_drives.go} (66%) diff --git a/builder/xenserver/common/common_config.go b/builder/xenserver/common/common_config.go index 4f33d055..dc2639ba 100644 --- a/builder/xenserver/common/common_config.go +++ b/builder/xenserver/common/common_config.go @@ -50,9 +50,9 @@ type CommonConfig struct { RawSSHWaitTimeout string `mapstructure:"ssh_wait_timeout"` SSHWaitTimeout time.Duration + DiscDrives int `mapstructure:"disc_drives"` OutputDir string `mapstructure:"output_directory"` Format string `mapstructure:"format"` - DiskDrives uint `mapstructure:"disk_drives"` KeepVM string `mapstructure:"keep_vm"` IPGetter string `mapstructure:"ip_getter"` } @@ -184,6 +184,10 @@ func (c *CommonConfig) Prepare(ctx *interpolate.Context, pc *common.PackerConfig errs = append(errs, fmt.Errorf("Failed to parse ssh_wait_timeout: %s", err)) } + if c.DiscDrives < 0 { + errs = append(errs, errors.New("disc_drives greater than or equal to 0.")) + } + switch c.Format { case "xva", "xva_compressed", "vdi_raw", "vdi_vhd", "none": default: diff --git a/builder/xenserver/common/step_configure_disk_drives.go b/builder/xenserver/common/step_configure_disc_drives.go similarity index 66% rename from builder/xenserver/common/step_configure_disk_drives.go rename to builder/xenserver/common/step_configure_disc_drives.go index 0e76dc2e..1a3350dc 100644 --- a/builder/xenserver/common/step_configure_disk_drives.go +++ b/builder/xenserver/common/step_configure_disc_drives.go @@ -9,13 +9,13 @@ import ( "strings" ) -type StepConfigureDiskDrives struct{} +type StepConfigureDiscDrives struct{} -func (self *StepConfigureDiskDrives) Run(state multistep.StateBag) multistep.StepAction { +func (self *StepConfigureDiscDrives) Run(state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) config := state.Get("commonconfig").(CommonConfig) client := state.Get("client").(xsclient.XenAPIClient) - ui.Say("Step: Configure disk drives") + ui.Say("Step: Configure disc drives") uuid := state.Get("instance_uuid").(string) instance, err := client.GetVMByUuid(uuid) @@ -30,7 +30,7 @@ func (self *StepConfigureDiskDrives) Run(state multistep.StateBag) multistep.Ste return multistep.ActionHalt } - var current_number_of_disk_drives uint = 0 + var current_number_of_disc_drives int = 0 for _, vbd := range vbds { vbd_rec, err := vbd.GetRecord() if err != nil { @@ -38,16 +38,16 @@ func (self *StepConfigureDiskDrives) Run(state multistep.StateBag) multistep.Ste return multistep.ActionHalt } if vbd_rec["type"].(string) == "CD" { - if current_number_of_disk_drives < config.DiskDrives { - ui.Say("Ejecting disk drive") + if current_number_of_disc_drives < config.DiscDrives { + ui.Say("Ejecting disc drive") err = vbd.Eject() if err != nil && !strings.Contains(err.Error(), "VBD_IS_EMPTY") { ui.Error(fmt.Sprintf("Error ejecting VBD: %s", err.Error())) return multistep.ActionHalt } - current_number_of_disk_drives++ + current_number_of_disc_drives++ } else { - ui.Say("Destroying excess disk drive") + ui.Say("Destroying excess disc drive") _ = vbd.Eject() _ = vbd.Unplug() err = vbd.Destroy() @@ -59,7 +59,7 @@ func (self *StepConfigureDiskDrives) Run(state multistep.StateBag) multistep.Ste } } - if current_number_of_disk_drives < config.DiskDrives { + if current_number_of_disc_drives < config.DiscDrives { vbd_rec := make(xmlrpc.Struct) vbd_rec["VM"] = instance.Ref vbd_rec["VDI"] = "OpaqueRef:NULL" @@ -72,15 +72,22 @@ func (self *StepConfigureDiskDrives) Run(state multistep.StateBag) multistep.Ste vbd_rec["bootable"] = true vbd_rec["unpluggable"] = false vbd_rec["type"] = "CD" - for current_number_of_disk_drives < config.DiskDrives { - ui.Say("Creating disk drive") + var failures int = 0 + for current_number_of_disc_drives < config.DiscDrives { + ui.Say("Creating disc drive") result := xsclient.APIResult{} err := client.APICall(&result, "VBD.create", vbd_rec) if err != nil { - ui.Error("Error creating disk drive. Retrying...") - continue + failures++ + if failures < 3 { + ui.Error("Error creating disc drive. Retrying...") + continue + } else { + ui.Error("Failed to create disc drive after 3 tries.") + return multistep.ActionHalt + } } vbd_ref := result.Value.(string) @@ -89,15 +96,21 @@ func (self *StepConfigureDiskDrives) Run(state multistep.StateBag) multistep.Ste err = client.APICall(&result, "VBD.get_uuid", vbd_ref) if err != nil { - ui.Error("Error verifying disk drive. Retrying...") - continue + failures++ + if failures < 3 { + ui.Error("Error verifying disc drive. Retrying...") + continue + } else { + ui.Error("Failed to create disc drive after 3 tries.") + return multistep.ActionHalt + } } - current_number_of_disk_drives++ + current_number_of_disc_drives++ } } return multistep.ActionContinue } -func (self *StepConfigureDiskDrives) Cleanup(state multistep.StateBag) {} +func (self *StepConfigureDiscDrives) Cleanup(state multistep.StateBag) {} diff --git a/builder/xenserver/iso/builder.go b/builder/xenserver/iso/builder.go index 121b0fc1..05d84762 100644 --- a/builder/xenserver/iso/builder.go +++ b/builder/xenserver/iso/builder.go @@ -317,7 +317,7 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa &xscommon.StepDetachVdi{ VdiUuidKey: "floppy_vdi_uuid", }, - new(xscommon.StepConfigureDiskDrives), + new(xscommon.StepConfigureDiscDrives), new(xscommon.StepExport), } diff --git a/builder/xenserver/xva/builder.go b/builder/xenserver/xva/builder.go index 2e09eae8..bd0bd10b 100644 --- a/builder/xenserver/xva/builder.go +++ b/builder/xenserver/xva/builder.go @@ -180,7 +180,7 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa &xscommon.StepDetachVdi{ VdiUuidKey: "tools_vdi_uuid", }, - new(xscommon.StepConfigureDiskDrives), + new(xscommon.StepConfigureDiscDrives), new(xscommon.StepExport), } diff --git a/docs/builders/xenserver-iso.html.markdown b/docs/builders/xenserver-iso.html.markdown index c6e2bc3a..e3dfdf83 100644 --- a/docs/builders/xenserver-iso.html.markdown +++ b/docs/builders/xenserver-iso.html.markdown @@ -100,7 +100,7 @@ each category, the available options are alphabetized and described. run `xe template-list`. Setting the correct value hints to XenServer how to optimize the virtual hardware to work best with that operating system. -* `disk_drives` (integer) - How many DVD drives to keep on the exported VM. +* `disc_drives` (integer) - How many DVD drives to keep on the exported VM. Default is 0. * `disk_size` (integer) - The size, in megabytes, of the hard disk to create