create: Break out storage helpers for use in addhw

This commit is contained in:
Cole Robinson 2010-03-04 15:31:33 -05:00
parent d9759e6c9b
commit 4d4f34e596
4 changed files with 142 additions and 112 deletions

View File

@ -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:

View File

@ -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 = ("<span color='#484848'>%s</span>" % 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

View File

@ -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 = ("<span color='#484848'>%s</span>" % hd_label)
widget.set_markup(hd_label)
return 1
#######################################################################
# Widgets for listing network device options (in create, addhardware) #

View File

@ -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