aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEamonn O'Toole <eamonn.otoole@hpe.com>2017-03-16 16:12:22 +0000
committerAlvaro <alvaro.saurin@gmail.com>2017-03-22 12:19:05 +0100
commita07e21b74726d9ce443ac9332417c169b2ccd708 (patch)
treecf8e1bee9cc6ed8c4fa37b56440615397f953c91
parent68630335a6c23ab544661b8ef9c6692df886fd7d (diff)
downloadterraform-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.markdown5
-rw-r--r--libvirt/disk_def.go15
-rw-r--r--libvirt/domain_def.go6
-rw-r--r--libvirt/resource_libvirt_domain.go16
-rw-r--r--libvirt/resource_libvirt_domain_test.go59
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
+ }
+}