diff --git a/builder/xenserver/common/client.go b/builder/xenserver/common/client.go index 33f27846..b9a19d43 100644 --- a/builder/xenserver/common/client.go +++ b/builder/xenserver/common/client.go @@ -576,14 +576,18 @@ func (self *VM) SetStaticMemoryRange(min, max uint) (err error) { return } -func (self *VM) ConnectVdi(vdi *VDI, vdiType VDIType) (err error) { +func (self *VM) ConnectVdi(vdi *VDI, vdiType VDIType, userdevice string) (err error) { // 1. Create a VBD vbd_rec := make(xmlrpc.Struct) vbd_rec["VM"] = self.Ref vbd_rec["VDI"] = vdi.Ref - vbd_rec["userdevice"] = "autodetect" + if (userdevice == nil) { + vbd_rec["userdevice"] = "autodetect" + } else { + vbd_rec["userdevice"] = userdevice + } vbd_rec["empty"] = false vbd_rec["other_config"] = make(xmlrpc.Struct) vbd_rec["qos_algorithm_type"] = "" diff --git a/builder/xenserver/common/common_config.go b/builder/xenserver/common/common_config.go index 0c644c04..d8db6a39 100644 --- a/builder/xenserver/common/common_config.go +++ b/builder/xenserver/common/common_config.go @@ -45,6 +45,7 @@ type CommonConfig struct { SSHPassword string `mapstructure:"ssh_password"` SSHPort uint `mapstructure:"ssh_port"` SSHUser string `mapstructure:"ssh_username"` + SSHHost string `mapstructure:"ssh_host"` SSHConfig `mapstructure:",squash"` RawSSHWaitTimeout string `mapstructure:"ssh_wait_timeout"` @@ -54,6 +55,9 @@ type CommonConfig struct { Format string `mapstructure:"format"` KeepVM string `mapstructure:"keep_vm"` IPGetter string `mapstructure:"ip_getter"` + + DiskBSize uint `mapstructure:"diskb_size"` + DiskCSize uint `mapstructure:"diskc_size"` } func (c *CommonConfig) Prepare(ctx *interpolate.Context, pc *common.PackerConfig) []error { @@ -196,9 +200,9 @@ func (c *CommonConfig) Prepare(ctx *interpolate.Context, pc *common.PackerConfig } switch c.IPGetter { - case "auto", "tools", "http": + case "auto", "tools", "http", "static": default: - errs = append(errs, errors.New("ip_getter must be one of 'auto', 'tools', 'http'")) + errs = append(errs, errors.New("ip_getter must be one of 'auto', 'tools', 'http', 'static'")) } return errs diff --git a/builder/xenserver/common/step_attach_vdi.go b/builder/xenserver/common/step_attach_vdi.go index 059dc499..4e8b6199 100644 --- a/builder/xenserver/common/step_attach_vdi.go +++ b/builder/xenserver/common/step_attach_vdi.go @@ -42,6 +42,7 @@ func (self *StepAttachVdi) Run(state multistep.StateBag) multistep.StepAction { } err = instance.ConnectVdi(self.vdi, self.VdiType, "") + ui.Error(fmt.Sprintf("VDI %s", self.vdi)) if err != nil { ui.Error(fmt.Sprintf("Error attaching VDI '%s': '%s'", vdiUuid, err.Error())) return multistep.ActionHalt diff --git a/builder/xenserver/common/step_wait_for_ip.go b/builder/xenserver/common/step_wait_for_ip.go index 1d29a2d5..ae0fcf67 100644 --- a/builder/xenserver/common/step_wait_for_ip.go +++ b/builder/xenserver/common/step_wait_for_ip.go @@ -66,6 +66,12 @@ func (self *StepWaitForIP) Run(state multistep.StateBag) multistep.StepAction { } + if config.IPGetter == "static" { + ip = config.SSHHost + ui.Message(fmt.Sprintf("Static IP is defined as '%s'", ip)) + return true,nil + } + return false, nil }, }.Wait(state) diff --git a/builder/xenserver/iso/builder.go b/builder/xenserver/iso/builder.go index 58ece251..ba6e5d8b 100644 --- a/builder/xenserver/iso/builder.go +++ b/builder/xenserver/iso/builder.go @@ -273,6 +273,8 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa VdiUuidKey: "tools_vdi_uuid", VdiType: xsclient.CD, }, + //Add the extra disks here? + new(stepAddDisks), new(xscommon.StepStartVmPaused), new(xscommon.StepGetVNCPort), &xscommon.StepForwardPortOverSSH{ diff --git a/builder/xenserver/iso/step_add_disks.go b/builder/xenserver/iso/step_add_disks.go new file mode 100644 index 00000000..e09ce1a7 --- /dev/null +++ b/builder/xenserver/iso/step_add_disks.go @@ -0,0 +1,108 @@ +package iso + +import ( + "fmt" + + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + xsclient "github.com/xenserver/go-xenserver-client" +) + +type stepAddDisks struct { + instance *xsclient.VM + vdiB *xsclient.VDI + vdiC *xsclient.VDI +} + + +func (self *stepAddDisks) Run(state multistep.StateBag) multistep.StepAction { + + client := state.Get("client").(xsclient.XenAPIClient) + config := state.Get("config").(config) + ui := state.Get("ui").(packer.Ui) + + ui.Say("Step: Add disks") + + sr, err := config.GetSR(client) + if err != nil { + ui.Error(fmt.Sprintf("Unable to get SR: %s", err.Error())) + return multistep.ActionHalt + } + + 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 + } + + // Add additional disks - this is a terrible hack until my golang gets better + if (config.DiskBSize !=0) { + ui.Say(fmt.Sprintf("Creating second disk with size %d", config.DiskBSize)) + + vdiB, err := sr.CreateVdi("Packer-disk-b", int64(config.DiskBSize*1024*1024)) + if err != nil { + ui.Error(fmt.Sprintf("Unable to create packer disk VDI: %s", err.Error())) + } + + self.vdiB = vdiB + + err = instance.ConnectVdi(vdiB, xsclient.Disk, "") + if err != nil { + ui.Error(fmt.Sprintf("Unable to connect packer disk VDI: %s", err.Error())) + return multistep.ActionHalt + } + + + } + + if (config.DiskCSize !=0) { + ui.Say(fmt.Sprintf("Creating third disk with size %d", config.DiskCSize)) + + vdiC, err := sr.CreateVdi("Packer-disk-c", int64(config.DiskCSize*1024*1024)) + if err != nil { + ui.Error(fmt.Sprintf("Unable to create packer disk VDI: %s", err.Error())) + } + + self.vdiC = vdiC + + err = instance.ConnectVdi(vdiC, xsclient.Disk, "") + if err != nil { + ui.Error(fmt.Sprintf("Unable to connect packer disk VDI: %s", err.Error())) + return multistep.ActionHalt + } + + } + + return multistep.ActionContinue +} + +func (self *stepAddDisks) Cleanup(state multistep.StateBag) { + config := state.Get("config").(config) + if config.ShouldKeepVM(state) { + return + } + + ui := state.Get("ui").(packer.Ui) + + ui.Say("Destroying additional disks") + + + //TODO: learn golang and make this better + if self.vdiB != nil { + ui.Say("Destroying second VDI") + err := self.vdiB.Destroy() + if err != nil { + ui.Error(err.Error()) + } + } + + if self.vdiC != nil { + ui.Say("Destroying third VDI") + err := self.vdiB.Destroy() + if err != nil { + ui.Error(err.Error()) + } + } + +} \ No newline at end of file diff --git a/builder/xenserver/iso/step_create_instance.go b/builder/xenserver/iso/step_create_instance.go index f0aaf1b6..bdef12a1 100644 --- a/builder/xenserver/iso/step_create_instance.go +++ b/builder/xenserver/iso/step_create_instance.go @@ -11,6 +11,8 @@ import ( type stepCreateInstance struct { instance *xsclient.VM vdi *xsclient.VDI + vdiB *xsclient.VDI + vdiC *xsclient.VDI } func (self *stepCreateInstance) Run(state multistep.StateBag) multistep.StepAction { @@ -192,4 +194,5 @@ func (self *stepCreateInstance) Cleanup(state multistep.StateBag) { ui.Error(err.Error()) } } + } diff --git a/docs/builders/xenserver-iso.html.markdown b/docs/builders/xenserver-iso.html.markdown index bc7c00e3..bcc3625d 100644 --- a/docs/builders/xenserver-iso.html.markdown +++ b/docs/builders/xenserver-iso.html.markdown @@ -180,6 +180,10 @@ each category, the available options are alphabetized and described. If it doesn't shut down in this time, it is an error. By default, the timeout is "5m", or five minutes. +* `ssh_host` - The IP address to use for the virtual machine. This is useful for + building in an environment where static IP assignment must be used. The + `ip_getter` option must also be set to `static`. + * `ssh_host_port_min` and `ssh_host_port_max` (integer) - The minimum and maximum port to use for the SSH port on the host machine which is forwarded to the SSH port on the guest machine. Because Packer often runs in parallel,