diff options
author | Flavio Castelli <fcastelli@suse.com> | 2016-10-08 20:49:07 +0200 |
---|---|---|
committer | Alvaro <alvaro.saurin@gmail.com> | 2016-10-10 17:43:08 +0200 |
commit | 89e78f356db8ef86ffa4ec42d5fcb38c14555b32 (patch) | |
tree | 740663d3d93cf6e4a84c4e75bcf556a569123d7e | |
parent | 6073b90b233f89394ca907f6579d9103965b1db1 (diff) | |
download | terraform-provider-libvirt-89e78f356db8ef86ffa4ec42d5fcb38c14555b32.tar terraform-provider-libvirt-89e78f356db8ef86ffa4ec42d5fcb38c14555b32.tar.gz |
Fix random issues when handling multiple cloudinit volumes
Sometimes the libvirt provider fails with cryptic messages when
multiple cloudinit volumes are being used.
libvirtd contains several messages like
`internal error: pool has asynchronous jobs running`. This seems to be
caused by invoking `pool.Refresh()` while a volume is being uploaded.
This commit introduces a new structure that can be used to synchronize
operations involving storage pools.
From my testing this solves the issues we have experiences so far.
-rw-r--r-- | libvirt/cloudinit_def.go | 5 | ||||
-rw-r--r-- | libvirt/pool_sync.go | 49 | ||||
-rw-r--r-- | libvirt/resource_libvirt_domain.go | 2 | ||||
-rw-r--r-- | libvirt/resource_libvirt_volume.go | 3 | ||||
-rw-r--r-- | libvirt/utils.go | 8 |
5 files changed, 66 insertions, 1 deletions
diff --git a/libvirt/cloudinit_def.go b/libvirt/cloudinit_def.go index da7e5f69..ea7c0dbe 100644 --- a/libvirt/cloudinit_def.go +++ b/libvirt/cloudinit_def.go @@ -58,6 +58,9 @@ func (ci *defCloudInit) CreateAndUpload(virConn *libvirt.VirConnection) (string, } defer pool.Free() + PoolSync.AcquireLock(ci.PoolName) + defer PoolSync.ReleaseLock(ci.PoolName) + // Refresh the pool of the volume so that libvirt knows it is // not longer in use. WaitForSuccess("Error refreshing pool for volume", func() error { @@ -161,7 +164,7 @@ func (ci *defCloudInit) createISO() (string, error) { if err = cmd.Run(); err != nil { return "", fmt.Errorf("Error while starting the creation of CloudInit's ISO image: %s", err) } - log.Print("ISO created at %s", isoDestination) + log.Printf("ISO created at %s", isoDestination) return isoDestination, nil } diff --git a/libvirt/pool_sync.go b/libvirt/pool_sync.go new file mode 100644 index 00000000..8c53ac05 --- /dev/null +++ b/libvirt/pool_sync.go @@ -0,0 +1,49 @@ +package libvirt + +import ( + "sync" +) + +// LibVirtPoolSync 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 LibVirtPoolSync struct { + PoolLocks map[string]*sync.Mutex + internalMutex sync.Mutex +} + +// Allocate a new instance of LibVirtPoolSync +func NewLibVirtPoolSync() LibVirtPoolSync { + pool := LibVirtPoolSync{} + pool.PoolLocks = make(map[string]*sync.Mutex) + + return pool +} + +// Acquire a lock for the specified pool +func (ps LibVirtPoolSync) 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() +} + +// Release the look for the specified pool +func (ps LibVirtPoolSync) ReleaseLock(pool string) { + ps.internalMutex.Lock() + defer ps.internalMutex.Unlock() + + lock, exists := ps.PoolLocks[pool] + if !exists { + return + } + + lock.Unlock() +} diff --git a/libvirt/resource_libvirt_domain.go b/libvirt/resource_libvirt_domain.go index 728c10ca..e7c86e10 100644 --- a/libvirt/resource_libvirt_domain.go +++ b/libvirt/resource_libvirt_domain.go @@ -14,6 +14,8 @@ import ( "github.com/hashicorp/terraform/helper/schema" ) +var PoolSync = NewLibVirtPoolSync() + func init() { spew.Config.Indent = "\t" } diff --git a/libvirt/resource_libvirt_volume.go b/libvirt/resource_libvirt_volume.go index 1e2de8a9..3f84b34c 100644 --- a/libvirt/resource_libvirt_volume.go +++ b/libvirt/resource_libvirt_volume.go @@ -181,6 +181,9 @@ func resourceLibvirtVolumeCreate(d *schema.ResourceData, meta interface{}) error poolName = d.Get("pool").(string) } + PoolSync.AcquireLock(poolName) + defer PoolSync.ReleaseLock(poolName) + pool, err := virConn.LookupStoragePoolByName(poolName) if err != nil { return fmt.Errorf("can't find storage pool '%s'", poolName) diff --git a/libvirt/utils.go b/libvirt/utils.go index a4110904..0700b756 100644 --- a/libvirt/utils.go +++ b/libvirt/utils.go @@ -70,6 +70,14 @@ func RemoveVolume(virConn *libvirt.VirConnection, key string) error { } defer volPool.Free() + poolName, err := volPool.GetName() + if err != nil { + return fmt.Errorf("Error retrieving name of volume: %s", err) + } + + PoolSync.AcquireLock(poolName) + defer PoolSync.ReleaseLock(poolName) + WaitForSuccess("Error refreshing pool for volume", func() error { return volPool.Refresh(0) }) |