diff options
author | Duncan Mac-Vicar P <dmacvicar@gmail.com> | 2017-11-21 11:41:02 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-11-21 11:41:02 +0100 |
commit | d7fe1a2a37a8373ac261b1e3025efba27bfab2d6 (patch) | |
tree | 0fe385d5b26869a6706fde0662366706324c9a49 | |
parent | 3a52429e58643dad0e6122f3fb47b61be2ba2c72 (diff) | |
parent | 49dadde97886f31fd32b220e1918c5025c6c317e (diff) | |
download | terraform-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.go | 4 | ||||
-rw-r--r-- | libvirt/disk_def_test.go | 2 | ||||
-rw-r--r-- | libvirt/resource_libvirt_domain.go | 124 | ||||
-rw-r--r-- | libvirt/resource_libvirt_domain_test.go | 68 | ||||
-rw-r--r-- | website/docs/r/domain.html.markdown | 11 |
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" + } } ``` |