Skip to content

Commit

Permalink
Add affinity host attribute to vm resource (#110)
Browse files Browse the repository at this point in the history
* Refactor the client.CreateVm method to scale better with more parameters

* Add support for affinity_host on vm creation

* Add the master attribute to the pool resource to make testing the affinity_host attribute easier

* Add docs for affinity_host attribute, implement update support for affinity_host and some unrelated test clean up

* Remove TODO comment that is resolved

* Update test to include master attribute
  • Loading branch information
ddelnano authored Jan 26, 2021
1 parent 873fba0 commit 67c6117
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 61 deletions.
42 changes: 24 additions & 18 deletions client/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type MemoryObject struct {
type Vm struct {
Type string `json:"type,omitempty"`
Id string `json:"id,omitempty"`
AffinityHost string `json:"affinityHost,omitempty"`
NameDescription string `json:"name_description"`
NameLabel string `json:"name_label"`
CPUs CPUs `json:"CPUs"`
Expand All @@ -42,6 +43,13 @@ type Vm struct {
CloudConfig string `json:"cloudConfig"`
ResourceSet string `json:"resourceSet,omitempty"`
Tags []string `json:"tags"`

// These fields are used for passing in disk inputs when
// creating Vms, however, this is not a real field as far
// as the XO api or XAPI is concerned
Disks []Disk `json:"-"`
CloudNetworkConfig string `json:"-"`
Networks []map[string]string `json:"-"`
}

func (v Vm) Compare(obj interface{}) bool {
Expand Down Expand Up @@ -70,18 +78,11 @@ func (v Vm) Compare(obj interface{}) bool {
return false
}

func (c *Client) CreateVm(name_label, name_description, template, cloudConfig, cloudNetworkConfig, resourceSet string, cpus, memoryMax int, networks []map[string]string, disks []VDI, tags []string) (*Vm, error) {
vifs := []map[string]string{}
for _, network := range networks {
vifs = append(vifs, map[string]string{
"network": network["network_id"],
"mac": network["mac_address"],
})
}
func (c *Client) CreateVm(vmReq Vm) (*Vm, error) {
existingDisks := map[string]interface{}{}
vdis := []interface{}{}

for idx, disk := range disks {
for idx, disk := range vmReq.Disks {
d := map[string]interface{}{
"$SR": disk.SrId,
"name_label": disk.NameLabel,
Expand All @@ -98,29 +99,33 @@ func (c *Client) CreateVm(name_label, name_description, template, cloudConfig, c
}
}
params := map[string]interface{}{
"affinityHost": vmReq.AffinityHost,
"bootAfterCreate": true,
"name_label": name_label,
"name_description": name_description,
"template": template,
"name_label": vmReq.NameLabel,
"name_description": vmReq.NameDescription,
"template": vmReq.Template,
"coreOs": false,
"cpuCap": nil,
"cpuWeight": nil,
"CPUs": cpus,
"memoryMax": memoryMax,
"CPUs": vmReq.CPUs.Number,
"memoryMax": vmReq.Memory.Static[1],
"existingDisks": existingDisks,
"VDIs": vdis,
"VIFs": vifs,
"tags": tags,
"VIFs": vmReq.Networks,
"tags": vmReq.Tags,
}

cloudConfig := vmReq.CloudConfig
if cloudConfig != "" {
params["cloudConfig"] = cloudConfig
}

resourceSet := vmReq.ResourceSet
if resourceSet != "" {
params["resourceSet"] = resourceSet
}

cloudNetworkConfig := vmReq.CloudNetworkConfig
if cloudNetworkConfig != "" {
params["networkConfig"] = cloudNetworkConfig
}
Expand All @@ -145,14 +150,15 @@ func (c *Client) CreateVm(name_label, name_description, template, cloudConfig, c
)
}

func (c *Client) UpdateVm(id string, cpus int, nameLabel, nameDescription, ha, rs string, autoPowerOn bool) (*Vm, error) {
func (c *Client) UpdateVm(id string, cpus int, nameLabel, nameDescription, ha, rs string, autoPowerOn bool, affinityHost string) (*Vm, error) {

var resourceSet interface{} = rs
if rs == "" {
resourceSet = nil
}
params := map[string]interface{}{
"id": id,
"affinityHost": affinityHost,
"name_label": nameLabel,
"name_description": nameDescription,
"auto_poweron": autoPowerOn,
Expand All @@ -162,7 +168,7 @@ func (c *Client) UpdateVm(id string, cpus int, nameLabel, nameDescription, ha, r
// "CPUs": cpus,
// "memoryMax": memoryMax,
// TODO: These need more investigation before they are implemented
// pv_args, cpuMask cpuWeight cpuCap affinityHost vga videoram coresPerSocket hasVendorDevice expNestedHvm resourceSet share startDelay nicType hvmBootFirmware virtualizationMode
// pv_args, cpuMask cpuWeight cpuCap vga videoram coresPerSocket hasVendorDevice expNestedHvm share startDelay nicType hvmBootFirmware virtualizationMode
}
log.Printf("[DEBUG] VM params for vm.set: %#v", params)
var success bool
Expand Down
1 change: 1 addition & 0 deletions docs/data-sources/pool.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ data "xenorchestra_sr" "local_storage" {
## Attributes Reference
* id - Id of the pool.
* description - The description of the pool.
* master - The id of the primary instance in the pool.
* cpus - CPU information about the pool.
* cores - Number of cores in the pool.
* sockets - Number of sockets in the pool.
10 changes: 9 additions & 1 deletion docs/resources/vm.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ Creates a Xen Orchestra vm resource.
## Example Usage

```hcl
data "xenorchestra_pool" "pool" {
name_label = "pool name"
}
data "xenorchestra_template" "template" {
name_label = "Puppet agent - Bionic 18.04 - 1"
}
Expand Down Expand Up @@ -33,8 +37,11 @@ resource "xenorchestra_vm" "bar" {
name_label = "Name"
name_description = "description"
template = data.xenorchestra_template.template.id
# Prefer to run the VM on the primary pool instance
affinity_host = data.xenorchestra_pool.pool.master
network {
network_id = data.xenorchestra_network.net.id
network_id = data.xenorchestra_network.net.id
}
disk {
Expand All @@ -60,6 +67,7 @@ resource "xenorchestra_vm" "bar" {
* memory_max - (Required) The amount of memory in bytes the VM will have.
* high_availabililty - (Optional) The restart priority for the VM. Possible values are `best-effort`, `restart` and empty string (no restarts on failure. Defaults to empty string.
* auto_poweron - (Optional) If the VM will automatically turn on. Defaults to `false`.
* affinity_host - (Optional) The preferred host you would like the VM to run on. If changed on an existing VM it will require a reboot for the VM to be rescheduled.
* network - (Required) The network the VM will use
* network_id - (Required) The ID of the network the VM will be on.
* mac_address - (Optional) The mac address of the network interaface
Expand Down
12 changes: 11 additions & 1 deletion xoa/data_source_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ func dataSourceXoaPool() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"master": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"cpus": &schema.Schema{
Type: schema.TypeMap,
Computed: true,
Expand Down Expand Up @@ -59,10 +63,16 @@ func dataSourcePoolRead(d *schema.ResourceData, m interface{}) error {
"sockets": fmt.Sprintf("%d", pool.Cpus.Sockets),
"cores": fmt.Sprintf("%d", pool.Cpus.Cores),
}
d.Set("description", pool.Description)
if err := d.Set("description", pool.Description); err != nil {
return err
}
err = d.Set("cpus", cpus)
if err != nil {
return err
}

if err := d.Set("master", pool.Master); err != nil {
return err
}
return nil
}
2 changes: 1 addition & 1 deletion xoa/data_source_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func TestAccXenorchestraDataSource_pool(t *testing.T) {
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckXenorchestraDataSourcePool(resourceName),
resource.TestCheckResourceAttrSet(resourceName, "id"),
// resource.TestCheckResourceAttrSet(resourceName, "description"),
resource.TestCheckResourceAttrSet(resourceName, "master"),
resource.TestCheckResourceAttr(resourceName, "cpus.%", "2"),
resource.TestCheckResourceAttrSet(resourceName, "cpus.sockets"),
resource.TestCheckResourceAttrSet(resourceName, "cpus.cores"),
Expand Down
58 changes: 37 additions & 21 deletions xoa/resource_xenorchestra_vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ func resourceRecord() *schema.Resource {
Update: &duration,
},
Schema: map[string]*schema.Schema{
"affinity_host": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"name_label": &schema.Schema{
Type: schema.TypeString,
Required: true,
Expand Down Expand Up @@ -187,23 +191,25 @@ func resourceVmCreate(d *schema.ResourceData, m interface{}) error {
net, _ := network.(map[string]interface{})

network_maps = append(network_maps, map[string]string{
"network_id": net["network_id"].(string),
"mac_address": net["mac_address"].(string),
"network": net["network_id"].(string),
"mac": net["mac_address"].(string),
})
}

vdis := []client.VDI{}
ds := []client.Disk{}

disks := d.Get("disk").([]interface{})

for _, disk := range disks {
vdi, _ := disk.(map[string]interface{})

vdis = append(vdis, client.VDI{
SrId: vdi["sr_id"].(string),
NameLabel: vdi["name_label"].(string),
NameDescription: vdi["name_description"].(string),
Size: vdi["size"].(int),
ds = append(ds, client.Disk{
VDI: client.VDI{
SrId: vdi["sr_id"].(string),
NameLabel: vdi["name_label"].(string),
NameDescription: vdi["name_description"].(string),
Size: vdi["size"].(int),
},
})
}

Expand All @@ -214,18 +220,26 @@ func resourceVmCreate(d *schema.ResourceData, m interface{}) error {
vmTags = append(vmTags, t)
}

vm, err := c.CreateVm(
d.Get("name_label").(string),
d.Get("name_description").(string),
d.Get("template").(string),
d.Get("cloud_config").(string),
d.Get("cloud_network_config").(string),
d.Get("resource_set").(string),
d.Get("cpus").(int),
d.Get("memory_max").(int),
network_maps,
vdis,
vmTags,
vm, err := c.CreateVm(client.Vm{
AffinityHost: d.Get("affinity_host").(string),
NameLabel: d.Get("name_label").(string),
NameDescription: d.Get("name_description").(string),
Template: d.Get("template").(string),
CloudConfig: d.Get("cloud_config").(string),
ResourceSet: d.Get("resource_set").(string),
CPUs: client.CPUs{
Number: d.Get("cpus").(int),
},
CloudNetworkConfig: d.Get("cloud_network_config").(string),
Memory: client.MemoryObject{
Static: []int{
0, d.Get("memory_max").(int),
},
},
Tags: vmTags,
Disks: ds,
Networks: network_maps,
},
)

if err != nil {
Expand Down Expand Up @@ -360,12 +374,13 @@ func resourceVmUpdate(d *schema.ResourceData, m interface{}) error {

id := d.Id()
nameLabel := d.Get("name_label").(string)
affinityHost := d.Get("affinity_host").(string)
nameDescription := d.Get("name_description").(string)
cpus := d.Get("cpus").(int)
autoPowerOn := d.Get("auto_poweron").(bool)
ha := d.Get("high_availability").(string)
rs := d.Get("resource_set").(string)
vm, err := c.UpdateVm(id, cpus, nameLabel, nameDescription, ha, rs, autoPowerOn)
vm, err := c.UpdateVm(id, cpus, nameLabel, nameDescription, ha, rs, autoPowerOn, affinityHost)
log.Printf("[DEBUG] Retrieved vm after update: %+v\n", vm)

if err != nil {
Expand Down Expand Up @@ -579,6 +594,7 @@ func recordToData(resource client.Vm, vifs []client.VIF, disks []client.Disk, d

d.Set("cpus", resource.CPUs.Number)
d.Set("name_label", resource.NameLabel)
d.Set("affinity_host", resource.AffinityHost)
d.Set("name_description", resource.NameDescription)
d.Set("high_availability", resource.HA)
d.Set("auto_poweron", resource.AutoPoweron)
Expand Down
Loading

0 comments on commit 67c6117

Please sign in to comment.