create: Break out storage helpers for use in addhw
This commit is contained in:
parent
d9759e6c9b
commit
4d4f34e596
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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) #
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue