19
19
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20
20
# MA 02110-1301 USA.
24
25
import logging.handlers
25
import gettext, locale
27
from optparse import OptionValueError, OptionParser
29
from optparse import OptionValueError, OptionParser, OptionGroup
32
from virtinst import VirtualNetworkInterface, VirtualVideoDevice, Guest, \
37
from _util import listify
38
from virtinst import VirtualNetworkInterface, Guest, \
33
39
VirtualGraphics, VirtualAudio, VirtualDisk, User
34
40
from virtinst import _virtinst as _
40
def check_if_test_uri_remote(uri):
41
magic = "__virtinst_test_remote__"
42
if uri and uri.startswith(magic):
43
uri = uri.replace(magic, "")
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"
44
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:///"
47
118
class VirtStreamHandler(logging.StreamHandler):
133
206
gettext.bindtextdomain(virtinst.gettext_app, virtinst.gettext_dir)
134
207
gettext.install(virtinst.gettext_app, virtinst.gettext_dir)
136
def setupLogging(appname, debug=False):
210
logging.basicConfig(level=logging.DEBUG, format='%(message)s')
212
def setupLogging(appname, debug=False, do_quiet=False):
138
216
vi_dir = os.path.expanduser("~/.virtinst")
139
217
if not os.access(vi_dir, os.W_OK):
140
218
if os.path.exists(vi_dir):
150
228
dateFormat = "%a, %d %b %Y %H:%M:%S"
151
fileFormat = "[%(asctime)s " + appname + " %(process)d] %(levelname)s (%(module)s:%(lineno)d) %(message)s"
229
fileFormat = ("[%(asctime)s " + appname + " %(process)d] "
230
"%(levelname)s (%(module)s:%(lineno)d) %(message)s")
152
231
streamDebugFormat = "%(asctime)s %(levelname)-8s %(message)s"
153
232
streamErrorFormat = "%(levelname)-8s %(message)s"
154
233
filename = os.path.join(vi_dir, appname + ".log")
156
235
rootLogger = logging.getLogger()
238
for handler in rootLogger.handlers:
239
rootLogger.removeHandler(handler)
157
241
rootLogger.setLevel(logging.DEBUG)
158
fileHandler = logging.handlers.RotatingFileHandler(filename, "a",
242
fileHandler = logging.handlers.RotatingFileHandler(filename, "ae",
161
245
fileHandler.setFormatter(logging.Formatter(fileFormat,
193
281
def fail(msg, do_exit=True):
194
282
"""Convenience function when failing in cli app"""
195
283
logging.error(msg)
196
_util.log_exception()
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
200
296
def _fail_exit():
204
print _("Exiting at user request.")
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)
207
316
# Connection opening helper functions
208
def getConnection(connect):
210
not User.current().has_priv(User.PRIV_CREATE_DOMAIN, connect)):
317
def getConnection(uri):
318
if (uri and not User.current().has_priv(User.PRIV_CREATE_DOMAIN, uri)):
211
319
fail(_("Must be root to create Xen guests"))
213
# Hack to facilitate remote unit testing
214
connect = check_if_test_uri_remote(connect)
321
# Hack to facilitate virtinst unit testing
322
if _is_virtinst_test_uri(uri):
323
return _open_test_uri(uri)
216
logging.debug("Requesting libvirt URI %s" % (connect or "default"))
217
conn = open_connection(connect)
325
logging.debug("Requesting libvirt URI %s" % (uri or "default"))
326
conn = open_connection(uri)
218
327
logging.debug("Received libvirt URI %s" % conn.getURI())
407
512
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)
410
530
# Register vnc + sdl options for virt-install and virt-image
411
531
def graphics_option_group(parser):
412
from optparse import OptionGroup
414
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=1,tlsport=2\n"
540
"--graphics vnc,password=foobar,port=5910,keymap=ja"))
415
541
vncg.add_option("", "--vnc", action="store_true", dest="vnc",
416
help=_("Use VNC for graphics support"))
542
help=optparse.SUPPRESS_HELP)
417
543
vncg.add_option("", "--vncport", type="int", dest="vncport",
418
help=_("Port to use for VNC"))
544
help=optparse.SUPPRESS_HELP)
419
545
vncg.add_option("", "--vnclisten", type="string", dest="vnclisten",
420
help=_("Address to listen on for VNC connections."))
546
help=optparse.SUPPRESS_HELP)
421
547
vncg.add_option("-k", "--keymap", type="string", dest="keymap",
422
548
action="callback", callback=check_before_store,
423
help=_("set up keymap for the VNC console"))
549
help=optparse.SUPPRESS_HELP)
424
550
vncg.add_option("", "--sdl", action="store_true", dest="sdl",
425
help=_("Use SDL for graphics support"))
551
help=optparse.SUPPRESS_HELP)
426
552
vncg.add_option("", "--nographics", action="store_true",
427
help=_("Don't set up a graphical console for the guest."))
553
help=optparse.SUPPRESS_HELP)
430
556
# Specific function for disk prompting. Returns a validated VirtualDisk
559
683
except ValueError, e:
562
def get_vcpus(vcpus, check_cpu, guest, conn, image_vcpus=None):
686
def _build_set_param(inst, opts):
687
def _set_param(paramname, keyname, val=None):
688
val = get_opt_param(opts, keyname, val)
691
setattr(inst, paramname, val)
695
def parse_vcpu_option(guest, optstring, default_vcpus):
697
Helper to parse --vcpu string
699
vcpus, opts = parse_optstr(optstring, remove_first=True)
700
vcpus = vcpus or default_vcpus
702
set_param = _build_set_param(guest, opts)
703
set_cpu_param = _build_set_param(guest.cpu, opts)
704
has_vcpus = ("vcpus" in opts or vcpus)
706
set_param("vcpus", "vcpus", vcpus)
707
set_param("maxvcpus", "maxvcpus")
709
set_cpu_param("sockets", "sockets")
710
set_cpu_param("cores", "cores")
711
set_cpu_param("threads", "threads")
714
guest.vcpus = guest.cpu.vcpus_from_topology()
717
raise ValueError(_("Unknown options %s") % opts.keys())
720
def get_vcpus(vcpus, check_cpu, guest, image_vcpus=None):
721
if vcpus is None and image_vcpus is not None:
722
vcpus = int(image_vcpus)
724
parse_vcpu_option(guest, vcpus, image_vcpus)
564
728
hostinfo = conn.getInfo()
565
729
cpu_num = hostinfo[4] * hostinfo[5] * hostinfo[6] * hostinfo[7]
758
def parse_cpu(guest, optstring):
766
model, opts = parse_optstr(optstring,
767
basedict=default_dict,
770
# Convert +feature, -feature into expected format
771
for key, value in opts.items():
773
if value or len(key) == 1:
776
if key.startswith("+"):
778
elif key.startswith("-"):
783
opts[policy].append(key[1:])
785
set_param = _build_set_param(guest.cpu, opts)
786
def set_features(policy):
787
for name in opts.get(policy):
788
guest.cpu.add_feature(name, policy)
792
guest.cpu.copy_host_cpu()
795
set_param("model", "model", model)
796
set_param("match", "match")
797
set_param("vendor", "vendor")
799
set_features("force")
800
set_features("require")
801
set_features("optional")
802
set_features("disable")
803
set_features("forbid")
806
raise ValueError(_("Unknown options %s") % opts.keys())
600
808
def get_network(net_kwargs, guest):
601
809
n = VirtualNetworkInterface(**net_kwargs)
602
810
guest.nics.append(n)
626
837
if opt.count("="):
627
838
opt_type, opt_val = opt.split("=", 1)
628
optlist.append((opt_type.lower(), opt_val.lower()))
839
optlist.append((opt_type.lower(), opt_val))
630
841
optlist.append((opt.lower(), None))
634
def parse_optstr(optstr, basedict=None):
845
def parse_optstr(optstr, basedict=None, remove_first=False):
636
847
Helper function for parsing opt strings of the form
637
848
opt1=val1,opt2=val2,...
638
'basedict' is a starting dictionary, so the caller can easily set
850
@param basedict: starting dictionary, so the caller can easily set
852
@param remove_first: If true, remove the first options off the string
853
and return it seperately. For example,
854
--serial pty,foo=bar returns ("pty", {"foo" : "bar"})
641
856
Returns a dictionary of {'opt1': 'val1', 'opt2': 'val2'}
643
858
optlist = parse_optstr_tuples(optstr)
644
859
optdict = basedict or {}
862
if remove_first and optlist:
863
first_tuple = optlist[0]
864
if first_tuple[1] == None:
865
first = first_tuple[0]
866
optlist.remove(first_tuple)
646
868
for opt, val in optlist:
869
if type(optdict.get(opt)) is list:
870
optdict[opt].append(val)
874
return (first, optdict)
651
876
def parse_network_opts(conn, mac, network):
688
913
if mac == "RANDOM":
690
return { "conn" : conn, "type" : net_type, "bridge": bridge_name,
691
"network" : network_name, "model" : model , "macaddr" : mac }
915
return {"conn" : conn, "type" : net_type, "bridge": bridge_name,
916
"network" : network_name, "model" : model , "macaddr" : mac}
693
def digest_networks(conn, macs, bridges, networks, nics = 0):
918
def digest_networks(conn, macs, bridges, networks, nics=0):
694
919
macs = listify(macs)
695
920
bridges = listify(bridges)
696
921
networks = listify(networks)
713
938
if len(macs) > len(networks):
714
939
fail(_("Cannot pass more mac addresses than networks."))
716
for dummy in range (len(macs),len(networks)):
941
for dummy in range(len(macs), len(networks)):
717
942
macs.append(None)
719
944
# Create extra networks up to the number of nics requested
720
945
if len(macs) < nics:
721
for dummy in range(len(macs),nics):
946
for dummy in range(len(macs), nics):
722
947
if User.current().has_priv(User.PRIV_CREATE_NETWORK, conn.getURI()):
723
948
net = _util.default_network(conn)
724
949
networks.append(net[0] + ":" + net[1])
735
960
return net_init_dicts
962
def sanitize_keymap(keymap):
968
if keymap.lower() == "local":
969
use_keymap = virtinst.VirtualGraphics.KEYMAP_LOCAL
971
elif keymap.lower() != "none":
972
use_keymap = _util.check_keytable(keymap)
974
raise ValueError(_("Didn't match keymap '%s' in keytable!") %
979
def parse_graphics(guest, optstring, basedict):
980
if optstring is None and not basedict:
983
# Peel the model type off the front
984
gtype, opts = parse_optstr(optstring, basedict, remove_first=True)
985
if gtype == "none" or basedict.get("type") == "none":
987
dev = VirtualGraphics(conn=guest.conn)
989
def set_param(paramname, dictname, val=None):
990
val = get_opt_param(opts, dictname, val)
994
if paramname == "keymap":
995
val = sanitize_keymap(val)
996
setattr(dev, paramname, val)
998
set_param("type", "type", gtype)
999
set_param("port", "port")
1000
set_param("tlsPort", "tlsport")
1001
set_param("listen", "listen")
1002
set_param("keymap", "keymap")
1003
set_param("passwd", "password")
1004
set_param("passwdValidTo", "passwordvalidto")
1007
raise ValueError(_("Unknown options %s") % opts.keys())
737
1011
def get_graphics(vnc, vncport, vnclisten, nographics, sdl, keymap,
738
video_models, guest):
1012
video_models, graphics, guest):
739
1013
video_models = video_models or []
741
if ((vnc and nographics) or
743
(sdl and nographics)):
744
raise ValueError, _("Can't specify more than one of VNC, SDL, "
747
for model in video_models:
748
dev = virtinst.VirtualVideoDevice(guest.conn)
749
dev.model_type = model
750
guest.add_device(dev)
752
if not (vnc or nographics or sdl):
1015
if graphics and (vnc or sdl or keymap or vncport or vnclisten):
1016
fail(_("Cannot mix --graphics and old style graphical options"))
1018
# If not graphics specified, choose a default
1019
if not (vnc or nographics or sdl or graphics):
753
1020
if "DISPLAY" in os.environ.keys():
754
1021
logging.debug("DISPLAY is set: graphics defaulting to VNC.")
757
1024
logging.debug("DISPLAY is not set: defaulting to nographics.")
758
1025
nographics = True
760
if nographics is not None:
761
guest.graphics_dev = None
1027
if (sum(map(int, map(bool, [vnc, nographics, sdl, graphics])))) > 1:
1028
raise ValueError(_("Can't specify more than one of VNC, SDL, "
1029
"--graphics or --nographics"))
1031
# Build an initial graphics argument dict
1033
"type" : ((vnc and "vnc") or
1035
(nographics and "none")),
1036
"listen" : vnclisten,
1042
dev = parse_graphics(guest, graphics, basedict)
1043
except Exception, e:
1044
fail(_("Error in graphics device parameters: %s") % str(e))
1048
guest.graphics_dev = dev
764
# After this point, we are using graphics, so add a video device
765
# if one wasn't passed
1050
# At this point we are definitely using graphics, so setup a default
1051
# video card if necc.
766
1052
if not video_models:
767
guest.add_device(VirtualVideoDevice(conn=guest.conn))
770
guest.graphics_dev = VirtualGraphics(type=VirtualGraphics.TYPE_SDL)
774
guest.graphics_dev = VirtualGraphics(type=VirtualGraphics.TYPE_VNC)
776
guest.graphics_dev.port = vncport
778
guest.graphics_dev.listen = vnclisten
783
if keymap.lower() == "local":
784
use_keymap = virtinst.VirtualGraphics.KEYMAP_LOCAL
786
elif keymap.lower() != "none":
787
use_keymap = _util.check_keytable(keymap)
789
raise ValueError(_("Didn't match keymap '%s' in keytable!") %
792
guest.graphics_dev.keymap = use_keymap
1053
video_models.append(None)
1054
for model in video_models:
1055
vdev = virtinst.VirtualVideoDevice(guest.conn)
1057
vdev.model_type = model
1058
guest.add_device(vdev)
794
1060
def get_sound(old_sound_bool, sound_opts, guest):
795
1061
if not sound_opts:
816
1082
### Option parsing
817
1083
def check_before_store(option, opt_str, value, parser):
818
1084
if len(value) == 0:
819
raise OptionValueError, _("%s option requires an argument") %opt_str
1085
raise OptionValueError(_("%s option requires an argument") % opt_str)
820
1086
setattr(parser.values, option.dest, value)
822
1088
def check_before_append(option, opt_str, value, parser):
823
1089
if len(value) == 0:
824
raise OptionValueError, _("%s option requires an argument") %opt_str
1090
raise OptionValueError(_("%s option requires an argument") % opt_str)
825
1091
parser.values.ensure_value(option.dest, []).append(value)
1093
def get_opt_param(opts, dictnames, val=None):
1094
if type(dictnames) is not list:
1095
dictnames = [dictnames]
1097
for key in dictnames:
1105
def partition(string, sep):
1107
return (None, None, None)
1109
if string.count(sep):
1110
splitres = string.split(sep, 1)
1111
ret = (splitres[0], sep, splitres[1])
1113
ret = (string, None, None)