aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--.travis.yml1
-rw-r--r--Makefile2
-rw-r--r--libvirt/cloudinit_def.go6
-rw-r--r--libvirt/cloudinit_def_test.go83
-rw-r--r--libvirt/coreos_ignition_def.go4
-rw-r--r--libvirt/disk_def.go4
-rw-r--r--libvirt/disk_def_test.go2
-rw-r--r--libvirt/network_def.go2
-rw-r--r--libvirt/pool_sync.go49
-rw-r--r--libvirt/pool_sync_test.go46
-rw-r--r--libvirt/provider.go4
-rw-r--r--libvirt/qemu_agent.go2
-rw-r--r--libvirt/resource_libvirt_domain.go133
-rw-r--r--libvirt/resource_libvirt_domain_test.go68
-rw-r--r--libvirt/resource_libvirt_volume.go8
-rw-r--r--libvirt/utils.go4
-rw-r--r--libvirt/utils_volume.go3
-rwxr-xr-xtravis/setup-guest2
-rw-r--r--website/docs/r/domain.html.markdown11
20 files changed, 271 insertions, 165 deletions
diff --git a/.gitignore b/.gitignore
index c3879151..f3879e37 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,8 @@
./terraform-provider-libvirt
+.terraform/*
./*.tf
*.tfstate
*.tfstate.backup
*.test
*.cov
+terraform-provider-libvirt
diff --git a/.travis.yml b/.travis.yml
index ab45ae97..1048239f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,6 +12,7 @@ before_script:
- sudo lxc exec libvirt -- bash /code/travis/setup-guest
script:
- bash ./travis/gofmtcheck.sh
+ - make vet
- golint -set_exit_status libvirt/
- sudo lxc exec libvirt -- bash /code/travis/run-tests-inside-guest
- sudo lxc file pull libvirt/root/go/src/github.com/dmacvicar/terraform-provider-libvirt/profile.cov .
diff --git a/Makefile b/Makefile
index fea63149..72b45f91 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
default: build
-build: gofmtcheck
+build: gofmtcheck golint vet
go build
install:
diff --git a/libvirt/cloudinit_def.go b/libvirt/cloudinit_def.go
index fb148b75..91b73514 100644
--- a/libvirt/cloudinit_def.go
+++ b/libvirt/cloudinit_def.go
@@ -65,8 +65,8 @@ func (ci *defCloudInit) CreateAndUpload(virConn *libvirt.Connect) (string, error
}
defer pool.Free()
- PoolSync.AcquireLock(ci.PoolName)
- defer PoolSync.ReleaseLock(ci.PoolName)
+ poolMutexKV.Lock(ci.PoolName)
+ defer poolMutexKV.Unlock(ci.PoolName)
// Refresh the pool of the volume so that libvirt knows it is
// not longer in use.
@@ -160,7 +160,7 @@ func (ci *defCloudInit) createISO() (string, error) {
filepath.Join(tmpDir, USERDATA),
filepath.Join(tmpDir, METADATA))
- log.Print("About to execute cmd: %+v", cmd)
+ log.Printf("About to execute cmd: %+v", cmd)
if err = cmd.Run(); err != nil {
return "", fmt.Errorf("Error while starting the creation of CloudInit's ISO image: %s", err)
}
diff --git a/libvirt/cloudinit_def_test.go b/libvirt/cloudinit_def_test.go
index ab01f4e7..c2202a75 100644
--- a/libvirt/cloudinit_def_test.go
+++ b/libvirt/cloudinit_def_test.go
@@ -1,12 +1,16 @@
package libvirt
import (
+ "fmt"
+ "github.com/hashicorp/terraform/helper/resource"
+ "github.com/hashicorp/terraform/terraform"
+ libvirt "github.com/libvirt/libvirt-go"
+ "gopkg.in/yaml.v2"
"os"
"path/filepath"
+ "regexp"
"strings"
"testing"
-
- "gopkg.in/yaml.v2"
)
func TestNewCloudInitDef(t *testing.T) {
@@ -161,6 +165,81 @@ ssh_authorized_keys:
}
}
+func TestCreateCloudIsoViaPlugin(t *testing.T) {
+ var volume libvirt.StorageVol
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ Providers: testAccProviders,
+ CheckDestroy: func(s *terraform.State) error {
+ return nil
+ },
+ Steps: []resource.TestStep{
+ {
+ Config: fmt.Sprintf(`
+ resource "libvirt_cloudinit" "test" {
+ name = "test.iso"
+ local_hostname = "tango1"
+ pool = "default"
+ user_data = "#cloud-config\nssh_authorized_keys: []\n"
+ }`),
+
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(
+ "libvirt_cloudinit.test", "name", "test.iso"),
+ resource.TestCheckResourceAttr(
+ "libvirt_cloudinit.test", "local_hostname", "tango1"),
+ testAccCheckCloudInitVolumeExists("libvirt_cloudinit.test", &volume),
+ ),
+ },
+ // 2nd tests Invalid userdata
+ {
+ Config: fmt.Sprintf(`
+ resource "libvirt_cloudinit" "test" {
+ name = "commoninit2.iso"
+ local_hostname = "samba2"
+ pool = "default"
+ user_data = "invalidgino"
+ }`),
+ ExpectError: regexp.MustCompile("Error merging UserData with UserDataRaw: yaml: unmarshal errors"),
+ },
+ },
+ })
+}
+
+func testAccCheckCloudInitVolumeExists(n string, volume *libvirt.StorageVol) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ virConn := testAccProvider.Meta().(*Client).libvirt
+
+ rs, ok := s.RootModule().Resources[n]
+ if !ok {
+ return fmt.Errorf("Not found: %s", n)
+ }
+
+ if rs.Primary.ID == "" {
+ return fmt.Errorf("No libvirt volume key ID is set")
+ }
+
+ cikey, err := getCloudInitVolumeKeyFromTerraformID(rs.Primary.ID)
+ retrievedVol, err := virConn.LookupStorageVolByKey(cikey)
+ if err != nil {
+ return err
+ }
+ realID, err := retrievedVol.GetKey()
+ if err != nil {
+ return err
+ }
+
+ if realID != cikey {
+ fmt.Printf("realID is: %s \ncloudinit key is %s", realID, cikey)
+ return fmt.Errorf("Resource ID and cloudinit volume key does not match")
+ }
+
+ *volume = *retrievedVol
+
+ return nil
+ }
+}
+
func exists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
diff --git a/libvirt/coreos_ignition_def.go b/libvirt/coreos_ignition_def.go
index 4e77b199..bef01d63 100644
--- a/libvirt/coreos_ignition_def.go
+++ b/libvirt/coreos_ignition_def.go
@@ -38,8 +38,8 @@ func (ign *defIgnition) CreateAndUpload(virConn *libvirt.Connect) (string, error
}
defer pool.Free()
- PoolSync.AcquireLock(ign.PoolName)
- defer PoolSync.ReleaseLock(ign.PoolName)
+ poolMutexKV.Lock(ign.PoolName)
+ defer poolMutexKV.Unlock(ign.PoolName)
// Refresh the pool of the volume so that libvirt knows it is
// not longer in use.
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/network_def.go b/libvirt/network_def.go
index 77ead849..c53f2896 100644
--- a/libvirt/network_def.go
+++ b/libvirt/network_def.go
@@ -52,7 +52,7 @@ func newNetworkDef() libvirtxml.Network {
</forward>
</network>`
if d, err := newDefNetworkFromXML(defNetworkXML); err != nil {
- panic(fmt.Sprint("Unexpected error while parsing default network definition: %s", err))
+ panic(fmt.Sprintf("Unexpected error while parsing default network definition: %s", err))
} else {
return d
}
diff --git a/libvirt/pool_sync.go b/libvirt/pool_sync.go
deleted file mode 100644
index a50528bc..00000000
--- a/libvirt/pool_sync.go
+++ /dev/null
@@ -1,49 +0,0 @@
-package libvirt
-
-import (
- "sync"
-)
-
-// LVirtPoolSync makes possible to synchronize operations
-// against libvirt pools.
-// Doing pool.Refresh() operations while uploading or removing
-// a volume into the pool causes errors inside of libvirtd
-type LVirtPoolSync struct {
- PoolLocks map[string]*sync.Mutex
- internalMutex sync.Mutex
-}
-
-// NewLVirtPoolSync allocates a new instance of LVirtPoolSync
-func NewLVirtPoolSync() LVirtPoolSync {
- pool := LVirtPoolSync{}
- pool.PoolLocks = make(map[string]*sync.Mutex)
-
- return pool
-}
-
-// AcquireLock acquires a lock for the specified pool
-func (ps LVirtPoolSync) AcquireLock(pool string) {
- ps.internalMutex.Lock()
- defer ps.internalMutex.Unlock()
-
- lock, exists := ps.PoolLocks[pool]
- if !exists {
- lock = new(sync.Mutex)
- ps.PoolLocks[pool] = lock
- }
-
- lock.Lock()
-}
-
-// ReleaseLock releases the look for the specified pool
-func (ps LVirtPoolSync) ReleaseLock(pool string) {
- ps.internalMutex.Lock()
- defer ps.internalMutex.Unlock()
-
- lock, exists := ps.PoolLocks[pool]
- if !exists {
- return
- }
-
- lock.Unlock()
-}
diff --git a/libvirt/pool_sync_test.go b/libvirt/pool_sync_test.go
deleted file mode 100644
index 90ad4849..00000000
--- a/libvirt/pool_sync_test.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package libvirt
-
-import (
- "testing"
-)
-
-func TestAcquireLock(t *testing.T) {
- ps := NewLVirtPoolSync()
-
- ps.AcquireLock("test")
-
- _, found := ps.PoolLocks["test"]
-
- if !found {
- t.Errorf("lock not found")
- }
-}
-
-func TestReleaseLock(t *testing.T) {
- ps := NewLVirtPoolSync()
-
- ps.AcquireLock("test")
-
- _, found := ps.PoolLocks["test"]
- if !found {
- t.Errorf("lock not found")
- }
-
- ps.ReleaseLock("test")
- _, found = ps.PoolLocks["test"]
- if !found {
- t.Errorf("lock not found")
- }
-}
-
-func TestReleaseNotExistingLock(t *testing.T) {
- ps := NewLVirtPoolSync()
-
- ps.ReleaseLock("test")
- _, found := ps.PoolLocks["test"]
- if found {
- t.Errorf("lock found")
- }
- // moreover there should be no runtime error because
- // we are not trying to unlock a not-locked mutex
-}
diff --git a/libvirt/provider.go b/libvirt/provider.go
index 2cdb3cb3..07b0c72e 100644
--- a/libvirt/provider.go
+++ b/libvirt/provider.go
@@ -1,10 +1,14 @@
package libvirt
import (
+ "github.com/hashicorp/terraform/helper/mutexkv"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform"
)
+// Global poolMutexKV
+var poolMutexKV = mutexkv.NewMutexKV()
+
// Provider libvirt
func Provider() terraform.ResourceProvider {
return &schema.Provider{
diff --git a/libvirt/qemu_agent.go b/libvirt/qemu_agent.go
index 82e76685..b884f7c4 100644
--- a/libvirt/qemu_agent.go
+++ b/libvirt/qemu_agent.go
@@ -50,7 +50,7 @@ func getDomainInterfacesViaQemuAgent(domain Domain, wait4ipv4 bool) []libvirt.Do
response := QemuAgentInterfacesResponse{}
if err := json.Unmarshal([]byte(result), &response); err != nil {
log.Printf("[DEBUG] Error converting Qemu agent response about domain interfaces: %s", err)
- log.Printf("[DEBUG] Original message: %s", response)
+ log.Printf("[DEBUG] Original message: %v", response)
log.Print("[DEBUG] Returning an empty list of interfaces")
return interfaces
}
diff --git a/libvirt/resource_libvirt_domain.go b/libvirt/resource_libvirt_domain.go
index 6e8830b4..a3b16792 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"
@@ -25,9 +26,6 @@ type DomainMeta struct {
ifaces chan libvirtxml.DomainInterface
}
-// PoolSync exported pool sync
-var PoolSync = NewLVirtPoolSync()
-
func init() {
spew.Config.Indent = "\t"
}
@@ -232,8 +230,8 @@ func resourceLibvirtDomainCreate(d *schema.ResourceData, meta interface{}) error
return err
}
ignStr := fmt.Sprintf("name=opt/com.coreos/config,file=%s", ignitionKey)
- fwCfg = append(fwCfg, libvirtxml.DomainQEMUCommandlineArg{"-fw_cfg"})
- fwCfg = append(fwCfg, libvirtxml.DomainQEMUCommandlineArg{ignStr})
+ fwCfg = append(fwCfg, libvirtxml.DomainQEMUCommandlineArg{Value: "-fw_cfg"})
+ fwCfg = append(fwCfg, libvirtxml.DomainQEMUCommandlineArg{Value: ignStr})
QemuCmdline := &libvirtxml.DomainQEMUCommandline{
Args: fwCfg,
}
@@ -367,22 +365,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,23 +378,53 @@ 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)
}
- log.Printf("[DEBUG] scsiDisk: %s", scsiDisk)
+ log.Printf("[DEBUG] scsiDisk: %t", scsiDisk)
if scsiDisk {
controller := libvirtxml.DomainController{Type: "scsi", Model: "virtio-scsi"}
domainDef.Devices.Controllers = append(domainDef.Devices.Controllers, controller)
@@ -870,33 +886,52 @@ func resourceLibvirtDomainRead(d *schema.ResourceData, meta interface{}) error {
var disks []map[string]interface{}
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)
var filesystems []map[string]interface{}
diff --git a/libvirt/resource_libvirt_domain_test.go b/libvirt/resource_libvirt_domain_test.go
index 5ea3af0b..2c9f1b52 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/libvirt/resource_libvirt_volume.go b/libvirt/resource_libvirt_volume.go
index 8d75b744..7a7f6a40 100644
--- a/libvirt/resource_libvirt_volume.go
+++ b/libvirt/resource_libvirt_volume.go
@@ -90,8 +90,8 @@ func resourceLibvirtVolumeCreate(d *schema.ResourceData, meta interface{}) error
poolName = d.Get("pool").(string)
}
- PoolSync.AcquireLock(poolName)
- defer PoolSync.ReleaseLock(poolName)
+ poolMutexKV.Lock(poolName)
+ defer poolMutexKV.Unlock(poolName)
pool, err := virConn.LookupStoragePoolByName(poolName)
if err != nil {
@@ -271,10 +271,10 @@ func resourceLibvirtVolumeRead(d *schema.ResourceData, meta interface{}) error {
if virErr.Code != libvirt.ERR_NO_STORAGE_VOL {
return fmt.Errorf("Can't retrieve volume %s", d.Id())
}
+ volID := d.Id()
- log.Printf("[INFO] Volume %s not found, attempting to start its pool")
+ log.Printf("[INFO] Volume %s not found, attempting to start its pool", d.Id())
- volID := d.Id()
volPoolName := d.Get("pool").(string)
volPool, err := virConn.LookupStoragePoolByName(volPoolName)
if err != nil {
diff --git a/libvirt/utils.go b/libvirt/utils.go
index a82417fb..13a34312 100644
--- a/libvirt/utils.go
+++ b/libvirt/utils.go
@@ -85,8 +85,8 @@ func RemoveVolume(virConn *libvirt.Connect, key string) error {
return fmt.Errorf("Error retrieving name of volume: %s", err)
}
- PoolSync.AcquireLock(poolName)
- defer PoolSync.ReleaseLock(poolName)
+ poolMutexKV.Lock(poolName)
+ defer poolMutexKV.Unlock(poolName)
WaitForSuccess("Error refreshing pool for volume", func() error {
return volPool.Refresh(0)
diff --git a/libvirt/utils_volume.go b/libvirt/utils_volume.go
index 457bacb9..03c99180 100644
--- a/libvirt/utils_volume.go
+++ b/libvirt/utils_volume.go
@@ -106,11 +106,12 @@ func (i *httpImage) Import(copier func(io.Reader) error, vol libvirtxml.StorageV
req.Header.Set("If-Modified-Since", timeFromEpoch(vol.Target.Timestamps.Mtime).UTC().Format(http.TimeFormat))
}
response, err := client.Do(req)
- defer response.Body.Close()
if err != nil {
return fmt.Errorf("Error while downloading %s: %s", i.url.String(), err)
}
+
+ defer response.Body.Close()
if response.StatusCode == http.StatusNotModified {
return nil
}
diff --git a/travis/setup-guest b/travis/setup-guest
index 71562655..42568e81 100755
--- a/travis/setup-guest
+++ b/travis/setup-guest
@@ -14,7 +14,7 @@ done
add-apt-repository -y ppa:gophers/archive
apt-get -qq update
-apt-get install -y qemu libvirt-bin libvirt-dev golang-1.9 ovmf
+apt-get install -y qemu libvirt-bin libvirt-dev golang-1.9 ovmf genisoimage
echo -e "<pool type='dir'>\n<name>default</name>\n<target>\n<path>/pool-default</path>\n</target>\n</pool>" > pool.xml
mkdir /pool-default
chmod a+rwx /pool-default
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"
+ }
}
```