예제 #1
0
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
            else:
                # Select the newly added cloud
                session['current_cloud'] = Kamaki.get_clouds().keys()[0]
            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 <Edit> to edit an existing account or <Add> to add "
            " a new one. Press <Back> or hit <ESC> when done.", height=18,
            width=WIDTH, choices=choices, menu_height=10, ok_label="Edit",
            extra_button=1, extra_label="Add", cancel="Back", title="Clouds")

        if code in (d.CANCEL, d.ESC):
            return True
        elif code == d.OK:  # Edit button
            edit_cloud(session, choice)
        elif code == d.EXTRA:  # Add button
            add_cloud(session)
예제 #2
0
def _check_cloud(session, name, url, token):
    """Checks if the provided info for a cloud are valid"""
    d = session['dialog']
    regexp = re.compile(r'^[~@#$:\-\w]+$')

    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
예제 #3
0
    def cloud_choices():
        """Returns the available clouds"""
        choices = []
        for (name, cloud) in Kamaki.get_clouds().items():
            descr = cloud['description'] if 'description' in cloud else ''
            choices.append((name, descr))

        return choices
예제 #4
0
    def cloud_choices():
        """Returns the available clouds"""
        choices = []
        for (name, cloud) in Kamaki.get_clouds().items():
            descr = cloud['description'] if 'description' in cloud else ''
            choices.append((name, descr))

        return choices
예제 #5
0
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:",
                                create_form_elements(fields),
                                height=13,
                                width=WIDTH,
                                form_height=4)

        if code in (d.CANCEL, d.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, 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
예제 #6
0
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:",
                                create_form_elements(fields), height=13,
                                width=WIDTH, form_height=4)

        if code in (d.CANCEL, d.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, 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
예제 #7
0
 def cloud_validate(cloud):
     """Checks if a cloud is valid"""
     if not Kamaki.get_account(cloud):
         if session['dialog'].yesno(
                 "The cloud you have selected is not valid! Would you "
                 "like to edit it now?", width=PAGE_WIDTH,
                 defaultno=0) == session['dialog'].OK:
             if edit_cloud(session, cloud):
                 return cloud
         raise WizardReloadPage
     return cloud
예제 #8
0
 def cloud_validate(cloud):
     """Checks if a cloud is valid"""
     if not Kamaki.get_account(cloud):
         if session['dialog'].yesno(
                 "The cloud you have selected is not valid! Would you "
                 "like to edit it now?",
                 width=PAGE_WIDTH,
                 defaultno=0) == session['dialog'].OK:
             if edit_cloud(session, cloud):
                 return cloud
         raise WizardReloadPage
     return cloud
예제 #9
0
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)
    to_delete = [x.strip('"') for x in to_delete]  # Needed for OpenSUSE

    if code in (d.CANCEL, d.ESC):
        return False

    if not len(to_delete):
        d.msgbox("Nothing selected!", width=SMALL_WIDTH)
        return False

    if d.yesno("Are you sure you want to remove the selected accounts?",
               width=WIDTH,
               defaultno=1) == d.OK:
        for i in to_delete:
            Kamaki.remove_cloud(i)
            if i in session['clouds']:
                del session['clouds'][i]
            if 'current_cloud' in session and session['current_cloud'] == i:
                del session['current_cloud']
    else:
        return False

    d.msgbox("%d cloud accounts were deleted." % len(to_delete),
             width=SMALL_WIDTH)
    return True
예제 #10
0
def edit_cloud(session, name):
    """Edit a cloud account"""

    info = Kamaki.get_cloud_by_name(name)

    assert info, "Cloud: `%s' does not exist" % name

    description = info['description'] if 'description' in info else ""
    url = info['url'] if 'url' in info else ""
    token = info['token'] if 'token' in info else ""

    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,
                                create_form_elements(fields),
                                height=13,
                                width=WIDTH,
                                form_height=3)

        if code in (d.CANCEL, d.ESC):
            return False

        description, url, token = output

        description = description.strip()
        url = url.strip()
        token = token.strip()

        if _check_cloud(session, name, url, token):
            Kamaki.save_cloud(name, url, token, description)
            break

        continue

    return True
예제 #11
0
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
            else:
                # Select the newly added cloud
                session['current_cloud'] = Kamaki.get_clouds().keys()[0]
            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 <Edit> to edit an existing account or <Add> to add "
            " a new one. Press <Back> or hit <ESC> when done.",
            height=18,
            width=WIDTH,
            choices=choices,
            menu_height=10,
            ok_label="Edit",
            extra_button=1,
            extra_label="Add",
            cancel="Back",
            title="Clouds")

        if code in (d.CANCEL, d.ESC):
            return True
        elif code == d.OK:  # Edit button
            edit_cloud(session, choice)
        elif code == d.EXTRA:  # Add button
            add_cloud(session)
예제 #12
0
def edit_cloud(session, name):
    """Edit a cloud account"""

    info = Kamaki.get_cloud_by_name(name)

    assert info, "Cloud: `%s' does not exist" % name

    description = info['description'] if 'description' in info else ""
    url = info['url'] if 'url' in info else ""
    token = info['token'] if 'token' in info else ""

    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,
                                create_form_elements(fields), height=13,
                                width=WIDTH, form_height=3)

        if code in (d.CANCEL, d.ESC):
            return False

        description, url, token = output

        description = description.strip()
        url = url.strip()
        token = token.strip()

        if _check_cloud(session, name, url, token):
            Kamaki.save_cloud(name, url, token, description)
            break

        continue

    return True
예제 #13
0
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)
    to_delete = [x.strip('"') for x in to_delete]  # Needed for OpenSUSE

    if code in (d.CANCEL, d.ESC):
        return False

    if not len(to_delete):
        d.msgbox("Nothing selected!", width=SMALL_WIDTH)
        return False

    if d.yesno("Are you sure you want to remove the selected accounts?",
               width=WIDTH, defaultno=1) == d.OK:
        for i in to_delete:
            Kamaki.remove_cloud(i)
            if i in session['clouds']:
                del session['clouds'][i]
            if 'current_cloud' in session and session['current_cloud'] == i:
                del session['current_cloud']
    else:
        return False

    d.msgbox("%d cloud accounts were deleted." % len(to_delete),
             width=SMALL_WIDTH)
    return True
예제 #14
0
def select_cloud(session):
    """Select one of the existing cloud accounts"""
    d = session['dialog']

    clouds = Kamaki.get_clouds()
    if not len(clouds):
        d.msgbox("No clouds available. Please add a new cloud!",
                 width=SMALL_WIDTH)
        return False

    try:
        current = session['current_cloud']
    except KeyError:
        current = clouds.keys()[0]
        session['current_cloud'] = current

    choices = []
    for name, info in clouds.items():
        default = 1 if current == 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.CANCEL, d.ESC):
        return True

    if answer not in session['clouds']:
        session['clouds'][answer] = {}

    cloud = session['clouds'][answer]
    cloud['account'] = Kamaki.get_account(answer)

    if cloud['account'] is None:  # invalid account
        if d.yesno("The cloud %s' is not valid! Would you like to edit it?" %
                   answer,
                   width=WIDTH) == d.OK:
            if edit_cloud(session, answer):
                session['current_cloud'] = answer
                cloud['account'] = Kamaki.get_account(answer)
                Kamaki.set_default_cloud(answer)

    if cloud['account'] is not None:
        session['current_cloud'] = answer
        Kamaki.set_default_cloud(answer)
        return True
    else:
        del cloud['account']
        del session['current_cloud']
예제 #15
0
def select_cloud(session):
    """Select one of the existing cloud accounts"""
    d = session['dialog']

    clouds = Kamaki.get_clouds()
    if not len(clouds):
        d.msgbox("No clouds available. Please add a new cloud!",
                 width=SMALL_WIDTH)
        return False

    try:
        current = session['current_cloud']
    except KeyError:
        current = clouds.keys()[0]
        session['current_cloud'] = current

    choices = []
    for name, info in clouds.items():
        default = 1 if current == 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.CANCEL, d.ESC):
        return True

    if answer not in session['clouds']:
        session['clouds'][answer] = {}

    cloud = session['clouds'][answer]
    cloud['account'] = Kamaki.get_account(answer)

    if cloud['account'] is None:  # invalid account
        if d.yesno("The cloud %s' is not valid! Would you like to edit it?"
                   % answer, width=WIDTH) == d.OK:
            if edit_cloud(session, answer):
                session['current_cloud'] = answer
                cloud['account'] = Kamaki.get_account(answer)
                Kamaki.set_default_cloud(answer)

    if cloud['account'] is not None:
        session['current_cloud'] = answer
        Kamaki.set_default_cloud(answer)
        return True
    else:
        del cloud['account']
        del session['current_cloud']
예제 #16
0
def _check_cloud(session, name, url, token):
    """Checks if the provided info for a cloud are valid"""
    d = session['dialog']
    regexp = re.compile(r'^[~@#$:\-\w]+$')

    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
예제 #17
0
def kamaki_menu(session):
    """Show kamaki related actions"""
    d = session['dialog']

    try:
        clouds = session['clouds']
    except KeyError:
        clouds = {}
        session['clouds'] = clouds

    default_item = "Add/Edit"

    try:
        current = session['current_cloud']
    except KeyError:
        current = Kamaki.get_default_cloud_name()
        if not current:
            try:
                current = Kamaki.get_clouds().keys()[0]
            except IndexError:
                # No available cloud
                pass
        session['current_cloud'] = current

    if current:
        if current not in clouds:
            clouds[current] = {}

        try:
            account = clouds[current]['account']
        except KeyError:
            account = Kamaki.get_account(current)
            clouds[current]['account'] = account

        if account:
            if 'registered' in clouds[current]:
                default_item = "Info"
            elif 'uploaded' in clouds[current]:
                default_item = "Register"
            else:
                default_item = "Upload"

    while 1:
        current = session['current_cloud'] if 'current_cloud' in session else \
            None
        if current:
            if current not in session['clouds']:
                session['clouds'][current] = {}

            cloud = current
            if 'account' not in clouds[current]:
                clouds[current]['account'] = Kamaki.get_account(current)
                if not clouds[current]['account']:
                    cloud += " <invalid>"
        else:
            cloud = '<none>'

        choices = [("Add/Edit", "Add/Edit cloud accounts"),
                   ("Delete", "Delete existing cloud accounts"),
                   ("Cloud", "Select cloud account to use: %s" % cloud),
                   ("Upload", "Upload image to the cloud")]

        if current and 'uploaded' in clouds[current]:
            _, _, _, _, name = clouds[current]['uploaded'].split('/')
            choices.append(("Register", "Register image with the cloud: %s"
                            % name))
        if current and 'registered' in clouds[current]:
            choices.append(("Info", "Show registration info for \"%s\"" %
                            clouds[current]['registered']['name']))

        (code, choice) = d.menu(
            text="Choose one of the following or press <Back> to go back.",
            width=WIDTH, choices=choices, cancel="Back", height=8+len(choices),
            menu_height=len(choices), default_item=default_item,
            title="Image Registration Menu")

        if code in (d.CANCEL, d.ESC):
            return False

        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_item = "Add/Edit"
            else:
                default_item = "Delete"
        elif choice == "Cloud":
            if select_cloud(session):
                default_item = "Cloud"
            else:
                default_item = 'Add/Edit'
        elif choice == "Upload":
            if upload_image(session):
                default_item = "Register"
            else:
                default_item = "Upload"
        elif choice == "Register":
            if register_image(session):
                default_item = "Info"
            else:
                default_item = "Register"
        elif choice == "Info":
            show_info(session)
예제 #18
0
def register_image(session):
    """Register image with the compute service"""
    d = session["dialog"]
    image = session['image']

    assert 'clouds' in session

    try:
        cloud_name = session['current_cloud']
        cloud = session['clouds'][cloud_name]
        account = cloud['account']
    except KeyError:
        cloud = None

    if cloud is None or account is None:
        d.msgbox("You need to select a valid cloud before you can register an "
                 "images with it", width=SMALL_WIDTH)
        return False

    if "uploaded" not in cloud:
        d.msgbox("You need to upload the image to a cloud before you can "
                 "register it", width=SMALL_WIDTH)
        return False

    is_public = False
    _, _, _, container, remote = cloud['uploaded'].split('/')
    name = "" if 'registered' not in cloud else cloud['registered']
    descr = image.meta['DESCRIPTION'] if 'DESCRIPTION' in image.meta else ""

    while 1:
        fields = [("Registration name:", name, 60),
                  ("Description (optional):", descr, 80)]

        (code, output) = d.form(
            "Please provide the following registration info:",
            create_form_elements(fields), height=11, width=WIDTH,
            form_height=2)

        if code in (d.CANCEL, d.ESC):
            return False

        name, descr = output
        name = name.strip()
        descr = descr.strip()

        if len(name) == 0:
            d.msgbox("Registration name cannot be empty", width=SMALL_WIDTH)
            continue

        answer = d.yesno("Make the image public?\\nA public image is "
                         "accessible by every user of the service.",
                         defaultno=1, width=WIDTH)
        if answer == d.ESC:
            continue

        is_public = (answer == d.OK)
        break

    image.meta['DESCRIPTION'] = descr
    metadata = {}
    metadata.update(image.meta)
    if 'task_metadata' in 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 = session['image'].out
        out.append(gauge)
        try:
            try:
                out.info("Registering %s image with the cloud ..." % img_type,
                         False)
                kamaki = Kamaki(cloud['account'], out)
                cloud['registered'] = kamaki.register(
                    name, cloud['uploaded'], metadata, is_public)
                out.success('done')

                # Upload metadata file
                out.info("Uploading metadata file ...", False)
                metastring = json.dumps(cloud['registered'], indent=4,
                                        ensure_ascii=False)
                kamaki.upload(StringIO.StringIO(metastring),
                              size=len(metastring),
                              remote_path="%s.meta" % remote,
                              container=container,
                              content_type="application/json")
                out.success("done")
                if is_public:
                    out.info("Sharing metadata and md5sum files ...", False)
                    kamaki.share("%s.meta" % remote)
                    kamaki.share("%s.md5sum" % remote)
                    out.success('done')
            except ClientError as error:
                d.msgbox("Error in storage service client: %s" % error.message)
                return False
        finally:
            out.remove(gauge)
    finally:
        gauge.cleanup()

    d.msgbox("%s image `%s' was successfully registered with the cloud as `%s'"
             % (img_type.title(), remote, name), width=SMALL_WIDTH)
    return True
예제 #19
0
def upload_image(session):
    """Upload the image to the storage service"""
    d = session["dialog"]
    image = session['image']

    assert 'clouds' in session

    try:
        cloud_name = session['current_cloud']
        cloud = session['clouds'][cloud_name]
        account = cloud['account']
    except KeyError:
        cloud = None

    if cloud is None or not account:
        d.msgbox("You need to select a valid cloud before you can upload "
                 "images to it", width=SMALL_WIDTH)
        return False

    while 1:
        if 'uploaded' in cloud:
            _, _, _, container, name = cloud['uploaded'].split('/')
        elif 'OS' in session['image'].meta:
            name = "%s.diskdump" % session['image'].meta['OS']
            container = CONTAINER
        else:
            name = ""
            container = CONTAINER

        fields = [("Remote Name:", name, 60), ("Container:", container, 60)]

        (code, output) = d.form("Please provide the following upload info:",
                                create_form_elements(fields), height=11,
                                width=WIDTH, form_height=2)

        if code in (d.CANCEL, d.ESC):
            return False

        name, container = output
        name = name.strip()
        container = container.strip()

        if len(name) == 0:
            d.msgbox("Remote Name cannot be empty", width=SMALL_WIDTH)
            continue

        if len(container) == 0:
            d.msgbox("Container cannot be empty", width=SMALL_WIDTH)
            continue

        kamaki = Kamaki(cloud['account'], None)
        overwrite = []
        for f in (name, "%s.md5sum" % name, "%s.meta" % name):
            if kamaki.object_exists(container, f):
                overwrite.append(f)

        if len(overwrite) > 0:
            if d.yesno("The following storage service object(s) already "
                       "exist(s):\n%s\nDo you want to overwrite them?" %
                       "\n".join(overwrite), width=WIDTH, defaultno=1
                       ) != d.OK:
                continue
        break

    gauge = GaugeOutput(d, "Image Upload", "Uploading ...")
    try:
        out = image.out
        out.append(gauge)
        kamaki.out = out
        try:
            if 'checksum' not in session:
                session['checksum'] = image.md5()

            try:
                # Upload image file
                with image.raw_device() as raw:
                    with open(raw, 'rb') as f:
                        cloud["uploaded"] = \
                            kamaki.upload(f, image.size, name, container, None,
                                          "Calculating block hashes",
                                          "Uploading missing blocks")
                # Upload md5sum file
                out.info("Uploading md5sum file ...")
                md5str = "%s %s\n" % (session['checksum'], name)
                kamaki.upload(StringIO.StringIO(md5str), size=len(md5str),
                              remote_path="%s.md5sum" % name,
                              container=container,
                              content_type="text/plain")
                out.success("done")

            except ClientError as e:
                d.msgbox(
                    "Error in storage service client: %s" % e.message,
                    title="Storage Service Client Error", width=SMALL_WIDTH)
                if 'uploaded' in cloud:
                    del cloud['uploaded']
                return False
        finally:
            out.remove(gauge)
    finally:
        gauge.cleanup()

    d.msgbox("Image file `%s' was successfully uploaded" % name,
             width=SMALL_WIDTH)

    return True
예제 #20
0
def upload_image(session):
    """Upload the image to the storage service"""
    d = session["dialog"]
    image = session['image']

    assert 'clouds' in session

    try:
        cloud_name = session['current_cloud']
        cloud = session['clouds'][cloud_name]
        account = cloud['account']
    except KeyError:
        cloud = None

    if cloud is None or not account:
        d.msgbox(
            "You need to select a valid cloud before you can upload "
            "images to it",
            width=SMALL_WIDTH)
        return False

    while 1:
        if 'uploaded' in cloud:
            _, _, _, container, name = cloud['uploaded'].split('/')
        elif 'OS' in session['image'].meta:
            name = "%s.diskdump" % session['image'].meta['OS']
            container = CONTAINER
        else:
            name = ""
            container = CONTAINER

        fields = [("Remote Name:", name, 60), ("Container:", container, 60)]

        (code, output) = d.form("Please provide the following upload info:",
                                create_form_elements(fields),
                                height=11,
                                width=WIDTH,
                                form_height=2)

        if code in (d.CANCEL, d.ESC):
            return False

        name, container = output
        name = name.strip()
        container = container.strip()

        if len(name) == 0:
            d.msgbox("Remote Name cannot be empty", width=SMALL_WIDTH)
            continue

        if len(container) == 0:
            d.msgbox("Container cannot be empty", width=SMALL_WIDTH)
            continue

        kamaki = Kamaki(cloud['account'], None)
        overwrite = []
        for f in (name, "%s.md5sum" % name, "%s.meta" % name):
            if kamaki.object_exists(container, f):
                overwrite.append(f)

        if len(overwrite) > 0:
            if d.yesno("The following storage service object(s) already "
                       "exist(s):\n%s\nDo you want to overwrite them?" %
                       "\n".join(overwrite),
                       width=WIDTH,
                       defaultno=1) != d.OK:
                continue
        break

    gauge = GaugeOutput(d, "Image Upload", "Uploading ...")
    try:
        out = image.out
        out.append(gauge)
        kamaki.out = out
        try:
            if 'checksum' not in session:
                session['checksum'] = image.md5()

            try:
                # Upload image file
                with image.raw_device() as raw:
                    with open(raw, 'rb') as f:
                        cloud["uploaded"] = \
                            kamaki.upload(f, image.size, name, container, None,
                                          "Calculating block hashes",
                                          "Uploading missing blocks")
                # Upload md5sum file
                out.info("Uploading md5sum file ...")
                md5str = "%s %s\n" % (session['checksum'], name)
                kamaki.upload(StringIO.StringIO(md5str),
                              size=len(md5str),
                              remote_path="%s.md5sum" % name,
                              container=container,
                              content_type="text/plain")
                out.success("done")

            except ClientError as e:
                d.msgbox("Error in storage service client: %s" % e.message,
                         title="Storage Service Client Error",
                         width=SMALL_WIDTH)
                if 'uploaded' in cloud:
                    del cloud['uploaded']
                return False
        finally:
            out.remove(gauge)
    finally:
        gauge.cleanup()

    d.msgbox("Image file `%s' was successfully uploaded" % name,
             width=SMALL_WIDTH)

    return True
예제 #21
0
def kamaki_menu(session):
    """Show kamaki related actions"""
    d = session['dialog']

    try:
        clouds = session['clouds']
    except KeyError:
        clouds = {}
        session['clouds'] = clouds

    default_item = "Add/Edit"

    try:
        current = session['current_cloud']
    except KeyError:
        current = Kamaki.get_default_cloud_name()
        if not current:
            try:
                current = Kamaki.get_clouds().keys()[0]
            except IndexError:
                # No available cloud
                pass
        session['current_cloud'] = current

    if current:
        if current not in clouds:
            clouds[current] = {}

        try:
            account = clouds[current]['account']
        except KeyError:
            account = Kamaki.get_account(current)
            clouds[current]['account'] = account

        if account:
            if 'registered' in clouds[current]:
                default_item = "Info"
            elif 'uploaded' in clouds[current]:
                default_item = "Register"
            else:
                default_item = "Upload"

    while 1:
        current = session['current_cloud'] if 'current_cloud' in session else \
            None
        if current:
            if current not in session['clouds']:
                session['clouds'][current] = {}

            cloud = current
            if 'account' not in clouds[current]:
                clouds[current]['account'] = Kamaki.get_account(current)
                if not clouds[current]['account']:
                    cloud += " <invalid>"
        else:
            cloud = '<none>'

        choices = [("Add/Edit", "Add/Edit cloud accounts"),
                   ("Delete", "Delete existing cloud accounts"),
                   ("Cloud", "Select cloud account to use: %s" % cloud),
                   ("Upload", "Upload image to the cloud")]

        if current and 'uploaded' in clouds[current]:
            _, _, _, _, name = clouds[current]['uploaded'].split('/')
            choices.append(
                ("Register", "Register image with the cloud: %s" % name))
        if current and 'registered' in clouds[current]:
            choices.append(("Info", "Show registration info for \"%s\"" %
                            clouds[current]['registered']['name']))

        (code, choice) = d.menu(
            text="Choose one of the following or press <Back> to go back.",
            width=WIDTH,
            choices=choices,
            cancel="Back",
            height=8 + len(choices),
            menu_height=len(choices),
            default_item=default_item,
            title="Image Registration Menu")

        if code in (d.CANCEL, d.ESC):
            return False

        if choice == "Add/Edit":
            if modify_clouds(session):
                if len(Kamaki.get_clouds()) == 1:
                    default_item = "Upload"
                else:
                    default_item = "Cloud"
        elif choice == "Delete":
            if delete_clouds(session):
                if len(Kamaki.get_clouds()):
                    default_item = "Cloud"
                else:
                    default_item = "Add/Edit"
            else:
                default_item = "Delete"
        elif choice == "Cloud":
            if select_cloud(session):
                default_item = "Cloud"
            else:
                default_item = 'Add/Edit'
        elif choice == "Upload":
            if upload_image(session):
                default_item = "Register"
            else:
                default_item = "Upload"
        elif choice == "Register":
            if register_image(session):
                default_item = "Info"
            else:
                default_item = "Register"
        elif choice == "Info":
            show_info(session)
예제 #22
0
def image_creator(options, out):
    """snf-mkimage main function"""

    if os.geteuid() != 0:
        raise FatalError("You must run %s as root"
                         % os.path.basename(sys.argv[0]))

    # Check if the authentication info is valid. The earlier the better
    if options.token is not None and options.url is not None:
        try:
            account = Kamaki.create_account(options.url, options.token)
            if account is None:
                raise FatalError("The authentication token and/or URL you "
                                 "provided is not valid!")
            else:
                kamaki = Kamaki(account, out)
        except ClientError as e:
            raise FatalError("Astakos client: %d %s" % (e.status, e.message))
    elif options.cloud:
        avail_clouds = Kamaki.get_clouds()
        if options.cloud not in avail_clouds.keys():
            raise FatalError(
                "Cloud: `%s' does not exist.\n\nAvailable clouds:\n\n\t%s\n"
                % (options.cloud, "\n\t".join(avail_clouds.keys())))
        try:
            account = Kamaki.get_account(options.cloud)
            if account is None:
                raise FatalError(
                    "Cloud: `%s' exists but is not valid!" % options.cloud)
            else:
                kamaki = Kamaki(account, out)
        except ClientError as e:
            raise FatalError("Astakos client: %d %s" % (e.status, e.message))

    if options.upload and not options.force:
        if kamaki.object_exists(options.container, options.upload):
            raise FatalError("Remote storage service object: `%s' exists "
                             "(use --force to overwrite it)." % options.upload)
        if kamaki.object_exists(options.container,
                                "%s.md5sum" % options.upload):
            raise FatalError("Remote storage service object: `%s.md5sum' "
                             "exists (use --force to overwrite it)." %
                             options.upload)

    if options.register and not options.force:
        if kamaki.object_exists(options.container, "%s.meta" % options.upload):
            raise FatalError("Remote storage service object `%s.meta' exists "
                             "(use --force to overwrite it)." % options.upload)

    disk = Disk(options.source, out, options.tmp)

    # pylint: disable=unused-argument
    def signal_handler(signum, frame):
        disk.cleanup()

    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)
    try:
        # There is no need to snapshot the media if it was created by the Disk
        # instance as a temporary object.
        device = disk.file if not options.snapshot else disk.snapshot()
        image = disk.get_image(device, sysprep_params=options.sysprep_params)

        if image.is_unsupported() and not options.allow_unsupported:
            raise FatalError(
                "The media seems to be unsupported.\n\n" +
                textwrap.fill("To create an image from an unsupported media, "
                              "you'll need to use the`--allow-unsupported' "
                              "command line option. Using this is highly "
                              "discouraged, since the resulting image will "
                              "not be cleared out of sensitive data and will "
                              "not get customized during the deployment."))

        if len(options.host_run) != 0 and not image.mount_local_support:
            raise FatalError("Running scripts against the guest media is not "
                             "supported for this build of libguestfs.")

        if len(options.host_run) != 0:
            for script in options.host_run:
                if not os.path.isfile(script):
                    raise FatalError("File: `%s' does not exist." % script)
                if not os.access(script, os.X_OK):
                    raise FatalError("File: `%s' is not executable." % script)

        for name in options.disabled_syspreps:
            sysprep = image.os.get_sysprep_by_name(name)
            if sysprep is not None:
                image.os.disable_sysprep(sysprep)
            else:
                out.warn("Sysprep: `%s' does not exist. Can't disable it." %
                         name)

        for name in options.enabled_syspreps:
            sysprep = image.os.get_sysprep_by_name(name)
            if sysprep is not None:
                image.os.enable_sysprep(sysprep)
            else:
                out.warn("Sysprep: `%s' does not exist. Can't enable it." %
                         name)
        if image.is_unsupported():
            image.meta['EXCLUDE_ALL_TASKS'] = "yes"

        # Add command line metadata to the collected ones...
        image.meta.update(options.metadata)

        if options.print_syspreps:
            image.os.print_syspreps()
            out.info()

        if options.print_sysprep_params:
            image.os.print_sysprep_params()
            out.info()

        if options.print_metadata:
            image.os.print_metadata()
            out.info()

        if options.outfile is None and not options.upload:
            return 0

        if options.virtio is not None and \
                hasattr(image.os, 'install_virtio_drivers'):
            image.os.install_virtio_drivers()

        if len(options.host_run) != 0:
            # Export image metadata as environment variables to make them
            # visible by the scripts
            for key, value in image.meta.items():
                os.environ["SNF_IMAGE_CREATOR_METADATA_%s" % key] = str(value)

            out.info("Running scripts on the input media:")
            mpoint = tempfile.mkdtemp()
            try:
                image.mount(mpoint)
                if not image.is_mounted():
                    raise FatalError("Mounting the media on the host failed.")
                try:
                    size = len(options.host_run)
                    cnt = 1
                    for script in options.host_run:
                        script = os.path.abspath(script)
                        out.info(("(%d/%d)" % (cnt, size)).ljust(7), False)
                        out.info("Running `%s'" % script)
                        ret = subprocess.Popen([script], cwd=mpoint).wait()
                        if ret != 0:
                            raise FatalError("Script: `%s' failed (rc=%d)" %
                                             (script, ret))
                        cnt += 1
                finally:
                    while not image.umount():
                        out.warn("Unable to umount the media. Retrying ...")
                        time.sleep(1)
                    out.info()
            finally:
                os.rmdir(mpoint)

        if options.sysprep:
            image.os.do_sysprep()

        checksum = image.md5()

        image_meta = {}
        for k, v in image.meta.items():
            image_meta[str(k)] = str(v)

        metastring = json.dumps(
            {'properties': image_meta, 'disk-format': 'diskdump'},
            ensure_ascii=False)

        img_properties = json.dumps(image_meta, ensure_ascii=False)

        if options.outfile is not None:
            if os.path.realpath(options.outfile) == '/dev/null':
                out.warn('Not dumping file to /dev/null')
            else:
                image.dump(options.outfile)

                out.info('Dumping metadata file ...', False)
                with open('%s.%s' % (options.outfile, 'meta'), 'w') as f:
                    f.write(metastring)
                out.success('done')

                out.info('Dumping md5sum file ...', False)
                with open('%s.%s' % (options.outfile, 'md5sum'), 'w') as f:
                    f.write('%s %s\n' % (checksum,
                                         os.path.basename(options.outfile)))
                out.success('done')

                out.info('Dumping variant file ...', False)
                with open('%s.%s' % (options.outfile, 'variant'), 'w') as f:
                    f.write(to_shell(IMG_ID=options.outfile,
                                     IMG_FORMAT="diskdump",
                                     IMG_PROPERTIES=img_properties))
                out.success('done')

        out.info()
        try:
            if options.upload:
                out.info("Uploading image to the storage service:")
                with image.raw_device() as raw:
                    with open(raw, 'rb') as f:
                        remote = kamaki.upload(
                            f, image.size, options.upload, options.container,
                            None, "(1/3)  Calculating block hashes",
                            "(2/3)  Uploading missing blocks")

                out.info("(3/3)  Uploading md5sum file ...", False)
                md5sumstr = '%s %s\n' % (checksum,
                                         os.path.basename(options.upload))
                kamaki.upload(StringIO.StringIO(md5sumstr),
                              size=len(md5sumstr),
                              remote_path="%s.%s" % (options.upload, 'md5sum'),
                              container=options.container,
                              content_type="text/plain")
                out.success('done')
                out.info()

            if options.register:
                img_type = 'public' if options.public else 'private'
                out.info('Registering %s image with the compute service ...'
                         % img_type, False)
                result = kamaki.register(options.register, remote,
                                         image.meta, options.public)
                out.success('done')
                out.info("Uploading metadata file ...", False)
                metastring = unicode(json.dumps(result, ensure_ascii=False,
                                                indent=4))
                kamaki.upload(StringIO.StringIO(metastring.encode('utf8')),
                              size=len(metastring),
                              remote_path="%s.%s" % (options.upload, 'meta'),
                              container=options.container,
                              content_type="application/json")
                out.success('done')
                if options.public:
                    out.info("Sharing md5sum file ...", False)
                    kamaki.share("%s.md5sum" % options.upload)
                    out.success('done')
                    out.info("Sharing metadata file ...", False)
                    kamaki.share("%s.meta" % options.upload)
                    out.success('done')
                out.result(json.dumps(result, indent=4, ensure_ascii=False))
                out.info()
        except ClientError as e:
            raise FatalError("Service client: %d %s" % (e.status, e.message))

    finally:
        out.info('cleaning up ...')
        disk.cleanup()

    out.success("snf-image-creator exited without errors")

    return 0
예제 #23
0
def register_image(session):
    """Register image with the compute service"""
    d = session["dialog"]
    image = session['image']

    assert 'clouds' in session

    try:
        cloud_name = session['current_cloud']
        cloud = session['clouds'][cloud_name]
        account = cloud['account']
    except KeyError:
        cloud = None

    if cloud is None or account is None:
        d.msgbox(
            "You need to select a valid cloud before you can register an "
            "images with it",
            width=SMALL_WIDTH)
        return False

    if "uploaded" not in cloud:
        d.msgbox(
            "You need to upload the image to a cloud before you can "
            "register it",
            width=SMALL_WIDTH)
        return False

    is_public = False
    _, _, _, container, remote = cloud['uploaded'].split('/')
    name = "" if 'registered' not in cloud else cloud['registered']
    descr = image.meta['DESCRIPTION'] if 'DESCRIPTION' in image.meta else ""

    while 1:
        fields = [("Registration name:", name, 60),
                  ("Description (optional):", descr, 80)]

        (code,
         output) = d.form("Please provide the following registration info:",
                          create_form_elements(fields),
                          height=11,
                          width=WIDTH,
                          form_height=2)

        if code in (d.CANCEL, d.ESC):
            return False

        name, descr = output
        name = name.strip()
        descr = descr.strip()

        if len(name) == 0:
            d.msgbox("Registration name cannot be empty", width=SMALL_WIDTH)
            continue

        answer = d.yesno(
            "Make the image public?\\nA public image is "
            "accessible by every user of the service.",
            defaultno=1,
            width=WIDTH)
        if answer == d.ESC:
            continue

        is_public = (answer == d.OK)
        break

    image.meta['DESCRIPTION'] = descr
    metadata = {}
    metadata.update(image.meta)
    if 'task_metadata' in 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 = session['image'].out
        out.append(gauge)
        try:
            try:
                out.info("Registering %s image with the cloud ..." % img_type,
                         False)
                kamaki = Kamaki(cloud['account'], out)
                cloud['registered'] = kamaki.register(name, cloud['uploaded'],
                                                      metadata, is_public)
                out.success('done')

                # Upload metadata file
                out.info("Uploading metadata file ...", False)
                metastring = json.dumps(cloud['registered'],
                                        indent=4,
                                        ensure_ascii=False)
                kamaki.upload(StringIO.StringIO(metastring),
                              size=len(metastring),
                              remote_path="%s.meta" % remote,
                              container=container,
                              content_type="application/json")
                out.success("done")
                if is_public:
                    out.info("Sharing metadata and md5sum files ...", False)
                    kamaki.share("%s.meta" % remote)
                    kamaki.share("%s.md5sum" % remote)
                    out.success('done')
            except ClientError as error:
                d.msgbox("Error in storage service client: %s" % error.message)
                return False
        finally:
            out.remove(gauge)
    finally:
        gauge.cleanup()

    d.msgbox(
        "%s image `%s' was successfully registered with the cloud as `%s'" %
        (img_type.title(), remote, name),
        width=SMALL_WIDTH)
    return True
예제 #24
0
def create_image(session, answers):
    """Create an image using the information collected by the wizard"""
    image = session['image']

    with_progress = OutputWthProgress()
    image.out.append(with_progress)
    try:
        image.out.clear()

        if 'virtio' in answers and image.os.sysprep_params['virtio'].value:
            image.os.install_virtio_drivers()

        # Sysprep
        image.os.do_sysprep()
        metadata = image.os.meta

        update_background_title(session)

        metadata['DESCRIPTION'] = answers['ImageDescription']

        # MD5
        session['checksum'] = image.md5()

        image.out.info()
        try:
            image.out.info("Uploading image to the cloud:")
            account = Kamaki.get_account(answers['Cloud'])
            assert account, "Cloud: %s is not valid" % answers['Cloud']
            kamaki = Kamaki(account, image.out)

            name = "%s-%s.diskdump" % (answers['ImageName'],
                                       time.strftime("%Y%m%d%H%M"))
            with image.raw_device() as raw:
                with open(raw, 'rb') as device:
                    remote = kamaki.upload(device, image.size, name, CONTAINER,
                                           None,
                                           "(1/3)  Calculating block hashes",
                                           "(2/3)  Uploading image blocks")

            image.out.info("(3/3)  Uploading md5sum file ...", False)
            md5sumstr = '%s %s\n' % (session['checksum'], name)
            kamaki.upload(StringIO.StringIO(md5sumstr), size=len(md5sumstr),
                          remote_path="%s.%s" % (name, 'md5sum'),
                          container=CONTAINER, content_type="text/plain")
            image.out.success('done')
            image.out.info()

            image.out.info('Registering %s image with the cloud ...' %
                           answers['RegistrationType'].lower(), False)
            result = kamaki.register(answers['ImageName'], remote, metadata,
                                     answers['RegistrationType'] == "Public")
            image.out.success('done')
            image.out.info("Uploading metadata file ...", False)
            metastring = unicode(
                json.dumps(result, ensure_ascii=False)).encode('utf8')
            kamaki.upload(StringIO.StringIO(metastring), size=len(metastring),
                          remote_path="%s.%s" % (name, 'meta'),
                          container=CONTAINER, content_type="application/json")
            image.out.success('done')

            if answers['RegistrationType'] == "Public":
                image.out.info("Sharing md5sum file ...", False)
                kamaki.share("%s.md5sum" % name)
                image.out.success('done')
                image.out.info("Sharing metadata file ...", False)
                kamaki.share("%s.meta" % name)
                image.out.success('done')

            image.out.info()

        except ClientError as error:
            raise FatalError("Storage service client: %d %s" %
                             (error.status, error.message))
    finally:
        image.out.remove(with_progress)

    text = "The %s image was successfully uploaded to the storage service " \
           "and registered with the compute service of %s. Would you like " \
           "to keep a local copy?" % \
           (answers['RegistrationType'].lower(), answers['Cloud'])

    if session['dialog'].yesno(text, width=PAGE_WIDTH) == session['dialog'].OK:
        extract_image(session)
예제 #25
0
def image_creator(options, out):
    """snf-mkimage main function"""

    if os.geteuid() != 0:
        raise FatalError("You must run %s as root" %
                         os.path.basename(sys.argv[0]))

    # Check if the authentication info is valid. The earlier the better
    if options.token is not None and options.url is not None:
        try:
            account = Kamaki.create_account(options.url, options.token)
            if account is None:
                raise FatalError("The authentication token and/or URL you "
                                 "provided is not valid!")
            else:
                kamaki = Kamaki(account, out)
        except ClientError as e:
            raise FatalError("Astakos client: %d %s" % (e.status, e.message))
    elif options.cloud:
        avail_clouds = Kamaki.get_clouds()
        if options.cloud not in avail_clouds.keys():
            raise FatalError(
                "Cloud: `%s' does not exist.\n\nAvailable clouds:\n\n\t%s\n" %
                (options.cloud, "\n\t".join(avail_clouds.keys())))
        try:
            account = Kamaki.get_account(options.cloud)
            if account is None:
                raise FatalError("Cloud: `%s' exists but is not valid!" %
                                 options.cloud)
            else:
                kamaki = Kamaki(account, out)
        except ClientError as e:
            raise FatalError("Astakos client: %d %s" % (e.status, e.message))

    if options.upload and not options.force:
        if kamaki.object_exists(options.container, options.upload):
            raise FatalError("Remote storage service object: `%s' exists "
                             "(use --force to overwrite it)." % options.upload)
        if kamaki.object_exists(options.container,
                                "%s.md5sum" % options.upload):
            raise FatalError("Remote storage service object: `%s.md5sum' "
                             "exists (use --force to overwrite it)." %
                             options.upload)

    if options.register and not options.force:
        if kamaki.object_exists(options.container, "%s.meta" % options.upload):
            raise FatalError("Remote storage service object `%s.meta' exists "
                             "(use --force to overwrite it)." % options.upload)

    disk = Disk(options.source, out, options.tmp)

    # pylint: disable=unused-argument
    def signal_handler(signum, frame):
        disk.cleanup()

    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)
    try:
        # There is no need to snapshot the media if it was created by the Disk
        # instance as a temporary object.
        device = disk.file if not options.snapshot else disk.snapshot()
        image = disk.get_image(device, sysprep_params=options.sysprep_params)

        if image.is_unsupported() and not options.allow_unsupported:
            raise FatalError(
                "The media seems to be unsupported.\n\n" +
                textwrap.fill("To create an image from an unsupported media, "
                              "you'll need to use the`--allow-unsupported' "
                              "command line option. Using this is highly "
                              "discouraged, since the resulting image will "
                              "not be cleared out of sensitive data and will "
                              "not get customized during the deployment."))

        if len(options.host_run) != 0 and not image.mount_local_support:
            raise FatalError("Running scripts against the guest media is not "
                             "supported for this build of libguestfs.")

        if len(options.host_run) != 0:
            for script in options.host_run:
                if not os.path.isfile(script):
                    raise FatalError("File: `%s' does not exist." % script)
                if not os.access(script, os.X_OK):
                    raise FatalError("File: `%s' is not executable." % script)

        for name in options.disabled_syspreps:
            sysprep = image.os.get_sysprep_by_name(name)
            if sysprep is not None:
                image.os.disable_sysprep(sysprep)
            else:
                out.warn("Sysprep: `%s' does not exist. Can't disable it." %
                         name)

        for name in options.enabled_syspreps:
            sysprep = image.os.get_sysprep_by_name(name)
            if sysprep is not None:
                image.os.enable_sysprep(sysprep)
            else:
                out.warn("Sysprep: `%s' does not exist. Can't enable it." %
                         name)
        if image.is_unsupported():
            image.meta['EXCLUDE_ALL_TASKS'] = "yes"

        # Add command line metadata to the collected ones...
        image.meta.update(options.metadata)

        if options.print_syspreps:
            image.os.print_syspreps()
            out.info()

        if options.print_sysprep_params:
            image.os.print_sysprep_params()
            out.info()

        if options.print_metadata:
            image.os.print_metadata()
            out.info()

        if options.outfile is None and not options.upload:
            return 0

        if options.virtio is not None and \
                hasattr(image.os, 'install_virtio_drivers'):
            image.os.install_virtio_drivers()

        if len(options.host_run) != 0:
            # Export image metadata as environment variables to make them
            # visible by the scripts
            for key, value in image.meta.items():
                os.environ["SNF_IMAGE_CREATOR_METADATA_%s" % key] = str(value)

            out.info("Running scripts on the input media:")
            mpoint = tempfile.mkdtemp()
            try:
                image.mount(mpoint)
                if not image.is_mounted():
                    raise FatalError("Mounting the media on the host failed.")
                try:
                    size = len(options.host_run)
                    cnt = 1
                    for script in options.host_run:
                        script = os.path.abspath(script)
                        out.info(("(%d/%d)" % (cnt, size)).ljust(7), False)
                        out.info("Running `%s'" % script)
                        ret = subprocess.Popen([script], cwd=mpoint).wait()
                        if ret != 0:
                            raise FatalError("Script: `%s' failed (rc=%d)" %
                                             (script, ret))
                        cnt += 1
                finally:
                    while not image.umount():
                        out.warn("Unable to umount the media. Retrying ...")
                        time.sleep(1)
                    out.info()
            finally:
                os.rmdir(mpoint)

        if options.sysprep:
            image.os.do_sysprep()

        checksum = image.md5()

        image_meta = {}
        for k, v in image.meta.items():
            image_meta[str(k)] = str(v)

        metastring = json.dumps(
            {
                'properties': image_meta,
                'disk-format': 'diskdump'
            },
            ensure_ascii=False)

        img_properties = json.dumps(image_meta, ensure_ascii=False)

        if options.outfile is not None:
            if os.path.realpath(options.outfile) == '/dev/null':
                out.warn('Not dumping file to /dev/null')
            else:
                image.dump(options.outfile)

                out.info('Dumping metadata file ...', False)
                with open('%s.%s' % (options.outfile, 'meta'), 'w') as f:
                    f.write(metastring)
                out.success('done')

                out.info('Dumping md5sum file ...', False)
                with open('%s.%s' % (options.outfile, 'md5sum'), 'w') as f:
                    f.write('%s %s\n' %
                            (checksum, os.path.basename(options.outfile)))
                out.success('done')

                out.info('Dumping variant file ...', False)
                with open('%s.%s' % (options.outfile, 'variant'), 'w') as f:
                    f.write(
                        to_shell(IMG_ID=options.outfile,
                                 IMG_FORMAT="diskdump",
                                 IMG_PROPERTIES=img_properties))
                out.success('done')

        out.info()
        try:
            if options.upload:
                out.info("Uploading image to the storage service:")
                with image.raw_device() as raw:
                    with open(raw, 'rb') as f:
                        remote = kamaki.upload(
                            f, image.size, options.upload, options.container,
                            None, "(1/3)  Calculating block hashes",
                            "(2/3)  Uploading missing blocks")

                out.info("(3/3)  Uploading md5sum file ...", False)
                md5sumstr = '%s %s\n' % (checksum,
                                         os.path.basename(options.upload))
                kamaki.upload(StringIO.StringIO(md5sumstr),
                              size=len(md5sumstr),
                              remote_path="%s.%s" % (options.upload, 'md5sum'),
                              container=options.container,
                              content_type="text/plain")
                out.success('done')
                out.info()

            if options.register:
                img_type = 'public' if options.public else 'private'
                out.info(
                    'Registering %s image with the compute service ...' %
                    img_type, False)
                result = kamaki.register(options.register, remote, image.meta,
                                         options.public)
                out.success('done')
                out.info("Uploading metadata file ...", False)
                metastring = unicode(
                    json.dumps(result, ensure_ascii=False, indent=4))
                kamaki.upload(StringIO.StringIO(metastring.encode('utf8')),
                              size=len(metastring),
                              remote_path="%s.%s" % (options.upload, 'meta'),
                              container=options.container,
                              content_type="application/json")
                out.success('done')
                if options.public:
                    out.info("Sharing md5sum file ...", False)
                    kamaki.share("%s.md5sum" % options.upload)
                    out.success('done')
                    out.info("Sharing metadata file ...", False)
                    kamaki.share("%s.meta" % options.upload)
                    out.success('done')
                out.result(json.dumps(result, indent=4, ensure_ascii=False))
                out.info()
        except ClientError as e:
            raise FatalError("Service client: %d %s" % (e.status, e.message))

    finally:
        out.info('cleaning up ...')
        disk.cleanup()

    out.success("snf-image-creator exited without errors")

    return 0
예제 #26
0
def create_image(session, answers):
    """Create an image using the information collected by the wizard"""
    image = session['image']

    with_progress = OutputWthProgress()
    image.out.append(with_progress)
    try:
        image.out.clear()

        if 'virtio' in answers and image.os.sysprep_params['virtio'].value:
            image.os.install_virtio_drivers()

        # Sysprep
        image.os.do_sysprep()
        metadata = image.os.meta

        update_background_title(session)

        metadata['DESCRIPTION'] = answers['ImageDescription']

        # MD5
        session['checksum'] = image.md5()

        image.out.info()
        try:
            image.out.info("Uploading image to the cloud:")
            account = Kamaki.get_account(answers['Cloud'])
            assert account, "Cloud: %s is not valid" % answers['Cloud']
            kamaki = Kamaki(account, image.out)

            name = "%s-%s.diskdump" % (answers['ImageName'],
                                       time.strftime("%Y%m%d%H%M"))
            with image.raw_device() as raw:
                with open(raw, 'rb') as device:
                    remote = kamaki.upload(device, image.size, name, CONTAINER,
                                           None,
                                           "(1/3)  Calculating block hashes",
                                           "(2/3)  Uploading image blocks")

            image.out.info("(3/3)  Uploading md5sum file ...", False)
            md5sumstr = '%s %s\n' % (session['checksum'], name)
            kamaki.upload(StringIO.StringIO(md5sumstr),
                          size=len(md5sumstr),
                          remote_path="%s.%s" % (name, 'md5sum'),
                          container=CONTAINER,
                          content_type="text/plain")
            image.out.success('done')
            image.out.info()

            image.out.info(
                'Registering %s image with the cloud ...' %
                answers['RegistrationType'].lower(), False)
            result = kamaki.register(answers['ImageName'], remote, metadata,
                                     answers['RegistrationType'] == "Public")
            image.out.success('done')
            image.out.info("Uploading metadata file ...", False)
            metastring = unicode(json.dumps(result,
                                            ensure_ascii=False)).encode('utf8')
            kamaki.upload(StringIO.StringIO(metastring),
                          size=len(metastring),
                          remote_path="%s.%s" % (name, 'meta'),
                          container=CONTAINER,
                          content_type="application/json")
            image.out.success('done')

            if answers['RegistrationType'] == "Public":
                image.out.info("Sharing md5sum file ...", False)
                kamaki.share("%s.md5sum" % name)
                image.out.success('done')
                image.out.info("Sharing metadata file ...", False)
                kamaki.share("%s.meta" % name)
                image.out.success('done')

            image.out.info()

        except ClientError as error:
            raise FatalError("Storage service client: %d %s" %
                             (error.status, error.message))
    finally:
        image.out.remove(with_progress)

    text = "The %s image was successfully uploaded to the storage service " \
           "and registered with the compute service of %s. Would you like " \
           "to keep a local copy?" % \
           (answers['RegistrationType'].lower(), answers['Cloud'])

    if session['dialog'].yesno(text, width=PAGE_WIDTH) == session['dialog'].OK:
        extract_image(session)