Enable xva builder to create VM from existing template
This commit is contained in:
parent
de46bb8b2f
commit
17c58e8d24
@ -3,7 +3,6 @@ package xva
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/hcl/v2/hcldec"
|
||||
@ -74,8 +73,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 {
|
||||
@ -134,6 +137,7 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p
|
||||
VdiName: self.config.ToolsIsoName,
|
||||
VdiUuidKey: "tools_vdi_uuid",
|
||||
},
|
||||
new(stepCreateFromTemplate),
|
||||
new(stepImportInstance),
|
||||
&xscommon.StepAttachVdi{
|
||||
VdiUuidKey: "floppy_vdi_uuid",
|
||||
|
191
builder/xenserver/xva/step_create_from_template.go
Normal file
191
builder/xenserver/xva/step_create_from_template.go
Normal file
@ -0,0 +1,191 @@
|
||||
package xva
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
"github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
xsclient "github.com/terra-farm/go-xen-api-client"
|
||||
xscommon "github.com/xenserver/packer-builder-xenserver/builder/xenserver/common"
|
||||
)
|
||||
|
||||
type stepCreateFromTemplate struct {
|
||||
instance *xsclient.VMRef
|
||||
}
|
||||
|
||||
func (self *stepCreateFromTemplate) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
c := state.Get("client").(*xscommon.Connection)
|
||||
config := state.Get("config").(xscommon.Config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Step: Create Instance from Template")
|
||||
|
||||
if config.CloneTemplate == "" {
|
||||
log.Println("Skipping creation from template - no `clone_template` configured.")
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
// Get the template to clone from
|
||||
|
||||
vms, err := c.GetClient().VM.GetByNameLabel(c.GetSessionRef(), config.CloneTemplate)
|
||||
|
||||
switch {
|
||||
case len(vms) == 0:
|
||||
ui.Error(fmt.Sprintf("Couldn't find a template with the name-label '%s'. Aborting.", config.CloneTemplate))
|
||||
return multistep.ActionHalt
|
||||
case len(vms) > 1:
|
||||
ui.Error(fmt.Sprintf("Found more than one template with the name '%s'. The name must be unique. Aborting.", config.CloneTemplate))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
template := vms[0]
|
||||
|
||||
// Clone that VM template
|
||||
instance, err := c.GetClient().VM.Clone(c.GetSessionRef(), template, config.VMName)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error cloning VM: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
self.instance = &instance
|
||||
|
||||
err = c.GetClient().VM.SetIsATemplate(c.GetSessionRef(), instance, false)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error setting is_a_template=false: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
err = c.GetClient().VM.SetVCPUsMax(c.GetSessionRef(), instance, int(config.VCPUsMax))
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error setting VM VCPUs Max=%d: %s", config.VCPUsMax, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
err = c.GetClient().VM.SetVCPUsAtStartup(c.GetSessionRef(), instance, int(config.VCPUsAtStartup))
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error setting VM VCPUs At Startup=%d: %s", config.VCPUsAtStartup, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
memory := int(config.VMMemory * 1024 * 1024)
|
||||
err = c.GetClient().VM.SetMemoryLimits(c.GetSessionRef(), instance, memory, memory, memory, memory)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error setting VM memory=%d: %s", memory, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
err = c.GetClient().VM.SetPlatform(c.GetSessionRef(), instance, config.PlatformArgs)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error setting VM platform: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
err = c.GetClient().VM.SetNameDescription(c.GetSessionRef(), instance, config.VMDescription)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error setting VM description: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
// Connect Network
|
||||
|
||||
var network xsclient.NetworkRef
|
||||
|
||||
if len(config.NetworkNames) == 0 {
|
||||
// No network has be specified. Use the management interface
|
||||
log.Println("No network name given, attempting to use management interface")
|
||||
pifs, err := c.GetClient().PIF.GetAll(c.GetSessionRef())
|
||||
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error getting PIFs: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
for _, pif := range pifs {
|
||||
pif_rec, err := c.GetClient().PIF.GetRecord(c.GetSessionRef(), pif)
|
||||
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error getting PIF record: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if pif_rec.Management {
|
||||
network = pif_rec.Network
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if string(network) == "" {
|
||||
ui.Error("Error: couldn't find management network. Aborting.")
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
log.Printf("Creating VIF on network '%s' on VM '%s'\n", network, instance)
|
||||
_, err = xscommon.ConnectNetwork(c, network, instance, "0")
|
||||
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Failed to create VIF with error: %v", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
} else {
|
||||
log.Printf("Using provided network names: %v\n", config.NetworkNames)
|
||||
// Look up each network by it's name label
|
||||
for i, networkNameLabel := range config.NetworkNames {
|
||||
networks, err := c.GetClient().Network.GetByNameLabel(c.GetSessionRef(), networkNameLabel)
|
||||
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error occured getting Network by name-label: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
switch {
|
||||
case len(networks) == 0:
|
||||
ui.Error(fmt.Sprintf("Couldn't find a network with the specified name-label '%s'. Aborting.", networkNameLabel))
|
||||
return multistep.ActionHalt
|
||||
case len(networks) > 1:
|
||||
ui.Error(fmt.Sprintf("Found more than one network with the name '%s'. The name must be unique. Aborting.", networkNameLabel))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
//we need the VIF index string
|
||||
vifIndexString := fmt.Sprintf("%d", i)
|
||||
_, err = xscommon.ConnectNetwork(c, networks[0], instance, vifIndexString)
|
||||
|
||||
if err != nil {
|
||||
ui.Say(fmt.Sprintf("Failed to connect VIF with error: %v", err.Error()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
instanceId, err := c.GetClient().VM.GetUUID(c.GetSessionRef(), instance)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to get VM UUID: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
state.Put("instance_uuid", instanceId)
|
||||
ui.Say(fmt.Sprintf("Created instance '%s'", instanceId))
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (self *stepCreateFromTemplate) Cleanup(state multistep.StateBag) {
|
||||
config := state.Get("config").(xscommon.Config)
|
||||
if config.ShouldKeepVM(state) {
|
||||
return
|
||||
}
|
||||
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
c := state.Get("client").(*xscommon.Connection)
|
||||
|
||||
if self.instance != nil {
|
||||
ui.Say("Destroying VM")
|
||||
_ = c.GetClient().VM.HardShutdown(c.GetSessionRef(), *self.instance) // redundant, just in case
|
||||
err := c.GetClient().VM.Destroy(c.GetSessionRef(), *self.instance)
|
||||
if err != nil {
|
||||
ui.Error(err.Error())
|
||||
}
|
||||
}
|
||||
}
|
@ -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]
|
||||
|
Loading…
Reference in New Issue
Block a user