diff options
-rw-r--r-- | libvirt/resource_libvirt_domain.go | 111 | ||||
-rw-r--r-- | libvirt/resource_libvirt_domain_test.go | 68 |
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) |