cli: Clean up disk source handling

...sort of. This stuff is a hairy mess, but this makes it more stream line
and easier to extend.
This commit is contained in:
Cole Robinson 2014-12-05 18:17:39 -05:00
parent 0cdf6032fb
commit ef0beeb18b
3 changed files with 90 additions and 139 deletions

View File

@ -1447,68 +1447,25 @@ def _default_image_file_format(conn):
return "raw"
def _parse_disk_source(guest, path, pool, vol, size, fmt, sparse):
abspath = None
volinst = None
volobj = None
def _get_default_image_format(conn, poolobj):
tmpvol = StorageVolume(conn)
tmpvol.pool = poolobj
# Strip media type
optcount = sum([bool(p) for p in [path, pool, vol]])
if optcount > 1:
fail(_("Cannot specify more than 1 storage path"))
if optcount == 0 and size:
# Saw something like --disk size=X, have it imply pool=default
pool = "default"
if tmpvol.file_type != StorageVolume.TYPE_FILE:
return None
return _default_image_file_format(conn)
if path:
abspath = os.path.abspath(path)
if os.path.dirname(abspath) == "/var/lib/libvirt/images":
StoragePool.build_default_pool(guest.conn)
elif pool:
if not size:
raise ValueError(_("Size must be specified with all 'pool='"))
if pool == "default":
StoragePool.build_default_pool(guest.conn)
def _generate_new_volume_name(guest, poolobj, fmt):
collidelist = []
for disk in guest.get_devices("disk"):
if (disk.get_vol_install() and
disk.get_vol_install().pool.name() == poolobj.name()):
collidelist.append(os.path.basename(disk.path))
poolobj = guest.conn.storagePoolLookupByName(pool)
collidelist = []
for disk in guest.get_devices("disk"):
if (disk.get_vol_install() and
disk.get_vol_install().pool.name() == poolobj.name()):
collidelist.append(os.path.basename(disk.path))
tmpvol = StorageVolume(guest.conn)
tmpvol.pool = poolobj
if fmt is None and tmpvol.file_type == tmpvol.TYPE_FILE:
fmt = _default_image_file_format(guest.conn)
ext = StorageVolume.get_file_extension_for_format(fmt)
vname = StorageVolume.find_free_name(
poolobj, guest.name, suffix=ext, collidelist=collidelist)
volinst = VirtualDisk.build_vol_install(
guest.conn, vname, poolobj, size, sparse)
if fmt:
if not volinst.supports_property("format"):
raise ValueError(_("Format attribute not supported for this "
"volume type"))
volinst.format = fmt
elif vol:
if not vol.count("/"):
raise ValueError(_("Storage volume must be specified as "
"vol=poolname/volname"))
vollist = vol.split("/")
voltuple = (vollist[0], vollist[1])
logging.debug("Parsed volume: as pool='%s' vol='%s'",
voltuple[0], voltuple[1])
if voltuple[0] == "default":
StoragePool.build_default_pool(guest.conn)
volobj = VirtualDisk.lookup_vol_object(guest.conn, voltuple)
return abspath, volinst, volobj
ext = StorageVolume.get_file_extension_for_format(fmt)
return StorageVolume.find_free_name(
poolobj, guest.name, suffix=ext, collidelist=collidelist)
class ParserDisk(VirtCLIParser):
@ -1576,31 +1533,55 @@ class ParserDisk(VirtCLIParser):
pass
else:
fail(_("Unknown '%s' value '%s'" % ("perms", val)))
convert_perms(opts.get_opt_param("perms"))
path = opts.get_opt_param("path")
had_path = path is not None
has_path = "path" in opts.opts
backing_store = opts.get_opt_param("backing_store")
pool = opts.get_opt_param("pool")
vol = opts.get_opt_param("vol")
poolname = opts.get_opt_param("pool")
volname = opts.get_opt_param("vol")
size = parse_size(opts.get_opt_param("size"))
fmt = opts.get_opt_param("format")
sparse = _on_off_convert("sparse", opts.get_opt_param("sparse"))
convert_perms(opts.get_opt_param("perms"))
abspath, volinst, volobj = _parse_disk_source(
self.guest, path, pool, vol, size, fmt, sparse)
optcount = sum([bool(p) for p in [has_path, poolname, volname]])
if optcount > 1:
fail(_("Cannot specify more than 1 storage path"))
if optcount == 0 and size:
# Saw something like --disk size=X, have it imply pool=default
poolname = "default"
path = volobj and volobj.path() or abspath
if had_path or path:
opts.opts["path"] = path or ""
if volname:
if volname.count("/") != 1:
raise ValueError(_("Storage volume must be specified as "
"vol=poolname/volname"))
poolname, volname = volname.split("/")
logging.debug("Parsed volume: as pool='%s' vol='%s'",
poolname, volname)
if poolname:
if poolname == "default":
StoragePool.build_default_pool(self.guest.conn)
poolobj = self.guest.conn.storagePoolLookupByName(poolname)
vol_install = None
vol_object = None
if volname:
vol_object = poolobj.storageVolLookupByName(volname)
elif poolname:
if not fmt:
fmt = _get_default_image_format(self.guest.conn, poolobj)
vname = _generate_new_volume_name(self.guest, poolobj, fmt)
vol_install = VirtualDisk.build_vol_install(
self.guest.conn, vname, poolobj, size, sparse,
fmt=fmt, backing_store=backing_store)
inst = VirtCLIParser._parse(self, opts, inst)
create_kwargs = {"size": size, "fmt": fmt, "sparse": sparse,
"vol_install": volinst, "backing_store": backing_store}
if any(create_kwargs.values()):
inst.set_create_storage(**create_kwargs)
inst.cli_size = size
if vol_object:
inst.set_vol_object(vol_object)
elif size or fmt or sparse or vol_install:
inst.set_create_storage(size=size, fmt=fmt,
vol_install=vol_install, sparse=sparse)
if not inst.target:
skip_targets = [d.target for d in self.guest.get_devices("disk")]
@ -1610,9 +1591,6 @@ class ParserDisk(VirtCLIParser):
return inst
parse_disk = ParserDisk("disk").parse
#####################
# --network parsing #
#####################

View File

@ -423,20 +423,6 @@ class VirtualDisk(VirtualDevice):
except:
return (True, 0)
@staticmethod
def lookup_vol_object(conn, name_tuple):
"""
Return a volume instance from a pool name, vol name tuple
"""
if not conn.check_support(conn.SUPPORT_CONN_STORAGE):
raise ValueError(_("Connection does not support storage lookup."))
try:
pool = conn.storagePoolLookupByName(name_tuple[0])
return pool.storageVolLookupByName(name_tuple[1])
except Exception, e:
raise ValueError(_("Couldn't lookup volume object: %s" % str(e)))
@staticmethod
def build_vol_install(*args, **kwargs):
return diskbackend.build_vol_install(*args, **kwargs)
@ -520,11 +506,9 @@ class VirtualDisk(VirtualDevice):
self._set_xmlpath(self.path)
path = property(_get_path, _set_path)
def get_sparse(self):
if self._storage_creator:
return self._storage_creator.get_sparse()
return None
def set_vol_object(self, vol_object):
self._change_backend(None, vol_object)
self._set_xmlpath(self.path)
def get_vol_object(self):
return self._storage_backend.get_vol_object()

View File

@ -147,17 +147,20 @@ def manage_path(conn, path):
return vol, pool
def build_vol_install(conn, path, pool, size, sparse):
# Path wasn't a volume. See if base of path is a managed
# pool, and if so, setup a StorageVolume object
def build_vol_install(conn, volname, poolobj, size, sparse,
fmt=None, backing_store=None):
"""
Helper for building a StorageVolume instance to pass to VirtualDisk
for eventual storage creation.
:param volname: name of the volume to be created
:param size: size in bytes
"""
if size is None:
raise ValueError(_("Size must be specified for non "
"existent volume path '%s'" % path))
"existent volume '%s'" % volname))
logging.debug("Path '%s' is target for pool '%s'. "
"Creating volume '%s'.",
os.path.dirname(path), pool.name(),
os.path.basename(path))
logging.debug("Creating volume '%s' on pool '%s'", volname, poolobj.name())
cap = (size * 1024 * 1024 * 1024)
if sparse:
@ -166,10 +169,18 @@ def build_vol_install(conn, path, pool, size, sparse):
alloc = cap
volinst = StorageVolume(conn)
volinst.pool = pool
volinst.name = os.path.basename(path)
volinst.pool = poolobj
volinst.name = volname
volinst.capacity = cap
volinst.allocation = alloc
volinst.backing_store = backing_store
if fmt:
if not volinst.supports_property("format"):
raise ValueError(_("Format attribute not supported for this "
"volume type"))
volinst.format = fmt
return volinst
@ -201,10 +212,18 @@ class StorageCreator(_StorageBase):
self.fake = False
if not self._vol_install and self._pool:
self._vol_install = build_vol_install(conn, path, pool,
size, sparse)
self._set_format(fmt)
self._set_backing_store(backing_store)
self._vol_install = build_vol_install(conn,
os.path.basename(path), pool,
size, sparse, fmt=fmt,
backing_store=backing_store)
if not self._vol_install:
if backing_store:
raise RuntimeError(_("Cannot set backing store for unmanaged "
"storage."))
if fmt and fmt != "raw":
raise RuntimeError(_("Format cannot be specified for "
"unmanaged storage."))
if self._vol_install:
self._path = None
@ -214,34 +233,6 @@ class StorageCreator(_StorageBase):
self._dev_type = None
###############
# Private API #
###############
def _set_format(self, val):
if val is None:
return
if self._vol_install:
if not self._vol_install.supports_property("format"):
raise ValueError(_("Storage type does not support format "
"parameter."))
if self._vol_install.format != val:
self._vol_install.format = val
elif val != "raw":
raise RuntimeError(_("Format cannot be specified for "
"unmanaged storage."))
def _set_backing_store(self, val):
if val is None:
return
if not self._vol_install:
raise RuntimeError(_("Cannot set backing store for unmanaged "
"storage."))
self._vol_install.backing_store = val
##############
# Public API #
##############
@ -256,8 +247,6 @@ class StorageCreator(_StorageBase):
def get_vol_install(self):
return self._vol_install
def get_sparse(self):
return self._sparse
def get_size(self):
if self._size is None: