mirror of
https://github.com/virt-manager/virt-manager.git
synced 2025-02-25 18:55:27 -06:00
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 "
|
logging.debug("Connection doesn't seem to support storage "
|
||||||
"APIs. Skipping all storage polling.")
|
"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:
|
if not self.storage_capable:
|
||||||
return (stopPools, startPools, origPools, newPools, currentPools)
|
return (stopPools, startPools, origPools, newPools, currentPools)
|
||||||
|
|
||||||
@ -1377,6 +1384,7 @@ class vmmConnection(gobject.GObject):
|
|||||||
else:
|
else:
|
||||||
# May be a new VM, we have no choice but
|
# May be a new VM, we have no choice but
|
||||||
# to create the wrapper so we can see
|
# to create the wrapper so we can see
|
||||||
|
# if its a previously inactive domain.
|
||||||
try:
|
try:
|
||||||
vm = self.vmm.lookupByName(name)
|
vm = self.vmm.lookupByName(name)
|
||||||
uuid = util.uuidstr(vm.UUID())
|
uuid = util.uuidstr(vm.UUID())
|
||||||
@ -1456,6 +1464,13 @@ class vmmConnection(gobject.GObject):
|
|||||||
# Update VM states
|
# Update VM states
|
||||||
for uuid in oldVMs:
|
for uuid in oldVMs:
|
||||||
self.emit("vm-removed", self.uri, uuid)
|
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:
|
for uuid in newVMs:
|
||||||
self.emit("vm-added", self.uri, uuid)
|
self.emit("vm-added", self.uri, uuid)
|
||||||
for uuid in startVMs:
|
for uuid in startVMs:
|
||||||
|
@ -22,7 +22,7 @@ import gobject
|
|||||||
import gtk
|
import gtk
|
||||||
import gtk.glade
|
import gtk.glade
|
||||||
|
|
||||||
import os, sys, statvfs
|
import sys
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
import threading
|
import threading
|
||||||
@ -80,7 +80,6 @@ class vmmCreate(gobject.GObject):
|
|||||||
self.capsguest = None
|
self.capsguest = None
|
||||||
self.capsdomain = None
|
self.capsdomain = None
|
||||||
self.guest = None
|
self.guest = None
|
||||||
self.usepool = False
|
|
||||||
self.storage_browser = None
|
self.storage_browser = None
|
||||||
self.conn_signals = []
|
self.conn_signals = []
|
||||||
|
|
||||||
@ -100,7 +99,6 @@ class vmmCreate(gobject.GObject):
|
|||||||
|
|
||||||
# Host space polling
|
# Host space polling
|
||||||
self.host_storage_timer = None
|
self.host_storage_timer = None
|
||||||
self.host_storage = None
|
|
||||||
|
|
||||||
# 'Configure before install' window
|
# 'Configure before install' window
|
||||||
self.config_window = None
|
self.config_window = None
|
||||||
@ -289,13 +287,9 @@ class vmmCreate(gobject.GObject):
|
|||||||
hyperList.add_attribute(text, 'sensitive', 3)
|
hyperList.add_attribute(text, 'sensitive', 3)
|
||||||
hyperList.set_model(hyperModel)
|
hyperList.set_model(hyperModel)
|
||||||
|
|
||||||
|
# Sparse tooltip
|
||||||
sparse_info = self.window.get_widget("config-storage-nosparse-info")
|
sparse_info = self.window.get_widget("config-storage-nosparse-info")
|
||||||
sparse_str = _("Fully allocating storage will take longer now, "
|
uihelpers.set_sparse_tooltip(sparse_info)
|
||||||
"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)
|
|
||||||
|
|
||||||
def reset_state(self, urihint=None):
|
def reset_state(self, urihint=None):
|
||||||
|
|
||||||
@ -348,9 +342,12 @@ class vmmCreate(gobject.GObject):
|
|||||||
self.window.get_widget("config-cpus").set_value(1)
|
self.window.get_widget("config-cpus").set_value(1)
|
||||||
|
|
||||||
# Storage
|
# Storage
|
||||||
|
label_widget = self.window.get_widget("phys-hd-label")
|
||||||
if not self.host_storage_timer:
|
if not self.host_storage_timer:
|
||||||
self.host_storage_timer = util.safe_timeout_add(3 * 1000,
|
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("enable-storage").set_active(True)
|
||||||
self.window.get_widget("config-storage-create").set_active(True)
|
self.window.get_widget("config-storage-create").set_active(True)
|
||||||
self.window.get_widget("config-storage-size").set_value(8)
|
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_local, local_tt)
|
||||||
util.tooltip_wrapper(method_pxe, pxe_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
|
# Install local
|
||||||
iso_option = self.window.get_widget("install-local-iso")
|
iso_option = self.window.get_widget("install-local-iso")
|
||||||
cdrom_option = self.window.get_widget("install-local-cdrom")
|
cdrom_option = self.window.get_widget("install-local-cdrom")
|
||||||
@ -823,6 +810,14 @@ class vmmCreate(gobject.GObject):
|
|||||||
|
|
||||||
return (media.strip(), extra.strip(), ks.strip())
|
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):
|
def is_default_storage(self):
|
||||||
return self.window.get_widget("config-storage-create").get_active()
|
return self.window.get_widget("config-storage-create").get_active()
|
||||||
|
|
||||||
@ -838,96 +833,6 @@ class vmmCreate(gobject.GObject):
|
|||||||
|
|
||||||
return (path, size, sparse)
|
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):
|
def get_config_network_info(self):
|
||||||
netidx = self.window.get_widget("config-netdev").get_active()
|
netidx = self.window.get_widget("config-netdev").get_active()
|
||||||
netinfo = self.window.get_widget("config-netdev").get_model()[netidx]
|
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:
|
if self.is_default_storage() and not revalidate:
|
||||||
# See if the ideal disk path (/default/pool/vmname.img)
|
# See if the ideal disk path (/default/pool/vmname.img)
|
||||||
# exists, and if unused, prompt the use for using it
|
# 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
|
do_exist = False
|
||||||
ret = True
|
ret = True
|
||||||
|
|
||||||
|
@ -20,12 +20,15 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import traceback
|
import traceback
|
||||||
|
import os, statvfs
|
||||||
|
|
||||||
import gtk
|
import gtk
|
||||||
|
|
||||||
|
import virtinst
|
||||||
from virtinst import VirtualNetworkInterface
|
from virtinst import VirtualNetworkInterface
|
||||||
from virtinst import VirtualDisk
|
from virtinst import VirtualDisk
|
||||||
|
|
||||||
|
from virtManager import util
|
||||||
from virtManager.error import vmmErrorDialog
|
from virtManager.error import vmmErrorDialog
|
||||||
|
|
||||||
OPTICAL_DEV_PATH = 0
|
OPTICAL_DEV_PATH = 0
|
||||||
@ -55,6 +58,51 @@ def set_error_parent(parent):
|
|||||||
err_dial.set_parent(parent)
|
err_dial.set_parent(parent)
|
||||||
err_dial = err_dial
|
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) #
|
# Widgets for listing network device options (in create, addhardware) #
|
||||||
|
@ -34,12 +34,15 @@ DEFAULT_POOL_NAME = "default"
|
|||||||
DEFAULT_POOL_PATH = "/var/lib/libvirt/images"
|
DEFAULT_POOL_PATH = "/var/lib/libvirt/images"
|
||||||
|
|
||||||
def build_default_pool(conn):
|
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 ?
|
# FIXME: This should use config.get_default_image_path ?
|
||||||
|
|
||||||
if not virtinst.util.is_storage_capable(conn):
|
if not virtinst.util.is_storage_capable(conn):
|
||||||
# VirtualDisk will raise an error for us
|
# VirtualDisk will raise an error for us
|
||||||
return
|
return
|
||||||
|
|
||||||
pool = None
|
pool = None
|
||||||
try:
|
try:
|
||||||
pool = conn.storagePoolLookupByName(DEFAULT_POOL_NAME)
|
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") %
|
raise RuntimeError(_("Couldn't create default storage pool '%s': %s") %
|
||||||
(DEFAULT_POOL_PATH, str(e)))
|
(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"):
|
def tooltip_wrapper(obj, txt, func="set_tooltip_text"):
|
||||||
# Catch & ignore errors - set_tooltip_* is in gtk >= 2.12
|
# Catch & ignore errors - set_tooltip_* is in gtk >= 2.12
|
||||||
# and we can easily work with lower versions
|
# and we can easily work with lower versions
|
||||||
@ -334,3 +394,4 @@ def iface_in_use_by(conn, name):
|
|||||||
use_str += iface.get_name()
|
use_str += iface.get_name()
|
||||||
|
|
||||||
return use_str
|
return use_str
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user