2013-03-18 01:06:52 +04: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.
2014-01-19 02:01:43 +04:00
import argparse
2013-03-18 01:06:52 +04:00
import errno
2014-01-19 02:01:43 +04:00
import logging
import os
import sys
2013-03-18 01:06:52 +04:00
2014-01-19 02:01:43 +04:00
from virtinst import cli
2013-03-18 01:06:52 +04:00
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 19:11:21 +04:00
def get_default_arch():
arch = os.uname()[4]
if arch == "x86_64":
return "x86_64"
return "i686"
2013-03-18 01:06:52 +04:00
def parse_args():
"""Parse and verify command line."""
2014-01-19 02:01:43 +04:00
parser = cli.setupParser(
"%(prog)s inputdir|input.vmx [outputdir|output.xml] [options]",
2013-06-30 23:03:53 +04:00
_("Convert from virtual machine descriptor format to another. The "
"VM contents are not altered."))
2013-03-18 01:06:52 +04:00
2014-01-19 02:01:43 +04:00
parser.add_argument("input", metavar="inputconfig", nargs=1,
help=_("Conversion input: flat file or directory."))
def add_output_arg(p):
p.add_argument("output", metavar="outputconfig", nargs='?',
help=_("Conversion destination"))
add_output_arg(parser)
cong = parser.add_argument_group("Conversion Options")
2014-01-21 03:04:23 +04:00
cong.add_argument("-i", "--input-format",
2013-03-18 01:06:52 +04:00
help=_("Input format, e.g. 'vmx'"))
2014-01-21 03:04:23 +04:00
cong.add_argument("-o", "--output-format",
2013-03-18 01:06:52 +04:00
default="virt-image",
help=_("Output format, e.g. 'virt-image'"))
2014-01-21 03:04:23 +04:00
cong.add_argument("-D", "--disk-format",
2013-03-18 01:06:52 +04:00
help=_("Output disk format"))
2014-01-19 02:01:43 +04:00
virg = parser.add_argument_group("Virtualization Type Options")
virg.add_argument("-v", "--hvm", action="store_true", dest="fullvirt",
2013-03-18 01:06:52 +04:00
help=_("This guest should be a fully virtualized guest"))
2014-01-19 02:01:43 +04:00
virg.add_argument("-p", "--paravirt", action="store_true", dest="paravirt",
2013-03-18 01:06:52 +04:00
help=_("This guest should be a paravirtualized guest"))
2014-01-19 02:01:43 +04:00
cfgg = parser.add_argument_group("Guest Configuration Options")
2014-01-21 03:04:23 +04:00
cfgg.add_argument("-a", "--arch",
2013-04-11 19:11:21 +04:00
default=get_default_arch(),
2013-03-18 01:06:52 +04:00
help=_("Machine Architecture Type (i686/x86_64/ppc)"))
2013-08-11 02:17:37 +04:00
cli.add_distro_options(cfgg)
2013-09-28 17:36:11 +04:00
cli.add_old_feature_options(cfgg)
2013-03-18 01:06:52 +04:00
2014-01-19 02:01:43 +04:00
misc = parser.add_argument_group("Miscellaneous Options")
2013-09-28 19:27:26 +04:00
cli.add_misc_options(misc, dryrun=True)
2013-03-18 01:06:52 +04:00
2014-01-19 02:01:43 +04:00
options, leftovers = parser.parse_known_args()
if options.input:
options.input = options.input[0]
# argparse does not allow interspersed positional arguments, which we
# used to allow with optparse. All this crazyness is to keep old
# cli working
parser2 = argparse.ArgumentParser()
add_output_arg(parser2)
if not options.output:
opt2, leftovers = parser2.parse_known_args(leftovers)
options.output = opt2.output
if leftovers:
leftovers = sys.argv[:]
if options.output in leftovers:
leftovers.pop(leftovers.index(options.output))
if options.input in leftovers:
leftovers.pop(leftovers.index(options.input))
parser.parse_args(leftovers)
2013-03-18 01:06:52 +04:00
cli.setupLogging("virt-convert", options.debug, options.quiet)
if (options.disk_format and
options.disk_format not in diskcfg.disk_formats()):
2014-01-19 02:01:43 +04:00
parser.error(_("Unknown output disk format \"%s\"") %
options.disk_format)
2013-03-18 01:06:52 +04:00
2014-01-19 02:01:43 +04:00
if not options.output:
2013-03-18 01:06:52 +04:00
options.output_file = None
options.output_dir = None
2014-01-19 02:01:43 +04:00
if os.path.isdir(options.input):
options.output_dir = options.input
elif os.path.isdir(options.output) or options.output.endswith("/"):
2013-03-18 01:06:52 +04:00
options.output_file = None
2014-01-19 02:01:43 +04:00
options.output_dir = options.output
2013-03-18 01:06:52 +04:00
else:
2014-01-19 02:01:43 +04:00
options.output_file = options.output
options.output_dir = os.path.dirname(os.path.realpath(options.output))
2013-03-18 01:06:52 +04:00
if options.output_format not in formats.formats():
2014-01-19 02:01:43 +04:00
parser.error(_("Unknown output format \"%s\")" %
options.output_format))
2013-03-18 01:06:52 +04:00
if options.output_format not in formats.output_formats():
2014-01-19 02:01:43 +04:00
parser.error(_("No output handler for format \"%s\")"
2013-03-18 01:06:52 +04:00
% options.output_format))
2014-01-19 02:01:43 +04:00
if not os.access(options.input, os.R_OK):
parser.error(_("Couldn't access input argument \"%s\"\n") % options.input)
2013-03-18 01:06:52 +04:00
sys.exit(1)
if not options.input_format:
try:
2014-01-19 02:01:43 +04:00
(options.input, options.input_format) = formats.find_input(options.input)
2013-03-18 01:06:52 +04:00
except StandardError, e:
2014-01-19 02:01:43 +04:00
parser.error(_("Couldn't determine input format for \"%s\": %s") %
(options.input, e))
2013-03-18 01:06:52 +04:00
sys.exit(1)
if options.input_format not in formats.formats():
2014-01-19 02:01:43 +04:00
parser.error(_("Unknown input format \"%s\")" % options.input_format))
2013-03-18 01:06:52 +04:00
if options.input_format not in formats.input_formats():
2014-01-19 02:01:43 +04:00
parser.error(_("No input handler for format \"%s\"")
2013-03-18 01:06:52 +04:00
% options.input_format)
2014-01-19 02:01:43 +04:00
if os.path.isdir(options.input):
(options.input_file, ignore) = formats.find_input(options.input,
2013-03-18 01:06:52 +04:00
options.input_format)
2014-01-19 02:01:43 +04:00
options.input_dir = options.input
2013-03-18 01:06:52 +04:00
else:
2014-01-19 02:01:43 +04:00
options.input_file = options.input
options.input_dir = os.path.dirname(os.path.realpath(options.input))
2013-03-18 01:06:52 +04:00
return options
2013-04-13 22:34:52 +04:00
2013-03-18 01:06:52 +04:00
def cleanup(msg, options, vmdef, paths):
"""
After failure, clean up anything we created.
"""
logging.error(msg)
2013-09-28 19:27:26 +04:00
if options.dry:
2013-03-18 01:06:52 +04: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-13 22:34:52 +04:00
2013-03-18 01:06:52 +04: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 02:17:37 +04:00
cli.set_os_variant(vmdef, options.distro_type, options.distro_variant)
2013-03-18 01:06:52 +04: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 19:27:26 +04:00
if not options.dry:
2013-03-18 01:06:52 +04:00
os.mkdir(options.output_dir)
2013-04-13 22:34:52 +04:00
clean += [options.output_dir]
2013-03-18 01:06:52 +04: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 19:53:17 +04:00
if options.output_format == "vmx":
2013-03-18 01:06:52 +04: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 19:27:26 +04:00
if not options.dry:
2013-03-18 01:06:52 +04: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 19:27:26 +04:00
if not options.dry:
2013-03-18 01:06:52 +04:00
outfile = open(options.output_file, "w")
outfile.writelines(output)
outfile.close()
2013-04-13 22:34:52 +04:00
clean += [options.output_file]
2013-03-18 01:06:52 +04: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)