aboutsummaryrefslogtreecommitdiff
path: root/libvirt
diff options
context:
space:
mode:
authorDuncan Mac-Vicar P <dmacvicar@suse.de>2017-11-16 13:44:15 +0100
committerDuncan Mac-Vicar P <dmacvicar@suse.de>2017-11-19 16:51:37 +0100
commit58bfa4b78a143699dff9962b1781a66b202e718e (patch)
treeec7f80152898b459d02ce755edf2c9938a80bc58 /libvirt
parent3a52429e58643dad0e6122f3fb47b61be2ba2c72 (diff)
downloadterraform-provider-libvirt-58bfa4b78a143699dff9962b1781a66b202e718e.tar
terraform-provider-libvirt-58bfa4b78a143699dff9962b1781a66b202e718e.tar.gz
Add support for remote http disks (qemu http curl backend)
Diffstat (limited to 'libvirt')
-rw-r--r--libvirt/resource_libvirt_domain.go111
-rw-r--r--libvirt/resource_libvirt_domain_test.go68
2 files changed, 148 insertions, 31 deletions
diff --git a/libvirt/resource_libvirt_domain.go b/libvirt/resource_libvirt_domain.go
index 317bfd33..90a0896d 100644
--- a/libvirt/resource_libvirt_domain.go
+++ b/libvirt/resource_libvirt_domain.go
@@ -7,6 +7,7 @@ import (
"fmt"
"log"
"net"
+ "net/url"
"os"
"strconv"
"strings"
@@ -382,7 +383,6 @@ func resourceLibvirtDomainCreate(d *schema.ResourceData, meta interface{}) error
diskKey := fmt.Sprintf("disk.%d", i)
diskMap := d.Get(diskKey).(map[string]interface{})
- volumeKey := diskMap["volume_id"].(string)
if _, ok := diskMap["scsi"].(string); ok {
disk.Target.Bus = "scsi"
scsiDisk = true
@@ -392,17 +392,47 @@ func resourceLibvirtDomainCreate(d *schema.ResourceData, meta interface{}) error
disk.WWN = randomWWN(10)
}
}
- diskVolume, err := virConn.LookupStorageVolByKey(volumeKey)
- if err != nil {
- return fmt.Errorf("Can't retrieve volume %s", volumeKey)
- }
- diskVolumeFile, err := diskVolume.GetPath()
- if err != nil {
- return fmt.Errorf("Error retrieving volume file: %s", err)
- }
- disk.Source = &libvirtxml.DomainDiskSource{
- File: diskVolumeFile,
+ if _, ok := diskMap["volume_id"].(string); ok {
+ volumeKey := diskMap["volume_id"].(string)
+
+ diskVolume, err := virConn.LookupStorageVolByKey(volumeKey)
+ if err != nil {
+ return fmt.Errorf("Can't retrieve volume %s", volumeKey)
+ }
+ diskVolumeFile, err := diskVolume.GetPath()
+ if err != nil {
+ return fmt.Errorf("Error retrieving volume file: %s", err)
+ }
+
+ disk.Source = &libvirtxml.DomainDiskSource{
+ File: diskVolumeFile,
+ }
+ } else if _, ok := diskMap["url"].(string); ok {
+ // Support for remote, read-only http disks
+ // useful for booting CDs
+ disk.Type = "network"
+ url, err := url.Parse(diskMap["url"].(string))
+ if err != nil {
+ return err
+ }
+
+ disk.Source = &libvirtxml.DomainDiskSource{
+ Protocol: url.Scheme,
+ Name: url.Path,
+ Hosts: []libvirtxml.DomainDiskSourceHost{
+ libvirtxml.DomainDiskSourceHost{
+ Name: url.Hostname(),
+ Port: url.Port(),
+ },
+ },
+ }
+ if strings.HasSuffix(url.Path, ".iso") {
+ disk.Device = "cdrom"
+ }
+ if !strings.HasSuffix(url.Path, ".qcow2") {
+ disk.Driver.Type = "raw"
+ }
}
disks = append(disks, disk)
@@ -870,33 +900,52 @@ func resourceLibvirtDomainRead(d *schema.ResourceData, meta interface{}) error {
disks := make([]map[string]interface{}, 0)
for _, diskDef := range domainDef.Devices.Disks {
- var virVol *libvirt.StorageVol
- if len(diskDef.Source.File) > 0 {
- virVol, err = virConn.LookupStorageVolByPath(diskDef.Source.File)
- } else {
- virPool, err := virConn.LookupStoragePoolByName(diskDef.Source.Pool)
+ // network drives do not have a volume associated
+ if diskDef.Type == "network" {
+ if len(diskDef.Source.Hosts) < 1 {
+ return fmt.Errorf("Network disk does not contain any hosts")
+ }
+ url, err := url.Parse(fmt.Sprintf("%s://%s:%s%s",
+ diskDef.Source.Protocol,
+ diskDef.Source.Hosts[0].Name,
+ diskDef.Source.Hosts[0].Port,
+ diskDef.Source.Name))
if err != nil {
- return fmt.Errorf("Error retrieving pool for disk: %s", err)
+ return err
+ }
+ disk := map[string]interface{}{
+ "url": url.String(),
}
- defer virPool.Free()
+ disks = append(disks, disk)
+ } else {
+ var virVol *libvirt.StorageVol
+ if len(diskDef.Source.File) > 0 {
+ virVol, err = virConn.LookupStorageVolByPath(diskDef.Source.File)
+ } else {
+ virPool, err := virConn.LookupStoragePoolByName(diskDef.Source.Pool)
+ if err != nil {
+ return fmt.Errorf("Error retrieving pool for disk: %s", err)
+ }
+ defer virPool.Free()
- virVol, err = virPool.LookupStorageVolByName(diskDef.Source.Volume)
- }
+ virVol, err = virPool.LookupStorageVolByName(diskDef.Source.Volume)
+ }
- if err != nil {
- return fmt.Errorf("Error retrieving volume for disk: %s", err)
- }
- defer virVol.Free()
+ if err != nil {
+ return fmt.Errorf("Error retrieving volume for disk: %s", err)
+ }
+ defer virVol.Free()
- virVolKey, err := virVol.GetKey()
- if err != nil {
- return fmt.Errorf("Error retrieving volume for disk: %s", err)
- }
+ virVolKey, err := virVol.GetKey()
+ if err != nil {
+ return fmt.Errorf("Error retrieving volume for disk: %s", err)
+ }
- disk := map[string]interface{}{
- "volume_id": virVolKey,
+ disk := map[string]interface{}{
+ "volume_id": virVolKey,
+ }
+ disks = append(disks, disk)
}
- disks = append(disks, disk)
}
d.Set("disks", disks)
diff --git a/libvirt/resource_libvirt_domain_test.go b/libvirt/resource_libvirt_domain_test.go
index 954f1ba5..0fe6d078 100644
--- a/libvirt/resource_libvirt_domain_test.go
+++ b/libvirt/resource_libvirt_domain_test.go
@@ -5,6 +5,7 @@ import (
"fmt"
"io/ioutil"
"log"
+ "net/url"
"os"
"testing"
@@ -202,6 +203,38 @@ func TestAccLibvirtDomain_ScsiDisk(t *testing.T) {
}
+func TestAccLibvirtDomainUrlDisk(t *testing.T) {
+ var domain libvirt.Domain
+ u, err := url.Parse("http://download.opensuse.org/tumbleweed/iso/openSUSE-Tumbleweed-DVD-x86_64-Current.iso")
+ if err != nil {
+ t.Error(err)
+ }
+
+ var configUrl = fmt.Sprintf(`
+ resource "libvirt_domain" "acceptance-test-domain" {
+ name = "terraform-test-domain"
+ disk {
+ url = "%s"
+ }
+ }`, u.String())
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ Providers: testAccProviders,
+ CheckDestroy: testAccCheckLibvirtDomainDestroy,
+ Steps: []resource.TestStep{
+ resource.TestStep{
+ Config: configUrl,
+ Check: resource.ComposeTestCheckFunc(
+ testAccCheckLibvirtDomainExists("libvirt_domain.acceptance-test-domain", &domain),
+ testAccCheckLibvirtUrlDisk(u, &domain),
+ ),
+ },
+ },
+ })
+
+}
+
func TestAccLibvirtDomain_NetworkInterface(t *testing.T) {
var domain libvirt.Domain
@@ -590,6 +623,41 @@ func testAccCheckLibvirtScsiDisk(n string, domain *libvirt.Domain) resource.Test
}
}
+func testAccCheckLibvirtUrlDisk(u *url.URL, domain *libvirt.Domain) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ xmlDesc, err := domain.GetXMLDesc(0)
+ if err != nil {
+ return fmt.Errorf("Error retrieving libvirt domain XML description: %s", err)
+ }
+
+ domainDef := newDomainDef()
+ err = xml.Unmarshal([]byte(xmlDesc), &domainDef)
+ if err != nil {
+ return fmt.Errorf("Error reading libvirt domain XML description: %s", err)
+ }
+
+ disks := domainDef.Devices.Disks
+ for _, disk := range disks {
+ if disk.Type != "network" {
+ return fmt.Errorf("Disk type is not network")
+ }
+ if disk.Source.Protocol != u.Scheme {
+ return fmt.Errorf("Disk protocol is not %s", u.Scheme)
+ }
+ if disk.Source.Name != u.Path {
+ return fmt.Errorf("Disk name is not %s", u.Path)
+ }
+ if len(disk.Source.Hosts) < 1 {
+ return fmt.Errorf("Disk has no hosts defined")
+ }
+ if disk.Source.Hosts[0].Name != u.Hostname() {
+ return fmt.Errorf("Disk hostname is not %s", u.Hostname())
+ }
+ }
+ return nil
+ }
+}
+
func createNvramFile() (string, error) {
// size of an accepted, valid, nvram backing store
NVRAMDummyBuffer := make([]byte, 131072)