36
37
import virtinst.CapabilitiesParser
37
38
import virtinst.cli as cli
39
import virtinst.util as util
40
import virtinst._util as _util
38
41
from virtinst.VirtualCharDevice import VirtualCharDevice
39
42
from virtinst.VirtualDevice import VirtualDevice
40
from virtinst.cli import fail
43
from virtinst.cli import fail, print_stdout, print_stderr
44
47
DEFAULT_POOL_PATH = "/var/lib/libvirt/images"
45
48
DEFAULT_POOL_NAME = "default"
47
def partition(string, sep):
49
return (None, None, None)
52
splitres = string.split(sep, 1)
53
ret = (splitres[0], sep, splitres[1])
55
ret = (string, None, None)
50
install_methods = "--location URL, --cdrom CD/ISO, --pxe, --import, --boot hd|cdrom|..."
51
install_missing = (_("An install method must be specified\n(%(methods)s)") %
52
{"methods" : install_methods })
53
disk_missing = _("--disk storage must be specified (override with --nodisks)")
55
def install_specified(location, cdpath, pxe, import_install):
56
return bool(pxe or cdpath or location or import_install)
58
def cdrom_specified(guest, diskopts=None):
59
for disk in guest.disks:
60
if disk.device == virtinst.VirtualDisk.DEVICE_CDROM:
63
# Probably haven't set up disks yet
64
if not guest.disks and diskopts:
66
if opts.count("device=cdrom"):
71
def storage_specified(files, disks, nodisks):
72
return bool(files or disks or nodisks)
58
74
def build_default_pool(guest):
81
97
raise RuntimeError(_("Couldn't create default storage pool '%s': %s") %
82
98
(DEFAULT_POOL_PATH, str(e)))
84
def parse_char_option(guest, char_type, optstring):
100
def supports_pxe(guest):
102
Return False if we are pretty sure the config doesn't support PXE
104
for nic in guest.get_devices("interface"):
105
if nic.type == nic.TYPE_USER:
107
if nic.type != nic.TYPE_VIRTUAL:
111
xml = nic.conn.networkLookupByName(nic.network).XMLDesc(0)
112
if util.get_xml_path(xml, "/network/ip/dhcp/bootp/@file"):
115
forward = util.get_xml_path(xml, "/network/forward/@mode")
116
if forward and forward != "nat":
119
_util.log_exception("Error checking if PXE supported")
124
def parse_boot_option(guest, optstring):
126
Helper to parse --boot string
128
ignore, opts = cli.parse_optstr(optstring)
129
optlist = map(lambda x: x[0], cli.parse_optstr_tuples(optstring))
132
def set_param(paramname, dictname, val=None):
133
val = cli.get_opt_param(opts, dictname, val)
137
setattr(guest.installer.bootconfig, paramname, val)
139
# Convert menu= value
141
menustr = opts["menu"]
144
if menustr.lower() == "on":
146
elif menustr.lower() == "off":
149
menu = cli.yes_or_no_convert(menustr)
152
fail(_("--boot menu must be 'on' or 'off'"))
154
set_param("enable_bootmenu", "menu", menu)
155
set_param("kernel", "kernel")
156
set_param("initrd", "initrd")
157
set_param("kernel_args", ["kernel_args", "extra_args"])
162
for boot_dev in optlist:
163
if not boot_dev in guest.installer.bootconfig.boot_devices:
167
if boot_dev not in boot_order:
168
boot_order.append(boot_dev)
170
guest.installer.bootconfig.bootorder = boot_order
173
raise ValueError(_("Unknown options %s") % opts.keys())
176
def parse_char_option(guest, dev_type, optstring):
86
178
Helper to parse --serial/--parallel options
88
180
# Peel the char type off the front
89
dev_type, ignore, optstring = partition(optstring, ",")
91
opts = cli.parse_optstr(optstring)
93
dev = VirtualCharDevice.get_dev_instance(guest.conn, char_type, dev_type)
181
char_type, opts = cli.parse_optstr(optstring, remove_first=True)
182
dev = VirtualCharDevice.get_dev_instance(guest.conn, dev_type, char_type)
95
184
def set_param(paramname, dictname, val=None):
97
if opts.has_key(dictname):
185
val = cli.get_opt_param(opts, dictname, val)
103
if not hasattr(dev, paramname):
189
if not dev.supports_property(paramname):
104
190
raise ValueError(_("%(chartype)s type %(devtype)s does not "
105
191
"support '%(optname)s' option.") %
106
{"chartype" : char_type, "devtype": dev_type,
192
{"devtype" : dev_type, "chartype": char_type,
107
193
"optname" : dictname} )
108
194
setattr(dev, paramname, val)
110
196
def parse_host(key):
111
host, ignore, port = partition(opts.get(key), ":")
112
if opts.has_key(key):
197
host, ignore, port = cli.partition(opts.get(key), ":")
115
201
return host, port
117
203
host, port = parse_host("host")
118
204
bind_host, bind_port = parse_host("bind_host")
205
target_addr, target_port = parse_host("target_address")
120
207
set_param("source_path", "path")
121
208
set_param("source_mode", "mode")
142
232
guest.add_device(dev)
143
233
except Exception, e:
144
234
fail(_("Error in %(chartype)s device parameters: %(err)s") %
145
{"chartype": char_type, "err": str(e) })
235
{"chartype": char_type, "err": str(e)})
147
237
def parse_watchdog(guest, optstring):
148
238
# Peel the model type off the front
149
model, ignore, optstring = partition(optstring, ",")
150
opts = cli.parse_optstr(optstring)
239
model, opts = cli.parse_optstr(optstring, remove_first=True)
151
240
dev = virtinst.VirtualWatchdog(guest.conn)
153
242
def set_param(paramname, dictname, val=None):
155
if opts.has_key(dictname):
243
val = cli.get_opt_param(opts, dictname, val)
161
247
setattr(dev, paramname, val)
163
249
set_param("model", "model", model)
164
250
set_param("action", "action")
166
# If extra parameters, then user passed some garbage param
168
raise ValueError(_("Unknown option(s) %s") % opts.keys())
253
raise ValueError(_("Unknown options %s") % opts.keys())
609
724
help=_("Treat the CD-ROM media as a Live CD"))
610
725
insg.add_option("-x", "--extra-args", type="string", dest="extra",
612
help=_("Additional arguments to pass to the kernel "
727
help=_("Additional arguments to pass to the install kernel "
613
728
"booted from --location"))
729
insg.add_option("", "--initrd-inject", type="string",
730
dest="initrd_injections", action="callback",
731
callback=cli.check_before_append,
732
help=_("Add given file to root of initrd from --location"))
614
733
insg.add_option("", "--os-type", type="string", dest="distro_type",
615
734
action="callback", callback=cli.check_before_store,
616
735
help=_("The OS type being installed, e.g. "
617
736
"'linux', 'unix', 'windows'"))
618
737
insg.add_option("", "--os-variant", type="string", dest="distro_variant",
619
action="callback", callback=cli.check_before_store,
620
help=_("The OS variant being installed guests, "
621
"e.g. 'fedora6', 'rhel5', 'solaris10', 'win2k'"))
738
action="callback", callback=cli.check_before_store,
739
help=_("The OS variant being installed guests, "
740
"e.g. 'fedora6', 'rhel5', 'solaris10', 'win2k'"))
741
insg.add_option("", "--boot", type="string", dest="bootopts", default="",
742
help=_("Optionally configure post-install boot order, "
743
"menu, permanent kernel boot, etc."))
622
744
parser.add_option_group(insg)
624
746
stog = OptionGroup(parser, _("Storage Configuration"))
676
798
devg.add_option("", "--parallel", type="string", dest="parallels",
677
799
action="callback", callback=cli.check_before_append,
678
800
help=_("Add a parallel device to the domain."))
801
geng.add_option("", "--channel", type="string", dest="channels",
802
action="callback", callback=cli.check_before_append,
803
help=_("Add a guest communication channel."))
804
geng.add_option("", "--console", type="string", dest="consoles",
805
action="callback", callback=cli.check_before_append,
806
help=_("Add a text console connection between the guest "
679
808
devg.add_option("", "--host-device", type="string", dest="hostdevs",
680
809
action="callback", callback=cli.check_before_append,
681
810
help=_("Physical host device to attach to the domain."))
725
857
misc.add_option("", "--autostart", action="store_true", default=False,
726
858
dest="autostart",
727
859
help=_("Have domain autostart on host boot up."))
860
misc.add_option("", "--print-xml", action="store_true", dest="xmlonly",
861
help=_("Print the generated domain XML rather than define "
863
misc.add_option("", "--print-step", type="str", dest="xmlstep",
864
help=_("Print XML of a specific install step "
865
"(1, 2, 3, all) rather than define the guest."))
728
866
misc.add_option("", "--noreboot", action="store_true", dest="noreboot",
729
867
help=_("Disables the automatic rebooting when the "
730
868
"installation is complete."))
731
869
misc.add_option("", "--wait", type="int", dest="wait",
732
870
help=_("Time to wait (in minutes)"))
871
misc.add_option("", "--dry-run", action="store_true", dest="dry",
872
help=_("Run through install process, but do not "
873
"create devices or define the guest."))
733
874
misc.add_option("", "--force", action="store_true", dest="force",
734
875
help=_("Forces 'yes' for any applicable prompts, "
735
876
"terminates for all others"),
878
misc.add_option("-q", "--quiet", action="store_true", dest="quiet",
879
help=_("Suppress non-error output"))
737
880
misc.add_option("", "--prompt", action="store_true", dest="prompt",
738
881
help=_("Request user input for ambiguous situations or "
739
882
"required options."), default=False)
740
misc.add_option("", "--check-cpu", action="store_true", dest="check_cpu",
741
help=_("Check that vcpus do not exceed physical CPUs "
742
"and warn if they do."))
743
883
misc.add_option("-d", "--debug", action="store_true", dest="debug",
744
884
help=_("Print debugging information"))
745
885
parser.add_option_group(misc)
747
(options, dummy) = parser.parse_args()
887
(options, cliargs) = parser.parse_args()
888
return options, cliargs
751
891
def vnc_console(dom, uri):
804
937
fail(_("Can't use --pxe with --nonetworks"))
806
939
instclass = virtinst.PXEInstaller
807
elif options.import_install:
940
elif options.cdrom or options.location:
941
instclass = virtinst.DistroInstaller
942
elif options.import_install or options.bootopts:
943
if options.import_install and options.nodisks:
944
fail(_("A disk device must be specified with --import."))
945
options.import_install = True
808
946
instclass = virtinst.ImportInstaller
810
948
instclass = virtinst.DistroInstaller
811
950
installer = instclass(type=hv_name, os_type=virt_type, conn=conn)
812
951
installer.arch = capsguest.arch
952
installer.initrd_injections = options.initrd_injections
953
installer.machine = options.machine
815
955
# Get Guest instance from installer parameters.
816
956
guest = installer.guest_from_installer()
819
959
# now let's get some of the common questions out of the way
820
if virt_type == "hvm":
825
cli.get_name(options.name, guest)
826
cli.get_memory(options.memory, guest)
960
ishvm = bool(virt_type == "hvm")
963
get_networks(options.mac, options.bridge, options.network,
964
options.nonetworks, guest)
965
cli.get_graphics(options.vnc, options.vncport, options.vnclisten,
966
options.nographics, options.sdl, options.keymap,
967
options.video, options.graphics, guest)
827
969
cli.get_uuid(options.uuid, guest)
828
cli.get_vcpus(options.vcpus, options.check_cpu, guest, conn)
829
cli.get_cpuset(options.cpuset, guest.memory, guest, conn)
970
cli.get_vcpus(options.vcpus, options.check_cpu, guest)
971
cli.get_cpuset(options.cpuset, guest.memory, guest)
972
cli.parse_cpu(guest, options.cpu)
830
973
get_security(options.security, guest)
974
parse_boot_option(guest, options.bootopts)
832
976
get_watchdog(options.watchdog, guest)
833
977
cli.get_sound(options.sound, options.soundhw, guest)
834
978
get_chardevs(VirtualDevice.VIRTUAL_DEV_SERIAL, options.serials, guest)
835
979
get_chardevs(VirtualDevice.VIRTUAL_DEV_PARALLEL, options.parallels, guest)
980
get_chardevs(VirtualDevice.VIRTUAL_DEV_CHANNEL, options.channels, guest)
981
get_chardevs(VirtualDevice.VIRTUAL_DEV_CONSOLE, options.consoles, guest)
837
983
guest.autostart = options.autostart
838
984
guest.description = options.description
841
get_disks(options.file_path, options.diskopts, options.disksize,
842
options.sparse, options.nodisks, guest, conn)
844
# set up network information
845
get_networks(options.mac, options.bridge, options.network,
846
options.nonetworks, guest)
848
# set up graphics and video device information
849
cli.get_graphics(options.vnc, options.vncport, options.vnclisten,
850
options.nographics, options.sdl, options.keymap,
851
options.video, guest)
853
986
# Set host device info
854
987
cli.get_hostdevs(options.hostdevs, guest)
856
989
guest.extraargs = options.extra
990
guest.features["acpi"] = not options.noacpi
991
guest.features["apic"] = not options.noapic
857
993
cli.set_os_variant(guest, options.distro_type, options.distro_variant)
859
# and now for the full-virt vs paravirt specific questions
995
# Required config. Don't error right away if nothing is specified,
996
# aggregate the errors to help first time users get it right
998
if not cli.is_prompt():
1000
msg += "\n" + cli.name_missing
1001
if not options.memory:
1002
msg += "\n" + cli.ram_missing
1003
if not storage_specified(options.file_path, options.diskopts,
1005
msg += "\n" + disk_missing
1006
if ((not install_specified(options.location, options.cdrom,
1007
options.pxe, options.import_install)) and
1008
(not cdrom_specified(guest, options.diskopts))):
1009
msg += "\n" + install_missing
1013
cli.get_name(options.name, guest)
1014
cli.get_memory(options.memory, guest)
1015
get_disks(options.file_path, options.diskopts, options.disksize,
1016
options.sparse, options.nodisks, guest, conn)
860
1017
get_install_media(options.location, options.cdrom, options.pxe,
861
options.livecd, options.import_install, guest, ishvm)
863
continue_inst = guest.get_continue_inst()
865
guest.features["acpi"] = False
867
guest.features["apic"] = False
1018
options.livecd, options.import_install,
1021
if not options.location and options.extra:
1022
fail(_("--extra-args only work if specified with --location."))
1024
if options.pxe and not supports_pxe(guest):
1025
logging.warn(_("The guest's network configuration does not support "
1030
def start_install(guest, continue_inst, options):
869
1031
def show_console(dom):
870
1032
if guest.graphics_dev:
871
1033
if guest.graphics_dev.type == virtinst.VirtualGraphics.TYPE_VNC:
872
return vnc_console(dom, options.connect)
1034
return vnc_console(dom, guest.conn.getURI())
874
1036
return None # SDL needs no viewer app
876
return txt_console(dom, options.connect)
1038
return txt_console(dom, guest.conn.getURI())
878
1040
# There are two main cases we care about:
885
1047
# waiting. Otherwise, we can exit before the domain has finished
886
1048
# installing. Passing --wait will give the above semantics.
1050
wait_on_install = continue_inst
890
autoconsole = options.autoconsole
892
1052
if options.wait != None:
1053
wait_on_install = True
894
1054
wait_time = options.wait * 60
896
# --wait 0 implies --noautoconsole
899
if autoconsole is False:
902
conscb = show_console
904
progresscb = progress.TextMeter()
1056
# If --wait specified, we don't want the default behavior of waiting
1057
# for virt-viewer to exit, since then we can't exit the app when time
1059
wait_on_console = not wait_on_install
1061
# --wait 0 implies --noautoconsole
1062
options.autoconsole = (wait_time != 0) and options.autoconsole or False
1064
conscb = options.autoconsole and show_console or None
1065
meter = options.quiet and progress.BaseMeter() or progress.TextMeter()
1066
logging.debug("Guest.has_install_phase: %s" %
1067
guest.installer.has_install_phase())
907
1069
# we've got everything -- try to start the install
908
print _("\n\nStarting install...")
1070
print_stdout(_("\nStarting install..."))
911
1073
start_time = time.time()
913
1075
# Do first install phase
914
dom = do_install(guest, conscb, progresscb, wait, wait_time,
915
start_time, guest.start_install)
1077
dom = guest.start_install(conscb, meter, wait=wait_on_console)
1078
dom = check_domain(guest, dom, conscb,
1079
wait_on_install, wait_time, start_time)
917
1081
# This should be valid even before doing continue install
918
1082
if not guest.post_install_check():
919
print _("Domain installation does not appear to have been\n "
920
"successful. If it was, you can restart your domain\n "
921
"by running 'virsh start %s'; otherwise, please\n "
922
"restart your installation.") % guest.name
1083
cli.install_fail(guest)
925
1085
if continue_inst:
926
dom = do_install(guest, conscb, progresscb, wait, wait_time,
927
start_time, guest.continue_install)
1086
dom = guest.continue_install(conscb, meter, wait=wait_on_console)
1087
dom = check_domain(guest, dom, conscb,
1088
wait_on_install, wait_time, start_time)
930
print _("Guest installation complete... you can restart your "
931
"domain\nby running 'virsh start %s'") % guest.name
1090
if options.noreboot or not guest.installer.has_install_phase():
1091
# XXX: --noreboot doesn't work with say import/livecd. what
1092
# should it do? never startup the guest?
1094
_("Domain creation completed. You can restart your domain by "
1095
"running:\n %s") % cli.virsh_start_cmd(guest))
933
# FIXME: Should we say 'installation' complete for livecd, import?
934
print _("Guest installation complete... restarting guest.")
1098
_("Guest installation complete... restarting guest."))
936
1100
guest.connect_console(conscb)
938
1102
except KeyboardInterrupt, e:
939
1104
guest.terminate_console()
940
print _("Guest install interrupted.")
1105
print_stderr(_("Domain install interrupted."))
941
1106
except RuntimeError, e:
943
1108
except SystemExit, e:
944
1109
sys.exit(e.code)
945
1110
except Exception, e:
947
print _("Domain installation does not appear to have been\n "
948
"successful. If it was, you can restart your domain\n "
949
"by running 'virsh start %s'; otherwise, please\n "
950
"restart your installation.") % guest.name
954
def do_install(guest, conscb, progresscb, wait, wait_time, start_time,
957
dom = install_func(conscb, progresscb, wait=(not wait))
1111
fail(e, do_exit=False)
1112
cli.install_fail(guest)
1114
def check_domain(guest, dom, conscb, wait_for_install, wait_time, start_time):
1116
Make sure domain ends up in expected state, and wait if for install
1117
to complete if requested
1119
wait_forever = (wait_time < 0)
959
1121
# Wait a bit so info is accurate
960
1122
def check_domain_state():
1152
# Domain seems to be running
991
1153
logging.debug("Domain state after install: %s" % state)
993
# Domain seems to be running
994
if wait and wait_time != 0:
997
timestr = _("%d minutes ") % (int(wait_time) / 60)
999
print _("Domain installation still in progress. Waiting %s"
1000
"for installation to complete.") % timestr
1004
if guest.domain_is_shutdown():
1005
print _("Domain has shutdown. Continuing.")
1007
# Lookup a new domain object incase current
1008
# one returned bogus data (see comment in
1009
# domain_is_shutdown
1010
dom = guest.conn.lookupByName(guest.name)
1011
except Exception, e:
1012
raise RuntimeError(_("Could not lookup domain after "
1013
"install: %s" % str(e)))
1016
if wait_time < 0 or ((time.time() - start_time) < wait_time):
1019
print _("Installation has exceeded specified time limit. "
1020
"Exiting application.")
1023
# User specified --wait 0, which means --noautoconsole, which
1025
print _("Domain installation still in progress. You can reconnect"
1026
" to \nthe console to complete the installation process.")
1155
if not wait_for_install or wait_time == 0:
1157
# used --noautoconsole
1159
# killed console and guest is still running
1160
if not guest.installer.has_install_phase():
1164
_("Domain installation still in progress. You can reconnect"
1165
" to \nthe console to complete the installation process."))
1168
timestr = (not wait_forever and
1169
_("%d minutes ") % (int(wait_time) / 60) or "")
1171
_("Domain installation still in progress. Waiting %s"
1172
"for installation to complete.") % timestr)
1176
if guest.domain_is_shutdown():
1177
print_stdout(_("Domain has shutdown. Continuing."))
1179
# Lookup a new domain object incase current
1180
# one returned bogus data (see comment in
1181
# domain_is_shutdown
1182
dom = guest.conn.lookupByName(guest.name)
1183
except Exception, e:
1184
raise RuntimeError(_("Could not lookup domain after "
1185
"install: %s" % str(e)))
1188
time_elapsed = (time.time() - start_time)
1189
if not wait_forever and time_elapsed >= wait_time:
1191
_("Installation has exceeded specified time limit. "
1192
"Exiting application."))
1199
def xml_to_print(guest, continue_inst, xmlonly, xmlstep, dry):
1200
start_xml, final_xml = guest.start_install(dry=dry, return_xml=True)
1203
start_xml = final_xml
1207
second_xml, final_xml = guest.continue_install(dry=dry,
1210
if dry and not (xmlonly or xmlstep):
1211
print_stdout(_("Dry run completed successfully"))
1215
if xmlonly and not xmlstep:
1216
if second_xml or final_xml:
1217
fail(_("--xml-only can only be used with guests that do not have "
1218
"an installation phase (--import, --boot, etc.). To see all"
1219
"all generated XML, please use --xml-step all."))
1226
if not (second_xml or final_xml):
1227
fail(_("Requested installation does not have XML step 2"))
1228
return second_xml or final_xml
1231
fail(_("Requested installation does not have XML step 3"))
1244
options, cliargs = parse_args()
1246
# Default setup options
1247
options.quiet = options.xmlstep or options.xmlonly or options.quiet
1248
cli.setupLogging("virt-install", options.debug, options.quiet)
1250
fail(_("Unknown argument '%s'") % cliargs[0])
1252
cli.set_force(options.force)
1253
cli.set_prompt(options.prompt)
1254
conn = cli.getConnection(options.connect)
1256
if options.xmlstep not in [None, "1", "2", "3", "all"]:
1257
fail(_("--print-step must be 1, 2, 3, or all"))
1259
guest = build_guest_instance(conn, options)
1260
continue_inst = guest.get_continue_inst()
1262
if options.xmlstep or options.xmlonly or options.dry:
1263
xml = xml_to_print(guest, continue_inst,
1264
options.xmlonly, options.xmlstep, options.dry)
1266
print_stdout(xml, do_force=True)
1268
start_install(guest, continue_inst, options)
1031
1272
if __name__ == "__main__":
1034
1275
except SystemExit, sys_e:
1035
1276
sys.exit(sys_e.code)
1036
1277
except KeyboardInterrupt:
1037
print >> sys.stderr, _("Installation aborted at user request")
1279
print_stderr(_("Installation aborted at user request"))
1038
1280
except Exception, main_e:
1039
logging.exception(main_e)