From: Nikos Skalkotos Date: Tue, 18 Jun 2013 13:27:05 +0000 (+0300) Subject: Comply with kamaki 0.9 X-Git-Tag: 0.4.1~3^2~1^2~5 X-Git-Url: https://code.grnet.gr/git/snf-image-creator/commitdiff_plain/49c07ce389257085642c76aa3318b80076e18bd6 Comply with kamaki 0.9 * Change the authentication everywhere to use clouds (authentication URL and token pairs) * Add menu entries to manage clouds * Add an extra -a option in snf-image-creator to allow the user to specify authentication URLs --- diff --git a/image_creator/dialog_main.py b/image_creator/dialog_main.py index e0e4e04..0834cb4 100644 --- a/image_creator/dialog_main.py +++ b/image_creator/dialog_main.py @@ -178,7 +178,7 @@ def _dialog_form(self, text, height=20, width=60, form_height=15, fields=[], if len(field[0]) > label_len: label_len = len(field[0]) - input_len = width - label_len - 2 + input_len = width - label_len - 1 line = 1 for field in fields: @@ -186,7 +186,7 @@ def _dialog_form(self, text, height=20, width=60, form_height=15, fields=[], item = field[1] item_len = field[2] cmd.extend((label, str(line), str(1), item, str(line), - str(label_len + 2), str(input_len), str(item_len))) + str(label_len + 1), str(input_len), str(item_len))) line += 1 code, output = self._perform(*(cmd,), **kwargs) diff --git a/image_creator/dialog_menu.py b/image_creator/dialog_menu.py index 5b5526c..858dc19 100644 --- a/image_creator/dialog_menu.py +++ b/image_creator/dialog_menu.py @@ -48,7 +48,7 @@ from image_creator.kamaki_wrapper import Kamaki, ClientError from image_creator.help import get_help_file from image_creator.dialog_util import SMALL_WIDTH, WIDTH, \ update_background_title, confirm_reset, confirm_exit, Reset, \ - extract_image, extract_metadata_string + extract_image, extract_metadata_string, add_cloud, edit_cloud CONFIGURATION_TASKS = [ ("Partition table manipulation", ["FixPartitionTable"], @@ -119,8 +119,8 @@ def upload_image(session): size = image.size if "account" not in session: - d.msgbox("You need to provide your ~okeanos credentials before you " - "can upload images to pithos+", width=SMALL_WIDTH) + d.msgbox("You need to select a valid cloud before you can upload " + "images to pithos+", width=SMALL_WIDTH) return False while 1: @@ -204,7 +204,7 @@ def register_image(session): is_public = False if "account" not in session: - d.msgbox("You need to provide your ~okeanos credentians before you " + d.msgbox("You need to select a valid cloud before you " "can register an images with cyclades", width=SMALL_WIDTH) return False @@ -277,25 +277,102 @@ def register_image(session): return True +def modify_clouds(session): + """Modify existing cloud accounts""" + d = session['dialog'] + + while 1: + clouds = Kamaki.get_clouds() + if not len(clouds): + if not add_cloud(session): + break + continue + + choices = [] + for (name, cloud) in clouds.items(): + descr = cloud['description'] if 'description' in cloud else '' + choices.append((name, descr)) + + (code, choice) = d.menu( + "In this menu you can edit existing cloud accounts or add new " + " ones. Press to edit an existing account or to add " + " a new one. Press or hit when done.", height=18, + width=WIDTH, choices=choices, menu_height=10, ok_label="Edit", + extra_button=1, extra_label="Add", cancel="Back", help_button=1, + title="Clouds") + + if code in (d.DIALOG_CANCEL, d.DIALOG_ESC): + return True + elif code == d.DIALOG_OK: # Edit button + edit_cloud(session, choice) + elif code == d.DIALOG_EXTRA: # Add button + add_cloud(session) + + +def delete_clouds(session): + """Delete existing cloud accounts""" + d = session['dialog'] + + choices = [] + for (name, cloud) in Kamaki.get_clouds().items(): + descr = cloud['description'] if 'description' in cloud else '' + choices.append((name, descr, 0)) + + if len(choices) == 0: + d.msgbox("No available clouds to delete!", width=SMALL_WIDTH) + return True + + (code, to_delete) = d.checklist("Choose which cloud accounts to delete:", + choices=choices, width=WIDTH) + + if code in (d.DIALOG_CANCEL, d.DIALOG_ESC): + return False + + if not len(to_delete): + d.msgbox("Nothing selected!", width=SMALL_WIDTH) + return False + + if not d.yesno("Are you sure you want to remove the selected cloud " + "accounts?", width=WIDTH, defaultno=1): + for i in to_delete: + Kamaki.remove_cloud(i) + if 'cloud' in session and session['cloud'] == i: + del session['cloud'] + if 'account' in session: + del session['account'] + else: + return False + + d.msgbox("%d cloud accounts were deleted." % len(to_delete), + width=SMALL_WIDTH) + return True + + def kamaki_menu(session): """Show kamaki related actions""" d = session['dialog'] - default_item = "Account" + default_item = "Cloud" - if 'account' not in session: - token = Kamaki.get_token() - if token: - session['account'] = Kamaki.get_account(token) + if 'cloud' not in session: + cloud = Kamaki.get_default_cloud_name() + if cloud: + session['cloud'] = cloud + session['account'] = Kamaki.get_account(cloud) if not session['account']: del session['account'] - Kamaki.save_token('') # The token was not valid. Remove it + else: + default_item = "Add/Edit" while 1: - account = session["account"]['username'] if "account" in session else \ - "" + cloud = session["cloud"] if "cloud" in session else "" + if 'account' not in session and 'cloud' in session: + cloud += " " + upload = session["upload"] if "upload" in session else "" - choices = [("Account", "Change your ~okeanos account: %s" % account), + choices = [("Add/Edit", "Add/Edit cloud accounts"), + ("Delete", "Delete existing cloud accounts"), + ("Cloud", "Select cloud account to use: %s" % cloud), ("Upload", "Upload image to pithos+"), ("Register", "Register the image to cyclades: %s" % upload)] @@ -308,26 +385,56 @@ def kamaki_menu(session): if code in (d.DIALOG_CANCEL, d.DIALOG_ESC): return False - if choice == "Account": - default_item = "Account" - (code, answer) = d.inputbox( - "Please provide your ~okeanos authentication token:", - init=session["account"]['auth_token'] if "account" in session - else '', width=WIDTH) + if choice == "Add/Edit": + if modify_clouds(session): + default_item = "Cloud" + elif choice == "Delete": + if delete_clouds(session): + if len(Kamaki.get_clouds()): + default_item = "Cloud" + else: + default_time = "Add/Edit" + else: + default_time = "Delete" + elif choice == "Cloud": + default_item = "Cloud" + clouds = Kamaki.get_clouds() + if not len(clouds): + d.msgbox("No clouds available. Please add a new cloud!", + width=SMALL_WIDTH) + default_item = "Add/Edit" + continue + + if 'cloud' not in session: + session['cloud'] = clouds.keys()[0] + + choices = [] + for name, info in clouds.items(): + default = 1 if session['cloud'] == name else 0 + descr = info['description'] if 'description' in info else "" + choices.append((name, descr, default)) + + (code, answer) = d.radiolist("Please select a cloud:", + width=WIDTH, choices=choices) if code in (d.DIALOG_CANCEL, d.DIALOG_ESC): continue - if len(answer) == 0 and "account" in session: - del session["account"] else: - token = answer.strip() - session['account'] = Kamaki.get_account(token) + session['account'] = Kamaki.get_account(answer) + + if session['account'] is None: # invalid account + if not d.yesno("The cloud %s' is not valid! Would you " + "like to edit it?" % answer, width=WIDTH): + if edit_cloud(session, answer): + session['account'] = Kamaki.get_account(answer) + Kamaki.set_default_cloud(answer) + if session['account'] is not None: - Kamaki.save_token(token) + session['cloud'] = answer + Kamaki.set_default_cloud(answer) default_item = "Upload" else: del session['account'] - d.msgbox("The token you provided is not valid!", - width=SMALL_WIDTH) + del session['cloud'] elif choice == "Upload": if upload_image(session): default_item = "Register" @@ -668,8 +775,8 @@ def main_menu(session): update_background_title(session) - choices = [("Customize", "Customize image & ~okeanos deployment options"), - ("Register", "Register image to ~okeanos"), + choices = [("Customize", "Customize image & cloud deployment options"), + ("Register", "Register image to a cloud"), ("Extract", "Dump image to local file system"), ("Reset", "Reset everything and start over again"), ("Help", "Get help for using snf-image-creator")] diff --git a/image_creator/dialog_util.py b/image_creator/dialog_util.py index 6c3b7ce..fee232a 100644 --- a/image_creator/dialog_util.py +++ b/image_creator/dialog_util.py @@ -38,8 +38,10 @@ snf-image-creator. """ import os +import re from image_creator.output.dialog import GaugeOutput from image_creator.util import MD5 +from image_creator.kamaki_wrapper import Kamaki SMALL_WIDTH = 60 WIDTH = 70 @@ -171,4 +173,115 @@ def extract_image(session): return True + +def _check_cloud(session, name, description, url, token): + """Checks if the provided info for a cloud are valid""" + d = session['dialog'] + regexp = re.compile('^[a-zA-Z0-9_]+$') + + if not re.match(regexp, name): + d.msgbox("Allowed characters for name: [a-zA-Z0-9_]", width=WIDTH) + return False + + if len(url) == 0: + d.msgbox("Url cannot be empty!", width=WIDTH) + return False + + if len(token) == 0: + d.msgbox("Token cannot be empty!", width=WIDTH) + return False + + if Kamaki.create_account(url, token) is None: + d.msgbox("The cloud info you provided is not valid. Please check the " + "Authentication URL and the token values again!", width=WIDTH) + return False + + return True + + +def add_cloud(session): + """Add a new cloud account""" + + d = session['dialog'] + + name = "" + description = "" + url = "" + token = "" + + while 1: + fields = [ + ("Name:", name, 60), + ("Description (optional): ", description, 80), + ("Authentication URL: ", url, 200), + ("Token:", token, 100)] + + (code, output) = d.form("Add a new cloud account:", height=13, + width=WIDTH, form_height=4, fields=fields) + + if code in (d.DIALOG_CANCEL, d.DIALOG_ESC): + return False + + name, description, url, token = output + + name = name.strip() + description = description.strip() + url = url.strip() + token = token.strip() + + if _check_cloud(session, name, description, url, token): + if name in Kamaki.get_clouds().keys(): + d.msgbox("A cloud with name `%s' already exists. If you want " + "to edit the existing cloud account, use the edit " + "menu." % name, width=WIDTH) + else: + Kamaki.save_cloud(name, url, token, description) + break + + continue + + return True + + +def edit_cloud(session, name): + """Edit a cloud account""" + + info = Kamaki.get_cloud_by_name(name) + + assert info, "Cloud: `%s' does not exist" % name + assert 'url' in info, "Cloud: `%s' does not have a url attr" % name + assert 'token' in info, "Cloud: `%s' does not have a token attr" % name + + description = info['description'] if 'description' in info else "" + url = info['url'] + token = info['token'] + + d = session['dialog'] + + while 1: + fields = [ + ("Description (optional): ", description, 80), + ("Authentication URL: ", url, 200), + ("Token:", token, 100)] + + (code, output) = d.form("Edit cloud account: `%s'" % name, height=13, + width=WIDTH, form_height=3, fields=fields) + + if code in (d.DIALOG_CANCEL, d.DIALOG_ESC): + return False + + description, url, token = output + + description = description.strip() + url = url.strip() + token = token.strip() + + if _check_cloud(session, name, description, url, token): + Kamaki.save_cloud(name, url, token, description) + break + + continue + + return True + # vim: set sta sts=4 shiftwidth=4 sw=4 et ai : diff --git a/image_creator/dialog_wizard.py b/image_creator/dialog_wizard.py index 20fe45a..f761d99 100644 --- a/image_creator/dialog_wizard.py +++ b/image_creator/dialog_wizard.py @@ -43,7 +43,8 @@ import StringIO from image_creator.kamaki_wrapper import Kamaki, ClientError from image_creator.util import MD5, FatalError from image_creator.output.cli import OutputWthProgress -from image_creator.dialog_util import extract_image, update_background_title +from image_creator.dialog_util import extract_image, update_background_title, \ + add_cloud, edit_cloud PAGE_WIDTH = 70 @@ -195,9 +196,40 @@ class WizardInputPage(WizardPage): def start_wizard(session): """Run the image creation wizard""" - init_token = Kamaki.get_token() - if init_token is None: - init_token = "" + + d = session['dialog'] + clouds = Kamaki.get_clouds() + if not len(clouds): + if not add_cloud(session): + return False + else: + while 1: + choices = [] + for (name, cloud) in clouds.items(): + descr = cloud['description'] if 'description' in cloud else '' + choices.append((name, descr)) + + (code, choice) = d.menu( + "In this menu you can select existing cloud account to use " + " or add new ones. Press