2013-03-18 05:06:52 +08:00
|
|
|
#!/usr/bin/python
|
|
|
|
#
|
|
|
|
# Copyright 2008, 2013 Red Hat, Inc.
|
|
|
|
# Joey Boggs <jboggs@redhat.com>
|
|
|
|
#
|
|
|
|
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
|
|
|
|
# Use is subject to license terms.
|
|
|
|
#
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program; if not, write to the Free Software
|
|
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
|
|
# MA 02110-1301 USA.
|
|
|
|
|
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
import logging
|
|
|
|
import errno
|
|
|
|
from optparse import OptionGroup
|
|
|
|
|
|
|
|
import virtinst.cli as cli
|
|
|
|
from virtinst.cli import fail, print_stdout, print_stderr
|
|
|
|
import virtconv.formats as formats
|
|
|
|
import virtconv.vmcfg as vmcfg
|
|
|
|
import virtconv.diskcfg as diskcfg
|
|
|
|
|
|
|
|
|
2013-04-11 23:11:21 +08:00
|
|
|
def get_default_arch():
|
|
|
|
arch = os.uname()[4]
|
|
|
|
if arch == "x86_64":
|
|
|
|
return "x86_64"
|
|
|
|
return "i686"
|
|
|
|
|
|
|
|
|
2013-03-18 05:06:52 +08:00
|
|
|
def parse_args():
|
|
|
|
"""Parse and verify command line."""
|
2013-07-01 03:03:53 +08:00
|
|
|
opts = cli.setupParser(
|
|
|
|
"%prog [options] inputdir|input.vmx [outputdir|output.xml]",
|
|
|
|
_("Convert from virtual machine descriptor format to another. The "
|
|
|
|
"VM contents are not altered."))
|
2013-03-18 05:06:52 +08:00
|
|
|
|
|
|
|
cong = OptionGroup(opts, "Conversion Options")
|
|
|
|
cong.add_option("-i", "--input-format", dest="input_format",
|
|
|
|
help=_("Input format, e.g. 'vmx'"))
|
|
|
|
cong.add_option("-o", "--output-format", dest="output_format",
|
|
|
|
default="virt-image",
|
|
|
|
help=_("Output format, e.g. 'virt-image'"))
|
|
|
|
cong.add_option("-D", "--disk-format", dest="disk_format",
|
|
|
|
help=_("Output disk format"))
|
|
|
|
opts.add_option_group(cong)
|
|
|
|
|
|
|
|
virg = OptionGroup(opts, "Virtualization Type Options")
|
|
|
|
virg.add_option("-v", "--hvm", action="store_true", dest="fullvirt",
|
|
|
|
help=_("This guest should be a fully virtualized guest"))
|
|
|
|
virg.add_option("-p", "--paravirt", action="store_true", dest="paravirt",
|
|
|
|
help=_("This guest should be a paravirtualized guest"))
|
|
|
|
opts.add_option_group(virg)
|
|
|
|
|
|
|
|
cfgg = OptionGroup(opts, "Guest Configuration Options")
|
|
|
|
cfgg.add_option("-a", "--arch", dest="arch",
|
2013-04-11 23:11:21 +08:00
|
|
|
default=get_default_arch(),
|
2013-03-18 05:06:52 +08:00
|
|
|
help=_("Machine Architecture Type (i686/x86_64/ppc)"))
|
2013-08-11 06:17:37 +08:00
|
|
|
cli.add_distro_options(cfgg)
|
2013-09-28 21:36:11 +08:00
|
|
|
cli.add_old_feature_options(cfgg)
|
2013-03-18 05:06:52 +08:00
|
|
|
opts.add_option_group(cfgg)
|
|
|
|
|
|
|
|
misc = OptionGroup(opts, "Miscellaneous Options")
|
2013-09-28 23:27:26 +08:00
|
|
|
cli.add_misc_options(misc, dryrun=True)
|
2013-03-18 05:06:52 +08:00
|
|
|
opts.add_option_group(misc)
|
|
|
|
|
|
|
|
|
|
|
|
(options, args) = opts.parse_args()
|
|
|
|
|
|
|
|
cli.setupLogging("virt-convert", options.debug, options.quiet)
|
|
|
|
|
|
|
|
if len(args) < 1:
|
|
|
|
opts.error(_("You need to provide an input VM definition"))
|
|
|
|
if len(args) > 2:
|
|
|
|
opts.error(_("Too many arguments provided"))
|
|
|
|
|
|
|
|
if (options.disk_format and
|
|
|
|
options.disk_format not in diskcfg.disk_formats()):
|
|
|
|
opts.error(_("Unknown output disk format \"%s\"") % options.disk_format)
|
|
|
|
|
|
|
|
if len(args) == 1:
|
|
|
|
options.output_file = None
|
|
|
|
options.output_dir = None
|
|
|
|
if os.path.isdir(args[0]):
|
|
|
|
options.output_dir = args[0]
|
|
|
|
elif os.path.isdir(args[1]) or args[1].endswith("/"):
|
|
|
|
options.output_file = None
|
|
|
|
options.output_dir = args[1]
|
|
|
|
else:
|
|
|
|
options.output_file = args[1]
|
|
|
|
options.output_dir = os.path.dirname(os.path.realpath(args[1]))
|
|
|
|
|
|
|
|
if options.output_format not in formats.formats():
|
|
|
|
opts.error(_("Unknown output format \"%s\")" % options.output_format))
|
|
|
|
if options.output_format not in formats.output_formats():
|
|
|
|
opts.error(_("No output handler for format \"%s\")"
|
|
|
|
% options.output_format))
|
|
|
|
|
|
|
|
if not os.access(args[0], os.R_OK):
|
|
|
|
opts.error(_("Couldn't access input argument \"%s\"\n") % args[0])
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
if not options.input_format:
|
|
|
|
try:
|
|
|
|
(args[0], options.input_format) = formats.find_input(args[0])
|
|
|
|
except StandardError, e:
|
|
|
|
opts.error(_("Couldn't determine input format for \"%s\": %s") %
|
|
|
|
(args[0], e))
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
if options.input_format not in formats.formats():
|
|
|
|
opts.error(_("Unknown input format \"%s\")" % options.input_format))
|
|
|
|
if options.input_format not in formats.input_formats():
|
|
|
|
opts.error(_("No input handler for format \"%s\"")
|
|
|
|
% options.input_format)
|
|
|
|
|
|
|
|
if os.path.isdir(args[0]):
|
|
|
|
(options.input_file, ignore) = formats.find_input(args[0],
|
|
|
|
options.input_format)
|
|
|
|
options.input_dir = args[0]
|
|
|
|
else:
|
|
|
|
options.input_file = args[0]
|
|
|
|
options.input_dir = os.path.dirname(os.path.realpath(args[0]))
|
|
|
|
|
|
|
|
return options
|
|
|
|
|
2013-04-14 02:34:52 +08:00
|
|
|
|
2013-03-18 05:06:52 +08:00
|
|
|
def cleanup(msg, options, vmdef, paths):
|
|
|
|
"""
|
|
|
|
After failure, clean up anything we created.
|
|
|
|
"""
|
|
|
|
logging.error(msg)
|
2013-09-28 23:27:26 +08:00
|
|
|
if options.dry:
|
2013-03-18 05:06:52 +08:00
|
|
|
return
|
|
|
|
|
|
|
|
try:
|
|
|
|
for disk in vmdef.disks.values():
|
|
|
|
disk.cleanup()
|
|
|
|
|
|
|
|
paths.reverse()
|
|
|
|
for path in paths:
|
|
|
|
if os.path.isdir(path):
|
|
|
|
os.rmdir(path)
|
|
|
|
elif os.path.isfile(path):
|
|
|
|
os.remove(path)
|
|
|
|
except OSError, e:
|
|
|
|
fail(_("Couldn't clean up output directory \"%s\": %s") %
|
|
|
|
(options.output_dir, e.strerror))
|
|
|
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
2013-04-14 02:34:52 +08:00
|
|
|
|
2013-03-18 05:06:52 +08:00
|
|
|
def main():
|
|
|
|
cli.earlyLogging()
|
|
|
|
options = parse_args()
|
|
|
|
|
|
|
|
inp = formats.parser_by_name(options.input_format)
|
|
|
|
outp = formats.parser_by_name(options.output_format)
|
|
|
|
|
|
|
|
vmdef = None
|
|
|
|
|
|
|
|
try:
|
|
|
|
vmdef = inp.import_file(options.input_file)
|
|
|
|
except IOError, e:
|
|
|
|
fail(_("Couldn't import file \"%s\": %s") %
|
|
|
|
(options.input_file, e.strerror))
|
|
|
|
except Exception, e:
|
|
|
|
fail(_("Couldn't import file \"%s\": %s") % (options.input_file, e))
|
|
|
|
|
|
|
|
if options.paravirt:
|
|
|
|
vmdef.type = vmcfg.VM_TYPE_PV
|
|
|
|
else:
|
|
|
|
vmdef.type = vmcfg.VM_TYPE_HVM
|
|
|
|
|
|
|
|
vmdef.arch = options.arch
|
2013-08-11 06:17:37 +08:00
|
|
|
cli.set_os_variant(vmdef, options.distro_type, options.distro_variant)
|
2013-03-18 05:06:52 +08:00
|
|
|
vmdef.noapic = options.noapic
|
|
|
|
vmdef.noacpi = options.noacpi
|
|
|
|
|
|
|
|
clean = []
|
|
|
|
|
|
|
|
unixname = vmdef.name.replace(" ", "-")
|
|
|
|
|
|
|
|
if not options.output_dir:
|
|
|
|
options.output_dir = unixname
|
|
|
|
try:
|
|
|
|
logging.debug("Creating directory %s", options.output_dir)
|
2013-09-28 23:27:26 +08:00
|
|
|
if not options.dry:
|
2013-03-18 05:06:52 +08:00
|
|
|
os.mkdir(options.output_dir)
|
2013-04-14 02:34:52 +08:00
|
|
|
clean += [options.output_dir]
|
2013-03-18 05:06:52 +08:00
|
|
|
except OSError, e:
|
|
|
|
if (e.errno != errno.EEXIST):
|
|
|
|
fail("Could not create directory %s: %s" %
|
|
|
|
(options.output_dir, e.strerror))
|
|
|
|
|
|
|
|
if not options.output_file:
|
|
|
|
options.output_file = os.path.join(options.output_dir,
|
|
|
|
"%s%s" % (unixname, outp.suffix))
|
|
|
|
|
|
|
|
logging.debug("input_file: %s", options.input_file)
|
|
|
|
logging.debug("input_dir: %s", options.input_dir)
|
|
|
|
logging.debug("output_file: %s", options.output_file)
|
|
|
|
logging.debug("output_dir: %s", options.output_dir)
|
|
|
|
|
|
|
|
print_stdout(_("Generating output in '%(format)s' format to %(dir)s/") %
|
|
|
|
{"format": options.output_format, "dir": options.output_dir})
|
|
|
|
|
|
|
|
try:
|
|
|
|
for d in vmdef.disks.values():
|
|
|
|
dformat = options.disk_format
|
|
|
|
|
|
|
|
if not dformat:
|
2013-07-03 23:53:17 +08:00
|
|
|
if options.output_format == "vmx":
|
2013-03-18 05:06:52 +08:00
|
|
|
dformat = "vmdk"
|
|
|
|
else:
|
|
|
|
dformat = "raw"
|
|
|
|
|
|
|
|
if d.path and dformat != "none":
|
|
|
|
print_stdout(_("Converting disk '%(path)s' to type "
|
|
|
|
"%(format)s...") % {"path": d.path,
|
|
|
|
"format": dformat})
|
|
|
|
|
2013-09-28 23:27:26 +08:00
|
|
|
if not options.dry:
|
2013-03-18 05:06:52 +08:00
|
|
|
d.convert(options.input_dir, options.output_dir, dformat)
|
|
|
|
|
|
|
|
except OSError, e:
|
|
|
|
cleanup(_("Couldn't convert disks: %s") % e.strerror,
|
|
|
|
options, vmdef, clean)
|
|
|
|
except RuntimeError, e:
|
|
|
|
cleanup(_("Couldn't convert disks: %s") % e, options, vmdef, clean)
|
|
|
|
|
|
|
|
try:
|
|
|
|
output = outp.export(vmdef)
|
|
|
|
logging.debug("Output VM config:\n%s", output)
|
|
|
|
|
2013-09-28 23:27:26 +08:00
|
|
|
if not options.dry:
|
2013-03-18 05:06:52 +08:00
|
|
|
outfile = open(options.output_file, "w")
|
|
|
|
outfile.writelines(output)
|
|
|
|
outfile.close()
|
|
|
|
|
2013-04-14 02:34:52 +08:00
|
|
|
clean += [options.output_file]
|
2013-03-18 05:06:52 +08:00
|
|
|
except ValueError, e:
|
|
|
|
cleanup(_("Couldn't export to file \"%s\": %s") %
|
|
|
|
(options.output_file, e), options, vmdef, clean)
|
|
|
|
|
|
|
|
print_stdout("Done.")
|
|
|
|
return 0
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
try:
|
|
|
|
sys.exit(main())
|
|
|
|
except SystemExit, sys_e:
|
|
|
|
sys.exit(sys_e.code)
|
|
|
|
except KeyboardInterrupt:
|
|
|
|
print_stderr(_("Aborted at user request"))
|
|
|
|
except Exception, main_e:
|
|
|
|
fail(main_e)
|