Statistics
| Branch: | Tag: | Revision:

root / image_creator / main.py @ ebe0f1e0

History | View | Annotate | Download (16.5 kB)

1 ae48a082 Nikos Skalkotos
#!/usr/bin/env python
2 121f3bc0 Nikos Skalkotos
# -*- coding: utf-8 -*-
3 121f3bc0 Nikos Skalkotos
#
4 574f2712 Nikos Skalkotos
# Copyright 2012 GRNET S.A. All rights reserved.
5 d57775d4 Nikos Skalkotos
#
6 d57775d4 Nikos Skalkotos
# Redistribution and use in source and binary forms, with or
7 d57775d4 Nikos Skalkotos
# without modification, are permitted provided that the following
8 d57775d4 Nikos Skalkotos
# conditions are met:
9 d57775d4 Nikos Skalkotos
#
10 d57775d4 Nikos Skalkotos
#   1. Redistributions of source code must retain the above
11 d57775d4 Nikos Skalkotos
#      copyright notice, this list of conditions and the following
12 d57775d4 Nikos Skalkotos
#      disclaimer.
13 d57775d4 Nikos Skalkotos
#
14 d57775d4 Nikos Skalkotos
#   2. Redistributions in binary form must reproduce the above
15 d57775d4 Nikos Skalkotos
#      copyright notice, this list of conditions and the following
16 d57775d4 Nikos Skalkotos
#      disclaimer in the documentation and/or other materials
17 d57775d4 Nikos Skalkotos
#      provided with the distribution.
18 d57775d4 Nikos Skalkotos
#
19 d57775d4 Nikos Skalkotos
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
20 d57775d4 Nikos Skalkotos
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 d57775d4 Nikos Skalkotos
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 d57775d4 Nikos Skalkotos
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
23 d57775d4 Nikos Skalkotos
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 d57775d4 Nikos Skalkotos
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 d57775d4 Nikos Skalkotos
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 d57775d4 Nikos Skalkotos
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 d57775d4 Nikos Skalkotos
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 d57775d4 Nikos Skalkotos
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29 d57775d4 Nikos Skalkotos
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 d57775d4 Nikos Skalkotos
# POSSIBILITY OF SUCH DAMAGE.
31 d57775d4 Nikos Skalkotos
#
32 d57775d4 Nikos Skalkotos
# The views and conclusions contained in the software and
33 d57775d4 Nikos Skalkotos
# documentation are those of the authors and should not be
34 d57775d4 Nikos Skalkotos
# interpreted as representing official policies, either expressed
35 d57775d4 Nikos Skalkotos
# or implied, of GRNET S.A.
36 d57775d4 Nikos Skalkotos
37 121f3bc0 Nikos Skalkotos
"""This module is the entrance point for the non-interactive version of the
38 121f3bc0 Nikos Skalkotos
snf-image-creator program.
39 121f3bc0 Nikos Skalkotos
"""
40 121f3bc0 Nikos Skalkotos
41 c408053f Nikos Skalkotos
from image_creator import __version__ as version
42 d57775d4 Nikos Skalkotos
from image_creator.disk import Disk
43 3582e34d Nikos Skalkotos
from image_creator.util import FatalError, MD5
44 4e58b51b Nikos Skalkotos
from image_creator.output.cli import SilentOutput, SimpleOutput, \
45 f99fe99d Nikos Skalkotos
    OutputWthProgress
46 3b7d3fc7 Nikos Skalkotos
from image_creator.kamaki_wrapper import Kamaki, ClientError
47 d57775d4 Nikos Skalkotos
import sys
48 d57775d4 Nikos Skalkotos
import os
49 c408053f Nikos Skalkotos
import optparse
50 b1395967 Nikos Skalkotos
import StringIO
51 9c354f13 Nikos Skalkotos
import signal
52 8e58e699 Nikos Skalkotos
import json
53 d0daafa2 Nikos Skalkotos
import textwrap
54 3ccb2618 Nikos Skalkotos
55 c408053f Nikos Skalkotos
56 0ae01e26 Nikos Skalkotos
def check_writable_dir(option, opt_str, value, parser):
57 0ae01e26 Nikos Skalkotos
    dirname = os.path.dirname(value)
58 0ae01e26 Nikos Skalkotos
    name = os.path.basename(value)
59 0ae01e26 Nikos Skalkotos
    if dirname and not os.path.isdir(dirname):
60 b5430a9f Nikos Skalkotos
        raise FatalError("`%s' is not an existing directory" % dirname)
61 c408053f Nikos Skalkotos
62 0ae01e26 Nikos Skalkotos
    if not name:
63 b5430a9f Nikos Skalkotos
        raise FatalError("`%s' is not a valid file name" % dirname)
64 c408053f Nikos Skalkotos
65 c408053f Nikos Skalkotos
    setattr(parser.values, option.dest, value)
66 c408053f Nikos Skalkotos
67 c408053f Nikos Skalkotos
68 c408053f Nikos Skalkotos
def parse_options(input_args):
69 0ae01e26 Nikos Skalkotos
    usage = "Usage: %prog [options] <input_media>"
70 c408053f Nikos Skalkotos
    parser = optparse.OptionParser(version=version, usage=usage)
71 c408053f Nikos Skalkotos
72 0ae01e26 Nikos Skalkotos
    parser.add_option("-o", "--outfile", type="string", dest="outfile",
73 f99fe99d Nikos Skalkotos
                      default=None, action="callback",
74 f99fe99d Nikos Skalkotos
                      callback=check_writable_dir, help="dump image to FILE",
75 f99fe99d Nikos Skalkotos
                      metavar="FILE")
76 979096dd Nikos Skalkotos
77 997ac76a Nikos Skalkotos
    parser.add_option("-f", "--force", dest="force", default=False,
78 f99fe99d Nikos Skalkotos
                      action="store_true",
79 f99fe99d Nikos Skalkotos
                      help="overwrite output files if they exist")
80 76d4a1c9 Nikos Skalkotos
81 979096dd Nikos Skalkotos
    parser.add_option("-s", "--silent", dest="silent", default=False,
82 c16850ae Nikos Skalkotos
                      help="output only errors",
83 f99fe99d Nikos Skalkotos
                      action="store_true")
84 0ae01e26 Nikos Skalkotos
85 b5430a9f Nikos Skalkotos
    parser.add_option("-u", "--upload", dest="upload", type="string",
86 f99fe99d Nikos Skalkotos
                      default=False,
87 ffc64d7c Nikos Skalkotos
                      help="upload the image to the cloud with name FILENAME",
88 f99fe99d Nikos Skalkotos
                      metavar="FILENAME")
89 1a3f1298 Nikos Skalkotos
90 b5430a9f Nikos Skalkotos
    parser.add_option("-r", "--register", dest="register", type="string",
91 f99fe99d Nikos Skalkotos
                      default=False,
92 ffc64d7c Nikos Skalkotos
                      help="register the image with a cloud as IMAGENAME",
93 f99fe99d Nikos Skalkotos
                      metavar="IMAGENAME")
94 1a3f1298 Nikos Skalkotos
95 7d3dc857 Nikos Skalkotos
    parser.add_option("-m", "--metadata", dest="metadata", default=[],
96 c16850ae Nikos Skalkotos
                      help="add custom KEY=VALUE metadata to the image",
97 f99fe99d Nikos Skalkotos
                      action="append", metavar="KEY=VALUE")
98 7d3dc857 Nikos Skalkotos
99 997ac76a Nikos Skalkotos
    parser.add_option("-t", "--token", dest="token", type="string",
100 c2cf27e8 Nikos Skalkotos
                      default=None, help="use this authentication token when "
101 c2cf27e8 Nikos Skalkotos
                      "uploading/registering images")
102 997ac76a Nikos Skalkotos
103 49c07ce3 Nikos Skalkotos
    parser.add_option("-a", "--authentication-url", dest="url", type="string",
104 49c07ce3 Nikos Skalkotos
                      default=None, help="use this authentication URL when "
105 49c07ce3 Nikos Skalkotos
                      "uploading/registering images")
106 49c07ce3 Nikos Skalkotos
107 b3a4845c Nikos Skalkotos
    parser.add_option("-c", "--cloud", dest="cloud", type="string",
108 b3a4845c Nikos Skalkotos
                      default=None, help="use this saved cloud account to "
109 b3a4845c Nikos Skalkotos
                      "authenticate against a cloud when "
110 b3a4845c Nikos Skalkotos
                      "uploading/registering images")
111 b3a4845c Nikos Skalkotos
112 419c8d7b Nikos Skalkotos
    parser.add_option("--print-syspreps", dest="print_syspreps", default=False,
113 f99fe99d Nikos Skalkotos
                      help="print the enabled and disabled system preparation "
114 f99fe99d Nikos Skalkotos
                      "operations for this input media", action="store_true")
115 997ac76a Nikos Skalkotos
116 997ac76a Nikos Skalkotos
    parser.add_option("--enable-sysprep", dest="enabled_syspreps", default=[],
117 f99fe99d Nikos Skalkotos
                      help="run SYSPREP operation on the input media",
118 f99fe99d Nikos Skalkotos
                      action="append", metavar="SYSPREP")
119 997ac76a Nikos Skalkotos
120 997ac76a Nikos Skalkotos
    parser.add_option("--disable-sysprep", dest="disabled_syspreps",
121 f99fe99d Nikos Skalkotos
                      help="prevent SYSPREP operation from running on the "
122 f99fe99d Nikos Skalkotos
                      "input media", default=[], action="append",
123 f99fe99d Nikos Skalkotos
                      metavar="SYSPREP")
124 997ac76a Nikos Skalkotos
125 b21b5519 Nikos Skalkotos
    parser.add_option("--print-sysprep-params", dest="print_sysprep_params",
126 b21b5519 Nikos Skalkotos
                      default=False, help="print the needed sysprep parameters"
127 b21b5519 Nikos Skalkotos
                      " for this input media", action="store_true")
128 b21b5519 Nikos Skalkotos
129 0eac0256 Nikos Skalkotos
    parser.add_option("--sysprep-param", dest="sysprep_params", default=[],
130 0eac0256 Nikos Skalkotos
                      help="Add KEY=VALUE system preparation parameter",
131 0eac0256 Nikos Skalkotos
                      action="append")
132 0eac0256 Nikos Skalkotos
133 997ac76a Nikos Skalkotos
    parser.add_option("--no-sysprep", dest="sysprep", default=True,
134 c16850ae Nikos Skalkotos
                      help="don't perform any system preparation operation",
135 f99fe99d Nikos Skalkotos
                      action="store_false")
136 997ac76a Nikos Skalkotos
137 997ac76a Nikos Skalkotos
    parser.add_option("--no-shrink", dest="shrink", default=True,
138 f99fe99d Nikos Skalkotos
                      help="don't shrink any partition", action="store_false")
139 997ac76a Nikos Skalkotos
140 37d581b8 Nikos Skalkotos
    parser.add_option("--public", dest="public", default=False,
141 ffc64d7c Nikos Skalkotos
                      help="register image with the cloud as public",
142 37d581b8 Nikos Skalkotos
                      action="store_true")
143 37d581b8 Nikos Skalkotos
144 e482b7f9 Nikos Skalkotos
    parser.add_option("--allow-unsupported", dest="allow_unsupported",
145 e482b7f9 Nikos Skalkotos
                      help="Proceed with the image creation even if the media "
146 e482b7f9 Nikos Skalkotos
                      "is not supported", default=False, action="store_true")
147 e482b7f9 Nikos Skalkotos
148 c16850ae Nikos Skalkotos
    parser.add_option("--tmpdir", dest="tmp", type="string", default=None,
149 c16850ae Nikos Skalkotos
                      help="create large temporary image files under DIR",
150 c16850ae Nikos Skalkotos
                      metavar="DIR")
151 c16850ae Nikos Skalkotos
152 c408053f Nikos Skalkotos
    options, args = parser.parse_args(input_args)
153 c408053f Nikos Skalkotos
154 0ae01e26 Nikos Skalkotos
    if len(args) != 1:
155 0ae01e26 Nikos Skalkotos
        parser.error('Wrong number of arguments')
156 7d3dc857 Nikos Skalkotos
157 c408053f Nikos Skalkotos
    options.source = args[0]
158 c408053f Nikos Skalkotos
    if not os.path.exists(options.source):
159 b5430a9f Nikos Skalkotos
        raise FatalError("Input media `%s' is not accessible" % options.source)
160 c408053f Nikos Skalkotos
161 f99fe99d Nikos Skalkotos
    if options.register and not options.upload:
162 b5430a9f Nikos Skalkotos
        raise FatalError("You also need to set -u when -r option is set")
163 1a3f1298 Nikos Skalkotos
164 b3a4845c Nikos Skalkotos
    if options.upload and (options.token is None or options.url is None) and \
165 b3a4845c Nikos Skalkotos
            options.cloud is None:
166 b3a4845c Nikos Skalkotos
167 b3a4845c Nikos Skalkotos
        err = "You need to either specify an authentication URL and token " \
168 b3a4845c Nikos Skalkotos
              "pair or an available cloud name."
169 49c07ce3 Nikos Skalkotos
170 49c07ce3 Nikos Skalkotos
        raise FatalError("Image uploading cannot be performed. %s" % err)
171 997ac76a Nikos Skalkotos
172 c16850ae Nikos Skalkotos
    if options.tmp is not None and not os.path.isdir(options.tmp):
173 c16850ae Nikos Skalkotos
        raise FatalError("The directory `%s' specified with --tmpdir is not "
174 31160dc8 Nikos Skalkotos
                         "valid" % options.tmp)
175 c16850ae Nikos Skalkotos
176 7d3dc857 Nikos Skalkotos
    meta = {}
177 7d3dc857 Nikos Skalkotos
    for m in options.metadata:
178 7d3dc857 Nikos Skalkotos
        try:
179 7d3dc857 Nikos Skalkotos
            key, value = m.split('=', 1)
180 7d3dc857 Nikos Skalkotos
        except ValueError:
181 31160dc8 Nikos Skalkotos
            raise FatalError("Metadata option: `%s' is not in KEY=VALUE "
182 31160dc8 Nikos Skalkotos
                             "format." % m)
183 7d3dc857 Nikos Skalkotos
        meta[key] = value
184 7d3dc857 Nikos Skalkotos
    options.metadata = meta
185 7d3dc857 Nikos Skalkotos
186 0eac0256 Nikos Skalkotos
    sysprep_params = {}
187 0eac0256 Nikos Skalkotos
    for p in options.sysprep_params:
188 0eac0256 Nikos Skalkotos
        try:
189 0eac0256 Nikos Skalkotos
            key, value = p.split('=', 1)
190 0eac0256 Nikos Skalkotos
        except ValueError:
191 0eac0256 Nikos Skalkotos
            raise FatalError("Sysprep parameter optiont: `%s' is not in "
192 0eac0256 Nikos Skalkotos
                             "KEY=VALUE format." % p)
193 0eac0256 Nikos Skalkotos
        sysprep_params[key] = value
194 0eac0256 Nikos Skalkotos
    options.sysprep_params = sysprep_params
195 0eac0256 Nikos Skalkotos
196 c408053f Nikos Skalkotos
    return options
197 d57775d4 Nikos Skalkotos
198 8c574358 Nikos Skalkotos
199 22a6d232 Nikos Skalkotos
def image_creator():
200 c408053f Nikos Skalkotos
    options = parse_options(sys.argv[1:])
201 c408053f Nikos Skalkotos
202 f99fe99d Nikos Skalkotos
    if options.outfile is None and not options.upload and not \
203 419c8d7b Nikos Skalkotos
            options.print_syspreps and not options.print_sysprep_params:
204 419c8d7b Nikos Skalkotos
        raise FatalError("At least one of `-o', `-u', `--print-syspreps' or "
205 b21b5519 Nikos Skalkotos
                         "`--print-sysprep-params' must be set")
206 76d4a1c9 Nikos Skalkotos
207 e77e66a9 Nikos Skalkotos
    if options.silent:
208 4e58b51b Nikos Skalkotos
        out = SilentOutput()
209 e77e66a9 Nikos Skalkotos
    else:
210 4e58b51b Nikos Skalkotos
        out = OutputWthProgress(True) if sys.stderr.isatty() else \
211 f99fe99d Nikos Skalkotos
            SimpleOutput(False)
212 e77e66a9 Nikos Skalkotos
213 e108efd2 Nikos Skalkotos
    title = 'snf-image-creator %s' % version
214 e77e66a9 Nikos Skalkotos
    out.output(title)
215 e77e66a9 Nikos Skalkotos
    out.output('=' * len(title))
216 979096dd Nikos Skalkotos
217 c408053f Nikos Skalkotos
    if os.geteuid() != 0:
218 f99fe99d Nikos Skalkotos
        raise FatalError("You must run %s as root"
219 f99fe99d Nikos Skalkotos
                         % os.path.basename(sys.argv[0]))
220 c408053f Nikos Skalkotos
221 69aa33fa Nikos Skalkotos
    if not options.force and options.outfile is not None:
222 8e3065a0 Nikos Skalkotos
        for extension in ('', '.meta', '.md5sum'):
223 0ae01e26 Nikos Skalkotos
            filename = "%s%s" % (options.outfile, extension)
224 c408053f Nikos Skalkotos
            if os.path.exists(filename):
225 03eb7dc8 Nikos Skalkotos
                raise FatalError("Output file `%s' exists "
226 03eb7dc8 Nikos Skalkotos
                                 "(use --force to overwrite it)." % filename)
227 31160dc8 Nikos Skalkotos
228 b3a4845c Nikos Skalkotos
    # Check if the authentication info is valid. The earlier the better
229 49c07ce3 Nikos Skalkotos
    if options.token is not None and options.url is not None:
230 c2cf27e8 Nikos Skalkotos
        try:
231 49c07ce3 Nikos Skalkotos
            account = Kamaki.create_account(options.url, options.token)
232 c2cf27e8 Nikos Skalkotos
            if account is None:
233 49c07ce3 Nikos Skalkotos
                raise FatalError("The authentication token and/or URL you "
234 49c07ce3 Nikos Skalkotos
                                 "provided is not valid!")
235 03eb7dc8 Nikos Skalkotos
            else:
236 03eb7dc8 Nikos Skalkotos
                kamaki = Kamaki(account, out)
237 c2cf27e8 Nikos Skalkotos
        except ClientError as e:
238 c2cf27e8 Nikos Skalkotos
            raise FatalError("Astakos client: %d %s" % (e.status, e.message))
239 b3a4845c Nikos Skalkotos
    elif options.cloud:
240 b3a4845c Nikos Skalkotos
        avail_clouds = Kamaki.get_clouds()
241 b3a4845c Nikos Skalkotos
        if options.cloud not in avail_clouds.keys():
242 b3a4845c Nikos Skalkotos
            raise FatalError(
243 b3a4845c Nikos Skalkotos
                "Cloud: `%s' does not exist.\n\nAvailable clouds:\n\n\t%s\n"
244 b3a4845c Nikos Skalkotos
                % (options.cloud, "\n\t".join(avail_clouds.keys())))
245 b3a4845c Nikos Skalkotos
        try:
246 b3a4845c Nikos Skalkotos
            account = Kamaki.get_account(options.cloud)
247 b3a4845c Nikos Skalkotos
            if account is None:
248 b3a4845c Nikos Skalkotos
                raise FatalError(
249 b3a4845c Nikos Skalkotos
                    "Cloud: `$s' exists but is not valid!" % options.cloud)
250 b3a4845c Nikos Skalkotos
            else:
251 b3a4845c Nikos Skalkotos
                kamaki = Kamaki(account, out)
252 b3a4845c Nikos Skalkotos
        except ClientError as e:
253 b3a4845c Nikos Skalkotos
            raise FatalError("Astakos client: %d %s" % (e.status, e.message))
254 c2cf27e8 Nikos Skalkotos
255 03eb7dc8 Nikos Skalkotos
    if options.upload and not options.force:
256 03eb7dc8 Nikos Skalkotos
        if kamaki.object_exists(options.upload):
257 ffc64d7c Nikos Skalkotos
            raise FatalError("Remote storage service object: `%s' exists "
258 03eb7dc8 Nikos Skalkotos
                             "(use --force to overwrite it)." % options.upload)
259 03eb7dc8 Nikos Skalkotos
        if kamaki.object_exists("%s.md5sum" % options.upload):
260 ffc64d7c Nikos Skalkotos
            raise FatalError("Remote storage service object: `%s.md5sum' "
261 ffc64d7c Nikos Skalkotos
                             "exists (use --force to overwrite it)." %
262 ffc64d7c Nikos Skalkotos
                             options.upload)
263 03eb7dc8 Nikos Skalkotos
264 03eb7dc8 Nikos Skalkotos
    if options.register and not options.force:
265 03eb7dc8 Nikos Skalkotos
        if kamaki.object_exists("%s.meta" % options.upload):
266 ffc64d7c Nikos Skalkotos
            raise FatalError("Remote storage service object `%s.meta' exists "
267 03eb7dc8 Nikos Skalkotos
                             "(use --force to overwrite it)." % options.upload)
268 03eb7dc8 Nikos Skalkotos
269 c16850ae Nikos Skalkotos
    disk = Disk(options.source, out, options.tmp)
270 9c354f13 Nikos Skalkotos
271 9c354f13 Nikos Skalkotos
    def signal_handler(signum, frame):
272 9c354f13 Nikos Skalkotos
        disk.cleanup()
273 9c354f13 Nikos Skalkotos
274 9c354f13 Nikos Skalkotos
    signal.signal(signal.SIGINT, signal_handler)
275 9c354f13 Nikos Skalkotos
    signal.signal(signal.SIGTERM, signal_handler)
276 d57775d4 Nikos Skalkotos
    try:
277 e22aa3a9 Nikos Skalkotos
        snapshot = disk.snapshot()
278 e22aa3a9 Nikos Skalkotos
279 0eac0256 Nikos Skalkotos
        image = disk.get_image(snapshot, sysprep_params=options.sysprep_params)
280 df499fea Nikos Skalkotos
281 d0daafa2 Nikos Skalkotos
        if image.is_unsupported() and not options.allow_unsupported:
282 e482b7f9 Nikos Skalkotos
            raise FatalError(
283 d0daafa2 Nikos Skalkotos
                "The media seems to be unsupported.\n\n" +
284 d0daafa2 Nikos Skalkotos
                textwrap.fill("To create an image from an unsupported media, "
285 d0daafa2 Nikos Skalkotos
                              "you'll need to use the`--allow-unsupported' "
286 d0daafa2 Nikos Skalkotos
                              "command line option. Using this is highly "
287 d0daafa2 Nikos Skalkotos
                              "discouraged, since the resulting image will "
288 d0daafa2 Nikos Skalkotos
                              "not be cleared out of sensitive data and will "
289 d0daafa2 Nikos Skalkotos
                              "not get customized during the deployment."))
290 e482b7f9 Nikos Skalkotos
291 71b0ab28 Nikos Skalkotos
        for sysprep in options.disabled_syspreps:
292 71b0ab28 Nikos Skalkotos
            image.os.disable_sysprep(image.os.get_sysprep_by_name(sysprep))
293 71b0ab28 Nikos Skalkotos
294 71b0ab28 Nikos Skalkotos
        for sysprep in options.enabled_syspreps:
295 71b0ab28 Nikos Skalkotos
            image.os.enable_sysprep(image.os.get_sysprep_by_name(sysprep))
296 71b0ab28 Nikos Skalkotos
297 419c8d7b Nikos Skalkotos
        if options.print_syspreps:
298 71b0ab28 Nikos Skalkotos
            image.os.print_syspreps()
299 71b0ab28 Nikos Skalkotos
            out.output()
300 71b0ab28 Nikos Skalkotos
301 b21b5519 Nikos Skalkotos
        if options.print_sysprep_params:
302 b21b5519 Nikos Skalkotos
            image.os.print_sysprep_params()
303 b21b5519 Nikos Skalkotos
            out.output()
304 b21b5519 Nikos Skalkotos
305 71b0ab28 Nikos Skalkotos
        if options.outfile is None and not options.upload:
306 71b0ab28 Nikos Skalkotos
            return 0
307 71b0ab28 Nikos Skalkotos
308 71b0ab28 Nikos Skalkotos
        if options.sysprep:
309 71b0ab28 Nikos Skalkotos
            image.os.do_sysprep()
310 71b0ab28 Nikos Skalkotos
311 71b0ab28 Nikos Skalkotos
        metadata = image.os.meta
312 1a3f1298 Nikos Skalkotos
313 f5174d2c Nikos Skalkotos
        size = options.shrink and image.shrink() or image.size
314 f5174d2c Nikos Skalkotos
        metadata.update(image.meta)
315 ae48a082 Nikos Skalkotos
316 d0daafa2 Nikos Skalkotos
        if image.is_unsupported():
317 e482b7f9 Nikos Skalkotos
            metadata['EXCLUDE_ALL_TASKS'] = "yes"
318 e482b7f9 Nikos Skalkotos
319 7d3dc857 Nikos Skalkotos
        # Add command line metadata to the collected ones...
320 7d3dc857 Nikos Skalkotos
        metadata.update(options.metadata)
321 7d3dc857 Nikos Skalkotos
322 e77e66a9 Nikos Skalkotos
        md5 = MD5(out)
323 f5174d2c Nikos Skalkotos
        checksum = md5.compute(image.device, size)
324 8e3065a0 Nikos Skalkotos
325 8e58e699 Nikos Skalkotos
        metastring = unicode(json.dumps(
326 8e58e699 Nikos Skalkotos
            {'properties': metadata,
327 8e58e699 Nikos Skalkotos
             'disk-format': 'diskdump'}, ensure_ascii=False))
328 0ae01e26 Nikos Skalkotos
329 b1395967 Nikos Skalkotos
        if options.outfile is not None:
330 f5174d2c Nikos Skalkotos
            image.dump(options.outfile)
331 997ac76a Nikos Skalkotos
332 663f5f80 Nikos Skalkotos
            out.output('Dumping metadata file ...', False)
333 b1395967 Nikos Skalkotos
            with open('%s.%s' % (options.outfile, 'meta'), 'w') as f:
334 5b801534 Nikos Skalkotos
                f.write(metastring)
335 e77e66a9 Nikos Skalkotos
            out.success('done')
336 b1395967 Nikos Skalkotos
337 663f5f80 Nikos Skalkotos
            out.output('Dumping md5sum file ...', False)
338 b1395967 Nikos Skalkotos
            with open('%s.%s' % (options.outfile, 'md5sum'), 'w') as f:
339 f99fe99d Nikos Skalkotos
                f.write('%s %s\n' % (checksum,
340 f99fe99d Nikos Skalkotos
                                     os.path.basename(options.outfile)))
341 e77e66a9 Nikos Skalkotos
            out.success('done')
342 b1395967 Nikos Skalkotos
343 f5174d2c Nikos Skalkotos
        # Destroy the image instance. We only need the snapshot from now on
344 f5174d2c Nikos Skalkotos
        disk.destroy_image(image)
345 e22aa3a9 Nikos Skalkotos
346 e77e66a9 Nikos Skalkotos
        out.output()
347 3b7d3fc7 Nikos Skalkotos
        try:
348 3b7d3fc7 Nikos Skalkotos
            uploaded_obj = ""
349 3b7d3fc7 Nikos Skalkotos
            if options.upload:
350 ffc64d7c Nikos Skalkotos
                out.output("Uploading image to the storage service:")
351 825fe2a6 Nikos Skalkotos
                with open(snapshot, 'rb') as f:
352 37d581b8 Nikos Skalkotos
                    uploaded_obj = kamaki.upload(
353 37d581b8 Nikos Skalkotos
                        f, size, options.upload,
354 03eb7dc8 Nikos Skalkotos
                        "(1/3)  Calculating block hashes",
355 03eb7dc8 Nikos Skalkotos
                        "(2/3)  Uploading missing blocks")
356 03eb7dc8 Nikos Skalkotos
                out.output("(3/3)  Uploading md5sum file ...", False)
357 f99fe99d Nikos Skalkotos
                md5sumstr = '%s %s\n' % (checksum,
358 f99fe99d Nikos Skalkotos
                                         os.path.basename(options.upload))
359 3b7d3fc7 Nikos Skalkotos
                kamaki.upload(StringIO.StringIO(md5sumstr),
360 3b7d3fc7 Nikos Skalkotos
                              size=len(md5sumstr),
361 3b7d3fc7 Nikos Skalkotos
                              remote_path="%s.%s" % (options.upload, 'md5sum'))
362 3b7d3fc7 Nikos Skalkotos
                out.success('done')
363 3b7d3fc7 Nikos Skalkotos
                out.output()
364 3b7d3fc7 Nikos Skalkotos
365 3b7d3fc7 Nikos Skalkotos
            if options.register:
366 37d581b8 Nikos Skalkotos
                img_type = 'public' if options.public else 'private'
367 ffc64d7c Nikos Skalkotos
                out.output('Registering %s image with the compute service ...'
368 ffc64d7c Nikos Skalkotos
                           % img_type, False)
369 8e58e699 Nikos Skalkotos
                result = kamaki.register(options.register, uploaded_obj,
370 8e58e699 Nikos Skalkotos
                                         metadata, options.public)
371 3b7d3fc7 Nikos Skalkotos
                out.success('done')
372 03eb7dc8 Nikos Skalkotos
                out.output("Uploading metadata file ...", False)
373 8e58e699 Nikos Skalkotos
                metastring = unicode(json.dumps(result, ensure_ascii=False))
374 03eb7dc8 Nikos Skalkotos
                kamaki.upload(StringIO.StringIO(metastring),
375 03eb7dc8 Nikos Skalkotos
                              size=len(metastring),
376 03eb7dc8 Nikos Skalkotos
                              remote_path="%s.%s" % (options.upload, 'meta'))
377 03eb7dc8 Nikos Skalkotos
                out.success('done')
378 3afe6b44 Nikos Skalkotos
                if options.public:
379 3afe6b44 Nikos Skalkotos
                    out.output("Sharing md5sum file ...", False)
380 3afe6b44 Nikos Skalkotos
                    kamaki.share("%s.md5sum" % options.upload)
381 3afe6b44 Nikos Skalkotos
                    out.success('done')
382 3afe6b44 Nikos Skalkotos
                    out.output("Sharing metadata file ...", False)
383 3afe6b44 Nikos Skalkotos
                    kamaki.share("%s.meta" % options.upload)
384 3afe6b44 Nikos Skalkotos
                    out.success('done')
385 3afe6b44 Nikos Skalkotos
386 3b7d3fc7 Nikos Skalkotos
                out.output()
387 3b7d3fc7 Nikos Skalkotos
        except ClientError as e:
388 ffc64d7c Nikos Skalkotos
            raise FatalError("Service client: %d %s" % (e.status, e.message))
389 997ac76a Nikos Skalkotos
390 d57775d4 Nikos Skalkotos
    finally:
391 fd9af948 Nikos Skalkotos
        out.output('cleaning up ...')
392 d57775d4 Nikos Skalkotos
        disk.cleanup()
393 d57775d4 Nikos Skalkotos
394 e77e66a9 Nikos Skalkotos
    out.success("snf-image-creator exited without errors")
395 b1395967 Nikos Skalkotos
396 c408053f Nikos Skalkotos
    return 0
397 c408053f Nikos Skalkotos
398 ae48a082 Nikos Skalkotos
399 0ae01e26 Nikos Skalkotos
def main():
400 c408053f Nikos Skalkotos
    try:
401 0ae01e26 Nikos Skalkotos
        ret = image_creator()
402 c408053f Nikos Skalkotos
        sys.exit(ret)
403 c408053f Nikos Skalkotos
    except FatalError as e:
404 bb4db5a8 Nikos Skalkotos
        colored = sys.stderr.isatty()
405 ebe0f1e0 Nikos Skalkotos
        warning = \
406 ebe0f1e0 Nikos Skalkotos
            "The name of the executable has changed. If you want to use the " \
407 ebe0f1e0 Nikos Skalkotos
            "user-friendly dialog-based program try `snf-image-creator'"
408 ebe0f1e0 Nikos Skalkotos
        SimpleOutput(colored).warn(warning)
409 bb4db5a8 Nikos Skalkotos
        SimpleOutput(colored).error(e)
410 c408053f Nikos Skalkotos
        sys.exit(1)
411 d57775d4 Nikos Skalkotos
412 0ae01e26 Nikos Skalkotos
if __name__ == '__main__':
413 0ae01e26 Nikos Skalkotos
    main()
414 ae48a082 Nikos Skalkotos
415 d57775d4 Nikos Skalkotos
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :