diff --git a/builder/xenserver/iso/step_create_instance.go b/builder/xenserver/common/step_create_instance.go similarity index 76% rename from builder/xenserver/iso/step_create_instance.go rename to builder/xenserver/common/step_create_instance.go index df6702a..7ceba97 100644 --- a/builder/xenserver/iso/step_create_instance.go +++ b/builder/xenserver/common/step_create_instance.go @@ -1,4 +1,4 @@ -package iso +package common import ( "context" @@ -9,18 +9,21 @@ import ( "github.com/hashicorp/packer-plugin-sdk/packer" xenapi "github.com/terra-farm/go-xen-api-client" xsclient "github.com/terra-farm/go-xen-api-client" - xscommon "github.com/xenserver/packer-builder-xenserver/builder/xenserver/common" ) -type stepCreateInstance struct { +type StepCreateInstance struct { + // The XVA builder assumes it will boot an instance with an OS installed on its disks + // while the ISO builder needs packer to create a disk for an OS to be installed on. + AssumePreInstalledOS bool + instance *xsclient.VMRef vdi *xsclient.VDIRef } -func (self *stepCreateInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { +func (self *StepCreateInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - c := state.Get("client").(*xscommon.Connection) - config := state.Get("config").(xscommon.Config) + c := state.Get("client").(*Connection) + config := state.Get("config").(Config) ui := state.Get("ui").(packer.Ui) ui.Say("Step: Create Instance") @@ -101,43 +104,45 @@ func (self *stepCreateInstance) Run(ctx context.Context, state multistep.StateBa } } - err = c.GetClient().VM.RemoveFromOtherConfig(c.GetSessionRef(), instance, "disks") - if err != nil { - ui.Error(fmt.Sprintf("Error removing disks from VM other-config: %s", err.Error())) - return multistep.ActionHalt - } + if !self.AssumePreInstalledOS { + err = c.GetClient().VM.RemoveFromOtherConfig(c.GetSessionRef(), instance, "disks") + if err != nil { + ui.Error(fmt.Sprintf("Error removing disks from VM other-config: %s", err.Error())) + return multistep.ActionHalt + } - // Create VDI for the instance - sr, err := config.GetSR(c) + // Create VDI for the instance + sr, err := config.GetSR(c) - if err != nil { - ui.Error(fmt.Sprintf("Unable to get SR: %s", err.Error())) - return multistep.ActionHalt - } + if err != nil { + ui.Error(fmt.Sprintf("Unable to get SR: %s", err.Error())) + return multistep.ActionHalt + } - ui.Say(fmt.Sprintf("Using the following SR for the VM: %s", sr)) + ui.Say(fmt.Sprintf("Using the following SR for the VM: %s", sr)) - vdi, err := c.GetClient().VDI.Create(c.GetSessionRef(), xenapi.VDIRecord{ - NameLabel: "Packer-disk", - VirtualSize: int(config.DiskSize * 1024 * 1024), - Type: "user", - Sharable: false, - ReadOnly: false, - SR: sr, - OtherConfig: map[string]string{ - "temp": "temp", - }, - }) - if err != nil { - ui.Error(fmt.Sprintf("Unable to create packer disk VDI: %s", err.Error())) - return multistep.ActionHalt - } - self.vdi = &vdi + vdi, err := c.GetClient().VDI.Create(c.GetSessionRef(), xenapi.VDIRecord{ + NameLabel: "Packer-disk", + VirtualSize: int(config.DiskSize * 1024 * 1024), + Type: "user", + Sharable: false, + ReadOnly: false, + SR: sr, + OtherConfig: map[string]string{ + "temp": "temp", + }, + }) + if err != nil { + ui.Error(fmt.Sprintf("Unable to create packer disk VDI: %s", err.Error())) + return multistep.ActionHalt + } + self.vdi = &vdi - err = xscommon.ConnectVdi(c, instance, vdi, xsclient.VbdTypeDisk) - if err != nil { - ui.Error(fmt.Sprintf("Unable to connect packer disk VDI: %s", err.Error())) - return multistep.ActionHalt + err = ConnectVdi(c, instance, vdi, xsclient.VbdTypeDisk) + if err != nil { + ui.Error(fmt.Sprintf("Unable to connect packer disk VDI: %s", err.Error())) + return multistep.ActionHalt + } } // Connect Network @@ -174,7 +179,7 @@ func (self *stepCreateInstance) Run(ctx context.Context, state multistep.StateBa } log.Printf("Creating VIF on network '%s' on VM '%s'\n", network, instance) - _, err = xscommon.ConnectNetwork(c, network, instance, "0") + _, err = ConnectNetwork(c, network, instance, "0") if err != nil { ui.Error(fmt.Sprintf("Failed to create VIF with error: %v", err)) @@ -203,7 +208,7 @@ func (self *stepCreateInstance) Run(ctx context.Context, state multistep.StateBa //we need the VIF index string vifIndexString := fmt.Sprintf("%d", i) - _, err = xscommon.ConnectNetwork(c, networks[0], instance, vifIndexString) + _, err = ConnectNetwork(c, networks[0], instance, vifIndexString) if err != nil { ui.Say(fmt.Sprintf("Failed to connect VIF with error: %v", err.Error())) @@ -223,14 +228,14 @@ func (self *stepCreateInstance) Run(ctx context.Context, state multistep.StateBa return multistep.ActionContinue } -func (self *stepCreateInstance) Cleanup(state multistep.StateBag) { - config := state.Get("config").(xscommon.Config) +func (self *StepCreateInstance) Cleanup(state multistep.StateBag) { + config := state.Get("config").(Config) if config.ShouldKeepVM(state) { return } ui := state.Get("ui").(packer.Ui) - c := state.Get("client").(*xscommon.Connection) + c := state.Get("client").(*Connection) if self.instance != nil { ui.Say("Destroying VM") diff --git a/builder/xenserver/iso/builder.go b/builder/xenserver/iso/builder.go index 9a0d1d1..7a3c5cc 100644 --- a/builder/xenserver/iso/builder.go +++ b/builder/xenserver/iso/builder.go @@ -235,7 +235,9 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p VdiName: self.config.ISOName, VdiUuidKey: "isoname_vdi_uuid", }, - new(stepCreateInstance), + &xscommon.StepCreateInstance{ + AssumePreInstalledOS: false, + }, &xscommon.StepAttachVdi{ VdiUuidKey: "floppy_vdi_uuid", VdiType: xsclient.VbdTypeFloppy, diff --git a/builder/xenserver/xva/builder.go b/builder/xenserver/xva/builder.go index 4eee1c4..e948413 100644 --- a/builder/xenserver/xva/builder.go +++ b/builder/xenserver/xva/builder.go @@ -3,7 +3,6 @@ package xva import ( "context" "errors" - "fmt" "time" "github.com/hashicorp/hcl/v2/hcldec" @@ -43,6 +42,7 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, warns []stri errs = packer.MultiErrorAppend( errs, self.config.CommonConfig.Prepare(self.config.GetInterpContext(), &self.config.PackerConfig)...) + errs = packer.MultiErrorAppend(errs, self.config.SSHConfig.Prepare(self.config.GetInterpContext())...) // Set default values if self.config.VCPUsMax == 0 { @@ -74,8 +74,12 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, warns []stri // Validation - if self.config.SourcePath == "" { - errs = packer.MultiErrorAppend(errs, fmt.Errorf("A source_path must be specified")) + if self.config.SourcePath == "" && self.config.CloneTemplate == "" { + errs = packer.MultiErrorAppend( + errs, errors.New("Either source_path or clone_template must be specified")) + } else if self.config.SourcePath != "" && self.config.CloneTemplate != "" { + errs = packer.MultiErrorAppend( + errs, errors.New("Only one of source_path and clone_template must be specified")) } if len(errs.Errors) > 0 { @@ -101,7 +105,7 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p //Share state between the other steps using a statebag state := new(multistep.BasicStateBag) state.Put("client", c) - // state.Put("config", self.config) + state.Put("config", self.config) state.Put("commonconfig", self.config.CommonConfig) state.Put("hook", hook) state.Put("ui", ui) @@ -116,8 +120,11 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p }, &commonsteps.StepCreateFloppy{ Files: self.config.FloppyFiles, + Label: "cidata", + }, + &xscommon.StepHTTPServer{ + Chan: httpReqChan, }, - new(xscommon.StepHTTPServer), &xscommon.StepUploadVdi{ VdiNameFunc: func() string { return "Packer-floppy-disk" @@ -134,6 +141,9 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p VdiName: self.config.ToolsIsoName, VdiUuidKey: "tools_vdi_uuid", }, + &xscommon.StepCreateInstance{ + AssumePreInstalledOS: true, + }, new(stepImportInstance), &xscommon.StepAttachVdi{ VdiUuidKey: "floppy_vdi_uuid", @@ -153,20 +163,28 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p Chan: httpReqChan, Timeout: 300 * time.Minute, /*self.config.InstallTimeout*/ // @todo change this }, + &xscommon.StepForwardPortOverSSH{ + RemotePort: xscommon.InstanceSSHPort, + RemoteDest: xscommon.InstanceSSHIP, + HostPortMin: self.config.HostPortMin, + HostPortMax: self.config.HostPortMax, + ResultKey: "local_ssh_port", + }, &communicator.StepConnect{ Config: &self.config.SSHConfig.Comm, - Host: xscommon.CommHost, - SSHConfig: xscommon.SSHConfigFunc(self.config.CommonConfig.SSHConfig), - SSHPort: xscommon.SSHPort, + Host: xscommon.InstanceSSHIP, + SSHConfig: self.config.Comm.SSHConfigFunc(), + SSHPort: xscommon.InstanceSSHPort, }, new(commonsteps.StepProvision), new(xscommon.StepShutdown), - &xscommon.StepDetachVdi{ - VdiUuidKey: "floppy_vdi_uuid", - }, + new(xscommon.StepSetVmToTemplate), &xscommon.StepDetachVdi{ VdiUuidKey: "tools_vdi_uuid", }, + &xscommon.StepDetachVdi{ + VdiUuidKey: "floppy_vdi_uuid", + }, new(xscommon.StepExport), } diff --git a/builder/xenserver/xva/step_import_instance.go b/builder/xenserver/xva/step_import_instance.go index 54215fa..ecc53a8 100644 --- a/builder/xenserver/xva/step_import_instance.go +++ b/builder/xenserver/xva/step_import_instance.go @@ -3,6 +3,7 @@ package xva import ( "context" "fmt" + "log" "os" "github.com/hashicorp/packer-plugin-sdk/multistep" @@ -24,6 +25,11 @@ func (self *stepImportInstance) Run(ctx context.Context, state multistep.StateBa ui.Say("Step: Import Instance") + if config.SourcePath == "" { + log.Println("Skipping imporing instance - no `source_path` configured.") + return multistep.ActionContinue + } + // find the SR srs, err := c.GetClient().SR.GetAll(c.GetSessionRef()) sr := srs[0]