コード例 #1
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
コード例 #2
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
コード例 #3
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
コード例 #4
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)