Adding defaults for Clone template, Network and Storage to avoid having to configure it in the packer file.

Signed-off-by: Rob Dobson <rob.dobson@citrix.com>
This commit is contained in:
Rob Dobson 2014-11-21 13:39:25 +00:00
parent 4746a397be
commit 74cfea407d
4 changed files with 290 additions and 28 deletions

View File

@ -28,9 +28,9 @@ type config struct {
InstanceName string `mapstructure:"instance_name"`
RootDiskSize string `mapstructure:"root_disk_size"`
CloneTemplate string `mapstructure:"clone_template"`
IsoUuid string `mapstructure:"iso_uuid"`
SrUuid string `mapstructure:"sr_uuid"`
NetworkUuid string `mapstructure:"network_uuid"`
IsoName string `mapstructure:"iso_name"`
SrName string `mapstructure:"sr_name"`
NetworkName string `mapstructure:"network_name"`
HostPortMin uint `mapstructure:"host_port_min"`
HostPortMax uint `mapstructure:"host_port_max"`
@ -127,9 +127,9 @@ func (self *Builder) Prepare (raws ...interface{}) (params []string, retErr erro
"instance_name": &self.config.InstanceName,
"root_disk_size": &self.config.RootDiskSize,
"clone_template": &self.config.CloneTemplate,
"iso_uuid": &self.config.IsoUuid,
"sr_uuid": &self.config.SrUuid,
"network_uuid": &self.config.NetworkUuid,
"iso_name": &self.config.IsoName,
"sr_name": &self.config.SrName,
"network_name": &self.config.NetworkName,
"boot_wait": &self.config.RawBootWait,
"iso_checksum": &self.config.ISOChecksum,
"iso_checksum_type": &self.config.ISOChecksumType,
@ -218,29 +218,15 @@ func (self *Builder) Prepare (raws ...interface{}) (params []string, retErr erro
}
if self.config.CloneTemplate == "" {
errs = packer.MultiErrorAppend(
errs, errors.New("A template to clone from must be specified."))
}
if self.config.IsoUuid == "" {
errs = packer.MultiErrorAppend(
errs, errors.New("a uuid for the installation iso must be specified."))
}
if self.config.SrUuid == "" {
errs = packer.MultiErrorAppend(
errs, errors.New("a uuid for the sr used for the instance must be specified."))
}
if self.config.NetworkUuid == "" {
errs = packer.MultiErrorAppend(
errs, errors.New("a uuid for the network used for the instance must be specified."))
self.config.CloneTemplate = "Other install media"
}
/*
if self.config.LocalIp == "" {
errs = packer.MultiErrorAppend(
errs, errors.New("A local IP visible to XenServer's mangement interface is required to serve files."))
}
*/
if len(self.config.PlatformArgs) == 0 {
pargs := make(map[string]string)

View File

@ -60,6 +60,16 @@ type VIF struct {
Client *XenAPIClient
}
type PIF struct {
Ref string
Client *XenAPIClient
}
type Pool struct {
Ref string
Client *XenAPIClient
}
func (c *XenAPIClient) RPCCall (result interface{}, method string, params []interface{}) (err error) {
fmt.Println(params)
p := new(xmlrpc.Params)
@ -129,6 +139,50 @@ func (client *XenAPIClient) GetHosts () (err error) {
}
func (client *XenAPIClient) GetPools () (pools []*Pool, err error) {
pools = make([]*Pool, 0)
result := APIResult{}
err = client.APICall(&result, "pool.get_all")
if err != nil {
return pools, err
}
for _, elem := range result.Value.([]interface{}) {
pool := new(Pool)
pool.Ref = elem.(string)
pool.Client = client
pools = append(pools, pool)
}
return pools, nil
}
func (client *XenAPIClient) GetDefaultSR () (sr *SR, err error) {
pools, err := client.GetPools()
if err != nil {
return nil, err
}
pool_rec, err := pools[0].GetRecord()
if err != nil {
return nil, err
}
if pool_rec["default_SR"] == "" {
return nil, errors.New("No default_SR specified for the pool.")
}
sr = new(SR)
sr.Ref = pool_rec["default_SR"].(string)
sr.Client = client
return sr, nil
}
func (client *XenAPIClient) GetVMByUuid (vm_uuid string) (vm *VM, err error) {
vm = new(VM)
result := APIResult{}
@ -141,6 +195,44 @@ func (client *XenAPIClient) GetVMByUuid (vm_uuid string) (vm *VM, err error) {
return
}
func (client *XenAPIClient) GetVMByNameLabel (name_label string) (vms []*VM, err error) {
vms = make([]*VM, 0)
result := APIResult{}
err = client.APICall(&result, "VM.get_by_name_label", name_label)
if err != nil {
return vms, err
}
for _, elem := range result.Value.([]interface{}) {
vm := new(VM)
vm.Ref = elem.(string)
vm.Client = client
vms = append(vms, vm)
}
return vms, nil
}
func (client *XenAPIClient) GetSRByNameLabel (name_label string) (srs []*SR, err error) {
srs = make([]*SR, 0)
result := APIResult{}
err = client.APICall(&result, "SR.get_by_name_label", name_label)
if err != nil {
return srs, err
}
for _, elem := range result.Value.([]interface{}) {
sr := new(SR)
sr.Ref = elem.(string)
sr.Client = client
srs = append(srs, sr)
}
return srs, nil
}
func (client *XenAPIClient) GetNetworkByUuid (network_uuid string) (network *Network, err error) {
network = new(Network)
result := APIResult{}
@ -172,6 +264,24 @@ func (client *XenAPIClient) GetNetworkByNameLabel (name_label string) (networks
return networks, nil
}
func (client *XenAPIClient) GetVdiByNameLabel (name_label string) (vdis []*VDI, err error) {
vdis = make([]*VDI, 0)
result := APIResult{}
err = client.APICall(&result, "VDI.get_by_name_label", name_label)
if err != nil {
return vdis, err
}
for _, elem := range result.Value.([]interface{}) {
vdi := new(VDI)
vdi.Ref = elem.(string)
vdi.Client = client
vdis = append(vdis, vdi)
}
return vdis, nil
}
func (client *XenAPIClient) GetSRByUuid (sr_uuid string) (sr *SR, err error) {
sr = new(SR)
@ -197,6 +307,22 @@ func (client *XenAPIClient) GetVdiByUuid (vdi_uuid string) (vdi *VDI, err error)
return
}
func (client *XenAPIClient) GetPIFs() (pifs []*PIF, err error) {
pifs = make([]*PIF, 0)
result := APIResult{}
err = client.APICall(&result, "PIF.get_all")
if err != nil {
return pifs, err
}
for _, elem := range result.Value.([]interface{}) {
pif := new(PIF)
pif.Ref = elem.(string)
pif.Client = client
pifs = append(pifs, pif)
}
return pifs, nil
}
// VM associated functions
@ -532,6 +658,37 @@ func (self *Network) GetAssignedIPs () (ip_map map[string]string, err error) {
return ip_map, nil
}
// PIF associated functions
func (self *PIF) GetRecord () (record map[string]interface{}, err error) {
record = make(map[string]interface{})
result := APIResult{}
err = self.Client.APICall(&result, "PIF.get_record", self.Ref)
if err != nil {
return record, err
}
for k, v := range result.Value.(xmlrpc.Struct) {
record[k] = v
}
return record, nil
}
// Pool associated functions
func (self *Pool) GetRecord () (record map[string]interface{}, err error) {
record = make(map[string]interface{})
result := APIResult{}
err = self.Client.APICall(&result, "pool.get_record", self.Ref)
if err != nil {
return record, err
}
for k, v := range result.Value.(xmlrpc.Struct) {
record[k] = v
}
return record, nil
}
// VBD associated functions
func (self *VBD) GetRecord () (record map[string]interface{}, err error) {
record = make(map[string]interface{})

View File

@ -5,6 +5,7 @@ import (
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"fmt"
"log"
)
type stepCreateInstance struct {
@ -21,7 +22,19 @@ func (self *stepCreateInstance) Run(state multistep.StateBag) multistep.StepActi
// Get the template to clone from
template, _ := client.GetVMByUuid(config.CloneTemplate)
vms, err := client.GetVMByNameLabel(config.CloneTemplate)
switch {
case len(vms) == 0:
log.Fatal(fmt.Sprintf("Couldn't find a template with the name-label '%s'. Aborting.", config.CloneTemplate))
return multistep.ActionHalt
case len(vms) > 1:
log.Fatal(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, _ := template.Clone(config.InstanceName)
@ -30,13 +43,102 @@ func (self *stepCreateInstance) Run(state multistep.StateBag) multistep.StepActi
instance.SetPlatform(config.PlatformArgs)
// Create VDI for the instance
sr, _ := client.GetSRByUuid(config.SrUuid)
var sr *SR
if config.SrName == "" {
// Find the default SR
default_sr, err := client.GetDefaultSR()
sr = default_sr
if err != nil {
log.Fatal(fmt.Sprintf("Error getting default SR: %s", err.Error()))
return multistep.ActionHalt
}
} else {
// Use the provided name label to find the SR to use
srs, err := client.GetSRByNameLabel(config.SrName)
if err != nil {
log.Fatal(fmt.Sprintf("Error getting default SR: %s", err.Error()))
return multistep.ActionHalt
}
switch {
case len(srs) == 0:
log.Fatal(fmt.Sprintf("Couldn't find a SR with the specified name-label '%s'. Aborting.", config.SrName))
return multistep.ActionHalt
case len(srs) > 1:
log.Fatal(fmt.Sprintf("Found more than one SR with the name '%s'. The name must be unique. Aborting.", config.SrName))
return multistep.ActionHalt
}
sr = srs[0]
}
vdi, _ := sr.CreateVdi("Packer-disk", config.RootDiskSize)
instance.ConnectVdi(vdi, false)
// Connect Network
network, err := client.GetNetworkByUuid(config.NetworkUuid)
var network *Network
if config.NetworkName == "" {
// No network has be specified. Use the management interface
network = new(Network)
network.Ref = ""
network.Client = &client
pifs, err := client.GetPIFs()
if err != nil {
log.Fatal(fmt.Sprintf("Error getting PIFs %s", err.Error()))
return multistep.ActionHalt
}
for _, pif := range pifs {
pif_rec, err := pif.GetRecord()
if err != nil {
log.Fatal(fmt.Sprintf("Error getting PIF record: %s", err.Error()))
return multistep.ActionHalt
}
if pif_rec["management"].(bool) {
network.Ref = pif_rec["network"].(string)
}
}
if network.Ref == "" {
log.Fatal("Error: couldn't find management network. Aborting.")
return multistep.ActionHalt
}
} else {
// Look up the network by it's name label
networks, err := client.GetNetworkByNameLabel(config.NetworkName)
if err != nil {
log.Fatal(fmt.Sprintf("Error occured getting Network by name-label: %s", err.Error()))
return multistep.ActionHalt
}
switch {
case len(networks) == 0:
log.Fatal(fmt.Sprintf("Couldn't find a network with the specified name-label '%s'. Aborting.", config.NetworkName))
return multistep.ActionHalt
case len(networks) > 1:
log.Fatal(fmt.Sprintf("Found more than one SR with the name '%s'. The name must be unique. Aborting.", config.NetworkName))
return multistep.ActionHalt
}
network = networks[0]
}
if err != nil {
ui.Say(err.Error())
}
@ -49,7 +151,22 @@ func (self *stepCreateInstance) Run(state multistep.StateBag) multistep.StepActi
// Connect the ISO
//iso_vdi_uuid := state.Get("iso_vdi_uuid").(string)
iso, _ := client.GetVdiByUuid(config.IsoUuid)
isos, err := client.GetVdiByNameLabel(config.IsoName)
switch {
case len(isos) == 0:
log.Fatal(fmt.Sprintf("Couldn't find an ISO named '%s'. Aborting", config.IsoName))
return multistep.ActionHalt
case len(isos) > 1:
log.Fatal(fmt.Sprintf("Found more than one VDI with name '%s'. Name must be unique. Aborting.", config.IsoName))
return multistep.ActionHalt
}
iso := isos[0]
//iso, _ := client.GetVdiByUuid(config.IsoUuid)
//ui.Say("Using VDI: " + iso_vdi_uuid)
//iso, _ := client.GetVdiByUuid(iso_vdi_uuid)
instance.ConnectVdi(iso, true)

View File

@ -37,7 +37,9 @@ func (self *stepUploadIso) Run(state multistep.StateBag) multistep.StepAction {
iso_filesize := stat.Size()
// Create a VDI with the write size
sr, err := client.GetSRByUuid(config.SrUuid)
srs, err := client.GetSRByNameLabel(config.SrName)
sr := srs[0]
if err != nil {
ui.Error(err.Error())