Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow XVA builder to use templates already on XenCenter #67

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions builder/xenserver/xva/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ type config struct {
common.PackerConfig `mapstructure:",squash"`
xscommon.CommonConfig `mapstructure:",squash"`

SourcePath string `mapstructure:"source_path"`
VMMemory uint `mapstructure:"vm_memory"`
SourcePath string `mapstructure:"source_path"`
SourceTemplate string `mapstructure:"source_template"`
VMMemory uint `mapstructure:"vm_memory"`

PlatformArgs map[string]string `mapstructure:"platform_args"`

Expand Down Expand Up @@ -72,8 +73,8 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, retErr error

// Validation

if self.config.SourcePath == "" {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("A source_path must be specified"))
if self.config.SourcePath == "" && self.config.SourceTemplate == "" {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("Either source_path or source_template must be specified"))
}

if len(errs.Errors) > 0 {
Expand Down Expand Up @@ -133,6 +134,7 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa
VdiName: self.config.ToolsIsoName,
VdiUuidKey: "tools_vdi_uuid",
},
new(stepInstantiateTemplate),
new(stepImportInstance),
&xscommon.StepAttachVdi{
VdiUuidKey: "floppy_vdi_uuid",
Expand Down
13 changes: 11 additions & 2 deletions builder/xenserver/xva/step_import_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,22 @@ type stepImportInstance struct {
}

func (self *stepImportInstance) Run(state multistep.StateBag) multistep.StepAction {

client := state.Get("client").(xsclient.XenAPIClient)
config := state.Get("config").(config)

if state.Get("instance_uuid") != nil {
return multistep.ActionContinue
}

ui := state.Get("ui").(packer.Ui)
client := state.Get("client").(xsclient.XenAPIClient)

ui.Say("Step: Import Instance")

if config.SourcePath == "" {
ui.Error(fmt.Sprintf("Failed to instantiate \"source_template\": \"%s\" and \"source_path\" is empty. Aborting.", config.SourceTemplate))
return multistep.ActionHalt
}

// find the SR
sr, err := config.GetSR(client)
if err != nil {
Expand Down
144 changes: 144 additions & 0 deletions builder/xenserver/xva/step_instantiate_template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package xva

import (
"fmt"

"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
xsclient "github.com/xenserver/go-xenserver-client"
)

type stepInstantiateTemplate struct {
instance *xsclient.VM
}

func (self *stepInstantiateTemplate) Run(state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(config)

if config.SourceTemplate == "" {
return multistep.ActionContinue
}

client := state.Get("client").(xsclient.XenAPIClient)
ui := state.Get("ui").(packer.Ui)

ui.Say("Step: Instantiate Template")

var template *xsclient.VM
var err error

if len(config.SourceTemplate) >= 7 && config.SourceTemplate[:7] == "uuid://" {
templateUuid := config.SourceTemplate[7:]

template, err = client.GetVMByUuid(templateUuid)
if err != nil {
ui.Error(fmt.Sprintf("Could not get template with UUID '%s': %s", templateUuid, err.Error()))
ui.Error("Defaulting to use \"source_path\".")
return multistep.ActionContinue
}
} else {
templates, err := client.GetVMByNameLabel(config.SourceTemplate)
if err != nil {
ui.Error(fmt.Sprintf("Error getting template: %s", err.Error()))
ui.Error("Defaulting to use \"source_path\".")
return multistep.ActionContinue
}

switch {
case len(templates) == 0:
ui.Error(fmt.Sprintf("Couldn't find a template with the name-label '%s'.", config.SourceTemplate))
ui.Error("Defaulting to use \"source_path\".")
return multistep.ActionContinue
case len(templates) > 1:
ui.Error(fmt.Sprintf("Found more than one template with the name '%s'. The name must be unique.", config.SourceTemplate))
ui.Error("Defaulting to use \"source_path\".")
return multistep.ActionContinue
}

template = templates[0]
}

self.instance, err = template.Clone(config.VMName)
if err != nil {
ui.Error(fmt.Sprintf("Error cloning template: %s", err.Error()))
return multistep.ActionHalt
}

instanceId, err := self.instance.GetUuid()
if err != nil {
ui.Error(fmt.Sprintf("Unable to get VM UUID: %s", err.Error()))
return multistep.ActionHalt
}
state.Put("instance_uuid", instanceId)

err = self.instance.SetIsATemplate(false)
if err != nil {
ui.Error(fmt.Sprintf("Error converting template to a VM: %s", err.Error()))
return multistep.ActionHalt
}

err = self.instance.SetDescription(config.VMDescription)
if err != nil {
ui.Error(fmt.Sprintf("Error setting VM description: %s", err.Error()))
return multistep.ActionHalt
}

ui.Say(fmt.Sprintf("Instantiated template '%s'", instanceId))

return multistep.ActionContinue
}

func (self *stepInstantiateTemplate) Cleanup(state multistep.StateBag) {
config := state.Get("config").(config)
if config.ShouldKeepVM(state) {
return
}

ui := state.Get("ui").(packer.Ui)

// We want to perform a 'xe vm-uninstall'
// Uninstall a VM. This operation will destroy those VDIs that are marked RW and connected to this VM only.
if self.instance != nil {
vbds, err := self.instance.GetVBDs()
if err != nil {
ui.Error(err.Error())
}

// Destroy VDIs before destroying VM, since vm.Destroy() also destroys VBDs,
// in which case we will be unable to find the VDIs
for _, vbd := range vbds {
vbd_rec, err := vbd.GetRecord()
if err != nil {
ui.Error(err.Error())
continue
}
if vbd_rec["mode"].(string) == "RW" {
vdi, err := vbd.GetVDI()
if err != nil {
ui.Error(err.Error())
continue
}
vdi_vbds, err := vdi.GetVBDs()
if err != nil {
ui.Error(err.Error())
continue
}
// If connected to this VM only
if len(vdi_vbds) <= 1 {
ui.Say("Destroying VDI")
err = vdi.Destroy()
if err != nil {
ui.Error(err.Error())
}
}
}
}

ui.Say("Destroying VM")
_ = self.instance.HardShutdown()
err = self.instance.Destroy()
if err != nil {
ui.Error(err.Error())
}
}
}