aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDuncan Mac-Vicar P <dmacvicar@gmail.com>2017-11-21 11:41:02 +0100
committerGitHub <noreply@github.com>2017-11-21 11:41:02 +0100
commitd7fe1a2a37a8373ac261b1e3025efba27bfab2d6 (patch)
tree0fe385d5b26869a6706fde0662366706324c9a49
parent3a52429e58643dad0e6122f3fb47b61be2ba2c72 (diff)
parent49dadde97886f31fd32b220e1918c5025c6c317e (diff)
downloadterraform-provider-libvirt-d7fe1a2a37a8373ac261b1e3025efba27bfab2d6.tar
terraform-provider-libvirt-d7fe1a2a37a8373ac261b1e3025efba27bfab2d6.tar.gz
Merge pull request #239 from dmacvicar/disks_from_http_url
Supports disks from the network using QEMU curl backend
-rw-r--r--libvirt/disk_def.go4
-rw-r--r--libvirt/disk_def_test.go2
-rw-r--r--libvirt/resource_libvirt_domain.go124
-rw-r--r--libvirt/resource_libvirt_domain_test.go68
-rw-r--r--website/docs/r/domain.html.markdown11
5 files changed, 163 insertions, 46 deletions
diff --git a/libvirt/disk_def.go b/libvirt/disk_def.go
index 3283f03b..f4e4e86a 100644
--- a/libvirt/disk_def.go
+++ b/libvirt/disk_def.go
@@ -1,6 +1,7 @@
package libvirt
import (
+ "fmt"
"math/rand"
"github.com/libvirt/libvirt-go-xml"
@@ -8,12 +9,13 @@ import (
const oui = "05abcd"
-func newDefDisk() libvirtxml.DomainDisk {
+func newDefDisk(i int) libvirtxml.DomainDisk {
return libvirtxml.DomainDisk{
Type: "file",
Device: "disk",
Target: &libvirtxml.DomainDiskTarget{
Bus: "virtio",
+ Dev: fmt.Sprintf("vd%s", DiskLetterForIndex(i)),
},
Driver: &libvirtxml.DomainDiskDriver{
Name: "qemu",
diff --git a/libvirt/disk_def_test.go b/libvirt/disk_def_test.go
index 1e3141d5..a6184cc6 100644
--- a/libvirt/disk_def_test.go
+++ b/libvirt/disk_def_test.go
@@ -13,7 +13,7 @@ func init() {
}
func TestDefaultDiskMarshall(t *testing.T) {
- b := newDefDisk()
+ b := newDefDisk(0)
buf := new(bytes.Buffer)
enc := xml.NewEncoder(buf)
enc.Indent(" ", " ")
diff --git a/libvirt/resource_libvirt_domain.go b/libvirt/resource_libvirt_domain.go
index 317bfd33..e5034352 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"
@@ -367,22 +368,10 @@ func resourceLibvirtDomainCreate(d *schema.ResourceData, meta interface{}) error
var disks []libvirtxml.DomainDisk
var scsiDisk = false
for i := 0; i < disksCount; i++ {
- disk := libvirtxml.DomainDisk{
- Type: "file",
- Device: "disk",
- Target: &libvirtxml.DomainDiskTarget{
- Bus: "virtio",
- Dev: fmt.Sprintf("vd%s", DiskLetterForIndex(i)),
- },
- Driver: &libvirtxml.DomainDiskDriver{
- Name: "qemu",
- Type: "qcow2",
- },
- }
+ disk := newDefDisk(i)
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 +381,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 +889,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
}
- defer virPool.Free()
+ disk := map[string]interface{}{
+ "url": url.String(),
+ }
+ 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..65d9f898 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)
diff --git a/website/docs/r/domain.html.markdown b/website/docs/r/domain.html.markdown
index c9bbfbaa..b047a6e7 100644
--- a/website/docs/r/domain.html.markdown
+++ b/website/docs/r/domain.html.markdown
@@ -143,7 +143,12 @@ resource "libvirt_domain" "my_machine" {
The `disk` block supports:
-* `volume_id` - (Required) The volume id to use for this disk.
+* `volume_id` - (Optional) The volume id to use for this disk.
+* `url` - (Optional) The http url to use as the block device for this disk (read-only)
+
+While both `volume_id` and `url` are optional, it is intended that you use either a volume or a
+url.
+
* `scsi` - (Optional) Use a scsi controller for this disk. The controller
model is set to `virtio-scsi`
* `wwn` - (Optional) Specify a WWN to use for the disk if the disk is using
@@ -167,6 +172,10 @@ resource "libvirt_domain" "domain1" {
volume_id = "${libvirt_volume.mydisk.id}"
scsi = "yes"
}
+
+ disk {
+ url = "http://foo.com/install.iso"
+ }
}
```