# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
-import sys
import os
import textwrap
import StringIO
]
-class metadata_monitor(object):
+class MetadataMonitor(object):
+ """Monitors image metadata chages"""
def __init__(self, session, meta):
self.session = session
self.meta = meta
def upload_image(session):
+ """Upload the image to pithos+"""
d = session["dialog"]
- dev = session['device']
- size = dev.size
+ image = session['image']
+ meta = session['metadata']
+ size = image.size
if "account" not in session:
- d.msgbox("You need to provide your ~okeanos account before you "
+ d.msgbox("You need to provide your ~okeanos credentials before you "
"can upload images to pithos+", width=SMALL_WIDTH)
return False
while 1:
- init = session["upload"] if "upload" in session else ''
+ if 'upload' in session:
+ init = session['upload']
+ elif 'OS' in meta:
+ init = "%s.diskdump" % meta['OS']
+ else:
+ init = ""
(code, answer) = d.inputbox("Please provide a filename:", init=init,
width=WIDTH)
if len(filename) == 0:
d.msgbox("Filename cannot be empty", width=SMALL_WIDTH)
continue
+
+ kamaki = Kamaki(session['account'], None)
+ overwrite = []
+ for f in (filename, "%s.md5sum" % filename, "%s.meta" % filename):
+ if kamaki.object_exists(f):
+ overwrite.append(f)
+
+ if len(overwrite) > 0:
+ if d.yesno("The following pithos object(s) already exist(s):\n"
+ "%s\nDo you want to overwrite them?" %
+ "\n".join(overwrite), width=WIDTH, defaultno=1):
+ continue
+
session['upload'] = filename
break
gauge = GaugeOutput(d, "Image Upload", "Uploading...")
try:
- out = dev.out
+ out = image.out
out.add(gauge)
+ kamaki.out = out
try:
if 'checksum' not in session:
md5 = MD5(out)
- session['checksum'] = md5.compute(session['snapshot'], size)
+ session['checksum'] = md5.compute(image.device, size)
- kamaki = Kamaki(session['account'], out)
try:
# Upload image file
- with open(session['snapshot'], 'rb') as f:
+ with open(image.device, 'rb') as f:
session["pithos_uri"] = \
kamaki.upload(f, size, filename,
"Calculating block hashes",
"Uploading missing blocks")
- # Upload metadata file
- out.output("Uploading metadata file...")
- metastring = extract_metadata_string(session)
- kamaki.upload(StringIO.StringIO(metastring),
- size=len(metastring),
- remote_path="%s.meta" % filename)
- out.success("done")
-
# Upload md5sum file
out.output("Uploading md5sum file...")
md5str = "%s %s\n" % (session['checksum'], filename)
def register_image(session):
+ """Register image with cyclades"""
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 "
- "can register an images to cyclades",
- width=SMALL_WIDTH)
+ d.msgbox("You need to provide your ~okeanos credentians before you "
+ "can register an images with cyclades", width=SMALL_WIDTH)
return False
if "pithos_uri" not in session:
d.msgbox("You need to upload the image to pithos+ before you can "
- "register it to cyclades", width=SMALL_WIDTH)
+ "register it with cyclades", width=SMALL_WIDTH)
return False
while 1:
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 = {}
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 = session['image'].out
out.add(gauge)
try:
- out.output("Registering image with Cyclades...")
try:
+ out.output("Registering %s image with Cyclades..." % img_type)
kamaki = Kamaki(session['account'], out)
- kamaki.register(name, session['pithos_uri'], metadata)
+ kamaki.register(name, session['pithos_uri'], metadata,
+ is_public)
out.success('done')
+ # Upload metadata file
+ out.output("Uploading metadata file...")
+ metastring = extract_metadata_string(session)
+ kamaki.upload(StringIO.StringIO(metastring),
+ size=len(metastring),
+ remote_path="%s.meta" % session['upload'])
+ out.success("done")
+ if is_public:
+ out.output("Sharing metadata and md5sum files...")
+ kamaki.share("%s.meta" % session['upload'])
+ kamaki.share("%s.md5sum" % session['upload'])
+ out.success('done')
except ClientError as e:
d.msgbox("Error in pithos+ client: %s" % e.message)
return False
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
def kamaki_menu(session):
+ """Show kamaki related actions"""
d = session['dialog']
default_item = "Account"
if choice == "Account":
default_item = "Account"
(code, answer) = d.inputbox(
- "Please provide your ~okeanos token:",
+ "Please provide your ~okeanos authentication token:",
init=session["account"]['auth_token'] if "account" in session
else '', width=WIDTH)
if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
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"
def add_property(session):
+ """Add a new property to the image"""
d = session['dialog']
while 1:
def modify_properties(session):
+ """Modify an existing image property"""
d = session['dialog']
while 1:
def delete_properties(session):
+ """Delete an image property"""
d = session['dialog']
choices = []
def exclude_tasks(session):
+ """Exclude specific tasks from running during image deployment"""
d = session['dialog']
index = 0
def sysprep(session):
+ """Perform various system preperation tasks on the image"""
d = session['dialog']
- image_os = session['image_os']
+ image = session['image']
# Is the image already shrinked?
if 'shrinked' in session and session['shrinked']:
help_title = "System Preperation Tasks"
sysprep_help = "%s\n%s\n\n" % (help_title, '=' * len(help_title))
- if 'exec_syspreps' not in session:
- session['exec_syspreps'] = []
-
- all_syspreps = image_os.list_syspreps()
- # Only give the user the choice between syspreps that have not ran yet
- syspreps = [s for s in all_syspreps if s not in session['exec_syspreps']]
+ syspreps = image.os.list_syspreps()
if len(syspreps) == 0:
d.msgbox("No system preparation task available to run!",
choices = []
index = 0
for sysprep in syspreps:
- name, descr = image_os.sysprep_info(sysprep)
+ name, descr = image.os.sysprep_info(sysprep)
display_name = name.replace('-', ' ').capitalize()
sysprep_help += "%s\n" % display_name
sysprep_help += "%s\n" % ('-' * len(display_name))
# Enable selected syspreps and disable the rest
for i in range(len(syspreps)):
if str(i + 1) in tags:
- image_os.enable_sysprep(syspreps[i])
- session['exec_syspreps'].append(syspreps[i])
+ image.os.enable_sysprep(syspreps[i])
else:
- image_os.disable_sysprep(syspreps[i])
+ image.os.disable_sysprep(syspreps[i])
+
+ if len([s for s in image.os.list_syspreps() if s.enabled]) == 0:
+ d.msgbox("No system preperation task is selected!",
+ title="System Preperation", width=SMALL_WIDTH)
+ continue
infobox = InfoBoxOutput(d, "Image Configuration")
try:
- dev = session['device']
- dev.out.add(infobox)
+ image.out.add(infobox)
try:
- dev.mount(readonly=False)
+ image.mount(readonly=False)
try:
+ err = "Unable to execute the system preparation " \
+ "tasks. Couldn't mount the media%s."
+ title = "System Preparation"
+ if not image.mounted:
+ d.msgbox(err % "", title=title, width=SMALL_WIDTH)
+ return
+ elif image.mounted_ro:
+ d.msgbox(err % " read-write", title=title,
+ width=SMALL_WIDTH)
+ return
+
# The checksum is invalid. We have mounted the image rw
if 'checksum' in session:
del session['checksum']
# Monitor the metadata changes during syspreps
- with metadata_monitor(session, image_os.meta):
- image_os.do_sysprep()
+ with MetadataMonitor(session, image.os.meta):
+ image.os.do_sysprep()
infobox.finalize()
- # Disable syspreps that have ran
- for sysprep in session['exec_syspreps']:
- image_os.disable_sysprep(sysprep)
finally:
- dev.umount()
+ image.umount()
finally:
- dev.out.remove(infobox)
+ image.out.remove(infobox)
finally:
infobox.cleanup()
break
def shrink(session):
+ """Shrink the image"""
d = session['dialog']
- dev = session['device']
+ image = session['image']
shrinked = 'shrinked' in session and session['shrinked']
if not d.yesno("%s\n\nDo you want to continue?" % msg, width=WIDTH,
height=12, title="Image Shrinking"):
- with metadata_monitor(session, dev.meta):
+ with MetadataMonitor(session, image.meta):
infobox = InfoBoxOutput(d, "Image Shrinking", height=4)
- dev.out.add(infobox)
+ image.out.add(infobox)
try:
- dev.shrink()
+ image.shrink()
infobox.finalize()
finally:
- dev.out.remove(infobox)
+ image.out.remove(infobox)
session['shrinked'] = True
update_background_title(session)
def customization_menu(session):
+ """Show image customization menu"""
d = session['dialog']
choices = [("Sysprep", "Run various image preparation tasks"),
def main_menu(session):
+ """Show the main menu of the program"""
d = session['dialog']
- dev = session['device']
update_background_title(session)
d.infobox("Resetting snf-image-creator. Please wait...",
width=SMALL_WIDTH)
raise Reset
+ elif choice == "Help":
+ d.msgbox("For help, check the online documentation:\n\nhttp://www"
+ ".synnefo.org/docs/snf-image-creator/latest/",
+ width=WIDTH, title="Help")
elif choice in actions:
actions[choice](session)