#!/usr/bin/python # # Copyright (C) 2011 Google Inc. # # 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. """Tool to translate between ovf and ganeti backup format. """ import logging import optparse import os from ganeti import cli from ganeti import constants from ganeti import errors from ganeti import ovf from ganeti import utils IMPORT_MODE = "import" EXPORT_MODE = "export" def CheckOptions(parser, options_dict, required, forbidden, excluding, mode): """Performes check on the command line options. Checks whether the required arguments are present and if none of the arguments not supported for the current mode are given. @type options_dict: list @param options_dict: dictionary containing all the options from the command line @type required: list @param required: list of pairs (option, argument) where 'option' is required in mode 'mode' @type forbidden: list @param forbidden: list of pairs (option, argument) which are not allowed in mode 'mode' @type excluding: list @param excluding: list of pairs (argument1, argument2); each pair contains mutually exclusive arguments @type mode: string @param mode: current mode of the converter """ for (option, argument) in required: if not options_dict[option]: parser.error("Argument %s is required for %s" % (argument, mode)) for (option, argument) in forbidden: if options_dict[option]: parser.error("Argument %s is not allowed in %s mode" % (argument, mode)) for (arg1, arg2) in excluding: if options_dict[arg1] and options_dict[arg2]: parser.error("Arguments %s and %s exclude each other" % (arg1, arg2)) def ParseOptions(): """Parses the command line options and arguments. In case of mismatching parameters, it will show the correct usage and exit. @rtype: tuple @return: (mode, sourcefile to read from, additional options) """ usage = ("%%prog {%s|%s} [options...]" % (IMPORT_MODE, EXPORT_MODE)) parser = optparse.OptionParser(usage=usage) #global options parser.add_option(cli.DEBUG_OPT) parser.add_option(cli.VERBOSE_OPT) parser.add_option("-n", "--name", dest="name", action="store", help="Name of the instance") parser.add_option("--output-dir", dest="output_dir", help="Path to the output directory") #import options import_group = optparse.OptionGroup(parser, "Import options") import_group.add_option(cli.BACKEND_OPT) import_group.add_option(cli.DISK_OPT) import_group.add_option(cli.DISK_TEMPLATE_OPT) import_group.add_option(cli.HYPERVISOR_OPT) import_group.add_option(cli.NET_OPT) import_group.add_option(cli.NONICS_OPT) import_group.add_option(cli.OS_OPT) import_group.add_option(cli.OSPARAMS_OPT) import_group.add_option(cli.TAG_ADD_OPT) parser.add_option_group(import_group) #export options export_group = optparse.OptionGroup(parser, "Export options") export_group.add_option("--compress", dest="compression", action="store_true", default=False, help="The exported disk will be compressed to tar.gz") export_group.add_option("--external", dest="ext_usage", action="store_true", default=False, help="The package will be used externally (ommits the" " Ganeti-specific parts of configuration)") export_group.add_option("-f", "--format", dest="disk_format", action="store", choices=("raw", "cow", "vmdk"), help="Disk format for export (one of raw/cow/vmdk)") export_group.add_option("--ova", dest="ova_package", action="store_true", default=False, help="Export everything into OVA package") parser.add_option_group(export_group) options, args = parser.parse_args() if len(args) != 2: parser.error("Wrong number of arguments") mode = args.pop(0) input_path = os.path.abspath(args.pop(0)) if mode == IMPORT_MODE: required = [] forbidden = [ ("compression", "--compress"), ("disk_format", "--format"), ("ext_usage", "--external"), ("ova_package", "--ova"), ] excluding = [("nics", "no_nics")] elif mode == EXPORT_MODE: required = [("disk_format", "--format")] forbidden = [ ("beparams", "--backend-parameters"), ("disk_template", "--disk-template"), ("disks", "--disk"), ("hypervisor", "--hypervisor-parameters"), ("nics", "--net"), ("no_nics", "--no-nics"), ("os", "--os-type"), ("osparams", "--os-parameters"), ("tags", "--tags"), ] excluding = [] else: parser.error("First argument should be either '%s' or '%s'" % (IMPORT_MODE, EXPORT_MODE)) options_dict = vars(options) CheckOptions(parser, options_dict, required, forbidden, excluding, mode) return (mode, input_path, options) def main(): """Main routine. """ (mode, input_path, options) = ParseOptions() utils.SetupToolLogging(options.debug, options.verbose) logging.info("Chosen %s mode, reading the %s file", mode, input_path) assert mode in (IMPORT_MODE, EXPORT_MODE) converter = None try: if mode == IMPORT_MODE: converter = ovf.OVFImporter(input_path, options) elif mode == EXPORT_MODE: converter = ovf.OVFExporter(input_path, options) converter.Parse() converter.Save() except errors.OpPrereqError, err: if converter: converter.Cleanup() logging.exception(err) return constants.EXIT_FAILURE if __name__ == "__main__": main()