diff options
author | Eamonn O'Toole <eamonn.otoole@hpe.com> | 2017-03-16 16:12:22 +0000 |
---|---|---|
committer | Alvaro <alvaro.saurin@gmail.com> | 2017-03-22 12:19:05 +0100 |
commit | a07e21b74726d9ce443ac9332417c169b2ccd708 (patch) | |
tree | cf8e1bee9cc6ed8c4fa37b56440615397f953c91 | |
parent | 68630335a6c23ab544661b8ef9c6692df886fd7d (diff) | |
download | terraform-provider-libvirt-a07e21b74726d9ce443ac9332417c169b2ccd708.tar terraform-provider-libvirt-a07e21b74726d9ce443ac9332417c169b2ccd708.tar.gz |
Add scsi controller option and wwn to virtual disks
We've added the facility to define a disk bus type of scsi to the
specification of a disk in the domain definition. If the disk is
a scsi disk, a random wwn is generated unless a wwn is provided for
that disk.
The disk stanza now looks as follows:
disk {
volume_id = "${libvirt_volume.mydisk.id}"
scsi = "yes"
wwn = "05abcd123456789a"
}
Having "scsi" present with any value will specify a scsi bus for
the disk. If "wwn" is present for a scsci disk then the value of
"wwn" is used for the disk wwn, otherwise a random value is generated.
-rw-r--r-- | docs/providers/libvirt/r/domain.html.markdown | 5 | ||||
-rw-r--r-- | libvirt/disk_def.go | 15 | ||||
-rw-r--r-- | libvirt/domain_def.go | 6 | ||||
-rw-r--r-- | libvirt/resource_libvirt_domain.go | 16 | ||||
-rw-r--r-- | libvirt/resource_libvirt_domain_test.go | 59 |
5 files changed, 101 insertions, 0 deletions
diff --git a/docs/providers/libvirt/r/domain.html.markdown b/docs/providers/libvirt/r/domain.html.markdown index 99948e39..af3d7247 100644 --- a/docs/providers/libvirt/r/domain.html.markdown +++ b/docs/providers/libvirt/r/domain.html.markdown @@ -109,6 +109,10 @@ nvram = [ The `disk` block supports: * `volume_id` - (Required) The volume id to use for this disk. +* `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 +a scsi controller, if not specified then a random wwn is generated for the disk If you have a volume with a template image, create a second volume using the image as the backing volume, and then use the new volume as the volume for the disk. This way the image will not be modified. @@ -127,6 +131,7 @@ resource "libvirt_domain" "domain1" { name = "domain1" disk { volume_id = "${libvirt_volume.mydisk.id}" + scsi = "yes" } network_interface { diff --git a/libvirt/disk_def.go b/libvirt/disk_def.go index b0a4a5b3..737364c3 100644 --- a/libvirt/disk_def.go +++ b/libvirt/disk_def.go @@ -2,12 +2,17 @@ package libvirt import ( "encoding/xml" + "math/rand" + "time" ) +const OUI = "05abcd" + type defDisk struct { XMLName xml.Name `xml:"disk"` Type string `xml:"type,attr"` Device string `xml:"device,attr"` + Wwn string `xml:"wwn,omitempty"` Format struct { Type string `xml:"type,attr"` } `xml:"format"` @@ -50,3 +55,13 @@ func newCDROM() defDisk { return disk } + +func randomWWN(strlen int) string { + const chars = "abcdef0123456789" + rand.Seed(time.Now().UTC().UnixNano()) + result := make([]byte, strlen) + for i := 0; i < strlen; i++ { + result[i] = chars[rand.Intn(len(chars))] + } + return OUI + string(result) +} diff --git a/libvirt/domain_def.go b/libvirt/domain_def.go index 306286ed..65425fd7 100644 --- a/libvirt/domain_def.go +++ b/libvirt/domain_def.go @@ -23,6 +23,7 @@ type defDomain struct { Pae string `xml:"pae"` } `xml:"features"` Devices struct { + Controller []defController `xml:"controller,omitempty"` Disks []defDisk `xml:"disk"` NetworkInterfaces []defNetworkInterface `xml:"interface"` Console []defConsole `xml:"console"` @@ -102,6 +103,11 @@ type defNvRam struct { File string `xml:",chardata"` } +type defController struct { + Type string `xml:"type,attr,omitempty"` + Model string `xml:"model,attr,omitempty"` +} + type defConsole struct { Type string `xml:"type,attr"` Source struct { diff --git a/libvirt/resource_libvirt_domain.go b/libvirt/resource_libvirt_domain.go index 3cf42740..1ac3cc86 100644 --- a/libvirt/resource_libvirt_domain.go +++ b/libvirt/resource_libvirt_domain.go @@ -258,6 +258,7 @@ func resourceLibvirtDomainCreate(d *schema.ResourceData, meta interface{}) error disksCount := d.Get("disk.#").(int) var disks []defDisk + var scsiDisk bool = false for i := 0; i < disksCount; i++ { disk := newDefDisk() disk.Target.Dev = fmt.Sprintf("vd%s", DiskLetterForIndex(i)) @@ -265,6 +266,15 @@ 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 + if wwn, ok := diskMap["wwn"].(string); ok { + disk.Wwn = wwn + } else { + disk.Wwn = randomWWN(10) + } + } diskVolume, err := virConn.LookupStorageVolByKey(volumeKey) if err != nil { return fmt.Errorf("Can't retrieve volume %s", volumeKey) @@ -288,6 +298,12 @@ func resourceLibvirtDomainCreate(d *schema.ResourceData, meta interface{}) error disks = append(disks, disk) } + log.Printf("[DEBUG] scsiDisk: %s", scsiDisk) + if scsiDisk { + controller := defController{Type:"scsi", Model:"virtio-scsi"} + domainDef.Devices.Controller = append(domainDef.Devices.Controller, controller) + } + type pendingMapping struct { mac string hostname string diff --git a/libvirt/resource_libvirt_domain_test.go b/libvirt/resource_libvirt_domain_test.go index b27df0e4..44606e16 100644 --- a/libvirt/resource_libvirt_domain_test.go +++ b/libvirt/resource_libvirt_domain_test.go @@ -167,6 +167,39 @@ func TestAccLibvirtDomain_VolumeTwoDisks(t *testing.T) { }) } +func TestAccLibvirtDomain_ScsiDisk(t *testing.T) { + var domain libvirt.VirDomain + var configScsi = fmt.Sprintf(` + resource "libvirt_volume" "acceptance-test-volume1" { + name = "terraform-test-vol1" + } + + resource "libvirt_domain" "acceptance-test-domain" { + name = "terraform-test-domain" + disk { + volume_id = "${libvirt_volume.acceptance-test-volume1.id}" + scsi = "yes" + wwn = "000000123456789a" + } + }`) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckLibvirtDomainDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: configScsi, + Check: resource.ComposeTestCheckFunc( + testAccCheckLibvirtDomainExists("libvirt_domain.acceptance-test-domain", &domain), + testAccCheckLibvirtScsiDisk("000000123456789a", &domain), + ), + }, + }, + }) + +} + func TestAccLibvirtDomain_NetworkInterface(t *testing.T) { var domain libvirt.VirDomain @@ -383,3 +416,29 @@ func TestHash(t *testing.T) { t.Errorf("Expected %s, got %s", expected, actual) } } + +func testAccCheckLibvirtScsiDisk(n string, domain *libvirt.VirDomain) 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 diskBus := disk.Target.Bus; diskBus != "scsi" { + return fmt.Errorf("Disk bus is not scsi") + } + if wwn := disk.Wwn; wwn != n { + return fmt.Errorf("Disk wwn %s is not equal to %s", wwn, n) + } + } + return nil + } +} |