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