Ejemplo n.º 1
0
 def _new_connection(self, *args, **kwargs):
     """
     Can be used to establish a new connection for all clients
     """
     keystone = _connect_to_keystone(*args, **kwargs)
     nova = _connect_to_nova(*args, **kwargs)
     glance = _connect_to_glance(keystone, *args, **kwargs)
     return (keystone, nova, glance)
Ejemplo n.º 2
0
    def _new_connection(self, *args, **kwargs):
        """
        Can be used to establish a new connection for all clients
        """
        ks_kwargs = self._build_keystone_creds(kwargs)
        nova_kwargs = self._build_nova_creds(kwargs)

        keystone = _connect_to_keystone(*args, **ks_kwargs)
        nova = _connect_to_nova(*args, **nova_kwargs)
        glance = _connect_to_glance(keystone, *args, **kwargs)
        return (keystone, nova, glance)
 def _new_connection(self, *args, **kwargs):
     """
     Can be used to establish a new connection for all clients
     """
     version = kwargs.get('version')
     if version == 'v3':
         (auth, sess, token) = _connect_to_keystone_v3(**kwargs)
         keystone = _connect_to_keystone(auth=auth, session=sess, version=version)
         nova = _connect_to_nova_by_auth(auth=auth, session=sess)
         glance = _connect_to_glance_by_auth(auth=auth, session=sess)
         glance_v1 = glance
     else:
         ks_kwargs = self._build_keystone_creds(kwargs)
         nova_kwargs = self._build_nova_creds(kwargs)
         keystone = _connect_to_keystone(*args, **ks_kwargs)
         nova = _connect_to_nova(*args, **nova_kwargs)
         glance = _connect_to_glance(keystone, *args, **kwargs)
         kwargs.pop('version', None)
         kwargs['version'] = 1
         glance_v1 = _connect_to_glance(keystone, *args, **kwargs)
     return (keystone, nova, glance, glance_v1)
Ejemplo n.º 4
0
 def _new_connection(self, *args, **kwargs):
     """
     Can be used to establish a new connection for all clients
     """
     version = kwargs.get('version')
     if version == 'v3':
         (auth, sess, token) = _connect_to_keystone_v3(**kwargs)
         keystone = _connect_to_keystone(auth=auth,
                                         session=sess,
                                         version=version)
         nova = _connect_to_nova_by_auth(auth=auth, session=sess)
         glance = _connect_to_glance_by_auth(auth=auth, session=sess)
         glance_v1 = glance
     else:
         ks_kwargs = self._build_keystone_creds(kwargs)
         nova_kwargs = self._build_nova_creds(kwargs)
         keystone = _connect_to_keystone(*args, **ks_kwargs)
         nova = _connect_to_nova(*args, **nova_kwargs)
         glance = _connect_to_glance(keystone, *args, **kwargs)
         kwargs.pop('version', None)
         kwargs['version'] = 1
         glance_v1 = _connect_to_glance(keystone, *args, **kwargs)
     return (keystone, nova, glance, glance_v1)
Ejemplo n.º 5
0
    def get_openstack_clients(self, username, password=None, tenant_name=None):

        user_creds = self._get_openstack_credentials(username,
                                                     password,
                                                     tenant_name)
        neutron = self.network_manager.new_connection(**user_creds)
        keystone = _connect_to_keystone(*args, **kwargs)
        nova = _connect_to_nova(*args, **kwargs)
        glance = _connect_to_glance(keystone, *args, **kwargs)
        return {
            'glance': glance,
            'keystone': keystone,
            'nova': nova,
            'neutron': neutron,
            'horizon': self._get_horizon_url(keystone.tenant_id)
        }
 def new_connection(self, *args, **kwargs):
     if kwargs.get('version') == 'v3':
         if 'auth_token' in kwargs:
             (auth, session, token) = _connect_to_keystone_auth_v3(**kwargs)
         else:
             (auth, session, token) = _connect_to_keystone_v3(**kwargs)
         keystone = _connect_to_keystone(version="v3", auth=auth, session=session)
         glance = _connect_to_glance_by_auth(auth=auth, session=session)
         nova = _connect_to_nova_by_auth(auth=auth, session=session)
         swift = _connect_to_swift(session=session)
     else:
         #Legacy cloud method for connection (without keystoneauth1)
         keystone = _connect_to_keystone(*args, **kwargs)
         glance = _connect_to_glance(keystone, **kwargs)
         nova_args = kwargs.copy()
         nova_args['version'] = 'v2.0'
         nova_args['auth_url'] = nova_args['auth_url'].replace('v3','v2.0')
         nova = _connect_to_nova(*args, **nova_args)
         swift_args = self._get_swift_args(*args, **kwargs)
         swift = _connect_to_swift(*args, **swift_args)
     return keystone, nova, swift, glance
Ejemplo n.º 7
0
 def new_connection(self, *args, **kwargs):
     if kwargs.get('version') == 'v3':
         if 'auth_token' in kwargs:
             (auth, session, token) = _connect_to_keystone_auth_v3(**kwargs)
         else:
             (auth, session, token) = _connect_to_keystone_v3(**kwargs)
         keystone = _connect_to_keystone(version="v3",
                                         auth=auth,
                                         session=session)
         glance = _connect_to_glance_by_auth(auth=auth, session=session)
         nova = _connect_to_nova_by_auth(auth=auth, session=session)
         swift = _connect_to_swift(session=session)
     else:
         #Legacy cloud method for connection (without keystoneauth1)
         keystone = _connect_to_keystone(*args, **kwargs)
         glance = _connect_to_glance(keystone, **kwargs)
         nova_args = kwargs.copy()
         nova_args['version'] = 'v2.0'
         nova_args['auth_url'] = nova_args['auth_url'].replace('v3', 'v2.0')
         nova = _connect_to_nova(*args, **nova_args)
         swift_args = self._get_swift_args(*args, **kwargs)
         swift = _connect_to_swift(*args, **swift_args)
     return keystone, nova, swift, glance
Ejemplo n.º 8
0
def main(
    application_id,
    destination_provider_id,
    source_provider_id=None,
    metadata_only=False,
    ignore_missing_owner=False,
    ignore_missing_members=False,
    migrate_end_dated_versions=False,
    clean=False,
    persist_local_cache=False,
    src_glance_client_version=None,
    dst_glance_client_version=None,
    irods_conn_str=None,
    irods_src_coll=None,
    irods_dst_coll=None,
):

    irods_args = (irods_conn_str, irods_src_coll, irods_dst_coll)
    if clean and any(irods_args):
        raise Exception("--clean cannot be used with iRODS transfer mode")
    if any(irods_args):
        irods = True
        if all(irods_args) and source_provider_id:
            irods_conn = _parse_irods_conn(irods_conn_str)
        else:
            raise Exception(
                "If using iRODS transfer then --source-provider-id, --irods-conn, --irods-src-coll, and "
                "--irods-dst-coll must all be defined")
    else:
        irods = False
        irods_conn = irods_src_coll = irods_dst_coll = None

    if source_provider_id == destination_provider_id:
        raise Exception(
            "Source provider cannot be the same as destination provider")
    app = core.models.Application.objects.get(id=application_id)
    dprov = core.models.Provider.objects.get(id=destination_provider_id)
    if source_provider_id:
        sprov = core.models.Provider.objects.get(id=source_provider_id)
    else:
        sprov = None

    dprov_acct_driver = service.driver.get_account_driver(dprov,
                                                          raise_exception=True)
    if dst_glance_client_version:
        dprov_keystone_client = dprov_acct_driver.image_manager.keystone
        dprov_glance_client = _connect_to_glance(
            dprov_keystone_client, version=dst_glance_client_version)
    else:
        dprov_glance_client = dprov_acct_driver.image_manager.glance

    dprov_atmo_admin_uname = dprov.admin.project_name()
    dprov_atmo_admin_uuid = dprov_acct_driver.get_project(
        dprov_atmo_admin_uname).id

    # Get application-specific metadata from Atmosphere(2) and resolve identifiers on destination provider

    # Get application owner UUID in destination provider
    app_creator_uname = app.created_by_identity.project_name()
    try:
        dprov_app_owner_uuid = dprov_acct_driver.get_project(
            app_creator_uname, raise_exception=True).id
    except AttributeError:
        if ignore_missing_owner:
            dprov_app_owner_uuid = dprov_atmo_admin_uuid
        else:
            raise Exception(
                "Application owner missing from destination provider, run with "
                "--ignore-missing-owner to suppress this error (owner will "
                "default to Atmosphere administrator")
    logging.debug("Application owner UUID in destination provider: {0}".format(
        dprov_app_owner_uuid))

    # If private application, get app member UUIDs in destination provider
    dprov_app_members_uuids = []
    if app.private is True:
        dprov_app_members_uuids.append(
            dprov_atmo_admin_uuid
        )  # Atmosphere administrator is always a member
        for membership in app.get_members():
            member_name = membership.group.name
            try:
                member_proj_uuid = dprov_acct_driver.get_project(
                    member_name).id
                # This avoids duplicates when there is both an ApplicationMembership and a ProviderMachineMembership
                if member_proj_uuid not in dprov_app_members_uuids:
                    dprov_app_members_uuids.append(member_proj_uuid)
            except AttributeError:
                if not ignore_missing_members:
                    raise Exception(
                        "Application member missing from destination provider, run with "
                        "--ignore-missing-members to suppress this error")
        logging.debug(
            "Private app member UUIDs on destination provider: {0}".format(
                str(dprov_app_members_uuids)))

    # Get application tags
    app_tags = [
        tag.name for tag in core.models.Tag.objects.filter(application=app)
    ]
    logging.info("Application tags: {0}".format(str(app_tags)))

    # Loop for each ApplicationVersion of the specified Application
    if migrate_end_dated_versions:
        versions = app.all_versions()
    else:
        versions = app.active_versions()
    for app_version in versions:
        logging.info("Processing ApplicationVersion {0}".format(
            str(app_version)))

        # Choose/verify source provider
        existing_prov_machines = core.models.ProviderMachine.objects.filter(
            application_version=app_version)
        if sprov is not None:
            # Confirm given source provider has valid ProviderMachine+InstanceSource for current ApplicationVersion
            valid_sprov = False
            for provider_machine in existing_prov_machines:
                sprov_instance_source = provider_machine.instance_source
                if sprov_instance_source.provider == sprov:
                    valid_sprov = True
                    break
            if not valid_sprov:
                raise Exception(
                    "Source provider not valid for at least one version of given application"
                )
        else:
            # Find a source provider that is not the destination provider
            for provider_machine in existing_prov_machines:
                sprov_instance_source = provider_machine.instance_source
                if sprov_instance_source.provider != dprov:
                    sprov = sprov_instance_source.provider
                    break
            if sprov is None:
                raise Exception(
                    "Could not find a source provider for at least one version of given application"
                )
        logging.debug("Using source provider: {0}".format(sprov))

        # Get access to source provider
        sprov_img_uuid = sprov_instance_source.identifier

        sprov_acct_driver = service.driver.get_account_driver(
            sprov, raise_exception=True)
        if src_glance_client_version == 1:
            sprov_keystone_client = service.driver.get_account_driver(
                sprov, raise_exception=True)
            sprov_glance_client = _connect_to_glance(
                sprov_keystone_client, version=src_glance_client_version)
        else:
            sprov_glance_client = sprov_acct_driver.image_manager.glance

        # Get source image metadata from Glance, and determine if image is AMI-based
        sprov_glance_image = sprov_glance_client.images.get(sprov_img_uuid)
        if sprov_glance_image.get("kernel_id") or sprov_glance_image.get(
                "ramdisk_id"):
            if sprov_glance_image.get("kernel_id") and sprov_glance_image.get(
                    "ramdisk_id"):
                ami = True
            else:
                raise Exception(
                    "AMI-based image must have both a kernel_id and ramdisk_id defined"
                )
        else:
            ami = False
        # If AMI-based image, verify that AKI and ARI images actually exist in source provider
        if ami:
            try:
                sprov_aki_glance_image = sprov_glance_client.images.get(
                    sprov_glance_image.get("kernel_id"))
                sprov_ari_glance_image = sprov_glance_client.images.get(
                    sprov_glance_image.get("ramdisk_id"))
            except glanceclient.exc.HTTPNotFound:
                logging.critical(
                    "Could not retrieve the AKI or ARI image on source provider, for an AMI-based image"
                )

        logging.debug("Source image metadata: {0}".format(
            str(sprov_glance_image)))

        # Check for existing ProviderMachine + InstanceSource for ApplicationVersion on destination provider
        dprov_machine = dprov_instance_source = None
        for provider_machine in existing_prov_machines:
            if provider_machine.instance_source.provider == dprov:
                dprov_machine = provider_machine
                dprov_instance_source = dprov_machine.instance_source
                logging.info(
                    "Found existing ProviderMachine and InstanceSource for image on destination provider"
                )
        if not dprov_machine:
            logging.info(
                "Could not find existing ProviderMachine and InstanceSource for image on destination provider"
                ", new objects will be created")

        # Get or create Glance image
        """
        todo corner case: we have existing InstanceSource with wrong image UUID?
        Do we correct it later (good) or end up creating a duplicate (maybe bad)?
        this logic may also need refactor
        """
        dprov_glance_image = get_or_create_glance_image(
            dprov_glance_client, sprov_img_uuid)

        # Get or create AKI+ARI Glance images for AMI-based image
        if ami:
            dprov_aki_glance_image = get_or_create_glance_image(
                dprov_glance_client, sprov_glance_image.get("kernel_id"))
            dprov_ari_glance_image = get_or_create_glance_image(
                dprov_glance_client, sprov_glance_image.get("ramdisk_id"))

        # Create models in database
        if not (dprov_machine or dprov_instance_source):
            logging.info("Creating new ProviderMachine and InstanceSource")
            dprov_instance_source = core.models.InstanceSource(
                provider=dprov,
                identifier=dprov_glance_image.id,
                created_by=app.created_by,
                end_date=sprov_instance_source.end_date)
            dprov_instance_source.save()
            dprov_machine = core.models.ProviderMachine(
                application_version=app_version,
                instance_source=dprov_instance_source)
            dprov_machine.save()

        # Build image metadata (this is always done)
        metadata = dict(
            name=app.name,
            owner=dprov_app_owner_uuid,
            container_format="ami"
            if ami else sprov_glance_image.container_format,
            disk_format="ami" if ami else sprov_glance_image.disk_format)
        if dst_glance_client_version == 1:
            metadata['is_public'] = False if app.private else True
        elif dst_glance_client_version >= 2.5:
            metadata['visibility'] = "shared" if app.private else "public"
        else:
            metadata['visibility'] = "private" if app.private else "public"

        # Glance v1 client throws exception on line breaks
        if dst_glance_client_version == 1:
            app_description = app.description.replace('\r', '').replace(
                '\n', ' -- ')
        else:
            app_description = app.description
        atmo_metadata = dict(tags=app_tags,
                             application_name=app.name,
                             application_version=app_version.name,
                             application_description=app_description,
                             application_owner=app_creator_uname,
                             application_tags=json.dumps(app_tags),
                             application_uuid=str(app.uuid))
        if ami:
            atmo_metadata['kernel_id'] = sprov_glance_image.kernel_id
            atmo_metadata['ramdisk_id'] = sprov_glance_image.ramdisk_id

        # Gather custom metadata on image in source provider
        custom_metadata = dict(sprov_glance_image)
        filter_out_keys = [
            'application_description', 'application_name', 'application_owner',
            'application_tags', 'application_uuid', 'application_version',
            'checksum', 'container_format', 'created_at', 'direct_url',
            'disk_format', 'file', 'id', 'instance_uuid', 'is_public',
            'kernel_id', 'locations', 'min_disk', 'min_ram', 'name', 'owner',
            'protected', 'ramdisk_id', 'schema', 'self', 'size', 'status',
            'tags', 'updated_at', 'virtual_size', 'visibility'
        ]

        for key in filter_out_keys:
            if key in custom_metadata:
                del custom_metadata[key]
        atmo_metadata.update(custom_metadata)

        # Set image metadata (this is always done)
        if dst_glance_client_version == 1:
            metadata['properties'] = atmo_metadata
            dprov_glance_client.images.update(dprov_glance_image.id,
                                              **metadata)
        else:
            metadata.update(atmo_metadata)
            dprov_glance_client.images.update(dprov_glance_image.id,
                                              **metadata)

        logging.info("Populated Glance image metadata: {0}".format(
            str(dprov_glance_client.images.get(dprov_glance_image.id))))

        if app.private:
            # Turning generator into list so it can be searched
            dprov_img_prior_members = [
                m.member_id for m in dprov_glance_client.image_members.list(
                    dprov_glance_image.id)
            ]
            for add_member_uuid in dprov_app_members_uuids:
                if add_member_uuid not in dprov_img_prior_members:
                    dprov_glance_client.image_members.create(
                        dprov_glance_image.id, add_member_uuid)
                else:
                    dprov_img_prior_members.remove(add_member_uuid)
            for del_member_uuid in dprov_img_prior_members:
                dprov_glance_client.image_members.delete(
                    dprov_glance_image.id, del_member_uuid)
            logging.info("Private image updated with member UUIDs")

        # If AMI-based image, set metadata for AKI and ARI images
        if ami:
            dprov_glance_client.images.update(
                sprov_aki_glance_image.id,
                container_format="aki",
                disk_format="aki",
                visibility="public",
                name=sprov_aki_glance_image.name,
                owner=dprov_atmo_admin_uuid,
            )
            dprov_glance_client.images.update(
                sprov_ari_glance_image.id,
                container_format="ari",
                disk_format="ari",
                visibility="public",
                name=sprov_ari_glance_image.name,
                owner=dprov_atmo_admin_uuid,
            )

        if not metadata_only:
            local_storage_dir = secrets.LOCAL_STORAGE if os.path.exists(
                secrets.LOCAL_STORAGE) else "/tmp"
            local_path = os.path.join(local_storage_dir, sprov_img_uuid)

            # Populate image data in destination provider if needed
            migrate_or_verify_image_data(
                sprov_img_uuid,
                sprov_glance_client,
                dprov_glance_client,
                local_path,
                persist_local_cache,
                irods,
                irods_conn,
                irods_src_coll,
                irods_dst_coll,
                clean=True if clean else False,
                dst_glance_client_version=dst_glance_client_version)
            # If AMI-based image, populate image data in destination provider if needed
            if ami:
                migrate_or_verify_image_data(
                    sprov_aki_glance_image.id,
                    sprov_glance_client,
                    dprov_glance_client,
                    local_path,
                    persist_local_cache,
                    irods,
                    irods_conn,
                    irods_src_coll,
                    irods_dst_coll,
                    dst_glance_client_version=dst_glance_client_version)
                migrate_or_verify_image_data(
                    sprov_ari_glance_image.id,
                    sprov_glance_client,
                    dprov_glance_client,
                    local_path,
                    persist_local_cache,
                    irods,
                    irods_conn,
                    irods_src_coll,
                    irods_dst_coll,
                    dst_glance_client_version=dst_glance_client_version)
Ejemplo n.º 9
0
def main(application_id,
         destination_provider_id,
         source_provider_id=None,
         metadata_only=False,
         ignore_missing_owner=False,
         ignore_missing_members=False,
         migrate_end_dated_versions=False,
         clean=False,
         persist_local_cache=False,
         src_glance_client_version=None,
         dst_glance_client_version=None,
         irods_conn_str=None,
         irods_src_coll=None,
         irods_dst_coll=None,
         ):

    irods_args = (irods_conn_str, irods_src_coll, irods_dst_coll)
    if clean and any(irods_args):
        raise Exception("--clean cannot be used with iRODS transfer mode")
    if any(irods_args):
        irods = True
        if all(irods_args) and source_provider_id:
            irods_conn = _parse_irods_conn(irods_conn_str)
        else:
            raise Exception("If using iRODS transfer then --source-provider-id, --irods-conn, --irods-src-coll, and "
                            "--irods-dst-coll must all be defined")
    else:
        irods = False
        irods_conn = irods_src_coll = irods_dst_coll = None

    if source_provider_id == destination_provider_id:
        raise Exception("Source provider cannot be the same as destination provider")
    app = core.models.Application.objects.get(id=application_id)
    dprov = core.models.Provider.objects.get(id=destination_provider_id)
    if source_provider_id:
        sprov = core.models.Provider.objects.get(id=source_provider_id)
    else:
        sprov = None

    dprov_acct_driver = service.driver.get_account_driver(dprov, raise_exception=True)
    if dst_glance_client_version:
        dprov_keystone_client = dprov_acct_driver.image_manager.keystone
        dprov_glance_client = _connect_to_glance(dprov_keystone_client, version=dst_glance_client_version)
    else:
        dprov_glance_client = dprov_acct_driver.image_manager.glance

    dprov_atmo_admin_uname = dprov.admin.project_name()
    dprov_atmo_admin_uuid = dprov_acct_driver.get_project(dprov_atmo_admin_uname).id

    # Get application-specific metadata from Atmosphere(2) and resolve identifiers on destination provider

    # Get application owner UUID in destination provider
    app_creator_uname = app.created_by_identity.project_name()
    try:
        dprov_app_owner_uuid = dprov_acct_driver.get_project(app_creator_uname, raise_exception=True).id
    except AttributeError:
        if ignore_missing_owner:
            dprov_app_owner_uuid = dprov_atmo_admin_uuid
        else:
            raise Exception("Application owner missing from destination provider, run with "
                            "--ignore-missing-owner to suppress this error (owner will "
                            "default to Atmosphere administrator")
    logging.debug("Application owner UUID in destination provider: {0}".format(dprov_app_owner_uuid))

    # If private application, get app member UUIDs in destination provider
    dprov_app_members_uuids = []
    if app.private is True:
        dprov_app_members_uuids.append(dprov_atmo_admin_uuid)  # Atmosphere administrator is always a member
        for membership in app.get_members():
            member_name = membership.group.name
            try:
                member_proj_uuid = dprov_acct_driver.get_project(member_name).id
                # This avoids duplicates when there is both an ApplicationMembership and a ProviderMachineMembership
                if member_proj_uuid not in dprov_app_members_uuids:
                    dprov_app_members_uuids.append(member_proj_uuid)
            except AttributeError:
                if not ignore_missing_members:
                    raise Exception("Application member missing from destination provider, run with "
                                    "--ignore-missing-members to suppress this error")
        logging.debug("Private app member UUIDs on destination provider: {0}".format(str(dprov_app_members_uuids)))

    # Get application tags
    app_tags = [tag.name for tag in core.models.Tag.objects.filter(application=app)]
    logging.info("Application tags: {0}".format(str(app_tags)))

    # Loop for each ApplicationVersion of the specified Application
    if migrate_end_dated_versions:
        versions = app.all_versions()
    else:
        versions = app.active_versions()
    for app_version in versions:
        logging.info("Processing ApplicationVersion {0}".format(str(app_version)))

        # Choose/verify source provider
        existing_prov_machines = core.models.ProviderMachine.objects.filter(application_version=app_version)
        if sprov is not None:
            # Confirm given source provider has valid ProviderMachine+InstanceSource for current ApplicationVersion
            valid_sprov = False
            for provider_machine in existing_prov_machines:
                sprov_instance_source = provider_machine.instance_source
                if sprov_instance_source.provider == sprov:
                    valid_sprov = True
                    break
            if not valid_sprov:
                raise Exception("Source provider not valid for at least one version of given application")
        else:
            # Find a source provider that is not the destination provider
            for provider_machine in existing_prov_machines:
                sprov_instance_source = provider_machine.instance_source
                if sprov_instance_source.provider != dprov:
                    sprov = sprov_instance_source.provider
                    break
            if sprov is None:
                raise Exception("Could not find a source provider for at least one version of given application")
        logging.debug("Using source provider: {0}".format(sprov))

        # Get access to source provider
        sprov_img_uuid = sprov_instance_source.identifier

        sprov_acct_driver = service.driver.get_account_driver(sprov, raise_exception=True)
        if src_glance_client_version == 1:
            sprov_keystone_client = service.driver.get_account_driver(sprov, raise_exception=True)
            sprov_glance_client = _connect_to_glance(sprov_keystone_client, version=src_glance_client_version)
        else:
            sprov_glance_client = sprov_acct_driver.image_manager.glance

        # Get source image metadata from Glance, and determine if image is AMI-based
        sprov_glance_image = sprov_glance_client.images.get(sprov_img_uuid)
        if sprov_glance_image.get("kernel_id") or sprov_glance_image.get("ramdisk_id"):
            if sprov_glance_image.get("kernel_id") and sprov_glance_image.get("ramdisk_id"):
                ami = True
            else:
                raise Exception("AMI-based image must have both a kernel_id and ramdisk_id defined")
        else:
            ami = False
        # If AMI-based image, verify that AKI and ARI images actually exist in source provider
        if ami:
            try:
                sprov_aki_glance_image = sprov_glance_client.images.get(sprov_glance_image.get("kernel_id"))
                sprov_ari_glance_image = sprov_glance_client.images.get(sprov_glance_image.get("ramdisk_id"))
            except glanceclient.exc.HTTPNotFound:
                logging.critical("Could not retrieve the AKI or ARI image on source provider, for an AMI-based image")

        logging.debug("Source image metadata: {0}".format(str(sprov_glance_image)))

        # Check for existing ProviderMachine + InstanceSource for ApplicationVersion on destination provider
        dprov_machine = dprov_instance_source = None
        for provider_machine in existing_prov_machines:
            if provider_machine.instance_source.provider == dprov:
                dprov_machine = provider_machine
                dprov_instance_source = dprov_machine.instance_source
                logging.info("Found existing ProviderMachine and InstanceSource for image on destination provider")
        if not dprov_machine:
            logging.info("Could not find existing ProviderMachine and InstanceSource for image on destination provider"
                         ", new objects will be created")

        # Get or create Glance image
        """
        todo corner case: we have existing InstanceSource with wrong image UUID?
        Do we correct it later (good) or end up creating a duplicate (maybe bad)?
        this logic may also need refactor
        """
        dprov_glance_image = get_or_create_glance_image(dprov_glance_client, sprov_img_uuid)

        # Get or create AKI+ARI Glance images for AMI-based image
        if ami:
            dprov_aki_glance_image = get_or_create_glance_image(dprov_glance_client,
                                                                sprov_glance_image.get("kernel_id"))
            dprov_ari_glance_image = get_or_create_glance_image(dprov_glance_client,
                                                                sprov_glance_image.get("ramdisk_id"))

        # Create models in database
        if not (dprov_machine or dprov_instance_source):
            logging.info("Creating new ProviderMachine and InstanceSource")
            dprov_instance_source = core.models.InstanceSource(provider=dprov,
                                                               identifier=dprov_glance_image.id,
                                                               created_by=app.created_by,
                                                               end_date=sprov_instance_source.end_date
                                                               )
            dprov_instance_source.save()
            dprov_machine = core.models.ProviderMachine(application_version=app_version,
                                                        instance_source=dprov_instance_source)
            dprov_machine.save()

        # Build image metadata (this is always done)
        metadata = dict(
            name=app.name,
            owner=dprov_app_owner_uuid,
            container_format="ami" if ami else sprov_glance_image.container_format,
            disk_format="ami" if ami else sprov_glance_image.disk_format
        )
        if dst_glance_client_version == 1:
            metadata['is_public'] = False if app.private else True
        elif dst_glance_client_version >= 2.5:
            metadata['visibility'] = "shared" if app.private else "public"
        else:
            metadata['visibility'] = "private" if app.private else "public"

        # Glance v1 client throws exception on line breaks
        if dst_glance_client_version == 1:
            app_description = app.description.replace('\r', '').replace('\n', ' -- ')
        else:
            app_description = app.description
        atmo_metadata = dict(
            tags=app_tags,
            application_name=app.name,
            application_version=app_version.name,
            application_description=app_description,
            application_owner=app_creator_uname,
            application_tags=json.dumps(app_tags),
            application_uuid=str(app.uuid)
        )
        if ami:
            atmo_metadata['kernel_id'] = sprov_glance_image.kernel_id
            atmo_metadata['ramdisk_id'] = sprov_glance_image.ramdisk_id

        # Gather custom metadata on image in source provider
        custom_metadata = dict(sprov_glance_image)
        filter_out_keys = ['application_description',
                           'application_name',
                           'application_owner',
                           'application_tags',
                           'application_uuid',
                           'application_version',
                           'checksum',
                           'container_format',
                           'created_at',
                           'direct_url',
                           'disk_format',
                           'file',
                           'id',
                           'instance_uuid',
                           'is_public',
                           'kernel_id',
                           'locations',
                           'min_disk',
                           'min_ram',
                           'name',
                           'owner',
                           'protected',
                           'ramdisk_id',
                           'schema',
                           'self',
                           'size',
                           'status',
                           'tags',
                           'updated_at',
                           'virtual_size',
                           'visibility']

        for key in filter_out_keys:
            if key in custom_metadata:
                del custom_metadata[key]
        atmo_metadata.update(custom_metadata)

        # Set image metadata (this is always done)
        if dst_glance_client_version == 1:
            metadata['properties'] = atmo_metadata
            dprov_glance_client.images.update(dprov_glance_image.id, **metadata)
        else:
            metadata.update(atmo_metadata)
            dprov_glance_client.images.update(dprov_glance_image.id, **metadata)

        logging.info("Populated Glance image metadata: {0}"
                     .format(str(dprov_glance_client.images.get(dprov_glance_image.id))))

        if app.private:
            # Turning generator into list so it can be searched
            dprov_img_prior_members = [m.member_id for m in dprov_glance_client.image_members.list(dprov_glance_image.id)]
            for add_member_uuid in dprov_app_members_uuids:
                if add_member_uuid not in dprov_img_prior_members:
                    dprov_glance_client.image_members.create(dprov_glance_image.id, add_member_uuid)
                else:
                    dprov_img_prior_members.remove(add_member_uuid)
            for del_member_uuid in dprov_img_prior_members:
                dprov_glance_client.image_members.delete(dprov_glance_image.id, del_member_uuid)
            logging.info("Private image updated with member UUIDs")

        # If AMI-based image, set metadata for AKI and ARI images
        if ami:
            dprov_glance_client.images.update(sprov_aki_glance_image.id,
                                              container_format="aki",
                                              disk_format="aki",
                                              visibility="public",
                                              name=sprov_aki_glance_image.name,
                                              owner=dprov_atmo_admin_uuid,
                                              )
            dprov_glance_client.images.update(sprov_ari_glance_image.id,
                                              container_format="ari",
                                              disk_format="ari",
                                              visibility="public",
                                              name=sprov_ari_glance_image.name,
                                              owner=dprov_atmo_admin_uuid,
                                              )

        if not metadata_only:
            local_storage_dir = secrets.LOCAL_STORAGE if os.path.exists(secrets.LOCAL_STORAGE) else "/tmp"
            local_path = os.path.join(local_storage_dir, sprov_img_uuid)

            # Populate image data in destination provider if needed
            migrate_or_verify_image_data(sprov_img_uuid, sprov_glance_client, dprov_glance_client, local_path,
                                         persist_local_cache, irods, irods_conn, irods_src_coll, irods_dst_coll,
                                         clean=True if clean else False,
                                         dst_glance_client_version=dst_glance_client_version)
            # If AMI-based image, populate image data in destination provider if needed
            if ami:
                migrate_or_verify_image_data(sprov_aki_glance_image.id, sprov_glance_client, dprov_glance_client,
                                             local_path, persist_local_cache, irods, irods_conn, irods_src_coll,
                                             irods_dst_coll, dst_glance_client_version=dst_glance_client_version)
                migrate_or_verify_image_data(sprov_ari_glance_image.id, sprov_glance_client, dprov_glance_client,
                                             local_path, persist_local_cache, irods, irods_conn, irods_src_coll,
                                             irods_dst_coll, dst_glance_client_version=dst_glance_client_version)