25
25
import logging.handlers
29
from optparse import OptionValueError, OptionParser, OptionGroup
37
from virtinst import _util
38
from _util import log_exception
37
39
from _util import listify
38
from virtinst import VirtualNetworkInterface, Guest, \
39
VirtualGraphics, VirtualAudio, VirtualDisk, User
40
from virtinst import _virtinst as _
40
from virtinst import _gettext as _
42
from virtinst import Guest
43
from virtinst import VirtualNetworkInterface
44
from virtinst import VirtualGraphics
45
from virtinst import VirtualAudio
46
from virtinst import VirtualDisk
47
from virtinst import VirtualCharDevice
48
from virtinst import VirtualDevice
49
from virtinst import User
51
DEFAULT_POOL_PATH = "/var/lib/libvirt/images"
52
DEFAULT_POOL_NAME = "default"
47
log_exception = _util.log_exception
48
_virtinst_uri_magic = "__virtinst_test__"
50
def _is_virtinst_test_uri(uri):
51
return uri and uri.startswith(_virtinst_uri_magic)
53
def _open_test_uri(uri):
55
This hack allows us to fake various drivers via passing a magic
56
URI string to virt-*. Helps with testing
58
uri = uri.replace(_virtinst_uri_magic, "")
59
ret = uri.split(",", 1)
61
ignore, opts = parse_optstr(len(ret) > 1 and ret[1] or "")
63
conn = open_connection(uri)
65
def sanitize_xml(xml):
67
xml = re.sub("arch='.*'", "arch='i686'", xml)
68
xml = re.sub("domain type='.*'", "domain type='test'", xml)
69
xml = re.sub("machine type='.*'", "", xml)
71
logging.debug("virtinst test sanitizing diff\n:%s" %
72
"\n".join(difflib.unified_diff(orig.split("\n"),
76
# Need tmpfile names to be deterministic
77
if "predictable" in opts:
78
def fakemkstemp(prefix, *args, **kwargs):
81
filename = os.path.join(".", prefix)
82
return os.open(filename, os.O_RDWR | os.O_CREAT), filename
83
tempfile.mkstemp = fakemkstemp
85
_util.randomMAC = lambda type_: "00:11:22:33:44:55"
86
_util.uuidToString = lambda r: "00000000-1111-2222-3333-444444444444"
90
_util.is_uri_remote = lambda uri_: True
94
capsxml = file(opts["caps"]).read()
95
conn.getCapabilities = lambda: capsxml
97
if "qemu" in opts or "xen" in opts:
98
conn.getVersion = lambda: 10000000000
100
origcreate = conn.createLinux
101
origdefine = conn.defineXML
102
def newcreate(xml, flags):
103
xml = sanitize_xml(xml)
104
origcreate(xml, flags)
106
xml = sanitize_xml(xml)
108
conn.createLinux = newcreate
109
conn.defineXML = newdefine
112
conn.getURI = lambda: "qemu+abc:///system"
114
conn.getURI = lambda: "xen+abc:///"
118
64
class VirtStreamHandler(logging.StreamHandler):
278
221
# Log the app command string
279
222
logging.debug("Launched with command line:\n%s" % " ".join(sys.argv))
281
def fail(msg, do_exit=True):
282
"""Convenience function when failing in cli app"""
288
def print_stdout(msg, do_force=False):
289
if do_force or not quiet:
292
def print_stderr(msg):
294
print >> sys.stderr, msg
300
print_stdout(_("Exiting at user request."))
303
def virsh_start_cmd(guest):
304
return ("virsh --connect %s start %s" % (guest.conn.getURI(), guest.name))
306
def install_fail(guest):
307
virshcmd = virsh_start_cmd(guest)
310
_("Domain installation does not appear to have been successful.\n"
311
"If it was, you can restart your domain by running:\n"
313
"otherwise, please restart your installation.") % virshcmd)
316
# Connection opening helper functions
225
#######################################
226
# Libvirt connection helpers #
227
#######################################
229
_virtinst_uri_magic = "__virtinst_test__"
231
def _is_virtinst_test_uri(uri):
232
return uri and uri.startswith(_virtinst_uri_magic)
234
def _open_test_uri(uri):
236
This hack allows us to fake various drivers via passing a magic
237
URI string to virt-*. Helps with testing
239
uri = uri.replace(_virtinst_uri_magic, "")
240
ret = uri.split(",", 1)
242
opts = parse_optstr(len(ret) > 1 and ret[1] or "")
244
conn = open_connection(uri)
246
def sanitize_xml(xml):
248
xml = re.sub("arch='.*'", "arch='i686'", xml)
249
xml = re.sub("domain type='.*'", "domain type='test'", xml)
250
xml = re.sub("machine type='.*'", "", xml)
251
xml = re.sub(">exe<", ">hvm<", xml)
253
logging.debug("virtinst test sanitizing diff\n:%s" %
254
"\n".join(difflib.unified_diff(orig.split("\n"),
258
# Need tmpfile names to be deterministic
259
if "predictable" in opts:
260
def fakemkstemp(prefix, *args, **kwargs):
263
filename = os.path.join(".", prefix)
264
return os.open(filename, os.O_RDWR | os.O_CREAT), filename
265
tempfile.mkstemp = fakemkstemp
267
_util.randomMAC = lambda type_: "00:11:22:33:44:55"
268
_util.uuidToString = lambda r: "00000000-1111-2222-3333-444444444444"
272
_util.is_uri_remote = lambda uri_: True
276
capsxml = file(opts["caps"]).read()
277
conn.getCapabilities = lambda: capsxml
279
if ("qemu" in opts) or ("xen" in opts) or ("lxc" in opts):
280
conn.getVersion = lambda: 10000000000
282
origcreate = conn.createLinux
283
origdefine = conn.defineXML
284
def newcreate(xml, flags):
285
xml = sanitize_xml(xml)
286
return origcreate(xml, flags)
288
xml = sanitize_xml(xml)
289
return origdefine(xml)
290
conn.createLinux = newcreate
291
conn.defineXML = newdefine
294
conn.getURI = lambda: "qemu+abc:///system"
296
conn.getURI = lambda: "xen+abc:///"
298
conn.getURI = lambda: "lxc+abc:///"
300
# These need to come after the HV setter, since that sets a default
302
if "connver" in opts:
303
ver = int(opts["connver"])
304
def newconnversion():
306
conn.getVersion = newconnversion
309
ver = int(opts["libver"])
310
def newlibversion(drv=None):
314
libvirt.getVersion = newlibversion
317
318
def getConnection(uri):
318
319
if (uri and not User.current().has_priv(User.PRIV_CREATE_DOMAIN, uri)):
319
320
fail(_("Must be root to create Xen guests"))
512
595
passed_val = None
515
def vcpu_cli_options(grp):
516
grp.add_option("", "--vcpus", type="string", dest="vcpus",
517
help=_("Number of vcpus to configure for your guest. Ex:\n"
519
"--vcpus 5,maxcpus=10\n"
520
"--vcpus sockets=2,cores=4,threads=2"))
521
grp.add_option("", "--cpuset", type="string", dest="cpuset",
522
action="callback", callback=check_before_store,
523
help=_("Set which physical CPUs Domain can use."))
524
grp.add_option("", "--cpu", type="string", dest="cpu",
525
action="callback", callback=check_before_store,
526
help=_("CPU model and features. Ex: --cpu coreduo,+x2apic"))
527
grp.add_option("", "--check-cpu", action="store_true", dest="check_cpu",
528
help=optparse.SUPPRESS_HELP)
530
# Register vnc + sdl options for virt-install and virt-image
531
def graphics_option_group(parser):
533
vncg = OptionGroup(parser, _("Graphics Configuration"))
534
vncg.add_option("", "--graphics", type="string", dest="graphics",
535
action="callback", callback=check_before_store,
536
help=_("Specify display configuration. Ex:\n"
538
"--graphics spice,port=5901,tlsport=5902\n"
540
"--graphics vnc,password=foobar,port=5910,keymap=ja"))
541
vncg.add_option("", "--vnc", action="store_true", dest="vnc",
542
help=optparse.SUPPRESS_HELP)
543
vncg.add_option("", "--vncport", type="int", dest="vncport",
544
help=optparse.SUPPRESS_HELP)
545
vncg.add_option("", "--vnclisten", type="string", dest="vnclisten",
546
help=optparse.SUPPRESS_HELP)
547
vncg.add_option("-k", "--keymap", type="string", dest="keymap",
548
action="callback", callback=check_before_store,
549
help=optparse.SUPPRESS_HELP)
550
vncg.add_option("", "--sdl", action="store_true", dest="sdl",
551
help=optparse.SUPPRESS_HELP)
552
vncg.add_option("", "--nographics", action="store_true",
553
help=optparse.SUPPRESS_HELP)
556
600
# Specific function for disk prompting. Returns a validated VirtualDisk
559
def disk_prompt(prompt_txt, arg_dict, warn_overwrite=False, prompt_size=True,
603
def disk_prompt(conn, origpath, origsize, origsparse,
605
warn_overwrite=False, check_size=True,
606
path_to_clone=None, origdev=None):
608
askmsg = _("Do you really want to use this disk (yes or no)")
562
609
retry_path = True
563
conn = arg_dict.get("conn")
564
passed_path = arg_dict.get("path")
565
size = arg_dict.get("size")
567
no_path_needed = (bool(arg_dict.get("volInstall")) or
568
bool(arg_dict.get("volName")))
611
no_path_needed = (origdev and
612
(origdev.vol_install or
613
origdev.vol_object or
614
origdev.can_be_empty()))
616
def prompt_path(chkpath, chksize):
618
Prompt for disk path if necc
577
621
patherr = _("A disk path must be specified.")
578
622
if path_to_clone:
582
626
if not prompt_txt:
583
627
msg = _("What would you like to use as the disk (file path)?")
628
if not chksize is None:
585
629
msg = _("Please enter the path to the file you would like to "
586
"use for storage. It will have size %sGB.") % size
630
"use for storage. It will have size %sGB.") % chksize
588
632
if not no_path_needed:
589
path = prompt_for_input(patherr, prompt_txt or msg, passed_path)
633
path = prompt_for_input(patherr, prompt_txt or msg, chkpath)
592
arg_dict["path"] = path
593
path_exists = VirtualDisk.path_exists(conn, path)
639
def prompt_size(chkpath, chksize, path_exists):
641
Prompt for disk size if necc.
595
643
sizeerr = _("A size must be specified for non-existent disks.")
596
if path and not size and prompt_size:
597
size_prompt = _("How large would you like the disk (%s) to "
598
"be (in gigabytes)?") % path
602
size = prompt_loop(size_prompt, sizeerr, size, None, None,
605
# Path is probably bogus, raise the error
606
logging.error(str(e))
608
arg_dict["size"] = size
610
# Build disk object for validation
644
size_prompt = _("How large would you like the disk (%s) to "
645
"be (in gigabytes)?") % chkpath
649
chksize is not None or
651
return False, chksize
612
dev = VirtualDisk(**arg_dict)
613
except ValueError, e:
618
fail(_("Error with storage parameters: %s" % str(e)))
620
askmsg = _("Do you really want to use this disk (yes or no)")
622
# Prompt if disk file already exists and preserve mode is not used
654
chksize = prompt_loop(size_prompt, sizeerr, chksize, None, None,
656
return False, chksize
658
# Path is probably bogus, raise the error
659
fail(str(e), do_exit=not is_prompt())
662
def prompt_path_exists(dev):
664
Prompt if disk file already exists and preserve mode is not used
623
666
does_collide = (path_exists and
624
667
dev.type == dev.TYPE_FILE and
625
668
dev.device == dev.DEVICE_DISK)
626
if (does_collide and (warn_overwrite or is_prompt())):
627
msg = (_("This will overwrite the existing path '%s'" %
629
if not prompt_for_yes_or_no(msg, askmsg):
632
# Check disk conflicts
633
if dev.is_conflict_disk(conn) is True:
634
msg = (_("Disk %s is already in use by another guest" %
636
if not prompt_for_yes_or_no(msg, askmsg):
669
msg = (_("This will overwrite the existing path '%s'" % dev.path))
674
if warn_overwrite or is_prompt():
675
return not prompt_for_yes_or_no(msg, askmsg)
678
def prompt_inuse_conflict(dev):
680
Check if disk is inuse by another guest
682
msg = (_("Disk %s is already in use by another guest" % dev.path))
684
if not dev.is_conflict_disk(conn):
687
return not prompt_for_yes_or_no(msg, askmsg)
689
def prompt_size_conflict(dev):
691
Check if specified size exceeds available storage
639
693
isfatal, errmsg = dev.is_size_conflict()
643
if not prompt_for_yes_or_no(errmsg, askmsg):
695
fail(errmsg, do_exit=not is_prompt())
699
return not prompt_for_yes_or_no(errmsg, askmsg)
704
# If we fail within the loop, reprompt for size and path
711
path = prompt_path(origpath, origsize)
712
path_exists = VirtualDisk.path_exists(conn, path)
715
didfail, size = prompt_size(path, origsize, path_exists)
719
# Build disk object for validation
728
dev = VirtualDisk(conn=conn, path=path, size=size,
730
except ValueError, e:
646
# Passed all validation, return path
735
fail(_("Error with storage parameters: %s" % str(e)))
737
# Check if path exists
738
if prompt_path_exists(dev):
741
# Check disk in use by other guests
742
if prompt_inuse_conflict(dev):
745
# Check if disk exceeds available storage
746
if prompt_size_conflict(dev):
749
# Passed all validation, return disk instance
753
#######################
754
# Validation wrappers #
755
#######################
652
757
name_missing = _("--name is required")
653
758
ram_missing = _("--ram amount in MB is required")
838
def _default_network_opts(guest):
840
if User.current().has_priv(User.PRIV_CREATE_NETWORK, guest.get_uri()):
841
net = _util.default_network(guest.conn)
842
opts = "%s=%s" % (net[0], net[1])
848
def digest_networks(guest, options, numnics=1):
849
macs = listify(options.mac)
850
networks = listify(options.network)
851
bridges = listify(options.bridge)
853
if bridges and networks:
854
fail(_("Cannot mix both --bridge and --network arguments"))
857
# Convert old --bridges to --networks
858
networks = map(lambda b: "bridge:" + b, bridges)
860
def padlist(l, padsize):
862
l.extend((padsize - len(l)) * [None])
865
# If a plain mac is specified, have it imply a default network
866
networks = padlist(networks, max(len(macs), numnics))
867
macs = padlist(macs, len(networks))
869
for idx in range(len(networks)):
870
if networks[idx] is None:
871
networks[idx] = _default_network_opts(guest)
873
return networks, macs
875
def get_networks(guest, networks, macs):
876
for idx in range(len(networks)):
878
netstr = networks[idx]
881
dev = parse_network(guest, netstr, mac=mac)
882
guest.add_device(dev)
884
fail(_("Error in network device parameters: %s") % str(e))
886
def set_os_variant(guest, distro_type, distro_variant):
887
if not distro_type and not distro_variant:
888
# Default to distro autodetection
889
guest.set_os_autodetect(True)
892
if (distro_type and str(distro_type).lower() != "none"):
893
guest.set_os_type(distro_type)
895
if (distro_variant and str(distro_variant).lower() != "none"):
896
guest.set_os_variant(distro_variant)
898
def digest_graphics(guest, options, default_override=None):
900
vncport = options.vncport
901
vnclisten = options.vnclisten
902
nographics = options.nographics
904
keymap = options.keymap
905
graphics = options.graphics
907
if graphics and (vnc or sdl or keymap or vncport or vnclisten):
908
fail(_("Cannot mix --graphics and old style graphical options"))
910
optnum = sum(map(bool, [vnc, nographics, sdl, graphics]))
912
raise ValueError(_("Can't specify more than one of VNC, SDL, "
913
"--graphics or --nographics"))
919
# If no graphics specified, choose a default
920
if default_override is True:
922
elif default_override is False:
925
if guest.installer.is_container():
926
logging.debug("Container guest, defaulting to nographics")
928
elif "DISPLAY" in os.environ.keys():
929
logging.debug("DISPLAY is set: graphics defaulting to VNC.")
932
logging.debug("DISPLAY is not set: defaulting to nographics.")
936
# Build a --graphics command line from old style opts
937
optstr = ((vnc and "vnc") or
939
(nographics and ("none")))
941
optstr += ",listen=%s" % vnclisten
943
optstr += ",port=%s" % vncport
945
optstr += ",keymap=%s" % keymap
947
logging.debug("--graphics compat generated: %s" % optstr)
950
def get_graphics(guest, graphics):
951
for optstr in graphics:
953
dev = parse_graphics(guest, optstr)
955
fail(_("Error in graphics device parameters: %s") % str(e))
958
guest.add_device(dev)
960
def get_video(guest, video_models=None):
961
video_models = video_models or []
963
if guest.get_devices(VirtualDevice.VIRTUAL_DEV_GRAPHICS):
965
video_models.append(None)
967
for model in video_models:
968
guest.add_device(parse_video(guest, model))
970
def get_sound(old_sound_bool, sound_opts, guest):
974
guest.sound_devs.append(VirtualAudio(conn=guest.conn))
977
for opts in listify(sound_opts):
978
guest.add_device(parse_sound(guest, opts))
980
def get_hostdevs(hostdevs, guest):
984
for devname in hostdevs:
985
guest.add_device(parse_hostdev(guest, devname))
987
def get_smartcard(guest, sc_opts):
988
for sc in listify(sc_opts):
990
dev = parse_smartcard(guest, sc)
992
fail(_("Error in smartcard device parameters: %s") % str(e))
995
guest.add_device(dev)
997
#############################
998
# Common CLI option/group #
999
#############################
1001
def add_connect_option(parser):
1002
parser.add_option("", "--connect", metavar="URI", dest="connect",
1003
help=_("Connect to hypervisor with libvirt URI"))
1005
def vcpu_cli_options(grp, backcompat=True):
1006
grp.add_option("", "--vcpus", dest="vcpus",
1007
help=_("Number of vcpus to configure for your guest. Ex:\n"
1009
"--vcpus 5,maxcpus=10\n"
1010
"--vcpus sockets=2,cores=4,threads=2"))
1011
grp.add_option("", "--cpuset", dest="cpuset",
1012
help=_("Set which physical CPUs domain can use."))
1013
grp.add_option("", "--cpu", dest="cpu",
1014
help=_("CPU model and features. Ex: --cpu coreduo,+x2apic"))
1017
grp.add_option("", "--check-cpu", action="store_true",
1018
dest="check_cpu", help=optparse.SUPPRESS_HELP)
1020
def graphics_option_group(parser):
1022
Register vnc + sdl options for virt-install and virt-image
1025
vncg = optparse.OptionGroup(parser, _("Graphics Configuration"))
1026
add_gfx_option(vncg)
1027
vncg.add_option("", "--vnc", action="store_true", dest="vnc",
1028
help=optparse.SUPPRESS_HELP)
1029
vncg.add_option("", "--vncport", type="int", dest="vncport",
1030
help=optparse.SUPPRESS_HELP)
1031
vncg.add_option("", "--vnclisten", dest="vnclisten",
1032
help=optparse.SUPPRESS_HELP)
1033
vncg.add_option("-k", "--keymap", dest="keymap",
1034
help=optparse.SUPPRESS_HELP)
1035
vncg.add_option("", "--sdl", action="store_true", dest="sdl",
1036
help=optparse.SUPPRESS_HELP)
1037
vncg.add_option("", "--nographics", action="store_true",
1038
help=optparse.SUPPRESS_HELP)
1041
def network_option_group(parser):
1043
Register common network options for virt-install and virt-image
1045
netg = optparse.OptionGroup(parser, _("Networking Configuration"))
1047
add_net_option(netg)
1049
# Deprecated net options
1050
netg.add_option("-b", "--bridge", dest="bridge", action="append",
1051
help=optparse.SUPPRESS_HELP)
1052
netg.add_option("-m", "--mac", dest="mac", action="append",
1053
help=optparse.SUPPRESS_HELP)
1057
def add_net_option(devg):
1058
devg.add_option("-w", "--network", dest="network", action="append",
1059
help=_("Configure a guest network interface. Ex:\n"
1060
"--network bridge=mybr0\n"
1061
"--network network=my_libvirt_virtual_net\n"
1062
"--network network=mynet,model=virtio,mac=00:11..."))
1064
def add_device_options(devg):
1065
devg.add_option("", "--serial", dest="serials", action="append",
1066
help=_("Configure a guest serial device"))
1067
devg.add_option("", "--parallel", dest="parallels", action="append",
1068
help=_("Configure a guest parallel device"))
1069
devg.add_option("", "--channel", dest="channels", action="append",
1070
help=_("Configure a guest communication channel"))
1071
devg.add_option("", "--console", dest="consoles", action="append",
1072
help=_("Configure a text console connection between "
1073
"the guest and host"))
1074
devg.add_option("", "--host-device", dest="hostdevs", action="append",
1075
help=_("Configure physical host devices attached to the "
1077
devg.add_option("", "--soundhw", dest="soundhw", action="append",
1078
help=_("Configure guest sound device emulation"))
1079
devg.add_option("", "--watchdog", dest="watchdog", action="append",
1080
help=_("Configure a guest watchdog device"))
1081
devg.add_option("", "--video", dest="video", action="append",
1082
help=_("Configure guest video hardware."))
1083
devg.add_option("", "--smartcard", dest="smartcard", action="append",
1084
help=_("Configure a guest smartcard device. Ex:\n"
1085
"--smartcard mode=passthrough"))
1087
def add_gfx_option(devg):
1088
devg.add_option("", "--graphics", dest="graphics", action="append",
1089
help=_("Configure guest display settings. Ex:\n"
1091
"--graphics spice,port=5901,tlsport=5902\n"
1093
"--graphics vnc,password=foobar,port=5910,keymap=ja"))
1095
def add_fs_option(devg):
1096
devg.add_option("", "--filesystem", dest="filesystems", action="append",
1097
help=_("Pass host directory to the guest. Ex: \n"
1098
"--filesystem /my/source/dir,/dir/in/guest\n"
1099
"--filesystem template_name,/,type=template"))
1101
#############################################
1102
# CLI complex parsing helpers #
1103
# (for options like --disk, --network, etc. #
1104
#############################################
1106
def get_opt_param(opts, dictnames, val=None):
1107
if type(dictnames) is not list:
1108
dictnames = [dictnames]
1110
for key in dictnames:
1118
def _build_set_param(inst, opts):
1119
def _set_param(paramname, keyname, val=None):
1120
val = get_opt_param(opts, keyname, val)
1123
setattr(inst, paramname, val)
1127
def parse_optstr_tuples(optstr, compress_first=False):
1129
Parse optstr into a list of ordered tuples
1131
optstr = str(optstr or "")
1134
if compress_first and optstr and not optstr.count("="):
1135
return [(optstr, None)]
1137
argsplitter = shlex.shlex(optstr, posix=True)
1138
argsplitter.whitespace = ","
1139
argsplitter.whitespace_split = True
1141
for opt in list(argsplitter):
1148
opt_type, opt_val = opt.split("=", 1)
1149
optlist.append((opt_type.lower(), opt_val))
1151
optlist.append((opt.lower(), None))
1155
def parse_optstr(optstr, basedict=None, remove_first=None,
1156
compress_first=False):
1158
Helper function for parsing opt strings of the form
1159
opt1=val1,opt2=val2,...
1161
@param basedict: starting dictionary, so the caller can easily set
1162
default values, etc.
1163
@param remove_first: List or parameters to peel off the front of
1164
option string, and store in the returned dict.
1165
remove_first=["char_type"] for --serial pty,foo=bar
1166
returns {"char_type", "pty", "foo" : "bar"}
1167
@param compress_first: If there are no options of the form opt1=opt2,
1168
compress the string to a single option
1170
Returns a dictionary of {'opt1': 'val1', 'opt2': 'val2'}
1172
optlist = parse_optstr_tuples(optstr, compress_first=compress_first)
1173
optdict = basedict or {}
1175
paramlist = remove_first
1176
if type(paramlist) is not list:
1177
paramlist = paramlist and [paramlist] or []
1179
for idx in range(len(paramlist)):
1180
if len(optlist) < len(paramlist):
1183
if optlist[idx][1] == None:
1184
optlist[idx] = (paramlist[idx], optlist[idx][0])
1186
for opt, val in optlist:
1187
if type(optdict.get(opt)) is list:
1188
optdict[opt].append(val)
1196
#######################
1197
# Guest param parsing #
1198
#######################
1200
######################
1201
# --numatune parsing #
1202
######################
1204
def parse_numatune(guest, optstring):
1206
Helper to parse --numatune string
1208
@param guest: virtinst.Guest instanct (object)
1209
@param optstring: value of the option '--numatune' (str)
1211
opts = parse_optstr(optstring, remove_first="nodeset", compress_first=True)
1213
set_param = _build_set_param(guest.numatune, opts)
1215
set_param("memory_nodeset", "nodeset")
1216
set_param("memory_mode", "mode")
1219
raise ValueError(_("Unknown options %s") % opts.keys())
1225
def parse_vcpu(guest, optstring, default_vcpus=None):
1227
Helper to parse --vcpu string
1229
@param guest: virtinst.Guest instance (object)
1230
@param optstring: value of the option '--vcpus' (str)
1231
@param default_vcpus: ? (it should be None at present.)
1236
opts = parse_optstr(optstring, remove_first="vcpus")
1237
vcpus = opts.get("vcpus") or default_vcpus
1238
if vcpus is not None:
1239
opts["vcpus"] = vcpus
1241
set_param = _build_set_param(guest, opts)
1242
set_cpu_param = _build_set_param(guest.cpu, opts)
1243
has_vcpus = ("vcpus" in opts or (vcpus is not None))
1245
set_param("vcpus", "vcpus")
1246
set_param("maxvcpus", "maxvcpus")
1248
set_cpu_param("sockets", "sockets")
1249
set_cpu_param("cores", "cores")
1250
set_cpu_param("threads", "threads")
1253
guest.vcpus = guest.cpu.vcpus_from_topology()
1256
raise ValueError(_("Unknown options %s") % opts.keys())
772
1262
def parse_cpu(guest, optstring):
773
1263
default_dict = {
820
1310
raise ValueError(_("Unknown options %s") % opts.keys())
822
def get_network(net_kwargs, guest):
823
n = VirtualNetworkInterface(**net_kwargs)
826
def set_os_variant(guest, distro_type, distro_variant):
827
if not distro_type and not distro_variant:
828
# Default to distro autodetection
829
guest.set_os_autodetect(True)
831
if (distro_type and str(distro_type).lower() != "none"):
832
guest.set_os_type(distro_type)
834
if (distro_variant and str(distro_variant).lower() != "none"):
835
guest.set_os_variant(distro_variant)
837
def parse_optstr_tuples(optstr):
839
Parse optstr into a list of ordered tuples
841
optstr = str(optstr or "")
844
args = optstr.split(",")
852
opt_type, opt_val = opt.split("=", 1)
853
optlist.append((opt_type.lower(), opt_val))
855
optlist.append((opt.lower(), None))
859
def parse_optstr(optstr, basedict=None, remove_first=False):
861
Helper function for parsing opt strings of the form
862
opt1=val1,opt2=val2,...
864
@param basedict: starting dictionary, so the caller can easily set
866
@param remove_first: If true, remove the first options off the string
867
and return it seperately. For example,
868
--serial pty,foo=bar returns ("pty", {"foo" : "bar"})
870
Returns a dictionary of {'opt1': 'val1', 'opt2': 'val2'}
872
optlist = parse_optstr_tuples(optstr)
873
optdict = basedict or {}
876
if remove_first and optlist:
877
first_tuple = optlist[0]
878
if first_tuple[1] == None:
879
first = first_tuple[0]
880
optlist.remove(first_tuple)
882
for opt, val in optlist:
883
if type(optdict.get(opt)) is list:
884
optdict[opt].append(val)
888
return (first, optdict)
890
def parse_network_opts(conn, mac, network):
895
option_whitelist = ["model", "mac"]
897
args = network.split(",")
899
# Determine net type and bridge vs. network
904
if typestr.count(":"):
905
net_type, netdata = typestr.split(":", 1)
906
elif typestr.count("="):
907
net_type, netdata = typestr.split("=", 1)
911
if net_type == VirtualNetworkInterface.TYPE_VIRTUAL:
912
network_name = netdata
913
elif net_type == VirtualNetworkInterface.TYPE_BRIDGE:
914
bridge_name = netdata
916
# Pass the remaining arg=value pairs
917
ignore, opts = parse_optstr(",".join(args))
918
for opt_type, ignore_val in opts.items():
919
if opt_type not in option_whitelist:
920
fail(_("Unknown network option '%s'") % opt_type)
922
model = opts.get("model")
923
mac = opts.get("mac") or mac
925
# The keys here correspond to parameter names for VirtualNetworkInterface
929
return {"conn" : conn, "type" : net_type, "bridge": bridge_name,
930
"network" : network_name, "model" : model , "macaddr" : mac}
932
def digest_networks(conn, macs, bridges, networks, nics=0):
934
bridges = listify(bridges)
935
networks = listify(networks)
937
if bridges and networks:
938
fail(_("Cannot mix both --bridge and --network arguments"))
941
networks = map(lambda b: "bridge:" + b, bridges)
943
# With just one mac, create a default network if one is not specified.
944
if len(macs) == 1 and len(networks) == 0:
945
if User.current().has_priv(User.PRIV_CREATE_NETWORK, conn.getURI()):
946
net = _util.default_network(conn)
947
networks.append(net[0] + ":" + net[1])
949
networks.append(VirtualNetworkInterface.TYPE_USER)
951
# ensure we have less macs then networks, otherwise autofill the mac list
952
if len(macs) > len(networks):
953
fail(_("Cannot pass more mac addresses than networks."))
955
for dummy in range(len(macs), len(networks)):
958
# Create extra networks up to the number of nics requested
960
for dummy in range(len(macs), nics):
961
if User.current().has_priv(User.PRIV_CREATE_NETWORK, conn.getURI()):
962
net = _util.default_network(conn)
963
networks.append(net[0] + ":" + net[1])
965
networks.append(VirtualNetworkInterface.TYPE_USER)
969
for i in range(0, len(networks)):
972
net_init_dicts.append(parse_network_opts(conn, mac, netstr))
974
return net_init_dicts
976
def sanitize_keymap(keymap):
1316
def parse_boot(guest, optstring):
1318
Helper to parse --boot string
1320
opts = parse_optstr(optstring)
1321
optlist = map(lambda x: x[0], parse_optstr_tuples(optstring))
1324
def set_param(paramname, dictname, val=None):
1325
val = get_opt_param(opts, dictname, val)
1329
setattr(guest.installer.bootconfig, paramname, val)
1331
# Convert menu= value
1333
menustr = opts["menu"]
1336
if menustr.lower() == "on":
1338
elif menustr.lower() == "off":
1341
menu = yes_or_no_convert(menustr)
1344
fail(_("--boot menu must be 'on' or 'off'"))
1346
set_param("enable_bootmenu", "menu", menu)
1347
set_param("kernel", "kernel")
1348
set_param("initrd", "initrd")
1349
set_param("kernel_args", ["kernel_args", "extra_args"])
1354
for boot_dev in optlist:
1355
if not boot_dev in guest.installer.bootconfig.boot_devices:
1359
if boot_dev not in boot_order:
1360
boot_order.append(boot_dev)
1362
guest.installer.bootconfig.bootorder = boot_order
1365
raise ValueError(_("Unknown options %s") % opts.keys())
1367
######################
1368
# --security parsing #
1369
######################
1371
def parse_security(guest, security):
1372
seclist = listify(security)
1373
secopts = seclist and seclist[0] or None
1377
# Parse security opts
1378
opts = parse_optstr(secopts)
1379
arglist = secopts.split(",")
1380
secmodel = guest.seclabel
1382
# Beware, adding boolean options here could upset label comma handling
1383
mode = get_opt_param(opts, "type")
1384
label = get_opt_param(opts, "label")
1386
# Try to fix up label if it contained commas
1388
tmparglist = arglist[:]
1389
for idx in range(len(tmparglist)):
1390
arg = tmparglist[idx]
1391
if not arg.split("=")[0] == "label":
1394
for arg in tmparglist[idx + 1:]:
1405
secmodel.label = label
1407
mode = secmodel.SECLABEL_TYPE_STATIC
1409
secmodel.type = mode
1412
raise ValueError(_("Unknown options %s") % opts.keys())
1414
# Run for validation purposes
1415
secmodel.get_xml_config()
1419
##########################
1420
# Guest <device> parsing #
1421
##########################
1428
def _parse_disk_source(guest, path, pool, vol, size, fmt, sparse):
1434
if sum(map(int, map(bool, [path, pool, vol]))) > 1:
1435
fail(_("Cannot specify more than 1 storage path"))
1438
abspath = os.path.abspath(path)
1439
if os.path.dirname(abspath) == DEFAULT_POOL_PATH:
1440
build_default_pool(guest)
1444
raise ValueError(_("Size must be specified with all 'pool='"))
1445
if pool == DEFAULT_POOL_NAME:
1446
build_default_pool(guest)
1447
vc = virtinst.Storage.StorageVolume.get_volume_for_pool(pool_name=pool,
1449
vname = virtinst.Storage.StorageVolume.find_free_name(conn=guest.conn,
1453
volinst = vc(pool_name=pool, name=vname, conn=guest.conn,
1454
allocation=0, capacity=(size and
1455
size * 1024 * 1024 * 1024))
1457
if not hasattr(volinst, "format"):
1458
raise ValueError(_("Format attribute not supported for this "
1460
setattr(volinst, "format", fmt)
1463
volinst.allocation = volinst.capacity
1466
if not vol.count("/"):
1467
raise ValueError(_("Storage volume must be specified as "
1468
"vol=poolname/volname"))
1469
vollist = vol.split("/")
1470
voltuple = (vollist[0], vollist[1])
1471
logging.debug("Parsed volume: as pool='%s' vol='%s'" %
1472
(voltuple[0], voltuple[1]))
1473
if voltuple[0] == DEFAULT_POOL_NAME:
1474
build_default_pool(guest)
1476
volobj = virtinst.VirtualDisk.lookup_vol_object(guest.conn, voltuple)
1478
return abspath, volinst, volobj
1480
def parse_disk(guest, optstr, dev=None):
1482
helper to properly parse --disk options
1484
def parse_perms(val):
1493
# It's default. Nothing to do.
1496
fail(_("Unknown '%s' value '%s'" % ("perms", val)))
1500
def parse_size(val):
1504
newsize = float(val)
1505
except Exception, e:
1506
fail(_("Improper value for 'size': %s" % str(e)))
1510
def parse_sparse(val):
1513
val = str(val).lower()
1514
if val in ["true", "yes"]:
1516
elif val in ["false", "no"]:
1519
fail(_("Unknown '%s' value '%s'") % ("sparse", val))
1531
# Parse out comma separated options
1532
opts = parse_optstr(optstr, remove_first="path")
1534
# We annoyingly need these params ahead of time to deal with
1535
# VirtualDisk validation
1536
path = opt_get("path")
1537
pool = opt_get("pool")
1538
vol = opt_get("vol")
1539
size = parse_size(opt_get("size"))
1540
fmt = opt_get("format")
1541
sparse = parse_sparse(opt_get("sparse"))
1542
ro, shared = parse_perms(opt_get("perms"))
1543
device = opt_get("device")
1545
abspath, volinst, volobj = _parse_disk_source(guest, path, pool, vol,
1549
# Build a stub device that should always validate cleanly
1550
dev = virtinst.VirtualDisk(conn=guest.conn,
1560
set_param = _build_set_param(dev, opts)
1562
set_param("path", "path", abspath)
1563
set_param("vol", "vol_object", volobj)
1564
set_param("pool", "vol_install", volinst)
1565
set_param("size", "size", size)
1566
set_param("format", "format", fmt)
1567
set_param("sparse", "sparse", sparse)
1568
set_param("read_only", "perms", ro)
1569
set_param("shareable", "perms", shared)
1570
set_param("device", "device", device)
1572
set_param("bus", "bus")
1573
set_param("driver_cache", "cache")
1574
set_param("driver_name", "driver_name")
1575
set_param("driver_type", "driver_type")
1576
set_param("driver_io", "io")
1577
set_param("error_policy", "error_policy")
1578
set_param("serial", "serial")
1581
fail(_("Unknown options %s") % opts.keys())
1585
#####################
1586
# --network parsing #
1587
#####################
1589
def parse_network(guest, optstring, dev=None, mac=None):
1590
# Handle old format of bridge:foo instead of bridge=foo
1591
for prefix in ["network", "bridge"]:
1592
if optstring.startswith(prefix + ":"):
1593
optstring = optstring.replace(prefix + ":", prefix + "=")
1595
opts = parse_optstr(optstring, remove_first="type")
1597
# Determine device type
1598
net_type = opts.get("type")
1599
if "network" in opts:
1600
net_type = VirtualNetworkInterface.TYPE_VIRTUAL
1601
elif "bridge" in opts:
1602
net_type = VirtualNetworkInterface.TYPE_BRIDGE
1604
# Build initial device
1606
dev = VirtualNetworkInterface(conn=guest.conn,
1608
network=opts.get("network"),
1609
bridge=opts.get("bridge"))
1611
if mac and not "mac" in opts:
1614
if opts["mac"] == "RANDOM":
1617
set_param = _build_set_param(dev, opts)
1619
set_param("type", "type", net_type)
1620
set_param("network", "network")
1621
set_param("bridge", "bridge")
1622
set_param("model", "model")
1623
set_param("macaddr", "mac")
1626
raise ValueError(_("Unknown options %s") % opts.keys())
1630
######################
1631
# --graphics parsing #
1632
######################
1634
def parse_graphics(guest, optstring, dev=None):
1635
if optstring is None:
982
if keymap.lower() == "local":
983
use_keymap = virtinst.VirtualGraphics.KEYMAP_LOCAL
985
elif keymap.lower() != "none":
1638
def sanitize_keymap(keymap):
1641
if keymap.lower() == "local":
1642
return virtinst.VirtualGraphics.KEYMAP_LOCAL
1643
if keymap.lower() == "none":
986
1646
use_keymap = _util.check_keytable(keymap)
987
1647
if not use_keymap:
988
raise ValueError(_("Didn't match keymap '%s' in keytable!") %
993
def parse_graphics(guest, optstring, basedict):
994
if optstring is None and not basedict:
1649
_("Didn't match keymap '%s' in keytable!") % keymap)
997
1652
# Peel the model type off the front
998
gtype, opts = parse_optstr(optstring, basedict, remove_first=True)
999
if gtype == "none" or basedict.get("type") == "none":
1653
opts = parse_optstr(optstring, remove_first="type")
1654
if opts.get("type") == "none":
1001
dev = VirtualGraphics(conn=guest.conn)
1658
dev = VirtualGraphics(conn=guest.conn)
1003
1660
def set_param(paramname, dictname, val=None):
1004
1661
val = get_opt_param(opts, dictname, val)
1025
def get_graphics(vnc, vncport, vnclisten, nographics, sdl, keymap,
1026
video_models, graphics, guest):
1027
video_models = video_models or []
1029
if graphics and (vnc or sdl or keymap or vncport or vnclisten):
1030
fail(_("Cannot mix --graphics and old style graphical options"))
1032
# If not graphics specified, choose a default
1033
if not (vnc or nographics or sdl or graphics):
1034
if "DISPLAY" in os.environ.keys():
1035
logging.debug("DISPLAY is set: graphics defaulting to VNC.")
1038
logging.debug("DISPLAY is not set: defaulting to nographics.")
1041
if (sum(map(int, map(bool, [vnc, nographics, sdl, graphics])))) > 1:
1042
raise ValueError(_("Can't specify more than one of VNC, SDL, "
1043
"--graphics or --nographics"))
1045
# Build an initial graphics argument dict
1047
"type" : ((vnc and "vnc") or
1049
(nographics and "none")),
1050
"listen" : vnclisten,
1056
dev = parse_graphics(guest, graphics, basedict)
1057
except Exception, e:
1058
fail(_("Error in graphics device parameters: %s") % str(e))
1062
guest.graphics_dev = dev
1064
# At this point we are definitely using graphics, so setup a default
1065
# video card if necc.
1066
if not video_models:
1067
video_models.append(None)
1068
for model in video_models:
1069
vdev = virtinst.VirtualVideoDevice(guest.conn)
1071
vdev.model_type = model
1072
guest.add_device(vdev)
1074
def get_sound(old_sound_bool, sound_opts, guest):
1078
guest.sound_devs.append(VirtualAudio(conn=guest.conn))
1081
for model in listify(sound_opts):
1082
dev = VirtualAudio(conn=guest.conn)
1084
guest.add_device(dev)
1087
def get_hostdevs(hostdevs, guest):
1091
for devname in hostdevs:
1092
dev = virtinst.VirtualHostDevice.device_from_node(conn=guest.conn,
1094
guest.hostdevs.append(dev)
1097
def check_before_store(option, opt_str, value, parser):
1099
raise OptionValueError(_("%s option requires an argument") % opt_str)
1100
setattr(parser.values, option.dest, value)
1102
def check_before_append(option, opt_str, value, parser):
1104
raise OptionValueError(_("%s option requires an argument") % opt_str)
1105
parser.values.ensure_value(option.dest, []).append(value)
1107
def get_opt_param(opts, dictnames, val=None):
1108
if type(dictnames) is not list:
1109
dictnames = [dictnames]
1111
for key in dictnames:
1682
#######################
1683
# --smartcard parsing #
1684
#######################
1686
def parse_smartcard(guest, optstring, dev=None):
1687
if optstring is None:
1690
# Peel the mode off the front
1691
opts = parse_optstr(optstring, remove_first="mode")
1692
if opts.get("mode") == "none":
1696
dev = virtinst.VirtualSmartCardDevice(guest.conn, opts.get("mode"))
1698
set_param = _build_set_param(dev, opts)
1700
set_param("mode", "mode")
1701
set_param("type", "type")
1704
raise ValueError(_("Unknown options %s") % opts.keys())
1708
######################
1709
# --watchdog parsing #
1710
######################
1712
def parse_watchdog(guest, optstring, dev=None):
1713
# Peel the model type off the front
1714
opts = parse_optstr(optstring, remove_first="model")
1717
dev = virtinst.VirtualWatchdog(guest.conn)
1719
def set_param(paramname, dictname, val=None):
1720
val = get_opt_param(opts, dictname, val)
1724
setattr(dev, paramname, val)
1726
set_param("model", "model")
1727
set_param("action", "action")
1730
raise ValueError(_("Unknown options %s") % opts.keys())
1735
######################################################
1736
# --serial, --parallel, --channel, --console parsing #
1737
######################################################
1739
def parse_serial(guest, optstring, dev=None):
1740
return _parse_char(guest, optstring, "serial", dev)
1741
def parse_parallel(guest, optstring, dev=None):
1742
return _parse_char(guest, optstring, "parallel", dev)
1743
def parse_console(guest, optstring, dev=None):
1744
return _parse_char(guest, optstring, "console", dev)
1745
def parse_channel(guest, optstring, dev=None):
1746
return _parse_char(guest, optstring, "channel", dev)
1748
def _parse_char(guest, optstring, dev_type, dev=None):
1750
Helper to parse --serial/--parallel options
1752
# Peel the char type off the front
1753
opts = parse_optstr(optstring, remove_first="char_type")
1754
char_type = opts.get("char_type")
1757
dev = VirtualCharDevice.get_dev_instance(guest.conn,
1758
dev_type, char_type)
1760
def set_param(paramname, dictname, val=None):
1761
val = get_opt_param(opts, dictname, val)
1765
if not dev.supports_property(paramname):
1766
raise ValueError(_("%(devtype)s type '%(chartype)s' does not "
1767
"support '%(optname)s' option.") %
1768
{"devtype" : dev_type, "chartype": char_type,
1769
"optname" : dictname} )
1770
setattr(dev, paramname, val)
1772
def parse_host(key):
1773
host, ignore, port = partition(opts.get(key), ":")
1112
1774
if key in opts:
1119
def partition(string, sep):
1121
return (None, None, None)
1123
if string.count(sep):
1124
splitres = string.split(sep, 1)
1125
ret = (splitres[0], sep, splitres[1])
1127
ret = (string, None, None)
1777
return host or None, port or None
1779
host, port = parse_host("host")
1780
bind_host, bind_port = parse_host("bind_host")
1781
target_addr, target_port = parse_host("target_address")
1783
set_param("char_type", "char_type")
1784
set_param("source_path", "path")
1785
set_param("source_mode", "mode")
1786
set_param("protocol", "protocol")
1787
set_param("source_host", "host", host)
1788
set_param("source_port", "host", port)
1789
set_param("bind_host", "bind_host", bind_host)
1790
set_param("bind_port", "bind_host", bind_port)
1791
set_param("target_type", "target_type")
1792
set_param("target_name", "name")
1793
set_param("target_address", "target_address", target_addr)
1794
set_param("target_port", "target_address", target_port)
1797
raise ValueError(_("Unknown options %s") % opts.keys())
1799
# Try to generate dev XML to perform upfront validation
1800
dev.get_xml_config()
1805
########################
1806
# --filesystem parsing #
1807
########################
1809
def parse_filesystem(guest, optstring, dev=None):
1810
opts = parse_optstr(optstring, remove_first=["source", "target"])
1813
dev = virtinst.VirtualFilesystem(guest.conn)
1815
def set_param(paramname, dictname, val=None):
1816
val = get_opt_param(opts, dictname, val)
1820
setattr(dev, paramname, val)
1822
set_param("type", "type")
1823
set_param("mode", "mode")
1824
set_param("source", "source")
1825
set_param("target", "target")
1828
raise ValueError(_("Unknown options %s") % opts.keys())
1836
def parse_video(guest, optstr, dev=None):
1837
opts = {"model" : optstr}
1840
dev = virtinst.VirtualVideoDevice(conn=guest.conn)
1842
set_param = _build_set_param(dev, opts)
1844
set_param("model_type", "model")
1847
raise ValueError(_("Unknown options %s") % opts.keys())
1850
#####################
1851
# --soundhw parsing #
1852
#####################
1854
def parse_sound(guest, optstr, dev=None):
1855
opts = {"model" : optstr}
1858
dev = virtinst.VirtualAudio(conn=guest.conn)
1860
set_param = _build_set_param(dev, opts)
1862
set_param("model", "model")
1865
raise ValueError(_("Unknown options %s") % opts.keys())
1868
#####################
1869
# --hostdev parsing #
1870
#####################
1872
def parse_hostdev(guest, optstr, dev=None):
1873
# XXX: Need to implement this for virt-xml
1875
return virtinst.VirtualHostDevice.device_from_node(conn=guest.conn,