Initial work on XVA import
This commit is contained in:
parent
396a8de131
commit
462082bee8
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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),
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
Loading…
Reference in New Issue
Block a user