Revision 5a380da9 image_creator/dialog_wizard.py

b/image_creator/dialog_wizard.py
48 48
    add_cloud, edit_cloud
49 49

  
50 50
PAGE_WIDTH = 70
51
PAGE_HEIGHT = 10
51 52

  
52 53

  
53 54
class WizardExit(Exception):
......
55 56
    pass
56 57

  
57 58

  
58
class WizardInvalidData(Exception):
59
    """Exception triggered when the user provided data are invalid"""
59
class WizardReloadPage(Exception):
60
    """Exception that reloads the last WizardPage"""
60 61
    pass
61 62

  
62 63

  
......
85 86
                idx += self.pages[idx].run(self.session, idx, len(self.pages))
86 87
            except WizardExit:
87 88
                return False
88
            except WizardInvalidData:
89
            except WizardReloadPage:
89 90
                continue
90 91

  
91 92
            if idx >= len(self.pages):
......
146 147
        w = session['wizard']
147 148

  
148 149
        choices = []
149
        for i in range(len(self.choices)):
150
            default = 1 if self.choices[i][0] == self.default else 0
151
            choices.append((self.choices[i][0], self.choices[i][1], default))
150
        for choice in self.choices():
151
            default = 1 if choice[0] == self.default else 0
152
            choices.append((choice[0], choice[1], default))
152 153

  
153 154
        (code, answer) = d.radiolist(
154
            self.message, height=10, width=PAGE_WIDTH, ok_label="Next",
155
            cancel="Back", choices=choices,
155
            self.message, width=PAGE_WIDTH, ok_label="Next", cancel="Back",
156
            choices=choices, height=PAGE_HEIGHT,
156 157
            title="(%d/%d) %s" % (index + 1, total, self.title))
157 158

  
158 159
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
......
182 183

  
183 184
        (code, answer) = d.inputbox(
184 185
            self.message, init=self.init, width=PAGE_WIDTH, ok_label="Next",
185
            cancel="Back", title="(%d/%d) %s" % (index + 1, total, self.title))
186
            cancel="Back", height=PAGE_HEIGHT,
187
            title="(%d/%d) %s" % (index + 1, total, self.title))
186 188

  
187 189
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
188 190
            return self.PREV
......
195 197
        return self.NEXT
196 198

  
197 199

  
200
class WizardMenuPage(WizardPage):
201
    """Represents a menu dialog in a wizard"""
202
    def __init__(self, name, printable, message, choices, **kargs):
203
        super(WizardMenuPage, self).__init__(**kargs)
204
        self.name = name
205
        self.printable = printable
206
        self.message = message
207
        self.info = "%s: <none>" % self.printable
208
        self.choices = choices
209
        self.title = kargs['title'] if 'title' in kargs else ''
210
        self.default = kargs['default'] if 'default' in kargs else ""
211
        self.extra = kargs['extra'] if 'extra' in kargs else None
212
        self.extra_label = \
213
            kargs['extra_label'] if 'extra_label' in kargs else 'Extra'
214
        self.fallback = kargs['fallback'] if 'fallback' in kargs else None
215

  
216
    def run(self, session, index, total):
217
        d = session['dialog']
218
        w = session['wizard']
219

  
220
        extra_button = 1 if self.extra else 0
221

  
222
        choices = self.choices()
223

  
224
        if len(choices) == 0:
225
            assert self.fallback, "Zero choices and no fallback"
226
            if self.fallback():
227
                raise WizardReloadPage
228
            else:
229
                return self.PREV
230

  
231
        default_item = self.default if self.default else choices[0][0]
232

  
233
        (code, choice) = d.menu(
234
            self.message, width=PAGE_WIDTH, ok_label="Next", cancel="Back",
235
            title="(%d/%d) %s" % (index + 1, total, self.title),
236
            choices=choices, height=PAGE_HEIGHT, default_item=default_item,
237
            extra_label=self.extra_label, extra_button=extra_button)
238

  
239
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
240
            return self.PREV
241
        elif code == d.DIALOG_EXTRA:
242
            self.extra()
243
            raise WizardReloadPage
244

  
245
        self.default = choice
246
        w[self.name] = self.validate(choice)
247
        self.info = "%s: %s" % (self.printable, self.display(w[self.name]))
248

  
249
        return self.NEXT
250

  
251

  
198 252
def start_wizard(session):
199 253
    """Run the image creation wizard"""
200 254

  
201
    d = session['dialog']
202
    clouds = Kamaki.get_clouds()
203
    if not len(clouds):
204
        if not add_cloud(session):
205
            return False
206
    else:
207
        while 1:
208
            choices = []
209
            for (name, cloud) in clouds.items():
210
                descr = cloud['description'] if 'description' in cloud else ''
211
                choices.append((name, descr))
212

  
213
            (code, choice) = d.menu(
214
                "In this menu you can select existing cloud account to use "
215
                " or add new ones. Press <Select> to select an existing "
216
                "account or <Add> to add a new one.", height=18,
217
                width=PAGE_WIDTH, choices=choices, menu_height=10,
218
                ok_label="Select", extra_button=1, extra_label="Add",
219
                title="Clouds")
220

  
221
            if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
222
                return False
223
            elif code == d.DIALOG_OK:  # Select button
224
                account = Kamaki.get_account(choice)
225
                if not account:
226
                    if not d.yesno("Then cloud you have selected is not "
227
                                   "valid! Would you like to edit it?",
228
                                   width=PAGE_WIDTH, defaultno=0):
229
                        edit_cloud(session, choice)
230
                    continue
231
                break
232
            elif code == d.DIALOG_EXTRA:  # Add button
233
                add_cloud(session)
234

  
235 255
    distro = session['image'].distro
236 256
    ostype = session['image'].ostype
257

  
258
    def cloud_choices():
259
        choices = []
260
        for (name, cloud) in Kamaki.get_clouds().items():
261
            descr = cloud['description'] if 'description' in cloud else ''
262
            choices.append((name, descr))
263

  
264
        return choices
265

  
266
    def cloud_add():
267
        return add_cloud(session)
268

  
269
    def cloud_none_available():
270
        if not session['dialog'].yesno(
271
                "No available clouds found. Would you like to add one now?",
272
                width=PAGE_WIDTH, defaultno=0):
273
            return add_cloud(session)
274
        return False
275

  
276
    def cloud_validate(cloud):
277
        if not Kamaki.get_account(cloud):
278
            if not session['dialog'].yesno(
279
                    "The cloud you have selected is not valid! Would you "
280
                    "like to edit it now?", width=PAGE_WIDTH, defaultno=0):
281
                if edit_cloud(session, cloud):
282
                    return cloud
283

  
284
            raise WizardInvalidData
285

  
286
        return cloud
287

  
288
    cloud = WizardMenuPage(
289
        "Cloud", "Cloud",
290
        "Please select a cloud account or press <Add> to add a new one:",
291
        choices=cloud_choices, extra_label="Add", extra=cloud_add,
292
        title="Clouds", validate=cloud_validate, fallback=cloud_none_available)
293

  
237 294
    name = WizardInputPage(
238 295
        "ImageName", "Image Name", "Please provide a name for the image:",
239 296
        title="Image Name", init=ostype if distro == "unknown" else distro)
......
244 301
        title="Image Description", init=session['metadata']['DESCRIPTION'] if
245 302
        'DESCRIPTION' in session['metadata'] else '')
246 303

  
304
    def registration_choices():
305
        return [("Private", "Image is accessible only by this user"),
306
                ("Public", "Everyone can create VMs from this image")]
307

  
247 308
    registration = WizardRadioListPage(
248 309
        "ImageRegistration", "Registration Type",
249
        "Please provide a registration type:",
250
        [("Private", "Image is accessible only by this user"),
251
         ("Public", "Everyone can create VMs from this image")],
310
        "Please provide a registration type:", registration_choices,
252 311
        title="Registration Type", default="Private")
253 312

  
254 313
    w = Wizard(session)
255 314

  
315
    w.add_page(cloud)
256 316
    w.add_page(name)
257 317
    w.add_page(descr)
258 318
    w.add_page(registration)
259 319

  
260 320
    if w.run():
261
        create_image(session, account)
321
        create_image(session)
262 322
    else:
263 323
        return False
264 324

  
265 325
    return True
266 326

  
267 327

  
268
def create_image(session, account):
328
def create_image(session):
269 329
    """Create an image using the information collected by the wizard"""
270 330
    d = session['dialog']
271 331
    image = session['image']
......
296 356
        out.output()
297 357
        try:
298 358
            out.output("Uploading image to pithos:")
359
            account = Kamaki.get_account(wizard['Cloud'])
360
            assert account, "Cloud: %s is not valid" % wizard['Cloud']
299 361
            kamaki = Kamaki(account, out)
300 362

  
301 363
            name = "%s-%s.diskdump" % (wizard['ImageName'],
......
342 404
        out.remove(with_progress)
343 405

  
344 406
    msg = "The %s image was successfully uploaded to Pithos and registered " \
345
          "with Cyclades. Would you like to keep a local copy of the image?" \
407
          "with Cyclades. Would you like to keep a local copy?" \
346 408
          % wizard['ImageRegistration'].lower()
347 409
    if not d.yesno(msg, width=PAGE_WIDTH):
348 410
        extract_image(session)

Also available in: Unified diff