2013-03-18 01:06:52 +04:00
#
# Utility functions for the command line drivers
#
2014-01-20 16:58:17 +04:00
# Copyright 2006-2007, 2013, 2014 Red Hat, Inc.
2013-03-18 01:06:52 +04:00
#
2018-04-04 16:35:41 +03:00
# This work is licensed under the GNU GPLv2 or later.
2018-03-20 22:00:02 +03:00
# See the COPYING file in the top-level directory.
2013-03-18 01:06:52 +04:00
2014-01-19 02:01:43 +04:00
import argparse
2016-06-12 17:11:11 +03:00
import collections
2013-04-12 16:26:21 +04:00
import os
2016-06-15 00:29:54 +03:00
import re
2013-03-18 01:06:52 +04:00
import shlex
2019-07-02 19:56:15 +03:00
import shutil
2013-04-12 16:26:21 +04:00
import sys
2013-07-05 23:14:11 +04:00
import traceback
2018-12-18 16:44:56 +03:00
import types
2013-03-18 01:06:52 +04:00
import libvirt
2019-06-08 01:21:24 +03:00
from . import xmlutil
2019-06-14 23:34:00 +03:00
from . buildconfig import BuildConfig
2019-06-08 00:50:58 +03:00
from . connection import VirtinstConnection
2018-03-21 02:38:18 +03:00
from . devices import ( Device , DeviceController , DeviceDisk , DeviceGraphics ,
2022-01-21 20:58:50 +03:00
DeviceHostdev , DeviceInterface , DevicePanic )
2020-02-03 15:20:40 +03:00
from . guest import Guest
2019-12-12 01:34:03 +03:00
from . logger import log , reset_logging
2014-09-12 23:59:22 +04:00
from . nodedev import NodeDevice
2019-06-14 03:56:16 +03:00
from . osdict import OSDB
2014-09-12 23:59:22 +04:00
from . storage import StoragePool , StorageVolume
2019-06-17 04:34:47 +03:00
from . install . unattended import UnattendedData
2019-06-28 19:05:18 +03:00
from . install . cloudinit import CloudInitData
2013-03-18 01:06:52 +04:00
2013-03-18 02:18:22 +04:00
2019-07-02 19:56:15 +03:00
HAS_VIRTVIEWER = shutil . which ( " virt-viewer " )
2015-04-12 02:25:46 +03:00
##########################
# 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 ( )
2013-03-18 01:06:52 +04:00
2018-12-18 16:44:53 +03:00
VIRT_PARSERS = [ ]
2013-03-18 01:06:52 +04:00
####################
# CLI init helpers #
####################
2014-01-22 18:06:35 +04:00
class VirtHelpFormatter ( argparse . RawDescriptionHelpFormatter ) :
2014-01-19 02:01:43 +04:00
'''
2013-03-18 01:06:52 +04:00
Subclass the default help formatter to allow printing newline characters
in - - help output . The way we do this is a huge hack : (
Inspiration : http : / / groups . google . com / group / comp . lang . python / browse_thread / thread / 6 df6e6b541a15bc2 / 09 f28e26af0699b1
2014-01-19 02:01:43 +04:00
'''
2013-03-18 01:06:52 +04:00
oldwrap = None
2017-06-15 15:18:26 +03:00
# pylint: disable=arguments-differ
2014-01-19 02:01:43 +04:00
def _split_lines ( self , * args , * * kwargs ) :
def return_default ( ) :
2014-01-22 18:06:35 +04:00
return argparse . RawDescriptionHelpFormatter . _split_lines (
self , * args , * * kwargs )
2013-03-18 01:06:52 +04:00
2014-01-19 02:01:43 +04:00
if len ( kwargs ) != 0 and len ( args ) != 2 :
2019-06-10 21:15:50 +03:00
return return_default ( ) # pragma: no cover
2013-03-18 01:06:52 +04:00
2014-01-19 02:01:43 +04:00
try :
text = args [ 0 ]
if " \n " in text :
return text . splitlines ( )
return return_default ( )
2019-06-10 21:15:50 +03:00
except Exception : # pragma: no cover
2014-01-19 02:01:43 +04:00
return return_default ( )
2013-04-13 22:34:52 +04:00
2013-03-18 01:06:52 +04:00
2014-01-22 18:06:35 +04:00
def setupParser ( usage , description , introspection_epilog = False ) :
2014-01-19 02:01:43 +04:00
epilog = _ ( " See man page for examples and full option syntax. " )
2014-01-22 18:06:35 +04:00
if introspection_epilog :
2014-01-27 23:48:23 +04:00
epilog = _ ( " Use ' --option=? ' or ' --option help ' to see "
" available suboptions " ) + " \n " + epilog
2013-06-30 23:03:53 +04:00
2014-01-19 02:01:43 +04:00
parser = argparse . ArgumentParser (
usage = usage , description = description ,
formatter_class = VirtHelpFormatter ,
epilog = epilog )
parser . add_argument ( ' --version ' , action = ' version ' ,
2019-06-14 23:34:00 +03:00
version = BuildConfig . version )
2013-06-30 23:03:53 +04:00
2013-03-18 01:06:52 +04:00
return parser
2013-04-13 22:34:52 +04:00
2013-03-18 01:06:52 +04:00
def earlyLogging ( ) :
2019-12-12 01:34:03 +03:00
reset_logging ( )
2019-06-17 04:12:39 +03:00
import logging
2013-03-18 01:06:52 +04:00
logging . basicConfig ( level = logging . DEBUG , format = ' %(message)s ' )
2013-04-13 22:34:52 +04:00
2013-07-05 23:14:11 +04:00
def setupLogging ( appname , debug_stdout , do_quiet , cli_app = True ) :
2015-04-12 02:25:46 +03:00
_reset_global_state ( )
get_global_state ( ) . quiet = do_quiet
2013-03-18 01:06:52 +04:00
2019-06-10 21:15:50 +03:00
vi_dir = VirtinstConnection . get_app_cache_dir ( )
logfile = os . path . join ( vi_dir , appname + " .log " )
2020-07-18 01:46:54 +03:00
if xmlutil . in_testsuite ( ) :
2019-06-10 21:15:50 +03:00
vi_dir = None
logfile = None
2013-10-01 18:12:56 +04:00
2019-06-10 21:15:50 +03:00
try : # pragma: no cover
2014-09-08 18:51:34 +04:00
if vi_dir and not os . access ( vi_dir , os . W_OK ) :
if os . path . exists ( vi_dir ) :
raise RuntimeError ( " No write access to directory %s " % vi_dir )
2013-03-18 01:06:52 +04:00
2014-09-08 18:51:34 +04:00
try :
2017-05-05 20:05:30 +03:00
os . makedirs ( vi_dir , 0o751 )
2017-05-05 19:47:21 +03:00
except IOError as e :
2014-09-08 18:51:34 +04:00
raise RuntimeError ( " Could not create directory %s : %s " %
2020-09-15 19:33:31 +03:00
( vi_dir , e ) ) from None
2014-09-08 18:51:34 +04:00
if ( logfile and
os . path . exists ( logfile ) and
not os . access ( logfile , os . W_OK ) ) :
raise RuntimeError ( " No write access to logfile %s " % logfile )
2019-06-10 21:15:50 +03:00
except Exception as e : # pragma: no cover
2019-06-17 04:12:39 +03:00
log . warning ( " Error setting up logfile: %s " , e )
2014-09-08 18:51:34 +04:00
logfile = None
2013-03-18 01:06:52 +04:00
dateFormat = " %a , %d % b % Y % H: % M: % S "
fileFormat = ( " [ %(asctime)s " + appname + " %(process)d ] "
" %(levelname)s ( %(module)s : %(lineno)d ) %(message)s " )
streamErrorFormat = " %(levelname)-8s %(message)s "
2019-06-17 04:12:39 +03:00
import logging
import logging . handlers
2019-12-12 01:34:03 +03:00
reset_logging ( )
2013-03-18 01:06:52 +04:00
2019-06-17 04:12:39 +03:00
log . setLevel ( logging . DEBUG )
2014-09-08 18:51:34 +04:00
if logfile :
fileHandler = logging . handlers . RotatingFileHandler (
logfile , " ae " , 1024 * 1024 , 5 )
fileHandler . setFormatter (
logging . Formatter ( fileFormat , dateFormat ) )
2019-06-17 04:12:39 +03:00
log . addHandler ( fileHandler )
2013-03-18 01:06:52 +04:00
2018-10-05 02:43:18 +03:00
streamHandler = logging . StreamHandler ( sys . stderr )
2013-07-05 23:14:11 +04:00
if debug_stdout :
2013-03-18 01:06:52 +04:00
streamHandler . setLevel ( logging . DEBUG )
streamHandler . setFormatter ( logging . Formatter ( fileFormat ,
dateFormat ) )
2015-09-07 01:36:37 +03:00
elif cli_app or not logfile :
2019-06-10 21:15:50 +03:00
# Have cli tools show WARN/ERROR by default
2015-04-12 02:25:46 +03:00
if get_global_state ( ) . quiet :
2013-03-18 01:06:52 +04:00
level = logging . ERROR
else :
level = logging . WARN
streamHandler . setLevel ( level )
streamHandler . setFormatter ( logging . Formatter ( streamErrorFormat ) )
2019-06-10 21:15:50 +03:00
else : # pragma: no cover
2015-09-07 01:36:37 +03:00
streamHandler = None
2013-07-05 23:14:11 +04:00
if streamHandler :
2019-06-17 04:12:39 +03:00
log . addHandler ( streamHandler )
2013-03-18 01:06:52 +04:00
2013-07-05 23:14:11 +04:00
# Log uncaught exceptions
2019-06-10 21:15:50 +03:00
def exception_log ( typ , val , tb ) : # pragma: no cover
2019-06-17 04:12:39 +03:00
log . debug ( " Uncaught exception: \n %s " ,
2013-07-05 23:14:11 +04:00
" " . join ( traceback . format_exception ( typ , val , tb ) ) )
2018-03-17 00:48:17 +03:00
if not debug_stdout :
# If we are already logging to stdout, don't double print
# the backtrace
sys . __excepthook__ ( typ , val , tb )
2013-03-18 01:06:52 +04:00
sys . excepthook = exception_log
# Log the app command string
2019-06-17 04:12:39 +03:00
log . debug ( " Launched with command line: %s " , " " . join ( sys . argv ) )
2013-03-18 01:06:52 +04:00
2014-02-18 18:40:39 +04:00
##############################
# Libvirt connection helpers #
##############################
2013-03-18 01:06:52 +04:00
2019-06-11 01:13:31 +03:00
def getConnection ( uri , conn = None ) :
if conn :
# preopened connection passed in via test suite
return conn
2019-06-17 04:12:39 +03:00
log . debug ( " Requesting libvirt URI %s " , ( uri or " default " ) )
2018-03-20 19:18:35 +03:00
conn = VirtinstConnection ( uri )
2018-05-03 02:55:07 +03:00
conn . open ( _openauth_cb , None )
2019-06-17 04:12:39 +03:00
log . debug ( " Received libvirt URI %s " , conn . uri )
2013-03-18 01:06:52 +04:00
return conn
2019-07-02 19:56:15 +03:00
def _openauth_cb ( creds , _cbdata ) : # pragma: no cover
2013-03-18 01:06:52 +04:00
for cred in creds :
2018-05-03 02:55:07 +03:00
# Libvirt virConnectCredential
credtype , prompt , _challenge , _defresult , _result = cred
noecho = credtype in [
libvirt . VIR_CRED_PASSPHRASE , libvirt . VIR_CRED_NOECHOPROMPT ]
if not prompt :
2019-06-17 04:12:39 +03:00
log . error ( " No prompt for auth credtype= %s " , credtype )
2018-05-03 02:55:07 +03:00
return - 1
2019-06-17 04:12:39 +03:00
log . debug ( " openauth_cb prompt= %s " , prompt )
2013-03-18 01:06:52 +04:00
2018-05-03 02:55:07 +03:00
prompt + = " : "
if noecho :
2013-03-18 01:06:52 +04:00
import getpass
res = getpass . getpass ( prompt )
else :
2018-05-03 02:55:07 +03:00
res = input ( prompt )
2013-03-18 01:06:52 +04:00
2018-05-03 02:55:07 +03:00
# Overwriting 'result' is how we return values to libvirt
cred [ - 1 ] = res
2013-03-18 01:06:52 +04:00
return 0
##############################
# Misc CLI utility functions #
##############################
def fail ( msg , do_exit = True ) :
"""
Convenience function when failing in cli app
"""
2019-06-17 04:12:39 +03:00
log . debug ( " " . join ( traceback . format_stack ( ) ) )
log . error ( msg )
2018-09-07 01:37:18 +03:00
if sys . exc_info ( ) [ 0 ] is not None :
2019-06-17 04:12:39 +03:00
log . debug ( " " , exc_info = True )
2013-03-18 01:06:52 +04:00
if do_exit :
_fail_exit ( )
2013-04-13 22:34:52 +04:00
2019-08-14 12:16:00 +03:00
def print_stdout ( msg , do_force = False , do_log = True ) :
if do_log :
log . debug ( msg )
if do_force or not get_global_state ( ) . quiet or not do_log :
2017-05-05 21:16:59 +03:00
print ( msg )
2013-03-18 01:06:52 +04:00
2013-04-13 22:34:52 +04:00
2013-03-18 01:06:52 +04:00
def print_stderr ( msg ) :
2019-06-17 04:12:39 +03:00
log . debug ( msg )
2017-05-05 21:16:59 +03:00
print ( msg , file = sys . stderr )
2013-03-18 01:06:52 +04:00
2013-04-13 22:34:52 +04:00
2013-03-18 01:06:52 +04:00
def _fail_exit ( ) :
sys . exit ( 1 )
2013-04-13 22:34:52 +04:00
2013-03-18 01:06:52 +04:00
def virsh_start_cmd ( guest ) :
2013-07-06 04:36:28 +04:00
return ( " virsh --connect %s start %s " % ( guest . conn . uri , guest . name ) )
2013-03-18 01:06:52 +04:00
2013-04-13 22:34:52 +04:00
2013-03-18 01:06:52 +04:00
def install_fail ( guest ) :
virshcmd = virsh_start_cmd ( guest )
print_stderr (
_ ( " Domain installation does not appear to have been successful. \n "
" If it was, you can restart your domain by running: \n "
" %s \n "
" otherwise, please restart your installation. " ) % virshcmd )
sys . exit ( 1 )
2013-04-13 22:34:52 +04:00
2013-09-28 19:34:03 +04:00
def set_prompt ( prompt ) :
2013-03-18 01:06:52 +04:00
# Set whether we allow prompts, or fail if a prompt pops up
2013-09-28 19:34:03 +04:00
if prompt :
2019-06-17 04:12:39 +03:00
log . warning ( " --prompt mode is no longer supported. " )
2013-04-13 22:34:52 +04:00
2013-03-18 01:06:52 +04:00
2019-06-10 21:28:42 +03:00
def check_path_search ( conn , path ) :
searchdata = DeviceDisk . check_path_search ( conn , path )
if not searchdata . fixlist :
return
2020-07-12 00:31:40 +03:00
msg = ( # pragma: no cover
_ ( " %(path)s may not be accessible by the hypervisor. "
" You will need to grant the ' %(user)s ' user search permissions for "
" the following directories: %(dirs)s " ) %
{ " path " : path , " user " : searchdata . user , " dirs " : searchdata . fixlist } )
log . warning ( msg ) # pragma: no cover
2019-06-10 21:28:42 +03:00
2020-07-06 01:39:15 +03:00
def _optional_fail ( msg , checkname , warn_on_skip = True ) :
"""
Handle printing a message with an associated - - check option
"""
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 ) )
log . debug ( " Skipping --check %s error condition ' %s ' " ,
checkname , msg )
if warn_on_skip :
log . warning ( msg )
def validate_mac ( conn , macaddr ) :
"""
There ' s legitimate use cases for creating/cloning VMs with duplicate
MACs , so we do the collision check here but allow it to be skipped
with - - check
"""
try :
2020-07-06 01:56:36 +03:00
DeviceInterface . check_mac_in_use ( conn , macaddr )
2020-07-06 01:39:15 +03:00
return
except Exception as e :
_optional_fail ( str ( e ) , " mac_in_use " )
2015-04-12 02:25:46 +03:00
2013-03-18 01:06:52 +04:00
2020-07-06 01:39:15 +03:00
def validate_disk ( dev , warn_overwrite = False ) :
2020-11-11 23:38:34 +03:00
path = dev . get_source_path ( )
def check_path_exists ( ) :
2013-03-18 01:06:52 +04:00
"""
Prompt if disk file already exists and preserve mode is not used
"""
2014-02-05 01:16:39 +04:00
if not warn_overwrite :
return
2020-11-11 23:38:34 +03:00
if not DeviceDisk . path_definitely_exists ( dev . conn , path ) :
2015-04-12 02:25:46 +03:00
return
_optional_fail (
2020-11-11 23:38:34 +03:00
_ ( " This will overwrite the existing path ' %s ' " ) % path ,
2015-04-12 02:25:46 +03:00
" path_exists " )
2013-03-18 01:06:52 +04:00
2020-11-11 23:38:34 +03:00
def check_inuse_conflict ( ) :
2013-03-18 01:06:52 +04:00
"""
Check if disk is inuse by another guest
"""
2014-01-15 02:11:51 +04:00
names = dev . is_conflict_disk ( )
2013-07-08 00:34:46 +04:00
if not names :
2014-02-05 01:16:39 +04:00
return
2013-03-18 01:06:52 +04:00
2020-07-12 00:31:40 +03:00
msg = ( _ ( " Disk %(path)s is already in use by other guests %(names)s . " ) %
2020-11-11 23:38:34 +03:00
{ " path " : path , " names " : names } )
2020-07-12 00:31:40 +03:00
_optional_fail ( msg , " path_in_use " )
2013-03-18 01:06:52 +04:00
2020-11-11 23:38:34 +03:00
def check_size_conflict ( ) :
2013-03-18 01:06:52 +04:00
"""
Check if specified size exceeds available storage
"""
isfatal , errmsg = dev . is_size_conflict ( )
2014-02-05 01:16:39 +04:00
# The isfatal case should have already caused us to fail
if not isfatal and errmsg :
2017-04-27 19:19:53 +03:00
_optional_fail ( errmsg , " disk_size " , warn_on_skip = False )
2013-03-18 01:06:52 +04:00
2020-11-11 23:38:34 +03:00
check_path_exists ( )
check_inuse_conflict ( )
check_size_conflict ( )
check_path_search ( dev . conn , path )
2013-04-13 22:34:52 +04:00
2013-03-18 01:06:52 +04:00
2020-09-11 01:14:13 +03:00
def _run_console ( message , args ) :
2019-06-17 04:12:39 +03:00
log . debug ( " Running: %s " , " " . join ( args ) )
2020-02-02 16:49:06 +03:00
argstr = " " . join ( [ shlex . quote ( a ) for a in args ] )
2020-07-14 10:41:47 +03:00
print_stdout ( message % { " command " : argstr } )
2020-02-02 16:49:06 +03:00
2020-07-18 01:46:54 +03:00
if xmlutil . in_testsuite ( ) :
2019-12-12 01:57:35 +03:00
args = [ " /bin/test " ]
2016-06-17 15:57:30 +03:00
2014-02-06 04:09:26 +04:00
child = os . fork ( )
if child :
return child
2019-06-10 21:15:50 +03:00
# pylint: disable=protected-access
2019-12-12 01:57:35 +03:00
try : # pragma: no cover
os . execvp ( args [ 0 ] , args )
2020-01-15 18:59:17 +03:00
except Exception as e : # pragma: no cover
2019-12-12 01:57:35 +03:00
print ( " Error launching %s : %s " % ( args , e ) )
finally :
os . _exit ( 1 ) # pragma: no cover
2014-02-06 04:09:26 +04:00
2020-09-11 01:14:13 +03:00
def _gfx_console ( guest ) :
2015-03-23 16:39:14 +03:00
args = [ " virt-viewer " ,
2014-02-06 04:09:26 +04:00
" --connect " , guest . conn . uri ,
" --wait " , guest . name ]
2020-07-14 10:41:47 +03:00
message = _ ( " Running graphical console command: %(command)s " )
2014-02-06 04:09:26 +04:00
2016-05-04 12:33:26 +03:00
# Currently virt-viewer needs attaching to the local display while
2018-01-05 11:13:45 +03:00
# spice gl is enabled or listen type none is used.
if guest . has_gl ( ) or guest . has_listen_none ( ) :
2016-05-04 12:33:26 +03:00
args . append ( " --attach " )
2020-09-11 01:14:13 +03:00
return _run_console ( message , args )
2014-02-06 04:09:26 +04:00
2020-09-11 01:14:13 +03:00
def _txt_console ( guest ) :
2015-03-23 16:39:14 +03:00
args = [ " virsh " ,
2014-02-06 04:09:26 +04:00
" --connect " , guest . conn . uri ,
" console " , guest . name ]
2020-07-14 10:41:47 +03:00
message = _ ( " Running text console command: %(command)s " )
2014-02-06 04:09:26 +04:00
2020-09-11 01:14:13 +03:00
return _run_console ( message , args )
2014-02-06 04:09:26 +04:00
2015-04-12 02:25:46 +03:00
def get_meter ( ) :
2019-06-08 00:32:51 +03:00
import virtinst . progress
2020-07-18 01:46:54 +03:00
quiet = ( get_global_state ( ) . quiet or xmlutil . in_testsuite ( ) )
2019-06-08 00:32:51 +03:00
return virtinst . progress . make_meter ( quiet = quiet )
2015-04-12 02:25:46 +03:00
2020-02-03 15:20:40 +03:00
def get_xmldesc ( domain , inactive = False ) :
flags = libvirt . VIR_DOMAIN_XML_SECURE
if inactive :
flags | = libvirt . VIR_DOMAIN_XML_INACTIVE
return domain . XMLDesc ( flags )
def get_domain_and_guest ( conn , domstr ) :
try :
int ( domstr )
isint = True
except ValueError :
isint = False
uuidre = " [a-fA-F0-9] {8} [-]([a-fA-F0-9] {4} [-]) {3} [a-fA-F0-9] {12} $ "
isuuid = bool ( re . match ( uuidre , domstr ) )
try :
domain = None
try :
domain = conn . lookupByName ( domstr )
except Exception :
# In case the VM has a UUID or ID for a name
log . debug ( " Error looking up domain by name " , exc_info = True )
if isint :
domain = conn . lookupByID ( int ( domstr ) )
elif isuuid :
domain = conn . lookupByUUIDString ( domstr )
else :
raise
except libvirt . libvirtError as e :
2020-07-14 10:41:49 +03:00
fail ( _ ( " Could not find domain ' %(domain)s ' : %(error)s " ) % {
" domain " : domstr ,
" error " : str ( e ) ,
} )
2020-02-03 15:20:40 +03:00
state = domain . info ( ) [ 0 ]
active_xmlobj = None
inactive_xmlobj = Guest ( conn , parsexml = get_xmldesc ( domain ) )
if state != libvirt . VIR_DOMAIN_SHUTOFF :
active_xmlobj = inactive_xmlobj
inactive_xmlobj = Guest ( conn ,
parsexml = get_xmldesc ( domain , inactive = True ) )
return ( domain , inactive_xmlobj , active_xmlobj )
2020-09-17 09:44:01 +03:00
def fail_conflicting ( option1 , option2 ) :
# translators: option1 and option2 are command line options,
# e.g. -a or --disk
msg = _ ( " Cannot use %(option1)s and %(option2)s at the same time " ) % {
" option1 " : option1 ,
" option2 " : option2 ,
}
fail ( msg )
2018-12-07 11:28:48 +03:00
###########################
# bash completion helpers #
###########################
2019-01-07 03:01:35 +03:00
def _get_completer_parsers ( ) :
2019-06-14 03:56:16 +03:00
return VIRT_PARSERS + [ ParserCheck , ParserLocation ,
2020-09-15 02:05:58 +03:00
ParserUnattended , ParserInstall , ParserCloudInit , ParserXML ,
ParserOSVariant ]
2019-01-07 03:01:35 +03:00
2018-12-18 23:24:03 +03:00
def _virtparser_completer ( prefix , * * kwargs ) :
2018-12-07 11:28:48 +03:00
sub_options = [ ]
2019-01-07 03:01:35 +03:00
for parserclass in _get_completer_parsers ( ) :
2018-12-07 11:28:48 +03:00
if kwargs [ ' action ' ] . dest == parserclass . cli_arg_name :
# pylint: disable=protected-access
2019-05-15 20:06:29 +03:00
for virtarg in sorted ( parserclass . _virtargs ,
key = lambda p : p . nonregex_cliname ( ) ) :
sub_options . append ( virtarg . nonregex_cliname ( ) + " = " )
2018-12-07 11:28:48 +03:00
entered_options = prefix . split ( " , " )
for option in entered_options :
pos = option . find ( " = " )
if pos > 0 and option [ : pos + 1 ] in sub_options :
sub_options . remove ( option [ : pos + 1 ] )
return sub_options
2019-05-15 20:06:29 +03:00
def _completer_validator ( suboption , current_input ) :
"""
: param suboption : The virtarg . cliname we are checking for a match
: param current_input : The user typed string we are checking against .
So if the user types ' --disk path=foo,dev<TAB> ' ,
current_input == ' path=foo,dev '
2018-12-07 11:28:48 +03:00
2019-05-15 20:06:29 +03:00
For debugging here , ' export _ARC_DEBUG=1 ' . Now exceptions / printing
will be shown on stderr
"""
# e.g. for: --disk <TAB><TAB> (return all suboptions)
if current_input == " " :
2018-12-07 11:28:48 +03:00
return True
2019-05-15 20:06:29 +03:00
# e.g. for: --disk path=foo,<TAB><TAB> (return all suboptions)
# or: --disk path=foo,de<TAB>TAB> (return all 'de*' options)
current_option = current_input . rsplit ( " , " , 1 ) [ - 1 ]
return suboption . startswith ( current_option )
2018-12-07 11:28:48 +03:00
def autocomplete ( parser ) :
2018-12-18 23:24:03 +03:00
if " _ARGCOMPLETE " not in os . environ :
return
2018-12-18 23:36:04 +03:00
import argcomplete
2020-07-13 16:31:40 +03:00
import unittest . mock
2018-12-18 23:36:04 +03:00
2019-01-14 12:21:33 +03:00
parsernames = [ pclass . cli_flag_name ( ) for pclass in
2019-01-07 03:01:35 +03:00
_get_completer_parsers ( ) ]
2018-12-18 23:24:03 +03:00
# pylint: disable=protected-access
for action in parser . _actions :
for opt in action . option_strings :
if opt in parsernames :
action . completer = _virtparser_completer
break
2018-12-18 22:20:57 +03:00
kwargs = { " validator " : _completer_validator }
2020-07-18 01:46:54 +03:00
if xmlutil . in_testsuite ( ) :
2018-12-18 22:20:57 +03:00
import io
kwargs [ " output_stream " ] = io . BytesIO ( )
kwargs [ " exit_method " ] = sys . exit
2020-07-13 16:31:40 +03:00
# This fdopen hackery is to avoid argcomplete debug_stream behavior
# from taking over an fd that pytest wants to use
fake_fdopen = os . fdopen
2020-07-18 01:46:54 +03:00
if xmlutil . in_testsuite ( ) :
2020-07-13 16:31:40 +03:00
def fake_fdopen_cb ( * args , * * kwargs ) :
return sys . stderr
fake_fdopen = fake_fdopen_cb
with unittest . mock . patch . object ( os , " fdopen " , fake_fdopen ) :
try :
argcomplete . autocomplete ( parser , * * kwargs )
except SystemExit :
2020-07-18 01:46:54 +03:00
if xmlutil . in_testsuite ( ) :
2020-07-13 16:31:40 +03:00
output = kwargs [ " output_stream " ] . getvalue ( ) . decode ( " utf-8 " )
print ( output )
raise
2018-12-07 11:28:48 +03:00
2014-02-18 18:40:39 +04:00
###########################
# Common CLI option/group #
###########################
2013-03-18 01:06:52 +04:00
2014-02-12 18:57:40 +04:00
def add_connect_option ( parser , invoker = None ) :
if invoker == " virt-xml " :
parser . add_argument ( " -c " , " --connect " , metavar = " URI " ,
help = _ ( " Connect to hypervisor with libvirt URI " ) )
else :
parser . add_argument ( " --connect " , metavar = " URI " ,
help = _ ( " Connect to hypervisor with libvirt URI " ) )
2013-03-18 01:06:52 +04:00
2013-04-13 22:34:52 +04:00
2013-09-28 19:27:26 +04:00
def add_misc_options ( grp , prompt = False , replace = False ,
printxml = False , printstep = False ,
2014-02-06 04:09:26 +04:00
noreboot = False , dryrun = False ,
noautoconsole = False ) :
2013-09-28 19:27:26 +04:00
if prompt :
2014-01-21 03:04:23 +04:00
grp . add_argument ( " --prompt " , action = " store_true " ,
2014-01-19 02:01:43 +04:00
default = False , help = argparse . SUPPRESS )
2014-01-21 03:04:23 +04:00
grp . add_argument ( " --force " , action = " store_true " ,
2014-01-19 02:01:43 +04:00
default = False , help = argparse . SUPPRESS )
2013-09-28 19:27:26 +04:00
2014-02-06 04:09:26 +04:00
if noautoconsole :
2019-11-25 14:22:14 +03:00
grp . add_argument ( " --autoconsole " , default = " default " ,
help = _ ( " Configure guest console auto connect. Example: \n "
" --autoconsole text \n "
" --autoconsole graphical \n "
" --autoconsole none " ) )
grp . add_argument ( " --noautoconsole " , dest = " autoconsole " ,
action = " store_const " , const = " none " ,
2014-02-06 04:09:26 +04:00
help = _ ( " Don ' t automatically try to connect to the guest console " ) )
2013-09-28 19:27:26 +04:00
if noreboot :
2014-01-21 03:04:23 +04:00
grp . add_argument ( " --noreboot " , action = " store_true " ,
2013-09-28 19:27:26 +04:00
help = _ ( " Don ' t boot guest after completing install. " ) )
if replace :
2014-01-21 03:04:23 +04:00
grp . add_argument ( " --replace " , action = " store_true " ,
2013-09-28 19:27:26 +04:00
help = _ ( " Don ' t check name collision, overwrite any guest "
" with the same name. " ) )
if printxml :
2015-04-08 02:58:28 +03:00
print_kwargs = {
" dest " : " xmlonly " ,
" default " : False ,
" help " : _ ( " Print the generated domain XML rather than create "
" the guest. " ) ,
}
if printstep :
print_kwargs [ " nargs " ] = " ? "
print_kwargs [ " const " ] = " all "
else :
print_kwargs [ " action " ] = " store_true "
grp . add_argument ( " --print-xml " , * * print_kwargs )
2013-09-28 19:27:26 +04:00
if printstep :
2015-04-05 00:10:45 +03:00
# Back compat, argparse allows us to use --print-xml
# for everything.
2014-01-19 02:01:43 +04:00
grp . add_argument ( " --print-step " , dest = " xmlstep " ,
2015-04-05 00:10:45 +03:00
help = argparse . SUPPRESS )
2013-09-28 19:27:26 +04:00
if dryrun :
2014-01-19 02:01:43 +04:00
grp . add_argument ( " --dry-run " , action = " store_true " , dest = " dry " ,
2013-09-28 19:27:26 +04:00
help = _ ( " Run through install process, but do not "
" create devices or define the guest. " ) )
2015-04-12 02:25:46 +03:00
if prompt :
2018-10-01 20:14:43 +03:00
grp . add_argument ( " --check " , action = " append " ,
2015-04-12 02:25:46 +03:00
help = _ ( " Enable or disable validation checks. Example: \n "
" --check path_in_use=off \n "
2018-12-18 23:24:03 +03:00
" --check all=off " ) )
2014-01-21 03:04:23 +04:00
grp . add_argument ( " -q " , " --quiet " , action = " store_true " ,
2013-09-28 19:27:26 +04:00
help = _ ( " Suppress non-error output " ) )
2014-01-21 03:04:23 +04:00
grp . add_argument ( " -d " , " --debug " , action = " store_true " ,
2013-09-28 19:27:26 +04:00
help = _ ( " Print debugging information " ) )
2014-01-25 05:03:30 +04:00
def add_metadata_option ( grp ) :
2018-12-18 16:44:53 +03:00
ParserMetadata . register ( )
2018-10-01 20:14:43 +03:00
grp . add_argument ( " --metadata " , action = " append " ,
2014-01-25 05:03:30 +04:00
help = _ ( " Configure guest metadata. Ex: \n "
" --metadata name=foo,title= \" My pretty title \" ,uuid=... \n "
2018-12-18 23:24:03 +03:00
" --metadata description= \" My nice long description \" " ) )
2014-01-25 05:03:30 +04:00
2014-01-25 03:56:59 +04:00
def add_memory_option ( grp , backcompat = False ) :
2018-12-18 16:44:53 +03:00
ParserMemory . register ( )
2018-10-01 20:14:43 +03:00
grp . add_argument ( " --memory " , action = " append " ,
2014-01-25 03:56:59 +04:00
help = _ ( " Configure guest memory allocation. Ex: \n "
2014-07-05 00:42:24 +04:00
" --memory 1024 (in MiB) \n "
2019-05-11 21:03:46 +03:00
" --memory memory=1024,currentMemory=512 \n " ) )
2014-01-25 03:56:59 +04:00
if backcompat :
grp . add_argument ( " -r " , " --ram " , type = int , dest = " oldmemory " ,
help = argparse . SUPPRESS )
2014-01-26 05:20:55 +04:00
def vcpu_cli_options ( grp , backcompat = True , editexample = False ) :
2018-12-18 16:44:53 +03:00
# The order of the parser registration is important here!
ParserCPU . register ( )
ParserVCPU . register ( )
2018-10-01 20:14:43 +03:00
grp . add_argument ( " --vcpus " , action = " append " ,
2020-07-13 11:25:39 +03:00
help = _ ( " Number of vCPUs to configure for your guest. Ex: \n "
2013-03-18 01:06:52 +04:00
" --vcpus 5 \n "
2019-01-15 16:47:01 +03:00
" --vcpus 5,maxvcpus=10,cpuset=1-4,6,8 \n "
" --vcpus sockets=2,cores=4,threads=2 " ) )
2014-01-26 05:20:55 +04:00
extramsg = " --cpu host "
if editexample :
extramsg = " --cpu host-model,clearxml=yes "
2018-10-01 20:14:43 +03:00
grp . add_argument ( " --cpu " , action = " append " ,
2014-01-22 01:28:07 +04:00
help = _ ( " CPU model and features. Ex: \n "
2017-09-14 06:30:26 +03:00
" --cpu coreduo,+x2apic \n "
2018-12-18 23:24:03 +03:00
" --cpu host-passthrough \n " ) + extramsg )
2013-03-18 01:06:52 +04:00
if backcompat :
2014-01-19 02:01:43 +04:00
grp . add_argument ( " --check-cpu " , action = " store_true " ,
2014-01-21 03:04:23 +04:00
help = argparse . SUPPRESS )
2014-01-22 00:24:46 +04:00
grp . add_argument ( " --cpuset " , help = argparse . SUPPRESS )
2013-03-18 01:06:52 +04:00
2013-04-13 22:34:52 +04:00
2014-01-22 01:26:35 +04:00
def add_gfx_option ( devg ) :
2018-12-18 16:44:53 +03:00
ParserGraphics . register ( )
2014-01-22 01:26:35 +04:00
devg . add_argument ( " --graphics " , action = " append " ,
help = _ ( " Configure guest display settings. Ex: \n "
2019-05-12 15:50:32 +03:00
" --graphics spice \n "
" --graphics vnc,port=5901,listen=0.0.0.0 \n "
" --graphics none \n " ) )
2014-01-22 01:26:35 +04:00
2013-03-18 01:06:52 +04:00
def add_net_option ( devg ) :
2018-12-18 16:44:53 +03:00
ParserNetwork . register ( )
2014-01-21 03:04:23 +04:00
devg . add_argument ( " -w " , " --network " , action = " append " ,
2013-03-18 01:06:52 +04:00
help = _ ( " Configure a guest network interface. Ex: \n "
" --network bridge=mybr0 \n "
" --network network=my_libvirt_virtual_net \n "
2013-08-28 19:36:25 +04:00
" --network network=mynet,model=virtio,mac=00:11... \n "
2014-09-21 02:56:39 +04:00
" --network none \n "
2018-12-18 23:24:03 +03:00
" --network help " ) )
2013-03-18 01:06:52 +04:00
2013-04-13 22:34:52 +04:00
2014-02-05 21:32:53 +04:00
def add_device_options ( devg , sound_back_compat = False ) :
2018-12-18 16:44:53 +03:00
ParserController . register ( )
2014-01-21 03:04:23 +04:00
devg . add_argument ( " --controller " , action = " append " ,
2018-10-04 01:52:33 +03:00
help = _ ( " Configure a guest controller device. Ex: \n "
" --controller type=usb,model=qemu-xhci \n "
2018-12-18 23:24:03 +03:00
" --controller virtio-scsi \n " ) )
2018-12-18 16:44:53 +03:00
ParserInput . register ( )
2015-04-09 20:22:40 +03:00
devg . add_argument ( " --input " , action = " append " ,
help = _ ( " Configure a guest input device. Ex: \n "
" --input tablet \n "
2018-12-18 23:24:03 +03:00
" --input keyboard,bus=usb " ) )
2018-12-18 16:44:53 +03:00
ParserSerial . register ( )
2014-01-21 03:04:23 +04:00
devg . add_argument ( " --serial " , action = " append " ,
2018-12-18 23:24:03 +03:00
help = _ ( " Configure a guest serial device " ) )
2018-12-18 16:44:53 +03:00
ParserParallel . register ( )
2014-01-21 03:04:23 +04:00
devg . add_argument ( " --parallel " , action = " append " ,
2018-12-18 23:24:03 +03:00
help = _ ( " Configure a guest parallel device " ) )
2018-12-18 16:44:53 +03:00
ParserChannel . register ( )
2014-01-21 03:04:23 +04:00
devg . add_argument ( " --channel " , action = " append " ,
2018-12-18 23:24:03 +03:00
help = _ ( " Configure a guest communication channel " ) )
2018-12-18 16:44:53 +03:00
ParserConsole . register ( )
2014-01-21 03:04:23 +04:00
devg . add_argument ( " --console " , action = " append " ,
2013-03-18 01:06:52 +04:00
help = _ ( " Configure a text console connection between "
2018-12-18 23:24:03 +03:00
" the guest and host " ) )
2018-12-18 16:44:53 +03:00
ParserHostdev . register ( )
2014-09-20 22:29:34 +04:00
devg . add_argument ( " --hostdev " , action = " append " ,
help = _ ( " Configure physical USB/PCI/etc host devices "
2018-12-18 23:24:03 +03:00
" to be shared with the guest " ) )
2018-12-18 16:44:53 +03:00
# Back compat name
devg . add_argument ( " --host-device " , action = " append " , dest = " hostdev " ,
help = argparse . SUPPRESS )
ParserFilesystem . register ( )
2014-09-21 03:30:16 +04:00
devg . add_argument ( " --filesystem " , action = " append " ,
help = _ ( " Pass host directory to the guest. Ex: \n "
" --filesystem /my/source/dir,/dir/in/guest \n "
2018-12-18 23:24:03 +03:00
" --filesystem template_name,/,type=template " ) )
2014-09-21 03:30:16 +04:00
2018-12-18 16:44:53 +03:00
ParserSound . register ( )
2014-02-05 21:32:53 +04:00
# --sound used to be a boolean option, hence the nargs handling
sound_kwargs = {
" action " : " append " ,
" help " : _ ( " Configure guest sound device emulation " ) ,
}
if sound_back_compat :
sound_kwargs [ " nargs " ] = ' ? '
2018-12-18 23:24:03 +03:00
devg . add_argument ( " --sound " , * * sound_kwargs )
2014-02-05 21:32:53 +04:00
if sound_back_compat :
devg . add_argument ( " --soundhw " , action = " append " , dest = " sound " ,
2018-12-18 23:24:03 +03:00
help = argparse . SUPPRESS )
2014-02-05 21:32:53 +04:00
2018-12-18 16:44:53 +03:00
ParserWatchdog . register ( )
2014-01-21 03:04:23 +04:00
devg . add_argument ( " --watchdog " , action = " append " ,
2018-12-18 23:24:03 +03:00
help = _ ( " Configure a guest watchdog device " ) )
2018-12-18 16:44:53 +03:00
ParserVideo . register ( )
2014-01-21 03:04:23 +04:00
devg . add_argument ( " --video " , action = " append " ,
2018-12-18 23:24:03 +03:00
help = _ ( " Configure guest video hardware. " ) )
2018-12-18 16:44:53 +03:00
ParserSmartcard . register ( )
2014-01-21 03:04:23 +04:00
devg . add_argument ( " --smartcard " , action = " append " ,
2013-03-18 01:06:52 +04:00
help = _ ( " Configure a guest smartcard device. Ex: \n "
2018-12-18 23:24:03 +03:00
" --smartcard mode=passthrough " ) )
2018-12-18 16:44:53 +03:00
ParserRedir . register ( )
2014-01-21 03:04:23 +04:00
devg . add_argument ( " --redirdev " , action = " append " ,
2013-03-18 01:06:52 +04:00
help = _ ( " Configure a guest redirection device. Ex: \n "
2018-12-18 23:24:03 +03:00
" --redirdev usb,type=tcp,server=192.168.1.1:4000 " ) )
2018-12-18 16:44:53 +03:00
ParserMemballoon . register ( )
2014-01-21 03:04:23 +04:00
devg . add_argument ( " --memballoon " , action = " append " ,
2013-03-18 01:06:52 +04:00
help = _ ( " Configure a guest memballoon device. Ex: \n "
2018-12-18 23:24:03 +03:00
" --memballoon model=virtio " ) )
2018-12-18 16:44:53 +03:00
ParserTPM . register ( )
2014-01-21 03:04:23 +04:00
devg . add_argument ( " --tpm " , action = " append " ,
2013-06-26 05:45:07 +04:00
help = _ ( " Configure a guest TPM device. Ex: \n "
2018-12-18 23:24:03 +03:00
" --tpm /dev/tpm " ) )
2018-12-18 16:44:53 +03:00
ParserRNG . register ( )
2014-01-21 03:04:23 +04:00
devg . add_argument ( " --rng " , action = " append " ,
2013-09-18 17:29:29 +04:00
help = _ ( " Configure a guest RNG device. Ex: \n "
2018-12-18 23:24:03 +03:00
" --rng /dev/urandom " ) )
2018-12-18 16:44:53 +03:00
ParserPanic . register ( )
2014-01-21 03:04:23 +04:00
devg . add_argument ( " --panic " , action = " append " ,
2014-01-22 13:44:38 +04:00
help = _ ( " Configure a guest panic device. Ex: \n "
2018-12-18 23:24:03 +03:00
" --panic default " ) )
2021-07-26 23:14:30 +03:00
ParserShMem . register ( )
devg . add_argument ( " --shmem " , action = " append " ,
help = _ ( " Configure a guest shared memory device. Ex: \n "
" --shmem name=shmem0 " ) )
2018-12-18 16:44:54 +03:00
ParserMemdev . register ( )
2017-05-05 12:50:06 +03:00
devg . add_argument ( " --memdev " , action = " append " ,
help = _ ( " Configure a guest memory device. Ex: \n "
2019-05-10 20:42:19 +03:00
" --memdev dimm,target.size=1024 " ) )
2018-12-18 16:44:53 +03:00
ParserVsock . register ( )
2018-12-14 17:34:17 +03:00
devg . add_argument ( " --vsock " , action = " append " ,
help = _ ( " Configure guest vsock sockets. Ex: \n "
2019-05-12 16:23:07 +03:00
" --vsock cid.auto=yes \n "
" --vsock cid.address=7 " ) )
2020-07-07 10:55:53 +03:00
ParserIommu . register ( )
devg . add_argument ( " --iommu " , action = " append " ,
help = _ ( " Configure an IOMMU device. Ex: \n "
" --iommu model=intel,driver.aw_bits=48 " ) )
2013-03-18 01:06:52 +04:00
2013-04-13 22:34:52 +04:00
2014-01-22 01:26:35 +04:00
def add_guest_xml_options ( geng ) :
2019-06-04 10:50:18 +03:00
ParserIOThreads . register ( )
geng . add_argument ( " --iothreads " , action = " append " ,
2019-06-04 21:17:45 +03:00
help = _ ( " Set domain <iothreads> and <iothreadids> configuration. " ) )
2019-06-04 10:50:18 +03:00
2019-05-16 00:49:58 +03:00
ParserSeclabel . register ( )
geng . add_argument ( " --seclabel " , " --security " , action = " append " ,
help = _ ( " Set domain seclabel configuration. " ) )
2018-12-18 16:44:53 +03:00
2019-07-21 16:37:37 +03:00
ParserKeyWrap . register ( )
geng . add_argument ( " --keywrap " , action = " append " ,
2019-07-29 01:11:04 +03:00
help = _ ( " Set guest to perform the S390 cryptographic "
" key management operations. " ) )
2019-07-21 16:37:37 +03:00
2018-12-18 16:44:53 +03:00
ParserCputune . register ( )
2018-10-01 20:14:43 +03:00
geng . add_argument ( " --cputune " , action = " append " ,
2018-12-18 23:24:03 +03:00
help = _ ( " Tune CPU parameters for the domain process. " ) )
2018-12-18 16:44:53 +03:00
ParserNumatune . register ( )
2018-10-01 20:14:43 +03:00
geng . add_argument ( " --numatune " , action = " append " ,
2018-12-18 23:24:03 +03:00
help = _ ( " Tune NUMA policy for the domain process. " ) )
2018-12-18 16:44:53 +03:00
ParserMemtune . register ( )
2014-02-25 06:02:31 +04:00
geng . add_argument ( " --memtune " , action = " append " ,
2018-12-18 23:24:03 +03:00
help = _ ( " Tune memory policy for the domain process. " ) )
2018-12-18 16:44:53 +03:00
ParserBlkiotune . register ( )
2014-02-06 18:41:00 +04:00
geng . add_argument ( " --blkiotune " , action = " append " ,
2018-12-18 23:24:03 +03:00
help = _ ( " Tune blkio policy for the domain process. " ) )
2018-12-18 16:44:53 +03:00
ParserMemoryBacking . register ( )
2014-03-22 20:28:23 +04:00
geng . add_argument ( " --memorybacking " , action = " append " ,
2014-07-15 17:25:20 +04:00
help = _ ( " Set memory backing policy for the domain process. Ex: \n "
2018-12-18 23:24:03 +03:00
" --memorybacking hugepages=on " ) )
2018-12-18 16:44:53 +03:00
ParserFeatures . register ( )
2018-10-01 20:14:43 +03:00
geng . add_argument ( " --features " , action = " append " ,
2014-07-15 17:25:20 +04:00
help = _ ( " Set domain <features> XML. Ex: \n "
" --features acpi=off \n "
2019-05-12 03:03:10 +03:00
" --features apic=on,apic.eoi=on " ) )
2018-12-18 16:44:53 +03:00
ParserClock . register ( )
2018-10-01 20:14:43 +03:00
geng . add_argument ( " --clock " , action = " append " ,
2014-07-15 17:25:20 +04:00
help = _ ( " Set domain <clock> XML. Ex: \n "
2018-12-18 23:24:03 +03:00
" --clock offset=localtime,rtc_tickpolicy=catchup " ) )
2018-12-18 16:44:53 +03:00
ParserPM . register ( )
2018-10-01 20:14:43 +03:00
geng . add_argument ( " --pm " , action = " append " ,
2018-12-18 23:24:03 +03:00
help = _ ( " Configure VM power management features " ) )
2018-12-18 16:44:53 +03:00
ParserEvents . register ( )
2018-10-01 20:14:43 +03:00
geng . add_argument ( " --events " , action = " append " ,
2018-12-18 23:24:03 +03:00
help = _ ( " Configure VM lifecycle management policy " ) )
2018-12-18 16:44:53 +03:00
ParserResource . register ( )
2014-06-04 06:08:05 +04:00
geng . add_argument ( " --resource " , action = " append " ,
2018-12-18 23:24:03 +03:00
help = _ ( " Configure VM resource partitioning (cgroups) " ) )
2018-12-18 16:44:53 +03:00
ParserSysinfo . register ( )
2016-09-07 01:12:20 +03:00
geng . add_argument ( " --sysinfo " , action = " append " ,
help = _ ( " Configure SMBIOS System Information. Ex: \n "
" --sysinfo host \n "
2019-05-13 01:35:37 +03:00
" --sysinfo bios.vendor=MyVendor,bios.version=1.2.3,... \n " ) )
2018-12-18 16:44:53 +03:00
ParserQemuCLI . register ( )
2017-03-06 04:45:33 +03:00
geng . add_argument ( " --qemu-commandline " , action = " append " ,
2020-07-13 11:25:39 +03:00
help = _ ( " Pass arguments directly to the QEMU emulator. Ex: \n "
2017-03-06 04:45:33 +03:00
" --qemu-commandline= ' -display gtk,gl=on ' \n "
2018-12-18 23:24:03 +03:00
" --qemu-commandline env=DISPLAY=:0.1 " ) )
2014-01-22 01:26:35 +04:00
2019-06-11 18:41:57 +03:00
ParserLaunchSecurity . register ( )
geng . add_argument ( " --launchSecurity " , " --launchsecurity " , action = " append " ,
help = _ ( " Configure VM launch security (e.g. SEV memory encryption). Ex: \n "
" --launchSecurity type=sev,cbitpos=47,reducedPhysBits=1,policy=0x0001,dhCert=BASE64CERT \n "
" --launchSecurity sev " ) )
2014-01-22 01:26:35 +04:00
2014-02-11 03:13:42 +04:00
def add_boot_options ( insg ) :
2018-12-18 16:44:53 +03:00
ParserBoot . register ( )
2018-10-01 20:14:43 +03:00
insg . add_argument ( " --boot " , action = " append " ,
2014-02-11 03:13:42 +04:00
help = _ ( " Configure guest boot settings. Ex: \n "
" --boot hd,cdrom,menu=on \n "
2018-12-18 23:24:03 +03:00
" --boot init=/sbin/init (for containers) " ) )
2018-12-18 16:44:53 +03:00
ParserIdmap . register ( )
2018-10-01 20:14:43 +03:00
insg . add_argument ( " --idmap " , action = " append " ,
2014-02-11 18:08:55 +04:00
help = _ ( " Enable user namespace for LXC container. Ex: \n "
2019-05-12 02:50:09 +03:00
" --idmap uid.start=0,uid.target=1000,uid.count=10 " ) )
2014-01-22 01:26:35 +04:00
2014-01-26 21:25:18 +04:00
def add_disk_option ( stog , editexample = False ) :
2018-12-18 16:44:53 +03:00
ParserDisk . register ( )
2014-01-26 21:25:18 +04:00
editmsg = " "
if editexample :
editmsg + = " \n --disk cache= (unset cache) "
2014-01-22 01:26:35 +04:00
stog . add_argument ( " --disk " , action = " append " ,
help = _ ( " Specify storage with various options. Ex. \n "
2014-06-17 05:33:14 +04:00
" --disk size=10 (new 10GiB image in default location) \n "
2014-12-10 21:19:19 +03:00
" --disk /my/existing/disk,cache=none \n "
2014-01-22 18:06:35 +04:00
" --disk device=cdrom,bus=scsi \n "
2018-12-18 23:24:03 +03:00
" --disk=? " ) + editmsg )
2014-01-22 01:26:35 +04:00
2014-01-19 22:56:06 +04:00
2019-01-08 20:44:53 +03:00
def add_os_variant_option ( parser , virtinstall ) :
osg = parser . add_argument_group ( _ ( " OS options " ) )
if virtinstall :
msg = _ ( " The OS being installed in the guest. " )
else :
msg = _ ( " The OS installed in the guest. " )
msg + = " \n "
2020-07-13 11:25:39 +03:00
msg + = _ ( " This is used for deciding optimal defaults like VirtIO. \n "
2019-01-08 20:44:53 +03:00
" Example values: fedora29, rhel7.0, win10, ... \n "
" See ' osinfo-query os ' for a full list. " )
2020-09-15 01:12:41 +03:00
osg . add_argument ( " --os-variant " , " --osinfo " , help = msg )
2019-01-08 20:44:53 +03:00
return osg
2020-09-10 20:52:07 +03:00
def add_xml_option ( grp ) :
grp . add_argument ( " --xml " , action = " append " , default = [ ] ,
help = _ ( " Perform raw XML XPath options on the final XML. Example: \n "
" --xml ./cpu/@mode=host-passthrough \n "
" --xml ./devices/disk[2]/serial=new-serial \n "
" --xml xpath.delete=./clock " ) )
2013-03-18 01:06:52 +04:00
#############################################
# CLI complex parsing helpers #
# (for options like --disk, --network, etc. #
#############################################
2015-11-18 21:59:15 +03:00
def _raw_on_off_convert ( s ) :
tvalues = [ " y " , " yes " , " 1 " , " true " , " t " , " on " ]
fvalues = [ " n " , " no " , " 0 " , " false " , " f " , " off " ]
s = ( s or " " ) . lower ( )
if s in tvalues :
return True
elif s in fvalues :
return False
return None
2014-02-05 01:16:39 +04:00
2015-11-18 21:59:15 +03:00
def _on_off_convert ( key , val ) :
if val is None :
2014-02-05 01:16:39 +04:00
return None
2015-11-18 21:59:15 +03:00
val = _raw_on_off_convert ( val )
2014-02-05 01:16:39 +04:00
if val is not None :
return val
2021-10-04 22:38:24 +03:00
fail ( _ ( " %(key)s must be ' yes ' or ' no ' " ) % { " key " : key } )
2014-02-05 01:16:39 +04:00
2019-05-15 20:36:41 +03:00
class _SuboptCheckerClass :
"""
Used by the test suite to ensure we actually test all cli suboptions
"""
def __init__ ( self ) :
self . _all = set ( )
self . _seen = set ( )
def add_all ( self , name ) :
self . _all . add ( name )
def add_seen ( self , name ) :
self . _seen . add ( name )
def get_unseen ( self ) :
return self . _all - self . _seen
_SuboptChecker = _SuboptCheckerClass ( )
2017-10-20 23:47:56 +03:00
class _VirtCLIArgumentStatic ( object ) :
2016-06-14 21:37:21 +03:00
"""
2017-10-20 23:47:56 +03:00
Helper class to hold all of the static data we need for knowing
how to parse a cli subargument , like - - disk path = , or - - network mac = .
2016-06-14 21:37:21 +03:00
@cliname : The command line option name , ' path ' for path = FOO
2019-05-10 19:10:41 +03:00
@propname : The virtinst API attribute name the cliargument maps to .
@cb : Rather than set a virtinst object property directly , use
this callback instead . It should have the signature :
cb ( parser , inst , val , virtarg )
2016-06-14 21:37:21 +03:00
@ignore_default : If the value passed on the cli is ' default ' , don ' t
do anything .
@can_comma : If True , this option is expected to have embedded commas .
After the parser sees this option , it will iterate over the
option string until it finds another known argument name :
everything prior to that argument name is considered part of
the value of this option , ' = ' included . Should be used sparingly .
@is_onoff : The value expected on the cli is on / off or yes / no , convert
it to true / false .
@lookup_cb : If specified , use this function for performing match
lookups .
@find_inst_cb : If specified , this can be used to return a different
' inst ' to check and set attributes against . For example ,
2018-03-20 19:18:35 +03:00
DeviceDisk has multiple seclabel children , this provides a hook
2016-06-14 21:37:21 +03:00
to lookup the specified child object .
"""
2019-05-15 20:36:41 +03:00
def __init__ ( self , cliname , propname , parent_cliname ,
2017-10-20 23:47:56 +03:00
cb = None , can_comma = None ,
2019-05-11 01:46:54 +03:00
ignore_default = False , is_onoff = False ,
2019-05-10 22:56:26 +03:00
lookup_cb = - 1 , find_inst_cb = None ) :
2017-10-20 23:47:56 +03:00
self . cliname = cliname
2019-05-10 22:04:47 +03:00
self . propname = propname
2017-10-20 23:47:56 +03:00
self . cb = cb
self . can_comma = can_comma
self . ignore_default = ignore_default
self . is_onoff = is_onoff
self . lookup_cb = lookup_cb
self . find_inst_cb = find_inst_cb
2019-05-15 20:36:41 +03:00
self . _parent_cliname = parent_cliname
self . _aliases = [ ]
2017-10-20 23:47:56 +03:00
2019-05-10 19:10:41 +03:00
if not self . propname and not self . cb :
2020-07-18 01:58:00 +03:00
raise xmlutil . DevError ( " propname or cb must be specified. " )
2019-04-09 20:35:20 +03:00
2019-05-10 22:04:47 +03:00
if not self . propname and self . lookup_cb == - 1 :
2020-07-18 01:58:00 +03:00
raise xmlutil . DevError (
2019-05-10 22:04:47 +03:00
" cliname= %s propname is None but lookup_cb is not specified. "
" Even if a ' cb ' is passed, ' propname ' is still used for "
" device lookup for virt-xml --edit. \n \n If cb is just "
2019-05-16 14:13:09 +03:00
" a converter function for a single propname, then set "
2019-05-10 22:04:47 +03:00
" both propname and cb. If this cliname is truly "
" not backed by a single propname, set lookup_cb=None or "
" better yet implement a lookup_cb. This message is here "
" to ensure propname isn ' t omitted without understanding "
" the distinction. " % self . cliname )
if self . lookup_cb == - 1 :
self . lookup_cb = None
2019-05-15 20:36:41 +03:00
_SuboptChecker . add_all ( self . _testsuite_argcheck_name ( self . cliname ) )
def _testsuite_argcheck_name ( self , cliname ) :
if not self . _parent_cliname :
return " sharedoption %s " % cliname
return " -- %s %s " % ( self . _parent_cliname , cliname )
def set_aliases ( self , aliases ) :
self . _aliases = aliases
for alias in self . _aliases :
_SuboptChecker . add_all ( self . _testsuite_argcheck_name ( alias ) )
2019-04-09 20:35:20 +03:00
2019-05-15 20:06:29 +03:00
def nonregex_cliname ( self ) :
return self . cliname . replace ( " [0-9]* " , " " )
2019-05-15 21:43:37 +03:00
def match_name ( self , userstr ) :
2016-06-14 02:35:21 +03:00
"""
2019-05-15 21:43:37 +03:00
Return True if the passed user string matches this
2016-06-14 21:37:21 +03:00
VirtCLIArgument . So for an option like - - foo bar = X , this
checks if we are the parser for ' bar '
2016-06-14 14:37:21 +03:00
"""
2019-06-08 01:21:24 +03:00
for cliname in [ self . cliname ] + xmlutil . listify ( self . _aliases ) :
2019-05-15 21:43:37 +03:00
if " [ " in cliname :
ret = re . match ( " ^ %s $ " % cliname . replace ( " . " , r " \ . " ) , userstr )
else :
ret = ( cliname == userstr )
if ret :
2019-05-15 20:36:41 +03:00
_SuboptChecker . add_seen ( self . _testsuite_argcheck_name ( cliname ) )
2016-06-14 21:37:21 +03:00
return True
return False
2016-06-14 14:37:21 +03:00
2017-10-20 23:47:56 +03:00
class _VirtCLIArgument ( object ) :
"""
A class that combines the static parsing data _VirtCLIArgumentStatic
with actual values passed on the command line .
"""
def __init__ ( self , virtarg , key , val ) :
2016-06-14 14:37:21 +03:00
"""
2016-06-14 21:37:21 +03:00
Instantiate a VirtCLIArgument with the actual key = val pair
from the command line .
2016-06-14 02:35:21 +03:00
"""
2014-01-19 22:56:06 +04:00
if val is None :
2019-05-10 22:56:26 +03:00
# When a command line tuple option has no value set, say
# --network bridge=br0,model=virtio
# is instead called
# --network bridge=br0,model
# We error that 'model' didn't have a value
raise RuntimeError ( " Option ' %s ' had no value set. " % key )
2014-01-19 19:37:14 +04:00
if val == " " :
val = None
2017-10-20 23:47:56 +03:00
if virtarg . is_onoff :
2016-06-14 21:37:21 +03:00
val = _on_off_convert ( key , val )
2016-06-14 18:38:53 +03:00
2016-06-14 21:37:21 +03:00
self . val = val
self . key = key
2017-10-20 23:47:56 +03:00
self . _virtarg = virtarg
# For convenience
2019-05-10 19:10:41 +03:00
self . propname = virtarg . propname
2017-10-20 23:47:56 +03:00
self . cliname = virtarg . cliname
2014-01-19 22:56:06 +04:00
2019-05-10 19:27:23 +03:00
def parse_param ( self , parser , inst ) :
2016-06-13 21:16:36 +03:00
"""
2016-06-14 02:35:21 +03:00
Process the cli param against the pass inst .
So if we are VirtCLIArgument for - - disk device = , and the user
2018-05-21 22:42:50 +03:00
specified - - disk device = foo , we were instantiated with
2016-06-14 21:37:21 +03:00
key = device val = foo , so set inst . device = foo
2016-06-13 21:16:36 +03:00
"""
2017-10-20 23:47:56 +03:00
if self . val == " default " and self . _virtarg . ignore_default :
2016-06-14 18:38:53 +03:00
return
2014-01-19 19:37:14 +04:00
2017-10-20 23:47:56 +03:00
if self . _virtarg . find_inst_cb :
inst = self . _virtarg . find_inst_cb ( parser ,
2019-07-02 19:56:15 +03:00
inst , self . val , self ,
can_edit = True )
2016-06-15 00:29:54 +03:00
2014-01-19 22:56:06 +04:00
try :
2019-05-10 19:10:41 +03:00
if self . propname :
2019-06-08 01:21:24 +03:00
xmlutil . get_prop_path ( inst , self . propname )
2019-06-10 21:15:50 +03:00
except AttributeError : # pragma: no cover
2020-09-15 19:33:31 +03:00
msg = " obj= %s does not have member= %s " % ( inst , self . propname )
raise xmlutil . DevError ( msg ) from None
2014-01-19 22:56:06 +04:00
2017-10-20 23:47:56 +03:00
if self . _virtarg . cb :
self . _virtarg . cb ( parser , inst , self . val , self )
2014-01-19 22:56:06 +04:00
else :
2019-06-08 01:21:24 +03:00
xmlutil . set_prop_path ( inst , self . propname , self . val )
2013-03-18 01:06:52 +04:00
2016-06-14 21:37:21 +03:00
def lookup_param ( self , parser , inst ) :
2016-06-13 02:48:16 +03:00
"""
2016-06-14 02:35:21 +03:00
See if the passed value matches our Argument , like via virt - xml
So if this Argument is for - - disk device = , and the user
2016-06-14 21:37:21 +03:00
specified virt - xml - - edit device = floppy - - disk . . . , we were
instantiated with key = device val = floppy , so return
' inst.device == floppy '
2016-06-13 02:48:16 +03:00
"""
2019-05-10 19:10:41 +03:00
if not self . propname and not self . _virtarg . lookup_cb :
2016-06-13 02:48:16 +03:00
raise RuntimeError (
_ ( " Don ' t know how to match device type ' %(device_type)s ' "
" property ' %(property_name)s ' " ) %
2018-03-21 01:59:14 +03:00
{ " device_type " : getattr ( inst , " DEVICE_TYPE " , " " ) ,
2016-06-14 21:37:21 +03:00
" property_name " : self . key } )
2016-06-13 02:48:16 +03:00
2017-10-20 23:47:56 +03:00
if self . _virtarg . find_inst_cb :
inst = self . _virtarg . find_inst_cb ( parser ,
2019-07-02 19:56:15 +03:00
inst , self . val , self ,
can_edit = False )
2016-06-15 00:29:54 +03:00
if not inst :
return False
2017-10-20 23:47:56 +03:00
if self . _virtarg . lookup_cb :
return self . _virtarg . lookup_cb ( parser ,
inst , self . val , self )
2022-01-25 21:43:58 +03:00
# To reliably compare between CLI style values and internal
# XML API values, we need to set the CLI value on a copy of the
# object we are checking, read back the result, and compare with that
xmlval = xmlutil . get_prop_path ( inst , self . propname )
setter = inst . __class__ ( inst . conn , parsexml = inst . get_xml ( ) )
xmlutil . set_prop_path ( setter , self . propname , self . val )
clival = xmlutil . get_prop_path ( setter , self . propname )
return xmlval == clival
2016-06-13 21:16:36 +03:00
def parse_optstr_tuples ( optstr ) :
"""
Parse the command string into an ordered list of tuples . So
a string like - - disk path = foo , size = 5 , path = bar will end up like
[ ( " path " , " foo " ) , ( " size " , " 5 " ) , ( " path " , " bar " ) ]
"""
argsplitter = shlex . shlex ( optstr or " " , posix = True )
argsplitter . commenters = " "
argsplitter . whitespace = " , "
argsplitter . whitespace_split = True
ret = [ ]
for opt in list ( argsplitter ) :
2018-02-14 03:04:08 +03:00
if " = " in opt :
2016-06-13 21:16:36 +03:00
cliname , val = opt . split ( " = " , 1 )
else :
cliname = opt
val = None
ret . append ( ( cliname , val ) )
return ret
2013-03-18 01:06:52 +04:00
2016-06-13 21:16:36 +03:00
2016-06-14 14:37:21 +03:00
def _parse_optstr_to_dict ( optstr , virtargs , remove_first ) :
"""
Parse the passed argument string into an OrderedDict WRT
the passed list of VirtCLIArguments and their special handling .
2013-04-13 22:34:52 +04:00
2016-06-14 14:37:21 +03:00
So for - - disk path = foo , size = 5 , optstr is ' path=foo,size=5 ' , and
we return { " path " : " foo " , " size " : " 5 " }
"""
2016-06-14 20:54:37 +03:00
optdict = collections . OrderedDict ( )
2016-06-14 14:37:21 +03:00
opttuples = parse_optstr_tuples ( optstr )
2014-01-19 22:56:06 +04:00
2016-06-14 14:37:21 +03:00
def _lookup_virtarg ( cliname ) :
for virtarg in virtargs :
if virtarg . match_name ( cliname ) :
return virtarg
2016-06-14 20:54:37 +03:00
def _consume_comma_arg ( commaopt ) :
while opttuples :
cliname , val = opttuples [ 0 ]
if _lookup_virtarg ( cliname ) :
# Next tuple is for an actual virtarg
break
# Next tuple is a continuation of the comma argument,
# sum it up
opttuples . pop ( 0 )
commaopt [ 1 ] + = " , " + cliname
if val :
commaopt [ 1 ] + = " = " + val
return commaopt
2016-06-14 14:37:21 +03:00
# Splice in remove_first names upfront
for idx , ( cliname , val ) in enumerate ( opttuples ) :
if val is not None or not remove_first :
break
opttuples [ idx ] = ( remove_first . pop ( 0 ) , cliname )
2016-06-14 20:54:37 +03:00
while opttuples :
cliname , val = opttuples . pop ( 0 )
2016-06-14 14:37:21 +03:00
virtarg = _lookup_virtarg ( cliname )
2016-06-14 20:54:37 +03:00
if not virtarg :
optdict [ cliname ] = val
2016-06-14 14:37:21 +03:00
continue
2013-09-28 04:16:35 +04:00
2016-06-14 20:54:37 +03:00
if virtarg . can_comma :
commaopt = _consume_comma_arg ( [ cliname , val ] )
2019-05-10 22:42:05 +03:00
cliname = commaopt [ 0 ]
val = commaopt [ 1 ]
optdict [ cliname ] = val
2013-03-18 01:06:52 +04:00
2016-06-14 20:54:37 +03:00
return optdict
2013-03-18 01:06:52 +04:00
2013-04-13 22:34:52 +04:00
2019-05-10 20:17:30 +03:00
class _InitClass ( type ) :
""" Metaclass for providing the _init_class function.
2018-12-18 16:44:56 +03:00
This allows the customisation of class creation . Similar to
2019-05-10 20:17:30 +03:00
' __init_subclass__ ' ( see https : / / www . python . org / dev / peps / pep - 0487 / ) ,
but without giving us an explicit dep on python 3.6
2018-12-18 16:44:56 +03:00
"""
def __new__ ( cls , * args , * * kwargs ) :
if len ( args ) != 3 :
2019-06-10 21:15:50 +03:00
return super ( ) . __new__ ( cls , * args ) # pragma: no cover
2018-12-18 16:44:56 +03:00
name , bases , ns = args
2019-05-10 20:17:30 +03:00
init = ns . get ( ' _init_class ' )
2018-12-18 16:44:56 +03:00
if isinstance ( init , types . FunctionType ) :
2019-06-10 21:15:50 +03:00
raise RuntimeError ( # pragma: no cover
" _init_class must be a @classmethod " )
2018-12-18 16:44:56 +03:00
self = super ( ) . __new__ ( cls , name , bases , ns )
2019-05-10 20:17:30 +03:00
self . _init_class ( * * kwargs ) # pylint: disable=protected-access
2019-05-11 01:46:54 +03:00
# Check for leftover aliases
if self . aliases :
2020-07-18 01:58:00 +03:00
raise xmlutil . DevError (
" class= %s leftover aliases= %s " % ( self , self . aliases ) )
2018-12-18 16:44:56 +03:00
return self
2019-05-10 20:17:30 +03:00
class VirtCLIParser ( metaclass = _InitClass ) :
2013-03-18 01:06:52 +04:00
"""
2014-01-19 22:56:06 +04:00
Parse a compound arg string like - - option foo = bar , baz = 12. This is
the desired interface to VirtCLIArgument and VirtCLIOptionString .
2016-06-13 23:30:29 +03:00
A command line argument like - - disk just extends this interface
and calls add_arg a bunch to register subarguments like path = ,
size = , etc . See existing impls examples of how to do all sorts of
crazy stuff .
Class parameters :
2019-05-10 20:03:27 +03:00
@guest_propname : The property name in the Guest class that tracks
the object type that backs this parser . For example , the - - sound
option maps to DeviceSound , which on the guest class is at
guest . devices . sound , so guest_propname = " devices.sound "
2016-06-14 14:37:21 +03:00
@remove_first : List of parameters to peel off the front of the
option string , and store in the optdict . So :
remove_first = [ " char_type " ] for - - serial pty , foo = bar
2017-08-05 09:39:32 +03:00
maps to { " char_type " , " pty " , " foo " : " bar " }
2017-03-09 01:03:01 +03:00
@stub_none : If the parsed option string is just ' none ' , make it a no - op .
This helps us be backwards compatible : for example , - - rng none is
a no - op , but one day we decide to add an rng device by default to
certain VMs , and - - rng none is extended to handle that . - - rng none
can be added to users command lines and it will give the expected
results regardless of the virt - install version .
2016-06-14 01:50:31 +03:00
@cli_arg_name : The command line argument this maps to , so
" hostdev " for - - hostdev
2013-03-18 01:06:52 +04:00
"""
2019-05-10 20:03:27 +03:00
guest_propname = None
2016-06-13 23:30:29 +03:00
remove_first = None
2017-03-09 01:03:01 +03:00
stub_none = True
2016-06-14 01:50:31 +03:00
cli_arg_name = None
2016-06-14 14:37:21 +03:00
_virtargs = [ ]
2019-05-11 01:46:54 +03:00
aliases = { }
2019-11-21 00:40:00 +03:00
supports_clearxml = True
2016-06-13 23:30:29 +03:00
@classmethod
2019-05-15 20:36:41 +03:00
def add_arg ( cls , cliname , propname , * args , * * kwargs ) :
2016-06-13 23:30:29 +03:00
"""
Add a VirtCLIArgument for this class .
2019-05-15 20:36:41 +03:00
: param skip_testsuite_tracking : Special argument handled here . If True ,
if means the argument is shared among multiple cli commands .
Don ' t insist that each instance has full testsuite coverage.
2016-06-13 23:30:29 +03:00
"""
2016-06-14 14:37:21 +03:00
if not cls . _virtargs :
2019-11-21 00:40:00 +03:00
cls . _virtargs = [ ]
if cls . supports_clearxml :
clearxmlvirtarg = _VirtCLIArgumentStatic (
" clearxml " , None , None ,
cb = cls . _clearxml_cb , lookup_cb = None ,
is_onoff = True )
cls . _virtargs . append ( clearxmlvirtarg )
2019-05-15 20:36:41 +03:00
parent_cliname = cls . cli_arg_name
if kwargs . pop ( " skip_testsuite_tracking " , False ) :
parent_cliname = None
virtarg = _VirtCLIArgumentStatic ( cliname , propname , parent_cliname ,
* args , * * kwargs )
2019-05-11 01:46:54 +03:00
if virtarg . cliname in cls . aliases :
2019-06-08 01:21:24 +03:00
virtarg . set_aliases ( xmlutil . listify ( cls . aliases . pop ( virtarg . cliname ) ) )
2019-05-11 01:46:54 +03:00
cls . _virtargs . append ( virtarg )
2013-03-18 01:06:52 +04:00
2019-01-14 12:21:33 +03:00
@classmethod
def cli_flag_name ( cls ) :
return " -- " + cls . cli_arg_name . replace ( " _ " , " - " )
2016-06-14 14:37:21 +03:00
@classmethod
2016-06-14 18:38:53 +03:00
def print_introspection ( cls ) :
"""
Print out all _param names , triggered via ex . - - disk help
"""
2019-05-11 01:21:40 +03:00
def _sortkey ( virtarg ) :
prefix = " "
if virtarg . cliname == " clearxml " :
prefix = " 0 "
if virtarg . cliname . startswith ( " address. " ) :
prefix = " 1 "
return prefix + virtarg . cliname
2019-01-14 12:21:33 +03:00
print ( " %s options: " % cls . cli_flag_name ( ) )
2019-05-11 01:21:40 +03:00
for arg in sorted ( cls . _virtargs , key = _sortkey ) :
2017-05-05 21:16:59 +03:00
print ( " %s " % arg . cliname )
2017-07-10 14:48:30 +03:00
print ( " " )
2016-06-14 18:38:53 +03:00
2018-03-21 02:38:18 +03:00
@classmethod
def lookup_prop ( cls , obj ) :
"""
For the passed obj , return the equivalent of
2019-05-10 20:03:27 +03:00
getattr ( obj , cls . guest_propname ) , but handle ' . ' in the guest_propname
2018-03-21 02:38:18 +03:00
"""
2019-05-10 20:03:27 +03:00
if not cls . guest_propname :
2019-07-02 21:07:16 +03:00
return None # pragma: no cover
2019-06-08 01:21:24 +03:00
return xmlutil . get_prop_path ( obj , cls . guest_propname )
2018-03-21 02:38:18 +03:00
@classmethod
def prop_is_list ( cls , obj ) :
inst = cls . lookup_prop ( obj )
return isinstance ( inst , list )
2018-12-18 16:44:53 +03:00
@classmethod
def register ( cls ) :
# register the parser class only once
if cls not in VIRT_PARSERS :
VIRT_PARSERS . append ( cls )
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
2019-05-15 20:36:41 +03:00
""" This method also terminates the super() chain """
2016-06-14 18:38:53 +03:00
2019-06-14 00:37:26 +03:00
def __init__ ( self , optstr , guest = None , editing = None ) :
2016-06-14 18:38:53 +03:00
self . optstr = optstr
2019-05-11 00:20:21 +03:00
self . guest = guest
2019-06-14 00:37:26 +03:00
self . editing = editing
2016-06-14 18:38:53 +03:00
self . optdict = _parse_optstr_to_dict ( self . optstr ,
2019-06-08 01:21:24 +03:00
self . _virtargs , xmlutil . listify ( self . remove_first ) [ : ] )
2016-06-14 18:38:53 +03:00
def _clearxml_cb ( self , inst , val , virtarg ) :
2016-06-13 23:05:56 +03:00
"""
Callback that handles virt - xml clearxml = yes | no magic
"""
2019-05-10 20:03:27 +03:00
if not self . guest_propname :
raise RuntimeError ( " Don ' t know how to clearxml for %s " %
2019-01-14 12:21:33 +03:00
self . cli_flag_name ( ) )
2016-06-13 23:05:56 +03:00
if val is not True :
return
2014-01-26 00:44:14 +04:00
2016-06-13 23:05:56 +03:00
# If there's any opts remaining, leave the root stub element
2016-06-14 14:37:21 +03:00
# in place with leave_stub=True, so virt-xml updates are done
# in place.
2016-06-13 23:05:56 +03:00
#
2016-06-14 14:37:21 +03:00
# Example: --edit --cpu clearxml=yes should remove the <cpu>
2016-06-13 23:05:56 +03:00
# block. But --edit --cpu clearxml=yes,model=foo should leave
# a <cpu> stub in place, so that it gets model=foo in place,
2016-10-25 18:35:47 +03:00
# otherwise the newly created cpu block gets appended to the
2016-06-13 23:05:56 +03:00
# end of the domain XML, which gives an ugly diff
2018-03-21 12:32:36 +03:00
inst . clear ( leave_stub = ( " , " in self . optstr ) )
2016-06-14 21:37:21 +03:00
2019-05-10 20:03:27 +03:00
def _make_find_inst_cb ( self , cliarg , list_propname ) :
2018-01-26 20:50:44 +03:00
"""
Create a callback used for find_inst_cb command line lookup .
: param cliarg : The cliarg string that is followed by an index .
Example , for - - disk seclabel [ 0 - 9 ] * mapping , this is ' seclabel '
2019-05-10 20:03:27 +03:00
: param list_propname : The property name on the virtinst object that
2018-01-26 20:50:44 +03:00
this parameter maps too . For the seclabel example , we want
disk . seclabels , so this value is ' seclabels '
"""
def cb ( inst , val , virtarg , can_edit ) :
ignore = val
num = 0
2018-09-29 20:59:19 +03:00
reg = re . search ( r " %s ( \ d+) " % cliarg , virtarg . key )
2018-01-26 20:50:44 +03:00
if reg :
num = int ( reg . groups ( ) [ 0 ] )
if can_edit :
2019-06-08 01:21:24 +03:00
while len ( xmlutil . get_prop_path ( inst , list_propname ) ) < ( num + 1 ) :
xmlutil . get_prop_path ( inst , list_propname ) . add_new ( )
2018-01-26 20:50:44 +03:00
try :
2019-06-08 01:21:24 +03:00
return xmlutil . get_prop_path ( inst , list_propname ) [ num ]
2018-01-26 20:50:44 +03:00
except IndexError :
if not can_edit :
return None
2019-07-02 21:07:16 +03:00
raise # pragma: no cover
2018-01-26 20:50:44 +03:00
return cb
2016-06-14 21:37:21 +03:00
def _optdict_to_param_list ( self , optdict ) :
"""
Convert the passed optdict to a list of instantiated
VirtCLIArguments to actually interact with
"""
ret = [ ]
2017-10-20 23:47:56 +03:00
for virtargstatic in self . _virtargs :
for key in list ( optdict . keys ( ) ) :
if virtargstatic . match_name ( key ) :
arginst = _VirtCLIArgument ( virtargstatic ,
key , optdict . pop ( key ) )
ret . append ( arginst )
2016-06-14 21:37:21 +03:00
return ret
def _check_leftover_opts ( self , optdict ) :
"""
Used to check if there were any unprocessed entries in the
optdict after we should have emptied it . Like if the user
passed an invalid argument such as - - disk idontexist = foo
"""
if optdict :
2020-07-12 00:31:40 +03:00
fail ( _ ( " Unknown %(optionflag)s options: %(string)s " ) %
{ " optionflag " : self . cli_flag_name ( ) ,
" string " : list ( optdict . keys ( ) ) } )
2014-01-21 17:48:22 +04:00
2016-06-14 14:37:21 +03:00
def _parse ( self , inst ) :
"""
Subclasses can hook into this to do any pre / post processing
of the inst , or self . optdict
"""
2016-06-14 21:37:21 +03:00
optdict = self . optdict . copy ( )
for param in self . _optdict_to_param_list ( optdict ) :
2019-05-10 19:27:23 +03:00
param . parse_param ( self , inst )
2014-01-21 17:48:22 +04:00
2016-06-14 21:37:21 +03:00
self . _check_leftover_opts ( optdict )
2016-06-14 14:37:21 +03:00
return inst
2014-01-21 17:48:22 +04:00
2019-06-14 00:37:26 +03:00
def parse ( self , inst ) :
2016-06-14 14:37:21 +03:00
"""
Main entry point . Iterate over self . _virtargs , and serialize
self . optdict into ' inst ' .
For virt - xml , ' inst ' is the virtinst object we are editing ,
2018-03-20 19:18:35 +03:00
ex . a DeviceDisk from a parsed Guest object .
2016-06-14 14:37:21 +03:00
For virt - install , ' inst ' is None , and we will create a new
2019-05-10 20:03:27 +03:00
inst for self . guest_propname , or edit a singleton object in place
2016-06-14 14:37:21 +03:00
like Guest . features / DomainFeatures
"""
if not self . optstr :
2014-01-21 17:48:22 +04:00
return None
2017-03-09 01:03:01 +03:00
if self . stub_none and self . optstr == " none " :
2016-06-14 14:37:21 +03:00
return None
new_object = False
2019-05-10 20:03:27 +03:00
if self . guest_propname and not inst :
2018-03-21 02:38:18 +03:00
inst = self . lookup_prop ( self . guest )
new_object = self . prop_is_list ( self . guest )
if new_object :
inst = inst . new ( )
2016-06-14 14:37:21 +03:00
ret = [ ]
try :
2019-01-31 19:34:13 +03:00
objs = self . _parse ( inst is None and self . guest or inst )
2019-06-11 18:09:56 +03:00
for obj in xmlutil . listify ( objs ) :
2019-06-14 00:37:26 +03:00
if not self . editing and hasattr ( obj , " validate " ) :
2019-06-11 18:09:56 +03:00
obj . validate ( )
if not new_object :
continue
if isinstance ( obj , Device ) :
self . guest . add_device ( obj )
else :
self . guest . add_child ( obj )
2016-06-14 14:37:21 +03:00
2019-06-08 01:21:24 +03:00
ret + = xmlutil . listify ( objs )
2017-05-05 19:47:21 +03:00
except Exception as e :
2019-06-17 04:12:39 +03:00
log . debug ( " Exception parsing inst= %s optstr= %s " ,
2016-06-14 14:37:21 +03:00
inst , self . optstr , exc_info = True )
2019-01-14 12:21:33 +03:00
fail ( _ ( " Error: %(cli_flag_name)s %(options)s : %(err)s " ) %
{ " cli_flag_name " : self . cli_flag_name ( ) ,
2016-06-14 14:37:21 +03:00
" options " : self . optstr , " err " : str ( e ) } )
2014-01-21 17:48:22 +04:00
return ret
2013-03-18 01:06:52 +04:00
2016-06-14 14:37:21 +03:00
def lookup_child_from_option_string ( self ) :
2014-01-19 19:37:14 +04:00
"""
2015-09-04 23:07:01 +03:00
Given a passed option string , search the guests ' child list
for all objects which match the passed options .
2015-09-05 00:03:31 +03:00
Used only by virt - xml - - edit lookups
2014-01-19 19:37:14 +04:00
"""
ret = [ ]
2019-06-08 01:21:24 +03:00
objlist = xmlutil . listify ( self . lookup_prop ( self . guest ) )
2014-01-19 19:37:14 +04:00
2016-06-14 21:37:21 +03:00
try :
for inst in objlist :
2016-06-14 14:37:21 +03:00
optdict = self . optdict . copy ( )
2016-06-15 00:29:54 +03:00
valid = True
2016-06-14 21:37:21 +03:00
for param in self . _optdict_to_param_list ( optdict ) :
paramret = param . lookup_param ( self , inst )
2016-06-15 00:29:54 +03:00
if paramret is False :
valid = False
2014-09-20 21:22:52 +04:00
break
if valid :
ret . append ( inst )
2016-06-14 21:37:21 +03:00
self . _check_leftover_opts ( optdict )
2017-05-05 19:47:21 +03:00
except Exception as e :
2019-06-17 04:12:39 +03:00
log . debug ( " Exception parsing inst= %s optstr= %s " ,
2016-06-14 21:37:21 +03:00
inst , self . optstr , exc_info = True )
2019-01-14 12:21:33 +03:00
fail ( _ ( " Error: %(cli_flag_name)s %(options)s : %(err)s " ) %
{ " cli_flag_name " : self . cli_flag_name ( ) ,
2016-06-14 21:37:21 +03:00
" options " : self . optstr , " err " : str ( e ) } )
2014-01-19 19:37:14 +04:00
return ret
2018-12-18 16:44:57 +03:00
def noset_cb ( self , inst , val , virtarg ) :
""" Do nothing callback """
2013-03-18 01:06:52 +04:00
2020-09-10 20:52:07 +03:00
#################
# --xml parsing #
#################
class _XMLCLIInstance :
"""
Helper class to parse - - xml content into .
Generates XMLManualAction which actually performs the work
"""
def __init__ ( self ) :
self . xpath_delete = None
self . xpath_set = None
self . xpath_create = None
self . xpath_value = None
def build_action ( self ) :
from . xmlbuilder import XMLManualAction
if self . xpath_delete :
return XMLManualAction ( self . xpath_delete ,
action = XMLManualAction . ACTION_DELETE )
if self . xpath_create :
return XMLManualAction ( self . xpath_create ,
action = XMLManualAction . ACTION_CREATE )
xpath = self . xpath_set
if self . xpath_value :
val = self . xpath_value
else :
if " = " not in str ( xpath ) :
fail ( " %s : Setting xpath must be in the form of XPATH=VALUE " %
xpath )
xpath , val = xpath . rsplit ( " = " , 1 )
return XMLManualAction ( xpath , val or None )
class ParserXML ( VirtCLIParser ) :
cli_arg_name = " xml "
supports_clearxml = False
@classmethod
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
cls . add_arg ( " xpath.delete " , " xpath_delete " , can_comma = True )
cls . add_arg ( " xpath.set " , " xpath_set " , can_comma = True )
cls . add_arg ( " xpath.create " , " xpath_create " , can_comma = True )
cls . add_arg ( " xpath.value " , " xpath_value " , can_comma = True )
def _parse ( self , inst ) :
if not self . optstr . startswith ( " xpath. " ) :
self . optdict . clear ( )
self . optdict [ " xpath.set " ] = self . optstr
super ( ) . _parse ( inst )
def parse_xmlcli ( guest , options ) :
"""
Parse - - xml option strings and add the resulting XMLManualActions
to the Guest instance
"""
for optstr in options . xml :
inst = _XMLCLIInstance ( )
ParserXML ( optstr ) . parse ( inst )
manualaction = inst . build_action ( )
guest . add_xml_manual_action ( manualaction )
2019-02-22 11:40:08 +03:00
########################
# --unattended parsing #
########################
2019-05-11 00:01:49 +03:00
class ParserUnattended ( VirtCLIParser ) :
2019-02-22 11:40:08 +03:00
cli_arg_name = " unattended "
2019-11-21 00:40:00 +03:00
supports_clearxml = False
2019-02-22 11:40:08 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-02-22 11:40:08 +03:00
cls . add_arg ( " profile " , " profile " )
2019-07-03 17:01:28 +03:00
cls . add_arg ( " admin-password-file " , " admin_password_file " )
2019-10-17 19:01:25 +03:00
cls . add_arg ( " user-login " , " user_login " )
2019-07-03 17:01:28 +03:00
cls . add_arg ( " user-password-file " , " user_password_file " )
2019-04-09 20:35:20 +03:00
cls . add_arg ( " product-key " , " product_key " )
2020-01-24 12:22:36 +03:00
cls . add_arg ( " reg-login " , " reg_login " )
2019-02-22 11:40:08 +03:00
2019-05-11 00:20:21 +03:00
def parse_unattended ( optstr ) :
2019-02-22 11:40:08 +03:00
ret = UnattendedData ( )
2019-06-11 22:18:47 +03:00
if optstr == 1 :
# This means bare --unattended, so there's nothing to parse
return ret
2019-05-11 00:20:21 +03:00
parser = ParserUnattended ( optstr )
2019-11-25 22:19:09 +03:00
if parser . parse ( ret ) :
return ret
2019-02-22 11:40:08 +03:00
2015-04-12 02:25:46 +03:00
###################
# --check parsing #
###################
def convert_old_force ( options ) :
if options . force :
if not options . check :
options . check = " all=off "
del ( options . force )
2019-05-11 00:01:49 +03:00
class ParserCheck ( VirtCLIParser ) :
2016-06-14 01:50:31 +03:00
cli_arg_name = " check "
2019-11-21 00:40:00 +03:00
supports_clearxml = False
2016-06-14 01:50:31 +03:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-10 22:04:47 +03:00
cls . add_arg ( " path_in_use " , None , is_onoff = True ,
cb = cls . set_cb , lookup_cb = None )
cls . add_arg ( " disk_size " , None , is_onoff = True ,
cb = cls . set_cb , lookup_cb = None )
cls . add_arg ( " path_exists " , None , is_onoff = True ,
cb = cls . set_cb , lookup_cb = None )
2020-07-06 01:39:15 +03:00
cls . add_arg ( " mac_in_use " , None , is_onoff = True ,
cb = cls . set_cb , lookup_cb = None )
2019-04-09 20:35:20 +03:00
cls . add_arg ( " all " , " all_checks " , is_onoff = True )
2018-12-18 16:44:56 +03:00
2016-06-14 18:38:53 +03:00
def set_cb ( self , inst , val , virtarg ) :
2016-06-13 23:30:29 +03:00
# This sets properties on the _GlobalState objects
2016-06-14 18:38:53 +03:00
inst . set_validation_check ( virtarg . cliname , val )
2015-04-12 02:25:46 +03:00
2018-10-01 20:14:43 +03:00
def parse_check ( checks ) :
2016-06-14 01:50:31 +03:00
# Overwrite this for each parse
2019-06-08 01:21:24 +03:00
for optstr in xmlutil . listify ( checks ) :
2019-05-11 00:20:21 +03:00
parser = ParserCheck ( optstr )
2018-10-01 20:14:43 +03:00
parser . parse ( get_global_state ( ) )
2015-04-12 02:25:46 +03:00
2019-06-12 00:34:18 +03:00
#####################
# --install parsing #
#####################
class ParserInstall ( VirtCLIParser ) :
cli_arg_name = " install "
2019-06-14 03:26:26 +03:00
remove_first = " os "
2019-11-21 00:40:00 +03:00
supports_clearxml = False
2019-06-12 00:34:18 +03:00
@classmethod
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
cls . add_arg ( " bootdev " , " bootdev " , can_comma = True )
cls . add_arg ( " kernel " , " kernel " , can_comma = True )
cls . add_arg ( " initrd " , " initrd " , can_comma = True )
2019-06-12 23:56:37 +03:00
cls . add_arg ( " kernel_args " , " kernel_args " , can_comma = True )
cls . add_arg ( " kernel_args_overwrite " , " kernel_args_overwrite " ,
is_onoff = True )
2019-06-14 03:26:26 +03:00
cls . add_arg ( " os " , " os " )
2019-06-17 06:12:24 +03:00
cls . add_arg ( " no_install " , " no_install " , is_onoff = True )
2019-06-12 00:34:18 +03:00
class InstallData :
def __init__ ( self ) :
self . bootdev = None
self . kernel = None
self . initrd = None
2019-06-12 23:56:37 +03:00
self . kernel_args = None
self . kernel_args_overwrite = None
2019-06-14 03:26:26 +03:00
self . os = None
2019-06-14 03:56:16 +03:00
self . is_set = False
2019-06-17 06:12:24 +03:00
self . no_install = None
2019-06-12 00:34:18 +03:00
def parse_install ( optstr ) :
installdata = InstallData ( )
2019-06-14 03:56:16 +03:00
installdata . is_set = bool ( optstr )
2019-06-12 00:34:18 +03:00
parser = ParserInstall ( optstr or None )
parser . parse ( installdata )
return installdata
2019-06-28 19:05:18 +03:00
########################
# --cloud-init parsing #
########################
class ParserCloudInit ( VirtCLIParser ) :
cli_arg_name = " cloud_init "
supports_clearxml = False
@classmethod
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-07-16 15:45:16 +03:00
cls . add_arg ( " root-password-generate " , " root_password_generate " , is_onoff = True )
2019-07-16 15:17:32 +03:00
cls . add_arg ( " root-password-file " , " root_password_file " )
2019-07-03 09:06:21 +03:00
cls . add_arg ( " disable " , " disable " , is_onoff = True )
2019-08-02 13:20:04 +03:00
cls . add_arg ( " ssh-key " , " ssh_key " )
2019-11-21 01:37:36 +03:00
cls . add_arg ( " user-data " , " user_data " )
2019-11-22 01:32:08 +03:00
cls . add_arg ( " meta-data " , " meta_data " )
2021-09-29 18:50:52 +03:00
cls . add_arg ( " network-config " , " network_config " )
2019-06-28 19:05:18 +03:00
def parse_cloud_init ( optstr ) :
ret = CloudInitData ( )
if optstr == 1 :
2019-07-01 23:33:28 +03:00
# This means bare --cloud-init, so there's nothing to parse.
2019-07-16 15:45:16 +03:00
log . warning ( " Defaulting to --cloud-init root-password-generate=yes,disable=yes " )
ret . root_password_generate = True
2019-07-03 09:06:21 +03:00
ret . disable = True
2019-06-28 19:05:18 +03:00
return ret
parser = ParserCloudInit ( optstr )
2019-11-25 22:19:09 +03:00
if parser . parse ( ret ) :
return ret
2019-06-28 19:05:18 +03:00
2019-01-31 19:34:13 +03:00
######################
# --location parsing #
######################
2019-05-11 00:01:49 +03:00
class ParserLocation ( VirtCLIParser ) :
2019-01-31 19:34:13 +03:00
cli_arg_name = " location "
remove_first = " location "
2019-11-21 00:40:00 +03:00
supports_clearxml = False
2019-01-31 19:34:13 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-01-31 19:34:13 +03:00
cls . add_arg ( " location " , " location " , can_comma = True )
2019-02-01 02:07:09 +03:00
cls . add_arg ( " kernel " , " kernel " , can_comma = True )
cls . add_arg ( " initrd " , " initrd " , can_comma = True )
2019-01-31 19:34:13 +03:00
def parse_location ( optstr ) :
2019-05-10 18:56:13 +03:00
class LocationData :
def __init__ ( self ) :
self . location = None
self . kernel = None
self . initrd = None
parsedata = LocationData ( )
2019-05-11 00:20:21 +03:00
parser = ParserLocation ( optstr or None )
parser . parse ( parsedata )
2019-02-01 02:07:09 +03:00
2019-05-10 18:56:13 +03:00
return parsedata . location , parsedata . kernel , parsedata . initrd
2019-01-31 19:34:13 +03:00
2019-02-08 00:26:04 +03:00
########################
# --os-variant parsing #
########################
class OSVariantData ( object ) :
2020-09-15 02:05:58 +03:00
def __init__ ( self ) :
2019-02-08 00:26:04 +03:00
self . _name = None
2020-09-15 02:05:58 +03:00
self . _id = None
self . _detect = False
2020-09-15 03:28:02 +03:00
self . _require = False
2019-06-14 03:56:16 +03:00
2020-09-15 02:05:58 +03:00
def set_compat_str ( self , rawstr ) :
if rawstr is None or rawstr == " auto " :
# The default behavior
self . _detect = True
2019-06-14 03:56:16 +03:00
return
2020-09-15 02:05:58 +03:00
if rawstr == " none " :
self . _name = " generic "
elif " :// " in rawstr :
self . _id = rawstr
2019-02-08 00:26:04 +03:00
else :
2020-09-15 02:05:58 +03:00
self . _name = rawstr
def validate ( self ) :
osobj = None
if self . _id :
osobj = OSDB . lookup_os_by_full_id ( self . _id , raise_error = True )
elif self . _name :
osobj = OSDB . lookup_os ( self . _name , raise_error = True )
if osobj :
self . _name = osobj . name
def is_generic_requested ( self ) :
return self . _detect is False or self . _name == " generic "
def is_detect ( self ) :
return self . _detect
2020-09-15 03:28:02 +03:00
def is_require ( self ) :
return self . _require
2020-09-15 02:05:58 +03:00
def get_name ( self ) :
2019-06-14 03:56:16 +03:00
return self . _name
2019-02-08 00:26:04 +03:00
2020-09-15 02:05:58 +03:00
class ParserOSVariant ( VirtCLIParser ) :
2020-09-20 23:00:33 +03:00
cli_arg_name = " os_variant "
2020-09-15 02:05:58 +03:00
supports_clearxml = False
@classmethod
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
cls . add_arg ( " name " , " _name " )
cls . add_arg ( " short-id " , " _name " )
cls . add_arg ( " id " , " _id " )
cls . add_arg ( " detect " , " _detect " , is_onoff = True )
2020-09-15 03:28:02 +03:00
cls . add_arg ( " require " , " _require " , is_onoff = True )
2020-09-15 02:05:58 +03:00
def parse ( self , inst ) :
if " = " not in str ( self . optstr ) :
inst . set_compat_str ( self . optstr )
return
return super ( ) . parse ( inst )
2019-02-08 00:26:04 +03:00
def parse_os_variant ( optstr ) :
2020-09-15 02:05:58 +03:00
data = OSVariantData ( )
parser = ParserOSVariant ( optstr )
parser . parse ( data )
data . validate ( )
return data
2019-02-08 00:26:04 +03:00
2019-11-25 01:40:27 +03:00
###########################
# --noautoconsole parsing #
###########################
2019-11-25 21:38:52 +03:00
def _determine_default_autoconsole_type ( guest , installer ) :
2019-11-25 02:10:56 +03:00
"""
Determine the default console for the passed guest config
: returns : ' text ' , ' graphical ' , or None
"""
2019-11-25 21:38:52 +03:00
if installer . has_cloudinit ( ) :
log . info ( " --cloud-init specified, defaulting to --autoconsole text " )
return " text "
2019-11-25 02:10:56 +03:00
gdevs = guest . devices . graphics
if not gdevs :
return " text "
gtype = gdevs [ 0 ] . type
if gtype not in [ " default " ,
DeviceGraphics . TYPE_VNC ,
DeviceGraphics . TYPE_SPICE ] :
log . debug ( " No viewer to launch for graphics type ' %s ' " , gtype )
return None
2020-07-18 01:46:54 +03:00
if not HAS_VIRTVIEWER and not xmlutil . in_testsuite ( ) : # pragma: no cover
2019-11-25 02:10:56 +03:00
log . warning ( _ ( " Unable to connect to graphical console: "
" virt-viewer not installed. Please install "
" the ' virt-viewer ' package. " ) )
return None
if ( not os . environ . get ( " DISPLAY " , " " ) and
2020-07-18 01:46:54 +03:00
not xmlutil . in_testsuite ( ) ) : # pragma: no cover
2019-11-25 02:10:56 +03:00
log . warning ( _ ( " Graphics requested but DISPLAY is not set. "
" Not running virt-viewer. " ) )
return None
return " graphical "
2019-11-25 01:40:27 +03:00
class _AutoconsoleData ( object ) :
2019-11-25 21:38:52 +03:00
def __init__ ( self , autoconsole , guest , installer ) :
2019-11-25 01:40:27 +03:00
self . _autoconsole = autoconsole
2019-11-25 02:10:56 +03:00
if self . _autoconsole not in [ " none " , " default " , " text " , " graphical " ] :
fail ( _ ( " Unknown autoconsole type ' %s ' " ) % self . _autoconsole )
self . _is_default = self . _autoconsole == " default "
if self . _is_default :
2019-11-25 21:38:52 +03:00
default = _determine_default_autoconsole_type ( guest , installer )
2019-11-25 02:10:56 +03:00
self . _autoconsole = default or " none "
def is_text ( self ) :
return self . _autoconsole == " text "
def is_graphical ( self ) :
return self . _autoconsole == " graphical "
2019-11-25 01:40:27 +03:00
def is_default ( self ) :
2019-11-25 02:10:56 +03:00
return self . _is_default
2020-09-11 02:45:37 +03:00
def has_console_cb ( self ) :
return bool ( self . get_console_cb ( ) )
2019-11-25 02:10:56 +03:00
def get_console_cb ( self ) :
if self . is_graphical ( ) :
return _gfx_console
if self . is_text ( ) :
return _txt_console
return None
2019-11-25 01:40:27 +03:00
2019-11-25 21:38:52 +03:00
def parse_autoconsole ( options , guest , installer ) :
return _AutoconsoleData ( options . autoconsole , guest , installer )
2019-11-25 01:40:27 +03:00
2014-01-25 05:03:30 +04:00
######################
# --metadata parsing #
######################
class ParserMetadata ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " metadata "
2016-06-13 23:30:29 +03:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2018-12-18 16:44:56 +03:00
cls . add_arg ( " name " , " name " , can_comma = True )
cls . add_arg ( " title " , " title " , can_comma = True )
cls . add_arg ( " uuid " , " uuid " )
2019-05-14 21:26:19 +03:00
cls . add_arg ( " genid " , " genid " )
cls . add_arg ( " genid_enable " , " genid_enable " , is_onoff = True )
2018-12-18 16:44:56 +03:00
cls . add_arg ( " description " , " description " , can_comma = True )
2019-05-10 22:04:47 +03:00
cls . add_arg ( " os_name " , None , lookup_cb = None ,
cb = cls . set_os_name_cb )
cls . add_arg ( " os_full_id " , None , lookup_cb = None ,
cb = cls . set_os_full_id_cb )
2018-12-18 16:44:56 +03:00
2018-10-01 02:12:19 +03:00
def set_os_name_cb ( self , inst , val , virtarg ) :
inst . set_os_name ( val )
def set_os_full_id_cb ( self , inst , val , virtarg ) :
2019-06-14 03:56:16 +03:00
osobj = OSDB . lookup_os_by_full_id ( val , raise_error = True )
inst . set_os_name ( osobj . name )
2018-10-01 02:12:19 +03:00
2013-03-18 01:06:52 +04:00
2014-05-29 13:03:24 +04:00
####################
# --events parsing #
####################
2014-05-29 05:46:24 +04:00
class ParserEvents ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " events "
2016-06-13 23:30:29 +03:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2018-12-18 16:44:56 +03:00
cls . add_arg ( " on_poweroff " , " on_poweroff " )
cls . add_arg ( " on_reboot " , " on_reboot " )
cls . add_arg ( " on_crash " , " on_crash " )
cls . add_arg ( " on_lockfailure " , " on_lockfailure " )
2014-05-29 05:46:24 +04:00
2014-06-04 06:08:05 +04:00
######################
# --resource parsing #
######################
class ParserResource ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " resource "
2019-05-10 20:03:27 +03:00
guest_propname = " resource "
2016-06-13 23:30:29 +03:00
remove_first = " partition "
2014-06-04 06:08:05 +04:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2018-12-18 16:44:56 +03:00
cls . add_arg ( " partition " , " partition " )
2021-09-14 18:08:35 +03:00
cls . add_arg ( " fibrechannel.appid " , " fibrechannel_appid " , can_comma = True )
2014-06-04 06:08:05 +04:00
2013-03-18 01:06:52 +04:00
######################
# --numatune parsing #
######################
2014-01-19 22:56:06 +04:00
class ParserNumatune ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " numatune "
2019-05-10 20:03:27 +03:00
guest_propname = " numatune "
2016-06-13 23:30:29 +03:00
remove_first = " nodeset "
2019-05-11 04:42:28 +03:00
aliases = {
" memory.mode " : " mode " ,
" memory.nodeset " : " nodeset " ,
}
2013-03-18 01:06:52 +04:00
2019-06-17 22:32:54 +03:00
def memnode_find_inst_cb ( self , * args , * * kwargs ) :
cliarg = " memnode " # memnode[0-9]*
list_propname = " memnode "
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( * args , * * kwargs )
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-11 04:42:28 +03:00
cls . add_arg ( " memory.nodeset " , " memory_nodeset " , can_comma = True )
cls . add_arg ( " memory.mode " , " memory_mode " )
2019-06-09 11:48:08 +03:00
cls . add_arg ( " memory.placement " , " memory_placement " )
2013-03-18 01:06:52 +04:00
2019-06-17 22:32:54 +03:00
cls . add_arg ( " memnode[0-9]*.cellid " , " cellid " , can_comma = True ,
find_inst_cb = cls . memnode_find_inst_cb )
cls . add_arg ( " memnode[0-9]*.mode " , " mode " ,
find_inst_cb = cls . memnode_find_inst_cb )
cls . add_arg ( " memnode[0-9]*.nodeset " , " nodeset " , can_comma = True ,
find_inst_cb = cls . memnode_find_inst_cb )
2013-07-30 22:26:53 +04:00
2014-01-25 03:56:59 +04:00
####################
# --memory parsing #
####################
class ParserMemory ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " memory "
2016-06-13 23:30:29 +03:00
remove_first = " memory "
2019-05-11 21:03:46 +03:00
aliases = {
" maxMemory.slots " : " hotplugmemoryslots " ,
" maxMemory " : " hotplugmemorymax " ,
}
def _convert_old_memory_options ( self ) :
"""
Historically the cli had :
memory - > . / currentMemory
maxmemory - > . / memory
Then later libvirt gained . / maxMemory . So things are quite a mess .
Try to convert the back compat cases . Basically if new style option
currentMemory is specified , interpret currentMemory and memory as
the XML values . Otherwise treat memory and maxmemory as the old
swapped names .
"""
havecur = " currentMemory " in self . optdict
havemax = " maxmemory " in self . optdict
havemem = " memory " in self . optdict
if havecur :
if havemax :
self . optdict [ " memory " ] = self . optdict . pop ( " maxmemory " , None )
elif havemax :
if havemem :
self . optdict [ " currentMemory " ] = self . optdict . pop ( " memory " )
self . optdict [ " memory " ] = self . optdict . pop ( " maxmemory " )
elif havemem :
self . optdict [ " currentMemory " ] = self . optdict . pop ( " memory " )
def _parse ( self , inst ) :
self . _convert_old_memory_options ( )
return super ( ) . _parse ( inst )
###################
# Option handling #
###################
2016-06-13 23:30:29 +03:00
2016-06-14 18:38:53 +03:00
def set_memory_cb ( self , inst , val , virtarg ) :
2019-06-08 01:21:24 +03:00
xmlutil . set_prop_path ( inst , virtarg . propname , int ( val ) * 1024 )
2014-01-25 03:56:59 +04:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
2019-05-11 21:03:46 +03:00
cls . add_arg ( " memory " , " memory " , cb = cls . set_memory_cb )
cls . add_arg ( " currentMemory " , " currentMemory " , cb = cls . set_memory_cb )
cls . add_arg ( " maxMemory " , " maxMemory " , cb = cls . set_memory_cb )
cls . add_arg ( " maxMemory.slots " , " maxMemorySlots " )
# This is converted into either memory or currentMemory
cls . add_arg ( " maxmemory " , None , lookup_cb = None , cb = cls . noset_cb )
# New memoryBacking properties should be added to the --memorybacking
2019-04-09 20:35:20 +03:00
cls . add_arg ( " hugepages " , " memoryBacking.hugepages " , is_onoff = True )
2014-01-25 03:56:59 +04:00
2014-02-25 06:02:31 +04:00
#####################
# --memtune parsing #
#####################
2018-03-20 22:10:04 +03:00
class ParserMemtune ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " memtune "
2019-05-10 20:03:27 +03:00
guest_propname = " memtune "
2016-06-13 23:30:29 +03:00
remove_first = " soft_limit "
2014-02-25 06:02:31 +04:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2018-12-18 16:44:56 +03:00
cls . add_arg ( " hard_limit " , " hard_limit " )
cls . add_arg ( " soft_limit " , " soft_limit " )
cls . add_arg ( " swap_hard_limit " , " swap_hard_limit " )
cls . add_arg ( " min_guarantee " , " min_guarantee " )
2014-02-25 06:02:31 +04:00
2016-06-11 20:45:05 +03:00
#######################
# --blkiotune parsing #
#######################
class ParserBlkiotune ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " blkiotune "
2019-05-10 20:03:27 +03:00
guest_propname = " blkiotune "
2016-06-13 23:30:29 +03:00
remove_first = " weight "
2019-05-13 00:17:19 +03:00
aliases = {
2019-05-15 16:59:25 +03:00
" device[0-9]*.path " : " device_path " ,
" device[0-9]*.weight " : " device_weight " ,
2019-07-25 13:15:57 +03:00
" device[0-9]*.read_bytes_sec " : " read_bytes_sec " ,
" device[0-9]*.write_bytes_sec " : " write_bytes_sec " ,
" device[0-9]*.read_iops_sec " : " read_iops_sec " ,
" device[0-9]*.write_iops_sec " : " write_iops_sec " ,
2019-05-13 00:17:19 +03:00
}
2016-06-11 20:45:05 +03:00
2019-05-15 16:59:25 +03:00
def device_find_inst_cb ( self , * args , * * kwargs ) :
cliarg = " device " # device[0-9]*
list_propname = " devices " # blkiotune.devices
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( * args , * * kwargs )
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2018-12-18 16:44:56 +03:00
cls . add_arg ( " weight " , " weight " )
2019-05-15 16:59:25 +03:00
cls . add_arg ( " device[0-9]*.path " , " path " ,
find_inst_cb = cls . device_find_inst_cb )
cls . add_arg ( " device[0-9]*.weight " , " weight " ,
find_inst_cb = cls . device_find_inst_cb )
2019-07-25 13:15:57 +03:00
cls . add_arg ( " device[0-9]*.read_bytes_sec " , " read_bytes_sec " ,
find_inst_cb = cls . device_find_inst_cb )
cls . add_arg ( " device[0-9]*.write_bytes_sec " , " write_bytes_sec " ,
find_inst_cb = cls . device_find_inst_cb )
cls . add_arg ( " device[0-9]*.read_iops_sec " , " read_iops_sec " ,
find_inst_cb = cls . device_find_inst_cb )
cls . add_arg ( " device[0-9]*.write_iops_sec " , " write_iops_sec " ,
find_inst_cb = cls . device_find_inst_cb )
2016-06-11 20:45:05 +03:00
###########################
# --memorybacking parsing #
###########################
2018-03-20 22:10:04 +03:00
class ParserMemoryBacking ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " memorybacking "
2019-05-10 20:03:27 +03:00
guest_propname = " memoryBacking "
2019-05-13 00:18:17 +03:00
aliases = {
2019-05-14 22:45:16 +03:00
" hugepages.page[0-9]*.size " : " size " ,
" hugepages.page[0-9]*.unit " : " unit " ,
" hugepages.page[0-9]*.nodeset " : " nodeset " ,
2019-05-13 00:18:17 +03:00
" access.mode " : " access_mode " ,
" source.type " : " source_type " ,
}
2016-06-11 20:45:05 +03:00
2019-05-14 22:45:16 +03:00
def page_find_inst_cb ( self , * args , * * kwargs ) :
cliarg = " page " # page[0-9]*
list_propname = " pages " # memoryBacking.pages
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( * args , * * kwargs )
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2018-12-18 16:44:56 +03:00
cls . add_arg ( " hugepages " , " hugepages " , is_onoff = True )
2019-05-14 22:45:16 +03:00
cls . add_arg ( " hugepages.page[0-9]*.size " , " size " ,
find_inst_cb = cls . page_find_inst_cb )
cls . add_arg ( " hugepages.page[0-9]*.unit " , " unit " ,
find_inst_cb = cls . page_find_inst_cb )
cls . add_arg ( " hugepages.page[0-9]*.nodeset " , " nodeset " , can_comma = True ,
find_inst_cb = cls . page_find_inst_cb )
2019-05-13 00:18:17 +03:00
2018-12-18 16:44:56 +03:00
cls . add_arg ( " nosharepages " , " nosharepages " , is_onoff = True )
cls . add_arg ( " locked " , " locked " , is_onoff = True )
2019-05-13 00:18:17 +03:00
cls . add_arg ( " access.mode " , " access_mode " )
cls . add_arg ( " source.type " , " source_type " )
2019-05-14 22:50:51 +03:00
cls . add_arg ( " discard " , " discard " , is_onoff = True )
cls . add_arg ( " allocation.mode " , " allocation_mode " )
2016-06-11 20:45:05 +03:00
2013-03-18 01:06:52 +04:00
#################
# --cpu parsing #
#################
2014-01-19 22:56:06 +04:00
class ParserCPU ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " cpu "
2019-05-10 20:03:27 +03:00
guest_propname = " cpu "
2016-06-13 23:30:29 +03:00
remove_first = " model "
2017-03-09 01:03:01 +03:00
stub_none = False
2019-05-11 22:16:00 +03:00
aliases = {
" numa.cell[0-9]*.distances.sibling[0-9]*.id " :
" cell[0-9]*.distances.sibling[0-9]*.id " ,
" numa.cell[0-9]*.distances.sibling[0-9]*.value " :
" cell[0-9]*.distances.sibling[0-9]*.value " ,
" numa.cell[0-9]*.id " : " cell[0-9]*.id " ,
" numa.cell[0-9]*.cpus " : " cell[0-9]*.cpus " ,
" numa.cell[0-9]*.memory " : " cell[0-9]*.memory " ,
}
2021-08-04 13:00:13 +03:00
###################
# Special parsing #
###################
2019-05-11 22:16:00 +03:00
def _convert_old_feature_options ( self ) :
# For old CLI compat, --cpu force=foo,force=bar should force
# enable 'foo' and 'bar' features, but that doesn't fit with the
# CLI parser infrastructure very well.
converted = collections . defaultdict ( list )
for key , value in parse_optstr_tuples ( self . optstr ) :
if key in [ " force " , " require " , " optional " , " disable " , " forbid " ] :
converted [ key ] . append ( value )
# Convert +feature, -feature into expected format
for key , value in list ( self . optdict . items ( ) ) :
policy = None
if value or len ( key ) == 1 :
2019-07-02 21:07:16 +03:00
# We definitely hit this case, but coverage doesn't notice
# for some reason
continue # pragma: no cover
2019-05-11 22:16:00 +03:00
if key . startswith ( " + " ) :
policy = " force "
elif key . startswith ( " - " ) :
policy = " disable "
if policy :
del ( self . optdict [ key ] )
converted [ policy ] . append ( key [ 1 : ] )
self . optdict . update ( converted )
def _parse ( self , inst ) :
self . _convert_old_feature_options ( )
return super ( ) . _parse ( inst )
2021-08-04 13:00:13 +03:00
#################################
# Option multi-instance finders #
#################################
2014-01-19 22:56:06 +04:00
2018-01-26 20:50:44 +03:00
def cell_find_inst_cb ( self , * args , * * kwargs ) :
cliarg = " cell " # cell[0-9]*
2019-05-10 20:03:27 +03:00
list_propname = " cells " # cpu.cells
cb = self . _make_find_inst_cb ( cliarg , list_propname )
2018-01-26 20:50:44 +03:00
return cb ( * args , * * kwargs )
2016-06-15 01:19:09 +03:00
2021-08-03 20:54:51 +03:00
def cell_sibling_find_inst_cb ( self , inst , * args , * * kwargs ) :
virtinst: Add NUMA distance support
Now that libvirt has support for administration of distances between NUMA cells
it would be nice to be able to set those with virt-install directly instead of
having to 'virsh edit' the domain XML manually after installation.
For example
--cpu cell0.memory=1234,cell0.cpus=0-3,cell1.memory=5678,cell1.cpus=4-7,\
cell0.distances.sibling0.id=0,cell0.distances.sibling0.value=10,\
cell0.distances.sibling1.id=1,cell0.distances.sibling1.value=21,\
cell1.distances.sibling0.id=0,cell1.distances.sibling0.value=21,\
cell1.distances.sibling1.id=1,cell1.distances.sibling1.value=10
would generate the following XML:
<cpu>
<numa>
<cell cpus="0-3" memory="1234">
<distances>
<sibling id="0" value="10"/>
<sibling id="1" value="21"/>
</distances>
</cell>
<cell cpus="4-7" memory="5678">
<distances>
<sibling id="0" value="21"/>
<sibling id="1" value="10"/>
</distances>
</cell>
</numa>
</cpu>
Signed-off-by: Menno Lageman <menno.lageman@oracle.com>
(crobinso: rework cli format, drop some validation, drop man changes)
2018-01-22 15:36:00 +03:00
cell = self . cell_find_inst_cb ( inst , * args , * * kwargs )
inst = cell
cliarg = " sibling " # cell[0-9]*.distances.sibling[0-9]*
2019-05-10 20:03:27 +03:00
list_propname = " siblings " # cell.siblings
cb = self . _make_find_inst_cb ( cliarg , list_propname )
virtinst: Add NUMA distance support
Now that libvirt has support for administration of distances between NUMA cells
it would be nice to be able to set those with virt-install directly instead of
having to 'virsh edit' the domain XML manually after installation.
For example
--cpu cell0.memory=1234,cell0.cpus=0-3,cell1.memory=5678,cell1.cpus=4-7,\
cell0.distances.sibling0.id=0,cell0.distances.sibling0.value=10,\
cell0.distances.sibling1.id=1,cell0.distances.sibling1.value=21,\
cell1.distances.sibling0.id=0,cell1.distances.sibling0.value=21,\
cell1.distances.sibling1.id=1,cell1.distances.sibling1.value=10
would generate the following XML:
<cpu>
<numa>
<cell cpus="0-3" memory="1234">
<distances>
<sibling id="0" value="10"/>
<sibling id="1" value="21"/>
</distances>
</cell>
<cell cpus="4-7" memory="5678">
<distances>
<sibling id="0" value="21"/>
<sibling id="1" value="10"/>
</distances>
</cell>
</numa>
</cpu>
Signed-off-by: Menno Lageman <menno.lageman@oracle.com>
(crobinso: rework cli format, drop some validation, drop man changes)
2018-01-22 15:36:00 +03:00
return cb ( inst , * args , * * kwargs )
2021-08-03 20:54:51 +03:00
def cell_cache_find_inst_cb ( self , inst , * args , * * kwargs ) :
cell = self . cell_find_inst_cb ( inst , * args , * * kwargs )
inst = cell
cliarg = " cache " # cell[0-9]*.cache[0-9]*
list_propname = " caches " # cell.caches
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( inst , * args , * * kwargs )
2021-08-03 20:59:34 +03:00
def latency_find_inst_cb ( self , * args , * * kwargs ) :
cliarg = " latency " # latency[0-9]*
list_propname = " latencies " # cpu.latencies
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( * args , * * kwargs )
def bandwidth_find_inst_cb ( self , * args , * * kwargs ) :
cliarg = " bandwidth " # bandwidth[0-9]*
list_propname = " bandwidths " # cpu.bandwidths
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( * args , * * kwargs )
2021-08-04 13:00:13 +03:00
#############################
# Option handling callbacks #
#############################
2016-06-14 18:38:53 +03:00
def set_model_cb ( self , inst , val , virtarg ) :
2016-06-13 23:30:29 +03:00
if val == " host " :
val = inst . SPECIAL_MODE_HOST_MODEL
if val == " none " :
val = inst . SPECIAL_MODE_CLEAR
2014-01-19 19:37:14 +04:00
2016-06-13 23:30:29 +03:00
if val in inst . SPECIAL_MODES :
2018-10-04 21:19:32 +03:00
inst . set_special_mode ( self . guest , val )
2016-06-13 23:30:29 +03:00
else :
2019-03-14 12:48:21 +03:00
inst . set_model ( self . guest , val )
2014-01-19 19:37:14 +04:00
2016-06-14 18:38:53 +03:00
def set_feature_cb ( self , inst , val , virtarg ) :
policy = virtarg . cliname
2019-06-08 01:21:24 +03:00
for feature_name in xmlutil . listify ( val ) :
2016-06-13 23:30:29 +03:00
featureobj = None
2014-01-19 22:56:06 +04:00
2016-06-13 23:30:29 +03:00
for f in inst . features :
if f . name == feature_name :
featureobj = f
break
2014-01-19 22:56:06 +04:00
2016-06-13 23:30:29 +03:00
if featureobj :
featureobj . policy = policy
else :
inst . add_feature ( feature_name , policy )
2014-01-19 22:56:06 +04:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-22 15:10:36 +03:00
# 'secure' needs to be parsed before 'model'
cls . add_arg ( " secure " , " secure " , is_onoff = True )
2019-05-10 22:04:47 +03:00
cls . add_arg ( " model " , " model " , cb = cls . set_model_cb )
2021-08-03 20:59:34 +03:00
# 'model.fallback' must be parsed after 'model' as it may otherwise be
# overridden
cls . add_arg ( " model.fallback " , " model_fallback " )
cls . add_arg ( " model.vendor_id " , " model_vendor_id " )
2021-08-04 13:00:13 +03:00
cls . add_arg ( " vendor " , " vendor " )
2021-07-29 15:34:24 +03:00
2018-12-18 16:44:56 +03:00
cls . add_arg ( " mode " , " mode " )
cls . add_arg ( " match " , " match " )
2021-07-29 15:34:24 +03:00
cls . add_arg ( " check " , " check " )
cls . add_arg ( " migratable " , " migratable " , is_onoff = True )
2021-08-04 13:00:13 +03:00
cls . add_arg ( " topology.sockets " , " topology.sockets " )
cls . add_arg ( " topology.dies " , " topology.dies " )
cls . add_arg ( " topology.cores " , " topology.cores " )
cls . add_arg ( " topology.threads " , " topology.threads " )
2019-05-11 22:05:36 +03:00
cls . add_arg ( " cache.level " , " cache.level " )
2021-08-04 13:00:13 +03:00
cls . add_arg ( " cache.mode " , " cache.mode " )
2018-12-18 16:44:56 +03:00
2021-08-04 13:00:13 +03:00
# CPU features
2019-05-10 22:42:05 +03:00
# These are handled specially in _parse
cls . add_arg ( " force " , None , lookup_cb = None , cb = cls . set_feature_cb )
cls . add_arg ( " require " , None , lookup_cb = None , cb = cls . set_feature_cb )
cls . add_arg ( " optional " , None , lookup_cb = None , cb = cls . set_feature_cb )
cls . add_arg ( " disable " , None , lookup_cb = None , cb = cls . set_feature_cb )
cls . add_arg ( " forbid " , None , lookup_cb = None , cb = cls . set_feature_cb )
2018-12-18 16:44:56 +03:00
2021-08-04 13:00:13 +03:00
# NUMA cells
2019-05-11 22:16:00 +03:00
cls . add_arg ( " numa.cell[0-9]*.id " , " id " ,
2018-12-18 16:44:56 +03:00
find_inst_cb = cls . cell_find_inst_cb )
2019-05-11 22:16:00 +03:00
cls . add_arg ( " numa.cell[0-9]*.cpus " , " cpus " , can_comma = True ,
2018-12-18 16:44:56 +03:00
find_inst_cb = cls . cell_find_inst_cb )
2019-05-11 22:16:00 +03:00
cls . add_arg ( " numa.cell[0-9]*.memory " , " memory " ,
2018-12-18 16:44:56 +03:00
find_inst_cb = cls . cell_find_inst_cb )
2021-08-03 20:41:33 +03:00
cls . add_arg ( " numa.cell[0-9]*.unit " , " unit " ,
find_inst_cb = cls . cell_find_inst_cb )
2021-08-04 13:00:13 +03:00
cls . add_arg ( " numa.cell[0-9]*.memAccess " , " memAccess " ,
find_inst_cb = cls . cell_find_inst_cb )
cls . add_arg ( " numa.cell[0-9]*.discard " , " discard " ,
find_inst_cb = cls . cell_find_inst_cb , is_onoff = True )
2019-05-11 22:16:00 +03:00
cls . add_arg ( " numa.cell[0-9]*.distances.sibling[0-9]*.id " , " id " ,
2021-08-03 20:54:51 +03:00
find_inst_cb = cls . cell_sibling_find_inst_cb )
2019-05-11 22:16:00 +03:00
cls . add_arg ( " numa.cell[0-9]*.distances.sibling[0-9]*.value " , " value " ,
2021-08-03 20:54:51 +03:00
find_inst_cb = cls . cell_sibling_find_inst_cb )
2021-08-04 13:00:13 +03:00
# NUMA cell caches
2021-08-03 20:54:51 +03:00
cls . add_arg ( " numa.cell[0-9]*.cache[0-9]*.level " , " level " ,
find_inst_cb = cls . cell_cache_find_inst_cb )
cls . add_arg ( " numa.cell[0-9]*.cache[0-9]*.associativity " , " associativity " ,
find_inst_cb = cls . cell_cache_find_inst_cb )
cls . add_arg ( " numa.cell[0-9]*.cache[0-9]*.policy " , " policy " ,
find_inst_cb = cls . cell_cache_find_inst_cb )
cls . add_arg ( " numa.cell[0-9]*.cache[0-9]*.size.value " , " size_value " ,
find_inst_cb = cls . cell_cache_find_inst_cb )
cls . add_arg ( " numa.cell[0-9]*.cache[0-9]*.size.unit " , " size_unit " ,
find_inst_cb = cls . cell_cache_find_inst_cb )
cls . add_arg ( " numa.cell[0-9]*.cache[0-9]*.line.value " , " line_value " ,
find_inst_cb = cls . cell_cache_find_inst_cb )
cls . add_arg ( " numa.cell[0-9]*.cache[0-9]*.line.unit " , " line_unit " ,
find_inst_cb = cls . cell_cache_find_inst_cb )
2018-12-18 16:44:56 +03:00
2021-08-04 13:00:13 +03:00
# Interconnections between NUMA cells
2021-08-03 20:59:34 +03:00
cls . add_arg ( " numa.interconnects.latency[0-9]*.initiator " , " initiator " ,
find_inst_cb = cls . latency_find_inst_cb )
cls . add_arg ( " numa.interconnects.latency[0-9]*.target " , " target " ,
find_inst_cb = cls . latency_find_inst_cb )
cls . add_arg ( " numa.interconnects.latency[0-9]*.cache " , " cache " ,
find_inst_cb = cls . latency_find_inst_cb )
cls . add_arg ( " numa.interconnects.latency[0-9]*.type " , " type " ,
find_inst_cb = cls . latency_find_inst_cb )
cls . add_arg ( " numa.interconnects.latency[0-9]*.value " , " value " ,
find_inst_cb = cls . latency_find_inst_cb )
cls . add_arg ( " numa.interconnects.latency[0-9]*.unit " , " unit " ,
find_inst_cb = cls . latency_find_inst_cb )
cls . add_arg ( " numa.interconnects.bandwidth[0-9]*.initiator " , " initiator " ,
find_inst_cb = cls . bandwidth_find_inst_cb )
cls . add_arg ( " numa.interconnects.bandwidth[0-9]*.target " , " target " ,
find_inst_cb = cls . bandwidth_find_inst_cb )
cls . add_arg ( " numa.interconnects.bandwidth[0-9]*.type " , " type " ,
find_inst_cb = cls . bandwidth_find_inst_cb )
cls . add_arg ( " numa.interconnects.bandwidth[0-9]*.cache " , " cache " ,
find_inst_cb = cls . bandwidth_find_inst_cb )
cls . add_arg ( " numa.interconnects.bandwidth[0-9]*.value " , " value " ,
find_inst_cb = cls . bandwidth_find_inst_cb )
cls . add_arg ( " numa.interconnects.bandwidth[0-9]*.unit " , " unit " ,
find_inst_cb = cls . bandwidth_find_inst_cb )
2016-06-13 23:30:29 +03:00
2018-02-06 14:56:41 +03:00
#####################
# --cputune parsing #
#####################
2018-03-20 22:10:04 +03:00
class ParserCputune ( VirtCLIParser ) :
2018-02-06 14:56:41 +03:00
cli_arg_name = " cputune "
2019-05-10 20:03:27 +03:00
guest_propname = " cputune "
2018-02-06 14:56:41 +03:00
remove_first = " model "
stub_none = False
2021-08-06 18:09:31 +03:00
def vcpupin_find_inst_cb ( self , * args , * * kwargs ) :
2018-02-06 14:56:41 +03:00
cliarg = " vcpupin " # vcpupin[0-9]*
2021-08-06 18:09:31 +03:00
list_propname = " vcpupins " # cputune.vcpupins
2019-05-10 20:03:27 +03:00
cb = self . _make_find_inst_cb ( cliarg , list_propname )
2018-02-06 14:56:41 +03:00
return cb ( * args , * * kwargs )
2021-07-26 16:53:51 +03:00
def iothreadpin_find_inst_cb ( self , * args , * * kwargs ) :
cliarg = " iothreadpin " # iothreadpin[0-9]*
2021-08-06 18:09:31 +03:00
list_propname = " iothreadpins " # cputune.iothreadpins
2021-07-26 16:53:51 +03:00
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( * args , * * kwargs )
2021-02-13 15:47:09 +03:00
def vcpusched_find_inst_cb ( self , * args , * * kwargs ) :
cliarg = " vcpusched " # vcpusched[0-9]*
2021-08-06 18:09:31 +03:00
list_propname = " vcpuscheds " # cputune.vcpuscheds
2021-02-13 15:47:09 +03:00
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( * args , * * kwargs )
2021-08-06 18:42:43 +03:00
def iothreadsched_find_inst_cb ( self , * args , * * kwargs ) :
cliarg = " iothreadsched " # iothreadsched[0-9]*
list_propname = " iothreadscheds " # cputune.iothreadscheds
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( * args , * * kwargs )
2019-08-09 12:14:05 +03:00
def cachetune_find_inst_cb ( self , * args , * * kwargs ) :
cliarg = " cachetune " # cachetune[0-9]*
2021-08-06 18:09:31 +03:00
list_propname = " cachetunes " # cputune.cachetunes
2019-08-09 12:14:05 +03:00
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( * args , * * kwargs )
def cache_find_inst_cb ( self , inst , * args , * * kwargs ) :
cachetune = self . cachetune_find_inst_cb ( inst , * args , * * kwargs )
inst = cachetune
cliarg = " cache " # cachetune[0-9]*.cache[0-9]*
list_propname = " caches " # cachetune.caches
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( inst , * args , * * kwargs )
2021-08-07 12:03:35 +03:00
def monitor_find_inst_cb ( self , inst , * args , * * kwargs ) :
cachetune = self . cachetune_find_inst_cb ( inst , * args , * * kwargs )
inst = cachetune
cliarg = " monitor " # cachetune[0-9]*.monitor[0-9]*
list_propname = " monitors " # cachetune.monitors
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( inst , * args , * * kwargs )
2019-08-14 18:50:40 +03:00
def memorytune_find_inst_cb ( self , * args , * * kwargs ) :
cliarg = " memorytune " # memorytune[0-9]*
2021-08-06 18:09:31 +03:00
list_propname = " memorytunes " # cputune.memorytunes
2019-08-14 18:50:40 +03:00
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( * args , * * kwargs )
def node_find_inst_cb ( self , inst , * args , * * kwargs ) :
memorytune = self . memorytune_find_inst_cb ( inst , * args , * * kwargs )
inst = memorytune
cliarg = " node " # memorytune[0-9]*.node[0-9]*
list_propname = " nodes " # memorytune.nodes
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( inst , * args , * * kwargs )
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2021-08-06 17:56:21 +03:00
# Resource quotas
cls . add_arg ( " shares " , " shares " )
cls . add_arg ( " period " , " period " )
cls . add_arg ( " quota " , " quota " )
cls . add_arg ( " global_period " , " global_period " )
cls . add_arg ( " global_quota " , " global_quota " )
cls . add_arg ( " emulator_period " , " emulator_period " )
cls . add_arg ( " emulator_quota " , " emulator_quota " )
cls . add_arg ( " iothread_period " , " iothread_period " )
cls . add_arg ( " iothread_quota " , " iothread_quota " )
2018-12-18 16:44:56 +03:00
# Options for CPU.vcpus config
2019-04-09 20:35:20 +03:00
cls . add_arg ( " vcpupin[0-9]*.vcpu " , " vcpu " ,
2021-08-06 18:09:31 +03:00
find_inst_cb = cls . vcpupin_find_inst_cb )
2019-04-09 20:35:20 +03:00
cls . add_arg ( " vcpupin[0-9]*.cpuset " , " cpuset " , can_comma = True ,
2021-08-06 18:09:31 +03:00
find_inst_cb = cls . vcpupin_find_inst_cb )
2021-07-26 16:48:08 +03:00
cls . add_arg ( " emulatorpin.cpuset " , " emulatorpin_cpuset " , can_comma = True )
2021-07-26 16:53:51 +03:00
cls . add_arg ( " iothreadpin[0-9]*.iothread " , " iothread " ,
find_inst_cb = cls . iothreadpin_find_inst_cb )
cls . add_arg ( " iothreadpin[0-9]*.cpuset " , " cpuset " , can_comma = True ,
find_inst_cb = cls . iothreadpin_find_inst_cb )
2021-08-06 18:42:43 +03:00
# Scheduling
cls . add_arg ( " emulatorsched.scheduler " , " emulatorsched_scheduler " )
cls . add_arg ( " emulatorsched.priority " , " emulatorsched_priority " )
2021-02-13 15:47:09 +03:00
cls . add_arg ( " vcpusched[0-9]*.vcpus " , " vcpus " , can_comma = True ,
find_inst_cb = cls . vcpusched_find_inst_cb )
cls . add_arg ( " vcpusched[0-9]*.scheduler " , " scheduler " ,
find_inst_cb = cls . vcpusched_find_inst_cb )
cls . add_arg ( " vcpusched[0-9]*.priority " , " priority " ,
find_inst_cb = cls . vcpusched_find_inst_cb )
2021-08-06 18:42:43 +03:00
cls . add_arg ( " iothreadsched[0-9]*.iothreads " , " iothreads " , can_comma = True ,
find_inst_cb = cls . iothreadsched_find_inst_cb )
cls . add_arg ( " iothreadsched[0-9]*.scheduler " , " scheduler " ,
find_inst_cb = cls . iothreadsched_find_inst_cb )
cls . add_arg ( " iothreadsched[0-9]*.priority " , " priority " ,
find_inst_cb = cls . iothreadsched_find_inst_cb )
2021-08-07 12:03:35 +03:00
# CPU Cache & Memory Tunables
2019-08-09 12:14:05 +03:00
cls . add_arg ( " cachetune[0-9]*.vcpus " , " vcpus " ,
2021-08-07 12:03:35 +03:00
find_inst_cb = cls . cachetune_find_inst_cb , can_comma = True )
2019-08-09 12:14:05 +03:00
cls . add_arg ( " cachetune[0-9]*.cache[0-9]*.id " , " id " ,
find_inst_cb = cls . cache_find_inst_cb )
2021-08-07 12:03:35 +03:00
cls . add_arg ( " cachetune[0-9]*.cache[0-9]*.level " , " level " ,
find_inst_cb = cls . cache_find_inst_cb )
2019-08-09 12:14:05 +03:00
cls . add_arg ( " cachetune[0-9]*.cache[0-9]*.type " , " type " ,
find_inst_cb = cls . cache_find_inst_cb )
cls . add_arg ( " cachetune[0-9]*.cache[0-9]*.size " , " size " ,
find_inst_cb = cls . cache_find_inst_cb )
cls . add_arg ( " cachetune[0-9]*.cache[0-9]*.unit " , " unit " ,
find_inst_cb = cls . cache_find_inst_cb )
2021-08-07 12:03:35 +03:00
cls . add_arg ( " cachetune[0-9]*.monitor[0-9]*.level " , " level " ,
find_inst_cb = cls . monitor_find_inst_cb )
cls . add_arg ( " cachetune[0-9]*.monitor[0-9]*.vcpus " , " vcpus " ,
find_inst_cb = cls . monitor_find_inst_cb , can_comma = True )
2019-08-14 18:50:40 +03:00
cls . add_arg ( " memorytune[0-9]*.vcpus " , " vcpus " ,
2021-08-07 12:03:35 +03:00
find_inst_cb = cls . memorytune_find_inst_cb , can_comma = True )
2019-08-14 18:50:40 +03:00
cls . add_arg ( " memorytune[0-9]*.node[0-9]*.id " , " id " ,
find_inst_cb = cls . node_find_inst_cb )
cls . add_arg ( " memorytune[0-9]*.node[0-9]*.bandwidth " , " bandwidth " ,
find_inst_cb = cls . node_find_inst_cb )
2018-02-06 14:56:41 +03:00
2019-06-04 10:50:18 +03:00
#######################
# --iothreads parsing #
#######################
class ParserIOThreads ( VirtCLIParser ) :
cli_arg_name = " iothreads "
guest_propname = " iothreads "
remove_first = " iothreads "
2019-06-04 18:42:59 +03:00
def iothreads_find_inst_cb ( self , * args , * * kwargs ) :
cliarg = " iothread " # iothreads[0-9]*
list_propname = " iothreadids "
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( * args , * * kwargs )
2019-06-04 10:50:18 +03:00
@classmethod
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
# Options for IOThreads config
cls . add_arg ( " iothreads " , " iothreads " )
2019-06-04 18:42:59 +03:00
cls . add_arg ( " iothreadids.iothread[0-9]*.id " , " id " ,
find_inst_cb = cls . iothreads_find_inst_cb )
2019-06-04 10:50:18 +03:00
2016-06-14 14:37:21 +03:00
###################
# --vcpus parsing #
###################
class ParserVCPU ( VirtCLIParser ) :
cli_arg_name = " vcpus "
2019-05-12 02:29:47 +03:00
remove_first = " vcpu "
aliases = {
" vcpu.placement " : " placement " ,
}
2016-06-14 14:37:21 +03:00
2019-05-12 02:29:47 +03:00
def _convert_old_vcpu_opts ( self ) :
havemax = " maxvcpus " in self . optdict
havecur = " vcpu.current " in self . optdict
havevcp = " vcpu " in self . optdict
if havecur :
if havemax :
self . optdict [ " vcpu " ] = self . optdict . pop ( " maxvcpus " )
elif havemax :
if havevcp :
self . optdict [ " vcpu.current " ] = self . optdict . pop ( " vcpu " )
self . optdict [ " vcpu " ] = self . optdict . pop ( " maxvcpus " )
def _add_advertised_aliases ( self ) :
# These are essentially aliases for new style options, but we still
# want to advertise them in --vcpus=help output because they are
# historically commonly used. This should rarely, if ever, be extended
if " cpuset " in self . optdict :
self . optdict [ " vcpu.cpuset " ] = self . optdict . pop ( " cpuset " )
if " vcpus " in self . optdict :
self . optdict [ " vcpu " ] = self . optdict . pop ( " vcpus " )
def _parse ( self , inst ) :
self . _add_advertised_aliases ( )
self . _convert_old_vcpu_opts ( )
return super ( ) . _parse ( inst )
###################
# Option handling #
###################
2016-06-14 14:37:21 +03:00
2019-05-14 22:18:49 +03:00
def vcpu_find_inst_cb ( self , * args , * * kwargs ) :
cliarg = " vcpu " # vcpu[0-9]*
list_propname = " vcpulist.vcpu " # guest.vcpulist.vcpu
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( * args , * * kwargs )
2016-06-14 18:38:53 +03:00
def set_cpuset_cb ( self , inst , val , virtarg ) :
2016-06-14 14:37:21 +03:00
if val != " auto " :
2019-05-12 02:15:07 +03:00
inst . vcpu_cpuset = val
2016-06-14 14:37:21 +03:00
return
# Previously we did our own one-time cpuset placement
# based on current NUMA memory availability, but that's
# pretty dumb unless the conditions on the host never change.
2018-09-01 04:06:18 +03:00
# So instead use newer vcpu placement=
2016-06-14 14:37:21 +03:00
inst . vcpu_placement = " auto "
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-12 02:29:47 +03:00
# This is converted into either vcpu.current or vcpu
2019-05-12 04:51:08 +03:00
cls . add_arg ( " maxvcpus " , " vcpus " , cb = cls . noset_cb )
2019-05-12 02:29:47 +03:00
# These are handled in _add_advertised_aliases
2019-05-12 04:51:08 +03:00
cls . add_arg ( " cpuset " , " vcpu_cpuset " , can_comma = True , cb = cls . noset_cb )
cls . add_arg ( " vcpus " , " vcpus " , cb = cls . noset_cb )
2019-05-12 02:29:47 +03:00
# Further CPU options should be added to --cpu
2020-08-28 01:02:10 +03:00
cls . add_arg ( " sockets " , " cpu.topology.sockets " )
2021-10-29 17:41:10 +03:00
cls . add_arg ( " dies " , " cpu.topology.dies " )
2020-08-28 01:02:10 +03:00
cls . add_arg ( " cores " , " cpu.topology.cores " )
cls . add_arg ( " threads " , " cpu.topology.threads " )
2016-06-14 14:37:21 +03:00
2019-05-12 02:29:47 +03:00
# <domain><vcpu> options
cls . add_arg ( " vcpu " , " vcpus " )
cls . add_arg ( " vcpu.current " , " vcpu_current " )
cls . add_arg ( " vcpu.cpuset " , " vcpu_cpuset " ,
2019-05-12 02:15:07 +03:00
can_comma = True , cb = cls . set_cpuset_cb )
2019-05-12 02:29:47 +03:00
cls . add_arg ( " vcpu.placement " , " vcpu_placement " )
2016-06-14 14:37:21 +03:00
2019-05-14 22:18:49 +03:00
# <domain><vcpus> options
cls . add_arg ( " vcpus.vcpu[0-9]*.id " , " id " ,
find_inst_cb = cls . vcpu_find_inst_cb )
cls . add_arg ( " vcpus.vcpu[0-9]*.enabled " , " enabled " ,
find_inst_cb = cls . vcpu_find_inst_cb , is_onoff = True )
cls . add_arg ( " vcpus.vcpu[0-9]*.hotpluggable " , " hotpluggable " ,
find_inst_cb = cls . vcpu_find_inst_cb , is_onoff = True )
cls . add_arg ( " vcpus.vcpu[0-9]*.order " , " order " ,
find_inst_cb = cls . vcpu_find_inst_cb )
2016-06-14 14:37:21 +03:00
2013-03-18 01:06:52 +04:00
##################
# --boot parsing #
##################
2014-01-19 22:56:06 +04:00
class ParserBoot ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " boot "
2019-05-10 20:03:27 +03:00
guest_propname = " os "
2019-05-11 01:46:54 +03:00
aliases = {
2019-05-12 02:35:06 +03:00
" bios.rebootTimeout " : " rebootTimeout " ,
" bios.useserial " : " useserial " ,
" bootmenu.enable " : " menu " ,
2019-06-12 01:59:20 +03:00
" cmdline " : [ " extra_args " , " kernel_args " ] ,
2019-05-12 02:35:06 +03:00
" loader.readonly " : " loader_ro " ,
" loader.type " : " loader_type " ,
" loader.secure " : " loader_secure " ,
" nvram.template " : " nvram_template " ,
" smbios.mode " : " smbios_mode " ,
2019-05-11 01:46:54 +03:00
}
2016-06-13 23:30:29 +03:00
2019-05-12 02:35:06 +03:00
def _convert_boot_order ( self , inst ) :
2014-01-19 22:56:06 +04:00
# Build boot order
2013-03-18 01:06:52 +04:00
boot_order = [ ]
2017-10-11 14:35:46 +03:00
for cliname in list ( self . optdict . keys ( ) ) :
2018-03-21 12:32:36 +03:00
if cliname not in inst . BOOT_DEVICES :
2013-03-18 01:06:52 +04:00
continue
2016-06-14 14:37:21 +03:00
del ( self . optdict [ cliname ] )
2014-01-19 22:56:06 +04:00
if cliname not in boot_order :
boot_order . append ( cliname )
2013-03-18 01:06:52 +04:00
2014-01-19 22:56:06 +04:00
if boot_order :
2018-03-21 12:32:36 +03:00
inst . bootorder = boot_order
2013-03-18 01:06:52 +04:00
2019-05-12 02:35:06 +03:00
def _parse ( self , inst ) :
self . _convert_boot_order ( inst )
2019-05-10 22:56:26 +03:00
# Back compat to allow uefi to have no cli value specified
if " uefi " in self . optdict :
self . optdict [ " uefi " ] = True
2019-01-21 15:47:17 +03:00
return super ( ) . _parse ( inst )
2014-01-19 22:56:06 +04:00
2019-05-12 02:35:06 +03:00
###################
# Option handling #
###################
def set_uefi_cb ( self , inst , val , virtarg ) :
2019-06-17 01:30:06 +03:00
if not self . editing :
# From virt-install, we just set this flag, and set_defaults()
# will fill in everything for us, otherwise we have a circular
# dep on determining arch/machine info
self . guest . uefi_requested = True
else :
2022-01-26 19:17:41 +03:00
self . guest . enable_uefi ( )
2019-05-12 02:35:06 +03:00
def set_initargs_cb ( self , inst , val , virtarg ) :
inst . set_initargs_string ( val )
def set_bootloader_cb ( self , inst , val , virtarg ) :
self . guest . bootloader = val
2021-07-28 16:07:55 +03:00
def set_bootloader_args_cb ( self , inst , val , virtarg ) :
self . guest . bootloader_args = val
2019-05-12 02:35:06 +03:00
def set_domain_type_cb ( self , inst , val , virtarg ) :
self . guest . type = val
def set_emulator_cb ( self , inst , val , virtarg ) :
self . guest . emulator = val
2019-05-14 20:39:42 +03:00
def boot_find_inst_cb ( self , * args , * * kwargs ) :
cliarg = " boot " # boot[0-9]*
2019-05-14 22:59:40 +03:00
list_propname = " bootdevs " # os.bootdevs
2019-05-14 20:39:42 +03:00
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( * args , * * kwargs )
2019-05-14 20:43:56 +03:00
def initarg_find_inst_cb ( self , * args , * * kwargs ) :
cliarg = " initarg " # initarg[0-9]*
list_propname = " initargs " # os.initargs
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( * args , * * kwargs )
2021-07-28 16:49:38 +03:00
def initenv_find_inst_cb ( self , * args , * * kwargs ) :
cliarg = " initenv " # initenv[0-9]*
list_propname = " initenvs " # os.initenvs
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( * args , * * kwargs )
2021-07-28 12:13:28 +03:00
def feature_find_inst_cb ( self , * args , * * kwargs ) :
cliarg = " feature " # firmware.feature[0-9]*
list_propname = " firmware_features " # os.firmware_features
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( * args , * * kwargs )
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-14 20:39:42 +03:00
# This is simply so the boot options are advertised with --boot help,
# actual processing is handled by _parse
cls . add_arg ( " hd " , None , lookup_cb = None , cb = cls . noset_cb )
cls . add_arg ( " cdrom " , None , lookup_cb = None , cb = cls . noset_cb )
cls . add_arg ( " fd " , None , lookup_cb = None , cb = cls . noset_cb )
cls . add_arg ( " network " , None , lookup_cb = None , cb = cls . noset_cb )
2018-12-18 16:44:56 +03:00
# UEFI depends on these bits, so set them first
2021-07-28 17:42:45 +03:00
cls . add_arg ( " os_type " , " os_type " )
2018-12-18 16:44:56 +03:00
cls . add_arg ( " arch " , " arch " )
2021-07-28 17:42:45 +03:00
cls . add_arg ( " machine " , " machine " )
2019-05-10 22:04:47 +03:00
cls . add_arg ( " bootloader " , None , lookup_cb = None ,
cb = cls . set_bootloader_cb )
2021-07-28 16:07:55 +03:00
cls . add_arg ( " bootloader_args " , None , lookup_cb = None ,
cb = cls . set_bootloader_args_cb )
2019-05-10 22:04:47 +03:00
cls . add_arg ( " domain_type " , None , lookup_cb = None ,
cb = cls . set_domain_type_cb )
cls . add_arg ( " emulator " , None , lookup_cb = None ,
cb = cls . set_emulator_cb )
cls . add_arg ( " uefi " , None , lookup_cb = None ,
2019-05-10 22:56:26 +03:00
cb = cls . set_uefi_cb )
2018-12-18 16:44:56 +03:00
2021-07-28 17:42:45 +03:00
# Common/Shared boot options
cls . add_arg ( " loader " , " loader " )
cls . add_arg ( " loader.readonly " , " loader_ro " , is_onoff = True )
cls . add_arg ( " loader.type " , " loader_type " )
cls . add_arg ( " loader.secure " , " loader_secure " , is_onoff = True )
2019-05-12 02:35:06 +03:00
2021-07-28 17:42:45 +03:00
# Guest-Based bootloader options
2019-06-17 00:15:08 +03:00
cls . add_arg ( " firmware " , " firmware " )
2021-07-28 12:13:28 +03:00
cls . add_arg ( " firmware.feature[0-9]*.enabled " , " enabled " ,
find_inst_cb = cls . feature_find_inst_cb , is_onoff = True )
cls . add_arg ( " firmware.feature[0-9]*.name " , " name " ,
find_inst_cb = cls . feature_find_inst_cb )
2021-07-28 17:42:45 +03:00
cls . add_arg ( " nvram " , " nvram " )
cls . add_arg ( " nvram.template " , " nvram_template " )
2019-05-14 20:39:42 +03:00
cls . add_arg ( " boot[0-9]*.dev " , " dev " ,
find_inst_cb = cls . boot_find_inst_cb )
2021-07-28 15:58:07 +03:00
cls . add_arg ( " bootmenu.enable " , " bootmenu_enable " , is_onoff = True )
cls . add_arg ( " bootmenu.timeout " , " bootmenu_timeout " )
cls . add_arg ( " bios.useserial " , " bios_useserial " , is_onoff = True )
cls . add_arg ( " bios.rebootTimeout " , " bios_rebootTimeout " )
2021-07-28 17:42:45 +03:00
cls . add_arg ( " smbios.mode " , " smbios_mode " )
# Direct kernel boot options
cls . add_arg ( " kernel " , " kernel " )
cls . add_arg ( " initrd " , " initrd " )
cls . add_arg ( " cmdline " , " kernel_args " , can_comma = True )
cls . add_arg ( " dtb " , " dtb " )
cls . add_arg ( " acpi.table " , " acpi_tb " )
cls . add_arg ( " acpi.table.type " , " acpi_tb_type " )
# Container boot options
2018-12-18 16:44:56 +03:00
cls . add_arg ( " init " , " init " )
cls . add_arg ( " initargs " , " initargs " , cb = cls . set_initargs_cb )
2019-05-14 20:43:56 +03:00
cls . add_arg ( " initarg[0-9]* " , " val " ,
find_inst_cb = cls . initarg_find_inst_cb )
2021-07-28 16:49:38 +03:00
cls . add_arg ( " initenv[0-9]* " , " value " ,
find_inst_cb = cls . initenv_find_inst_cb )
cls . add_arg ( " initenv[0-9]*.name " , " name " ,
find_inst_cb = cls . initenv_find_inst_cb )
2019-08-02 16:17:59 +03:00
cls . add_arg ( " initdir " , " initdir " )
cls . add_arg ( " inituser " , " inituser " )
cls . add_arg ( " initgroup " , " initgroup " )
2018-12-18 16:44:56 +03:00
2016-06-13 23:30:29 +03:00
2014-02-18 18:40:39 +04:00
###################
# --idmap parsing #
###################
2014-02-09 19:25:25 +04:00
class ParserIdmap ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " idmap "
2019-05-10 20:03:27 +03:00
guest_propname = " idmap "
2019-05-12 02:50:09 +03:00
aliases = {
" uid.start " : " uid_start " ,
" uid.target " : " uid_target " ,
" uid.count " : " uid_count " ,
" gid.start " : " gid_start " ,
" gid.target " : " gid_target " ,
" gid.count " : " gid_count " ,
}
2014-02-09 19:25:25 +04:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-12 02:50:09 +03:00
cls . add_arg ( " uid.start " , " uid_start " )
cls . add_arg ( " uid.target " , " uid_target " )
cls . add_arg ( " uid.count " , " uid_count " )
cls . add_arg ( " gid.start " , " gid_start " )
cls . add_arg ( " gid.target " , " gid_target " )
cls . add_arg ( " gid.count " , " gid_count " )
2014-02-09 19:25:25 +04:00
2013-03-18 01:06:52 +04:00
######################
2019-05-16 00:49:58 +03:00
# --seclabel parsing #
2013-03-18 01:06:52 +04:00
######################
2019-05-16 00:49:58 +03:00
class ParserSeclabel ( VirtCLIParser ) :
cli_arg_name = " seclabel "
2019-05-10 20:03:27 +03:00
guest_propname = " seclabels "
2014-01-26 00:44:14 +04:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2018-12-18 16:44:56 +03:00
cls . add_arg ( " type " , " type " )
cls . add_arg ( " model " , " model " )
cls . add_arg ( " relabel " , " relabel " , is_onoff = True )
cls . add_arg ( " label " , " label " , can_comma = True )
cls . add_arg ( " baselabel " , " baselabel " , can_comma = True )
2013-03-18 01:06:52 +04:00
2019-07-21 16:37:37 +03:00
######################
# --keywrap parsing #
######################
class ParserKeyWrap ( VirtCLIParser ) :
cli_arg_name = " keywrap "
guest_propname = " keywrap "
def cipher_find_inst_cb ( self , * args , * * kwargs ) :
cliarg = " cipher " # keywrap[0-9]*
list_propname = " cipher "
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( * args , * * kwargs )
@classmethod
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
cls . add_arg ( " cipher[0-9]*.name " , " name " , can_comma = True ,
find_inst_cb = cls . cipher_find_inst_cb )
cls . add_arg ( " cipher[0-9]*.state " , " state " , can_comma = True ,
find_inst_cb = cls . cipher_find_inst_cb )
2013-09-28 17:36:11 +04:00
######################
# --features parsing #
######################
2014-01-19 22:56:06 +04:00
class ParserFeatures ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " features "
2019-05-10 20:03:27 +03:00
guest_propname = " features "
2019-05-12 03:03:10 +03:00
aliases = {
" apic.eoi " : " eoi " ,
" pmu.state " : " pmu " ,
" vmport.state " : " vmport " ,
" kvm.hidden.state " : " kvm_hidden " ,
" gic.version " : " gic_version " ,
" smm.state " : " smm " ,
" vmcoreinfo.state " : " vmcoreinfo " ,
" hyperv.reset.state " : " hyperv_reset " ,
" hyperv.vapic.state " : " hyperv_vapic " ,
" hyperv.relaxed.state " : " hyperv_relaxed " ,
" hyperv.spinlocks.state " : " hyperv_spinlocks " ,
" hyperv.spinlocks.retries " : " hyperv_spinlocks_retries " ,
" hyperv.synic.state " : " hyperv_synic " ,
}
2014-01-26 00:44:14 +04:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2018-12-18 16:44:56 +03:00
cls . add_arg ( " acpi " , " acpi " , is_onoff = True )
cls . add_arg ( " apic " , " apic " , is_onoff = True )
cls . add_arg ( " pae " , " pae " , is_onoff = True )
cls . add_arg ( " privnet " , " privnet " , is_onoff = True )
cls . add_arg ( " hap " , " hap " , is_onoff = True )
cls . add_arg ( " viridian " , " viridian " , is_onoff = True )
2019-05-12 03:03:10 +03:00
cls . add_arg ( " apic.eoi " , " eoi " , is_onoff = True )
cls . add_arg ( " pmu.state " , " pmu " , is_onoff = True )
cls . add_arg ( " hyperv.reset.state " , " hyperv_reset " , is_onoff = True )
cls . add_arg ( " hyperv.vapic.state " , " hyperv_vapic " , is_onoff = True )
cls . add_arg ( " hyperv.relaxed.state " , " hyperv_relaxed " , is_onoff = True )
cls . add_arg ( " hyperv.spinlocks.state " , " hyperv_spinlocks " , is_onoff = True )
cls . add_arg ( " hyperv.spinlocks.retries " , " hyperv_spinlocks_retries " )
cls . add_arg ( " hyperv.synic.state " , " hyperv_synic " , is_onoff = True )
2018-12-18 16:44:56 +03:00
2019-05-12 03:03:10 +03:00
cls . add_arg ( " vmport.state " , " vmport " , is_onoff = True )
cls . add_arg ( " kvm.hidden.state " , " kvm_hidden " , is_onoff = True )
2019-08-13 09:57:13 +03:00
cls . add_arg ( " kvm.hint-dedicated.state " , " kvm_hint_dedicated " , is_onoff = True )
2021-05-27 07:01:48 +03:00
cls . add_arg ( " kvm.poll-control.state " , " kvm_poll_control " , is_onoff = True )
2019-05-12 03:03:10 +03:00
cls . add_arg ( " pvspinlock.state " , " pvspinlock " , is_onoff = True )
2018-12-18 16:44:56 +03:00
2019-05-12 03:03:10 +03:00
cls . add_arg ( " gic.version " , " gic_version " )
2018-12-18 16:44:56 +03:00
2019-05-12 03:03:10 +03:00
cls . add_arg ( " smm.state " , " smm " , is_onoff = True )
cls . add_arg ( " vmcoreinfo.state " , " vmcoreinfo " , is_onoff = True )
2022-01-11 20:21:39 +03:00
cls . add_arg ( " ioapic.driver " , " ioapic_driver " )
2017-01-26 17:08:36 +03:00
2013-03-18 01:06:52 +04:00
2013-10-06 00:45:15 +04:00
###################
# --clock parsing #
###################
2014-01-19 22:56:06 +04:00
class ParserClock ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " clock "
2019-05-10 20:03:27 +03:00
guest_propname = " clock "
2014-01-26 00:44:14 +04:00
2019-05-13 02:00:47 +03:00
def _remove_old_options ( self ) :
# These _tickpolicy options have never had any effect in libvirt,
2019-05-15 23:08:28 +03:00
# even though they aren't explicitly rejected. Make them no-ops.
# Keep them unrolled so we can easily check for code coverage
if " platform_tickpolicy " in self . optdict :
self . optdict . pop ( " platform_tickpolicy " )
if " hpet_tickpolicy " in self . optdict :
self . optdict . pop ( " hpet_tickpolicy " )
if " tsc_tickpolicy " in self . optdict :
self . optdict . pop ( " tsc_tickpolicy " )
if " kvmclock_tickpolicy " in self . optdict :
self . optdict . pop ( " kvmclock_tickpolicy " )
if " hypervclock_tickpolicy " in self . optdict :
self . optdict . pop ( " hypervclock_tickpolicy " )
2019-05-13 02:00:47 +03:00
def _parse ( self , inst ) :
self . _remove_old_options ( )
return super ( ) . _parse ( inst )
###################
# Option handling #
###################
2016-06-14 18:38:53 +03:00
def set_timer ( self , inst , val , virtarg ) :
2019-05-10 19:10:41 +03:00
tname , propname = virtarg . cliname . split ( " _ " )
2013-10-06 00:45:15 +04:00
2016-06-13 23:30:29 +03:00
timerobj = None
for t in inst . timers :
if t . name == tname :
timerobj = t
break
2013-10-06 00:45:15 +04:00
2016-06-13 23:30:29 +03:00
if not timerobj :
2018-02-08 01:27:56 +03:00
timerobj = inst . timers . add_new ( )
2016-06-13 23:30:29 +03:00
timerobj . name = tname
2019-06-08 01:21:24 +03:00
xmlutil . set_prop_path ( timerobj , propname , val )
2013-10-06 00:45:15 +04:00
2019-05-13 02:24:36 +03:00
def timer_find_inst_cb ( self , * args , * * kwargs ) :
cliarg = " timer " # timer[0-9]*
list_propname = " timers " # clock.timers
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( * args , * * kwargs )
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2013-10-06 00:45:15 +04:00
2019-05-13 02:24:36 +03:00
# Timer convenience helpers. It's unclear if we should continue
# extending this pattern, or just push users to use finegrained
# timer* config
2019-05-13 01:51:54 +03:00
cls . add_arg ( " pit_tickpolicy " , None , lookup_cb = None ,
cb = cls . set_timer )
cls . add_arg ( " rtc_tickpolicy " , None , lookup_cb = None ,
cb = cls . set_timer )
cls . add_arg ( " platform_present " , None , lookup_cb = None , is_onoff = True ,
cb = cls . set_timer )
cls . add_arg ( " pit_present " , None , lookup_cb = None , is_onoff = True ,
cb = cls . set_timer )
cls . add_arg ( " rtc_present " , None , lookup_cb = None , is_onoff = True ,
cb = cls . set_timer )
cls . add_arg ( " hpet_present " , None , lookup_cb = None , is_onoff = True ,
2019-05-10 22:04:47 +03:00
cb = cls . set_timer )
2019-05-13 01:51:54 +03:00
cls . add_arg ( " tsc_present " , None , lookup_cb = None , is_onoff = True ,
2019-05-10 22:04:47 +03:00
cb = cls . set_timer )
2019-05-13 01:51:54 +03:00
cls . add_arg ( " kvmclock_present " , None , lookup_cb = None , is_onoff = True ,
cb = cls . set_timer )
cls . add_arg ( " hypervclock_present " , None , lookup_cb = None , is_onoff = True ,
cb = cls . set_timer )
# Standard XML options
cls . add_arg ( " offset " , " offset " )
2019-05-13 02:24:36 +03:00
cls . add_arg ( " timer[0-9]*.name " , " name " ,
find_inst_cb = cls . timer_find_inst_cb )
cls . add_arg ( " timer[0-9]*.present " , " present " , is_onoff = True ,
find_inst_cb = cls . timer_find_inst_cb )
cls . add_arg ( " timer[0-9]*.tickpolicy " , " tickpolicy " ,
find_inst_cb = cls . timer_find_inst_cb )
2019-07-14 14:49:16 +03:00
cls . add_arg ( " timer[0-9]*.track " , " track " ,
find_inst_cb = cls . timer_find_inst_cb )
cls . add_arg ( " timer[0-9]*.mode " , " mode " ,
find_inst_cb = cls . timer_find_inst_cb )
cls . add_arg ( " timer[0-9]*.frequency " , " frequency " ,
find_inst_cb = cls . timer_find_inst_cb )
2019-08-17 19:10:03 +03:00
cls . add_arg ( " timer[0-9]*.catchup.threshold " , " threshold " ,
find_inst_cb = cls . timer_find_inst_cb )
cls . add_arg ( " timer[0-9]*.catchup.slew " , " slew " ,
find_inst_cb = cls . timer_find_inst_cb )
cls . add_arg ( " timer[0-9]*.catchup.limit " , " limit " ,
find_inst_cb = cls . timer_find_inst_cb )
2014-01-19 22:56:06 +04:00
2014-02-03 01:12:29 +04:00
################
# --pm parsing #
################
class ParserPM ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " pm "
2019-05-10 20:03:27 +03:00
guest_propname = " pm "
2019-05-12 04:26:56 +03:00
aliases = {
" suspend_to_mem.enabled " : " suspend_to_mem " ,
" suspend_to_disk.enabled " : " suspend_to_disk " ,
}
2014-02-03 01:12:29 +04:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-12 04:26:56 +03:00
cls . add_arg ( " suspend_to_mem.enabled " , " suspend_to_mem " , is_onoff = True )
cls . add_arg ( " suspend_to_disk.enabled " , " suspend_to_disk " , is_onoff = True )
2014-02-03 01:12:29 +04:00
2016-09-07 01:12:20 +03:00
#####################
# --sysinfo parsing #
#####################
2018-03-20 22:10:04 +03:00
class ParserSysinfo ( VirtCLIParser ) :
2016-09-07 01:12:20 +03:00
cli_arg_name = " sysinfo "
2019-05-10 20:03:27 +03:00
guest_propname = " sysinfo "
2016-09-07 01:12:20 +03:00
remove_first = " type "
2019-05-13 01:35:37 +03:00
aliases = {
" bios.vendor " : " bios_vendor " ,
" bios.version " : " bios_version " ,
" bios.date " : " bios_date " ,
" bios.release " : " bios_release " ,
" system.manufacturer " : " system_manufacturer " ,
" system.product " : " system_product " ,
" system.version " : " system_version " ,
" system.serial " : " system_serial " ,
" system.uuid " : " system_uuid " ,
" system.sku " : " system_sku " ,
" system.family " : " system_family " ,
" baseBoard.manufacturer " : " baseBoard_manufacturer " ,
" baseBoard.product " : " baseBoard_product " ,
" baseBoard.version " : " baseBoard_version " ,
" baseBoard.serial " : " baseBoard_serial " ,
" baseBoard.asset " : " baseBoard_asset " ,
" baseBoard.location " : " baseBoard_location " ,
}
2020-09-10 19:06:13 +03:00
def parse ( self , inst ) :
2019-05-14 15:00:18 +03:00
if self . optstr and ' type ' not in self . optdict :
2019-05-13 01:35:37 +03:00
# If any string specified, default to type=smbios otherwise
# libvirt errors. User args can still override this though
self . optdict [ ' type ' ] = ' smbios '
2020-09-10 19:06:13 +03:00
# Previously libvirt treated sysinfo as a singleton object, but
# that changed with fwcfg support. Our cli would merge all options
# together but now needs to support multiple. Maintain sorta
# backcompat behavior by mergin options if 'type' matches
if not inst :
typ = self . optdict [ " type " ]
for sysinfo in self . guest . sysinfo :
if sysinfo . type == typ :
inst = sysinfo
break
return super ( ) . parse ( inst )
2019-05-13 01:35:37 +03:00
###################
# Option handling #
###################
2016-09-07 01:12:20 +03:00
def set_type_cb ( self , inst , val , virtarg ) :
if val == " host " or val == " emulate " :
self . guest . os . smbios_mode = val
2019-07-02 21:07:16 +03:00
return
if val == " smbios " :
2016-09-07 01:12:20 +03:00
self . guest . os . smbios_mode = " sysinfo "
2019-07-02 21:07:16 +03:00
inst . type = val
2016-09-07 01:12:20 +03:00
2017-03-06 04:55:21 +03:00
def set_uuid_cb ( self , inst , val , virtarg ) :
2016-09-07 01:12:20 +03:00
# If a uuid is supplied it must match the guest UUID. This would be
# impossible to guess if the guest uuid is autogenerated so just
# overwrite the guest uuid with what is passed in assuming it passes
# the sanity checking below.
inst . system_uuid = val
2017-03-06 04:55:21 +03:00
self . guest . uuid = val
2016-09-07 01:12:20 +03:00
2019-05-14 21:16:14 +03:00
def oem_find_inst_cb ( self , * args , * * kwargs ) :
# pylint: disable=protected-access
cliarg = " entry " # oemStrings.entry[0-9]*
list_propname = " oemStrings " # sysinfo.oemStrings
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( * args , * * kwargs )
2020-09-10 19:06:13 +03:00
def entry_find_inst_cb ( self , * args , * * kwargs ) :
# pylint: disable=protected-access
cliarg = " entry " # entry[0-9]*
list_propname = " entries " # sysinfo.entries
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( * args , * * kwargs )
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2018-12-18 16:44:56 +03:00
# <sysinfo type='smbios'>
2019-05-13 01:35:37 +03:00
cls . add_arg ( " type " , " type " , cb = cls . set_type_cb , can_comma = True )
2018-12-18 16:44:56 +03:00
# <bios> type 0 BIOS Information
2019-05-13 01:35:37 +03:00
cls . add_arg ( " bios.vendor " , " bios_vendor " )
cls . add_arg ( " bios.version " , " bios_version " )
cls . add_arg ( " bios.date " , " bios_date " )
cls . add_arg ( " bios.release " , " bios_release " )
2018-12-18 16:44:56 +03:00
# <system> type 1 System Information
2019-05-13 01:35:37 +03:00
cls . add_arg ( " system.manufacturer " , " system_manufacturer " )
cls . add_arg ( " system.product " , " system_product " )
cls . add_arg ( " system.version " , " system_version " )
cls . add_arg ( " system.serial " , " system_serial " )
cls . add_arg ( " system.uuid " , " system_uuid " , cb = cls . set_uuid_cb )
cls . add_arg ( " system.sku " , " system_sku " )
cls . add_arg ( " system.family " , " system_family " )
2018-12-18 16:44:56 +03:00
# <baseBoard> type 2 Baseboard (or Module) Information
2019-05-13 01:35:37 +03:00
cls . add_arg ( " baseBoard.manufacturer " , " baseBoard_manufacturer " )
cls . add_arg ( " baseBoard.product " , " baseBoard_product " )
cls . add_arg ( " baseBoard.version " , " baseBoard_version " )
cls . add_arg ( " baseBoard.serial " , " baseBoard_serial " )
cls . add_arg ( " baseBoard.asset " , " baseBoard_asset " )
cls . add_arg ( " baseBoard.location " , " baseBoard_location " )
2016-09-07 01:12:20 +03:00
2019-05-14 21:05:08 +03:00
cls . add_arg ( " chassis.manufacturer " , " chassis_manufacturer " )
cls . add_arg ( " chassis.version " , " chassis_version " )
cls . add_arg ( " chassis.serial " , " chassis_serial " )
cls . add_arg ( " chassis.asset " , " chassis_asset " )
cls . add_arg ( " chassis.sku " , " chassis_sku " )
2020-09-10 19:06:13 +03:00
cls . add_arg ( " oemStrings.entry[0-9]* " , " value " , can_comma = True ,
2019-05-14 21:16:14 +03:00
find_inst_cb = cls . oem_find_inst_cb )
2020-09-10 19:06:13 +03:00
cls . add_arg ( " entry[0-9]* " , " value " , can_comma = True ,
find_inst_cb = cls . entry_find_inst_cb )
cls . add_arg ( " entry[0-9]*.name " , " name " , can_comma = True ,
find_inst_cb = cls . entry_find_inst_cb )
cls . add_arg ( " entry[0-9]*.file " , " file " , can_comma = True ,
find_inst_cb = cls . entry_find_inst_cb )
2016-09-07 01:12:20 +03:00
2017-03-06 04:45:33 +03:00
##############################
# --qemu-commandline parsing #
##############################
class ParserQemuCLI ( VirtCLIParser ) :
cli_arg_name = " qemu_commandline "
2019-05-10 20:03:27 +03:00
guest_propname = " xmlns_qemu "
2017-03-06 04:45:33 +03:00
def args_cb ( self , inst , val , virtarg ) :
for opt in shlex . split ( val ) :
2018-02-08 01:27:56 +03:00
obj = inst . args . add_new ( )
obj . value = opt
2017-03-06 04:45:33 +03:00
def env_cb ( self , inst , val , virtarg ) :
name , envval = val . split ( " = " , 1 )
2018-02-08 01:27:56 +03:00
obj = inst . envs . add_new ( )
obj . name = name
obj . value = envval
2017-03-06 04:45:33 +03:00
def _parse ( self , inst ) :
self . optdict . clear ( )
if self . optstr . startswith ( " env= " ) :
self . optdict [ " env " ] = self . optstr . split ( " = " , 1 ) [ 1 ]
elif self . optstr . startswith ( " args= " ) :
self . optdict [ " args " ] = self . optstr . split ( " = " , 1 ) [ 1 ]
elif self . optstr . startswith ( " clearxml= " ) :
self . optdict [ " clearxml " ] = self . optstr . split ( " = " , 1 ) [ 1 ]
else :
self . optdict [ " args " ] = self . optstr
2018-12-18 16:44:55 +03:00
return super ( ) . _parse ( inst )
2017-03-06 04:45:33 +03:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-10 22:04:47 +03:00
cls . add_arg ( " args " , None , lookup_cb = None ,
cb = cls . args_cb , can_comma = True )
cls . add_arg ( " env " , None , lookup_cb = None ,
cb = cls . env_cb , can_comma = True )
2017-03-06 04:45:33 +03:00
2013-03-18 01:06:52 +04:00
##########################
# Guest <device> parsing #
##########################
2019-05-14 19:45:57 +03:00
def _add_common_device_args ( cls ,
boot_order = False , boot_loadparm = False , virtio_options = False ) :
2016-06-13 23:30:29 +03:00
"""
2019-05-14 19:11:06 +03:00
Add common Device parameters , like address . *
2016-06-13 23:30:29 +03:00
"""
2019-05-15 20:36:41 +03:00
def _add_arg ( * args , * * kwargs ) :
kwargs [ " skip_testsuite_tracking " ] = True
cls . add_arg ( * args , * * kwargs )
_add_arg ( " address.type " , " address.type " )
_add_arg ( " address.domain " , " address.domain " )
_add_arg ( " address.bus " , " address.bus " )
_add_arg ( " address.slot " , " address.slot " )
_add_arg ( " address.multifunction " , " address.multifunction " ,
2016-06-13 23:30:29 +03:00
is_onoff = True )
2019-05-15 20:36:41 +03:00
_add_arg ( " address.function " , " address.function " )
_add_arg ( " address.controller " , " address.controller " )
_add_arg ( " address.unit " , " address.unit " )
_add_arg ( " address.port " , " address.port " )
_add_arg ( " address.target " , " address.target " )
_add_arg ( " address.reg " , " address.reg " )
_add_arg ( " address.cssid " , " address.cssid " )
_add_arg ( " address.ssid " , " address.ssid " )
_add_arg ( " address.devno " , " address.devno " )
_add_arg ( " address.iobase " , " address.iobase " )
_add_arg ( " address.irq " , " address.irq " )
_add_arg ( " address.base " , " address.base " )
_add_arg ( " address.zpci.uid " , " address.zpci_uid " )
_add_arg ( " address.zpci.fid " , " address.zpci_fid " )
_add_arg ( " alias.name " , " alias.name " )
2019-05-14 19:23:00 +03:00
2019-02-26 12:56:35 +03:00
def set_boot_order_cb ( self , inst , val , virtarg ) :
val = int ( val )
2019-03-06 21:15:48 +03:00
self . guest . reorder_boot_order ( inst , val )
2019-05-14 19:11:06 +03:00
if boot_order :
cls . aliases [ " boot.order " ] = " boot_order "
2019-05-15 20:36:41 +03:00
_add_arg ( " boot.order " , " boot.order " , cb = set_boot_order_cb )
2019-02-26 12:56:35 +03:00
2019-05-14 19:33:07 +03:00
if boot_loadparm :
2019-05-15 20:36:41 +03:00
_add_arg ( " boot.loadparm " , " boot.loadparm " )
2019-05-14 19:33:07 +03:00
2019-05-14 19:45:57 +03:00
if virtio_options :
2019-05-15 20:36:41 +03:00
_add_arg ( " driver.ats " , " virtio_driver.ats " , is_onoff = True )
_add_arg ( " driver.iommu " , " virtio_driver.iommu " , is_onoff = True )
2020-09-10 19:44:36 +03:00
_add_arg ( " driver.packed " , " virtio_driver.packed " , is_onoff = True )
2022-01-27 01:11:56 +03:00
_add_arg ( " driver.page_per_vq " ,
" virtio_driver.page_per_vq " , is_onoff = True )
2019-05-14 19:45:57 +03:00
2019-02-26 12:56:35 +03:00
2019-05-14 03:13:42 +03:00
def _add_device_seclabel_args ( cls , list_propname , prefix = " " ) :
2019-05-14 03:03:23 +03:00
def seclabel_find_inst_cb ( c , * args , * * kwargs ) :
# pylint: disable=protected-access
cliarg = " seclabel " # seclabel[0-9]*
cb = c . _make_find_inst_cb ( cliarg , list_propname )
return cb ( * args , * * kwargs )
2019-05-15 20:36:41 +03:00
def _add_arg ( * args , * * kwargs ) :
kwargs [ " skip_testsuite_tracking " ] = True
cls . add_arg ( * args , * * kwargs )
2019-05-14 03:03:23 +03:00
# DeviceDisk.seclabels properties
2019-05-15 20:36:41 +03:00
_add_arg ( prefix + " source.seclabel[0-9]*.model " , " model " ,
2019-05-14 03:03:23 +03:00
find_inst_cb = seclabel_find_inst_cb )
2019-05-15 20:36:41 +03:00
_add_arg ( prefix + " source.seclabel[0-9]*.relabel " , " relabel " ,
2019-05-14 03:13:42 +03:00
is_onoff = True , find_inst_cb = seclabel_find_inst_cb )
2019-05-15 20:36:41 +03:00
_add_arg ( prefix + " source.seclabel[0-9]*.label " , " label " ,
2019-05-14 03:13:42 +03:00
can_comma = True , find_inst_cb = seclabel_find_inst_cb )
2019-05-14 03:03:23 +03:00
2019-05-13 23:17:08 +03:00
def _add_char_source_args ( cls , prefix = " " ) :
"""
Add arguments that represent the CharSource object , which is shared
among multiple device types
"""
def set_sourcehost_cb ( c , inst , val , virtarg ) :
inst . source . set_friendly_host ( val )
def set_bind_cb ( c , inst , val , virtarg ) :
inst . source . set_friendly_bind ( val )
def set_connect_cb ( c , inst , val , virtarg ) :
inst . source . set_friendly_connect ( val )
def _add_arg ( cliname , propname , * args , * * kwargs ) :
2019-05-15 20:36:41 +03:00
kwargs [ " skip_testsuite_tracking " ] = True
2019-05-13 23:17:08 +03:00
cls . add_arg ( prefix + cliname , propname , * args , * * kwargs )
_add_arg ( " source.path " , " source.path " )
_add_arg ( " source.host " , " source.host " , cb = set_sourcehost_cb )
_add_arg ( " source.service " , " source.service " )
_add_arg ( " source.bind_host " , " source.bind_host " , cb = set_bind_cb )
_add_arg ( " source.bind_service " , " source.bind_service " )
_add_arg ( " source.connect_host " , " source.connect_host " , cb = set_connect_cb )
_add_arg ( " source.connect_service " , " source.connect_service " )
_add_arg ( " source.mode " , " source.mode " )
_add_arg ( " source.master " , " source.master " )
_add_arg ( " source.slave " , " source.slave " )
2019-05-14 03:13:42 +03:00
_add_device_seclabel_args ( cls , " source.seclabels " , prefix = prefix )
2019-05-13 23:17:08 +03:00
_add_arg ( " protocol.type " , " source.protocol " )
_add_arg ( " log.file " , " source.log_file " )
_add_arg ( " log.append " , " source.log_append " , is_onoff = True )
2013-03-18 01:06:52 +04:00
##################
# --disk parsing #
##################
2014-02-11 03:47:58 +04:00
def _default_image_file_format ( conn ) :
2019-06-07 23:06:52 +03:00
if conn . support . conn_default_qcow2 ( ) :
2014-02-11 03:47:58 +04:00
return " qcow2 "
2019-06-10 21:15:50 +03:00
return " raw " # pragma: no cover
2014-02-11 03:47:58 +04:00
2014-12-06 02:17:39 +03:00
def _get_default_image_format ( conn , poolobj ) :
tmpvol = StorageVolume ( conn )
tmpvol . pool = poolobj
if tmpvol . file_type != StorageVolume . TYPE_FILE :
return None
return _default_image_file_format ( conn )
def _generate_new_volume_name ( guest , poolobj , fmt ) :
ext = StorageVolume . get_file_extension_for_format ( fmt )
return StorageVolume . find_free_name (
2019-06-17 08:04:06 +03:00
guest . conn , poolobj , guest . name or " disk " ,
suffix = ext , collideguest = guest )
2013-03-18 01:06:52 +04:00
2013-04-13 22:34:52 +04:00
2014-01-19 22:56:06 +04:00
class ParserDisk ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " disk "
2019-05-10 20:03:27 +03:00
guest_propname = " devices.disk "
2016-06-13 23:30:29 +03:00
remove_first = " path "
2017-03-09 01:03:01 +03:00
stub_none = False
2019-05-12 04:51:08 +03:00
aliases = {
" blockio.logical_block_size " : " logical_block_size " ,
" blockio.physical_block_size " : " physical_block_size " ,
" iotune.read_bytes_sec " : " read_bytes_sec " ,
" iotune.write_bytes_sec " : " write_bytes_sec " ,
" iotune.total_bytes_sec " : " total_bytes_sec " ,
" iotune.read_iops_sec " : " read_iops_sec " ,
" iotune.write_iops_sec " : " write_iops_sec " ,
" iotune.total_iops_sec " : " total_iops_sec " ,
" source.pool " : " source_pool " ,
" source.volume " : " source_volume " ,
" source.name " : " source_name " ,
" source.protocol " : " source_protocol " ,
2019-05-15 16:47:53 +03:00
" source.host[0-9]*.name " : " source_host_name " ,
" source.host[0-9]*.port " : " source_host_port " ,
" source.host[0-9]*.socket " : " source_host_socket " ,
" source.host[0-9]*.transport " : " source_host_transport " ,
2019-05-12 04:51:08 +03:00
" source.startupPolicy " : " startup_policy " ,
2019-05-14 02:59:55 +03:00
" source.seclabel[0-9]*.model " : " seclabel[0-9]*.model " ,
" source.seclabel[0-9]*.relabel " : " seclabel[0-9]*.relabel " ,
" source.seclabel[0-9]*.label " : " seclabel[0-9]*.label " ,
2019-05-12 04:51:08 +03:00
" source.reservations.managed " : " reservations.managed " ,
" source.reservations.source.type " : " reservations.source.type " ,
" source.reservations.source.path " : " reservations.source.path " ,
" source.reservations.source.mode " : " reservations.source.mode " ,
" snapshot " : " snapshot_policy " ,
" target.dev " : " target " ,
" target.removable " : " removable " ,
2021-05-20 09:48:27 +03:00
" target.rotation_rate " : " rotation_rate " ,
2019-05-12 04:51:08 +03:00
" driver.discard " : " discard " ,
" driver.detect_zeroes " : " detect_zeroes " ,
" driver.error_policy " : " error_policy " ,
" driver.io " : " io " ,
" driver.name " : " driver_name " ,
" driver.type " : " driver_type " ,
}
2016-06-13 23:30:29 +03:00
2019-05-12 04:51:08 +03:00
def _add_advertised_aliases ( self ) :
# These are essentially aliases for new style options, but we still
# want to advertise them in --disk=help output because they are
# historically commonly used. This should rarely, if ever, be extended
if " bus " in self . optdict :
self . optdict [ " target.bus " ] = self . optdict . pop ( " bus " )
if " cache " in self . optdict :
self . optdict [ " driver.cache " ] = self . optdict . pop ( " cache " )
2016-06-15 00:29:54 +03:00
2016-06-14 14:37:21 +03:00
def _parse ( self , inst ) :
2019-05-12 04:51:08 +03:00
self . _add_advertised_aliases ( )
2016-06-14 14:37:21 +03:00
if self . optstr == " none " :
2014-09-21 03:16:13 +04:00
return
2014-01-19 22:56:06 +04:00
def parse_size ( val ) :
if val is None :
return None
2013-03-18 01:06:52 +04:00
try :
2014-01-19 22:56:06 +04:00
return float ( val )
2017-05-05 19:47:21 +03:00
except Exception as e :
2015-06-02 15:21:58 +03:00
fail ( _ ( " Improper value for ' size ' : %s " ) % str ( e ) )
2013-03-18 01:06:52 +04:00
2014-01-25 04:05:04 +04:00
def convert_perms ( val ) :
if val is None :
return
if val == " ro " :
2016-06-14 14:37:21 +03:00
self . optdict [ " readonly " ] = " on "
2014-01-25 04:05:04 +04:00
elif val == " sh " :
2016-06-14 14:37:21 +03:00
self . optdict [ " shareable " ] = " on "
2014-01-25 04:05:04 +04:00
elif val == " rw " :
# It's default. Nothing to do.
pass
else :
2020-07-14 10:41:54 +03:00
fail ( _ ( " Unknown ' %(optionname)s ' value ' %(string)s ' " ) %
2020-07-12 00:31:40 +03:00
{ " optionname " : " perms " , " string " : val } )
2013-03-18 01:06:52 +04:00
2016-06-14 14:37:21 +03:00
backing_store = self . optdict . pop ( " backing_store " , None )
2016-06-17 03:08:53 +03:00
backing_format = self . optdict . pop ( " backing_format " , None )
2016-06-14 14:37:21 +03:00
poolname = self . optdict . pop ( " pool " , None )
volname = self . optdict . pop ( " vol " , None )
size = parse_size ( self . optdict . pop ( " size " , None ) )
fmt = self . optdict . pop ( " format " , None )
2017-01-16 19:08:28 +03:00
sparse = _on_off_convert ( " sparse " , self . optdict . pop ( " sparse " , " yes " ) )
2016-06-14 14:37:21 +03:00
convert_perms ( self . optdict . pop ( " perms " , None ) )
2020-01-30 03:17:54 +03:00
disktype = self . optdict . pop ( " type " , None )
2014-12-06 02:17:39 +03:00
if volname :
if volname . count ( " / " ) != 1 :
raise ValueError ( _ ( " Storage volume must be specified as "
" vol=poolname/volname " ) )
poolname , volname = volname . split ( " / " )
2019-06-17 04:12:39 +03:00
log . debug ( " Parsed --disk volume as: pool= %s vol= %s " ,
2014-12-06 02:17:39 +03:00
poolname , volname )
2020-01-30 03:17:54 +03:00
# Set this up front, it has lots of follow on effects
if disktype :
inst . type = disktype
2018-12-18 16:44:55 +03:00
super ( ) . _parse ( inst )
2014-12-06 03:52:25 +03:00
2019-05-16 01:19:39 +03:00
if ( size and
not volname and
not poolname and
2020-11-11 23:38:34 +03:00
inst . is_empty ( ) and
2019-05-16 01:19:39 +03:00
inst . type == inst . TYPE_FILE ) :
# Saw something like --disk size=X, have it imply pool=default
poolname = " default "
2014-12-06 03:52:25 +03:00
# Generate and fill in the disk source info
newvolname = None
poolobj = None
2014-12-06 02:17:39 +03:00
if poolname :
if poolname == " default " :
2019-03-26 17:44:58 +03:00
poolxml = StoragePool . build_default_pool ( self . guest . conn )
if poolxml :
poolname = poolxml . name
2014-12-06 02:17:39 +03:00
poolobj = self . guest . conn . storagePoolLookupByName ( poolname )
2019-04-15 02:16:10 +03:00
StoragePool . ensure_pool_is_running ( poolobj )
2014-12-06 02:17:39 +03:00
2014-12-06 21:04:59 +03:00
if volname :
2014-12-06 02:17:39 +03:00
vol_object = poolobj . storageVolLookupByName ( volname )
2014-12-10 01:03:48 +03:00
inst . set_vol_object ( vol_object , poolobj )
2014-12-06 03:52:25 +03:00
poolobj = None
2014-12-06 21:04:59 +03:00
if ( ( poolobj or inst . wants_storage_creation ( ) ) and
( fmt or size or sparse or backing_store ) ) :
if not poolobj :
poolobj = inst . get_parent_pool ( )
2020-11-11 23:38:34 +03:00
newvolname = os . path . basename ( inst . get_source_path ( ) )
2014-12-06 21:04:59 +03:00
if poolobj and not fmt :
2014-12-06 02:17:39 +03:00
fmt = _get_default_image_format ( self . guest . conn , poolobj )
2014-12-06 03:52:25 +03:00
if newvolname is None :
newvolname = _generate_new_volume_name ( self . guest , poolobj ,
fmt )
2018-03-20 19:18:35 +03:00
vol_install = DeviceDisk . build_vol_install (
2014-12-06 03:52:25 +03:00
self . guest . conn , newvolname , poolobj , size , sparse ,
2016-06-17 03:08:53 +03:00
fmt = fmt , backing_store = backing_store ,
backing_format = backing_format )
2014-12-06 04:12:35 +03:00
inst . set_vol_install ( vol_install )
2014-01-26 06:08:11 +04:00
2014-01-19 22:56:06 +04:00
return inst
2013-03-18 01:06:52 +04:00
2019-05-12 04:51:08 +03:00
###################
# Option handling #
###################
2020-11-11 23:38:34 +03:00
def set_path_cb ( self , inst , val , virtarg ) :
inst . set_source_path ( val )
def path_lookup_cb ( self , inst , val , virtarg ) :
return inst . get_source_path ( ) == val
2019-05-15 16:47:53 +03:00
def host_find_inst_cb ( self , * args , * * kwargs ) :
2020-11-11 17:41:47 +03:00
cliarg = " hosts " # host[0-9]*
list_propname = " source.hosts " # disk.hosts
2019-05-15 16:47:53 +03:00
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( * args , * * kwargs )
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-14 19:45:57 +03:00
_add_common_device_args ( cls ,
boot_order = True , boot_loadparm = True , virtio_options = True )
2019-05-14 19:11:06 +03:00
2018-12-18 16:44:56 +03:00
# These are all handled specially in _parse
2019-05-10 22:04:47 +03:00
cls . add_arg ( " backing_store " , None , lookup_cb = None , cb = cls . noset_cb )
cls . add_arg ( " backing_format " , None , lookup_cb = None , cb = cls . noset_cb )
cls . add_arg ( " pool " , None , lookup_cb = None , cb = cls . noset_cb )
cls . add_arg ( " vol " , None , lookup_cb = None , cb = cls . noset_cb )
cls . add_arg ( " size " , None , lookup_cb = None , cb = cls . noset_cb )
cls . add_arg ( " format " , None , lookup_cb = None , cb = cls . noset_cb )
cls . add_arg ( " sparse " , None , lookup_cb = None , cb = cls . noset_cb )
2020-01-30 03:17:54 +03:00
cls . add_arg ( " type " , None , lookup_cb = None , cb = cls . noset_cb )
2019-05-12 04:51:08 +03:00
# These are handled in _add_advertised_aliases
cls . add_arg ( " bus " , " bus " , cb = cls . noset_cb )
cls . add_arg ( " cache " , " driver_cache " , cb = cls . noset_cb )
2019-05-10 22:04:47 +03:00
# More standard XML props
2020-11-11 17:41:47 +03:00
cls . add_arg ( " source.dir " , " source.dir " )
cls . add_arg ( " source.file " , " source.file " )
cls . add_arg ( " source.dev " , " source.dev " )
cls . add_arg ( " source.pool " , " source.pool " )
cls . add_arg ( " source.volume " , " source.volume " )
cls . add_arg ( " source.name " , " source.name " )
cls . add_arg ( " source.protocol " , " source.protocol " )
2019-05-12 04:51:08 +03:00
cls . add_arg ( " source.startupPolicy " , " startup_policy " )
2020-09-13 16:52:56 +03:00
# type=nvme source props
2020-11-11 17:41:47 +03:00
cls . add_arg ( " source.type " , " source.type " )
cls . add_arg ( " source.namespace " , " source.namespace " )
cls . add_arg ( " source.managed " , " source.managed " , is_onoff = True )
cls . add_arg ( " source.address.domain " , " source.address.domain " )
cls . add_arg ( " source.address.bus " , " source.address.bus " )
cls . add_arg ( " source.address.slot " , " source.address.slot " )
cls . add_arg ( " source.address.function " , " source.address.function " )
2019-05-15 16:47:53 +03:00
cls . add_arg ( " source.host[0-9]*.name " , " name " ,
find_inst_cb = cls . host_find_inst_cb )
cls . add_arg ( " source.host[0-9]*.port " , " port " ,
find_inst_cb = cls . host_find_inst_cb )
cls . add_arg ( " source.host[0-9]*.socket " , " socket " ,
find_inst_cb = cls . host_find_inst_cb )
cls . add_arg ( " source.host[0-9]*.transport " , " transport " ,
find_inst_cb = cls . host_find_inst_cb )
2019-05-14 03:03:23 +03:00
_add_device_seclabel_args ( cls , " seclabels " )
2018-12-18 16:44:56 +03:00
2020-11-11 23:38:34 +03:00
cls . add_arg ( " path " , None ,
cb = cls . set_path_cb ,
lookup_cb = cls . path_lookup_cb )
2018-12-18 16:44:56 +03:00
cls . add_arg ( " device " , " device " )
2019-05-12 04:51:08 +03:00
cls . add_arg ( " snapshot " , " snapshot_policy " )
cls . add_arg ( " sgio " , " sgio " )
2019-05-20 14:43:34 +03:00
cls . add_arg ( " rawio " , " rawio " )
2018-12-18 16:44:56 +03:00
cls . add_arg ( " serial " , " serial " )
2019-05-17 18:26:02 +03:00
cls . add_arg ( " wwn " , " wwn " )
2019-04-09 20:35:20 +03:00
cls . add_arg ( " readonly " , " read_only " , is_onoff = True )
2018-12-18 16:44:56 +03:00
cls . add_arg ( " shareable " , " shareable " , is_onoff = True )
2021-05-26 04:22:10 +03:00
cls . add_arg ( " transient " , " transient " , is_onoff = True )
2021-05-26 04:22:11 +03:00
cls . add_arg ( " transient.shareBacking " , " transient_shareBacking " , is_onoff = True )
2019-05-12 04:51:08 +03:00
cls . add_arg ( " target.bus " , " bus " )
cls . add_arg ( " target.removable " , " removable " , is_onoff = True )
cls . add_arg ( " target.dev " , " target " )
2021-05-20 09:48:27 +03:00
cls . add_arg ( " target.rotation_rate " , " rotation_rate " )
2019-05-12 04:51:08 +03:00
cls . add_arg ( " driver.cache " , " driver_cache " )
cls . add_arg ( " driver.discard " , " driver_discard " )
cls . add_arg ( " driver.detect_zeroes " , " driver_detect_zeroes " )
cls . add_arg ( " driver.name " , " driver_name " )
cls . add_arg ( " driver.type " , " driver_type " )
cls . add_arg ( " driver.copy_on_read " , " driver_copy_on_read " , is_onoff = True )
cls . add_arg ( " driver.io " , " driver_io " )
2019-08-28 19:43:56 +03:00
cls . add_arg ( " driver.iothread " , " driver_iothread " )
2021-07-26 19:44:45 +03:00
cls . add_arg ( " driver.queues " , " driver_queues " )
2019-05-12 04:51:08 +03:00
cls . add_arg ( " driver.error_policy " , " error_policy " )
cls . add_arg ( " iotune.read_bytes_sec " , " iotune_rbs " )
cls . add_arg ( " iotune.write_bytes_sec " , " iotune_wbs " )
cls . add_arg ( " iotune.total_bytes_sec " , " iotune_tbs " )
cls . add_arg ( " iotune.read_iops_sec " , " iotune_ris " )
cls . add_arg ( " iotune.write_iops_sec " , " iotune_wis " )
cls . add_arg ( " iotune.total_iops_sec " , " iotune_tis " )
cls . add_arg ( " blockio.logical_block_size " , " logical_block_size " )
cls . add_arg ( " blockio.physical_block_size " , " physical_block_size " )
2018-12-18 16:44:56 +03:00
2019-04-09 20:35:20 +03:00
cls . add_arg ( " geometry.cyls " , " geometry_cyls " )
cls . add_arg ( " geometry.heads " , " geometry_heads " )
cls . add_arg ( " geometry.secs " , " geometry_secs " )
cls . add_arg ( " geometry.trans " , " geometry_trans " )
2018-12-18 16:44:56 +03:00
2019-05-12 04:51:08 +03:00
cls . add_arg ( " source.reservations.managed " ,
" reservations_managed " )
cls . add_arg ( " source.reservations.source.type " ,
" reservations_source_type " )
cls . add_arg ( " source.reservations.source.path " ,
" reservations_source_path " )
cls . add_arg ( " source.reservations.source.mode " ,
" reservations_source_mode " )
2018-10-10 12:50:33 +03:00
2016-06-13 23:30:29 +03:00
2013-03-18 01:06:52 +04:00
#####################
# --network parsing #
#####################
2014-01-19 22:56:06 +04:00
class ParserNetwork ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " network "
2019-05-10 20:03:27 +03:00
guest_propname = " devices.interface "
2016-06-13 23:30:29 +03:00
remove_first = " type "
2017-03-09 01:03:01 +03:00
stub_none = False
2019-05-12 05:01:47 +03:00
aliases = {
" driver.name " : " driver_name " ,
" driver.queues " : " driver_queues " ,
" filterref.filter " : " filterref " ,
" link.state " : " link_state " ,
" mac.address " : " mac " ,
" model.type " : " model " ,
" rom.file " : " rom_file " ,
" rom.bar " : " rom_bar " ,
" target.dev " : " target " ,
" source.portgroup " : " portgroup " ,
" source.type " : " source_type " ,
" source.path " : " source_path " ,
" source.mode " : " source_mode " ,
" virtualport.type " : " virtualport_type " ,
" virtualport.parameters.managerid " : " virtualport_managerid " ,
2019-05-15 21:43:37 +03:00
" virtualport.parameters.typeid " : " virtualport_typeid " ,
" virtualport.parameters.typeidversion " : " virtualport_typeidversion " ,
" virtualport.parameters.instanceid " : " virtualport_instanceid " ,
" virtualport.parameters.profileid " : " virtualport_profileid " ,
2019-05-12 05:01:47 +03:00
" virtualport.parameters.interfaceid " : " virtualport_interfaceid " ,
}
def _add_advertised_aliases ( self ) :
# These are essentially aliases for new style options, but we still
# want to advertise them in --network=help output because they are
# historically commonly used. This should rarely, if ever, be extended
if " model " in self . optdict :
self . optdict [ " model.type " ] = self . optdict . pop ( " model " )
if " mac " in self . optdict :
self . optdict [ " mac.address " ] = self . optdict . pop ( " mac " )
2019-05-16 01:29:19 +03:00
# Back compat with old style network= and bridge=
2019-05-12 05:01:47 +03:00
if " type " not in self . optdict :
if " network " in self . optdict :
self . optdict [ " type " ] = DeviceInterface . TYPE_VIRTUAL
self . optdict [ " source " ] = self . optdict . pop ( " network " )
elif " bridge " in self . optdict :
self . optdict [ " type " ] = DeviceInterface . TYPE_BRIDGE
self . optdict [ " source " ] = self . optdict . pop ( " bridge " )
2019-05-16 01:29:19 +03:00
else :
self . optdict . pop ( " network " , None )
self . optdict . pop ( " bridge " , None )
def _parse ( self , inst ) :
self . _add_advertised_aliases ( )
if self . optstr == " none " :
return
2019-05-12 05:01:47 +03:00
return super ( ) . _parse ( inst )
###################
# Option handling #
###################
2013-03-18 01:06:52 +04:00
2016-06-14 18:38:53 +03:00
def set_mac_cb ( self , inst , val , virtarg ) :
2016-06-13 23:30:29 +03:00
if val == " RANDOM " :
return None
inst . macaddr = val
return val
2014-02-06 02:45:46 +04:00
2016-06-14 18:38:53 +03:00
def set_type_cb ( self , inst , val , virtarg ) :
2016-06-13 23:30:29 +03:00
if val == " default " :
inst . set_default_source ( )
else :
inst . type = val
2015-11-18 21:59:15 +03:00
2016-06-14 18:38:53 +03:00
def set_link_state ( self , inst , val , virtarg ) :
ignore = virtarg
2016-06-13 23:30:29 +03:00
if val in [ " up " , " down " ] :
2015-11-18 21:59:15 +03:00
inst . link_state = val
2016-06-13 23:30:29 +03:00
return
2015-11-18 21:59:15 +03:00
2016-06-13 23:30:29 +03:00
ret = _raw_on_off_convert ( val )
if ret is True :
val = " up "
elif ret is False :
val = " down "
inst . link_state = val
2015-08-28 14:12:49 +03:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-14 19:45:57 +03:00
_add_common_device_args ( cls ,
boot_order = True , boot_loadparm = True , virtio_options = True )
2019-05-12 05:01:47 +03:00
# These are handled in _add_advertised_aliases
cls . add_arg ( " model " , " model " , cb = cls . noset_cb )
cls . add_arg ( " mac " , " macaddr " , cb = cls . noset_cb )
2019-05-16 01:29:19 +03:00
cls . add_arg ( " network " , " source " , cb = cls . noset_cb )
cls . add_arg ( " bridge " , " source " , cb = cls . noset_cb )
2019-05-12 05:01:47 +03:00
# Standard XML options
2018-12-18 16:44:56 +03:00
cls . add_arg ( " type " , " type " , cb = cls . set_type_cb )
2019-05-12 05:01:47 +03:00
cls . add_arg ( " trustGuestRxFilters " , " trustGuestRxFilters " , is_onoff = True )
2018-12-18 16:44:56 +03:00
cls . add_arg ( " source " , " source " )
2019-05-12 05:01:47 +03:00
cls . add_arg ( " source.mode " , " source_mode " )
cls . add_arg ( " source.type " , " source_type " )
cls . add_arg ( " source.path " , " source_path " )
cls . add_arg ( " source.portgroup " , " portgroup " )
cls . add_arg ( " target.dev " , " target_dev " )
cls . add_arg ( " model.type " , " model " )
cls . add_arg ( " mac.address " , " macaddr " , cb = cls . set_mac_cb )
cls . add_arg ( " filterref.filter " , " filterref " )
cls . add_arg ( " link.state " , " link_state " , cb = cls . set_link_state )
2018-12-18 16:44:56 +03:00
2019-05-12 05:01:47 +03:00
cls . add_arg ( " driver.name " , " driver_name " )
cls . add_arg ( " driver.queues " , " driver_queues " )
2018-12-18 16:44:56 +03:00
2019-05-12 05:01:47 +03:00
cls . add_arg ( " rom.file " , " rom_file " )
cls . add_arg ( " rom.bar " , " rom_bar " , is_onoff = True )
2018-12-18 16:44:56 +03:00
2019-04-09 20:35:20 +03:00
cls . add_arg ( " mtu.size " , " mtu_size " )
2018-12-18 16:44:56 +03:00
2019-05-12 05:01:47 +03:00
cls . add_arg ( " virtualport.type " ,
" virtualport.type " )
cls . add_arg ( " virtualport.parameters.managerid " ,
" virtualport.managerid " )
cls . add_arg ( " virtualport.parameters.typeid " ,
" virtualport.typeid " )
cls . add_arg ( " virtualport.parameters.typeidversion " ,
" virtualport.typeidversion " )
cls . add_arg ( " virtualport.parameters.instanceid " ,
" virtualport.instanceid " )
cls . add_arg ( " virtualport.parameters.profileid " ,
" virtualport.profileid " )
cls . add_arg ( " virtualport.parameters.interfaceid " ,
" virtualport.interfaceid " )
2016-06-13 23:30:29 +03:00
2013-03-18 01:06:52 +04:00
######################
# --graphics parsing #
######################
2014-01-19 22:56:06 +04:00
class ParserGraphics ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " graphics "
2019-05-10 20:03:27 +03:00
guest_propname = " devices.graphics "
2016-06-13 23:30:29 +03:00
remove_first = " type "
2017-03-09 01:03:01 +03:00
stub_none = False
2019-05-12 15:50:32 +03:00
aliases = {
" tlsPort " : " tlsport " ,
" password " : " passwd " ,
" passwordValidTo " : " passwdValidTo " ,
" image.compression " : " image_compression " ,
" streaming.mode " : " streaming_mode " ,
" clipboard.copypaste " : " clipboard_copypaste " ,
" filetransfer.enable " : " filetransfer_enable " ,
" mouse.mode " : " mouse_mode " ,
" gl.enable " : " gl " ,
" gl.rendernode " : " rendernode " ,
}
def _parse ( self , inst ) :
if self . optstr == " none " :
self . guest . skip_default_graphics = True
return
2019-07-02 20:01:12 +03:00
return super ( ) . _parse ( inst )
2019-05-12 15:50:32 +03:00
###################
# Option handling #
###################
2013-03-18 01:06:52 +04:00
2016-06-14 18:38:53 +03:00
def set_keymap_cb ( self , inst , val , virtarg ) :
2016-06-13 23:30:29 +03:00
if not val :
val = None
elif val . lower ( ) == " local " :
2020-01-25 00:03:17 +03:00
log . debug ( " keymap=local is no longer implemented. Using None. " )
val = None
2016-06-13 23:30:29 +03:00
elif val . lower ( ) == " none " :
val = None
inst . keymap = val
2016-06-14 18:38:53 +03:00
def set_type_cb ( self , inst , val , virtarg ) :
2016-06-13 23:30:29 +03:00
if val == " default " :
return
inst . type = val
2018-01-26 20:50:44 +03:00
def listens_find_inst_cb ( self , * args , * * kwargs ) :
cliarg = " listens " # listens[0-9]*
2019-05-10 20:03:27 +03:00
list_propname = " listens " # graphics.listens
cb = self . _make_find_inst_cb ( cliarg , list_propname )
2018-01-26 20:50:44 +03:00
return cb ( * args , * * kwargs )
2017-09-06 11:17:43 +03:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-14 19:11:06 +03:00
_add_common_device_args ( cls )
2019-05-12 15:50:32 +03:00
2019-05-10 22:04:47 +03:00
cls . add_arg ( " type " , " type " , cb = cls . set_type_cb )
2018-12-18 16:44:56 +03:00
cls . add_arg ( " port " , " port " )
2019-05-12 15:50:32 +03:00
cls . add_arg ( " tlsPort " , " tlsPort " )
2020-07-16 15:55:17 +03:00
cls . add_arg ( " websocket " , " websocket " )
2019-02-22 18:32:39 +03:00
cls . add_arg ( " listen " , " listen " )
2019-05-10 22:04:47 +03:00
cls . add_arg ( " keymap " , " keymap " , cb = cls . set_keymap_cb )
2019-04-09 20:35:20 +03:00
cls . add_arg ( " password " , " passwd " )
2019-05-12 15:50:32 +03:00
cls . add_arg ( " passwordValidTo " , " passwdValidTo " )
2018-12-18 16:44:56 +03:00
cls . add_arg ( " connected " , " connected " )
cls . add_arg ( " defaultMode " , " defaultMode " )
2019-05-12 15:50:32 +03:00
cls . add_arg ( " listens[0-9]*.type " , " type " ,
find_inst_cb = cls . listens_find_inst_cb )
cls . add_arg ( " listens[0-9]*.address " , " address " ,
find_inst_cb = cls . listens_find_inst_cb )
cls . add_arg ( " listens[0-9]*.network " , " network " ,
find_inst_cb = cls . listens_find_inst_cb )
cls . add_arg ( " listens[0-9]*.socket " , " socket " ,
find_inst_cb = cls . listens_find_inst_cb )
cls . add_arg ( " image.compression " , " image_compression " )
cls . add_arg ( " streaming.mode " , " streaming_mode " )
cls . add_arg ( " clipboard.copypaste " , " clipboard_copypaste " ,
2018-12-18 16:44:56 +03:00
is_onoff = True )
2019-05-12 15:50:32 +03:00
cls . add_arg ( " mouse.mode " , " mouse_mode " )
cls . add_arg ( " filetransfer.enable " , " filetransfer_enable " ,
2018-12-18 16:44:56 +03:00
is_onoff = True )
2019-05-16 17:21:19 +03:00
cls . add_arg ( " zlib.compression " , " zlib_compression " )
2019-05-12 15:50:32 +03:00
cls . add_arg ( " gl.enable " , " gl " , is_onoff = True )
cls . add_arg ( " gl.rendernode " , " rendernode " )
2016-06-13 23:30:29 +03:00
2013-03-18 01:06:52 +04:00
2013-07-15 20:36:57 +04:00
########################
# --controller parsing #
########################
2013-04-13 22:34:52 +04:00
2014-01-19 22:56:06 +04:00
class ParserController ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " controller "
2019-05-10 20:03:27 +03:00
guest_propname = " devices.controller "
2016-06-13 23:30:29 +03:00
remove_first = " type "
2019-05-12 15:54:36 +03:00
aliases = {
" master.startport " : " master " ,
" driver.queues " : " driver_queues " ,
}
2013-03-18 01:06:52 +04:00
2016-06-14 14:37:21 +03:00
def _parse ( self , inst ) :
if self . optstr == " usb2 " :
2018-03-20 19:18:35 +03:00
return DeviceController . get_usb2_controllers ( inst . conn )
2016-06-14 14:37:21 +03:00
elif self . optstr == " usb3 " :
2018-10-04 16:24:43 +03:00
return DeviceController . get_usb3_controller ( inst . conn , self . guest )
2018-12-18 16:44:55 +03:00
return super ( ) . _parse ( inst )
2013-03-18 01:06:52 +04:00
2019-05-12 15:54:36 +03:00
###################
# Option handling #
###################
def set_address_cb ( self , inst , val , virtarg ) :
2020-01-25 21:42:03 +03:00
# Convenience option for address= PCI parsing. This pattern should
# not be extended IMO, make users manually specify the address
# fields they need
2020-01-25 21:40:24 +03:00
addrstr = val
if addrstr . count ( " : " ) in [ 1 , 2 ] and " . " in addrstr :
inst . address . type = inst . address . ADDRESS_TYPE_PCI
addrstr , inst . address . function = addrstr . split ( " . " , 1 )
addrstr , inst . address . slot = addrstr . rsplit ( " : " , 1 )
inst . address . domain = " 0 "
if " : " in addrstr :
inst . address . domain , inst . address . bus = addrstr . split ( " : " , 1 )
return
raise ValueError (
_ ( " Expected PCI format string for ' %s ' " ) % addrstr )
2019-05-12 15:54:36 +03:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-14 19:45:57 +03:00
_add_common_device_args ( cls , virtio_options = True )
2019-05-14 19:11:06 +03:00
2018-12-18 16:44:56 +03:00
cls . add_arg ( " type " , " type " )
cls . add_arg ( " model " , " model " )
cls . add_arg ( " index " , " index " )
2019-03-20 23:24:41 +03:00
cls . add_arg ( " maxGrantFrames " , " maxGrantFrames " )
2020-09-18 21:09:38 +03:00
cls . add_arg ( " vectors " , " vectors " )
2019-05-12 15:54:36 +03:00
cls . add_arg ( " master.startport " , " master_startport " )
2019-08-28 20:17:32 +03:00
cls . add_arg ( " driver.iothread " , " driver_iothread " )
2019-05-12 15:54:36 +03:00
cls . add_arg ( " driver.queues " , " driver_queues " )
2020-11-21 00:59:54 +03:00
cls . add_arg ( " target.chassisNr " , " target_chassisNr " )
cls . add_arg ( " target.chassis " , " target_chassis " )
cls . add_arg ( " target.port " , " target_port " )
cls . add_arg ( " target.hotplug " , " target_hotplug " )
cls . add_arg ( " target.busNr " , " target_busNr " )
cls . add_arg ( " target.index " , " target_index " )
cls . add_arg ( " target.node " , " target_node " )
2013-03-18 01:06:52 +04:00
2019-05-12 15:54:36 +03:00
cls . add_arg ( " address " , None , lookup_cb = None , cb = cls . set_address_cb )
2016-06-13 23:30:29 +03:00
2015-04-09 20:22:40 +03:00
###################
# --input parsing #
###################
class ParserInput ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " input "
2019-05-10 20:03:27 +03:00
guest_propname = " devices.input "
2016-06-13 23:30:29 +03:00
remove_first = " type "
2015-04-09 20:22:40 +03:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-14 19:45:57 +03:00
_add_common_device_args ( cls , virtio_options = True )
2019-05-14 19:11:06 +03:00
2018-12-18 16:44:56 +03:00
cls . add_arg ( " type " , " type " , ignore_default = True )
cls . add_arg ( " bus " , " bus " , ignore_default = True )
2021-07-27 21:21:46 +03:00
cls . add_arg ( " model " , " model " )
cls . add_arg ( " source.evdev " , " source_evdev " )
cls . add_arg ( " source.dev " , " source_dev " )
2021-07-28 19:45:29 +03:00
cls . add_arg ( " source.repeat " , " source_repeat " , is_onoff = True )
2021-07-27 21:21:46 +03:00
cls . add_arg ( " source.grab " , " source_grab " )
cls . add_arg ( " source.grabToggle " , " source_grabToggle " )
2015-04-09 20:22:40 +03:00
2020-09-10 19:39:21 +03:00
###################
# --iommu parsing #
###################
2020-07-07 10:55:53 +03:00
class ParserIommu ( VirtCLIParser ) :
cli_arg_name = " iommu "
guest_propname = " devices.iommu "
remove_first = " model "
@classmethod
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
cls . add_arg ( " model " , " model " )
cls . add_arg ( " driver.aw_bits " , " aw_bits " )
cls . add_arg ( " driver.intremap " , " intremap " , is_onoff = True )
cls . add_arg ( " driver.caching_mode " , " caching_mode " , is_onoff = True )
cls . add_arg ( " driver.eim " , " eim " , is_onoff = True )
cls . add_arg ( " driver.iotlb " , " iotlb " , is_onoff = True )
2013-03-18 01:06:52 +04:00
#######################
# --smartcard parsing #
#######################
2014-01-19 22:56:06 +04:00
class ParserSmartcard ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " smartcard "
2019-05-10 20:03:27 +03:00
guest_propname = " devices.smartcard "
2016-06-13 23:30:29 +03:00
remove_first = " mode "
2013-03-18 01:06:52 +04:00
2019-05-14 18:14:28 +03:00
def certificate_find_inst_cb ( self , * args , * * kwargs ) :
cliarg = " certificate " # certificate[0-9]*
list_propname = " certificates "
cb = self . _make_find_inst_cb ( cliarg , list_propname )
return cb ( * args , * * kwargs )
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-14 19:11:06 +03:00
_add_common_device_args ( cls )
2018-12-18 16:44:56 +03:00
cls . add_arg ( " mode " , " mode " , ignore_default = True )
cls . add_arg ( " type " , " type " , ignore_default = True )
2019-05-13 23:17:08 +03:00
_add_char_source_args ( cls )
2013-03-18 01:06:52 +04:00
2019-05-14 18:14:28 +03:00
cls . add_arg ( " database " , " database " , can_comma = True )
cls . add_arg ( " certificate[0-9]* " , " value " , can_comma = True ,
find_inst_cb = cls . certificate_find_inst_cb )
2013-03-18 01:06:52 +04:00
######################
# --redirdev parsing #
######################
2014-01-19 22:56:06 +04:00
class ParserRedir ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " redirdev "
2019-05-10 20:03:27 +03:00
guest_propname = " devices.redirdev "
2016-06-13 23:30:29 +03:00
remove_first = " bus "
2017-03-09 01:03:01 +03:00
stub_none = False
2014-01-19 19:37:14 +04:00
2016-06-14 18:38:53 +03:00
def set_server_cb ( self , inst , val , virtarg ) :
2019-05-13 21:59:33 +03:00
inst . source . set_friendly_host ( val )
2013-03-18 01:06:52 +04:00
2016-06-14 14:37:21 +03:00
def _parse ( self , inst ) :
if self . optstr == " none " :
2014-02-05 21:58:53 +04:00
self . guest . skip_default_usbredir = True
return
2018-12-18 16:44:55 +03:00
return super ( ) . _parse ( inst )
2014-02-05 21:58:53 +04:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-14 19:11:06 +03:00
_add_common_device_args ( cls , boot_order = True )
2018-12-18 16:44:56 +03:00
cls . add_arg ( " bus " , " bus " , ignore_default = True )
cls . add_arg ( " type " , " type " , ignore_default = True )
2019-05-10 22:04:47 +03:00
cls . add_arg ( " server " , None , lookup_cb = None , cb = cls . set_server_cb )
2019-05-13 23:17:08 +03:00
_add_char_source_args ( cls )
2016-06-13 23:30:29 +03:00
2013-06-26 05:45:07 +04:00
2013-07-15 20:36:57 +04:00
#################
# --tpm parsing #
#################
2013-06-26 05:45:07 +04:00
2014-01-19 22:56:06 +04:00
class ParserTPM ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " tpm "
2019-05-10 20:03:27 +03:00
guest_propname = " devices.tpm "
2016-06-13 23:30:29 +03:00
remove_first = " type "
2021-11-24 19:05:16 +03:00
stub_none = False
2019-05-12 16:00:39 +03:00
aliases = {
" backend.type " : " type " ,
" backend.version " : " version " ,
" backend.device.path " : " path " ,
}
2013-06-26 05:45:07 +04:00
2016-06-14 14:37:21 +03:00
def _parse ( self , inst ) :
2021-11-24 19:05:16 +03:00
if self . optstr == " none " :
self . guest . skip_default_tpm = True
return
2016-06-14 14:37:21 +03:00
if ( self . optdict . get ( " type " , " " ) . startswith ( " / " ) ) :
self . optdict [ " path " ] = self . optdict . pop ( " type " )
2018-12-18 16:44:55 +03:00
return super ( ) . _parse ( inst )
2013-09-28 18:28:04 +04:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-14 19:11:06 +03:00
_add_common_device_args ( cls )
2018-12-18 16:44:56 +03:00
cls . add_arg ( " model " , " model " )
2019-05-12 16:00:39 +03:00
cls . add_arg ( " backend.type " , " type " )
cls . add_arg ( " backend.version " , " version " )
cls . add_arg ( " backend.device.path " , " device_path " )
2019-09-04 15:29:58 +03:00
cls . add_arg ( " backend.encryption.secret " , " encryption_secret " )
2021-01-25 02:53:22 +03:00
cls . add_arg ( " backend.persistent_state " ,
" persistent_state " , is_onoff = True )
2016-06-13 23:30:29 +03:00
2013-06-26 05:45:07 +04:00
2013-09-28 00:52:41 +04:00
#################
# --rng parsing #
#################
2014-01-19 22:56:06 +04:00
class ParserRNG ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " rng "
2019-05-10 20:03:27 +03:00
guest_propname = " devices.rng "
2019-05-13 23:02:12 +03:00
remove_first = " backend.model "
2017-03-09 00:54:16 +03:00
stub_none = False
2019-05-13 23:02:12 +03:00
aliases = {
" backend.type " : " backend_type " ,
" backend.source.mode " : " backend_mode " ,
" backend.source.host " : " backend_host " ,
" backend.source.service " : " backend_service " ,
" backend.source.connect_host " : " backend_connect_host " ,
" backend.source.connect_service " : " backend_connect_service " ,
" rate.bytes " : " rate_bytes " ,
" rate.period " : " rate_period " ,
}
2016-06-13 23:30:29 +03:00
2019-05-13 23:02:12 +03:00
def _add_advertised_aliases ( self ) :
# These are essentially aliases for new style options, but we still
# want to advertise them in --rng=help output because they are
# historically commonly used. This should rarely, if ever, be extended
if " type " in self . optdict :
self . optdict [ " backend.model " ] = self . optdict . pop ( " type " )
if " device " in self . optdict :
self . optdict [ " backend " ] = self . optdict . pop ( " device " )
2013-09-18 17:29:29 +04:00
2016-06-14 14:37:21 +03:00
def _parse ( self , inst ) :
2017-03-09 00:54:16 +03:00
if self . optstr == " none " :
self . guest . skip_default_rng = True
return
2019-05-13 23:02:12 +03:00
self . _add_advertised_aliases ( )
if self . optdict . get ( " backend.model " , " " ) . startswith ( " / " ) :
# Handle --rng /path/to/dev
self . optdict [ " backend " ] = self . optdict . pop ( " backend.model " )
self . optdict [ " backend.model " ] = " random "
2014-01-19 22:56:06 +04:00
2018-12-18 16:44:55 +03:00
return super ( ) . _parse ( inst )
2014-01-19 22:56:06 +04:00
2019-05-13 23:02:12 +03:00
###################
# Option handling #
###################
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-14 19:45:57 +03:00
_add_common_device_args ( cls , virtio_options = True )
2019-05-14 19:11:06 +03:00
2019-05-13 23:02:12 +03:00
# These are handled in _add_advertised_aliases
cls . add_arg ( " type " , " backend_model " , cb = cls . noset_cb )
cls . add_arg ( " device " , " device " , cb = cls . noset_cb )
2016-06-13 23:30:29 +03:00
2018-12-18 16:44:56 +03:00
cls . add_arg ( " model " , " model " )
2019-05-13 23:02:12 +03:00
cls . add_arg ( " backend " , " device " )
cls . add_arg ( " backend.model " , " backend_model " )
cls . add_arg ( " backend.type " , " backend_type " )
2019-05-13 23:17:08 +03:00
_add_char_source_args ( cls , prefix = " backend. " )
2019-05-13 23:02:12 +03:00
cls . add_arg ( " rate.bytes " , " rate_bytes " )
cls . add_arg ( " rate.period " , " rate_period " )
2016-06-13 23:30:29 +03:00
2013-03-18 01:06:52 +04:00
######################
# --watchdog parsing #
######################
2014-01-19 22:56:06 +04:00
class ParserWatchdog ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " watchdog "
2019-05-10 20:03:27 +03:00
guest_propname = " devices.watchdog "
2016-06-13 23:30:29 +03:00
remove_first = " model "
2013-03-18 01:06:52 +04:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-14 19:11:06 +03:00
_add_common_device_args ( cls )
2018-12-18 16:44:56 +03:00
cls . add_arg ( " model " , " model " , ignore_default = True )
cls . add_arg ( " action " , " action " , ignore_default = True )
2013-03-18 01:06:52 +04:00
2017-05-05 12:50:06 +03:00
####################
# --memdev parsing #
####################
2018-12-18 16:44:54 +03:00
class ParserMemdev ( VirtCLIParser ) :
2017-05-05 12:50:06 +03:00
cli_arg_name = " memdev "
2019-05-10 20:03:27 +03:00
guest_propname = " devices.memory "
2017-05-05 12:50:06 +03:00
remove_first = " model "
2019-05-11 01:46:54 +03:00
aliases = {
" target.size " : " target_size " ,
" target.node " : " target_node " ,
" target.label_size " : " target_label_size " ,
" source.pagesize " : " source_pagesize " ,
" source.path " : " source_path " ,
" source.nodemask " : " source_nodemask " ,
}
2017-05-05 12:50:06 +03:00
def set_target_size ( self , inst , val , virtarg ) :
2019-06-08 01:21:24 +03:00
xmlutil . set_prop_path ( inst , virtarg . propname , int ( val ) * 1024 )
2017-05-05 12:50:06 +03:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-14 19:25:00 +03:00
_add_common_device_args ( cls )
2018-12-18 16:44:56 +03:00
cls . add_arg ( " model " , " model " )
cls . add_arg ( " access " , " access " )
2021-06-21 19:31:49 +03:00
cls . add_arg ( " discard " , " discard " , is_onoff = True )
2021-07-27 20:01:14 +03:00
cls . add_arg ( " uuid " , " uuid " )
2019-05-11 01:46:54 +03:00
cls . add_arg ( " target.size " , " target.size " , cb = cls . set_target_size )
cls . add_arg ( " target.node " , " target.node " )
2019-05-10 20:42:19 +03:00
cls . add_arg ( " target.label_size " , " target.label_size " ,
2019-05-11 01:46:54 +03:00
cb = cls . set_target_size )
2022-01-27 02:03:57 +03:00
cls . add_arg ( " target.block " , " target.block " )
cls . add_arg ( " target.current " , " target.current " )
cls . add_arg ( " target.requested " , " target.requested " )
2021-06-21 19:31:49 +03:00
cls . add_arg ( " target.readonly " , " target.readonly " , is_onoff = True )
2019-05-11 01:46:54 +03:00
cls . add_arg ( " source.pagesize " , " source.pagesize " )
cls . add_arg ( " source.path " , " source.path " )
cls . add_arg ( " source.nodemask " , " source.nodemask " , can_comma = True )
2021-06-21 19:31:49 +03:00
cls . add_arg ( " source.pmem " , " source.pmem " , is_onoff = True )
cls . add_arg ( " source.alignsize " , " source.alignsize " ,
cb = cls . set_target_size )
2017-05-05 12:50:06 +03:00
2013-03-18 01:06:52 +04:00
########################
# --memballoon parsing #
########################
2014-01-19 22:56:06 +04:00
class ParserMemballoon ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " memballoon "
2019-05-10 20:03:27 +03:00
guest_propname = " devices.memballoon "
2016-06-13 23:30:29 +03:00
remove_first = " model "
2017-03-09 01:03:01 +03:00
stub_none = False
2013-03-18 01:06:52 +04:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-14 19:45:57 +03:00
_add_common_device_args ( cls , virtio_options = True )
2019-05-14 19:11:06 +03:00
2019-06-09 23:39:15 +03:00
cls . add_arg ( " model " , " model " , ignore_default = True )
2019-05-23 15:57:43 +03:00
cls . add_arg ( " autodeflate " , " autodeflate " , is_onoff = True )
2019-05-28 19:53:45 +03:00
cls . add_arg ( " stats.period " , " stats_period " )
2021-01-25 02:49:55 +03:00
cls . add_arg ( " freePageReporting " , " freePageReporting " , is_onoff = True )
2013-03-18 01:06:52 +04:00
2014-01-22 13:44:38 +04:00
###################
# --panic parsing #
###################
2014-01-19 22:56:06 +04:00
class ParserPanic ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " panic "
2019-05-10 20:03:27 +03:00
guest_propname = " devices.panic "
2017-09-04 19:40:34 +03:00
remove_first = " model "
2019-05-12 16:20:53 +03:00
aliases = {
" address.iobase " : " iobase " ,
}
2017-09-04 19:40:34 +03:00
def _parse ( self , inst ) :
2019-05-12 16:20:53 +03:00
# Handle old style '--panic 0xFOO' to set the iobase value
if ( len ( self . optdict ) == 1 and
self . optdict . get ( " model " , " " ) . startswith ( " 0x " ) ) :
self . optdict [ " address.iobase " ] = self . optdict [ " model " ]
self . optdict [ " model " ] = DevicePanic . MODEL_ISA
2018-12-18 16:44:55 +03:00
return super ( ) . _parse ( inst )
2016-06-13 23:30:29 +03:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-14 19:11:06 +03:00
_add_common_device_args ( cls )
2019-05-12 16:20:53 +03:00
cls . add_arg ( " model " , " model " , ignore_default = True )
2014-01-22 13:44:38 +04:00
2021-07-26 23:14:30 +03:00
###################
# --shmem parsing #
###################
class ParserShMem ( VirtCLIParser ) :
cli_arg_name = " shmem "
guest_propname = " devices.shmem "
remove_first = " name "
@classmethod
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
_add_common_device_args ( cls )
cls . add_arg ( " name " , " name " )
cls . add_arg ( " role " , " role " )
cls . add_arg ( " model.type " , " type " )
cls . add_arg ( " size " , " size " )
cls . add_arg ( " size.unit " , " size_unit " )
cls . add_arg ( " server.path " , " server_path " )
cls . add_arg ( " msi.vectors " , " msi_vectors " )
cls . add_arg ( " msi.ioeventfd " , " msi_ioeventfd " )
2018-12-14 17:34:17 +03:00
###################
# --vsock parsing #
###################
class ParserVsock ( VirtCLIParser ) :
cli_arg_name = " vsock "
2019-05-10 20:03:27 +03:00
guest_propname = " devices.vsock "
2018-12-14 17:34:17 +03:00
remove_first = " model "
stub_none = False
2019-05-12 16:23:07 +03:00
aliases = {
" cid.auto " : " auto_cid " ,
" cid.address " : " cid " ,
}
2018-12-14 17:34:17 +03:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2021-07-30 20:09:08 +03:00
_add_common_device_args ( cls , virtio_options = True )
2019-05-14 19:11:06 +03:00
2019-06-09 23:39:15 +03:00
cls . add_arg ( " model " , " model " , ignore_default = True )
2019-05-12 16:23:07 +03:00
cls . add_arg ( " cid.auto " , " auto_cid " , is_onoff = True )
cls . add_arg ( " cid.address " , " cid " )
2018-12-14 17:34:17 +03:00
2013-03-18 01:06:52 +04:00
######################################################
# --serial, --parallel, --channel, --console parsing #
######################################################
2014-01-19 22:56:06 +04:00
class _ParserChar ( VirtCLIParser ) :
2019-12-24 20:02:53 +03:00
remove_first = " type "
2017-03-09 01:03:01 +03:00
stub_none = False
2019-05-13 22:33:05 +03:00
aliases = {
2019-12-24 20:02:53 +03:00
" type " : " char_type " ,
2019-05-13 22:33:05 +03:00
" protocol.type " : " protocol " ,
2014-01-19 22:56:06 +04:00
2019-05-13 22:33:05 +03:00
" target.address " : " target_address " ,
" target.type " : " target_type " ,
" target.name " : " name " ,
}
2014-01-19 22:56:06 +04:00
2019-05-13 22:33:05 +03:00
def _add_advertised_aliases ( self ) :
# These are essentially aliases for new style options, but we still
# want to advertise them in --$OPT=help output because they are
# historically commonly used. This should rarely, if ever, be extended
if " path " in self . optdict :
self . optdict [ " source.path " ] = self . optdict . pop ( " path " )
if " mode " in self . optdict :
self . optdict [ " source.mode " ] = self . optdict . pop ( " mode " )
if " bind_host " in self . optdict :
self . optdict [ " source.bind_host " ] = self . optdict . pop ( " bind_host " )
2015-09-05 23:27:27 +03:00
2016-06-14 14:37:21 +03:00
def _parse ( self , inst ) :
2018-03-21 01:59:14 +03:00
if self . optstr == " none " and inst . DEVICE_TYPE == " console " :
2014-01-19 22:56:06 +04:00
self . guest . skip_default_console = True
return
2018-03-21 01:59:14 +03:00
if self . optstr == " none " and inst . DEVICE_TYPE == " channel " :
2014-01-19 22:56:06 +04:00
self . guest . skip_default_channel = True
return
2013-03-18 01:06:52 +04:00
2019-05-13 22:33:05 +03:00
self . _add_advertised_aliases ( )
2018-12-18 16:44:55 +03:00
return super ( ) . _parse ( inst )
2013-10-06 17:41:37 +04:00
2019-05-13 22:33:05 +03:00
###################
# Option handling #
###################
def set_host_cb ( self , inst , val , virtarg ) :
if ( " source.bind_host " not in self . optdict and
self . optdict . get ( " source.mode " , None ) == " bind " ) :
inst . source . set_friendly_bind ( val )
else :
inst . source . set_friendly_connect ( val )
def set_target_cb ( self , inst , val , virtarg ) :
inst . set_friendly_target ( val )
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
2019-05-11 00:27:32 +03:00
# _virtargs already populated via subclass creation, so
# don't double register options
if cls . _virtargs :
return
2019-05-10 20:17:30 +03:00
VirtCLIParser . _init_class ( * * kwargs )
2019-05-14 19:25:00 +03:00
_add_common_device_args ( cls )
2019-12-24 20:02:53 +03:00
cls . add_arg ( " type " , " type " )
2019-05-13 22:33:05 +03:00
# These are handled in _add_advertised_aliases
cls . add_arg ( " path " , " source.path " , cb = cls . noset_cb )
cls . add_arg ( " mode " , " source.mode " , cb = cls . noset_cb )
cls . add_arg ( " bind_host " , " source.bind_host " , cb = cls . noset_cb )
# Old backcompat argument
cls . add_arg ( " host " , " source.host " , cb = cls . set_host_cb )
2019-05-13 23:17:08 +03:00
_add_char_source_args ( cls )
2016-06-13 23:30:29 +03:00
2019-05-13 22:33:05 +03:00
cls . add_arg ( " target.address " , " target_address " , cb = cls . set_target_cb )
cls . add_arg ( " target.type " , " target_type " )
cls . add_arg ( " target.name " , " target_name " )
2019-05-14 18:21:16 +03:00
cls . add_arg ( " target.port " , " target_port " )
2019-05-14 18:32:18 +03:00
cls . add_arg ( " target.model.name " , " target_model_name " )
2019-05-13 22:33:05 +03:00
2014-01-19 22:56:06 +04:00
class ParserSerial ( _ParserChar ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " serial "
2019-05-10 20:03:27 +03:00
guest_propname = " devices.serial "
2014-01-19 22:56:06 +04:00
class ParserParallel ( _ParserChar ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " parallel "
2019-05-10 20:03:27 +03:00
guest_propname = " devices.parallel "
2014-01-19 22:56:06 +04:00
class ParserChannel ( _ParserChar ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " channel "
2019-05-10 20:03:27 +03:00
guest_propname = " devices.channel "
2014-01-19 22:56:06 +04:00
class ParserConsole ( _ParserChar ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " console "
2019-05-10 20:03:27 +03:00
guest_propname = " devices.console "
2013-09-28 00:52:41 +04:00
2013-03-18 01:06:52 +04:00
########################
# --filesystem parsing #
########################
2014-01-19 22:56:06 +04:00
class ParserFilesystem ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " filesystem "
2019-05-10 20:03:27 +03:00
guest_propname = " devices.filesystem "
2016-06-13 23:30:29 +03:00
remove_first = [ " source " , " target " ]
2019-05-11 01:46:54 +03:00
aliases = {
" accessmode " : " mode " ,
}
2013-03-18 01:06:52 +04:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-14 19:45:57 +03:00
_add_common_device_args ( cls , virtio_options = True )
2019-05-14 19:11:06 +03:00
2018-12-18 16:44:56 +03:00
cls . add_arg ( " type " , " type " )
2019-05-11 01:46:54 +03:00
cls . add_arg ( " accessmode " , " accessmode " )
2020-09-10 20:06:41 +03:00
cls . add_arg ( " model " , " model " )
cls . add_arg ( " multidevs " , " multidevs " )
cls . add_arg ( " readonly " , " readonly " , is_onoff = True )
cls . add_arg ( " space_hard_limit " , " space_hard_limit " )
cls . add_arg ( " space_soft_limit " , " space_soft_limit " )
2021-01-25 02:45:07 +03:00
cls . add_arg ( " fmode " , " fmode " )
cls . add_arg ( " dmode " , " dmode " )
2020-09-10 20:06:41 +03:00
2018-12-18 16:44:56 +03:00
cls . add_arg ( " source " , " source " )
cls . add_arg ( " target " , " target " )
2013-03-18 01:06:52 +04:00
2020-09-10 20:06:41 +03:00
cls . add_arg ( " source.file " , " source_file " )
cls . add_arg ( " source.dir " , " source_dir " )
cls . add_arg ( " source.dev " , " source_dev " )
cls . add_arg ( " source.name " , " source_name " )
cls . add_arg ( " source.pool " , " source_pool " )
cls . add_arg ( " source.volume " , " source_volume " )
cls . add_arg ( " source.units " , " source_units " )
cls . add_arg ( " source.usage " , " source_usage " )
2021-07-30 20:15:29 +03:00
cls . add_arg ( " source.socket " , " source_socket " )
2020-09-10 20:06:41 +03:00
cls . add_arg ( " target.dir " , " target_dir " )
cls . add_arg ( " binary.path " , " binary_path " )
cls . add_arg ( " binary.xattr " , " binary_xattr " , is_onoff = True )
cls . add_arg ( " binary.cache.mode " , " binary_cache_mode " )
cls . add_arg ( " binary.lock.posix " , " binary_lock_posix " , is_onoff = True )
cls . add_arg ( " binary.lock.flock " , " binary_lock_flock " , is_onoff = True )
2021-07-30 20:15:29 +03:00
cls . add_arg ( " binary.sandbox.mode " , " binary_sandbox_mode " )
2020-09-10 20:06:41 +03:00
cls . add_arg ( " driver.format " , " driver_format " )
cls . add_arg ( " driver.name " , " driver_name " )
cls . add_arg ( " driver.queue " , " driver_queue " )
cls . add_arg ( " driver.type " , " driver_type " )
cls . add_arg ( " driver.wrpolicy " , " driver_wrpolicy " )
2013-03-18 01:06:52 +04:00
###################
# --video parsing #
###################
2014-01-19 22:56:06 +04:00
class ParserVideo ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " video "
2019-05-10 20:03:27 +03:00
guest_propname = " devices.video "
2019-05-12 16:38:33 +03:00
remove_first = " model.type "
aliases = {
" model.type " : " model " ,
" model.heads " : " heads " ,
" model.ram " : " ram " ,
" model.vram " : " vram " ,
" model.vram64 " : " vram64 " ,
" model.vgamem " : " vgamem " ,
" model.acceleration.accel3d " : " accel3d " ,
}
2016-05-20 19:44:13 +03:00
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-14 19:45:57 +03:00
_add_common_device_args ( cls , virtio_options = True )
2019-05-14 19:11:06 +03:00
2019-05-12 16:38:33 +03:00
cls . add_arg ( " model.type " , " model " , ignore_default = True )
cls . add_arg ( " model.acceleration.accel3d " , " accel3d " , is_onoff = True )
cls . add_arg ( " model.heads " , " heads " )
cls . add_arg ( " model.ram " , " ram " )
cls . add_arg ( " model.vram " , " vram " )
cls . add_arg ( " model.vram64 " , " vram64 " )
cls . add_arg ( " model.vgamem " , " vgamem " )
2016-06-13 23:30:29 +03:00
2013-03-18 01:06:52 +04:00
2014-02-05 21:49:16 +04:00
###################
2014-02-05 21:32:53 +04:00
# --sound parsing #
2014-02-05 21:49:16 +04:00
###################
2013-03-18 01:06:52 +04:00
2014-01-19 22:56:06 +04:00
class ParserSound ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " sound "
2019-05-10 20:03:27 +03:00
guest_propname = " devices.sound "
2016-06-13 23:30:29 +03:00
remove_first = " model "
2017-03-09 01:03:01 +03:00
stub_none = False
2013-03-18 01:06:52 +04:00
2016-06-14 14:37:21 +03:00
def _parse ( self , inst ) :
if self . optstr == " none " :
2014-02-05 21:49:16 +04:00
self . guest . skip_default_sound = True
return
2018-12-18 16:44:55 +03:00
return super ( ) . _parse ( inst )
2014-02-05 21:49:16 +04:00
2018-06-11 18:48:30 +03:00
def codec_find_inst_cb ( self , * args , * * kwargs ) :
cliarg = " codec " # codec[0-9]*
2019-05-10 20:03:27 +03:00
list_propname = " codecs "
cb = self . _make_find_inst_cb ( cliarg , list_propname )
2018-06-11 18:48:30 +03:00
return cb ( * args , * * kwargs )
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-14 19:11:06 +03:00
_add_common_device_args ( cls )
2018-12-18 16:44:56 +03:00
cls . add_arg ( " model " , " model " , ignore_default = True )
2021-01-25 02:48:09 +03:00
cls . add_arg ( " audio.id " , " audio_id " )
2019-04-09 20:35:20 +03:00
cls . add_arg ( " codec[0-9]*.type " , " type " ,
2019-05-14 19:11:06 +03:00
find_inst_cb = cls . codec_find_inst_cb )
2016-06-13 23:30:29 +03:00
2013-03-18 01:06:52 +04:00
2016-06-13 23:30:29 +03:00
#####################
2014-09-20 22:29:34 +04:00
# --hostdev parsing #
2016-06-13 23:30:29 +03:00
#####################
2013-03-18 01:06:52 +04:00
2022-01-21 20:51:57 +03:00
def _AddressStringToHostdev ( conn , addrstr ) :
2022-01-21 20:58:50 +03:00
"""
Decompose common USB and PCI address string formats into a DeviceHostdev
instance . The 3 expected formats are :
- bus . addr ( ex . 001.003 for a usb device )
- vendor : product ( ex . 0x1234 : 0x5678 for a usb device
- ( domain : ) bus : slot . func ( ex . 00 : 10.0 for a pci device )
"""
2022-01-21 20:51:57 +03:00
hostdev = DeviceHostdev ( conn )
2022-01-21 20:58:50 +03:00
if addrstr . count ( " : " ) in [ 1 , 2 ] and " . " in addrstr :
# PCI address
addrstr , func = addrstr . split ( " . " , 1 )
addrstr , slot = addrstr . rsplit ( " : " , 1 )
domain = " 0 "
if " : " in addrstr :
domain , bus = addrstr . split ( " : " , 1 )
else :
bus = addrstr
2022-01-21 20:51:57 +03:00
2022-01-21 20:58:50 +03:00
hostdev . type = " pci "
hostdev . domain = " 0x %.4X " % int ( domain , 16 )
hostdev . function = " 0x %.2X " % int ( func , 16 )
hostdev . slot = " 0x %.2X " % int ( slot , 16 )
hostdev . bus = " 0x %.2X " % int ( bus , 16 )
2022-01-21 20:51:57 +03:00
2022-01-21 20:58:50 +03:00
elif " : " in addrstr :
# USB product:vendor
vendor , product = addrstr . split ( " : " )
2022-01-21 20:51:57 +03:00
2022-01-21 20:58:50 +03:00
hostdev . type = " usb "
hostdev . vendor = " 0x %.4X " % int ( vendor , 16 )
hostdev . product = " 0x %.4X " % int ( product , 16 )
2022-01-21 20:51:57 +03:00
2022-01-21 20:58:50 +03:00
elif " . " in addrstr :
# USB bus.device
bus , device = addrstr . split ( " . " , 1 )
2022-01-21 20:51:57 +03:00
2022-01-21 20:58:50 +03:00
hostdev . type = " usb "
hostdev . bus = bus
hostdev . device = device
else :
raise RuntimeError (
" Unknown hostdev address string format ' %s ' " % addrstr )
2022-01-21 20:51:57 +03:00
return hostdev
def _AddressStringToNodedev ( conn , addrstr ) :
2022-01-21 20:58:50 +03:00
try :
hostdev = _AddressStringToHostdev ( conn , addrstr )
except Exception :
log . debug ( " Error parsing node device string. " , exc_info = True )
raise
2022-01-21 20:51:57 +03:00
count = 0
nodedev = None
for xmlobj in conn . fetch_all_nodedevs ( ) :
if xmlobj . compare_to_hostdev ( hostdev ) :
nodedev = xmlobj
count + = 1
2022-01-21 20:58:50 +03:00
if count > 1 :
2022-01-21 20:51:57 +03:00
raise ValueError ( _ ( " %s corresponds to multiple node devices " ) %
addrstr )
2022-01-21 20:58:50 +03:00
if count < 1 :
2022-01-21 20:51:57 +03:00
raise ValueError ( _ ( " Did not find a matching node device for ' %s ' " ) %
addrstr )
2022-01-21 20:58:50 +03:00
return nodedev
2022-01-21 20:51:57 +03:00
def _lookupNodedevFromString ( conn , idstring ) :
# First try and see if this is a libvirt nodedev name
nodedev = NodeDevice . lookupNodedevByName ( conn , idstring )
if nodedev :
return nodedev
2022-01-21 20:58:50 +03:00
# If not it must be a special CLI format that we need to parse
2022-01-21 20:51:57 +03:00
try :
return _AddressStringToNodedev ( conn , idstring )
except Exception :
log . debug ( " Error looking up nodedev from idstring= %s " ,
idstring , exc_info = True )
raise
2014-01-19 22:56:06 +04:00
class ParserHostdev ( VirtCLIParser ) :
2016-06-14 14:37:21 +03:00
cli_arg_name = " hostdev "
2019-05-10 20:03:27 +03:00
guest_propname = " devices.hostdev "
2016-06-13 23:30:29 +03:00
remove_first = " name "
2019-05-12 16:32:55 +03:00
aliases = {
" driver.name " : " driver_name " ,
" rom.bar " : " rom_bar " ,
}
2016-06-13 23:30:29 +03:00
2016-06-14 18:38:53 +03:00
def set_name_cb ( self , inst , val , virtarg ) :
2018-06-15 12:29:34 +03:00
if inst . type == " net " :
inst . mode = " capabilities "
inst . net_interface = val
2018-06-15 12:29:35 +03:00
elif inst . type == " misc " :
inst . mode = " capabilities "
inst . misc_char = val
2018-06-15 12:29:36 +03:00
elif inst . type == " storage " :
inst . mode = " capabilities "
inst . storage_block = val
2018-06-15 12:29:34 +03:00
else :
2022-01-21 20:51:57 +03:00
val = _lookupNodedevFromString ( inst . conn , val )
2018-06-15 12:29:34 +03:00
inst . set_from_nodedev ( val )
2016-06-13 23:30:29 +03:00
2016-06-14 18:38:53 +03:00
def name_lookup_cb ( self , inst , val , virtarg ) :
2022-01-21 20:51:57 +03:00
nodedev = _lookupNodedevFromString ( inst . conn , val )
2016-06-13 23:30:29 +03:00
return nodedev . compare_to_hostdev ( inst )
2018-12-18 16:44:56 +03:00
@classmethod
2019-05-10 20:17:30 +03:00
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
2019-05-14 19:11:06 +03:00
_add_common_device_args ( cls , boot_order = True )
2018-12-18 16:44:56 +03:00
cls . add_arg ( " type " , " type " )
2019-05-10 22:04:47 +03:00
cls . add_arg ( " name " , None ,
2018-12-18 16:44:56 +03:00
cb = cls . set_name_cb ,
lookup_cb = cls . name_lookup_cb )
2019-05-12 16:32:55 +03:00
cls . add_arg ( " driver.name " , " driver_name " )
cls . add_arg ( " rom.bar " , " rom_bar " , is_onoff = True )
2013-09-28 02:06:39 +04:00
2013-09-28 00:52:41 +04:00
2019-06-11 18:41:57 +03:00
#############################
# --launchSecurity parsing #
#############################
class ParserLaunchSecurity ( VirtCLIParser ) :
cli_arg_name = " launchSecurity "
guest_propname = " launchSecurity "
remove_first = " type "
@classmethod
def _init_class ( cls , * * kwargs ) :
VirtCLIParser . _init_class ( * * kwargs )
cls . add_arg ( " type " , " type " )
cls . add_arg ( " cbitpos " , " cbitpos " )
cls . add_arg ( " reducedPhysBits " , " reducedPhysBits " )
cls . add_arg ( " policy " , " policy " )
cls . add_arg ( " session " , " session " )
cls . add_arg ( " dhCert " , " dhCert " )
2022-01-27 01:08:27 +03:00
cls . add_arg ( " kernelHashes " , " kernelHashes " , is_onoff = True )
2019-06-11 18:41:57 +03:00
2014-01-21 23:28:47 +04:00
###########################
2016-06-14 14:37:21 +03:00
# Public virt parser APIs #
2014-01-21 23:28:47 +04:00
###########################
2019-06-14 00:37:26 +03:00
def parse_option_strings ( options , guest , instlist , editing = False ) :
2014-01-21 23:28:47 +04:00
"""
2016-06-14 14:37:21 +03:00
Iterate over VIRT_PARSERS , and launch the associated parser
2014-01-21 23:28:47 +04:00
function for every value that was filled in on ' options ' , which
came from argparse / the command line .
2014-01-25 04:05:04 +04:00
2019-06-14 00:37:26 +03:00
@editing : If we are updating an existing guest , like from virt - xml
2014-01-21 23:28:47 +04:00
"""
2019-06-08 01:21:24 +03:00
instlist = xmlutil . listify ( instlist )
2014-01-19 19:37:14 +04:00
if not instlist :
instlist = [ None ]
2014-01-26 04:51:56 +04:00
ret = [ ]
2016-06-14 14:37:21 +03:00
for parserclass in VIRT_PARSERS :
2019-06-08 01:21:24 +03:00
optlist = xmlutil . listify ( getattr ( options , parserclass . cli_arg_name ) )
2016-06-14 14:37:21 +03:00
if not optlist :
2016-06-14 01:50:31 +03:00
continue
2016-06-14 14:37:21 +03:00
for inst in instlist :
if inst and optlist :
# If an object is passed in, we are updating it in place, and
# only use the last command line occurrence, eg. from virt-xml
optlist = [ optlist [ - 1 ] ]
2014-01-19 19:37:14 +04:00
2016-06-14 14:37:21 +03:00
for optstr in optlist :
2019-06-14 00:37:26 +03:00
parserobj = parserclass ( optstr , guest = guest , editing = editing )
parseret = parserobj . parse ( inst )
2019-06-08 01:21:24 +03:00
ret + = xmlutil . listify ( parseret )
2014-01-26 04:51:56 +04:00
return ret
2014-01-22 18:06:35 +04:00
2016-06-14 14:37:21 +03:00
def check_option_introspection ( options ) :
2014-01-22 18:06:35 +04:00
"""
2014-01-25 04:05:04 +04:00
Check if the user requested option introspection with ex : ' --disk=? '
2014-01-22 18:06:35 +04:00
"""
ret = False
2019-05-11 00:22:23 +03:00
for parserclass in _get_completer_parsers ( ) :
if not hasattr ( options , parserclass . cli_arg_name ) :
continue
2019-06-08 01:21:24 +03:00
optlist = xmlutil . listify ( getattr ( options , parserclass . cli_arg_name ) )
2016-06-14 14:37:21 +03:00
if not optlist :
2014-01-22 18:06:35 +04:00
continue
2016-06-14 01:36:12 +03:00
2016-06-14 14:37:21 +03:00
for optstr in optlist :
2016-06-14 01:36:12 +03:00
if optstr == " ? " or optstr == " help " :
2016-06-14 14:37:21 +03:00
parserclass . print_introspection ( )
2016-06-14 01:36:12 +03:00
ret = True
2014-01-22 18:06:35 +04:00
return ret