From 37d581b868919aaee6cc8c14aa7e99dccb465a79 Mon Sep 17 00:00:00 2001 From: Nikos Skalkotos Date: Sun, 17 Mar 2013 23:55:02 +0200 Subject: [PATCH] Support private images Support images that can only be deployed by the user that registers the image to cyclades --- image_creator/bundle_volume.py | 6 ++--- image_creator/dialog_menu.py | 25 ++++++++++++++++----- image_creator/dialog_wizard.py | 47 ++++++++++++++++++++++----------------- image_creator/kamaki_wrapper.py | 11 ++++----- image_creator/main.py | 17 ++++++++++---- 5 files changed, 67 insertions(+), 39 deletions(-) diff --git a/image_creator/bundle_volume.py b/image_creator/bundle_volume.py index e32d90b..a5cc9d7 100644 --- a/image_creator/bundle_volume.py +++ b/image_creator/bundle_volume.py @@ -143,9 +143,9 @@ class BundleVolume(object): # Copy the Secondary GPT Header table = GPTPartitionTable(self.disk.device.path) dd('if=%s' % self.disk.device.path, 'of=%s' % image, - 'bs=%d' % self.disk.device.sectorSize, 'conv=notrunc', - 'seek=%d' % table.primary.last_usable_lba, - 'skip=%d' % table.primary.last_usable_lba) + 'bs=%d' % self.disk.device.sectorSize, 'conv=notrunc', + 'seek=%d' % table.primary.last_usable_lba, + 'skip=%d' % table.primary.last_usable_lba) # Create the Extended boot records (EBRs) in the image extended = self.disk.getExtendedPartition() diff --git a/image_creator/dialog_menu.py b/image_creator/dialog_menu.py index c8cfe27..d54af2a 100644 --- a/image_creator/dialog_menu.py +++ b/image_creator/dialog_menu.py @@ -185,8 +185,10 @@ def register_image(session): d = session["dialog"] dev = session['device'] + is_public = False + if "account" not in session: - d.msgbox("You need to provide your ~okeanos login username before you " + d.msgbox("You need to provide your ~okeanos credentians before you " "can register an images to cyclades", width=SMALL_WIDTH) return False @@ -206,6 +208,15 @@ def register_image(session): if len(name) == 0: d.msgbox("Registration name cannot be empty", width=SMALL_WIDTH) continue + + ret = d.yesno("Make the image public?\\nA public image is accessible" + "by every user of the service.", defaultno=1, + width=WIDTH) + if ret not in (0, 1): + continue + + is_public = True if ret == 0 else False + break metadata = {} @@ -214,15 +225,17 @@ def register_image(session): for key in session['task_metadata']: metadata[key] = 'yes' + img_type = "public" if is_public else "private" gauge = GaugeOutput(d, "Image Registration", "Registering image...") try: out = dev.out out.add(gauge) try: - out.output("Registering image with Cyclades...") + out.output("Registering %s image with Cyclades..." % img_type) try: kamaki = Kamaki(session['account'], out) - kamaki.register(name, session['pithos_uri'], metadata) + kamaki.register(name, session['pithos_uri'], metadata, + is_public) out.success('done') except ClientError as e: d.msgbox("Error in pithos+ client: %s" % e.message) @@ -232,8 +245,8 @@ def register_image(session): finally: gauge.cleanup() - d.msgbox("Image `%s' was successfully registered with Cyclades as `%s'" % - (session['upload'], name), width=SMALL_WIDTH) + d.msgbox("%s image `%s' was successfully registered with Cyclades as `%s'" + % (img_type.title(), session['upload'], name), width=SMALL_WIDTH) return True @@ -286,7 +299,7 @@ def kamaki_menu(session): else: del session['account'] d.msgbox("The token you provided is not valid!", - width=SMALL_WIDTH) + width=SMALL_WIDTH) elif choice == "Upload": if upload_image(session): default_item = "Register" diff --git a/image_creator/dialog_wizard.py b/image_creator/dialog_wizard.py index ee62963..61e7ecd 100644 --- a/image_creator/dialog_wizard.py +++ b/image_creator/dialog_wizard.py @@ -103,12 +103,12 @@ class WizardRadioListPage(WizardPage): choices = [] for i in range(len(self.choices)): - default = 1 if i == self.default else 0 + default = 1 if self.choices[i][0] == self.default else 0 choices.append((self.choices[i][0], self.choices[i][1], default)) while True: (code, answer) = \ - d.radiolist(self.message, width=PAGE_WIDTH, + d.radiolist(self.message, height=10, width=PAGE_WIDTH, ok_label="Next", cancel="Back", choices=choices, title="(%d/%d) %s" % (index + 1, total, self.title) ) @@ -116,11 +116,8 @@ class WizardRadioListPage(WizardPage): if code in (d.DIALOG_CANCEL, d.DIALOG_ESC): return self.PREV - for i in range(len(choices)): - if self.choices[i] == answer: - self.default = i - w[name] = i - break + w[self.name] = answer + self.default = answer return self.NEXT @@ -190,11 +187,15 @@ def wizard(session): name = WizardInputPage("ImageName", "Please provide a name for the image:", title="Image Name", init=session['device'].distro) - descr = WizardInputPage("ImageDescription", - "Please provide a description for the image:", - title="Image Description", - init=session['metadata']['DESCRIPTION'] if - 'DESCRIPTION' in session['metadata'] else '') + descr = WizardInputPage( + "ImageDescription", "Please provide a description for the image:", + title="Image Description", init=session['metadata']['DESCRIPTION'] if + 'DESCRIPTION' in session['metadata'] else '') + registration = WizardRadioListPage( + "ImageRegistration", "Please provide a registration type:", + [("Private", "Image is accessible only by this user"), + ("Public", "Everyone can create VMs from this image")], + title="Registration Type", default="Private") def validate_account(token): if len(token) == 0: @@ -204,15 +205,14 @@ def wizard(session): account = Kamaki.get_account(token) if account is None: session['dialog'].msgbox("The token you provided in not valid!", - width=PAGE_WIDTH) + width=PAGE_WIDTH) raise WizardInvalidData return account - account = WizardInputPage("account", - "Please provide your ~okeanos authentication token:", - title="~okeanos account token", init=init_token, - validate=validate_account) + account = WizardInputPage( + "account", "Please provide your ~okeanos authentication token:", + title="~okeanos account", init=init_token, validate=validate_account) msg = "All necessary information has been gathered. Confirm and Proceed." proceed = WizardYesNoPage(msg, title="Confirmation") @@ -221,6 +221,7 @@ def wizard(session): w.add_page(name) w.add_page(descr) + w.add_page(registration) w.add_page(account) w.add_page(proceed) @@ -296,8 +297,11 @@ def create_image(session): out.success('done') out.output() - out.output('Registering image with ~okeanos ...', False) - kamaki.register(wizard['ImageName'], pithos_file, metadata) + is_public = True if w['ImageRegistration'] == "Public" else False + out.output('Registering %s image with ~okeanos ...' % + w['ImageRegistration'].lower(), False) + kamaki.register(wizard['ImageName'], pithos_file, metadata, + is_public) out.success('done') out.output() @@ -306,8 +310,9 @@ def create_image(session): finally: out.remove(with_progress) - msg = "The image was successfully uploaded and registered with " \ - "~okeanos. Would you like to keep a local copy of the image?" + msg = "The %s image was successfully uploaded and registered with " \ + "~okeanos. Would you like to keep a local copy of the image?" \ + % w['ImageRegistration'].lower() if not d.yesno(msg, width=PAGE_WIDTH): extract_image(session) diff --git a/image_creator/kamaki_wrapper.py b/image_creator/kamaki_wrapper.py index dafea32..5963990 100644 --- a/image_creator/kamaki_wrapper.py +++ b/image_creator/kamaki_wrapper.py @@ -77,8 +77,9 @@ class Kamaki(object): config = Config() pithos_url = config.get('store', 'url') - self.pithos_client = PithosClient(pithos_url, - self.account['auth_token'], self.account['uuid'], self.CONTAINER) + self.pithos_client = PithosClient( + pithos_url, self.account['auth_token'], self.account['uuid'], + self.CONTAINER) image_url = config.get('image', 'url') self.image_client = ImageClient(image_url, self.account['auth_token']) @@ -103,15 +104,15 @@ class Kamaki(object): return "pithos://%s/%s/%s" % (self.account['uuid'], self.CONTAINER, path) - def register(self, name, location, metadata): + def register(self, name, location, metadata, public=False): """Register an image to ~okeanos""" # Convert all metadata to strings str_metadata = {} for (key, value) in metadata.iteritems(): str_metadata[str(key)] = str(value) - - params = {'is_public': 'true', 'disk_format': 'diskdump'} + is_public = 'true' if public else 'false' + params = {'is_public': is_public, 'disk_format': 'diskdump'} self.image_client.register(name, location, params, str_metadata) # vim: set sta sts=4 shiftwidth=4 sw=4 et ai : diff --git a/image_creator/main.py b/image_creator/main.py index afdf1a5..6d46ae3 100644 --- a/image_creator/main.py +++ b/image_creator/main.py @@ -118,6 +118,10 @@ def parse_options(input_args): parser.add_option("--no-shrink", dest="shrink", default=True, help="don't shrink any partition", action="store_false") + parser.add_option("--public", dest="public", default=False, + help="register image to cyclades as public", + action="store_true") + parser.add_option("--tmpdir", dest="tmp", type="string", default=None, help="create large temporary image files under DIR", metavar="DIR") @@ -135,7 +139,8 @@ def parse_options(input_args): raise FatalError("You also need to set -u when -r option is set") if options.upload and options.token is None: - raise FatalError("Image uploading cannot be performed. " + raise FatalError( + "Image uploading cannot be performed. " "No authentication token is specified. Use -t to set a token") if options.tmp is not None and not os.path.isdir(options.tmp): @@ -270,7 +275,8 @@ def image_creator(): out.output("Uploading image to pithos:") kamaki = Kamaki(account, out) with open(snapshot, 'rb') as f: - uploaded_obj = kamaki.upload(f, size, options.upload, + uploaded_obj = kamaki.upload( + f, size, options.upload, "(1/4) Calculating block hashes", "(2/4) Uploading missing blocks") @@ -289,8 +295,11 @@ def image_creator(): out.output() if options.register: - out.output('Registering image with ~okeanos ...', False) - kamaki.register(options.register, uploaded_obj, metadata) + img_type = 'public' if options.public else 'private' + out.output('Registering %s image with ~okeanos ...' % img_type, + False) + kamaki.register(options.register, uploaded_obj, metadata, + options.public) out.success('done') out.output() except ClientError as e: -- 1.7.10.4