Statistics
| Branch: | Tag: | Revision:

root / image_creator / main.py @ 8e3065a0

History | View | Annotate | Download (8.2 kB)

1 ae48a082 Nikos Skalkotos
#!/usr/bin/env python
2 ae48a082 Nikos Skalkotos
3 d57775d4 Nikos Skalkotos
# Copyright 2011 GRNET S.A. All rights reserved.
4 d57775d4 Nikos Skalkotos
#
5 d57775d4 Nikos Skalkotos
# Redistribution and use in source and binary forms, with or
6 d57775d4 Nikos Skalkotos
# without modification, are permitted provided that the following
7 d57775d4 Nikos Skalkotos
# conditions are met:
8 d57775d4 Nikos Skalkotos
#
9 d57775d4 Nikos Skalkotos
#   1. Redistributions of source code must retain the above
10 d57775d4 Nikos Skalkotos
#      copyright notice, this list of conditions and the following
11 d57775d4 Nikos Skalkotos
#      disclaimer.
12 d57775d4 Nikos Skalkotos
#
13 d57775d4 Nikos Skalkotos
#   2. Redistributions in binary form must reproduce the above
14 d57775d4 Nikos Skalkotos
#      copyright notice, this list of conditions and the following
15 d57775d4 Nikos Skalkotos
#      disclaimer in the documentation and/or other materials
16 d57775d4 Nikos Skalkotos
#      provided with the distribution.
17 d57775d4 Nikos Skalkotos
#
18 d57775d4 Nikos Skalkotos
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
19 d57775d4 Nikos Skalkotos
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 d57775d4 Nikos Skalkotos
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 d57775d4 Nikos Skalkotos
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
22 d57775d4 Nikos Skalkotos
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 d57775d4 Nikos Skalkotos
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 d57775d4 Nikos Skalkotos
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25 d57775d4 Nikos Skalkotos
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 d57775d4 Nikos Skalkotos
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 d57775d4 Nikos Skalkotos
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 d57775d4 Nikos Skalkotos
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 d57775d4 Nikos Skalkotos
# POSSIBILITY OF SUCH DAMAGE.
30 d57775d4 Nikos Skalkotos
#
31 d57775d4 Nikos Skalkotos
# The views and conclusions contained in the software and
32 d57775d4 Nikos Skalkotos
# documentation are those of the authors and should not be
33 d57775d4 Nikos Skalkotos
# interpreted as representing official policies, either expressed
34 d57775d4 Nikos Skalkotos
# or implied, of GRNET S.A.
35 d57775d4 Nikos Skalkotos
36 aa2062ba Nikos Skalkotos
from image_creator import get_os_class
37 c408053f Nikos Skalkotos
from image_creator import __version__ as version
38 997ac76a Nikos Skalkotos
from image_creator import util
39 d57775d4 Nikos Skalkotos
from image_creator.disk import Disk
40 8e3065a0 Nikos Skalkotos
from image_creator.util import get_command, error, success, output, \
41 8e3065a0 Nikos Skalkotos
                                                    FatalError, progress, md5
42 997ac76a Nikos Skalkotos
from image_creator.kamaki_wrapper import Kamaki
43 d57775d4 Nikos Skalkotos
import sys
44 d57775d4 Nikos Skalkotos
import os
45 c408053f Nikos Skalkotos
import optparse
46 3ccb2618 Nikos Skalkotos
47 3ccb2618 Nikos Skalkotos
dd = get_command('dd')
48 c408053f Nikos Skalkotos
49 c408053f Nikos Skalkotos
50 0ae01e26 Nikos Skalkotos
def check_writable_dir(option, opt_str, value, parser):
51 0ae01e26 Nikos Skalkotos
    dirname = os.path.dirname(value)
52 0ae01e26 Nikos Skalkotos
    name = os.path.basename(value)
53 0ae01e26 Nikos Skalkotos
    if dirname and not os.path.isdir(dirname):
54 b5430a9f Nikos Skalkotos
        raise FatalError("`%s' is not an existing directory" % dirname)
55 c408053f Nikos Skalkotos
56 0ae01e26 Nikos Skalkotos
    if not name:
57 b5430a9f Nikos Skalkotos
        raise FatalError("`%s' is not a valid file name" % dirname)
58 c408053f Nikos Skalkotos
59 c408053f Nikos Skalkotos
    setattr(parser.values, option.dest, value)
60 c408053f Nikos Skalkotos
61 c408053f Nikos Skalkotos
62 c408053f Nikos Skalkotos
def parse_options(input_args):
63 0ae01e26 Nikos Skalkotos
    usage = "Usage: %prog [options] <input_media>"
64 c408053f Nikos Skalkotos
    parser = optparse.OptionParser(version=version, usage=usage)
65 c408053f Nikos Skalkotos
66 997ac76a Nikos Skalkotos
    account = os.environ["OKEANOS_USER"] if "OKEANOS_USER" in os.environ \
67 997ac76a Nikos Skalkotos
        else None
68 997ac76a Nikos Skalkotos
    token = os.environ["OKEANOS_TOKEN"] if "OKEANOS_TOKEN" in os.environ \
69 997ac76a Nikos Skalkotos
        else None
70 9cbb5794 Nikos Skalkotos
71 0ae01e26 Nikos Skalkotos
    parser.add_option("-o", "--outfile", type="string", dest="outfile",
72 0ae01e26 Nikos Skalkotos
        default=None, action="callback", callback=check_writable_dir,
73 979096dd Nikos Skalkotos
        help="dump image to FILE", metavar="FILE")
74 979096dd Nikos Skalkotos
75 997ac76a Nikos Skalkotos
    parser.add_option("-f", "--force", dest="force", default=False,
76 997ac76a Nikos Skalkotos
        action="store_true", help="overwrite output files if they exist")
77 76d4a1c9 Nikos Skalkotos
78 979096dd Nikos Skalkotos
    parser.add_option("-s", "--silent", dest="silent", default=False,
79 f165adc0 Nikos Skalkotos
        help="silent mode, only output errors", action="store_true")
80 0ae01e26 Nikos Skalkotos
81 b5430a9f Nikos Skalkotos
    parser.add_option("-u", "--upload", dest="upload", type="string",
82 b5430a9f Nikos Skalkotos
        default=False, help="upload the image to pithos with name FILENAME",
83 b5430a9f Nikos Skalkotos
        metavar="FILENAME")
84 1a3f1298 Nikos Skalkotos
85 b5430a9f Nikos Skalkotos
    parser.add_option("-r", "--register", dest="register", type="string",
86 b5430a9f Nikos Skalkotos
        default=False, help="register the image to ~okeanos as IMAGENAME",
87 b5430a9f Nikos Skalkotos
        metavar="IMAGENAME")
88 1a3f1298 Nikos Skalkotos
89 997ac76a Nikos Skalkotos
    parser.add_option("-a", "--account", dest="account", type="string",
90 997ac76a Nikos Skalkotos
        default=account,
91 997ac76a Nikos Skalkotos
        help="Use this ACCOUNT when uploading/registring images [Default: %s]"\
92 997ac76a Nikos Skalkotos
        % account)
93 997ac76a Nikos Skalkotos
94 997ac76a Nikos Skalkotos
    parser.add_option("-t", "--token", dest="token", type="string",
95 997ac76a Nikos Skalkotos
        default=token,
96 997ac76a Nikos Skalkotos
        help="Use this token when uploading/registring images [Default: %s]"\
97 997ac76a Nikos Skalkotos
        % token)
98 997ac76a Nikos Skalkotos
99 997ac76a Nikos Skalkotos
    parser.add_option("--print-sysprep", dest="print_sysprep", default=False,
100 997ac76a Nikos Skalkotos
        help="print the enabled and disabled system preparation operations "
101 997ac76a Nikos Skalkotos
        "for this input media", action="store_true")
102 997ac76a Nikos Skalkotos
103 997ac76a Nikos Skalkotos
    parser.add_option("--enable-sysprep", dest="enabled_syspreps", default=[],
104 997ac76a Nikos Skalkotos
        help="run SYSPREP operation on the input media",
105 997ac76a Nikos Skalkotos
        action="append", metavar="SYSPREP")
106 997ac76a Nikos Skalkotos
107 997ac76a Nikos Skalkotos
    parser.add_option("--disable-sysprep", dest="disabled_syspreps",
108 997ac76a Nikos Skalkotos
        help="prevent SYSPREP operation from running on the input media",
109 997ac76a Nikos Skalkotos
        default=[], action="append", metavar="SYSPREP")
110 997ac76a Nikos Skalkotos
111 997ac76a Nikos Skalkotos
    parser.add_option("--no-sysprep", dest="sysprep", default=True,
112 997ac76a Nikos Skalkotos
        help="don't perform system preperation", action="store_false")
113 997ac76a Nikos Skalkotos
114 997ac76a Nikos Skalkotos
    parser.add_option("--no-shrink", dest="shrink", default=True,
115 997ac76a Nikos Skalkotos
        help="don't shrink any partition", action="store_false")
116 997ac76a Nikos Skalkotos
117 c408053f Nikos Skalkotos
    options, args = parser.parse_args(input_args)
118 c408053f Nikos Skalkotos
119 0ae01e26 Nikos Skalkotos
    if len(args) != 1:
120 0ae01e26 Nikos Skalkotos
        parser.error('Wrong number of arguments')
121 c408053f Nikos Skalkotos
    options.source = args[0]
122 c408053f Nikos Skalkotos
    if not os.path.exists(options.source):
123 b5430a9f Nikos Skalkotos
        raise FatalError("Input media `%s' is not accessible" % options.source)
124 c408053f Nikos Skalkotos
125 997ac76a Nikos Skalkotos
    if options.register and options.upload == False:
126 b5430a9f Nikos Skalkotos
        raise FatalError("You also need to set -u when -r option is set")
127 1a3f1298 Nikos Skalkotos
128 997ac76a Nikos Skalkotos
    if options.upload and options.account is None:
129 997ac76a Nikos Skalkotos
        raise FatalError("Image uploading cannot be performed. No ~okeanos "
130 997ac76a Nikos Skalkotos
        "account name is specified. Use -a to set an account name.")
131 997ac76a Nikos Skalkotos
132 997ac76a Nikos Skalkotos
    if options.upload and options.token is None:
133 997ac76a Nikos Skalkotos
        raise FatalError("Image uploading cannot be performed. No ~okeanos "
134 997ac76a Nikos Skalkotos
        "token is specified. User -t to set a token.")
135 997ac76a Nikos Skalkotos
136 c408053f Nikos Skalkotos
    return options
137 d57775d4 Nikos Skalkotos
138 8c574358 Nikos Skalkotos
139 22a6d232 Nikos Skalkotos
def image_creator():
140 c408053f Nikos Skalkotos
    options = parse_options(sys.argv[1:])
141 c408053f Nikos Skalkotos
142 979096dd Nikos Skalkotos
    if options.silent:
143 979096dd Nikos Skalkotos
        util.silent = True
144 979096dd Nikos Skalkotos
145 76d4a1c9 Nikos Skalkotos
    if options.outfile is None and not options.upload \
146 f165adc0 Nikos Skalkotos
                                            and not options.print_sysprep:
147 f165adc0 Nikos Skalkotos
        raise FatalError("At least one of `-o', `-u' or" \
148 f165adc0 Nikos Skalkotos
                            "`--print-sysprep' must be set")
149 76d4a1c9 Nikos Skalkotos
150 979096dd Nikos Skalkotos
    output('snf-image-creator %s\n' % version)
151 979096dd Nikos Skalkotos
152 c408053f Nikos Skalkotos
    if os.geteuid() != 0:
153 c408053f Nikos Skalkotos
        raise FatalError("You must run %s as root" \
154 c408053f Nikos Skalkotos
                        % os.path.basename(sys.argv[0]))
155 c408053f Nikos Skalkotos
156 69aa33fa Nikos Skalkotos
    if not options.force and options.outfile is not None:
157 8e3065a0 Nikos Skalkotos
        for extension in ('', '.meta', '.md5sum'):
158 0ae01e26 Nikos Skalkotos
            filename = "%s%s" % (options.outfile, extension)
159 c408053f Nikos Skalkotos
            if os.path.exists(filename):
160 c408053f Nikos Skalkotos
                raise FatalError("Output file %s exists "
161 c408053f Nikos Skalkotos
                    "(use --force to overwrite it)." % filename)
162 c408053f Nikos Skalkotos
163 c408053f Nikos Skalkotos
    disk = Disk(options.source)
164 d57775d4 Nikos Skalkotos
    try:
165 e22aa3a9 Nikos Skalkotos
        snapshot = disk.snapshot()
166 e22aa3a9 Nikos Skalkotos
167 e22aa3a9 Nikos Skalkotos
        dev = disk.get_device(snapshot)
168 0d5a999d Nikos Skalkotos
        dev.mount()
169 22a6d232 Nikos Skalkotos
170 aa2062ba Nikos Skalkotos
        osclass = get_os_class(dev.distro, dev.ostype)
171 aa2062ba Nikos Skalkotos
        image_os = osclass(dev.root, dev.g)
172 aa2062ba Nikos Skalkotos
        metadata = image_os.get_metadata()
173 9cbb5794 Nikos Skalkotos
174 979096dd Nikos Skalkotos
        output()
175 3f70f242 Nikos Skalkotos
176 f165adc0 Nikos Skalkotos
        for sysprep in options.disabled_syspreps:
177 f165adc0 Nikos Skalkotos
            image_os.disable_sysprep(sysprep)
178 f165adc0 Nikos Skalkotos
179 f165adc0 Nikos Skalkotos
        for sysprep in options.enabled_syspreps:
180 f165adc0 Nikos Skalkotos
            image_os.enable_sysprep(sysprep)
181 76d4a1c9 Nikos Skalkotos
182 f165adc0 Nikos Skalkotos
        if options.print_sysprep:
183 f165adc0 Nikos Skalkotos
            image_os.print_syspreps()
184 76d4a1c9 Nikos Skalkotos
            output()
185 76d4a1c9 Nikos Skalkotos
186 76d4a1c9 Nikos Skalkotos
        if options.outfile is None and not options.upload:
187 76d4a1c9 Nikos Skalkotos
            return 0
188 76d4a1c9 Nikos Skalkotos
189 9cbb5794 Nikos Skalkotos
        if options.sysprep:
190 f165adc0 Nikos Skalkotos
            image_os.do_sysprep()
191 1a3f1298 Nikos Skalkotos
192 8c574358 Nikos Skalkotos
        dev.umount()
193 1a3f1298 Nikos Skalkotos
194 c408053f Nikos Skalkotos
        size = options.shrink and dev.shrink() or dev.size()
195 39cfd61a Nikos Skalkotos
        metadata['SIZE'] = str(size // 2 ** 20)
196 ae48a082 Nikos Skalkotos
197 8e3065a0 Nikos Skalkotos
        #Calculating MD5sum
198 8e3065a0 Nikos Skalkotos
        output("Calculating md5sum...", False)
199 8e3065a0 Nikos Skalkotos
        checksum = md5(snapshot, size)
200 8e3065a0 Nikos Skalkotos
        success(checksum)
201 8e3065a0 Nikos Skalkotos
        output()
202 8e3065a0 Nikos Skalkotos
203 0ae01e26 Nikos Skalkotos
        if options.outfile is not None:
204 0ae01e26 Nikos Skalkotos
            f = open('%s.%s' % (options.outfile, 'meta'), 'w')
205 0ae01e26 Nikos Skalkotos
            try:
206 0ae01e26 Nikos Skalkotos
                for key in metadata.keys():
207 0ae01e26 Nikos Skalkotos
                    f.write("%s=%s\n" % (key, metadata[key]))
208 0ae01e26 Nikos Skalkotos
            finally:
209 0ae01e26 Nikos Skalkotos
                f.close()
210 0ae01e26 Nikos Skalkotos
211 d603d80d Nikos Skalkotos
            dev.dump(options.outfile)
212 997ac76a Nikos Skalkotos
213 e22aa3a9 Nikos Skalkotos
        # Destroy the device. We only need the snapshot from now on
214 e22aa3a9 Nikos Skalkotos
        disk.destroy_device(dev)
215 e22aa3a9 Nikos Skalkotos
216 997ac76a Nikos Skalkotos
        if options.upload:
217 8e3065a0 Nikos Skalkotos
            output("Uploading image to pithos:")
218 997ac76a Nikos Skalkotos
            kamaki = Kamaki(options.account, options.token)
219 e22aa3a9 Nikos Skalkotos
            kamaki.upload(snapshot, size, options.upload)
220 997ac76a Nikos Skalkotos
221 d57775d4 Nikos Skalkotos
    finally:
222 979096dd Nikos Skalkotos
        output('cleaning up...')
223 d57775d4 Nikos Skalkotos
        disk.cleanup()
224 d57775d4 Nikos Skalkotos
225 c408053f Nikos Skalkotos
    return 0
226 c408053f Nikos Skalkotos
227 ae48a082 Nikos Skalkotos
228 0ae01e26 Nikos Skalkotos
def main():
229 c408053f Nikos Skalkotos
    try:
230 0ae01e26 Nikos Skalkotos
        ret = image_creator()
231 c408053f Nikos Skalkotos
        sys.exit(ret)
232 c408053f Nikos Skalkotos
    except FatalError as e:
233 22a6d232 Nikos Skalkotos
        error(e)
234 c408053f Nikos Skalkotos
        sys.exit(1)
235 d57775d4 Nikos Skalkotos
236 0ae01e26 Nikos Skalkotos
237 0ae01e26 Nikos Skalkotos
if __name__ == '__main__':
238 0ae01e26 Nikos Skalkotos
    main()
239 ae48a082 Nikos Skalkotos
240 d57775d4 Nikos Skalkotos
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :