Cole Robinson wrote:
> Per Dan's advice, I've changed the previously proposed
> virt-install cli options for specifying libvirt managed
> storage.
>
> This patch does not change any possible semantics of
> --file or --cdrom: they remain strictly for specifying
> local media. In this way they are basically deprecated.
>
Here's the second cut. Format for the cli options is
--disk path=/some/path[,device=cdrom|floppy][,permissions=ro|sh]
--disk pool=poolname[,device=cdrom|floppy][,permissions=ro|sh]
--disk vol=poolname/volname[,device=cdrom|floppy][,permissions=ro|sh]
Hopefully this will simplify things and fix the issues encountered.
Once this is committed I'll be writing up the man pages and
creating a wiki page detailing how this can all fit together
for remote installs.
Thanks,
Cole
diff -r bd9e79483f70 virt-install
--- a/virt-install Mon Aug 11 18:20:28 2008 -0400
+++ b/virt-install Thu Aug 14 12:22:09 2008 -0400
@@ -44,26 +44,101 @@
gettext.bindtextdomain(virtinst.gettext_app, virtinst.gettext_dir)
gettext.install(virtinst.gettext_app, virtinst.gettext_dir, unicode=1)
-### General input gathering functions
-def get_disk(disk, size, sparse, guest, hvm, conn):
+def parse_disk_option(guest, path, size):
+ """helper to properly parse --disk options"""
+ abspath = None
+ voltuple = None
+ volinst = None
+ devtype = None
+ ro = False
+ shared = False
- # Getting disk size
- if not os.path.exists(disk) and size is None:
- fail(_("Must specify size for non-existent disks"))
+ origpath = path
+
+ # Strip media type
+ if path.startswith("path="):
+ path_type = "path="
+ elif path.startswith("vol="):
+ path_type = "vol="
+ elif path.startswith("pool="):
+ path_type = "pool="
+ else:
+ fail(_("--disk path must start with path=, pool=, or vol=."))
+ path = path[len(path_type):]
+
+ # Parse endings for permissions and device type
+ while True:
+ if not path.count(","):
+ break
+ path, opts = path.split(",", 1)
+ for opt in opts.split(","):
+ opt_type = None
+ opt_val = None
+ if opt.count("="):
+ opt_type, opt_val = opt.split("=", 1)
+ if opt_type == "device":
+ devtype = opt_val
+ elif opt_type == "permissions":
+ if opt_val == "ro":
+ ro = True
+ elif opt_val == "sh":
+ shared = True
+ else:
+ fail(_("Unknown permissions value '%s'." % opt_val))
+ else:
+ fail(_("Unknown disk option '%s'." % opt))
+
+ # We return (path, (poolname, volname), volinst, device, readonly, shared)
+ if path_type == "path=":
+ abspath = os.path.abspath(path)
+ elif path_type == "pool=":
+ if not size:
+ raise ValueError(_("Size must be specified with all 'pool='"))
+ vc = virtinst.Storage.StorageVolume.get_volume_for_pool(pool_name=path,
+ conn=guest.conn)
+ vname = virtinst.Storage.StorageVolume.find_free_name(conn=guest.conn,
+ pool_name=path,
+ name=guest.name)
+ volinst = vc(pool_name=path, name=vname, conn=guest.conn,
+ capacity=(size and size*1024*1024*1024))
+ elif path_type == "vol=":
+ if not path.count("/"):
+ raise ValueError(_("Storage volume must be specified as "
+ "pool=poolname/volname"))
+ vollist = path.split("/")
+ voltuple = (vollist[0], vollist[1])
+ logging.debug("Parsed volume: as pool='%s' vol='%s'" % \
+ (voltuple[0], voltuple[1]))
+
+ if not devtype:
+ devtype = virtinst.VirtualDisk.DEVICE_DISK
+ ret = (abspath, voltuple, volinst, devtype, ro, shared)
+ logging.debug("parse_disk: returning %s" % str(ret))
+ return ret
+
+def get_disk(disk, size, sparse, guest, hvm, conn, is_file_path):
+
try:
- size = float(size)
- except Exception, e:
- fail(e)
+ # Get disk parameters
+ if is_file_path:
+ (path, voltuple, volinst,
+ device, readOnly, shared) = (disk, None, None,
+ virtinst.VirtualDisk.DEVICE_DISK,
+ False, False)
+ else:
+ (path, voltuple, volinst,
+ device, readOnly, shared) = parse_disk_option(guest, disk, size)
- # Build disk object
- try:
- d = virtinst.VirtualDisk(disk, size, sparse = sparse)
+ d = virtinst.VirtualDisk(path=path, size=size, sparse=sparse,
+ volInstall=volinst, volName=voltuple,
+ readOnly=readOnly, device=device,
+ conn=guest.conn)
# Default file backed PV guests to tap driver
if d.type == virtinst.VirtualDisk.TYPE_FILE \
and not(hvm) and virtinst.util.is_blktap_capable():
d.driver_name = virtinst.VirtualDisk.DRIVER_TAP
except ValueError, e:
- fail(e)
+ fail(_("Error with storage parameters: %s" % str(e)))
# Check disk conflicts
if d.is_conflict_disk(conn) is True:
@@ -71,7 +146,7 @@
if not cli.prompt_for_yes_or_no(warnmsg + _("Do you really want to use the disk (yes or no)? ")):
cli.nice_exit()
- ret = d.size_conflict()
+ ret = d.is_size_conflict()
if ret[0]:
fail(ret[1])
elif ret[1]:
@@ -80,11 +155,19 @@
guest.disks.append(d)
-def get_disks(disk, size, sparse, nodisks, guest, hvm, conn):
+def get_disks(file_paths, disk_paths, size, sparse, nodisks, guest, hvm, conn):
if nodisks:
- if disk or size:
- fail(_("Cannot use --file with --nodisks"))
+ if file_paths or disk_paths or size:
+ fail(_("Cannot use --file, --size, or --disk with --nodisks"))
return
+ if file_paths and disk_paths:
+ fail(_("Cannot mix --file and --disk options."))
+ elif not file_paths and not disk_paths:
+ fail(_("A disk must be specified (use --nodisks to override)"))
+
+ is_file_path = (file_paths or False)
+ disk = (file_paths or disk_paths)
+
# ensure we have equal length lists
if (type(disk) == type(size) == list):
if len(disk) != len(size):
@@ -94,17 +177,14 @@
elif type(size) == list:
disk = [ None ] * len(size)
- if (type(disk) == list):
- map(lambda d, s: get_disk(d, s, sparse, guest, hvm, conn),
- disk, size)
- elif (type(size) == list):
- map(lambda d, s: get_disk(d, s, sparse, guest, hvm, conn),
- disk, size)
+ if type(disk) == list or type(size) == list:
+ map(lambda d, s: get_disk(d, s, sparse, guest, hvm, conn,
+ is_file_path), disk, size)
else:
- get_disk(disk, size, sparse, guest, hvm, conn)
+ get_disk(disk, size, sparse, guest, hvm, conn, is_file_path)
def get_networks(macs, bridges, networks, guest):
- (macs, networks) = cli.digest_networks(macs, bridges, networks)
+ (macs, networks) = cli.digest_networks(macs, bridges, networks, nics=1)
map(lambda m, n: cli.get_network(m, n, guest), macs, networks)
@@ -128,22 +208,34 @@
if location is None:
fail(_("location must be specified for paravirtualized guests."))
- if not (pxe or location or cdpath):
- fail(_("One of --pxe, --location or --cdrom must be specified."))
+ if location and virtinst.util.is_uri_remote(guest.conn.getURI()):
+ fail(_("--location can not be specified for remote connections."))
+
+ cdinstall = (cdpath or False)
+ if not (pxe or cdpath or location):
+ # Look at Guest disks: if there is a cdrom, use for install
+ for disk in guest.disks:
+ if disk.device == virtinst.VirtualDisk.DEVICE_CDROM:
+ cdinstall = True
+ if not cdinstall:
+ fail(_("One of --pxe, --location, or cdrom media must be "
+ "specified."))
if pxe:
return
try:
- # guest.cdrom is deprecated
- guest.location = (location or cdpath)
+ if location or cdpath:
+ guest.location = (location or cdpath)
if cdpath and os.path.exists(cdpath):
# Build a throwaway disk for validation for local CDs only
- cddisk = virtinst.VirtualDisk(path=guest.location,
+ cddisk = virtinst.VirtualDisk(path=cdpath,
+ conn=guest.conn,
transient=True,
device=virtinst.VirtualDisk.DEVICE_CDROM,
readOnly=True)
+ if cdinstall:
guest.installer.cdrom = True
except ValueError, e:
- fail(e)
+ fail(_("Error creating cdrom disk: %s" % str(e)))
### Option parsing
@@ -177,8 +269,12 @@
# disk options
parser.add_option("-f", "--file", type="string",
- dest="diskfile", action="callback", callback=cli.check_before_append,
+ dest="file_path", action="callback", callback=cli.check_before_append,
help=_("File to use as the disk image"))
+ parser.add_option("", "--disk", type="string", dest="disk_path",
+ action="callback", callback=cli.check_before_append,
+ help=_("Specify storage to use as a disk with various "
+ "options."))
parser.add_option("-s", "--file-size", type="float",
action="append", dest="disksize",
help=_("Size of the disk image (if it doesn't exist) in gigabytes"))
@@ -337,7 +433,6 @@
conn = cli.getConnection(options.connect)
capabilities = virtinst.CapabilitiesParser.parse(conn.getCapabilities())
-
if options.fullvirt and options.paravirt:
fail(_("Can't do both --hvm and --paravirt"))
@@ -372,12 +467,14 @@
logging.debug("Hypervisor type is '%s'" % type)
if options.livecd:
- installer = virtinst.LiveCDInstaller(type = type, os_type = os_type)
+ installer = virtinst.LiveCDInstaller(type = type, os_type = os_type,
+ conn = conn)
elif options.pxe:
- installer = virtinst.PXEInstaller(type = type, os_type = os_type)
+ installer = virtinst.PXEInstaller(type = type, os_type = os_type,
+ conn = conn)
else:
- installer = virtinst.DistroInstaller(type = type, os_type = os_type)
-
+ installer = virtinst.DistroInstaller(type = type, os_type = os_type,
+ conn = conn)
if hvm:
guest = virtinst.FullVirtGuest(connection=conn, installer=installer,
@@ -394,10 +491,9 @@
if hvm:
cli.get_sound(options.sound, guest)
-
# set up disks
- get_disks(options.diskfile, options.disksize, options.sparse, options.nodisks,
- guest, hvm, conn)
+ get_disks(options.file_path, options.disk_path, options.disksize,
+ options.sparse, options.nodisks, guest, hvm, conn)
# set up network information
get_networks(options.mac, options.bridge, options.network, guest)
diff -r bd9e79483f70 virtinst/DistroManager.py
--- a/virtinst/DistroManager.py Mon Aug 11 18:20:28 2008 -0400
+++ b/virtinst/DistroManager.py Thu Aug 14 12:22:09 2008 -0400
@@ -135,20 +135,17 @@
def get_location(self):
return self._location
def set_location(self, val):
- voltuple = None
- path = None
# 'location' is kind of overloaded: it can be a local file or device
# path (for a boot.iso), a local directory (for a tree), a
# tuple of the form (poolname, volname), or an http, ftp, or
# nfs for an iso or a tree
if type(val) is tuple and len(val) == 2:
- voltuple = val
logging.debug("DistroInstaller location is a (poolname, volname)"
" tuple")
elif os.path.exists(os.path.abspath(val)):
- path = os.path.abspath(val)
+ val = os.path.abspath(val)
logging.debug("DistroInstaller location is a local "
- "file/path: %s" % path)
+ "file/path: %s" % val)
elif val.startswith("nfs://"):
# Convert RFC compliant NFS nfs://server/path/to/distro
# to what mount/anaconda expect nfs:server:/path/to/distro
@@ -165,7 +162,8 @@
elif (val.startswith("http://") or val.startswith("ftp://") or
val.startswith("nfs:")):
logging.debug("DistroInstaller location is a network source.")
- elif self.conn and util.is_storage_capable(self.conn):
+ elif self.conn and util.is_storage_capable(self.conn) and \
+ util.is_uri_remote(self.conn.getURI()):
# If conn is specified, pass the path to a VirtualDisk object
# and see what comes back
try:
@@ -258,7 +256,11 @@
}
if self.cdrom:
- self._prepare_cdrom(guest, distro, meter)
+ if self.location:
+ self._prepare_cdrom(guest, distro, meter)
+ else:
+ # Booting from a cdrom directly allocated to the guest
+ pass
else:
self._prepare_kernel_and_initrd(guest, distro, meter)
diff -r bd9e79483f70 virtinst/LiveCDInstaller.py
--- a/virtinst/LiveCDInstaller.py Mon Aug 11 18:20:28 2008 -0400
+++ b/virtinst/LiveCDInstaller.py Thu Aug 14 12:22:09 2008 -0400
@@ -47,19 +47,23 @@
break
if not found:
- raise LiveCDInstallerException(_("HVM virtualisation not supported; cannot boot LiveCD"))
+ raise LiveCDInstallerException(_("Connection does not support HVM virtualisation, cannot boot live CD"))
path = None
vol_tuple = None
if type(self.location) is tuple:
vol_tuple = self.location
- else:
+ elif self.location:
path = self.location
+ elif not self.cdrom:
+ raise LiveCDInstallerException(_("CDROM media must be specified "
+ "for the live CD installer."))
- disk = VirtualDisk(path=path, conn=guest.conn, volName=vol_tuple,
- device = VirtualDisk.DEVICE_CDROM,
- readOnly = True)
- guest._install_disks.insert(0, disk)
+ if path or vol_tuple:
+ disk = VirtualDisk(path=path, conn=guest.conn, volName=vol_tuple,
+ device = VirtualDisk.DEVICE_CDROM,
+ readOnly = True)
+ guest._install_disks.insert(0, disk)
def _get_osblob(self, install, hvm, arch = None, loader = None, conn = None):
if install:
_______________________________________________
et-mgmt-tools mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/et-mgmt-tools