Initial work on XVA import

This commit is contained in:
Cheng Sun 2014-12-31 15:21:54 +00:00
parent 396a8de131
commit 462082bee8
5 changed files with 82 additions and 81 deletions

View File

@ -23,25 +23,27 @@ func appendQuery(urlstring, k, v string) (string, error) {
return u.String(), err
}
func httpUpload(import_url string, fh *os.File, state multistep.StateBag) error {
func HTTPUpload(import_url string, fh *os.File, state multistep.StateBag) (result *XenAPIObject, err error) {
ui := state.Get("ui").(packer.Ui)
client := state.Get("client").(XenAPIClient)
task, err := client.CreateTask()
if err != nil {
return fmt.Errorf("Unable to create task: %s", err.Error())
err = fmt.Errorf("Unable to create task: %s", err.Error())
return
}
defer task.Destroy()
import_task_url, err := appendQuery(import_url, "task_id", task.Ref)
if err != nil {
return err
return
}
// Get file length
fstat, err := fh.Stat()
if err != nil {
return fmt.Errorf("Unable to stat '%s': %s", fh.Name(), err.Error())
err = fmt.Errorf("Unable to stat '%s': %s", fh.Name(), err.Error())
return
}
fileLength := fstat.Size()
@ -61,11 +63,12 @@ func httpUpload(import_url string, fh *os.File, state multistep.StateBag) error
resp, err := httpClient.Do(request) // Do closes fh for us, according to docs
if err != nil {
return err
return
}
if resp.StatusCode != 200 {
return fmt.Errorf("PUT request got non-200 status code: %s", resp.Status)
err = fmt.Errorf("PUT request got non-200 status code: %s", resp.Status)
return
}
logIteration := 0
@ -107,9 +110,16 @@ func httpUpload(import_url string, fh *os.File, state multistep.StateBag) error
resp.Body.Close()
if err != nil {
return fmt.Errorf("Error uploading: %s", err.Error())
err = fmt.Errorf("Error uploading: %s", err.Error())
return
}
result, err = task.GetResult()
if err != nil {
err = fmt.Errorf("Error getting result: %s", err.Error())
return
}
log.Printf("Upload complete")
return nil
return
}

View File

@ -39,7 +39,8 @@ func (self *StepDetachVdi) Run(state multistep.StateBag) multistep.StepAction {
err = instance.DisconnectVdi(vdi)
if err != nil {
ui.Error(fmt.Sprintf("Unable to detach VDI '%s': %s", vdiUuid, err.Error()))
return multistep.ActionHalt
//return multistep.ActionHalt
return multistep.ActionContinue
}
log.Printf("Detached VDI '%s'", vdiUuid)

View File

@ -35,7 +35,7 @@ func (self *StepUploadVdi) Run(state multistep.StateBag) multistep.StepAction {
return multistep.ActionHalt
}
// Open the file for reading (NB: httpUpload closes the file for us)
// Open the file for reading (NB: HTTPUpload closes the file for us)
fh, err := os.Open(imagePath)
if err != nil {
ui.Error(fmt.Sprintf("Unable to open disk image '%s': %s", imagePath, err.Error()))
@ -64,7 +64,7 @@ func (self *StepUploadVdi) Run(state multistep.StateBag) multistep.StepAction {
}
state.Put(self.VdiUuidKey, vdiUuid)
err = httpUpload(fmt.Sprintf("https://%s/import_raw_vdi?vdi=%s&session_id=%s",
_, err = HTTPUpload(fmt.Sprintf("https://%s/import_raw_vdi?vdi=%s&session_id=%s",
client.Host,
vdi.Ref,
client.Session.(string),

View File

@ -15,6 +15,7 @@ type config struct {
common.PackerConfig `mapstructure:",squash"`
xscommon.CommonConfig `mapstructure:",squash"`
SourcePath string `mapstructure:"source_path"`
VMMemory uint `mapstructure:"vm_memory"`
CloneTemplate string `mapstructure:"clone_template"`
@ -65,6 +66,7 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, retErr error
// Template substitution
templates := map[string]*string{
"source_path": &self.config.SourcePath,
"clone_template": &self.config.CloneTemplate,
"network_name": &self.config.NetworkName,
}
@ -79,6 +81,10 @@ 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 len(errs.Errors) > 0 {
retErr = errors.New(errs.Error())
}
@ -104,6 +110,7 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa
state.Put("cache", cache)
state.Put("client", client)
state.Put("config", self.config)
state.Put("commonconfig", self.config.CommonConfig)
state.Put("hook", hook)
state.Put("ui", ui)
@ -131,7 +138,7 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa
VdiName: self.config.ToolsIsoName,
VdiUuidKey: "tools_vdi_uuid",
},
new(stepCreateInstance),
new(stepImportInstance),
&xscommon.StepAttachVdi{
VdiUuidKey: "floppy_vdi_uuid",
VdiType: xscommon.Floppy,
@ -140,6 +147,7 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa
VdiUuidKey: "tools_vdi_uuid",
VdiType: xscommon.CD,
},
new(xscommon.StepRemoveDevices),
new(xscommon.StepStartOnHIMN),
&xscommon.StepForwardPortOverSSH{
RemotePort: xscommon.HimnSSHPort,

View File

@ -1,56 +1,58 @@
package xva
import (
// "fmt"
"fmt"
"os"
"github.com/mitchellh/multistep"
// "github.com/mitchellh/packer/packer"
"github.com/mitchellh/packer/packer"
xscommon "github.com/rdobson/packer-builder-xenserver/builder/xenserver/common"
)
type stepCreateInstance struct {
type stepImportInstance struct {
instance *xscommon.VM
vdi *xscommon.VDI
}
func (self *stepCreateInstance) Run(state multistep.StateBag) multistep.StepAction {
func (self *stepImportInstance) Run(state multistep.StateBag) multistep.StepAction {
client := state.Get("client").(xscommon.XenAPIClient)
config := state.Get("config").(config)
ui := state.Get("ui").(packer.Ui)
ui.Say("Step: Import Instance")
// find the SR
sr, err := config.GetSR(client)
if err != nil {
ui.Error(fmt.Sprintf("Unable to get SR: %s", err.Error()))
return multistep.ActionHalt
}
// Open the file for reading (NB: httpUpload closes the file for us)
fh, err := os.Open(config.SourcePath)
if err != nil {
ui.Error(fmt.Sprintf("Unable to open XVA '%s': %s", config.SourcePath, err.Error()))
return multistep.ActionHalt
}
result, err := xscommon.HTTPUpload(fmt.Sprintf("https://%s/import?session_id=%s&sr_id=%s",
client.Host,
client.Session.(string),
sr.Ref,
), fh, state)
if err != nil {
ui.Error(fmt.Sprintf("Unable to upload VDI: %s", err.Error()))
return multistep.ActionHalt
}
if result == nil {
ui.Error("XAPI did not reply with an instance reference")
return multistep.ActionHalt
}
instance := xscommon.VM(*result)
/*
client := state.Get("client").(xscommon.XenAPIClient)
config := state.Get("config").(config)
ui := state.Get("ui").(packer.Ui)
ui.Say("Step: Create Instance")
// Get the template to clone from
vms, err := client.GetVMByNameLabel(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 := template.Clone(config.VMName)
if err != nil {
ui.Error(fmt.Sprintf("Error cloning VM: %s", err.Error()))
return multistep.ActionHalt
}
self.instance = instance
err = instance.SetIsATemplate(false)
if err != nil {
ui.Error(fmt.Sprintf("Error setting is_a_template=false: %s", err.Error()))
return multistep.ActionHalt
}
err = instance.SetStaticMemoryRange(config.VMMemory*1024*1024, config.VMMemory*1024*1024)
if err != nil {
ui.Error(fmt.Sprintf("Error setting VM memory=%d: %s", config.VMMemory*1024*1024, err.Error()))
@ -63,27 +65,6 @@ func (self *stepCreateInstance) Run(state multistep.StateBag) multistep.StepActi
return multistep.ActionHalt
}
// Create VDI for the instance
sr, err := config.GetSR(client)
if err != nil {
ui.Error(fmt.Sprintf("Unable to get SR: %s", err.Error()))
return multistep.ActionHalt
}
vdi, err := sr.CreateVdi("Packer-disk", int64(config.DiskSize*1024*1024))
if err != nil {
ui.Error(fmt.Sprintf("Unable to create packer disk VDI: %s", err.Error()))
return multistep.ActionHalt
}
self.vdi = vdi
err = instance.ConnectVdi(vdi, xscommon.Disk)
if err != nil {
ui.Error(fmt.Sprintf("Unable to connect packer disk VDI: %s", err.Error()))
return multistep.ActionHalt
}
// Connect Network
var network *xscommon.Network
@ -151,20 +132,21 @@ func (self *stepCreateInstance) Run(state multistep.StateBag) multistep.StepActi
ui.Say(err.Error())
}
instanceId, err := 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)
ui.Say(fmt.Sprintf("Created instance '%s'", instanceId))
*/
instanceId, err := 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)
ui.Say(fmt.Sprintf("Imported instance '%s'", instanceId))
return multistep.ActionContinue
}
func (self *stepCreateInstance) Cleanup(state multistep.StateBag) {
func (self *stepImportInstance) Cleanup(state multistep.StateBag) {
/*
config := state.Get("config").(config)
if config.ShouldKeepVM(state) {