root / tools / ovfconverter @ 36c70d4d
History | View | Annotate | Download (6.7 kB)
1 | ced78a66 | Agata Murawska | #!/usr/bin/python |
---|---|---|---|
2 | ced78a66 | Agata Murawska | # |
3 | ced78a66 | Agata Murawska | |
4 | ced78a66 | Agata Murawska | # Copyright (C) 2011 Google Inc. |
5 | ced78a66 | Agata Murawska | # |
6 | ced78a66 | Agata Murawska | # This program is free software; you can redistribute it and/or modify |
7 | ced78a66 | Agata Murawska | # it under the terms of the GNU General Public License as published by |
8 | ced78a66 | Agata Murawska | # the Free Software Foundation; either version 2 of the License, or |
9 | ced78a66 | Agata Murawska | # (at your option) any later version. |
10 | ced78a66 | Agata Murawska | # |
11 | ced78a66 | Agata Murawska | # This program is distributed in the hope that it will be useful, but |
12 | ced78a66 | Agata Murawska | # WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | ced78a66 | Agata Murawska | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | ced78a66 | Agata Murawska | # General Public License for more details. |
15 | ced78a66 | Agata Murawska | # |
16 | ced78a66 | Agata Murawska | # You should have received a copy of the GNU General Public License |
17 | ced78a66 | Agata Murawska | # along with this program; if not, write to the Free Software |
18 | ced78a66 | Agata Murawska | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
19 | ced78a66 | Agata Murawska | # 02110-1301, USA. |
20 | ced78a66 | Agata Murawska | |
21 | ced78a66 | Agata Murawska | |
22 | ced78a66 | Agata Murawska | """Tool to translate between ovf and ganeti backup format. |
23 | ced78a66 | Agata Murawska | |
24 | ced78a66 | Agata Murawska | """ |
25 | ced78a66 | Agata Murawska | |
26 | ced78a66 | Agata Murawska | import logging |
27 | ced78a66 | Agata Murawska | import optparse |
28 | ced78a66 | Agata Murawska | import os |
29 | ced78a66 | Agata Murawska | |
30 | ced78a66 | Agata Murawska | from ganeti import cli |
31 | ced78a66 | Agata Murawska | from ganeti import constants |
32 | ced78a66 | Agata Murawska | from ganeti import errors |
33 | ced78a66 | Agata Murawska | from ganeti import ovf |
34 | ced78a66 | Agata Murawska | |
35 | ced78a66 | Agata Murawska | |
36 | ced78a66 | Agata Murawska | IMPORT_MODE = "import" |
37 | ced78a66 | Agata Murawska | EXPORT_MODE = "export" |
38 | ced78a66 | Agata Murawska | |
39 | ced78a66 | Agata Murawska | |
40 | ced78a66 | Agata Murawska | def CheckOptions(parser, options_dict, required, forbidden, excluding, mode): |
41 | ced78a66 | Agata Murawska | """Performes check on the command line options. |
42 | ced78a66 | Agata Murawska | |
43 | ced78a66 | Agata Murawska | Checks whether the required arguments are present and if none of the arguments |
44 | ced78a66 | Agata Murawska | not supported for the current mode are given. |
45 | ced78a66 | Agata Murawska | |
46 | ced78a66 | Agata Murawska | @type options_dict: list |
47 | ced78a66 | Agata Murawska | @param options_dict: dictionary containing all the options from the command |
48 | ced78a66 | Agata Murawska | line |
49 | ced78a66 | Agata Murawska | @type required: list |
50 | ced78a66 | Agata Murawska | @param required: list of pairs (option, argument) where 'option' is required |
51 | ced78a66 | Agata Murawska | in mode 'mode' |
52 | ced78a66 | Agata Murawska | @type forbidden: list |
53 | ced78a66 | Agata Murawska | @param forbidden: list of pairs (option, argument) which are not allowed in |
54 | ced78a66 | Agata Murawska | mode 'mode' |
55 | ced78a66 | Agata Murawska | @type excluding: list |
56 | ced78a66 | Agata Murawska | @param excluding: list of pairs (argument1, argument2); each pair contains |
57 | ced78a66 | Agata Murawska | mutually exclusive arguments |
58 | ced78a66 | Agata Murawska | @type mode: string |
59 | ced78a66 | Agata Murawska | @param mode: current mode of the converter |
60 | ced78a66 | Agata Murawska | |
61 | ced78a66 | Agata Murawska | """ |
62 | ced78a66 | Agata Murawska | for (option, argument) in required: |
63 | ced78a66 | Agata Murawska | if not options_dict[option]: |
64 | ced78a66 | Agata Murawska | parser.error("Argument %s is required for %s" % (argument, mode)) |
65 | ced78a66 | Agata Murawska | for (option, argument) in forbidden: |
66 | ced78a66 | Agata Murawska | if options_dict[option]: |
67 | ced78a66 | Agata Murawska | parser.error("Argument %s is not allowed in %s mode" % (argument, mode)) |
68 | ced78a66 | Agata Murawska | for (arg1, arg2) in excluding: |
69 | ced78a66 | Agata Murawska | if options_dict[arg1] and options_dict[arg2]: |
70 | ced78a66 | Agata Murawska | parser.error("Arguments %s and %s exclude each other" % (arg1, arg2)) |
71 | ced78a66 | Agata Murawska | |
72 | ced78a66 | Agata Murawska | |
73 | ced78a66 | Agata Murawska | def ParseOptions(): |
74 | ced78a66 | Agata Murawska | """Parses the command line options and arguments. |
75 | ced78a66 | Agata Murawska | |
76 | ced78a66 | Agata Murawska | In case of mismatching parameters, it will show the correct usage and exit. |
77 | ced78a66 | Agata Murawska | |
78 | ced78a66 | Agata Murawska | @rtype: tuple |
79 | ced78a66 | Agata Murawska | @return: (mode, sourcefile to read from, additional options) |
80 | ced78a66 | Agata Murawska | |
81 | ced78a66 | Agata Murawska | """ |
82 | ced78a66 | Agata Murawska | usage = ("%%prog {%s|%s} <source-cfg-file> [options...]" % |
83 | ced78a66 | Agata Murawska | (IMPORT_MODE, EXPORT_MODE)) |
84 | ced78a66 | Agata Murawska | parser = optparse.OptionParser(usage=usage) |
85 | ced78a66 | Agata Murawska | |
86 | ced78a66 | Agata Murawska | #global options |
87 | ced78a66 | Agata Murawska | parser.add_option(cli.DEBUG_OPT) |
88 | ced78a66 | Agata Murawska | parser.add_option(cli.VERBOSE_OPT) |
89 | ced78a66 | Agata Murawska | parser.add_option("-n", "--name", dest="name", action="store", |
90 | ced78a66 | Agata Murawska | help="Name of the instance") |
91 | ced78a66 | Agata Murawska | parser.add_option("--output-dir", dest="output_dir", |
92 | ced78a66 | Agata Murawska | help="Path to the output directory") |
93 | ced78a66 | Agata Murawska | |
94 | ced78a66 | Agata Murawska | #import options |
95 | ced78a66 | Agata Murawska | import_group = optparse.OptionGroup(parser, "Import options") |
96 | ced78a66 | Agata Murawska | import_group.add_option(cli.BACKEND_OPT) |
97 | ced78a66 | Agata Murawska | import_group.add_option(cli.DISK_OPT) |
98 | ced78a66 | Agata Murawska | import_group.add_option(cli.DISK_TEMPLATE_OPT) |
99 | ced78a66 | Agata Murawska | import_group.add_option(cli.HYPERVISOR_OPT) |
100 | ced78a66 | Agata Murawska | import_group.add_option(cli.NET_OPT) |
101 | ced78a66 | Agata Murawska | import_group.add_option(cli.NONICS_OPT) |
102 | ced78a66 | Agata Murawska | import_group.add_option(cli.OS_OPT) |
103 | ced78a66 | Agata Murawska | import_group.add_option(cli.OSPARAMS_OPT) |
104 | ced78a66 | Agata Murawska | import_group.add_option(cli.TAG_ADD_OPT) |
105 | ced78a66 | Agata Murawska | parser.add_option_group(import_group) |
106 | ced78a66 | Agata Murawska | |
107 | ced78a66 | Agata Murawska | #export options |
108 | ced78a66 | Agata Murawska | export_group = optparse.OptionGroup(parser, "Export options") |
109 | ced78a66 | Agata Murawska | export_group.add_option("--compress", dest="compression", |
110 | ced78a66 | Agata Murawska | action="store_true", default=False, |
111 | ced78a66 | Agata Murawska | help="The exported disk will be compressed to tar.gz") |
112 | ced78a66 | Agata Murawska | export_group.add_option("--external", dest="ext_usage", |
113 | ced78a66 | Agata Murawska | action="store_true", default=False, |
114 | ced78a66 | Agata Murawska | help="The package will be used externally (ommits the" |
115 | ced78a66 | Agata Murawska | " Ganeti-specific parts of configuration)") |
116 | ced78a66 | Agata Murawska | export_group.add_option("-f", "--format", dest="disk_format", |
117 | ced78a66 | Agata Murawska | action="store", |
118 | ced78a66 | Agata Murawska | choices=("raw", "cow", "vmdk"), |
119 | ced78a66 | Agata Murawska | help="Disk format for export (one of raw/cow/vmdk)") |
120 | ced78a66 | Agata Murawska | export_group.add_option("--ova", dest="ova_package", |
121 | ced78a66 | Agata Murawska | action="store_true", default=False, |
122 | ced78a66 | Agata Murawska | help="Export everything into OVA package") |
123 | ced78a66 | Agata Murawska | parser.add_option_group(export_group) |
124 | ced78a66 | Agata Murawska | |
125 | ced78a66 | Agata Murawska | options, args = parser.parse_args() |
126 | ced78a66 | Agata Murawska | if len(args) != 2: |
127 | ced78a66 | Agata Murawska | parser.error("Wrong number of arguments") |
128 | ced78a66 | Agata Murawska | mode = args.pop(0) |
129 | ced78a66 | Agata Murawska | input_path = os.path.abspath(args.pop(0)) |
130 | ced78a66 | Agata Murawska | |
131 | ced78a66 | Agata Murawska | if mode == IMPORT_MODE: |
132 | ced78a66 | Agata Murawska | required = [] |
133 | ced78a66 | Agata Murawska | forbidden = [ |
134 | ced78a66 | Agata Murawska | ("compression", "--compress"), |
135 | ced78a66 | Agata Murawska | ("disk_format", "--format"), |
136 | ced78a66 | Agata Murawska | ("ext_usage", "--external"), |
137 | ced78a66 | Agata Murawska | ("ova_package", "--ova"), |
138 | ced78a66 | Agata Murawska | ] |
139 | ced78a66 | Agata Murawska | excluding = [("nics", "no_nics")] |
140 | ced78a66 | Agata Murawska | elif mode == EXPORT_MODE: |
141 | ced78a66 | Agata Murawska | required = [("disk_format", "--format")] |
142 | ced78a66 | Agata Murawska | forbidden = [ |
143 | ced78a66 | Agata Murawska | ("beparams", "--backend-parameters"), |
144 | ced78a66 | Agata Murawska | ("disk_template", "--disk-template"), |
145 | ced78a66 | Agata Murawska | ("disks", "--disk"), |
146 | ced78a66 | Agata Murawska | ("hypervisor", "--hypervisor-parameters"), |
147 | ced78a66 | Agata Murawska | ("nics", "--net"), |
148 | ced78a66 | Agata Murawska | ("no_nics", "--no-nics"), |
149 | ced78a66 | Agata Murawska | ("os", "--os-type"), |
150 | ced78a66 | Agata Murawska | ("osparams", "--os-parameters"), |
151 | ced78a66 | Agata Murawska | ("tags", "--tags"), |
152 | ced78a66 | Agata Murawska | ] |
153 | ced78a66 | Agata Murawska | excluding = [] |
154 | ced78a66 | Agata Murawska | else: |
155 | ced78a66 | Agata Murawska | parser.error("First argument should be either '%s' or '%s'" % |
156 | ced78a66 | Agata Murawska | (IMPORT_MODE, EXPORT_MODE)) |
157 | ced78a66 | Agata Murawska | |
158 | ced78a66 | Agata Murawska | options_dict = vars(options) |
159 | ced78a66 | Agata Murawska | CheckOptions(parser, options_dict, required, forbidden, excluding, mode) |
160 | ced78a66 | Agata Murawska | |
161 | ced78a66 | Agata Murawska | return (mode, input_path, options) |
162 | ced78a66 | Agata Murawska | |
163 | ced78a66 | Agata Murawska | |
164 | ced78a66 | Agata Murawska | def SetupLogging(options): |
165 | ced78a66 | Agata Murawska | """Setting up logging infrastructure. |
166 | ced78a66 | Agata Murawska | |
167 | ced78a66 | Agata Murawska | @type options: optparse.Values |
168 | ced78a66 | Agata Murawska | @param options: parsed command line options |
169 | ced78a66 | Agata Murawska | |
170 | ced78a66 | Agata Murawska | """ |
171 | ced78a66 | Agata Murawska | formatter = logging.Formatter("%(asctime)s: %(levelname)s %(message)s") |
172 | ced78a66 | Agata Murawska | |
173 | ced78a66 | Agata Murawska | stderr_handler = logging.StreamHandler() |
174 | ced78a66 | Agata Murawska | stderr_handler.setFormatter(formatter) |
175 | ced78a66 | Agata Murawska | if options.debug: |
176 | ced78a66 | Agata Murawska | stderr_handler.setLevel(logging.NOTSET) |
177 | ced78a66 | Agata Murawska | elif options.verbose: |
178 | ced78a66 | Agata Murawska | stderr_handler.setLevel(logging.INFO) |
179 | ced78a66 | Agata Murawska | else: |
180 | ced78a66 | Agata Murawska | stderr_handler.setLevel(logging.WARNING) |
181 | ced78a66 | Agata Murawska | |
182 | ced78a66 | Agata Murawska | root_logger = logging.getLogger("") |
183 | ced78a66 | Agata Murawska | root_logger.setLevel(logging.NOTSET) |
184 | ced78a66 | Agata Murawska | root_logger.addHandler(stderr_handler) |
185 | ced78a66 | Agata Murawska | |
186 | ced78a66 | Agata Murawska | |
187 | ced78a66 | Agata Murawska | def main(): |
188 | ced78a66 | Agata Murawska | """Main routine. |
189 | ced78a66 | Agata Murawska | |
190 | ced78a66 | Agata Murawska | """ |
191 | ced78a66 | Agata Murawska | (mode, input_path, options) = ParseOptions() |
192 | ced78a66 | Agata Murawska | SetupLogging(options) |
193 | ced78a66 | Agata Murawska | logging.info("Chosen %s mode, reading the %s file", mode, input_path) |
194 | ced78a66 | Agata Murawska | assert mode in (IMPORT_MODE, EXPORT_MODE) |
195 | ced78a66 | Agata Murawska | converter = None |
196 | ced78a66 | Agata Murawska | try: |
197 | ced78a66 | Agata Murawska | if mode == IMPORT_MODE: |
198 | ced78a66 | Agata Murawska | converter = ovf.OVFImporter(input_path, options) |
199 | ced78a66 | Agata Murawska | elif mode == EXPORT_MODE: |
200 | ced78a66 | Agata Murawska | converter = ovf.OVFExporter(input_path, options) |
201 | ced78a66 | Agata Murawska | converter.Parse() |
202 | ced78a66 | Agata Murawska | converter.Save() |
203 | ced78a66 | Agata Murawska | except errors.OpPrereqError, err: |
204 | ced78a66 | Agata Murawska | if converter: |
205 | ced78a66 | Agata Murawska | converter.Cleanup() |
206 | ced78a66 | Agata Murawska | logging.exception(err) |
207 | ced78a66 | Agata Murawska | return constants.EXIT_FAILURE |
208 | ced78a66 | Agata Murawska | |
209 | ced78a66 | Agata Murawska | |
210 | ced78a66 | Agata Murawska | if __name__ == "__main__": |
211 | ced78a66 | Agata Murawska | main() |