From e4c4c8572331453b5ca07c705ed34260e0dc2857 Mon Sep 17 00:00:00 2001 From: Maksym Borodin Date: Sun, 14 Jan 2018 09:17:56 +0100 Subject: [PATCH 01/19] Obtain VM Metrics --- xenserver/types.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/xenserver/types.go b/xenserver/types.go index 03917c3..72c862a 100644 --- a/xenserver/types.go +++ b/xenserver/types.go @@ -224,6 +224,24 @@ func (this *VMDescriptor) Load(c *Connection) error { return this.Query(c) } +func (this *VMDescriptor) Metrics(c *Connection) (metrics xenAPI.VMMetricsRecord, err error) { + var metricsRef xenAPI.VMMetricsRef + if metricsRef, err = c.client.VM.GetMetrics(c.session, this.VMRef); err != nil { + return + } + + return c.client.VMMetrics.GetRecord(c.session, metricsRef) +} + +func (this *VMDescriptor) GuestMetrics(c *Connection) (metrics xenAPI.VMGuestMetricsRecord, err error) { + var metricsRef xenAPI.VMGuestMetricsRef + if metricsRef, err = c.client.VM.GetGuestMetrics(c.session, this.VMRef); err != nil { + return + } + + return c.client.VMGuestMetrics.GetRecord(c.session, metricsRef) +} + func (this *VMDescriptor) Query(c *Connection) error { vm, err := c.client.VM.GetRecord(c.session, this.VMRef) if err != nil { From 30f60673461482661a54ae52e658e2560acee301 Mon Sep 17 00:00:00 2001 From: Maksym Borodin Date: Tue, 16 Jan 2018 05:57:30 +0100 Subject: [PATCH 02/19] Implemented VM Guest Metrics data source --- xenserver/data_source_vm_guest_metrics.go | 128 ++++++++++++++++++++++ xenserver/provider.go | 3 +- xenserver/types.go | 85 ++++++++++++-- 3 files changed, 207 insertions(+), 9 deletions(-) create mode 100644 xenserver/data_source_vm_guest_metrics.go diff --git a/xenserver/data_source_vm_guest_metrics.go b/xenserver/data_source_vm_guest_metrics.go new file mode 100644 index 0000000..5993ae7 --- /dev/null +++ b/xenserver/data_source_vm_guest_metrics.go @@ -0,0 +1,128 @@ +package xenserver + +import ( + "github.com/hashicorp/terraform/helper/schema" + "log" +) + +const ( + vmGuestMetricsVmUUID = "vm_uuid" + vmGuestMetricsDisks = "disks" + vmGuestMetricsNetworks = "networks" + vmGuestMetricsMemory = "memory" + vmGuestMetricsOSVersion = "os_version" + vmGuestMetricsPVDriversVersion = "pv_driver_version" + vmGuestMetricsPVDriversDetected = "is_pv_driver_present" + vmGuestMetricsCanUseHotPlugVbd = "can_use_hotplug_vbd" + vmGuestMetricsCanUseHotPlugVif = "can_use_hotplug_vif" + vmGuestMetricsLive = "is_live" + vmGuestMetricsLastUpdated = "last_updated" +) + +func dataSourceVmGuestMetrics() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVmGuestMetricsRead, + Schema: map[string]*schema.Schema{ + vmGuestMetricsVmUUID: &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + vmGuestMetricsDisks: &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + }, + vmGuestMetricsNetworks: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "ipv6": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + vmGuestMetricsMemory: &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + }, + vmGuestMetricsOSVersion: &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + }, + vmGuestMetricsPVDriversVersion: &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + }, + vmGuestMetricsPVDriversDetected: &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + }, + vmGuestMetricsCanUseHotPlugVbd: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + vmGuestMetricsCanUseHotPlugVif: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + vmGuestMetricsLive: &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + }, + vmGuestMetricsLastUpdated: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceVmGuestMetricsRead(d *schema.ResourceData, meta interface{}) (err error) { + c := meta.(*Connection) + + vm := &VMDescriptor{ + UUID: d.Get(vmGuestMetricsVmUUID).(string), + } + if err = vm.Load(c); err != nil { + return + } + + var metrics VMGuestMetrics + + if metrics, err = vm.GuestMetrics(c); err != nil { + return + } + + d.SetId(metrics.UUID) + + log.Printf("[DEBUG] Id is %s\n", d.Id()) + log.Println("[DEBUG] Networks: ", metrics.Networks) + + d.Set(vmGuestMetricsDisks, metrics.Disks) + d.Set(vmGuestMetricsNetworks, metrics.Networks) + d.Set(vmGuestMetricsMemory, metrics.Memory) + d.Set(vmGuestMetricsOSVersion, metrics.OSVersion) + d.Set(vmGuestMetricsPVDriversVersion, metrics.PVDriversVersion) + d.Set(vmGuestMetricsPVDriversDetected, metrics.PVDriversDetected) + d.Set(vmGuestMetricsCanUseHotPlugVbd, metrics.CanUseHotplugVbd) + d.Set(vmGuestMetricsCanUseHotPlugVif, metrics.CanUseHotplugVif) + d.Set(vmGuestMetricsLive, metrics.Live) + d.Set(vmGuestMetricsLastUpdated, metrics.LastUpdated.String()) + + return nil +} + +/* +func networksToSchemaList(networks []map[string][]string) []interface{} { + + + +}*/ diff --git a/xenserver/provider.go b/xenserver/provider.go index bb80973..a2d82de 100644 --- a/xenserver/provider.go +++ b/xenserver/provider.go @@ -32,7 +32,8 @@ func Provider() terraform.ResourceProvider { }, DataSourcesMap: map[string]*schema.Resource{ - "xenserver_pifs": dataSourceXenServerPifs(), + "xenserver_pifs": dataSourceXenServerPifs(), + "xenserver_vm_guest_metrics": dataSourceVmGuestMetrics(), }, ResourcesMap: map[string]*schema.Resource{ diff --git a/xenserver/types.go b/xenserver/types.go index 72c862a..15a9333 100644 --- a/xenserver/types.go +++ b/xenserver/types.go @@ -24,6 +24,9 @@ import ( "strconv" "github.com/ringods/go-xen-api-client" + "regexp" + "sort" + "time" ) type Range struct { @@ -129,6 +132,21 @@ type VLANDescriptor struct { VLANRef xenAPI.VLANRef } +type VMGuestMetrics struct { + UUID string + Disks interface{} + Networks []map[string][]string + Memory interface{} + OSVersion interface{} + PVDriversVersion interface{} + PVDriversDetected bool + PVDriversUpToDate bool + CanUseHotplugVbd string + CanUseHotplugVif string + Live bool + LastUpdated time.Time +} + func (this *NetworkDescriptor) Load(c *Connection) error { var network xenAPI.NetworkRef @@ -224,22 +242,73 @@ func (this *VMDescriptor) Load(c *Connection) error { return this.Query(c) } -func (this *VMDescriptor) Metrics(c *Connection) (metrics xenAPI.VMMetricsRecord, err error) { - var metricsRef xenAPI.VMMetricsRef - if metricsRef, err = c.client.VM.GetMetrics(c.session, this.VMRef); err != nil { +func (this *VMDescriptor) GuestMetrics(c *Connection) (metrics VMGuestMetrics, err error) { + var metricsRef xenAPI.VMGuestMetricsRef + var metricsRecord xenAPI.VMGuestMetricsRecord + if metricsRef, err = c.client.VM.GetGuestMetrics(c.session, this.VMRef); err != nil { return } - return c.client.VMMetrics.GetRecord(c.session, metricsRef) + if metricsRecord, err = c.client.VMGuestMetrics.GetRecord(c.session, metricsRef); err == nil { + metrics.UUID = metricsRecord.UUID + metrics.Disks = metricsRecord.Disks + metrics.Memory = metricsRecord.Memory + metrics.OSVersion = metricsRecord.OSVersion + metrics.PVDriversVersion = metricsRecord.PVDriversVersion + metrics.PVDriversDetected = metricsRecord.PVDriversDetected + metrics.PVDriversUpToDate = metricsRecord.PVDriversUpToDate + metrics.CanUseHotplugVbd = string(metricsRecord.CanUseHotplugVbd) + metrics.CanUseHotplugVif = string(metricsRecord.CanUseHotplugVif) + metrics.Live = metricsRecord.Live + metrics.LastUpdated = metricsRecord.LastUpdated + + var keys []string + for k := range metricsRecord.Networks { + keys = append(keys, k) + } + sort.Strings(keys) + + var re *regexp.Regexp + if re, err = regexp.Compile("([0-9]+)/(ipv?6?)/?[0-9]*"); err != nil { + return + } + + // Find out number of interfaces + lastKey := keys[len(keys)-1:][0] + var count int + + if count, err = strconv.Atoi(re.FindStringSubmatch(lastKey)[1]); err != nil { + return + } + count += 1 // increase by 1 since we obtained index and not length + + metrics.Networks = make([]map[string][]string, count) + + for _, k := range keys { + matches := re.FindStringSubmatch(k) + var index int + if index, err = strconv.Atoi(matches[1]); err != nil { + return + } + + if metrics.Networks[index] == nil { + metrics.Networks[index] = make(map[string][]string) + } + + metrics.Networks[index][matches[2]] = append(metrics.Networks[index][matches[2]], metricsRecord.Networks[k]) + } + } + + return } -func (this *VMDescriptor) GuestMetrics(c *Connection) (metrics xenAPI.VMGuestMetricsRecord, err error) { - var metricsRef xenAPI.VMGuestMetricsRef - if metricsRef, err = c.client.VM.GetGuestMetrics(c.session, this.VMRef); err != nil { +func (this *VMDescriptor) Metrics(c *Connection) (metrics xenAPI.VMMetricsRecord, err error) { + var metricsRef xenAPI.VMMetricsRef + if metricsRef, err = c.client.VM.GetMetrics(c.session, this.VMRef); err != nil { return } - return c.client.VMGuestMetrics.GetRecord(c.session, metricsRef) + return c.client.VMMetrics.GetRecord(c.session, metricsRef) } func (this *VMDescriptor) Query(c *Connection) error { From 88c593902d0583d7aa6a171e9a3b9ec08b556869 Mon Sep 17 00:00:00 2001 From: Maksym Borodin Date: Tue, 16 Jan 2018 06:04:53 +0100 Subject: [PATCH 03/19] Example how to use VM metrics data source --- examples/datasource_vm_guest_metrics/main.tf | 44 ++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 examples/datasource_vm_guest_metrics/main.tf diff --git a/examples/datasource_vm_guest_metrics/main.tf b/examples/datasource_vm_guest_metrics/main.tf new file mode 100644 index 0000000..11f6ded --- /dev/null +++ b/examples/datasource_vm_guest_metrics/main.tf @@ -0,0 +1,44 @@ +# To execute with `credentials.tfvars` in the `examples` folder: +# terraform init && terraform plan --var-file=../credentials.tfvars && terraform apply --var-file=../credentials.tfvars && terraform destroy --var-file=../credentials.tfvars -force + +variable "url" {} +variable "username" {} +variable "password" {} +variable "vm_uuid" {} + +provider "xenserver" { + url = "${var.url}" + username = "${var.username}" + password = "${var.password}" +} + +data "xenserver_vm_guest_metrics" "interfaces" { + vm_uuid = "${vm_uuid}" +} + +data "template_file" "interfaces_written" { + template = "$${uuids}" + + vars { + uuids = "${jsonencode(data.xenserver_vm_guest_metrics.interfaces.networks)}" + } +} + +resource "null_resource" "interfaces_file" { + triggers { + content = "${data.template_file.interfaces_written.rendered}" + } + + provisioner "local-exec" { + command = <<-EOC + tee ${path.cwd}/output.json < Date: Wed, 17 Jan 2018 13:31:47 +0100 Subject: [PATCH 04/19] bugfix: network information could be empty --- xenserver/types.go | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/xenserver/types.go b/xenserver/types.go index 15a9333..437684c 100644 --- a/xenserver/types.go +++ b/xenserver/types.go @@ -273,29 +273,31 @@ func (this *VMDescriptor) GuestMetrics(c *Connection) (metrics VMGuestMetrics, e return } - // Find out number of interfaces - lastKey := keys[len(keys)-1:][0] - var count int + if len(keys) > 0 { + // Find out number of interfaces + lastKey := keys[len(keys)-1:][0] + var count int - if count, err = strconv.Atoi(re.FindStringSubmatch(lastKey)[1]); err != nil { - return - } - count += 1 // increase by 1 since we obtained index and not length - - metrics.Networks = make([]map[string][]string, count) - - for _, k := range keys { - matches := re.FindStringSubmatch(k) - var index int - if index, err = strconv.Atoi(matches[1]); err != nil { + if count, err = strconv.Atoi(re.FindStringSubmatch(lastKey)[1]); err != nil { return } + count += 1 // increase by 1 since we obtained index and not length - if metrics.Networks[index] == nil { - metrics.Networks[index] = make(map[string][]string) - } + metrics.Networks = make([]map[string][]string, count) + + for _, k := range keys { + matches := re.FindStringSubmatch(k) + var index int + if index, err = strconv.Atoi(matches[1]); err != nil { + return + } - metrics.Networks[index][matches[2]] = append(metrics.Networks[index][matches[2]], metricsRecord.Networks[k]) + if metrics.Networks[index] == nil { + metrics.Networks[index] = make(map[string][]string) + } + + metrics.Networks[index][matches[2]] = append(metrics.Networks[index][matches[2]], metricsRecord.Networks[k]) + } } } From fecf17887119e94a80034d24abbf0e594480c4e6 Mon Sep 17 00:00:00 2001 From: Maksym Borodin Date: Thu, 18 Jan 2018 06:46:13 +0100 Subject: [PATCH 05/19] Implemented xenserver_vm_networks data source, since xenserver_vm_guest_metrics is only usable to display information and not to reuse it due to HCL limitations --- xenserver/data_source_vm_networks.go | 101 +++++++++++++++++++++++++++ xenserver/provider.go | 1 + xenserver/types.go | 21 +++++- 3 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 xenserver/data_source_vm_networks.go diff --git a/xenserver/data_source_vm_networks.go b/xenserver/data_source_vm_networks.go new file mode 100644 index 0000000..869b141 --- /dev/null +++ b/xenserver/data_source_vm_networks.go @@ -0,0 +1,101 @@ +package xenserver + +import ( + "github.com/hashicorp/terraform/helper/schema" + "log" + "time" +) + +const ( + vmNetworksVmUUID = "vm_uuid" + vmNetworksIp = "ip" + vmNetworksIpv6 = "ipv6" + vmNetworksStartupDelay = "startup_delay" +) + +func dataSourceVmNetworks() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVmNetworksRead, + Schema: map[string]*schema.Schema{ + vmNetworksVmUUID: &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + vmNetworksIp: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + vmNetworksIpv6: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + vmNetworksStartupDelay: &schema.Schema{ + Type: schema.TypeFloat, + Optional: true, + Default: 0, + }, + }, + } +} + +func dataSourceVmNetworksRead(d *schema.ResourceData, meta interface{}) (err error) { + c := meta.(*Connection) + + vm := &VMDescriptor{ + UUID: d.Get(vmNetworksVmUUID).(string), + } + if err = vm.Load(c); err != nil { + return + } + + if delay, ok := d.Get(vmNetworksStartupDelay).(float64); ok && delay > 0 { + var vmmetrics VMMetrics + if vmmetrics, err = vm.Metrics(c); err != nil { + return + } + + now := time.Now() + diff := now.Sub(vmmetrics.StartTime).Seconds() + + if delay > diff { + sleep := time.Duration(delay-diff) * time.Second + time.Sleep(sleep) + } + } + + var metrics VMGuestMetrics + + if metrics, err = vm.GuestMetrics(c); err != nil { + return + } + + d.SetId(metrics.UUID) + + log.Printf("[DEBUG] Id is %s\n", d.Id()) + log.Println("[DEBUG] Networks: ", metrics.Networks) + + ipNetworks := make([][]string, 0) + ipv6Networks := make([][]string, 0) + + for _, network := range metrics.Networks { + ipNetworks = append(ipNetworks, network["ip"]) + ipv6Networks = append(ipv6Networks, network["ipv6"]) + } + + d.Set(vmNetworksIp, ipNetworks) + d.Set(vmNetworksIpv6, ipv6Networks) + + return nil +} diff --git a/xenserver/provider.go b/xenserver/provider.go index a2d82de..260b89f 100644 --- a/xenserver/provider.go +++ b/xenserver/provider.go @@ -34,6 +34,7 @@ func Provider() terraform.ResourceProvider { DataSourcesMap: map[string]*schema.Resource{ "xenserver_pifs": dataSourceXenServerPifs(), "xenserver_vm_guest_metrics": dataSourceVmGuestMetrics(), + "xenserver_vm_networks": dataSourceVmNetworks(), }, ResourcesMap: map[string]*schema.Resource{ diff --git a/xenserver/types.go b/xenserver/types.go index 437684c..796a490 100644 --- a/xenserver/types.go +++ b/xenserver/types.go @@ -132,6 +132,12 @@ type VLANDescriptor struct { VLANRef xenAPI.VLANRef } +type VMMetrics struct { + UUID string + StartTime time.Time + InstallTime time.Time +} + type VMGuestMetrics struct { UUID string Disks interface{} @@ -304,13 +310,24 @@ func (this *VMDescriptor) GuestMetrics(c *Connection) (metrics VMGuestMetrics, e return } -func (this *VMDescriptor) Metrics(c *Connection) (metrics xenAPI.VMMetricsRecord, err error) { +func (this *VMDescriptor) Metrics(c *Connection) (metrics VMMetrics, err error) { + var metricsRecord xenAPI.VMMetricsRecord var metricsRef xenAPI.VMMetricsRef if metricsRef, err = c.client.VM.GetMetrics(c.session, this.VMRef); err != nil { return } - return c.client.VMMetrics.GetRecord(c.session, metricsRef) + if metricsRecord, err = c.client.VMMetrics.GetRecord(c.session, metricsRef); err != nil { + return + } + + metrics = VMMetrics{ + UUID: metricsRecord.UUID, + StartTime: metricsRecord.StartTime, + InstallTime: metricsRecord.LastUpdated, + } + + return } func (this *VMDescriptor) Query(c *Connection) error { From 67019183d037a38957a75d4f28bf46750880e6c9 Mon Sep 17 00:00:00 2001 From: Maksym Borodin Date: Thu, 18 Jan 2018 06:46:43 +0100 Subject: [PATCH 06/19] Added IntelliJ files to .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 224f6c1..b4ab10f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ +.idea +*.iml vendor/ dist/ From e500216730c9b46cf95cedccf43962a5065713da Mon Sep 17 00:00:00 2001 From: Maksym Borodin Date: Thu, 18 Jan 2018 07:02:00 +0100 Subject: [PATCH 07/19] Added few examples on how to use xenserver_vm_networks data source --- examples/datasource_vm_networks/main.tf | 43 ++++++++++++ examples/datasource_vm_networks/newvm.tf | 83 ++++++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 examples/datasource_vm_networks/main.tf create mode 100644 examples/datasource_vm_networks/newvm.tf diff --git a/examples/datasource_vm_networks/main.tf b/examples/datasource_vm_networks/main.tf new file mode 100644 index 0000000..0b18453 --- /dev/null +++ b/examples/datasource_vm_networks/main.tf @@ -0,0 +1,43 @@ +# To execute with `credentials.tfvars` in the `examples` folder: +# terraform init && terraform plan --var-file=../credentials.tfvars && terraform apply --var-file=../credentials.tfvars && terraform destroy --var-file=../credentials.tfvars -force + +variable "url" {} +variable "username" {} +variable "password" {} +variable "vm_uuid" {} + +provider "xenserver" { + url = "${var.url}" + username = "${var.username}" + password = "${var.password}" +} + +data "xenserver_vm_networks" "interfaces" { + vm_uuid = "${vm_uuid}" +} + +data "template_file" "interfaces_written" { + template = "$${ips}" + + vars { + ips = "${jsonencode(data.xenserver_vm_networks.interfaces.ip)}" + } +} + +resource "null_resource" "interfaces_file" { + triggers { + content = "${data.template_file.interfaces_written.rendered}" + } + + provisioner "local-exec" { + command = <<-EOC + tee ${path.cwd}/output.json < Date: Thu, 18 Jan 2018 15:08:51 +0100 Subject: [PATCH 08/19] example added: provision VM with ansible --- .../datasource_vm_networks/provision.yaml | 5 ++ .../provision_ansible.tf | 63 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 examples/datasource_vm_networks/provision.yaml create mode 100644 examples/datasource_vm_networks/provision_ansible.tf diff --git a/examples/datasource_vm_networks/provision.yaml b/examples/datasource_vm_networks/provision.yaml new file mode 100644 index 0000000..1b6ebbe --- /dev/null +++ b/examples/datasource_vm_networks/provision.yaml @@ -0,0 +1,5 @@ +--- +- hosts: all + tasks: + - hostname: + name: "{{ provisioned_host_name }}" diff --git a/examples/datasource_vm_networks/provision_ansible.tf b/examples/datasource_vm_networks/provision_ansible.tf new file mode 100644 index 0000000..c1ddee6 --- /dev/null +++ b/examples/datasource_vm_networks/provision_ansible.tf @@ -0,0 +1,63 @@ +# To execute with `credentials.tfvars` in the `examples` folder: +# terraform init && terraform plan --var-file=../credentials.tfvars && terraform apply --var-file=../credentials.tfvars && terraform destroy --var-file=../credentials.tfvars -force + +variable "url" {} +variable "username" {} +variable "password" {} + +provider "xenserver" { + url = "${var.url}" + username = "${var.username}" + password = "${var.password}" +} + +resource "xenserver_vm" "ansiblevm" { + base_template_name = "CentOS 7.4 Template" + name_label = "Ansible VM" + static_mem_min = 2147483648 + static_mem_max = 2147483648 + dynamic_mem_min = 2147483648 + dynamic_mem_max = 2147483648 + vcpus = 1 + boot_order = "c" + hard_drive { + is_from_template = true + user_device = "0" + } + cdrom { + is_from_template = true + user_device = "3" + } + network_interface { + network_uuid = "92467b56-21a7-dfdd-b412-978181a69f32" + device = 0 + mtu = 1500 + mac = "" + other_config { + ethtool-gso = "off" + ethtool-ufo = "off" + ethtool-tso = "off" + ethtool-sg = "off" + ethtool-tx = "off" + ethtool-rx = "off" + } + } + network_interface { + network_uuid = "9318f024-7937-870f-32c7-171040f1fbd8" + device = 1 + mtu = 1500 + mac = "" + } +} + +data "xenserver_vm_networks" "ansible_interfaces" { + vm_uuid = "${xenserver_vm.ansiblevm.id}" + startup_delay = 10 # wait for VM to boot for 10 seconds +} + +resource "null_resource" "provision_ansiblevm" { + provisioner "local-exec" { + command = +"sleep 120; ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -i '${element(data.xenserver_vm_networks.ansible_interfaces.ip[0],0)},' --extra-vars 'provisioned_host_name=ansible.local' ${path.cwd}/provision.yaml" + } +} From 238a2a07b62fa22b348526f9a8601aebcb4445b8 Mon Sep 17 00:00:00 2001 From: Maksym Borodin Date: Thu, 18 Jan 2018 20:07:23 +0100 Subject: [PATCH 09/19] added documentation --- website/docs/d/vm_guest_metrics.md | 30 ++++++++++++++++++++++++++++++ website/docs/d/vm_networks.md | 23 +++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 website/docs/d/vm_guest_metrics.md create mode 100644 website/docs/d/vm_networks.md diff --git a/website/docs/d/vm_guest_metrics.md b/website/docs/d/vm_guest_metrics.md new file mode 100644 index 0000000..91f9f2f --- /dev/null +++ b/website/docs/d/vm_guest_metrics.md @@ -0,0 +1,30 @@ +--- +title: "xenserver_vm_data_metrics" +--- + +Provides metrics reported by guest tools. + +## Parameters +* [in] vm_uuid - UUID of the VM to obtain metrics from +* [out] disks +* [out] networks +* [out] memory +* [out] os_version +* [out] pv_driver_version +* [out] is_pv_driver_present +* [out] can_use_hotplug_vbd +* [out] can_use_hotplug_vif +* [out] is_live +* [out] last_updated + +## Example Usage + +```hcl +data "xenserver_vm_guest_metrics" "interfaces" { + vm_uuid = "${vm_uuid}" +} + +output "vm_main_interface" { + value = "${data.xenserver_vm_guest_metrics.interfaces.networks[0]}" +} +``` diff --git a/website/docs/d/vm_networks.md b/website/docs/d/vm_networks.md new file mode 100644 index 0000000..ac4fa42 --- /dev/null +++ b/website/docs/d/vm_networks.md @@ -0,0 +1,23 @@ +--- +title: "xenserver_vm_networks" +--- + +Query information on IP addresses reported by guest tools. + +## Parameters +* [in] vm_uuid - UUID of the VM to query information about +* [in] [optional] startup_delay - how many seconds should be passed after VM start before information could be queried. Useful when new VM was just created to wait until it boots and guest tools are started +* [out] ip array of arrays with ip addresses where first index corresponds to interface and second to address +* [out] ipv6 array of arrays with IPv6 addresses where first index corresponds to interface and second to address + +## Example Usage + +```hcl +data "xenserver_vm_networks" "interfaces" { + vm_uuid = "${vm_uuid}" +} + +output "vm_main_ip" { + value = "${${element(data.xenserver_vm_networks.interfaces.ip[0],0)}}" +} +``` From 514b8dd29f404708ce1a9d7a4dd32d902bc60304 Mon Sep 17 00:00:00 2001 From: Maksym Borodin Date: Sun, 14 Jan 2018 09:17:56 +0100 Subject: [PATCH 10/19] Obtain VM Metrics --- xenserver/types.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/xenserver/types.go b/xenserver/types.go index 03917c3..72c862a 100644 --- a/xenserver/types.go +++ b/xenserver/types.go @@ -224,6 +224,24 @@ func (this *VMDescriptor) Load(c *Connection) error { return this.Query(c) } +func (this *VMDescriptor) Metrics(c *Connection) (metrics xenAPI.VMMetricsRecord, err error) { + var metricsRef xenAPI.VMMetricsRef + if metricsRef, err = c.client.VM.GetMetrics(c.session, this.VMRef); err != nil { + return + } + + return c.client.VMMetrics.GetRecord(c.session, metricsRef) +} + +func (this *VMDescriptor) GuestMetrics(c *Connection) (metrics xenAPI.VMGuestMetricsRecord, err error) { + var metricsRef xenAPI.VMGuestMetricsRef + if metricsRef, err = c.client.VM.GetGuestMetrics(c.session, this.VMRef); err != nil { + return + } + + return c.client.VMGuestMetrics.GetRecord(c.session, metricsRef) +} + func (this *VMDescriptor) Query(c *Connection) error { vm, err := c.client.VM.GetRecord(c.session, this.VMRef) if err != nil { From 660002534143351fe207aebf5f0b5eac848aa753 Mon Sep 17 00:00:00 2001 From: Maksym Borodin Date: Tue, 16 Jan 2018 05:57:30 +0100 Subject: [PATCH 11/19] Implemented VM Guest Metrics data source --- xenserver/data_source_vm_guest_metrics.go | 128 ++++++++++++++++++++++ xenserver/provider.go | 1 + xenserver/types.go | 85 ++++++++++++-- 3 files changed, 206 insertions(+), 8 deletions(-) create mode 100644 xenserver/data_source_vm_guest_metrics.go diff --git a/xenserver/data_source_vm_guest_metrics.go b/xenserver/data_source_vm_guest_metrics.go new file mode 100644 index 0000000..5993ae7 --- /dev/null +++ b/xenserver/data_source_vm_guest_metrics.go @@ -0,0 +1,128 @@ +package xenserver + +import ( + "github.com/hashicorp/terraform/helper/schema" + "log" +) + +const ( + vmGuestMetricsVmUUID = "vm_uuid" + vmGuestMetricsDisks = "disks" + vmGuestMetricsNetworks = "networks" + vmGuestMetricsMemory = "memory" + vmGuestMetricsOSVersion = "os_version" + vmGuestMetricsPVDriversVersion = "pv_driver_version" + vmGuestMetricsPVDriversDetected = "is_pv_driver_present" + vmGuestMetricsCanUseHotPlugVbd = "can_use_hotplug_vbd" + vmGuestMetricsCanUseHotPlugVif = "can_use_hotplug_vif" + vmGuestMetricsLive = "is_live" + vmGuestMetricsLastUpdated = "last_updated" +) + +func dataSourceVmGuestMetrics() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVmGuestMetricsRead, + Schema: map[string]*schema.Schema{ + vmGuestMetricsVmUUID: &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + vmGuestMetricsDisks: &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + }, + vmGuestMetricsNetworks: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "ipv6": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + vmGuestMetricsMemory: &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + }, + vmGuestMetricsOSVersion: &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + }, + vmGuestMetricsPVDriversVersion: &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + }, + vmGuestMetricsPVDriversDetected: &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + }, + vmGuestMetricsCanUseHotPlugVbd: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + vmGuestMetricsCanUseHotPlugVif: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + vmGuestMetricsLive: &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + }, + vmGuestMetricsLastUpdated: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceVmGuestMetricsRead(d *schema.ResourceData, meta interface{}) (err error) { + c := meta.(*Connection) + + vm := &VMDescriptor{ + UUID: d.Get(vmGuestMetricsVmUUID).(string), + } + if err = vm.Load(c); err != nil { + return + } + + var metrics VMGuestMetrics + + if metrics, err = vm.GuestMetrics(c); err != nil { + return + } + + d.SetId(metrics.UUID) + + log.Printf("[DEBUG] Id is %s\n", d.Id()) + log.Println("[DEBUG] Networks: ", metrics.Networks) + + d.Set(vmGuestMetricsDisks, metrics.Disks) + d.Set(vmGuestMetricsNetworks, metrics.Networks) + d.Set(vmGuestMetricsMemory, metrics.Memory) + d.Set(vmGuestMetricsOSVersion, metrics.OSVersion) + d.Set(vmGuestMetricsPVDriversVersion, metrics.PVDriversVersion) + d.Set(vmGuestMetricsPVDriversDetected, metrics.PVDriversDetected) + d.Set(vmGuestMetricsCanUseHotPlugVbd, metrics.CanUseHotplugVbd) + d.Set(vmGuestMetricsCanUseHotPlugVif, metrics.CanUseHotplugVif) + d.Set(vmGuestMetricsLive, metrics.Live) + d.Set(vmGuestMetricsLastUpdated, metrics.LastUpdated.String()) + + return nil +} + +/* +func networksToSchemaList(networks []map[string][]string) []interface{} { + + + +}*/ diff --git a/xenserver/provider.go b/xenserver/provider.go index 8220c2f..6aed40a 100644 --- a/xenserver/provider.go +++ b/xenserver/provider.go @@ -35,6 +35,7 @@ func Provider() terraform.ResourceProvider { "xenserver_pif": dataSourceXenServerPif(), "xenserver_pifs": dataSourceXenServerPifs(), "xenserver_sr": dataSourceXenServerSR(), + "xenserver_vm_guest_metrics": dataSourceVmGuestMetrics(), }, ResourcesMap: map[string]*schema.Resource{ diff --git a/xenserver/types.go b/xenserver/types.go index 72c862a..15a9333 100644 --- a/xenserver/types.go +++ b/xenserver/types.go @@ -24,6 +24,9 @@ import ( "strconv" "github.com/ringods/go-xen-api-client" + "regexp" + "sort" + "time" ) type Range struct { @@ -129,6 +132,21 @@ type VLANDescriptor struct { VLANRef xenAPI.VLANRef } +type VMGuestMetrics struct { + UUID string + Disks interface{} + Networks []map[string][]string + Memory interface{} + OSVersion interface{} + PVDriversVersion interface{} + PVDriversDetected bool + PVDriversUpToDate bool + CanUseHotplugVbd string + CanUseHotplugVif string + Live bool + LastUpdated time.Time +} + func (this *NetworkDescriptor) Load(c *Connection) error { var network xenAPI.NetworkRef @@ -224,22 +242,73 @@ func (this *VMDescriptor) Load(c *Connection) error { return this.Query(c) } -func (this *VMDescriptor) Metrics(c *Connection) (metrics xenAPI.VMMetricsRecord, err error) { - var metricsRef xenAPI.VMMetricsRef - if metricsRef, err = c.client.VM.GetMetrics(c.session, this.VMRef); err != nil { +func (this *VMDescriptor) GuestMetrics(c *Connection) (metrics VMGuestMetrics, err error) { + var metricsRef xenAPI.VMGuestMetricsRef + var metricsRecord xenAPI.VMGuestMetricsRecord + if metricsRef, err = c.client.VM.GetGuestMetrics(c.session, this.VMRef); err != nil { return } - return c.client.VMMetrics.GetRecord(c.session, metricsRef) + if metricsRecord, err = c.client.VMGuestMetrics.GetRecord(c.session, metricsRef); err == nil { + metrics.UUID = metricsRecord.UUID + metrics.Disks = metricsRecord.Disks + metrics.Memory = metricsRecord.Memory + metrics.OSVersion = metricsRecord.OSVersion + metrics.PVDriversVersion = metricsRecord.PVDriversVersion + metrics.PVDriversDetected = metricsRecord.PVDriversDetected + metrics.PVDriversUpToDate = metricsRecord.PVDriversUpToDate + metrics.CanUseHotplugVbd = string(metricsRecord.CanUseHotplugVbd) + metrics.CanUseHotplugVif = string(metricsRecord.CanUseHotplugVif) + metrics.Live = metricsRecord.Live + metrics.LastUpdated = metricsRecord.LastUpdated + + var keys []string + for k := range metricsRecord.Networks { + keys = append(keys, k) + } + sort.Strings(keys) + + var re *regexp.Regexp + if re, err = regexp.Compile("([0-9]+)/(ipv?6?)/?[0-9]*"); err != nil { + return + } + + // Find out number of interfaces + lastKey := keys[len(keys)-1:][0] + var count int + + if count, err = strconv.Atoi(re.FindStringSubmatch(lastKey)[1]); err != nil { + return + } + count += 1 // increase by 1 since we obtained index and not length + + metrics.Networks = make([]map[string][]string, count) + + for _, k := range keys { + matches := re.FindStringSubmatch(k) + var index int + if index, err = strconv.Atoi(matches[1]); err != nil { + return + } + + if metrics.Networks[index] == nil { + metrics.Networks[index] = make(map[string][]string) + } + + metrics.Networks[index][matches[2]] = append(metrics.Networks[index][matches[2]], metricsRecord.Networks[k]) + } + } + + return } -func (this *VMDescriptor) GuestMetrics(c *Connection) (metrics xenAPI.VMGuestMetricsRecord, err error) { - var metricsRef xenAPI.VMGuestMetricsRef - if metricsRef, err = c.client.VM.GetGuestMetrics(c.session, this.VMRef); err != nil { +func (this *VMDescriptor) Metrics(c *Connection) (metrics xenAPI.VMMetricsRecord, err error) { + var metricsRef xenAPI.VMMetricsRef + if metricsRef, err = c.client.VM.GetMetrics(c.session, this.VMRef); err != nil { return } - return c.client.VMGuestMetrics.GetRecord(c.session, metricsRef) + return c.client.VMMetrics.GetRecord(c.session, metricsRef) } func (this *VMDescriptor) Query(c *Connection) error { From a3e918498b4fe5ecc477063bbfc2d5ae23bb3a67 Mon Sep 17 00:00:00 2001 From: Maksym Borodin Date: Tue, 16 Jan 2018 06:04:53 +0100 Subject: [PATCH 12/19] Example how to use VM metrics data source --- examples/datasource_vm_guest_metrics/main.tf | 44 ++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 examples/datasource_vm_guest_metrics/main.tf diff --git a/examples/datasource_vm_guest_metrics/main.tf b/examples/datasource_vm_guest_metrics/main.tf new file mode 100644 index 0000000..11f6ded --- /dev/null +++ b/examples/datasource_vm_guest_metrics/main.tf @@ -0,0 +1,44 @@ +# To execute with `credentials.tfvars` in the `examples` folder: +# terraform init && terraform plan --var-file=../credentials.tfvars && terraform apply --var-file=../credentials.tfvars && terraform destroy --var-file=../credentials.tfvars -force + +variable "url" {} +variable "username" {} +variable "password" {} +variable "vm_uuid" {} + +provider "xenserver" { + url = "${var.url}" + username = "${var.username}" + password = "${var.password}" +} + +data "xenserver_vm_guest_metrics" "interfaces" { + vm_uuid = "${vm_uuid}" +} + +data "template_file" "interfaces_written" { + template = "$${uuids}" + + vars { + uuids = "${jsonencode(data.xenserver_vm_guest_metrics.interfaces.networks)}" + } +} + +resource "null_resource" "interfaces_file" { + triggers { + content = "${data.template_file.interfaces_written.rendered}" + } + + provisioner "local-exec" { + command = <<-EOC + tee ${path.cwd}/output.json < Date: Wed, 17 Jan 2018 13:31:47 +0100 Subject: [PATCH 13/19] bugfix: network information could be empty --- xenserver/types.go | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/xenserver/types.go b/xenserver/types.go index 15a9333..437684c 100644 --- a/xenserver/types.go +++ b/xenserver/types.go @@ -273,29 +273,31 @@ func (this *VMDescriptor) GuestMetrics(c *Connection) (metrics VMGuestMetrics, e return } - // Find out number of interfaces - lastKey := keys[len(keys)-1:][0] - var count int + if len(keys) > 0 { + // Find out number of interfaces + lastKey := keys[len(keys)-1:][0] + var count int - if count, err = strconv.Atoi(re.FindStringSubmatch(lastKey)[1]); err != nil { - return - } - count += 1 // increase by 1 since we obtained index and not length - - metrics.Networks = make([]map[string][]string, count) - - for _, k := range keys { - matches := re.FindStringSubmatch(k) - var index int - if index, err = strconv.Atoi(matches[1]); err != nil { + if count, err = strconv.Atoi(re.FindStringSubmatch(lastKey)[1]); err != nil { return } + count += 1 // increase by 1 since we obtained index and not length - if metrics.Networks[index] == nil { - metrics.Networks[index] = make(map[string][]string) - } + metrics.Networks = make([]map[string][]string, count) + + for _, k := range keys { + matches := re.FindStringSubmatch(k) + var index int + if index, err = strconv.Atoi(matches[1]); err != nil { + return + } - metrics.Networks[index][matches[2]] = append(metrics.Networks[index][matches[2]], metricsRecord.Networks[k]) + if metrics.Networks[index] == nil { + metrics.Networks[index] = make(map[string][]string) + } + + metrics.Networks[index][matches[2]] = append(metrics.Networks[index][matches[2]], metricsRecord.Networks[k]) + } } } From 33b25869d0dcff3a0f84d4bd4a33ea190cb3c05e Mon Sep 17 00:00:00 2001 From: Maksym Borodin Date: Thu, 18 Jan 2018 06:46:13 +0100 Subject: [PATCH 14/19] Implemented xenserver_vm_networks data source, since xenserver_vm_guest_metrics is only usable to display information and not to reuse it due to HCL limitations --- xenserver/data_source_vm_networks.go | 101 +++++++++++++++++++++++++++ xenserver/provider.go | 1 + xenserver/types.go | 21 +++++- 3 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 xenserver/data_source_vm_networks.go diff --git a/xenserver/data_source_vm_networks.go b/xenserver/data_source_vm_networks.go new file mode 100644 index 0000000..869b141 --- /dev/null +++ b/xenserver/data_source_vm_networks.go @@ -0,0 +1,101 @@ +package xenserver + +import ( + "github.com/hashicorp/terraform/helper/schema" + "log" + "time" +) + +const ( + vmNetworksVmUUID = "vm_uuid" + vmNetworksIp = "ip" + vmNetworksIpv6 = "ipv6" + vmNetworksStartupDelay = "startup_delay" +) + +func dataSourceVmNetworks() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVmNetworksRead, + Schema: map[string]*schema.Schema{ + vmNetworksVmUUID: &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + vmNetworksIp: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + vmNetworksIpv6: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + vmNetworksStartupDelay: &schema.Schema{ + Type: schema.TypeFloat, + Optional: true, + Default: 0, + }, + }, + } +} + +func dataSourceVmNetworksRead(d *schema.ResourceData, meta interface{}) (err error) { + c := meta.(*Connection) + + vm := &VMDescriptor{ + UUID: d.Get(vmNetworksVmUUID).(string), + } + if err = vm.Load(c); err != nil { + return + } + + if delay, ok := d.Get(vmNetworksStartupDelay).(float64); ok && delay > 0 { + var vmmetrics VMMetrics + if vmmetrics, err = vm.Metrics(c); err != nil { + return + } + + now := time.Now() + diff := now.Sub(vmmetrics.StartTime).Seconds() + + if delay > diff { + sleep := time.Duration(delay-diff) * time.Second + time.Sleep(sleep) + } + } + + var metrics VMGuestMetrics + + if metrics, err = vm.GuestMetrics(c); err != nil { + return + } + + d.SetId(metrics.UUID) + + log.Printf("[DEBUG] Id is %s\n", d.Id()) + log.Println("[DEBUG] Networks: ", metrics.Networks) + + ipNetworks := make([][]string, 0) + ipv6Networks := make([][]string, 0) + + for _, network := range metrics.Networks { + ipNetworks = append(ipNetworks, network["ip"]) + ipv6Networks = append(ipv6Networks, network["ipv6"]) + } + + d.Set(vmNetworksIp, ipNetworks) + d.Set(vmNetworksIpv6, ipv6Networks) + + return nil +} diff --git a/xenserver/provider.go b/xenserver/provider.go index 6aed40a..88bdaec 100644 --- a/xenserver/provider.go +++ b/xenserver/provider.go @@ -36,6 +36,7 @@ func Provider() terraform.ResourceProvider { "xenserver_pifs": dataSourceXenServerPifs(), "xenserver_sr": dataSourceXenServerSR(), "xenserver_vm_guest_metrics": dataSourceVmGuestMetrics(), + "xenserver_vm_networks": dataSourceVmNetworks(), }, ResourcesMap: map[string]*schema.Resource{ diff --git a/xenserver/types.go b/xenserver/types.go index 437684c..796a490 100644 --- a/xenserver/types.go +++ b/xenserver/types.go @@ -132,6 +132,12 @@ type VLANDescriptor struct { VLANRef xenAPI.VLANRef } +type VMMetrics struct { + UUID string + StartTime time.Time + InstallTime time.Time +} + type VMGuestMetrics struct { UUID string Disks interface{} @@ -304,13 +310,24 @@ func (this *VMDescriptor) GuestMetrics(c *Connection) (metrics VMGuestMetrics, e return } -func (this *VMDescriptor) Metrics(c *Connection) (metrics xenAPI.VMMetricsRecord, err error) { +func (this *VMDescriptor) Metrics(c *Connection) (metrics VMMetrics, err error) { + var metricsRecord xenAPI.VMMetricsRecord var metricsRef xenAPI.VMMetricsRef if metricsRef, err = c.client.VM.GetMetrics(c.session, this.VMRef); err != nil { return } - return c.client.VMMetrics.GetRecord(c.session, metricsRef) + if metricsRecord, err = c.client.VMMetrics.GetRecord(c.session, metricsRef); err != nil { + return + } + + metrics = VMMetrics{ + UUID: metricsRecord.UUID, + StartTime: metricsRecord.StartTime, + InstallTime: metricsRecord.LastUpdated, + } + + return } func (this *VMDescriptor) Query(c *Connection) error { From 5168a49d00d4f8ca30ef94ca1d551c34d519981c Mon Sep 17 00:00:00 2001 From: Maksym Borodin Date: Thu, 18 Jan 2018 06:46:43 +0100 Subject: [PATCH 15/19] Added IntelliJ files to .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 224f6c1..b4ab10f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ +.idea +*.iml vendor/ dist/ From 6126097e0d96fdb53c1fbd3d10f289244a06054e Mon Sep 17 00:00:00 2001 From: Maksym Borodin Date: Thu, 18 Jan 2018 07:02:00 +0100 Subject: [PATCH 16/19] Added few examples on how to use xenserver_vm_networks data source --- examples/datasource_vm_networks/main.tf | 43 ++++++++++++ examples/datasource_vm_networks/newvm.tf | 83 ++++++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 examples/datasource_vm_networks/main.tf create mode 100644 examples/datasource_vm_networks/newvm.tf diff --git a/examples/datasource_vm_networks/main.tf b/examples/datasource_vm_networks/main.tf new file mode 100644 index 0000000..0b18453 --- /dev/null +++ b/examples/datasource_vm_networks/main.tf @@ -0,0 +1,43 @@ +# To execute with `credentials.tfvars` in the `examples` folder: +# terraform init && terraform plan --var-file=../credentials.tfvars && terraform apply --var-file=../credentials.tfvars && terraform destroy --var-file=../credentials.tfvars -force + +variable "url" {} +variable "username" {} +variable "password" {} +variable "vm_uuid" {} + +provider "xenserver" { + url = "${var.url}" + username = "${var.username}" + password = "${var.password}" +} + +data "xenserver_vm_networks" "interfaces" { + vm_uuid = "${vm_uuid}" +} + +data "template_file" "interfaces_written" { + template = "$${ips}" + + vars { + ips = "${jsonencode(data.xenserver_vm_networks.interfaces.ip)}" + } +} + +resource "null_resource" "interfaces_file" { + triggers { + content = "${data.template_file.interfaces_written.rendered}" + } + + provisioner "local-exec" { + command = <<-EOC + tee ${path.cwd}/output.json < Date: Thu, 18 Jan 2018 15:08:51 +0100 Subject: [PATCH 17/19] example added: provision VM with ansible --- .../datasource_vm_networks/provision.yaml | 5 ++ .../provision_ansible.tf | 63 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 examples/datasource_vm_networks/provision.yaml create mode 100644 examples/datasource_vm_networks/provision_ansible.tf diff --git a/examples/datasource_vm_networks/provision.yaml b/examples/datasource_vm_networks/provision.yaml new file mode 100644 index 0000000..1b6ebbe --- /dev/null +++ b/examples/datasource_vm_networks/provision.yaml @@ -0,0 +1,5 @@ +--- +- hosts: all + tasks: + - hostname: + name: "{{ provisioned_host_name }}" diff --git a/examples/datasource_vm_networks/provision_ansible.tf b/examples/datasource_vm_networks/provision_ansible.tf new file mode 100644 index 0000000..c1ddee6 --- /dev/null +++ b/examples/datasource_vm_networks/provision_ansible.tf @@ -0,0 +1,63 @@ +# To execute with `credentials.tfvars` in the `examples` folder: +# terraform init && terraform plan --var-file=../credentials.tfvars && terraform apply --var-file=../credentials.tfvars && terraform destroy --var-file=../credentials.tfvars -force + +variable "url" {} +variable "username" {} +variable "password" {} + +provider "xenserver" { + url = "${var.url}" + username = "${var.username}" + password = "${var.password}" +} + +resource "xenserver_vm" "ansiblevm" { + base_template_name = "CentOS 7.4 Template" + name_label = "Ansible VM" + static_mem_min = 2147483648 + static_mem_max = 2147483648 + dynamic_mem_min = 2147483648 + dynamic_mem_max = 2147483648 + vcpus = 1 + boot_order = "c" + hard_drive { + is_from_template = true + user_device = "0" + } + cdrom { + is_from_template = true + user_device = "3" + } + network_interface { + network_uuid = "92467b56-21a7-dfdd-b412-978181a69f32" + device = 0 + mtu = 1500 + mac = "" + other_config { + ethtool-gso = "off" + ethtool-ufo = "off" + ethtool-tso = "off" + ethtool-sg = "off" + ethtool-tx = "off" + ethtool-rx = "off" + } + } + network_interface { + network_uuid = "9318f024-7937-870f-32c7-171040f1fbd8" + device = 1 + mtu = 1500 + mac = "" + } +} + +data "xenserver_vm_networks" "ansible_interfaces" { + vm_uuid = "${xenserver_vm.ansiblevm.id}" + startup_delay = 10 # wait for VM to boot for 10 seconds +} + +resource "null_resource" "provision_ansiblevm" { + provisioner "local-exec" { + command = +"sleep 120; ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -i '${element(data.xenserver_vm_networks.ansible_interfaces.ip[0],0)},' --extra-vars 'provisioned_host_name=ansible.local' ${path.cwd}/provision.yaml" + } +} From 89c296c44746243299b4b828e02c3921781ddc01 Mon Sep 17 00:00:00 2001 From: Maksym Borodin Date: Thu, 18 Jan 2018 20:07:23 +0100 Subject: [PATCH 18/19] added documentation --- website/docs/d/vm_guest_metrics.md | 30 ++++++++++++++++++++++++++++++ website/docs/d/vm_networks.md | 23 +++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 website/docs/d/vm_guest_metrics.md create mode 100644 website/docs/d/vm_networks.md diff --git a/website/docs/d/vm_guest_metrics.md b/website/docs/d/vm_guest_metrics.md new file mode 100644 index 0000000..91f9f2f --- /dev/null +++ b/website/docs/d/vm_guest_metrics.md @@ -0,0 +1,30 @@ +--- +title: "xenserver_vm_data_metrics" +--- + +Provides metrics reported by guest tools. + +## Parameters +* [in] vm_uuid - UUID of the VM to obtain metrics from +* [out] disks +* [out] networks +* [out] memory +* [out] os_version +* [out] pv_driver_version +* [out] is_pv_driver_present +* [out] can_use_hotplug_vbd +* [out] can_use_hotplug_vif +* [out] is_live +* [out] last_updated + +## Example Usage + +```hcl +data "xenserver_vm_guest_metrics" "interfaces" { + vm_uuid = "${vm_uuid}" +} + +output "vm_main_interface" { + value = "${data.xenserver_vm_guest_metrics.interfaces.networks[0]}" +} +``` diff --git a/website/docs/d/vm_networks.md b/website/docs/d/vm_networks.md new file mode 100644 index 0000000..ac4fa42 --- /dev/null +++ b/website/docs/d/vm_networks.md @@ -0,0 +1,23 @@ +--- +title: "xenserver_vm_networks" +--- + +Query information on IP addresses reported by guest tools. + +## Parameters +* [in] vm_uuid - UUID of the VM to query information about +* [in] [optional] startup_delay - how many seconds should be passed after VM start before information could be queried. Useful when new VM was just created to wait until it boots and guest tools are started +* [out] ip array of arrays with ip addresses where first index corresponds to interface and second to address +* [out] ipv6 array of arrays with IPv6 addresses where first index corresponds to interface and second to address + +## Example Usage + +```hcl +data "xenserver_vm_networks" "interfaces" { + vm_uuid = "${vm_uuid}" +} + +output "vm_main_ip" { + value = "${${element(data.xenserver_vm_networks.interfaces.ip[0],0)}}" +} +``` From 0ed360167b0d5f12cb94fc6787d902f65fb9d783 Mon Sep 17 00:00:00 2001 From: Mathieu Debove Date: Thu, 7 Jun 2018 14:11:26 +0200 Subject: [PATCH 19/19] Go fmt --- xenserver/provider.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xenserver/provider.go b/xenserver/provider.go index 88bdaec..0d9af53 100644 --- a/xenserver/provider.go +++ b/xenserver/provider.go @@ -32,9 +32,9 @@ func Provider() terraform.ResourceProvider { }, DataSourcesMap: map[string]*schema.Resource{ - "xenserver_pif": dataSourceXenServerPif(), - "xenserver_pifs": dataSourceXenServerPifs(), - "xenserver_sr": dataSourceXenServerSR(), + "xenserver_pif": dataSourceXenServerPif(), + "xenserver_pifs": dataSourceXenServerPifs(), + "xenserver_sr": dataSourceXenServerSR(), "xenserver_vm_guest_metrics": dataSourceVmGuestMetrics(), "xenserver_vm_networks": dataSourceVmNetworks(), },