diff --git a/src/virtManager/connection.py b/src/virtManager/connection.py
index 27db578a9..a9409bd8d 100644
--- a/src/virtManager/connection.py
+++ b/src/virtManager/connection.py
@@ -1139,6 +1139,13 @@ class vmmConnection(gobject.GObject):
logging.debug("Connection doesn't seem to support storage "
"APIs. Skipping all storage polling.")
+ else:
+ # Try to create the default storage pool
+ try:
+ util.build_default_pool(self.vmm)
+ except Exception, e:
+ logging.debug("Building default pool failed: %s" % str(e))
+
if not self.storage_capable:
return (stopPools, startPools, origPools, newPools, currentPools)
@@ -1377,6 +1384,7 @@ class vmmConnection(gobject.GObject):
else:
# May be a new VM, we have no choice but
# to create the wrapper so we can see
+ # if its a previously inactive domain.
try:
vm = self.vmm.lookupByName(name)
uuid = util.uuidstr(vm.UUID())
@@ -1456,6 +1464,13 @@ class vmmConnection(gobject.GObject):
# Update VM states
for uuid in oldVMs:
self.emit("vm-removed", self.uri, uuid)
+
+ # This forces the backing virDomain to be deleted and
+ # unreferenced. Not forcing this seems to cause refcount
+ # issues, and if the user creates another domain with the
+ # same name, libvirt will return the original UUID when
+ # requested, causing confusion.
+ oldVMs[uuid].release_handle()
for uuid in newVMs:
self.emit("vm-added", self.uri, uuid)
for uuid in startVMs:
diff --git a/src/virtManager/create.py b/src/virtManager/create.py
index db5346d08..3701fcd98 100644
--- a/src/virtManager/create.py
+++ b/src/virtManager/create.py
@@ -22,7 +22,7 @@ import gobject
import gtk
import gtk.glade
-import os, sys, statvfs
+import sys
import time
import traceback
import threading
@@ -80,7 +80,6 @@ class vmmCreate(gobject.GObject):
self.capsguest = None
self.capsdomain = None
self.guest = None
- self.usepool = False
self.storage_browser = None
self.conn_signals = []
@@ -100,7 +99,6 @@ class vmmCreate(gobject.GObject):
# Host space polling
self.host_storage_timer = None
- self.host_storage = None
# 'Configure before install' window
self.config_window = None
@@ -289,13 +287,9 @@ class vmmCreate(gobject.GObject):
hyperList.add_attribute(text, 'sensitive', 3)
hyperList.set_model(hyperModel)
+ # Sparse tooltip
sparse_info = self.window.get_widget("config-storage-nosparse-info")
- sparse_str = _("Fully allocating storage will take longer now, "
- "but the OS install phase will be quicker. \n\n"
- "Skipping allocation can also cause space issues on "
- "the host machine, if the maximum image size exceeds "
- "available storage space.")
- util.tooltip_wrapper(sparse_info, sparse_str)
+ uihelpers.set_sparse_tooltip(sparse_info)
def reset_state(self, urihint=None):
@@ -348,9 +342,12 @@ class vmmCreate(gobject.GObject):
self.window.get_widget("config-cpus").set_value(1)
# Storage
+ label_widget = self.window.get_widget("phys-hd-label")
if not self.host_storage_timer:
self.host_storage_timer = util.safe_timeout_add(3 * 1000,
- self.host_space_tick)
+ uihelpers.host_space_tick,
+ self.conn, self.config,
+ label_widget)
self.window.get_widget("enable-storage").set_active(True)
self.window.get_widget("config-storage-create").set_active(True)
self.window.get_widget("config-storage-size").set_value(8)
@@ -450,16 +447,6 @@ class vmmCreate(gobject.GObject):
util.tooltip_wrapper(method_local, local_tt)
util.tooltip_wrapper(method_pxe, pxe_tt)
- # Attempt to create the default pool
- self.usepool = False
- try:
- if is_storage_capable:
- util.build_default_pool(self.conn.vmm)
- self.usepool = True
- except Exception, e:
- logging.debug("Building default pool failed: %s" % str(e))
-
-
# Install local
iso_option = self.window.get_widget("install-local-iso")
cdrom_option = self.window.get_widget("install-local-cdrom")
@@ -823,6 +810,14 @@ class vmmCreate(gobject.GObject):
return (media.strip(), extra.strip(), ks.strip())
+ def get_default_path(self, name):
+ # Don't generate a new path if the install failed
+ if self.failed_guest:
+ if len(self.failed_guest.disks) > 0:
+ return self.failed_guest.disks[0].path
+
+ return util.get_default_path(self.conn, self.config, name)
+
def is_default_storage(self):
return self.window.get_widget("config-storage-create").get_active()
@@ -838,96 +833,6 @@ class vmmCreate(gobject.GObject):
return (path, size, sparse)
- def get_default_pool(self):
- pool = None
- for uuid in self.conn.list_pool_uuids():
- p = self.conn.get_pool(uuid)
- if p.get_name() == util.DEFAULT_POOL_NAME:
- pool = p
-
- if not pool:
- raise RuntimeError(_("Did not find pool '%s'") %
- util.DEFAULT_POOL_NAME)
-
- return pool
-
- def get_ideal_path_info(self, name):
- pool = self.get_default_pool()
- suffix = ".img"
- return (pool.get_target_path(), name, suffix)
-
- def get_ideal_path(self, name):
- target, name, suffix = self.get_ideal_path_info(name)
- return os.path.join(target, name) + suffix
-
- def get_default_path(self, name):
- path = ""
-
- # Don't generate a new path if the install failed
- if self.failed_guest:
- if len(self.failed_guest.disks) > 0:
- return self.failed_guest.disks[0].path
-
- if not self.usepool:
- # Use old generating method
- d = self.config.get_default_image_dir(self.conn)
- origf = os.path.join(d, name + ".img")
- f = origf
-
- n = 1
- while os.path.exists(f) and n < 100:
- f = os.path.join(d, self.get_config_name() +
- "-" + str(n) + ".img")
- n += 1
- if os.path.exists(f):
- f = origf
-
- path = f
-
- else:
- pool = self.get_default_pool()
- target, ignore, suffix = self.get_ideal_path_info(name)
-
- path = virtinst.Storage.StorageVolume.find_free_name(name,
- pool_object=pool.pool, suffix=suffix)
-
- path = os.path.join(target, path)
-
- return path
-
- def host_disk_space(self, path=None):
- if not path:
- path = util.DEFAULT_POOL_PATH
-
- avail = 0
- if self.usepool:
- # FIXME: make sure not inactive?
- # FIXME: use a conn specific function after we send pool-added
- pool = virtinst.util.lookup_pool_by_path(self.conn.vmm, path)
- if pool:
- pool.refresh(0)
- avail = int(virtinst.util.get_xml_path(pool.XMLDesc(0),
- "/pool/available"))
-
- if not avail and not self.conn.is_remote():
- vfs = os.statvfs(os.path.dirname(path))
- avail = vfs[statvfs.F_FRSIZE] * vfs[statvfs.F_BAVAIL]
-
- return float(avail / 1024.0 / 1024.0 / 1024.0)
-
- def host_space_tick(self):
- max_storage = self.host_disk_space()
- if self.host_storage == max_storage:
- return 1
- self.host_storage = max_storage
-
- hd_label = ("%s available in the default location" %
- self.pretty_storage(max_storage))
- hd_label = ("%s" % hd_label)
- self.window.get_widget("phys-hd-label").set_markup(hd_label)
-
- return 1
-
def get_config_network_info(self):
netidx = self.window.get_widget("config-netdev").get_active()
netinfo = self.window.get_widget("config-netdev").get_model()[netidx]
@@ -1374,7 +1279,8 @@ class vmmCreate(gobject.GObject):
if self.is_default_storage() and not revalidate:
# See if the ideal disk path (/default/pool/vmname.img)
# exists, and if unused, prompt the use for using it
- ideal = self.get_ideal_path(self.guest.name)
+ ideal = util.get_ideal_path(self.conn, self.config,
+ self.guest.name)
do_exist = False
ret = True
diff --git a/src/virtManager/uihelpers.py b/src/virtManager/uihelpers.py
index ebde68d34..24bf1915d 100644
--- a/src/virtManager/uihelpers.py
+++ b/src/virtManager/uihelpers.py
@@ -20,12 +20,15 @@
import logging
import traceback
+import os, statvfs
import gtk
+import virtinst
from virtinst import VirtualNetworkInterface
from virtinst import VirtualDisk
+from virtManager import util
from virtManager.error import vmmErrorDialog
OPTICAL_DEV_PATH = 0
@@ -55,6 +58,51 @@ def set_error_parent(parent):
err_dial.set_parent(parent)
err_dial = err_dial
+############################################################
+# Helpers for shared storage UI between create/addhardware #
+############################################################
+
+def set_sparse_tooltip(widget):
+ sparse_str = _("Fully allocating storage will take longer now, "
+ "but the OS install phase will be quicker. \n\n"
+ "Skipping allocation can also cause space issues on "
+ "the host machine, if the maximum image size exceeds "
+ "available storage space.")
+ util.tooltip_wrapper(widget, sparse_str)
+
+def host_disk_space(conn, config):
+ pool = util.get_default_pool(conn)
+ path = util.get_default_dir(conn, config)
+
+ avail = 0
+ if pool:
+ # FIXME: make sure not inactive?
+ # FIXME: use a conn specific function after we send pool-added
+ pool = virtinst.util.lookup_pool_by_path(conn.vmm, path)
+ if pool:
+ pool.refresh(0)
+ avail = int(virtinst.util.get_xml_path(pool.XMLDesc(0),
+ "/pool/available"))
+
+ elif not conn.is_remote():
+ vfs = os.statvfs(os.path.dirname(path))
+ avail = vfs[statvfs.F_FRSIZE] * vfs[statvfs.F_BAVAIL]
+
+ return float(avail / 1024.0 / 1024.0 / 1024.0)
+
+def host_space_tick(conn, config, widget):
+ max_storage = host_disk_space(conn, config)
+
+ def pretty_storage(size):
+ return "%.1f Gb" % float(size)
+
+ hd_label = ("%s available in the default location" %
+ pretty_storage(max_storage))
+ hd_label = ("%s" % hd_label)
+ widget.set_markup(hd_label)
+
+ return 1
+
#######################################################################
# Widgets for listing network device options (in create, addhardware) #
diff --git a/src/virtManager/util.py b/src/virtManager/util.py
index 25b61ecf2..8bc190ac1 100644
--- a/src/virtManager/util.py
+++ b/src/virtManager/util.py
@@ -34,12 +34,15 @@ DEFAULT_POOL_NAME = "default"
DEFAULT_POOL_PATH = "/var/lib/libvirt/images"
def build_default_pool(conn):
- """Helper to build the 'default' storage pool"""
+ """
+ Helper to build the 'default' storage pool
+ """
# FIXME: This should use config.get_default_image_path ?
if not virtinst.util.is_storage_capable(conn):
# VirtualDisk will raise an error for us
return
+
pool = None
try:
pool = conn.storagePoolLookupByName(DEFAULT_POOL_NAME)
@@ -61,6 +64,63 @@ def build_default_pool(conn):
raise RuntimeError(_("Couldn't create default storage pool '%s': %s") %
(DEFAULT_POOL_PATH, str(e)))
+def get_ideal_path_info(conn, config, name):
+ path = get_default_dir(conn, config)
+ suffix = ".img"
+ return (path, name, suffix)
+
+def get_ideal_path(conn, config, name):
+ target, name, suffix = get_ideal_path_info(conn, config, name)
+ return os.path.join(target, name) + suffix
+
+def get_default_pool(conn):
+ pool = None
+ for uuid in conn.list_pool_uuids():
+ p = conn.get_pool(uuid)
+ if p.get_name() == DEFAULT_POOL_NAME:
+ pool = p
+
+ return pool
+
+def get_default_dir(conn, config):
+ pool = get_default_pool(conn)
+
+ if pool:
+ return pool.get_target_path()
+ else:
+ return config.get_default_image_dir(conn)
+
+def get_default_path(conn, config, name):
+ pool = get_default_pool(conn)
+
+ default_dir = get_default_dir(conn, config)
+
+ if not pool:
+ # Use old generating method
+ origf = os.path.join(default_dir, name + ".img")
+ f = origf
+
+ n = 1
+ while os.path.exists(f) and n < 100:
+ f = os.path.join(default_dir, name +
+ "-" + str(n) + ".img")
+ n += 1
+
+ if os.path.exists(f):
+ f = origf
+
+ path = f
+ else:
+ target, ignore, suffix = get_ideal_path_info(conn, config, name)
+
+ path = virtinst.Storage.StorageVolume.find_free_name(name,
+ pool_object=pool.pool, suffix=suffix)
+
+ path = os.path.join(target, path)
+
+ return path
+
+
def tooltip_wrapper(obj, txt, func="set_tooltip_text"):
# Catch & ignore errors - set_tooltip_* is in gtk >= 2.12
# and we can easily work with lower versions
@@ -334,3 +394,4 @@ def iface_in_use_by(conn, name):
use_str += iface.get_name()
return use_str
+