2020-01-27 01:12:09 +03:00
# Copyright 2013-2014 Red Hat, Inc.
#
# This work is licensed under the GNU GPLv2 or later.
# See the COPYING file in the top-level directory.
2021-10-12 19:58:21 +03:00
import os
2020-01-27 01:12:09 +03:00
import sys
import libvirt
from . import cli
2020-09-17 09:44:02 +03:00
from . cli import fail , fail_conflicting , print_stdout , print_stderr
2020-01-27 01:12:09 +03:00
from . guest import Guest
from . logger import log
from . import xmlutil
###################
# Utility helpers #
###################
def prompt_yes_or_no ( msg ) :
while 1 :
printmsg = msg + " (y/n): "
sys . stdout . write ( printmsg )
sys . stdout . flush ( )
inp = sys . stdin . readline ( ) . lower ( ) . strip ( )
if inp in [ " y " , " yes " ] :
return True
elif inp in [ " n " , " no " ] :
return False
else :
print_stdout ( _ ( " Please enter ' yes ' or ' no ' . " ) )
def get_diff ( origxml , newxml ) :
2020-09-05 15:29:04 +03:00
diff = xmlutil . diff ( origxml , newxml , " Original XML " , " Altered XML " )
2020-01-27 01:12:09 +03:00
2020-09-05 15:29:04 +03:00
if diff :
log . debug ( " XML diff: \n %s " , diff )
2020-01-27 01:12:09 +03:00
else :
log . debug ( " No XML diff, didn ' t generate any change. " )
2020-09-05 15:29:04 +03:00
return diff
2020-01-27 01:12:09 +03:00
2024-09-16 19:05:33 +03:00
def set_os_variant ( guest , os_variant ) :
if os_variant is None :
2020-01-27 01:12:09 +03:00
return
2024-09-16 19:05:33 +03:00
osdata = cli . parse_os_variant ( os_variant )
2020-09-15 02:05:58 +03:00
if osdata . get_name ( ) :
guest . set_os_name ( osdata . get_name ( ) )
2020-01-27 01:12:09 +03:00
def defined_xml_is_unchanged ( conn , domain , original_xml ) :
2020-02-03 15:20:40 +03:00
rawxml = cli . get_xmldesc ( domain , inactive = True )
2020-01-27 01:12:09 +03:00
new_xml = Guest ( conn , parsexml = rawxml ) . get_xml ( )
return new_xml == original_xml
2024-09-16 18:52:17 +03:00
##################
# Action parsing #
##################
2024-09-16 18:56:16 +03:00
class Action :
"""
Helper class tracking one pair of
XML ACTION ( ex . - - edit ) and
XML OPTION ( ex . - - disk )
"""
def __init__ ( self , action_name , selector , parserclass , parservalue ) :
# one of ["edit", "add-device", "remove-device", "build-xml"]
self . action_name = action_name
# ex. for `--edit 1` this is selector="1"
self . selector = selector
# ParserDisk, etc
self . parserclass = parserclass
# ex for `--disk path=/foo` this is "path=/foo"
self . parservalue = parservalue
@property
def is_edit ( self ) :
return self . action_name == " edit "
@property
def is_add_device ( self ) :
return self . action_name == " add-device "
@property
def is_remove_device ( self ) :
return self . action_name == " remove-device "
@property
def is_build_xml ( self ) :
return self . action_name == " build-xml "
def validate_action ( action , conn , options ) :
if options . os_variant is not None :
if action . is_edit :
fail ( _ ( " --os-variant/--osinfo is not supported with --edit " ) )
if action . is_remove_device :
fail ( _ ( " --os-variant/--osinfo is not supported with --remove-device " ) )
if action . is_build_xml :
fail ( _ ( " --os-variant/--osinfo is not supported with --build-xml " ) )
if not action . parserclass . guest_propname and action . is_build_xml :
2024-09-18 23:11:03 +03:00
fail ( _ ( " --build-xml not supported for {cli_flag} " ) . format (
cli_flag = action . parserclass . cli_flag_name ( ) ) )
2024-09-16 18:56:16 +03:00
stub_guest = Guest ( conn )
if not action . parserclass . prop_is_list ( stub_guest ) :
if action . is_remove_device :
2024-09-18 23:11:03 +03:00
fail ( _ ( " Cannot use --remove-device with {cli_flag} " ) . format (
cli_flag = action . parserclass . cli_flag_name ( ) ) )
2024-09-16 18:56:16 +03:00
if action . is_add_device :
2024-09-18 23:11:03 +03:00
fail ( _ ( " Cannot use --add-device with {cli_flag} " ) . format (
cli_flag = action . parserclass . cli_flag_name ( ) ) )
2024-09-16 18:56:16 +03:00
if options . update and not action . parserclass . guest_propname :
2024-09-18 23:11:03 +03:00
fail ( _ ( " Don ' t know how to --update for {cli_flag} " ) . format (
cli_flag = action . parserclass . cli_flag_name ( ) ) )
2024-09-16 18:52:17 +03:00
2024-09-16 18:56:16 +03:00
def check_action_collision ( options ) :
2024-09-16 18:52:17 +03:00
collisions = [ ]
2024-09-16 18:56:16 +03:00
actions = [ " edit " , " add-device " , " remove-device " , " build-xml " ]
2024-09-16 18:52:17 +03:00
for cliname in actions :
optname = cliname . replace ( " - " , " _ " )
2024-09-16 18:56:16 +03:00
value = getattr ( options , optname )
if value not in [ False , - 1 ] :
collisions . append ( ( cliname , value ) )
2024-09-16 18:52:17 +03:00
if len ( collisions ) == 0 :
fail ( _ ( " One of %s must be specified. " ) %
" , " . join ( [ " -- " + c for c in actions ] ) )
if len ( collisions ) > 1 :
fail ( _ ( " Conflicting options %s " ) %
2024-09-16 18:56:16 +03:00
" , " . join ( [ " -- " + c [ 0 ] for c in collisions ] ) )
action_name , selector = collisions [ 0 ]
return action_name , selector
2024-09-16 18:52:17 +03:00
def check_xmlopt_collision ( options ) :
collisions = [ ]
2024-09-18 22:55:20 +03:00
for parserclass in cli . VIRT_PARSERS :
2024-09-16 18:56:16 +03:00
value = getattr ( options , parserclass . cli_arg_name )
if value :
collisions . append ( ( parserclass , value ) )
2024-09-16 18:52:17 +03:00
if len ( collisions ) == 0 :
fail ( _ ( " No change specified. " ) )
if len ( collisions ) != 1 :
fail ( _ ( " Only one change operation may be specified "
" (conflicting options %s ) " ) %
2024-09-16 18:56:16 +03:00
[ c [ 0 ] . cli_flag_name ( ) for c in collisions ] )
parserclass , parservalue = collisions [ 0 ]
return parserclass , parservalue
2024-09-16 18:52:17 +03:00
2024-09-16 18:56:16 +03:00
def parse_action ( conn , options ) :
# Ensure there wasn't more than one device/xml config option
# specified. So reject '--disk X --network X'
parserclass , parservalue = check_xmlopt_collision ( options )
# Ensure only one of these actions was specified
# --edit
# --remove-device
# --add-device
# --build-xml
action_name , selector = check_action_collision ( options )
action = Action ( action_name , selector , parserclass , parservalue )
validate_action ( action , conn , options )
return action
2024-09-16 18:52:17 +03:00
2020-01-27 01:12:09 +03:00
################
# Change logic #
################
def _find_objects_to_edit ( guest , action_name , editval , parserclass ) :
objlist = xmlutil . listify ( parserclass . lookup_prop ( guest ) )
idx = None
if editval is None :
idx = 1
elif ( editval . isdigit ( ) or
editval . startswith ( " - " ) and editval [ 1 : ] . isdigit ( ) ) :
idx = int ( editval )
if idx is not None :
# Edit device by index
if idx == 0 :
fail ( _ ( " Invalid --edit option ' %s ' " ) % editval )
if not objlist :
2024-09-18 23:11:03 +03:00
fail ( _ ( " No {cli_flag} objects found in the XML " ) . format (
cli_flag = parserclass . cli_flag_name ( ) ) )
2020-01-27 01:12:09 +03:00
if len ( objlist ) < abs ( idx ) :
2024-09-18 23:11:03 +03:00
fail ( ngettext ( " ' --edit {number} ' requested but there ' s only "
" {maxnum} {cli_flag} object in the XML " ,
" ' --edit {number} ' requested but there are only "
" {maxnum} {cli_flag} objects in the XML " ,
len ( objlist ) ) . format (
number = idx , maxnum = len ( objlist ) ,
cli_flag = parserclass . cli_flag_name ( ) ) )
2020-01-27 01:12:09 +03:00
if idx > 0 :
idx - = 1
inst = objlist [ idx ]
elif editval == " all " :
# Edit 'all' devices
inst = objlist [ : ]
else :
# Lookup device by the passed prop string
parserobj = parserclass ( editval , guest = guest )
inst = parserobj . lookup_child_from_option_string ( )
if not inst :
2020-07-12 00:31:40 +03:00
fail ( _ ( " No matching objects found for %s " ) %
( " -- %s %s " % ( action_name , editval ) ) )
2020-01-27 01:12:09 +03:00
return inst
2024-09-16 19:05:33 +03:00
def action_edit ( action , guest ) :
2024-09-16 18:56:16 +03:00
parserclass = action . parserclass
2024-09-16 19:05:33 +03:00
parservalue = action . parservalue
2024-09-16 18:56:16 +03:00
selector = action . selector
2020-01-27 01:12:09 +03:00
if parserclass . guest_propname :
2024-09-16 18:56:16 +03:00
inst = _find_objects_to_edit ( guest , " edit " ,
selector , parserclass )
2020-01-27 01:12:09 +03:00
else :
inst = guest
2024-09-16 18:56:16 +03:00
if ( selector and selector != ' 1 ' and selector != ' all ' ) :
2024-09-18 23:11:03 +03:00
fail ( _ ( " ' --edit {option} ' doesn ' t make sense with "
" {cli_flag} , just use empty ' --edit ' " ) . format (
option = selector ,
cli_flag = parserclass . cli_flag_name ( ) ) )
2020-01-27 01:12:09 +03:00
2022-08-03 18:23:23 +03:00
devs = [ ]
for editinst in xmlutil . listify ( inst ) :
2024-09-16 19:05:33 +03:00
devs + = cli . run_parser ( guest , parserclass , parservalue ,
2024-09-16 18:56:16 +03:00
editinst = editinst )
2022-08-03 18:23:23 +03:00
return devs
2020-01-27 01:12:09 +03:00
2024-09-16 19:05:33 +03:00
def action_add_device ( action , guest , os_variant , input_devs ) :
2024-09-16 18:56:16 +03:00
parserclass = action . parserclass
2024-09-16 19:05:33 +03:00
parservalue = action . parservalue
2024-09-16 18:56:16 +03:00
2024-09-16 19:05:33 +03:00
set_os_variant ( guest , os_variant )
2021-10-12 21:34:55 +03:00
2024-09-16 18:56:16 +03:00
if input_devs :
for dev in input_devs :
2021-10-12 21:34:55 +03:00
guest . add_device ( dev )
2024-09-16 18:56:16 +03:00
devs = input_devs
2021-10-12 21:34:55 +03:00
else :
2024-09-16 19:05:33 +03:00
devs = cli . run_parser ( guest , parserclass , parservalue )
2021-10-12 21:34:55 +03:00
for dev in devs :
dev . set_defaults ( guest )
2020-01-27 01:12:09 +03:00
return devs
2024-09-16 18:56:16 +03:00
def action_remove_device ( action , guest ) :
parserclass = action . parserclass
parservalue = action . parservalue [ - 1 ]
2020-01-27 01:12:09 +03:00
devs = _find_objects_to_edit ( guest , " remove-device " ,
2024-09-16 18:56:16 +03:00
parservalue , parserclass )
2020-01-27 01:12:09 +03:00
devs = xmlutil . listify ( devs )
2020-09-09 00:55:09 +03:00
2020-01-27 01:12:09 +03:00
for dev in devs :
guest . remove_device ( dev )
return devs
2024-09-16 19:05:33 +03:00
def action_build_xml ( action , guest ) :
2024-09-16 18:56:16 +03:00
parserclass = action . parserclass
2024-09-16 19:05:33 +03:00
parservalue = action . parservalue
2020-01-27 01:12:09 +03:00
2024-09-16 19:05:33 +03:00
devs = cli . run_parser ( guest , parserclass , parservalue )
2020-01-27 01:12:09 +03:00
for dev in devs :
dev . set_defaults ( guest )
return devs
2024-09-16 18:56:16 +03:00
def perform_action ( action , guest , options , input_devs ) :
if action . is_add_device :
2024-09-16 19:05:33 +03:00
return action_add_device ( action , guest , options . os_variant , input_devs )
2024-09-16 18:56:16 +03:00
if action . is_remove_device :
return action_remove_device ( action , guest )
if action . is_edit :
2024-09-16 19:05:33 +03:00
return action_edit ( action , guest )
2024-09-16 18:56:16 +03:00
raise xmlutil . DevError (
" perform_action() incorrectly called with action_name= %s " %
action . action_name )
2020-01-27 01:12:09 +03:00
def setup_device ( dev ) :
if getattr ( dev , " DEVICE_TYPE " , None ) != " disk " :
return
log . debug ( " Doing setup for disk= %s " , dev )
dev . build_storage ( cli . get_meter ( ) )
def define_changes ( conn , inactive_xmlobj , devs , action , confirm ) :
if confirm :
if not prompt_yes_or_no (
_ ( " Define ' %s ' with the changed XML? " ) % inactive_xmlobj . name ) :
return False
2024-09-16 18:56:16 +03:00
if action . is_add_device :
2020-01-27 01:12:09 +03:00
for dev in devs :
setup_device ( dev )
dom = conn . defineXML ( inactive_xmlobj . get_xml ( ) )
print_stdout ( _ ( " Domain ' %s ' defined successfully. " ) % inactive_xmlobj . name )
return dom
def start_domain_transient ( conn , xmlobj , devs , action , confirm ) :
if confirm :
if not prompt_yes_or_no (
_ ( " Start ' %s ' with the changed XML? " ) % xmlobj . name ) :
return False
2024-09-16 18:56:16 +03:00
if action . is_add_device :
2020-01-27 01:12:09 +03:00
for dev in devs :
setup_device ( dev )
try :
dom = conn . createXML ( xmlobj . get_xml ( ) )
except libvirt . libvirtError as e :
2020-07-14 10:41:49 +03:00
fail ( _ ( " Failed starting domain ' %(domain)s ' : %(error)s " ) % {
2021-02-10 16:54:10 +03:00
" domain " : xmlobj . name ,
2020-07-14 10:41:49 +03:00
" error " : e ,
} )
2020-01-27 01:12:09 +03:00
else :
print_stdout ( _ ( " Domain ' %s ' started successfully. " ) % xmlobj . name )
return dom
def update_changes ( domain , devs , action , confirm ) :
2024-09-16 18:56:16 +03:00
if action . is_add_device :
2020-09-17 09:44:00 +03:00
msg_confirm = _ ( " %(xml)s \n \n Hotplug this device to the guest "
" ' %(domain)s ' ? " )
msg_success = _ ( " Device hotplug successful. " )
msg_fail = _ ( " Error attempting device hotplug: %(error)s " )
2024-09-16 18:56:16 +03:00
elif action . is_remove_device :
2020-09-17 09:44:00 +03:00
msg_confirm = _ ( " %(xml)s \n \n Hotunplug this device from the guest "
" ' %(domain)s ' ? " )
msg_success = _ ( " Device hotunplug successful. " )
msg_fail = _ ( " Error attempting device hotunplug: %(error)s " )
2024-09-16 18:56:16 +03:00
elif action . is_edit :
2020-09-17 09:44:00 +03:00
msg_confirm = _ ( " %(xml)s \n \n Update this device for the guest "
" ' %(domain)s ' ? " )
msg_success = _ ( " Device update successful. " )
msg_fail = _ ( " Error attempting device update: %(error)s " )
2024-09-16 18:56:16 +03:00
else :
raise xmlutil . DevError (
" update_changes() incorrectly called with action= %s " %
action . action_name )
2020-09-17 09:44:00 +03:00
2020-01-27 01:12:09 +03:00
for dev in devs :
xml = dev . get_xml ( )
if confirm :
2020-09-17 09:44:00 +03:00
msg = msg_confirm % {
" xml " : xml ,
" domain " : domain . name ( ) ,
}
2020-01-27 01:12:09 +03:00
if not prompt_yes_or_no ( msg ) :
continue
2024-09-16 18:56:16 +03:00
if action . is_add_device :
2020-01-27 01:12:09 +03:00
setup_device ( dev )
try :
2024-09-16 18:56:16 +03:00
if action . is_add_device :
2020-01-27 01:12:09 +03:00
domain . attachDeviceFlags ( xml , libvirt . VIR_DOMAIN_AFFECT_LIVE )
2024-09-16 18:56:16 +03:00
elif action . is_remove_device :
2020-01-27 01:12:09 +03:00
domain . detachDeviceFlags ( xml , libvirt . VIR_DOMAIN_AFFECT_LIVE )
2024-09-16 18:56:16 +03:00
elif action . is_edit :
2020-01-27 01:12:09 +03:00
domain . updateDeviceFlags ( xml , libvirt . VIR_DOMAIN_AFFECT_LIVE )
except libvirt . libvirtError as e :
2021-10-12 19:58:21 +03:00
if " VIRTXML_TESTSUITE_UPDATE_IGNORE_FAIL " not in os . environ :
fail ( msg_fail % { " error " : e } )
2020-01-27 01:12:09 +03:00
2021-10-12 19:58:21 +03:00
print_stdout ( msg_success )
if confirm :
2020-01-27 01:12:09 +03:00
print_stdout ( " " )
2024-09-16 18:56:16 +03:00
def prepare_changes ( orig_xmlobj , options , action , input_devs = None ) :
2021-10-12 21:34:55 +03:00
"""
2024-09-16 18:56:16 +03:00
Perform requested XML edits locally , but don ' t submit them to libvirt.
Optionally perform any XML printing per user request
2021-10-12 21:34:55 +03:00
2024-09-16 18:56:16 +03:00
: returns : ( list of device objects , altered xmlobj )
2021-10-12 21:34:55 +03:00
"""
origxml = orig_xmlobj . get_xml ( )
xmlobj = orig_xmlobj . __class__ ( conn = orig_xmlobj . conn , parsexml = origxml )
2020-01-27 01:12:09 +03:00
2024-09-16 18:56:16 +03:00
devs = perform_action ( action , xmlobj , options , input_devs )
2020-01-27 01:12:09 +03:00
newxml = xmlobj . get_xml ( )
diff = get_diff ( origxml , newxml )
if not diff :
log . warning ( _ ( " No XML diff was generated. The requested "
" changes will have no effect. " ) )
if options . print_diff :
if diff :
print_stdout ( diff )
elif options . print_xml :
print_stdout ( newxml )
2024-09-16 18:56:16 +03:00
return devs , xmlobj
2020-01-27 01:12:09 +03:00
#######################
# CLI option handling #
#######################
def parse_args ( ) :
parser = cli . setupParser (
" %(prog)s [options] " ,
_ ( " Edit libvirt XML using command line options. " ) ,
introspection_epilog = True )
cli . add_connect_option ( parser , " virt-xml " )
parser . add_argument ( " domain " , nargs = ' ? ' ,
help = _ ( " Domain name, id, or uuid " ) )
actg = parser . add_argument_group ( _ ( " XML actions " ) )
2024-08-28 18:43:36 +03:00
actg . add_argument ( " --edit " , nargs = ' ? ' , default = - 1 ,
2020-01-27 01:12:09 +03:00
help = _ ( " Edit VM XML. Examples: \n "
" --edit --disk ... (edit first disk device) \n "
" --edit 2 --disk ... (edit second disk device) \n "
" --edit all --disk ... (edit all disk devices) \n "
" --edit target=hda --disk ... (edit disk ' hda ' ) \n " ) )
actg . add_argument ( " --remove-device " , action = " store_true " ,
help = _ ( " Remove specified device. Examples: \n "
" --remove-device --disk 1 (remove first disk) \n "
" --remove-device --disk all (remove all disks) \n "
" --remove-device --disk /some/path " ) )
actg . add_argument ( " --add-device " , action = " store_true " ,
help = _ ( " Add specified device. Example: \n "
" --add-device --disk ... " ) )
actg . add_argument ( " --build-xml " , action = " store_true " ,
help = _ ( " Output built device XML. Domain is optional but "
" recommended to ensure optimal defaults. " ) )
outg = parser . add_argument_group ( _ ( " Output options " ) )
outg . add_argument ( " --update " , action = " store_true " ,
help = _ ( " Apply changes to the running VM. \n "
" With --add-device, this is a hotplug operation. \n "
" With --remove-device, this is a hotunplug operation. \n "
" With --edit, this is an update device operation. " ) )
define_g = outg . add_mutually_exclusive_group ( )
define_g . add_argument ( " --define " , action = " store_true " ,
help = _ ( " Force defining the domain. Only required if a --print "
" option was specified. " ) )
define_g . add_argument ( " --no-define " , dest = ' define ' , action = " store_false " ,
help = _ ( " Force not defining the domain. " ) )
define_g . set_defaults ( define = None )
outg . add_argument ( " --start " , action = " store_true " ,
help = _ ( " Start the domain. " ) )
outg . add_argument ( " --print-diff " , action = " store_true " ,
help = _ ( " Only print the requested change, in diff format " ) )
outg . add_argument ( " --print-xml " , action = " store_true " ,
help = _ ( " Only print the requested change, in full XML format " ) )
outg . add_argument ( " --confirm " , action = " store_true " ,
help = _ ( " Require confirmation before saving any results. " ) )
cli . add_os_variant_option ( parser , virtinstall = False )
2024-09-19 20:23:27 +03:00
conv = parser . add_argument_group ( _ ( " Conversion options " ) )
cli . ParserConvertToQ35 . register ( )
conv . add_argument ( " --convert-to-q35 " , nargs = " ? " ,
const = cli . VirtCLIParser . OPTSTR_EMPTY ,
help = _ ( " Convert an existing VM from PC/i440FX to Q35. " ) )
2020-01-27 01:12:09 +03:00
g = parser . add_argument_group ( _ ( " XML options " ) )
cli . add_disk_option ( g , editexample = True )
cli . add_net_option ( g )
cli . add_gfx_option ( g )
cli . add_metadata_option ( g )
cli . add_memory_option ( g )
cli . vcpu_cli_options ( g , editexample = True )
2020-09-10 20:52:07 +03:00
cli . add_xml_option ( g )
2020-01-27 01:12:09 +03:00
cli . add_guest_xml_options ( g )
cli . add_boot_options ( g )
cli . add_device_options ( g )
misc = parser . add_argument_group ( _ ( " Miscellaneous Options " ) )
cli . add_misc_options ( misc , prompt = False , printxml = False , dryrun = False )
cli . autocomplete ( parser )
return parser . parse_args ( )
###################
# main() handling #
###################
def main ( conn = None ) :
cli . earlyLogging ( )
options = parse_args ( )
if ( options . confirm or options . print_xml or
options . print_diff or options . build_xml ) :
options . quiet = False
cli . setupLogging ( " virt-xml " , options . debug , options . quiet )
if cli . check_option_introspection ( options ) :
return 0
2022-02-11 19:50:13 +03:00
if cli . check_osinfo_list ( options ) :
return 0
2020-01-27 01:12:09 +03:00
options . stdinxml = None
if not options . domain and not options . build_xml :
if not sys . stdin . closed and not sys . stdin . isatty ( ) :
if options . confirm :
fail ( _ ( " Can ' t use --confirm with stdin input. " ) )
if options . update :
fail ( _ ( " Can ' t use --update with stdin input. " ) )
options . stdinxml = sys . stdin . read ( )
else :
fail ( _ ( " A domain must be specified " ) )
# Default to --define, unless:
# --no-define explicitly specified
# --print-* option is used
# XML input came from stdin
if not options . print_xml and not options . print_diff :
if options . stdinxml :
if not options . define :
options . print_xml = True
else :
if options . define is None :
options . define = True
if options . confirm and not options . print_xml :
options . print_diff = True
conn = cli . getConnection ( options . connect , conn )
2024-09-16 18:56:16 +03:00
action = parse_action ( conn , options )
2020-01-27 01:12:09 +03:00
domain = None
active_xmlobj = None
inactive_xmlobj = None
if options . domain :
2020-02-03 15:20:40 +03:00
domain , inactive_xmlobj , active_xmlobj = cli . get_domain_and_guest (
2020-01-27 01:12:09 +03:00
conn , options . domain )
else :
inactive_xmlobj = Guest ( conn , parsexml = options . stdinxml )
vm_is_running = bool ( active_xmlobj )
2024-09-16 18:56:16 +03:00
if action . is_build_xml :
2024-09-16 19:05:33 +03:00
built_devs = action_build_xml ( action , inactive_xmlobj )
2024-09-16 18:56:16 +03:00
for dev in built_devs :
2020-01-27 01:12:09 +03:00
# pylint: disable=no-member
2022-08-03 17:45:50 +03:00
print_stdout ( xmlutil . unindent_device_xml ( dev . get_xml ( ) ) )
2020-01-27 01:12:09 +03:00
return 0
2024-09-16 18:56:16 +03:00
input_devs = None
2020-01-27 01:12:09 +03:00
performed_update = False
if options . update :
if options . update and options . start :
2020-09-17 09:44:02 +03:00
fail_conflicting ( " --update " , " --start " )
2020-01-27 01:12:09 +03:00
if vm_is_running :
2024-09-16 18:56:16 +03:00
input_devs , dummy = prepare_changes (
active_xmlobj , options , action )
update_changes ( domain , input_devs , action , options . confirm )
2020-01-27 01:12:09 +03:00
performed_update = True
else :
log . warning (
_ ( " The VM is not running, --update is inapplicable. " ) )
if not options . define :
# --update and --no-define passed, so we are done
2021-10-12 19:58:21 +03:00
return 0
2020-01-27 01:12:09 +03:00
original_xml = inactive_xmlobj . get_xml ( )
2024-09-16 18:56:16 +03:00
devs , xmlobj_to_define = prepare_changes (
inactive_xmlobj , options , action , input_devs = input_devs )
2020-01-27 01:12:09 +03:00
if not options . define :
if options . start :
2021-10-12 21:34:55 +03:00
start_domain_transient ( conn , xmlobj_to_define , devs ,
2020-01-27 01:12:09 +03:00
action , options . confirm )
return 0
2021-10-12 21:34:55 +03:00
dom = define_changes ( conn , xmlobj_to_define ,
2020-01-27 01:12:09 +03:00
devs , action , options . confirm )
if not dom :
# --confirm user said 'no'
return 0
if options . start :
try :
dom . create ( )
except libvirt . libvirtError as e : # pragma: no cover
2020-07-14 10:41:49 +03:00
fail ( _ ( " Failed starting domain ' %(domain)s ' : %(error)s " ) % {
" domain " : inactive_xmlobj . name ,
" error " : e ,
} )
2020-01-27 01:12:09 +03:00
print_stdout ( _ ( " Domain ' %s ' started successfully. " ) %
inactive_xmlobj . name )
elif vm_is_running and not performed_update :
print_stdout (
_ ( " Changes will take effect after the domain is fully powered off. " ) )
2024-09-23 17:34:41 +03:00
elif defined_xml_is_unchanged ( conn , dom , original_xml ) :
2020-01-27 01:12:09 +03:00
log . warning ( _ ( " XML did not change after domain define. You may "
" have changed a value that libvirt is setting by default. " ) )
return 0
def runcli ( ) : # pragma: no cover
try :
sys . exit ( main ( ) )
except SystemExit as sys_e :
sys . exit ( sys_e . code )
except KeyboardInterrupt :
log . debug ( " " , exc_info = True )
print_stderr ( _ ( " Aborted at user request " ) )
except Exception as main_e :
fail ( main_e )