cli: Replace add --check option (bz 1063471)
For fine grained enabling/disabling validation checks. Use this to replace the heavy handed --force option.
This commit is contained in:
parent
0f3d86ac9e
commit
93f826a8b2
|
@ -139,6 +139,10 @@ Show the help message and exit
|
|||
|
||||
Show program's version number and exit
|
||||
|
||||
=item B<--check>
|
||||
|
||||
Enable or disable some validation checks. See L<virt-install(1)> for more details.
|
||||
|
||||
=item B<-q>
|
||||
|
||||
=item B<--quiet>
|
||||
|
|
|
@ -1476,6 +1476,10 @@ change host device configuration, or actually teach libvirt about the guest.
|
|||
virt-install may still fetch install media, since this is required to
|
||||
properly detect the OS to install.
|
||||
|
||||
=item B<--check>
|
||||
|
||||
Enable or disable some validation checks. Some examples are warning about using a disk that's already assigned to another VM (--check path_in_use=on|off), or warning about potentially running out of space during disk allocation (--check disk_size=on|off). Most checks are performed by default.
|
||||
|
||||
=item B<-q>
|
||||
|
||||
=item B<--quiet>
|
||||
|
|
|
@ -96,6 +96,8 @@ test_files = {
|
|||
'AUTOMANAGEIMG' : "/some/new/pool/dir/new",
|
||||
'EXISTIMG1' : "/dev/default-pool/testvol1.img",
|
||||
'EXISTIMG2' : "/dev/default-pool/testvol2.img",
|
||||
'EXISTIMG3' : exist_images[0],
|
||||
'EXISTIMG4' : exist_images[1],
|
||||
'EXISTUPPER' : "/dev/default-pool/UPPER",
|
||||
'POOL' : "default-pool",
|
||||
'VOL' : "testvol1.img",
|
||||
|
@ -638,6 +640,7 @@ c.add_valid("--disk path=%(MANAGEDNEW1)s,format=raw,size=.0000001") # Managed f
|
|||
c.add_valid("--disk path=%(MANAGEDNEW1)s,format=qcow2,size=.0000001") # Managed file using format qcow2
|
||||
c.add_valid("--disk %(EXISTIMG1)s") # Not specifying path=
|
||||
c.add_valid("--disk %(NEWIMG1)s,format=raw,size=.0000001") # Not specifying path= but creating storage
|
||||
c.add_valid("--disk %(COLLIDE)s --check path_in_use=off") # Colliding storage with --check
|
||||
c.add_valid("--disk %(COLLIDE)s --force") # Colliding storage with --force
|
||||
c.add_valid("--disk %(SHARE)s,perms=sh") # Colliding shareable storage
|
||||
c.add_valid("--disk path=%(EXISTIMG1)s,device=cdrom --disk path=%(EXISTIMG1)s,device=cdrom") # Two IDE cds
|
||||
|
@ -645,7 +648,7 @@ c.add_valid("--disk %(EXISTIMG1)s,driver_name=qemu,driver_type=qcow2") # Driver
|
|||
c.add_valid("--disk /dev/zero") # Referencing a local unmanaged /dev node
|
||||
c.add_valid("--disk pool=default,size=.00001") # Building 'default' pool
|
||||
c.add_valid("--disk %(AUTOMANAGEIMG)s,size=.1") # autocreate the pool
|
||||
c.add_invalid("--disk %(NEWIMG1)s,sparse=true,size=100000000000 --force") # Don't warn about fully allocated file exceeding disk space
|
||||
c.add_valid("--disk %(NEWIMG1)s,sparse=true,size=100000000 --check disk_size=off") # Don't warn about fully allocated file exceeding disk space
|
||||
c.add_invalid("--file %(NEWIMG1)s --file-size 100000 --nonsparse") # Nonexisting file, size too big
|
||||
c.add_invalid("--file %(NEWIMG1)s --file-size 100000") # Huge file, sparse, but no prompting
|
||||
c.add_invalid("--file %(NEWIMG1)s") # Nonexisting file, no size
|
||||
|
@ -828,7 +831,7 @@ c.add_invalid("--mac 22:22:33:12:34:AB") # Colliding macaddr
|
|||
c = vinst.add_category("storage-back-compat", "--pxe --noautoconsole")
|
||||
c.add_valid("--file %(EXISTIMG1)s --nonsparse --file-size 4") # Existing file, other opts
|
||||
c.add_valid("--file %(EXISTIMG1)s") # Existing file, no opts
|
||||
c.add_valid("--file %(EXISTIMG1)s --file virt-clone --file virt-clone") # Multiple existing files
|
||||
c.add_valid("--file %(EXISTIMG1)s --file %(EXISTIMG1)s") # Multiple existing files
|
||||
c.add_valid("--file %(NEWIMG1)s --file-size .00001 --nonsparse") # Nonexistent file
|
||||
|
||||
|
||||
|
@ -936,20 +939,22 @@ c.add_compare("--remove-device --host-device 0x04b3:0x4485", "remove-hostdev-nam
|
|||
vclon = App("virt-clone")
|
||||
c = vclon.add_category("remote", "--connect %(REMOTEURI)s")
|
||||
c.add_valid("-o test --auto-clone") # Auto flag, no storage
|
||||
c.add_valid("--original-xml %(CLONE_STORAGE_XML)s --auto-clone") # Auto flag w/ managed storage,
|
||||
c.add_invalid("--original-xml %(CLONE_DISK_XML)s --auto-clone") # Auto flag w/ storage,
|
||||
c.add_valid("--original-xml %(CLONE_STORAGE_XML)s --auto-clone") # Auto flag w/ managed storage
|
||||
c.add_invalid("--original-xml %(CLONE_DISK_XML)s --auto-clone") # Auto flag w/ local storage, which is invalid for remote connection
|
||||
|
||||
|
||||
c = vclon.add_category("misc", "")
|
||||
c.add_compare("--connect %(KVMURI)s -o test-for-clone --auto-clone --clone-running", "clone-auto1", compare_check=support.SUPPORT_CONN_LOADER_ROM)
|
||||
c.add_compare("-o test-clone-simple --name newvm --auto-clone --clone-running", "clone-auto2", compare_check=support.SUPPORT_CONN_LOADER_ROM)
|
||||
c.add_valid("-o test --auto-clone") # Auto flag, no storage
|
||||
c.add_valid("--original-xml %(CLONE_DISK_XML)s --auto-clone") # Auto flag w/ storage,
|
||||
c.add_valid("--original-xml %(CLONE_STORAGE_XML)s --auto-clone") # Auto flag w/ managed storage,
|
||||
c.add_valid("--original-xml %(CLONE_STORAGE_XML)s --auto-clone") # Auto flag w/ managed storage
|
||||
c.add_valid("--original-xml %(CLONE_DISK_XML)s --auto-clone") # Auto flag w/ local storage
|
||||
c.add_valid("-o test-for-clone --auto-clone --clone-running") # Auto flag, actual VM, skip state check
|
||||
c.add_valid("-o test-clone-simple -n newvm --preserve-data --file /dev/default-pool/default-vol --clone-running --force") # Preserve data shouldn't complain about existing volume
|
||||
c.add_valid("-o test-clone-simple -n newvm --preserve-data --file %(EXISTIMG1)s --clone-running") # Preserve data shouldn't complain about existing volume
|
||||
c.add_valid("-n clonetest --original-xml %(CLONE_DISK_XML)s --file %(EXISTIMG3)s --file %(EXISTIMG4)s --check path_exists=off") # Skip existing file check
|
||||
c.add_invalid("--auto-clone") # Just the auto flag
|
||||
c.add_invalid("-o test-for-clone --auto-clone")
|
||||
c.add_invalid("-o test-clone-simple -n newvm --file %(EXISTIMG1)s --clone-running") # Should complain about overwriting existing file
|
||||
|
||||
|
||||
c = vclon.add_category("general", "-n clonetest")
|
||||
|
|
|
@ -24,8 +24,6 @@ import argparse
|
|||
import logging
|
||||
import sys
|
||||
|
||||
import urlgrabber.progress as progress
|
||||
|
||||
import virtinst.cli as cli
|
||||
from virtinst import Cloner
|
||||
from virtinst.cli import fail, print_stdout, print_stderr
|
||||
|
@ -163,8 +161,9 @@ def main(conn=None):
|
|||
options.quiet = options.quiet or options.xmlonly
|
||||
cli.setupLogging("virt-clone", options.debug, options.quiet)
|
||||
|
||||
cli.convert_old_force(options)
|
||||
cli.parse_check(options.check)
|
||||
cli.set_prompt(options.prompt)
|
||||
cli.set_force(options.force)
|
||||
|
||||
if conn is None:
|
||||
conn = cli.getConnection(options.connect)
|
||||
|
@ -200,9 +199,7 @@ def main(conn=None):
|
|||
if options.xmlonly:
|
||||
print_stdout(design.clone_xml, do_force=True)
|
||||
else:
|
||||
# start cloning
|
||||
meter = progress.TextMeter(fo=sys.stdout)
|
||||
design.start_duplicate(meter)
|
||||
design.start_duplicate(cli.get_meter())
|
||||
|
||||
print_stdout("")
|
||||
print_stdout(_("Clone '%s' created successfully.") % design.clone_name)
|
||||
|
|
10
virt-install
10
virt-install
|
@ -24,7 +24,6 @@ import sys
|
|||
import time
|
||||
|
||||
import libvirt
|
||||
import urlgrabber.progress as progress
|
||||
|
||||
import virtinst
|
||||
from virtinst import cli
|
||||
|
@ -418,7 +417,7 @@ def validate_required_options(options, guest):
|
|||
msg = ""
|
||||
|
||||
if not options.name:
|
||||
msg += "\n" + cli.name_missing
|
||||
msg += "\n" + _("--name is required")
|
||||
|
||||
if not options.memory:
|
||||
msg += "\n" + _("--memory amount in MiB is required")
|
||||
|
@ -739,9 +738,7 @@ def start_install(guest, continue_inst, options):
|
|||
wait_on_install = True
|
||||
wait_time = -1
|
||||
|
||||
meter = (options.quiet and
|
||||
progress.BaseMeter() or
|
||||
progress.TextMeter(fo=sys.stdout))
|
||||
meter = cli.get_meter()
|
||||
logging.debug("Guest.has_install_phase: %s",
|
||||
guest.installer.has_install_phase())
|
||||
|
||||
|
@ -1048,7 +1045,8 @@ def main(conn=None):
|
|||
|
||||
check_cdrom_option_error(options)
|
||||
|
||||
cli.set_force(options.force)
|
||||
cli.convert_old_force(options)
|
||||
cli.parse_check(options.check)
|
||||
cli.set_prompt(options.prompt)
|
||||
|
||||
parsermap = cli.build_parser_map(options)
|
||||
|
|
7
virt-xml
7
virt-xml
|
@ -24,7 +24,6 @@ import os
|
|||
import sys
|
||||
|
||||
import libvirt
|
||||
import urlgrabber.progress as progress
|
||||
|
||||
import virtinst
|
||||
from virtinst import cli
|
||||
|
@ -241,11 +240,7 @@ def setup_device(dev):
|
|||
|
||||
logging.debug("Doing setup for disk=%s", dev)
|
||||
|
||||
meter = ((cli.quiet or "VIRTINST_TEST_SUITE" in os.environ) and
|
||||
progress.BaseMeter() or
|
||||
progress.TextMeter(fo=sys.stdout))
|
||||
|
||||
dev.setup(meter)
|
||||
dev.setup(cli.get_meter())
|
||||
dev.virt_xml_setup = True
|
||||
|
||||
|
||||
|
|
126
virtinst/cli.py
126
virtinst/cli.py
|
@ -29,6 +29,7 @@ import sys
|
|||
import traceback
|
||||
|
||||
import libvirt
|
||||
from urlgrabber import progress
|
||||
|
||||
from virtcli import CLIConfig
|
||||
|
||||
|
@ -58,8 +59,38 @@ from .osxml import OSXML
|
|||
from .storage import StoragePool, StorageVolume
|
||||
|
||||
|
||||
force = False
|
||||
quiet = False
|
||||
##########################
|
||||
# Global option handling #
|
||||
##########################
|
||||
|
||||
class _GlobalState(object):
|
||||
def __init__(self):
|
||||
self.quiet = False
|
||||
|
||||
self.all_checks = None
|
||||
self._validation_checks = {}
|
||||
|
||||
def set_validation_check(self, checkname, val):
|
||||
self._validation_checks[checkname] = val
|
||||
|
||||
def get_validation_check(self, checkname):
|
||||
if self.all_checks is not None:
|
||||
return self.all_checks
|
||||
|
||||
# Default to True for all checks
|
||||
return self._validation_checks.get(checkname, True)
|
||||
|
||||
|
||||
_globalstate = None
|
||||
|
||||
|
||||
def get_global_state():
|
||||
return _globalstate
|
||||
|
||||
|
||||
def _reset_global_state():
|
||||
global _globalstate
|
||||
_globalstate = _GlobalState()
|
||||
|
||||
|
||||
####################
|
||||
|
@ -136,8 +167,8 @@ def earlyLogging():
|
|||
|
||||
|
||||
def setupLogging(appname, debug_stdout, do_quiet, cli_app=True):
|
||||
global quiet
|
||||
quiet = do_quiet
|
||||
_reset_global_state()
|
||||
get_global_state().quiet = do_quiet
|
||||
|
||||
vi_dir = None
|
||||
logfile = None
|
||||
|
@ -192,7 +223,7 @@ def setupLogging(appname, debug_stdout, do_quiet, cli_app=True):
|
|||
elif not cli_app:
|
||||
streamHandler = None
|
||||
else:
|
||||
if quiet:
|
||||
if get_global_state().quiet:
|
||||
level = logging.ERROR
|
||||
else:
|
||||
level = logging.WARN
|
||||
|
@ -270,7 +301,7 @@ def fail(msg, do_exit=True):
|
|||
|
||||
|
||||
def print_stdout(msg, do_force=False):
|
||||
if do_force or not quiet:
|
||||
if do_force or not get_global_state().quiet:
|
||||
print msg
|
||||
|
||||
|
||||
|
@ -303,27 +334,22 @@ def install_fail(guest):
|
|||
sys.exit(1)
|
||||
|
||||
|
||||
def set_force(val=True):
|
||||
global force
|
||||
force = val
|
||||
|
||||
|
||||
def set_prompt(prompt):
|
||||
# Set whether we allow prompts, or fail if a prompt pops up
|
||||
if prompt:
|
||||
logging.warning("--prompt mode is no longer supported.")
|
||||
|
||||
|
||||
name_missing = _("--name is required")
|
||||
|
||||
|
||||
def validate_disk(dev, warn_overwrite=False):
|
||||
def _optional_fail(msg):
|
||||
if force:
|
||||
logging.debug("--force skipping error condition '%s'", msg)
|
||||
logging.warn(msg)
|
||||
else:
|
||||
fail(msg + _(" (Use --force to override)"))
|
||||
def _optional_fail(msg, checkname):
|
||||
do_check = get_global_state().get_validation_check(checkname)
|
||||
if do_check:
|
||||
fail(msg + (_(" (Use --check %s=off or "
|
||||
"--check all=off to override)") % checkname))
|
||||
|
||||
logging.debug("Skipping --check %s error condition '%s'",
|
||||
checkname, msg)
|
||||
logging.warn(msg)
|
||||
|
||||
def check_path_exists(dev):
|
||||
"""
|
||||
|
@ -331,10 +357,11 @@ def validate_disk(dev, warn_overwrite=False):
|
|||
"""
|
||||
if not warn_overwrite:
|
||||
return
|
||||
if VirtualDisk.path_definitely_exists(dev.conn, dev.path):
|
||||
_optional_fail(
|
||||
_("This will overwrite the existing path '%s'" % dev.path))
|
||||
|
||||
if not VirtualDisk.path_definitely_exists(dev.conn, dev.path):
|
||||
return
|
||||
_optional_fail(
|
||||
_("This will overwrite the existing path '%s'" % dev.path),
|
||||
"path_exists")
|
||||
|
||||
def check_inuse_conflict(dev):
|
||||
"""
|
||||
|
@ -345,7 +372,8 @@ def validate_disk(dev, warn_overwrite=False):
|
|||
return
|
||||
|
||||
_optional_fail(_("Disk %s is already in use by other guests %s." %
|
||||
(dev.path, names)))
|
||||
(dev.path, names)),
|
||||
"path_in_use")
|
||||
|
||||
def check_size_conflict(dev):
|
||||
"""
|
||||
|
@ -354,7 +382,7 @@ def validate_disk(dev, warn_overwrite=False):
|
|||
isfatal, errmsg = dev.is_size_conflict()
|
||||
# The isfatal case should have already caused us to fail
|
||||
if not isfatal and errmsg:
|
||||
_optional_fail(errmsg)
|
||||
_optional_fail(errmsg, "disk_size")
|
||||
|
||||
def check_path_search(dev):
|
||||
user, broken_paths = dev.check_path_search(dev.conn, dev.path)
|
||||
|
@ -446,6 +474,12 @@ def get_console_cb(guest):
|
|||
return _gfx_console
|
||||
|
||||
|
||||
def get_meter():
|
||||
if get_global_state().quiet or "VIRTINST_TEST_SUITE" in os.environ:
|
||||
return progress.BaseMeter()
|
||||
return progress.TextMeter(fo=sys.stdout)
|
||||
|
||||
|
||||
###########################
|
||||
# Common CLI option/group #
|
||||
###########################
|
||||
|
@ -509,6 +543,11 @@ def add_misc_options(grp, prompt=False, replace=False,
|
|||
help=_("Run through install process, but do not "
|
||||
"create devices or define the guest."))
|
||||
|
||||
if prompt:
|
||||
grp.add_argument("--check",
|
||||
help=_("Enable or disable validation checks. Example:\n"
|
||||
"--check path_in_use=off\n"
|
||||
"--check all=off"))
|
||||
grp.add_argument("-q", "--quiet", action="store_true",
|
||||
help=_("Suppress non-error output"))
|
||||
grp.add_argument("-d", "--debug", action="store_true",
|
||||
|
@ -1100,6 +1139,41 @@ class VirtCLIParser(object):
|
|||
raise NotImplementedError()
|
||||
|
||||
|
||||
###################
|
||||
# --check parsing #
|
||||
###################
|
||||
|
||||
def convert_old_force(options):
|
||||
if options.force:
|
||||
if not options.check:
|
||||
options.check = "all=off"
|
||||
del(options.force)
|
||||
|
||||
|
||||
class ParseCLICheck(VirtCLIParser):
|
||||
# This sets properties on the _GlobalState objects
|
||||
|
||||
def _init_params(self):
|
||||
def _set_check(opts, inst, cliname, val):
|
||||
ignore = opts
|
||||
inst.set_validation_check(cliname, val)
|
||||
|
||||
self.set_param(None, "path_in_use",
|
||||
is_onoff=True, setter_cb=_set_check)
|
||||
self.set_param(None, "disk_size",
|
||||
is_onoff=True, setter_cb=_set_check)
|
||||
self.set_param(None, "path_exists",
|
||||
is_onoff=True, setter_cb=_set_check)
|
||||
|
||||
self.set_param("all_checks", "all", is_onoff=True)
|
||||
|
||||
|
||||
def parse_check(checkstr):
|
||||
# Overwrite this for each parse,
|
||||
parser = ParseCLICheck("check")
|
||||
parser.parse(None, checkstr, get_global_state())
|
||||
|
||||
|
||||
######################
|
||||
# --metadata parsing #
|
||||
######################
|
||||
|
|
Loading…
Reference in New Issue