Statistics
| Branch: | Tag: | Revision:

root / image_creator / main.py @ d9aff2ae

History | View | Annotate | Download (15.3 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 3ccb2618 Nikos Skalkotos
54 c408053f Nikos Skalkotos
55 0ae01e26 Nikos Skalkotos
def check_writable_dir(option, opt_str, value, parser):
56 0ae01e26 Nikos Skalkotos
    dirname = os.path.dirname(value)
57 0ae01e26 Nikos Skalkotos
    name = os.path.basename(value)
58 0ae01e26 Nikos Skalkotos
    if dirname and not os.path.isdir(dirname):
59 b5430a9f Nikos Skalkotos
        raise FatalError("`%s' is not an existing directory" % dirname)
60 c408053f Nikos Skalkotos
61 0ae01e26 Nikos Skalkotos
    if not name:
62 b5430a9f Nikos Skalkotos
        raise FatalError("`%s' is not a valid file name" % dirname)
63 c408053f Nikos Skalkotos
64 c408053f Nikos Skalkotos
    setattr(parser.values, option.dest, value)
65 c408053f Nikos Skalkotos
66 c408053f Nikos Skalkotos
67 c408053f Nikos Skalkotos
def parse_options(input_args):
68 0ae01e26 Nikos Skalkotos
    usage = "Usage: %prog [options] <input_media>"
69 c408053f Nikos Skalkotos
    parser = optparse.OptionParser(version=version, usage=usage)
70 c408053f Nikos Skalkotos
71 0ae01e26 Nikos Skalkotos
    parser.add_option("-o", "--outfile", type="string", dest="outfile",
72 f99fe99d Nikos Skalkotos
                      default=None, action="callback",
73 f99fe99d Nikos Skalkotos
                      callback=check_writable_dir, help="dump image to FILE",
74 f99fe99d Nikos Skalkotos
                      metavar="FILE")
75 979096dd Nikos Skalkotos
76 997ac76a Nikos Skalkotos
    parser.add_option("-f", "--force", dest="force", default=False,
77 f99fe99d Nikos Skalkotos
                      action="store_true",
78 f99fe99d Nikos Skalkotos
                      help="overwrite output files if they exist")
79 76d4a1c9 Nikos Skalkotos
80 979096dd Nikos Skalkotos
    parser.add_option("-s", "--silent", dest="silent", default=False,
81 c16850ae Nikos Skalkotos
                      help="output only errors",
82 f99fe99d Nikos Skalkotos
                      action="store_true")
83 0ae01e26 Nikos Skalkotos
84 b5430a9f Nikos Skalkotos
    parser.add_option("-u", "--upload", dest="upload", type="string",
85 f99fe99d Nikos Skalkotos
                      default=False,
86 ffc64d7c Nikos Skalkotos
                      help="upload the image to the cloud with name FILENAME",
87 f99fe99d Nikos Skalkotos
                      metavar="FILENAME")
88 1a3f1298 Nikos Skalkotos
89 b5430a9f Nikos Skalkotos
    parser.add_option("-r", "--register", dest="register", type="string",
90 f99fe99d Nikos Skalkotos
                      default=False,
91 ffc64d7c Nikos Skalkotos
                      help="register the image with a cloud as IMAGENAME",
92 f99fe99d Nikos Skalkotos
                      metavar="IMAGENAME")
93 1a3f1298 Nikos Skalkotos
94 7d3dc857 Nikos Skalkotos
    parser.add_option("-m", "--metadata", dest="metadata", default=[],
95 c16850ae Nikos Skalkotos
                      help="add custom KEY=VALUE metadata to the image",
96 f99fe99d Nikos Skalkotos
                      action="append", metavar="KEY=VALUE")
97 7d3dc857 Nikos Skalkotos
98 997ac76a Nikos Skalkotos
    parser.add_option("-t", "--token", dest="token", type="string",
99 c2cf27e8 Nikos Skalkotos
                      default=None, help="use this authentication token when "
100 c2cf27e8 Nikos Skalkotos
                      "uploading/registering images")
101 997ac76a Nikos Skalkotos
102 49c07ce3 Nikos Skalkotos
    parser.add_option("-a", "--authentication-url", dest="url", type="string",
103 49c07ce3 Nikos Skalkotos
                      default=None, help="use this authentication URL when "
104 49c07ce3 Nikos Skalkotos
                      "uploading/registering images")
105 49c07ce3 Nikos Skalkotos
106 b3a4845c Nikos Skalkotos
    parser.add_option("-c", "--cloud", dest="cloud", type="string",
107 b3a4845c Nikos Skalkotos
                      default=None, help="use this saved cloud account to "
108 b3a4845c Nikos Skalkotos
                      "authenticate against a cloud when "
109 b3a4845c Nikos Skalkotos
                      "uploading/registering images")
110 b3a4845c Nikos Skalkotos
111 997ac76a Nikos Skalkotos
    parser.add_option("--print-sysprep", dest="print_sysprep", default=False,
112 f99fe99d Nikos Skalkotos
                      help="print the enabled and disabled system preparation "
113 f99fe99d Nikos Skalkotos
                      "operations for this input media", action="store_true")
114 997ac76a Nikos Skalkotos
115 997ac76a Nikos Skalkotos
    parser.add_option("--enable-sysprep", dest="enabled_syspreps", default=[],
116 f99fe99d Nikos Skalkotos
                      help="run SYSPREP operation on the input media",
117 f99fe99d Nikos Skalkotos
                      action="append", metavar="SYSPREP")
118 997ac76a Nikos Skalkotos
119 997ac76a Nikos Skalkotos
    parser.add_option("--disable-sysprep", dest="disabled_syspreps",
120 f99fe99d Nikos Skalkotos
                      help="prevent SYSPREP operation from running on the "
121 f99fe99d Nikos Skalkotos
                      "input media", default=[], action="append",
122 f99fe99d Nikos Skalkotos
                      metavar="SYSPREP")
123 997ac76a Nikos Skalkotos
124 d9aff2ae Nikos Skalkotos
    parser.add_option("--print-sysprep-params", dest="print_sysprep_params",
125 d9aff2ae Nikos Skalkotos
                      default=False, help="print the needed sysprep parameters"
126 d9aff2ae Nikos Skalkotos
                      " for this input media", action="store_true")
127 d9aff2ae Nikos Skalkotos
128 d415dda2 Nikos Skalkotos
    parser.add_option("--sysprep-param", dest="sysprep_params", default=[],
129 d415dda2 Nikos Skalkotos
                      help="Add KEY=VALUE system preparation parameter",
130 d415dda2 Nikos Skalkotos
                      action="append")
131 d415dda2 Nikos Skalkotos
132 997ac76a Nikos Skalkotos
    parser.add_option("--no-sysprep", dest="sysprep", default=True,
133 c16850ae Nikos Skalkotos
                      help="don't perform any system preparation operation",
134 f99fe99d Nikos Skalkotos
                      action="store_false")
135 997ac76a Nikos Skalkotos
136 997ac76a Nikos Skalkotos
    parser.add_option("--no-shrink", dest="shrink", default=True,
137 f99fe99d Nikos Skalkotos
                      help="don't shrink any partition", action="store_false")
138 997ac76a Nikos Skalkotos
139 37d581b8 Nikos Skalkotos
    parser.add_option("--public", dest="public", default=False,
140 ffc64d7c Nikos Skalkotos
                      help="register image with the cloud as public",
141 37d581b8 Nikos Skalkotos
                      action="store_true")
142 37d581b8 Nikos Skalkotos
143 c16850ae Nikos Skalkotos
    parser.add_option("--tmpdir", dest="tmp", type="string", default=None,
144 c16850ae Nikos Skalkotos
                      help="create large temporary image files under DIR",
145 c16850ae Nikos Skalkotos
                      metavar="DIR")
146 c16850ae Nikos Skalkotos
147 c408053f Nikos Skalkotos
    options, args = parser.parse_args(input_args)
148 c408053f Nikos Skalkotos
149 0ae01e26 Nikos Skalkotos
    if len(args) != 1:
150 0ae01e26 Nikos Skalkotos
        parser.error('Wrong number of arguments')
151 7d3dc857 Nikos Skalkotos
152 c408053f Nikos Skalkotos
    options.source = args[0]
153 c408053f Nikos Skalkotos
    if not os.path.exists(options.source):
154 b5430a9f Nikos Skalkotos
        raise FatalError("Input media `%s' is not accessible" % options.source)
155 c408053f Nikos Skalkotos
156 f99fe99d Nikos Skalkotos
    if options.register and not options.upload:
157 b5430a9f Nikos Skalkotos
        raise FatalError("You also need to set -u when -r option is set")
158 1a3f1298 Nikos Skalkotos
159 b3a4845c Nikos Skalkotos
    if options.upload and (options.token is None or options.url is None) and \
160 b3a4845c Nikos Skalkotos
            options.cloud is None:
161 b3a4845c Nikos Skalkotos
162 b3a4845c Nikos Skalkotos
        err = "You need to either specify an authentication URL and token " \
163 b3a4845c Nikos Skalkotos
              "pair or an available cloud name."
164 49c07ce3 Nikos Skalkotos
165 49c07ce3 Nikos Skalkotos
        raise FatalError("Image uploading cannot be performed. %s" % err)
166 997ac76a Nikos Skalkotos
167 c16850ae Nikos Skalkotos
    if options.tmp is not None and not os.path.isdir(options.tmp):
168 c16850ae Nikos Skalkotos
        raise FatalError("The directory `%s' specified with --tmpdir is not "
169 31160dc8 Nikos Skalkotos
                         "valid" % options.tmp)
170 c16850ae Nikos Skalkotos
171 7d3dc857 Nikos Skalkotos
    meta = {}
172 7d3dc857 Nikos Skalkotos
    for m in options.metadata:
173 7d3dc857 Nikos Skalkotos
        try:
174 7d3dc857 Nikos Skalkotos
            key, value = m.split('=', 1)
175 7d3dc857 Nikos Skalkotos
        except ValueError:
176 31160dc8 Nikos Skalkotos
            raise FatalError("Metadata option: `%s' is not in KEY=VALUE "
177 31160dc8 Nikos Skalkotos
                             "format." % m)
178 7d3dc857 Nikos Skalkotos
        meta[key] = value
179 7d3dc857 Nikos Skalkotos
    options.metadata = meta
180 7d3dc857 Nikos Skalkotos
181 d415dda2 Nikos Skalkotos
    sysprep_params = {}
182 d415dda2 Nikos Skalkotos
    for p in options.sysprep_params:
183 d415dda2 Nikos Skalkotos
        try:
184 d415dda2 Nikos Skalkotos
            key, value = p.split('=', 1)
185 d415dda2 Nikos Skalkotos
        except ValueError:
186 d415dda2 Nikos Skalkotos
            raise FatalError("Sysprep parameter optiont: `%s' is not in "
187 d415dda2 Nikos Skalkotos
                             "KEY=VALUE format." % p)
188 d415dda2 Nikos Skalkotos
        sysprep_params[key] = value
189 d415dda2 Nikos Skalkotos
    options.sysprep_params = sysprep_params
190 d415dda2 Nikos Skalkotos
191 c408053f Nikos Skalkotos
    return options
192 d57775d4 Nikos Skalkotos
193 8c574358 Nikos Skalkotos
194 22a6d232 Nikos Skalkotos
def image_creator():
195 c408053f Nikos Skalkotos
    options = parse_options(sys.argv[1:])
196 c408053f Nikos Skalkotos
197 f99fe99d Nikos Skalkotos
    if options.outfile is None and not options.upload and not \
198 d9aff2ae Nikos Skalkotos
            options.print_sysprep and not options.print_sysprep_params:
199 d9aff2ae Nikos Skalkotos
        raise FatalError("At least one of `-o', `-u', `--print-sysprep' or "
200 d9aff2ae Nikos Skalkotos
                         "`--print-sysprep-params' must be set")
201 76d4a1c9 Nikos Skalkotos
202 e77e66a9 Nikos Skalkotos
    if options.silent:
203 4e58b51b Nikos Skalkotos
        out = SilentOutput()
204 e77e66a9 Nikos Skalkotos
    else:
205 4e58b51b Nikos Skalkotos
        out = OutputWthProgress(True) if sys.stderr.isatty() else \
206 f99fe99d Nikos Skalkotos
            SimpleOutput(False)
207 e77e66a9 Nikos Skalkotos
208 e108efd2 Nikos Skalkotos
    title = 'snf-image-creator %s' % version
209 e77e66a9 Nikos Skalkotos
    out.output(title)
210 e77e66a9 Nikos Skalkotos
    out.output('=' * len(title))
211 979096dd Nikos Skalkotos
212 c408053f Nikos Skalkotos
    if os.geteuid() != 0:
213 f99fe99d Nikos Skalkotos
        raise FatalError("You must run %s as root"
214 f99fe99d Nikos Skalkotos
                         % os.path.basename(sys.argv[0]))
215 c408053f Nikos Skalkotos
216 69aa33fa Nikos Skalkotos
    if not options.force and options.outfile is not None:
217 8e3065a0 Nikos Skalkotos
        for extension in ('', '.meta', '.md5sum'):
218 0ae01e26 Nikos Skalkotos
            filename = "%s%s" % (options.outfile, extension)
219 c408053f Nikos Skalkotos
            if os.path.exists(filename):
220 03eb7dc8 Nikos Skalkotos
                raise FatalError("Output file `%s' exists "
221 03eb7dc8 Nikos Skalkotos
                                 "(use --force to overwrite it)." % filename)
222 31160dc8 Nikos Skalkotos
223 b3a4845c Nikos Skalkotos
    # Check if the authentication info is valid. The earlier the better
224 49c07ce3 Nikos Skalkotos
    if options.token is not None and options.url is not None:
225 c2cf27e8 Nikos Skalkotos
        try:
226 49c07ce3 Nikos Skalkotos
            account = Kamaki.create_account(options.url, options.token)
227 c2cf27e8 Nikos Skalkotos
            if account is None:
228 49c07ce3 Nikos Skalkotos
                raise FatalError("The authentication token and/or URL you "
229 49c07ce3 Nikos Skalkotos
                                 "provided is not valid!")
230 03eb7dc8 Nikos Skalkotos
            else:
231 03eb7dc8 Nikos Skalkotos
                kamaki = Kamaki(account, out)
232 c2cf27e8 Nikos Skalkotos
        except ClientError as e:
233 c2cf27e8 Nikos Skalkotos
            raise FatalError("Astakos client: %d %s" % (e.status, e.message))
234 b3a4845c Nikos Skalkotos
    elif options.cloud:
235 b3a4845c Nikos Skalkotos
        avail_clouds = Kamaki.get_clouds()
236 b3a4845c Nikos Skalkotos
        if options.cloud not in avail_clouds.keys():
237 b3a4845c Nikos Skalkotos
            raise FatalError(
238 b3a4845c Nikos Skalkotos
                "Cloud: `%s' does not exist.\n\nAvailable clouds:\n\n\t%s\n"
239 b3a4845c Nikos Skalkotos
                % (options.cloud, "\n\t".join(avail_clouds.keys())))
240 b3a4845c Nikos Skalkotos
        try:
241 b3a4845c Nikos Skalkotos
            account = Kamaki.get_account(options.cloud)
242 b3a4845c Nikos Skalkotos
            if account is None:
243 b3a4845c Nikos Skalkotos
                raise FatalError(
244 b3a4845c Nikos Skalkotos
                    "Cloud: `$s' exists but is not valid!" % options.cloud)
245 b3a4845c Nikos Skalkotos
            else:
246 b3a4845c Nikos Skalkotos
                kamaki = Kamaki(account, out)
247 b3a4845c Nikos Skalkotos
        except ClientError as e:
248 b3a4845c Nikos Skalkotos
            raise FatalError("Astakos client: %d %s" % (e.status, e.message))
249 c2cf27e8 Nikos Skalkotos
250 03eb7dc8 Nikos Skalkotos
    if options.upload and not options.force:
251 03eb7dc8 Nikos Skalkotos
        if kamaki.object_exists(options.upload):
252 ffc64d7c Nikos Skalkotos
            raise FatalError("Remote storage service object: `%s' exists "
253 03eb7dc8 Nikos Skalkotos
                             "(use --force to overwrite it)." % options.upload)
254 03eb7dc8 Nikos Skalkotos
        if kamaki.object_exists("%s.md5sum" % options.upload):
255 ffc64d7c Nikos Skalkotos
            raise FatalError("Remote storage service object: `%s.md5sum' "
256 ffc64d7c Nikos Skalkotos
                             "exists (use --force to overwrite it)." %
257 ffc64d7c Nikos Skalkotos
                             options.upload)
258 03eb7dc8 Nikos Skalkotos
259 03eb7dc8 Nikos Skalkotos
    if options.register and not options.force:
260 03eb7dc8 Nikos Skalkotos
        if kamaki.object_exists("%s.meta" % options.upload):
261 ffc64d7c Nikos Skalkotos
            raise FatalError("Remote storage service object `%s.meta' exists "
262 03eb7dc8 Nikos Skalkotos
                             "(use --force to overwrite it)." % options.upload)
263 03eb7dc8 Nikos Skalkotos
264 c16850ae Nikos Skalkotos
    disk = Disk(options.source, out, options.tmp)
265 9c354f13 Nikos Skalkotos
266 9c354f13 Nikos Skalkotos
    def signal_handler(signum, frame):
267 9c354f13 Nikos Skalkotos
        disk.cleanup()
268 9c354f13 Nikos Skalkotos
269 9c354f13 Nikos Skalkotos
    signal.signal(signal.SIGINT, signal_handler)
270 9c354f13 Nikos Skalkotos
    signal.signal(signal.SIGTERM, signal_handler)
271 d57775d4 Nikos Skalkotos
    try:
272 e22aa3a9 Nikos Skalkotos
        snapshot = disk.snapshot()
273 e22aa3a9 Nikos Skalkotos
274 d415dda2 Nikos Skalkotos
        image = disk.get_image(snapshot, sysprep_params=options.sysprep_params)
275 df499fea Nikos Skalkotos
276 71b0ab28 Nikos Skalkotos
        for sysprep in options.disabled_syspreps:
277 71b0ab28 Nikos Skalkotos
            image.os.disable_sysprep(image.os.get_sysprep_by_name(sysprep))
278 71b0ab28 Nikos Skalkotos
279 71b0ab28 Nikos Skalkotos
        for sysprep in options.enabled_syspreps:
280 71b0ab28 Nikos Skalkotos
            image.os.enable_sysprep(image.os.get_sysprep_by_name(sysprep))
281 71b0ab28 Nikos Skalkotos
282 71b0ab28 Nikos Skalkotos
        if options.print_sysprep:
283 71b0ab28 Nikos Skalkotos
            image.os.print_syspreps()
284 71b0ab28 Nikos Skalkotos
            out.output()
285 71b0ab28 Nikos Skalkotos
286 d9aff2ae Nikos Skalkotos
        if options.print_sysprep_params:
287 d9aff2ae Nikos Skalkotos
            image.os.print_sysprep_params()
288 d9aff2ae Nikos Skalkotos
            out.output()
289 d9aff2ae Nikos Skalkotos
290 71b0ab28 Nikos Skalkotos
        if options.outfile is None and not options.upload:
291 71b0ab28 Nikos Skalkotos
            return 0
292 71b0ab28 Nikos Skalkotos
293 71b0ab28 Nikos Skalkotos
        if options.sysprep:
294 71b0ab28 Nikos Skalkotos
            image.os.do_sysprep()
295 71b0ab28 Nikos Skalkotos
296 71b0ab28 Nikos Skalkotos
        metadata = image.os.meta
297 1a3f1298 Nikos Skalkotos
298 f5174d2c Nikos Skalkotos
        size = options.shrink and image.shrink() or image.size
299 f5174d2c Nikos Skalkotos
        metadata.update(image.meta)
300 ae48a082 Nikos Skalkotos
301 7d3dc857 Nikos Skalkotos
        # Add command line metadata to the collected ones...
302 7d3dc857 Nikos Skalkotos
        metadata.update(options.metadata)
303 7d3dc857 Nikos Skalkotos
304 e77e66a9 Nikos Skalkotos
        md5 = MD5(out)
305 f5174d2c Nikos Skalkotos
        checksum = md5.compute(image.device, size)
306 8e3065a0 Nikos Skalkotos
307 8e58e699 Nikos Skalkotos
        metastring = unicode(json.dumps(
308 8e58e699 Nikos Skalkotos
            {'properties': metadata,
309 8e58e699 Nikos Skalkotos
             'disk-format': 'diskdump'}, ensure_ascii=False))
310 0ae01e26 Nikos Skalkotos
311 b1395967 Nikos Skalkotos
        if options.outfile is not None:
312 f5174d2c Nikos Skalkotos
            image.dump(options.outfile)
313 997ac76a Nikos Skalkotos
314 663f5f80 Nikos Skalkotos
            out.output('Dumping metadata file ...', False)
315 b1395967 Nikos Skalkotos
            with open('%s.%s' % (options.outfile, 'meta'), 'w') as f:
316 5b801534 Nikos Skalkotos
                f.write(metastring)
317 e77e66a9 Nikos Skalkotos
            out.success('done')
318 b1395967 Nikos Skalkotos
319 663f5f80 Nikos Skalkotos
            out.output('Dumping md5sum file ...', False)
320 b1395967 Nikos Skalkotos
            with open('%s.%s' % (options.outfile, 'md5sum'), 'w') as f:
321 f99fe99d Nikos Skalkotos
                f.write('%s %s\n' % (checksum,
322 f99fe99d Nikos Skalkotos
                                     os.path.basename(options.outfile)))
323 e77e66a9 Nikos Skalkotos
            out.success('done')
324 b1395967 Nikos Skalkotos
325 f5174d2c Nikos Skalkotos
        # Destroy the image instance. We only need the snapshot from now on
326 f5174d2c Nikos Skalkotos
        disk.destroy_image(image)
327 e22aa3a9 Nikos Skalkotos
328 e77e66a9 Nikos Skalkotos
        out.output()
329 3b7d3fc7 Nikos Skalkotos
        try:
330 3b7d3fc7 Nikos Skalkotos
            uploaded_obj = ""
331 3b7d3fc7 Nikos Skalkotos
            if options.upload:
332 ffc64d7c Nikos Skalkotos
                out.output("Uploading image to the storage service:")
333 825fe2a6 Nikos Skalkotos
                with open(snapshot, 'rb') as f:
334 37d581b8 Nikos Skalkotos
                    uploaded_obj = kamaki.upload(
335 37d581b8 Nikos Skalkotos
                        f, size, options.upload,
336 03eb7dc8 Nikos Skalkotos
                        "(1/3)  Calculating block hashes",
337 03eb7dc8 Nikos Skalkotos
                        "(2/3)  Uploading missing blocks")
338 03eb7dc8 Nikos Skalkotos
                out.output("(3/3)  Uploading md5sum file ...", False)
339 f99fe99d Nikos Skalkotos
                md5sumstr = '%s %s\n' % (checksum,
340 f99fe99d Nikos Skalkotos
                                         os.path.basename(options.upload))
341 3b7d3fc7 Nikos Skalkotos
                kamaki.upload(StringIO.StringIO(md5sumstr),
342 3b7d3fc7 Nikos Skalkotos
                              size=len(md5sumstr),
343 3b7d3fc7 Nikos Skalkotos
                              remote_path="%s.%s" % (options.upload, 'md5sum'))
344 3b7d3fc7 Nikos Skalkotos
                out.success('done')
345 3b7d3fc7 Nikos Skalkotos
                out.output()
346 3b7d3fc7 Nikos Skalkotos
347 3b7d3fc7 Nikos Skalkotos
            if options.register:
348 37d581b8 Nikos Skalkotos
                img_type = 'public' if options.public else 'private'
349 ffc64d7c Nikos Skalkotos
                out.output('Registering %s image with the compute service ...'
350 ffc64d7c Nikos Skalkotos
                           % img_type, False)
351 8e58e699 Nikos Skalkotos
                result = kamaki.register(options.register, uploaded_obj,
352 8e58e699 Nikos Skalkotos
                                         metadata, options.public)
353 3b7d3fc7 Nikos Skalkotos
                out.success('done')
354 03eb7dc8 Nikos Skalkotos
                out.output("Uploading metadata file ...", False)
355 8e58e699 Nikos Skalkotos
                metastring = unicode(json.dumps(result, ensure_ascii=False))
356 03eb7dc8 Nikos Skalkotos
                kamaki.upload(StringIO.StringIO(metastring),
357 03eb7dc8 Nikos Skalkotos
                              size=len(metastring),
358 03eb7dc8 Nikos Skalkotos
                              remote_path="%s.%s" % (options.upload, 'meta'))
359 03eb7dc8 Nikos Skalkotos
                out.success('done')
360 3afe6b44 Nikos Skalkotos
                if options.public:
361 3afe6b44 Nikos Skalkotos
                    out.output("Sharing md5sum file ...", False)
362 3afe6b44 Nikos Skalkotos
                    kamaki.share("%s.md5sum" % options.upload)
363 3afe6b44 Nikos Skalkotos
                    out.success('done')
364 3afe6b44 Nikos Skalkotos
                    out.output("Sharing metadata file ...", False)
365 3afe6b44 Nikos Skalkotos
                    kamaki.share("%s.meta" % options.upload)
366 3afe6b44 Nikos Skalkotos
                    out.success('done')
367 3afe6b44 Nikos Skalkotos
368 3b7d3fc7 Nikos Skalkotos
                out.output()
369 3b7d3fc7 Nikos Skalkotos
        except ClientError as e:
370 ffc64d7c Nikos Skalkotos
            raise FatalError("Service client: %d %s" % (e.status, e.message))
371 997ac76a Nikos Skalkotos
372 d57775d4 Nikos Skalkotos
    finally:
373 fd9af948 Nikos Skalkotos
        out.output('cleaning up ...')
374 d57775d4 Nikos Skalkotos
        disk.cleanup()
375 d57775d4 Nikos Skalkotos
376 e77e66a9 Nikos Skalkotos
    out.success("snf-image-creator exited without errors")
377 b1395967 Nikos Skalkotos
378 c408053f Nikos Skalkotos
    return 0
379 c408053f Nikos Skalkotos
380 ae48a082 Nikos Skalkotos
381 0ae01e26 Nikos Skalkotos
def main():
382 c408053f Nikos Skalkotos
    try:
383 0ae01e26 Nikos Skalkotos
        ret = image_creator()
384 c408053f Nikos Skalkotos
        sys.exit(ret)
385 c408053f Nikos Skalkotos
    except FatalError as e:
386 bb4db5a8 Nikos Skalkotos
        colored = sys.stderr.isatty()
387 bb4db5a8 Nikos Skalkotos
        SimpleOutput(colored).error(e)
388 c408053f Nikos Skalkotos
        sys.exit(1)
389 d57775d4 Nikos Skalkotos
390 0ae01e26 Nikos Skalkotos
if __name__ == '__main__':
391 0ae01e26 Nikos Skalkotos
    main()
392 ae48a082 Nikos Skalkotos
393 d57775d4 Nikos Skalkotos
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :