Statistics
| Branch: | Tag: | Revision:

root / image_creator / dialog_wizard.py @ 84bc469c

History | View | Annotate | Download (11.4 kB)

1 09ed3d46 Nikos Skalkotos
#!/usr/bin/env python
2 09ed3d46 Nikos Skalkotos
3 09ed3d46 Nikos Skalkotos
# Copyright 2012 GRNET S.A. All rights reserved.
4 09ed3d46 Nikos Skalkotos
#
5 09ed3d46 Nikos Skalkotos
# Redistribution and use in source and binary forms, with or
6 09ed3d46 Nikos Skalkotos
# without modification, are permitted provided that the following
7 09ed3d46 Nikos Skalkotos
# conditions are met:
8 09ed3d46 Nikos Skalkotos
#
9 09ed3d46 Nikos Skalkotos
#   1. Redistributions of source code must retain the above
10 09ed3d46 Nikos Skalkotos
#      copyright notice, this list of conditions and the following
11 09ed3d46 Nikos Skalkotos
#      disclaimer.
12 09ed3d46 Nikos Skalkotos
#
13 09ed3d46 Nikos Skalkotos
#   2. Redistributions in binary form must reproduce the above
14 09ed3d46 Nikos Skalkotos
#      copyright notice, this list of conditions and the following
15 09ed3d46 Nikos Skalkotos
#      disclaimer in the documentation and/or other materials
16 09ed3d46 Nikos Skalkotos
#      provided with the distribution.
17 09ed3d46 Nikos Skalkotos
#
18 09ed3d46 Nikos Skalkotos
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
19 09ed3d46 Nikos Skalkotos
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 09ed3d46 Nikos Skalkotos
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 09ed3d46 Nikos Skalkotos
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
22 09ed3d46 Nikos Skalkotos
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 09ed3d46 Nikos Skalkotos
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 09ed3d46 Nikos Skalkotos
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25 09ed3d46 Nikos Skalkotos
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 09ed3d46 Nikos Skalkotos
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 09ed3d46 Nikos Skalkotos
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 09ed3d46 Nikos Skalkotos
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 09ed3d46 Nikos Skalkotos
# POSSIBILITY OF SUCH DAMAGE.
30 09ed3d46 Nikos Skalkotos
#
31 09ed3d46 Nikos Skalkotos
# The views and conclusions contained in the software and
32 09ed3d46 Nikos Skalkotos
# documentation are those of the authors and should not be
33 09ed3d46 Nikos Skalkotos
# interpreted as representing official policies, either expressed
34 09ed3d46 Nikos Skalkotos
# or implied, of GRNET S.A.
35 09ed3d46 Nikos Skalkotos
36 fbdf1d8f Nikos Skalkotos
import time
37 fbdf1d8f Nikos Skalkotos
import StringIO
38 09ed3d46 Nikos Skalkotos
39 fbdf1d8f Nikos Skalkotos
from image_creator.kamaki_wrapper import Kamaki, ClientError
40 fbdf1d8f Nikos Skalkotos
from image_creator.util import MD5, FatalError
41 fbdf1d8f Nikos Skalkotos
from image_creator.output.cli import OutputWthProgress
42 023e1217 Nikos Skalkotos
from image_creator.dialog_util import extract_image, update_background_title
43 09ed3d46 Nikos Skalkotos
44 3c33e68a Nikos Skalkotos
PAGE_WIDTH = 70
45 09ed3d46 Nikos Skalkotos
46 09ed3d46 Nikos Skalkotos
47 aeb95900 Nikos Skalkotos
class WizardExit(Exception):
48 88f83027 Nikos Skalkotos
    """Exception used to exit the wizard"""
49 aeb95900 Nikos Skalkotos
    pass
50 aeb95900 Nikos Skalkotos
51 aeb95900 Nikos Skalkotos
52 31160dc8 Nikos Skalkotos
class WizardInvalidData(Exception):
53 88f83027 Nikos Skalkotos
    """Exception triggered when the user provided data are invalid"""
54 31160dc8 Nikos Skalkotos
    pass
55 31160dc8 Nikos Skalkotos
56 31160dc8 Nikos Skalkotos
57 3c33e68a Nikos Skalkotos
class Wizard:
58 88f83027 Nikos Skalkotos
    """Represents a dialog-based wizard
59 88f83027 Nikos Skalkotos

60 88f83027 Nikos Skalkotos
    The wizard is a collection of pages that have a "Next" and a "Back" button
61 88f83027 Nikos Skalkotos
    on them. The pages are used to collect user data.
62 88f83027 Nikos Skalkotos
    """
63 88f83027 Nikos Skalkotos
64 3c33e68a Nikos Skalkotos
    def __init__(self, session):
65 3c33e68a Nikos Skalkotos
        self.session = session
66 3c33e68a Nikos Skalkotos
        self.pages = []
67 3c33e68a Nikos Skalkotos
        self.session['wizard'] = {}
68 baa62724 Nikos Skalkotos
        self.d = session['dialog']
69 3c33e68a Nikos Skalkotos
70 3c33e68a Nikos Skalkotos
    def add_page(self, page):
71 88f83027 Nikos Skalkotos
        """Add a new page to the wizard"""
72 3c33e68a Nikos Skalkotos
        self.pages.append(page)
73 09ed3d46 Nikos Skalkotos
74 09ed3d46 Nikos Skalkotos
    def run(self):
75 88f83027 Nikos Skalkotos
        """Run the wizard"""
76 3c33e68a Nikos Skalkotos
        idx = 0
77 3c33e68a Nikos Skalkotos
        while True:
78 aeb95900 Nikos Skalkotos
            try:
79 aeb95900 Nikos Skalkotos
                idx += self.pages[idx].run(self.session, idx, len(self.pages))
80 aeb95900 Nikos Skalkotos
            except WizardExit:
81 aeb95900 Nikos Skalkotos
                return False
82 31160dc8 Nikos Skalkotos
            except WizardInvalidData:
83 31160dc8 Nikos Skalkotos
                continue
84 09ed3d46 Nikos Skalkotos
85 3c33e68a Nikos Skalkotos
            if idx >= len(self.pages):
86 baa62724 Nikos Skalkotos
                msg = "All necessary information has been gathered:\n\n"
87 baa62724 Nikos Skalkotos
                for page in self.pages:
88 baa62724 Nikos Skalkotos
                    msg += " * %s\n" % page.info
89 66719e36 Nikos Skalkotos
                msg += "\nContinue with the image creation process?"
90 baa62724 Nikos Skalkotos
91 baa62724 Nikos Skalkotos
                ret = self.d.yesno(
92 66719e36 Nikos Skalkotos
                    msg, width=PAGE_WIDTH, height=8 + len(self.pages),
93 66719e36 Nikos Skalkotos
                    ok_label="Yes", cancel="Back", extra_button=1,
94 66719e36 Nikos Skalkotos
                    extra_label="Quit", title="Confirmation")
95 baa62724 Nikos Skalkotos
96 baa62724 Nikos Skalkotos
                if ret == self.d.DIALOG_CANCEL:
97 baa62724 Nikos Skalkotos
                    idx -= 1
98 baa62724 Nikos Skalkotos
                elif ret == self.d.DIALOG_EXTRA:
99 baa62724 Nikos Skalkotos
                    return False
100 baa62724 Nikos Skalkotos
                elif ret == self.d.DIALOG_OK:
101 baa62724 Nikos Skalkotos
                    return True
102 09ed3d46 Nikos Skalkotos
103 3c33e68a Nikos Skalkotos
            if idx < 0:
104 3c33e68a Nikos Skalkotos
                return False
105 09ed3d46 Nikos Skalkotos
106 09ed3d46 Nikos Skalkotos
107 baa62724 Nikos Skalkotos
class WizardPage(object):
108 88f83027 Nikos Skalkotos
    """Represents a page in a wizard"""
109 3c33e68a Nikos Skalkotos
    NEXT = 1
110 3c33e68a Nikos Skalkotos
    PREV = -1
111 fbdf1d8f Nikos Skalkotos
112 baa62724 Nikos Skalkotos
    def __init__(self, **kargs):
113 66719e36 Nikos Skalkotos
        validate = kargs['validate'] if 'validate' in kargs else lambda x: x
114 baa62724 Nikos Skalkotos
        setattr(self, "validate", validate)
115 baa62724 Nikos Skalkotos
116 66719e36 Nikos Skalkotos
        display = kargs['display'] if 'display' in kargs else lambda x: x
117 baa62724 Nikos Skalkotos
        setattr(self, "display", display)
118 baa62724 Nikos Skalkotos
119 fbdf1d8f Nikos Skalkotos
    def run(self, session, index, total):
120 88f83027 Nikos Skalkotos
        """Display this wizard page
121 88f83027 Nikos Skalkotos

122 88f83027 Nikos Skalkotos
        This function is used by the wizard program when accessing a page.
123 88f83027 Nikos Skalkotos
        """
124 fbdf1d8f Nikos Skalkotos
        raise NotImplementedError
125 fbdf1d8f Nikos Skalkotos
126 fbdf1d8f Nikos Skalkotos
127 37ee0098 Nikos Skalkotos
class WizardRadioListPage(WizardPage):
128 88f83027 Nikos Skalkotos
    """Represent a Radio List in a wizard"""
129 baa62724 Nikos Skalkotos
    def __init__(self, name, printable, message, choices, **kargs):
130 baa62724 Nikos Skalkotos
        super(WizardRadioListPage, self).__init__(**kargs)
131 37ee0098 Nikos Skalkotos
        self.name = name
132 baa62724 Nikos Skalkotos
        self.printable = printable
133 37ee0098 Nikos Skalkotos
        self.message = message
134 37ee0098 Nikos Skalkotos
        self.choices = choices
135 37ee0098 Nikos Skalkotos
        self.title = kargs['title'] if 'title' in kargs else ''
136 baa62724 Nikos Skalkotos
        self.default = kargs['default'] if 'default' in kargs else ""
137 37ee0098 Nikos Skalkotos
138 37ee0098 Nikos Skalkotos
    def run(self, session, index, total):
139 37ee0098 Nikos Skalkotos
        d = session['dialog']
140 37ee0098 Nikos Skalkotos
        w = session['wizard']
141 37ee0098 Nikos Skalkotos
142 37ee0098 Nikos Skalkotos
        choices = []
143 37ee0098 Nikos Skalkotos
        for i in range(len(self.choices)):
144 37d581b8 Nikos Skalkotos
            default = 1 if self.choices[i][0] == self.default else 0
145 37ee0098 Nikos Skalkotos
            choices.append((self.choices[i][0], self.choices[i][1], default))
146 37ee0098 Nikos Skalkotos
147 baa62724 Nikos Skalkotos
        (code, answer) = d.radiolist(
148 baa62724 Nikos Skalkotos
            self.message, height=10, width=PAGE_WIDTH, ok_label="Next",
149 baa62724 Nikos Skalkotos
            cancel="Back", choices=choices,
150 baa62724 Nikos Skalkotos
            title="(%d/%d) %s" % (index + 1, total, self.title))
151 37ee0098 Nikos Skalkotos
152 baa62724 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
153 baa62724 Nikos Skalkotos
            return self.PREV
154 37ee0098 Nikos Skalkotos
155 baa62724 Nikos Skalkotos
        w[self.name] = self.validate(answer)
156 baa62724 Nikos Skalkotos
        self.default = answer
157 baa62724 Nikos Skalkotos
        self.info = "%s: %s" % (self.printable, self.display(w[self.name]))
158 37ee0098 Nikos Skalkotos
159 baa62724 Nikos Skalkotos
        return self.NEXT
160 37ee0098 Nikos Skalkotos
161 37ee0098 Nikos Skalkotos
162 fbdf1d8f Nikos Skalkotos
class WizardInputPage(WizardPage):
163 88f83027 Nikos Skalkotos
    """Represents an input field in a wizard"""
164 baa62724 Nikos Skalkotos
    def __init__(self, name, printable, message, **kargs):
165 baa62724 Nikos Skalkotos
        super(WizardInputPage, self).__init__(**kargs)
166 3c33e68a Nikos Skalkotos
        self.name = name
167 baa62724 Nikos Skalkotos
        self.printable = printable
168 3c33e68a Nikos Skalkotos
        self.message = message
169 88f83027 Nikos Skalkotos
        self.info = "%s: <none>" % self.printable
170 3c33e68a Nikos Skalkotos
        self.title = kargs['title'] if 'title' in kargs else ''
171 31160dc8 Nikos Skalkotos
        self.init = kargs['init'] if 'init' in kargs else ''
172 09ed3d46 Nikos Skalkotos
173 3c33e68a Nikos Skalkotos
    def run(self, session, index, total):
174 3c33e68a Nikos Skalkotos
        d = session['dialog']
175 3c33e68a Nikos Skalkotos
        w = session['wizard']
176 09ed3d46 Nikos Skalkotos
177 baa62724 Nikos Skalkotos
        (code, answer) = d.inputbox(
178 baa62724 Nikos Skalkotos
            self.message, init=self.init, width=PAGE_WIDTH, ok_label="Next",
179 baa62724 Nikos Skalkotos
            cancel="Back", title="(%d/%d) %s" % (index + 1, total, self.title))
180 09ed3d46 Nikos Skalkotos
181 baa62724 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
182 baa62724 Nikos Skalkotos
            return self.PREV
183 09ed3d46 Nikos Skalkotos
184 baa62724 Nikos Skalkotos
        value = answer.strip()
185 baa62724 Nikos Skalkotos
        self.init = value
186 baa62724 Nikos Skalkotos
        w[self.name] = self.validate(value)
187 baa62724 Nikos Skalkotos
        self.info = "%s: %s" % (self.printable, self.display(w[self.name]))
188 09ed3d46 Nikos Skalkotos
189 09ed3d46 Nikos Skalkotos
        return self.NEXT
190 09ed3d46 Nikos Skalkotos
191 09ed3d46 Nikos Skalkotos
192 88f83027 Nikos Skalkotos
def start_wizard(session):
193 88f83027 Nikos Skalkotos
    """Run the image creation wizard"""
194 8bd0cbb6 Nikos Skalkotos
    init_token = Kamaki.get_token()
195 8bd0cbb6 Nikos Skalkotos
    if init_token is None:
196 8bd0cbb6 Nikos Skalkotos
        init_token = ""
197 09ed3d46 Nikos Skalkotos
198 baa62724 Nikos Skalkotos
    name = WizardInputPage(
199 baa62724 Nikos Skalkotos
        "ImageName", "Image Name", "Please provide a name for the image:",
200 f5174d2c Nikos Skalkotos
        title="Image Name", init=session['image'].distro)
201 baa62724 Nikos Skalkotos
202 37d581b8 Nikos Skalkotos
    descr = WizardInputPage(
203 baa62724 Nikos Skalkotos
        "ImageDescription", "Image Description",
204 baa62724 Nikos Skalkotos
        "Please provide a description for the image:",
205 37d581b8 Nikos Skalkotos
        title="Image Description", init=session['metadata']['DESCRIPTION'] if
206 37d581b8 Nikos Skalkotos
        'DESCRIPTION' in session['metadata'] else '')
207 baa62724 Nikos Skalkotos
208 37d581b8 Nikos Skalkotos
    registration = WizardRadioListPage(
209 baa62724 Nikos Skalkotos
        "ImageRegistration", "Registration Type",
210 baa62724 Nikos Skalkotos
        "Please provide a registration type:",
211 37d581b8 Nikos Skalkotos
        [("Private", "Image is accessible only by this user"),
212 37d581b8 Nikos Skalkotos
         ("Public", "Everyone can create VMs from this image")],
213 37d581b8 Nikos Skalkotos
        title="Registration Type", default="Private")
214 31160dc8 Nikos Skalkotos
215 31160dc8 Nikos Skalkotos
    def validate_account(token):
216 88f83027 Nikos Skalkotos
        """Check if a token is valid"""
217 76f42c27 Nikos Skalkotos
        d = session['dialog']
218 76f42c27 Nikos Skalkotos
219 31160dc8 Nikos Skalkotos
        if len(token) == 0:
220 31160dc8 Nikos Skalkotos
            d.msgbox("The token cannot be empty", width=PAGE_WIDTH)
221 31160dc8 Nikos Skalkotos
            raise WizardInvalidData
222 31160dc8 Nikos Skalkotos
223 31160dc8 Nikos Skalkotos
        account = Kamaki.get_account(token)
224 31160dc8 Nikos Skalkotos
        if account is None:
225 76f42c27 Nikos Skalkotos
            d.msgbox("The token you provided in not valid!", width=PAGE_WIDTH)
226 31160dc8 Nikos Skalkotos
            raise WizardInvalidData
227 31160dc8 Nikos Skalkotos
228 31160dc8 Nikos Skalkotos
        return account
229 31160dc8 Nikos Skalkotos
230 37d581b8 Nikos Skalkotos
    account = WizardInputPage(
231 baa62724 Nikos Skalkotos
        "Account", "Account",
232 baa62724 Nikos Skalkotos
        "Please provide your ~okeanos authentication token:",
233 baa62724 Nikos Skalkotos
        title="~okeanos account", init=init_token, validate=validate_account,
234 baa62724 Nikos Skalkotos
        display=lambda account: account['username'])
235 fbdf1d8f Nikos Skalkotos
236 3c33e68a Nikos Skalkotos
    w = Wizard(session)
237 fbdf1d8f Nikos Skalkotos
238 3c33e68a Nikos Skalkotos
    w.add_page(name)
239 3c33e68a Nikos Skalkotos
    w.add_page(descr)
240 37d581b8 Nikos Skalkotos
    w.add_page(registration)
241 3c33e68a Nikos Skalkotos
    w.add_page(account)
242 fbdf1d8f Nikos Skalkotos
243 fbdf1d8f Nikos Skalkotos
    if w.run():
244 023e1217 Nikos Skalkotos
        create_image(session)
245 fbdf1d8f Nikos Skalkotos
    else:
246 fbdf1d8f Nikos Skalkotos
        return False
247 fbdf1d8f Nikos Skalkotos
248 fbdf1d8f Nikos Skalkotos
    return True
249 fbdf1d8f Nikos Skalkotos
250 fbdf1d8f Nikos Skalkotos
251 023e1217 Nikos Skalkotos
def create_image(session):
252 88f83027 Nikos Skalkotos
    """Create an image using the information collected by the wizard"""
253 37ee0098 Nikos Skalkotos
    d = session['dialog']
254 f5174d2c Nikos Skalkotos
    image = session['image']
255 fbdf1d8f Nikos Skalkotos
    wizard = session['wizard']
256 fbdf1d8f Nikos Skalkotos
257 8bd0cbb6 Nikos Skalkotos
    # Save Kamaki credentials
258 baa62724 Nikos Skalkotos
    Kamaki.save_token(wizard['Account']['auth_token'])
259 8bd0cbb6 Nikos Skalkotos
260 789a3763 Nikos Skalkotos
    with_progress = OutputWthProgress(True)
261 f5174d2c Nikos Skalkotos
    out = image.out
262 789a3763 Nikos Skalkotos
    out.add(with_progress)
263 789a3763 Nikos Skalkotos
    try:
264 789a3763 Nikos Skalkotos
        out.clear()
265 fbdf1d8f Nikos Skalkotos
266 789a3763 Nikos Skalkotos
        #Sysprep
267 f5174d2c Nikos Skalkotos
        image.mount(False)
268 84bc469c Nikos Skalkotos
        err_msg = "Unable to execute the system preparation tasks."
269 84bc469c Nikos Skalkotos
        if not image.mounted:
270 84bc469c Nikos Skalkotos
            raise FatalError("%s Couldn't mount the media." % err_msg)
271 84bc469c Nikos Skalkotos
        elif image.mounted_ro:
272 84bc469c Nikos Skalkotos
            raise FatalError("%s Couldn't mount the media read-write."
273 84bc469c Nikos Skalkotos
                             % err_msg)
274 f5174d2c Nikos Skalkotos
        image.os.do_sysprep()
275 f5174d2c Nikos Skalkotos
        metadata = image.os.meta
276 f5174d2c Nikos Skalkotos
        image.umount()
277 1d413d1e Nikos Skalkotos
278 789a3763 Nikos Skalkotos
        #Shrink
279 f5174d2c Nikos Skalkotos
        size = image.shrink()
280 3793498a Nikos Skalkotos
        session['shrinked'] = True
281 023e1217 Nikos Skalkotos
        update_background_title(session)
282 fbdf1d8f Nikos Skalkotos
283 f5174d2c Nikos Skalkotos
        metadata.update(image.meta)
284 789a3763 Nikos Skalkotos
        metadata['DESCRIPTION'] = wizard['ImageDescription']
285 fbdf1d8f Nikos Skalkotos
286 789a3763 Nikos Skalkotos
        #MD5
287 789a3763 Nikos Skalkotos
        md5 = MD5(out)
288 f5174d2c Nikos Skalkotos
        session['checksum'] = md5.compute(image.device, size)
289 fbdf1d8f Nikos Skalkotos
290 789a3763 Nikos Skalkotos
        #Metadata
291 789a3763 Nikos Skalkotos
        metastring = '\n'.join(
292 789a3763 Nikos Skalkotos
            ['%s=%s' % (key, value) for (key, value) in metadata.items()])
293 789a3763 Nikos Skalkotos
        metastring += '\n'
294 fbdf1d8f Nikos Skalkotos
295 fbdf1d8f Nikos Skalkotos
        out.output()
296 789a3763 Nikos Skalkotos
        try:
297 789a3763 Nikos Skalkotos
            out.output("Uploading image to pithos:")
298 baa62724 Nikos Skalkotos
            kamaki = Kamaki(wizard['Account'], out)
299 789a3763 Nikos Skalkotos
300 789a3763 Nikos Skalkotos
            name = "%s-%s.diskdump" % (wizard['ImageName'],
301 789a3763 Nikos Skalkotos
                                       time.strftime("%Y%m%d%H%M"))
302 789a3763 Nikos Skalkotos
            pithos_file = ""
303 f5174d2c Nikos Skalkotos
            with open(image.device, 'rb') as f:
304 789a3763 Nikos Skalkotos
                pithos_file = kamaki.upload(f, size, name,
305 023e1217 Nikos Skalkotos
                                            "(1/4)  Calculating block hashes",
306 023e1217 Nikos Skalkotos
                                            "(2/4)  Uploading missing blocks")
307 789a3763 Nikos Skalkotos
308 663f5f80 Nikos Skalkotos
            out.output("(3/4)  Uploading metadata file ...", False)
309 789a3763 Nikos Skalkotos
            kamaki.upload(StringIO.StringIO(metastring), size=len(metastring),
310 789a3763 Nikos Skalkotos
                          remote_path="%s.%s" % (name, 'meta'))
311 789a3763 Nikos Skalkotos
            out.success('done')
312 663f5f80 Nikos Skalkotos
            out.output("(4/4)  Uploading md5sum file ...", False)
313 789a3763 Nikos Skalkotos
            md5sumstr = '%s %s\n' % (session['checksum'], name)
314 789a3763 Nikos Skalkotos
            kamaki.upload(StringIO.StringIO(md5sumstr), size=len(md5sumstr),
315 789a3763 Nikos Skalkotos
                          remote_path="%s.%s" % (name, 'md5sum'))
316 789a3763 Nikos Skalkotos
            out.success('done')
317 789a3763 Nikos Skalkotos
            out.output()
318 789a3763 Nikos Skalkotos
319 769526cb Nikos Skalkotos
            is_public = True if wizard['ImageRegistration'] == "Public" else \
320 769526cb Nikos Skalkotos
                False
321 37d581b8 Nikos Skalkotos
            out.output('Registering %s image with ~okeanos ...' %
322 769526cb Nikos Skalkotos
                       wizard['ImageRegistration'].lower(), False)
323 37d581b8 Nikos Skalkotos
            kamaki.register(wizard['ImageName'], pithos_file, metadata,
324 37d581b8 Nikos Skalkotos
                            is_public)
325 789a3763 Nikos Skalkotos
            out.success('done')
326 789a3763 Nikos Skalkotos
            out.output()
327 789a3763 Nikos Skalkotos
328 789a3763 Nikos Skalkotos
        except ClientError as e:
329 789a3763 Nikos Skalkotos
            raise FatalError("Pithos client: %d %s" % (e.status, e.message))
330 789a3763 Nikos Skalkotos
    finally:
331 789a3763 Nikos Skalkotos
        out.remove(with_progress)
332 09ed3d46 Nikos Skalkotos
333 37d581b8 Nikos Skalkotos
    msg = "The %s image was successfully uploaded and registered with " \
334 37d581b8 Nikos Skalkotos
          "~okeanos. Would you like to keep a local copy of the image?" \
335 769526cb Nikos Skalkotos
          % wizard['ImageRegistration'].lower()
336 37ee0098 Nikos Skalkotos
    if not d.yesno(msg, width=PAGE_WIDTH):
337 023e1217 Nikos Skalkotos
        extract_image(session)
338 37ee0098 Nikos Skalkotos
339 09ed3d46 Nikos Skalkotos
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :