ソースを参照

Removes the OpenStack provider

Alessandro Pilotti 9 年 前
コミット
dfccc74321

+ 0 - 5
coriolis/providers/openstack/__init__.py

@@ -1,5 +0,0 @@
-from coriolis.providers.openstack import exp
-from coriolis.providers.openstack import imp
-
-ExportProvider = exp.ExportProvider
-ImportProvider = imp.ImportProvider

+ 0 - 329
coriolis/providers/openstack/common.py

@@ -1,329 +0,0 @@
-# Copyright 2016 Cloudbase Solutions Srl
-# All Rights Reserved.
-
-import collections
-import math
-import time
-import uuid
-
-from oslo_log import log as logging
-from oslo_utils import units
-
-from coriolis import exception
-from coriolis import utils
-
-MIGRATION_TMP_FORMAT = "migration_tmp_%s"
-
-NOVA_API_VERSION = 2
-GLANCE_API_VERSION = 1
-NEUTRON_API_VERSION = '2.0'
-CINDER_API_VERSION = 2
-
-LOG = logging.getLogger(__name__)
-
-
-GlanceImage = collections.namedtuple(
-    "GlanceImage", "id format size path os_type")
-
-
-def get_unique_name():
-    return MIGRATION_TMP_FORMAT % str(uuid.uuid4())
-
-
-def create_image(glance, name, disk_path, disk_format, container_format,
-                 hypervisor_type):
-    properties = {}
-    if hypervisor_type:
-        properties["hypervisor_type"] = hypervisor_type
-
-    if glance.version == 1:
-        return _create_image_v1(glance, name, disk_path, disk_format,
-                                container_format, properties)
-    elif glance.version == 2:
-        return _create_image_v2(glance, name, disk_path, disk_format,
-                                container_format, properties)
-    else:
-        raise NotImplementedError("Unsupported Glance version")
-
-
-@utils.retry_on_error()
-def _create_image_v2(glance, name, disk_path, disk_format, container_format,
-                     properties):
-    image = glance.images.create(
-        name=name,
-        disk_format=disk_format,
-        container_format=container_format,
-        **properties)
-    try:
-        with open(disk_path, 'rb') as f:
-            glance.images.upload(image.id, f)
-        return image
-    except:
-        glance.images.delete(image.id)
-        raise
-
-
-@utils.retry_on_error()
-def _create_image_v1(glance, name, disk_path, disk_format, container_format,
-                     properties):
-    with open(disk_path, 'rb') as f:
-        return glance.images.create(
-            name=name,
-            disk_format=disk_format,
-            container_format=container_format,
-            properties=properties,
-            data=f)
-
-
-@utils.retry_on_error()
-def wait_for_image(nova, image_id, expected_status='ACTIVE'):
-    image = nova.images.get(image_id)
-    while image.status not in [expected_status, 'ERROR']:
-        LOG.debug('Image "%(id)s" in status: "%(status)s". '
-                  'Waiting for status: "%(expected_status)s".',
-                  {'id': image_id, 'status': image.status,
-                   'expected_status': expected_status})
-        time.sleep(2)
-        image = nova.images.get(image.id)
-    if image.status != expected_status:
-        raise exception.CoriolisException(
-            "Image is in status: %s" % image.status)
-
-
-@utils.retry_on_error()
-def wait_for_instance(nova, instance_id, expected_status='ACTIVE'):
-    instance = nova.servers.get(instance_id)
-    while instance.status not in [expected_status, 'ERROR']:
-        LOG.debug('Instance %(id)s status: %(status)s. '
-                  'Waiting for status: "%(expected_status)s".',
-                  {'id': instance_id, 'status': instance.status,
-                   'expected_status': expected_status})
-        time.sleep(2)
-        instance = nova.servers.get(instance.id)
-    if instance.status != expected_status:
-        raise exception.CoriolisException(
-            "VM is in status: %s" % instance.status)
-
-
-@utils.retry_on_error(terminal_exceptions=[exception.CoriolisException])
-def wait_for_instance_deletion(
-        nova, instance_id, max_retries=150, retry_period=2):
-    instances = nova.servers.findall(id=instance_id)
-    i = 0
-    while i < max_retries and instances:
-        i = i + 1
-        instance = utils.get_single_result(instances)
-        if instance.status == 'error':
-            raise exception.CoriolisException(
-                "Instance \"%s\" has reached invalid state \"%s\" while "
-                "deleting." % (instance_id, instance.status))
-
-        LOG.debug('Instance %(id)s status: %(status)s. '
-                  'Waiting %(period)s seconds for its deletion.',
-                  {'id': instance_id, 'status': instance.status,
-                   'period': retry_period})
-        time.sleep(retry_period)
-        instances = nova.servers.findall(id=instance_id)
-
-    if instances:
-        instance = utils.get_single_result(instances)
-        raise exception.CoriolisException(
-            "Max attempts of %(attempts)s reached while waiting for VM "
-            "\"%(instance_id)s\" deletion. Last known status: \"%(status)s\"" %
-            {'attempts': max_retries, 'status': instance.status,
-             'instance_id': instance_id})
-
-
-@utils.retry_on_error()
-def find_volume(cinder, volume_id):
-    volumes = cinder.volumes.findall(id=volume_id)
-    if volumes:
-        return utils.get_single_result(volumes)
-
-
-@utils.retry_on_error()
-def extend_volume(cinder, volume_id, new_size):
-    volume_size_gb = math.ceil(new_size / units.Gi)
-    cinder.volumes.extend(volume_id, volume_size_gb)
-
-
-@utils.retry_on_error()
-def get_volume_from_snapshot(cinder, snapshot_id):
-    snapshot = cinder.volume_snapshots.get(snapshot_id)
-    return cinder.volumes.get(snapshot.volume_id)
-
-
-@utils.retry_on_error()
-def create_volume(cinder, size, name, image_ref=None,
-                  snapshot_id=None, volume_type=None):
-    if snapshot_id:
-        volume_size_gb = None
-    else:
-        volume_size_gb = math.ceil(size / units.Gi)
-    return cinder.volumes.create(
-        size=volume_size_gb,
-        name=name,
-        volume_type=volume_type,
-        imageRef=image_ref,
-        snapshot_id=snapshot_id)
-
-
-@utils.retry_on_error(terminal_exceptions=[exception.NotFound])
-def get_flavor(nova, flavor_name):
-    flavors = nova.flavors.findall(name=flavor_name)
-    if not flavors:
-        raise exception.FlavorNotFound(flavor_name=flavor_name)
-    return flavors[0]
-
-
-@utils.retry_on_error(terminal_exceptions=[exception.NotFound])
-def get_image(glance, image_name):
-    images = glance.images.findall(name=image_name)
-    if not images:
-        raise exception.ImageNotFound(image_name=image_name)
-    return images[0]
-
-
-@utils.retry_on_error(terminal_exceptions=[exception.NotFound])
-def check_floating_ip_pool(nova, pool_name):
-    if not nova.floating_ip_pools.findall(name=pool_name):
-        raise exception.FloatingIPPoolNotFound(pool_name=pool_name)
-
-
-@utils.retry_on_error(terminal_exceptions=[exception.NotFound])
-def wait_for_volume(cinder, volume_id, expected_status='available'):
-    volumes = cinder.volumes.findall(id=volume_id)
-    if not volumes:
-        raise exception.VolumeNotFound(volume_id=volume_id)
-    volume = utils.get_single_result(volumes)
-
-    terminal_statuses = [expected_status, 'error']
-    if expected_status == 'in-use':
-        # if we're waiting for a volume to become attached, we are guaranteed
-        # that its status would no longer be 'available' the moment the
-        # attachment request is accepted.
-        terminal_statuses.append('available')
-
-    while volume.status not in terminal_statuses:
-        LOG.debug('Volume %(id)s status: %(status)s. '
-                  'Waiting for status: "%(expected_status)s".',
-                  {'id': volume_id, 'status': volume.status,
-                   'expected_status': expected_status})
-        time.sleep(2)
-        volume = cinder.volumes.get(volume.id)
-    if volume.status != expected_status:
-        raise exception.CoriolisException(
-            "Volume is in status: %s" % volume.status)
-
-
-@utils.retry_on_error()
-def delete_volume(cinder, volume_id):
-    volumes = cinder.volumes.findall(id=volume_id)
-    for volume in volumes:
-        volume.delete()
-
-
-@utils.retry_on_error()
-def create_volume_snapshot(cinder, volume_id, name, force=False):
-    return cinder.volume_snapshots.create(volume_id, name=name, force=force)
-
-
-@utils.retry_on_error(terminal_exceptions=[exception.NotFound])
-def wait_for_volume_snapshot(cinder, snapshot_id,
-                             expected_status='available'):
-    snapshots = cinder.volume_snapshots.findall(id=snapshot_id)
-
-    if not snapshots:
-        if expected_status == 'deleted':
-            return
-        raise exception.VolumeSnapshotNotFound(snapshot_id=snapshot_id)
-    snapshot = utils.get_single_result(snapshots)
-
-    while snapshot.status not in [expected_status, 'error']:
-        if expected_status == 'deleted' and snapshot.status == 'available':
-            LOG.debug("Cinder volume snapshot '%s' became 'available' while "
-                      "waiting for its deletion. This may be the behavior "
-                      "of the Cinder driver being used, so no further "
-                      "deletion attempts will be made.",
-                      snapshot_id)
-            return
-
-        LOG.debug('Volume snapshot %(id)s status: %(status)s. '
-                  'Waiting for status: "%(expected_status)s".',
-                  {'id': snapshot_id, 'status': snapshot.status,
-                   'expected_status': expected_status})
-        time.sleep(2)
-        if expected_status == 'deleted':
-            snapshots = cinder.volume_snapshots.findall(id=snapshot_id)
-            if not snapshots:
-                return
-            snapshot = utils.get_single_result(snapshots)
-        else:
-            snapshot = cinder.volume_snapshots.get(snapshot.id)
-    if snapshot.status != expected_status:
-        raise exception.CoriolisException(
-            "Volume snapshot is in status: %s" % snapshot.status)
-
-
-@utils.retry_on_error()
-def delete_volume_snapshot(cinder, snapshot_id):
-    snapshots = cinder.volume_snapshots.findall(id=snapshot_id)
-    for snapshot in snapshots:
-        return cinder.volume_snapshots.delete(snapshot.id)
-
-
-@utils.retry_on_error()
-def create_volume_backup(cinder, volume_id, snapshot_id, name, container,
-                         incremental, force=False):
-    return cinder.backups.create(
-        volume_id=volume_id,
-        snapshot_id=snapshot_id,
-        container=container,
-        name=name,
-        incremental=incremental,
-        force=force)
-
-
-@utils.retry_on_error(terminal_exceptions=[exception.NotFound])
-def wait_for_volume_backup(cinder, backup_id, expected_status='available'):
-    backups = cinder.backups.findall(id=backup_id)
-
-    if not backups:
-        if expected_status == 'deleted':
-            return
-        raise exception.VolumeBackupNotFound(backup_id=backup_id)
-    backup = utils.get_single_result(backups)
-
-    while backup.status not in [expected_status, 'error']:
-        LOG.debug('Volume backup %(id)s status: %(status)s. '
-                  'Waiting for status: "%(expected_status)s".',
-                  {'id': backup_id, 'status': backup.status,
-                   'expected_status': expected_status})
-        time.sleep(2)
-        if expected_status == 'deleted':
-            backups = cinder.backups.findall(id=backup_id)
-            if not backups:
-                return
-            backup = utils.get_single_result(backups)
-        else:
-            backup = cinder.backups.get(backup.id)
-    if backup.status != expected_status:
-        raise exception.CoriolisException(
-            "Volume backup is in status: %s" % backup.status)
-
-
-@utils.retry_on_error()
-def delete_volume_backup(cinder, backup_id):
-    cinder.backups.delete(backup_id)
-
-
-@utils.retry_on_error()
-def find_volume_backups(cinder, volume_id=None, container=None):
-    return cinder.backups.list(search_opts={
-        "volume_id": volume_id,
-        "container": container})
-
-
-@utils.retry_on_error()
-def get_instance_volumes(nova, instance_id):
-    return nova.volumes.get_server_volumes(instance_id)

+ 0 - 479
coriolis/providers/openstack/exp.py

@@ -1,479 +0,0 @@
-# Copyright 2016 Cloudbase Solutions Srl
-# All Rights Reserved.
-import gc
-import json
-import os
-import re
-import zlib
-
-from cinderclient import client as cinder_client
-from glanceclient import client as glance_client
-from novaclient import client as nova_client
-from oslo_config import cfg
-from oslo_log import log as logging
-from oslo_utils import units
-from swiftclient import client as swift_client
-
-from coriolis import constants
-from coriolis import events
-from coriolis import exception
-from coriolis import keystone
-from coriolis.providers import backup_writers
-from coriolis.providers import base
-from coriolis.providers.openstack import common
-from coriolis import schemas
-from coriolis import utils
-
-opts = [
-    cfg.StrOpt('volume_backups_container',
-               default="coriolis",
-               help='Cinder volume backups container name.'),
-]
-
-CONF = cfg.CONF
-CONF.register_opts(opts, 'openstack_migration_provider')
-
-LOG = logging.getLogger(__name__)
-
-VOLUME_BACKUP_VERSION = '1.0.0'
-
-
-class ExportProvider(base.BaseExportProvider, base.BaseReplicaExportProvider):
-
-    platform = constants.PLATFORM_OPENSTACK
-
-    _OS_DISTRO_MAP = {
-        'windows': constants.OS_TYPE_WINDOWS,
-        'freebsd': constants.OS_TYPE_BSD,
-        'netbsd': constants.OS_TYPE_BSD,
-        'openbsd': constants.OS_TYPE_BSD,
-        'opensolaris': constants.OS_TYPE_SOLARIS,
-        'arch': constants.OS_TYPE_LINUX,
-        'centos': constants.OS_TYPE_LINUX,
-        'debian': constants.OS_TYPE_LINUX,
-        'fedora': constants.OS_TYPE_LINUX,
-        'gentoo': constants.OS_TYPE_LINUX,
-        'mandrake': constants.OS_TYPE_LINUX,
-        'mandriva': constants.OS_TYPE_LINUX,
-        'mes': constants.OS_TYPE_LINUX,
-        'opensuse': constants.OS_TYPE_LINUX,
-        'rhel': constants.OS_TYPE_LINUX,
-        'sled': constants.OS_TYPE_LINUX,
-        'ubuntu': constants.OS_TYPE_LINUX,
-    }
-
-    connection_info_schema = schemas.get_schema(
-        __name__, schemas.PROVIDER_CONNECTION_INFO_SCHEMA_NAME)
-
-    def __init__(self, event_handler):
-        self._event_manager = events.EventManager(event_handler)
-
-    @utils.retry_on_error(terminal_exceptions=[exception.CoriolisException])
-    def _get_instance(self, nova, instance_name):
-        instances = nova.servers.list(
-            search_opts={'name': "^%s$" % instance_name})
-        if len(instances) > 1:
-            raise exception.CoriolisException(
-                'More than one instance exists with name: %s' % instance_name)
-        elif not instances:
-            raise exception.InstanceNotFound(instance_name=instance_name)
-        return instances[0]
-
-    def _get_os_type(self, image):
-        os_type = constants.DEFAULT_OS_TYPE
-        os_distro = image.properties.get('os_distro')
-        if not os_distro:
-            if 'os_type' in image.properties:
-                os_type = image.properties['os_type']
-            else:
-                self._event_manager.progress_update(
-                    "Image os_distro not set, defaulting to \"%s\"" % os_type)
-        elif os_distro not in self._OS_DISTRO_MAP:
-            self._event_manager.progress_update(
-                "Image os_distro \"%s\" not found, defaulting to \"%s\"" %
-                (os_distro, os_type))
-        else:
-            os_type = self._OS_DISTRO_MAP[os_distro]
-        return os_type
-
-    @utils.retry_on_error()
-    def _export_image(self, glance, export_path, image_id):
-        path = os.path.join(export_path, image_id)
-        LOG.debug('Saving snapshot to path: %s', export_path)
-        with open(path, 'wb') as f:
-            for chunk in glance.images.data(image_id):
-                f.write(chunk)
-
-        disk_info = utils.get_disk_info(path)
-        new_path = path + "." + disk_info['format']
-        os.rename(path, new_path)
-        LOG.debug('Renamed snapshot path: %s', new_path)
-        return new_path, disk_info['format']
-
-    @utils.retry_on_error()
-    def _create_snapshot(self, nova, glance, instance, export_path):
-        image_id = instance.create_image(common.get_unique_name())
-        try:
-            self._event_manager.progress_update(
-                "Waiting for instance snapshot to complete")
-            common.wait_for_image(nova, image_id)
-
-            image = glance.images.get(image_id)
-            image_size = image.size
-
-            if image.container_format != 'bare':
-                raise exception.CoriolisException(
-                    "Unsupported container format: %s" %
-                    image.container_format)
-
-            self._event_manager.progress_update(
-                "Exporting instance snapshot")
-
-            image_path, image_format = self._export_image(
-                glance, export_path, image_id)
-        finally:
-            self._event_manager.progress_update("Removing instance snapshot")
-
-            @utils.ignore_exceptions
-            @utils.retry_on_error()
-            def _del_image():
-                glance.images.delete(image_id)
-            _del_image()
-
-        os_type = self._get_os_type(image)
-        return common.GlanceImage(
-            id=image_id,
-            path=image_path,
-            format=image_format,
-            os_type=os_type,
-            size=image_size
-        )
-
-    def _get_instance_info(self, nova, cinder, instance_name):
-        self._event_manager.progress_update("Retrieving OpenStack instance")
-        instance = self._get_instance(nova, instance_name)
-
-        @utils.retry_on_error()
-        def _get_flavor_by_id():
-            return nova.flavors.get(instance.flavor["id"])
-        flavor = _get_flavor_by_id()
-
-        nics = []
-        for iface in instance.interface_list():
-            ips = set([ip['ip_address'] for ip in iface.fixed_ips])
-            net_name = [
-                n for n, v in instance.networks.items() if set(v) & ips][0]
-
-            nics.append({'name': iface.port_id,
-                         'id': iface.port_id,
-                         'mac_address': iface.mac_addr,
-                         'ip_addresses': list(ips),
-                         'network_id': iface.net_id,
-                         'network_name': net_name})
-
-        disks = []
-        vol_attachments = common.get_instance_volumes(nova, instance.id)
-        for vol_attachment in vol_attachments:
-            volume = cinder.volumes.get(vol_attachment.volumeId)
-            disks.append({
-                'format': constants.DISK_FORMAT_RAW,
-                'guest_device': vol_attachment.device,
-                'size_bytes': volume.size * units.Gi,
-                'storage_backend_identifier': volume.volume_type,
-                'path': '',
-                'id': volume.id
-            })
-
-        vm_info = {
-            'num_cpu': flavor.vcpus,
-            'num_cores_per_socket': 1,
-            'memory_mb': flavor.ram,
-            'nested_virtualization': False,
-            'name': instance_name,
-            'id': instance.id,
-            'flavor_name': flavor.name,
-            'devices': {
-                "nics": nics,
-                "disks": disks,
-                "cdroms": [],
-                "serial_ports": [],
-                "floppies": [],
-                "controllers": []
-            }
-        }
-
-        return instance, vm_info
-
-    def _check_shutdown_instance(self, nova, instance):
-        if instance.status != 'SHUTOFF':
-            self._event_manager.progress_update(
-                "Shutting down instance")
-
-            @utils.retry_on_error()
-            def _stop_instance():
-                instance.stop()
-
-            _stop_instance()
-            common.wait_for_instance(nova, instance.id, 'SHUTOFF')
-
-    def export_instance(self, ctxt, connection_info, instance_name,
-                        export_path):
-        session = keystone.create_keystone_session(ctxt, connection_info)
-        glance_api_version = connection_info.get("image_api_version",
-                                                 common.GLANCE_API_VERSION)
-        nova = nova_client.Client(common.NOVA_API_VERSION, session=session)
-        glance = glance_client.Client(glance_api_version, session=session)
-        cinder = cinder_client.Client(common.CINDER_API_VERSION,
-                                      session=session)
-
-        instance, vm_info = self._get_instance_info(
-            nova, cinder, instance_name)
-        self._check_shutdown_instance(nova, instance)
-
-        self._event_manager.progress_update("Creating instance snapshot")
-        image = self._create_snapshot(
-            nova, glance, instance, export_path)
-
-        disks = []
-        disks.append({
-            'format': image.format,
-            'path': image.path,
-            'size_bytes': image.size,
-            'id': str(image.id)
-        })
-
-        vm_info['os_type'] = image.os_type
-        vm_info['devices']['disks'] = disks
-
-        LOG.info("vm info: %s" % str(vm_info))
-        return vm_info
-
-    def get_replica_instance_info(self, ctxt, connection_info, instance_name):
-        session = keystone.create_keystone_session(ctxt, connection_info)
-        nova = nova_client.Client(common.NOVA_API_VERSION, session=session)
-        cinder = cinder_client.Client(common.CINDER_API_VERSION,
-                                      session=session)
-
-        instance, vm_info = self._get_instance_info(
-            nova, cinder, instance_name)
-
-        vm_info["os_type"] = constants.DEFAULT_OS_TYPE
-
-        return vm_info
-
-    def deploy_replica_source_resources(self, ctxt, connection_info):
-        return {"migr_resources": None, "connection_info": None}
-
-    def delete_replica_source_resources(self, ctxt, connection_info,
-                                        migr_resources_dict):
-        pass
-
-    @utils.retry_on_error()
-    def _get_backup_metadata(self, swift, volume_id, backup_id, container):
-        objects = swift.get_container(container)[1]
-
-        base_re = (r'volume_%(volume_id)s/\d+/az_nova_backup_%(backup_id)s' %
-                   {'volume_id': volume_id, 'backup_id': backup_id})
-
-        metadata_object_name = None
-        for obj in objects:
-            if re.match("%s_metadata" % base_re, obj["name"]):
-                metadata_object_name = obj["name"]
-                break
-
-        if not metadata_object_name:
-            raise exception.NotFound('Cinder backup metadata not found')
-
-        metadata_json = swift.get_object(container, metadata_object_name)[1]
-        metadata = json.loads(metadata_json.decode())
-
-        if metadata['version'] != VOLUME_BACKUP_VERSION:
-            raise exception.CoriolisException(
-                "Unsupported Cinder backup metadata version: %s" %
-                metadata['version'])
-
-        if metadata['backup_id'] != backup_id:
-            raise exception.CoriolisException(
-                "Metadata backup id does not match")
-
-        return metadata
-
-    @utils.retry_on_error()
-    def _read_backup_metadata_object(self, swift, metadata, container):
-        name, info = list(metadata.items())[0]
-        offset = info.get('offset', 0)
-        compression = info.get('compression')
-        md5 = info.get('md5')
-
-        data = swift.get_object(container, name)[1]
-
-        if compression == 'none':
-            pass
-        elif compression == 'zlib':
-            data = zlib.decompress(data)
-        else:
-            raise exception.CoriolisException(
-                "Unsupported compression format: %s" % compression)
-
-        if md5:
-            utils.check_md5(data, md5)
-
-        return data, offset
-
-    def replicate_disks(self, ctxt, connection_info, instance_name,
-                        source_conn_info, target_conn_info, volumes_info,
-                        incremental):
-        session = keystone.create_keystone_session(ctxt, connection_info)
-        cinder = cinder_client.Client(common.CINDER_API_VERSION,
-                                      session=session)
-        swift = swift_client.Connection(session=session)
-
-        ip = target_conn_info["ip"]
-        port = target_conn_info.get("port", 22)
-        username = target_conn_info["username"]
-        pkey = target_conn_info.get("pkey")
-        password = target_conn_info.get("password")
-
-        container = CONF.openstack_migration_provider.volume_backups_container
-
-        volumes_info, backups = self._create_volume_backups(
-            cinder, volumes_info, container)
-
-        LOG.info("Waiting for connectivity on host: %(ip)s:%(port)s",
-                 {"ip": ip, "port": port})
-        utils.wait_for_port_connectivity(ip, port)
-
-        for volume_info in volumes_info:
-            self._event_manager.progress_update(
-                "Retrieving backup metadata")
-
-            last_backup_id = volume_info.get("last_backup_id")
-            backup_metadata_list = []
-
-            volume_id = volume_info["disk_id"]
-            backup_id = backups[volume_id].id
-
-            # Other backups might have occurred since the last replica
-            # execution, make sure to replicate all data
-            while True:
-                backup_metadata = self._get_backup_metadata(
-                    swift, volume_id, backup_id, container)
-                backup_metadata_list.insert(0, backup_metadata)
-                previous_backup_id = backup_metadata.get("parent_id")
-                if (not previous_backup_id or
-                        previous_backup_id == last_backup_id):
-                    break
-                backup_id = previous_backup_id
-
-            backup_writer = backup_writers.SSHBackupWriter(
-                ip, port, username, pkey, password, volumes_info)
-
-            for backup_metadata in backup_metadata_list:
-                objects_metadata = backup_metadata["objects"]
-                backup_id = backup_metadata["backup_id"]
-
-                total_written_bytes = 0
-                total_bytes = sum([list(o.values())[0]['length']
-                                  for o in objects_metadata])
-
-                perc_step = self._event_manager.add_percentage_step(
-                    total_bytes,
-                    message_format="Volume backup %s replica progress: "
-                    "{:.0f}%%" % backup_id)
-
-                max_chunk_size = 10 * units.Mi
-
-                with backup_writer.open("", volume_id) as f:
-                    for object_metadata in objects_metadata:
-                        data, offset = self._read_backup_metadata_object(
-                            swift, object_metadata, container)
-
-                        f.seek(offset)
-
-                        i = 0
-                        while i < len(data):
-                            f.write(data[i:i + max_chunk_size])
-                            i += max_chunk_size
-
-                        total_written_bytes += len(data)
-                        self._event_manager.set_percentage_step(
-                            perc_step, total_written_bytes)
-
-                        data = None
-                        gc.collect()
-
-            volume_info["last_backup_id"] = backups[volume_id].id
-
-        return volumes_info
-
-    def _create_volume_backups(self, cinder, volumes_info, container):
-        snapshots = {}
-        backups = {}
-        try:
-            self._event_manager.progress_update("Creating volume snapshots")
-            for volume_info in volumes_info:
-                volume_id = volume_info["disk_id"]
-                snapshot = common.create_volume_snapshot(
-                    cinder, volume_id, common.get_unique_name(), force=True)
-                snapshots[volume_id] = snapshot
-
-            self._event_manager.progress_update(
-                "Waiting for volume snapshots to complete")
-            for snapshot in snapshots.values():
-                common.wait_for_volume_snapshot(cinder, snapshot.id)
-
-            self._event_manager.progress_update("Creating volume backups")
-            for volume_info in volumes_info:
-                volume_id = volume_info["disk_id"]
-
-                volume_backups = common.find_volume_backups(
-                    cinder, volume_id, container)
-                incremental = len(volume_backups) > 0
-
-                snapshot = snapshots[volume_id]
-                # TODO: add Cinder v1 check ('incremental' and 'force' are v2+)
-                volume_backup = common.create_volume_backup(
-                    cinder,
-                    volume_id=volume_id,
-                    snapshot_id=snapshot.id,
-                    container=container,
-                    name=common.get_unique_name(),
-                    incremental=incremental,
-                    # NOTE: 'force' is required by standard API definition for
-                    # any incremental backup while the VM is on, but some
-                    # Cinder backends will allow its absence.
-                    force=True
-                )
-                backups[volume_id] = volume_backup
-
-            self._event_manager.progress_update(
-                "Waiting for volume backups to complete")
-            for backup in backups.values():
-                common.wait_for_volume_backup(cinder, backup.id)
-
-            return volumes_info, backups
-        except Exception as ex:
-            LOG.exception(ex)
-            self._event_manager.progress_update(
-                "Deleting volume backups")
-            for backup in backups.values():
-                common.delete_volume_backup(cinder, backup.id)
-            self._event_manager.progress_update(
-                "Waiting for volume backups to be deleted")
-            for backup in backups.values():
-                common.wait_for_volume_backup(cinder, backup.id, 'deleted')
-            raise
-        finally:
-            self._event_manager.progress_update("Deleting volume snapshots")
-            for snapshot in snapshots.values():
-                common.delete_volume_snapshot(cinder, snapshot.id)
-            self._event_manager.progress_update(
-                "Waiting for volume snapshots to be deleted")
-            for snapshot in snapshots.values():
-                common.wait_for_volume_snapshot(cinder, snapshot.id, 'deleted')
-
-    def shutdown_instance(self, ctxt, connection_info, instance_name):
-        session = keystone.create_keystone_session(ctxt, connection_info)
-        nova = nova_client.Client(common.NOVA_API_VERSION, session=session)
-        instance = self._get_instance(nova, instance_name)
-        self._check_shutdown_instance(nova, instance)

+ 0 - 1119
coriolis/providers/openstack/imp.py

@@ -1,1119 +0,0 @@
-# Copyright 2016 Cloudbase Solutions Srl
-# All Rights Reserved.
-
-import math
-import os
-import tempfile
-
-from cinderclient import client as cinder_client
-from glanceclient import client as glance_client
-from neutronclient.neutron import client as neutron_client
-from novaclient import client as nova_client
-from oslo_config import cfg
-from oslo_log import log as logging
-from oslo_utils import units
-import paramiko
-
-from coriolis import constants
-from coriolis import events
-from coriolis import exception
-from coriolis import keystone
-from coriolis.providers import base
-from coriolis.providers.openstack import common
-from coriolis.providers.openstack.osmorphing import coreos
-from coriolis.providers.openstack.osmorphing import debian
-from coriolis.providers.openstack.osmorphing import openwrt
-from coriolis.providers.openstack.osmorphing import oracle
-from coriolis.providers.openstack.osmorphing import redhat
-from coriolis.providers.openstack.osmorphing import suse
-from coriolis.providers.openstack.osmorphing import ubuntu
-from coriolis.providers.openstack.osmorphing import windows
-from coriolis import schemas
-from coriolis import utils
-
-opts = [
-    cfg.StrOpt('disk_format',
-               default=constants.DISK_FORMAT_QCOW2,
-               help='Default image disk format.'),
-    cfg.StrOpt('container_format',
-               default='bare',
-               help='Default image container format.'),
-    cfg.StrOpt('hypervisor_type',
-               default=None,
-               help='Default hypervisor type.'),
-    cfg.StrOpt('boot_from_volume',
-               default=True,
-               help='Set to "True" to boot from volume by default instead of '
-               'using local storage.'),
-    cfg.StrOpt('delete_disks_on_vm_termination',
-               default=False,
-               help='Configure Cinder volumes to be deleted on an eventual '
-                    'termination of the migrated/replicated instance.'),
-    cfg.StrOpt('glance_upload',
-               default=True,
-               help='Set to "True" to use Glance to upload images.'),
-    cfg.StrOpt('default_cinder_volume_type',
-               default='',
-               help='Name of the Cinder volume type to be used for '
-                    'volumes with unspecified storage backing options.'),
-    cfg.DictOpt('migr_image_name_map',
-                default={},
-                help='Default image names used for worker instances during '
-                'migrations.'),
-    cfg.StrOpt('migr_flavor_name',
-               default='m1.small',
-               help='Default flavor name used for worker instances '
-               'during migrations.'),
-    cfg.StrOpt('migr_network_name',
-               default='private',
-               help='Default network name used for worker instances '
-               'during migrations.'),
-    cfg.StrOpt('fip_pool_name',
-               default='public',
-               help='Default floating ip pool name.'),
-]
-
-CONF = cfg.CONF
-CONF.register_opts(opts, 'openstack_migration_provider')
-
-DISK_HEADER_SIZE = 10 * units.Mi
-
-SSH_PORT = 22
-WINRM_HTTPS_PORT = 5986
-
-MIGR_USER_DATA = (
-    "#cloud-config\n"
-    "users:\n"
-    "  - name: %s\n"
-    "    ssh-authorized-keys:\n"
-    "      - %s\n"
-    "    sudo: ['ALL=(ALL) NOPASSWD:ALL']\n"
-    "    groups: sudo\n"
-    "    shell: /bin/bash\n"
-)
-MIGR_GUEST_USERNAME = 'cloudbase'
-MIGR_GUEST_USERNAME_WINDOWS = "admin"
-
-VOLUME_NAME_FORMAT = "%(instance_name)s %(num)s"
-REPLICA_VOLUME_NAME_FORMAT = "Coriolis Replica - %(instance_name)s %(num)s"
-
-LOG = logging.getLogger(__name__)
-
-
-class _MigrationResources(object):
-    def __init__(self, nova, neutron, keypair, instance, port,
-                 floating_ip, guest_port, sec_group, username, password, k):
-        self._nova = nova
-        self._neutron = neutron
-        self._instance = instance
-        self._port = port
-        self._floating_ip = floating_ip
-        self._guest_port = guest_port
-        self._sec_group = sec_group
-        self._keypair = keypair
-        self._k = k
-        self._username = username
-        self._password = password
-
-    def get_resources_dict(self):
-        return {
-            "instance_id": self._instance.id,
-            "keypair_name": self._keypair.name,
-            "port_id": self._port["id"],
-            "floating_ip_id": self._floating_ip.id,
-            "secgroup_id": self._sec_group.id,
-        }
-
-    @classmethod
-    @utils.retry_on_error()
-    def from_resources_dict(cls, nova, neutron, resources_dict):
-        instance_id = resources_dict["instance_id"]
-        keypair_name = resources_dict["keypair_name"]
-        floating_ip_id = resources_dict["floating_ip_id"]
-        secgroup_id = resources_dict["secgroup_id"]
-        port_id = resources_dict["port_id"]
-
-        instance = None
-        instances = nova.servers.findall(id=instance_id)
-        if instances:
-            instance = instances[0]
-
-        keypair = None
-        keypairs = nova.keypairs.findall(name=keypair_name)
-        if keypairs:
-            keypair = keypairs[0]
-
-        floating_ip = None
-        floating_ips = nova.floating_ips.findall(id=floating_ip_id)
-        if floating_ips:
-            floating_ip = floating_ips[0]
-
-        sec_group = None
-        sec_groups = nova.security_groups.findall(id=secgroup_id)
-        if sec_groups:
-            sec_group = sec_groups[0]
-
-        port = None
-        ports = neutron.list_ports(id=port_id)["ports"]
-        if ports:
-            port = ports[0]
-
-        return cls(
-            nova, neutron, keypair, instance, port, floating_ip, None,
-            sec_group, None, None, None)
-
-    def get_guest_connection_info(self):
-        return {
-            "ip": self._floating_ip.ip,
-            "port": self._guest_port,
-            "username": self._username,
-            "password": self._password,
-            "pkey": self._k,
-        }
-
-    def get_instance(self):
-        return self._instance
-
-    @utils.retry_on_error()
-    def delete(self):
-        if self._instance:
-            self._nova.servers.delete(self._instance)
-            common.wait_for_instance_deletion(self._nova, self._instance.id)
-            self._instance = None
-        if self._floating_ip:
-            self._nova.floating_ips.delete(self._floating_ip)
-            self._floating_ip = None
-        if self._port:
-            self._neutron.delete_port(self._port['id'])
-            self._port = None
-        if self._sec_group:
-            self._nova.security_groups.delete(self._sec_group.id)
-            self._sec_group = None
-        if self._keypair:
-            self._nova.keypairs.delete(self._keypair.name)
-            self._keypair = None
-
-
-class ImportProvider(base.BaseImportProvider, base.BaseReplicaImportProvider):
-
-    platform = constants.PLATFORM_OPENSTACK
-
-    connection_info_schema = schemas.get_schema(
-        __name__, schemas.PROVIDER_CONNECTION_INFO_SCHEMA_NAME)
-
-    target_environment_schema = schemas.get_schema(
-        __name__, schemas.PROVIDER_TARGET_ENVIRONMENT_SCHEMA_NAME)
-
-    def __init__(self, event_handler):
-        self._event_manager = events.EventManager(event_handler)
-
-    @utils.retry_on_error(terminal_exceptions=[exception.NotFound])
-    def _create_neutron_port(self, neutron, network_name, mac_address=None):
-        networks = neutron.list_networks(name=network_name)
-        if not networks['networks']:
-            raise exception.NetworkNotFound(network_name=network_name)
-        network_id = networks['networks'][0]['id']
-
-        # make sure that the port is not already existing from a previous
-        # migration attempt
-        if mac_address:
-            ports = neutron.list_ports(
-                mac_address=mac_address).get('ports', [])
-            if ports:
-                neutron.delete_port(ports[0]['id'])
-
-        body = {"port": {
-                "network_id": network_id,
-                }}
-        if mac_address:
-            body["port"]["mac_address"] = mac_address
-
-        return neutron.create_port(body=body)['port']
-
-    @utils.retry_on_error()
-    def _create_keypair(self, nova, name, public_key):
-        if nova.keypairs.findall(name=name):
-            nova.keypairs.delete(name)
-        return nova.keypairs.create(name=name, public_key=public_key)
-
-    @utils.retry_on_error(max_attempts=10, sleep_seconds=10)
-    def _get_instance_password(self, instance, k):
-        self._event_manager.progress_update("Getting instance password")
-        fd, key_path = tempfile.mkstemp()
-        try:
-            k.write_private_key_file(key_path)
-            return instance.get_password(private_key=key_path).decode()
-        finally:
-            os.close(fd)
-            os.remove(key_path)
-
-    @utils.retry_on_error(max_attempts=10, sleep_seconds=30,
-                          terminal_exceptions=[exception.NotFound])
-    def _deploy_migration_resources(self, nova, glance, neutron,
-                                    os_type, migr_image_name, migr_flavor_name,
-                                    migr_network_name, migr_fip_pool_name):
-        LOG.debug("Migration image name: %s", migr_image_name)
-        image = common.get_image(glance, migr_image_name)
-
-        LOG.debug("Migration flavor name: %s", migr_flavor_name)
-        flavor = common.get_flavor(nova, migr_flavor_name)
-
-        LOG.debug("Migration FIP pool name: %s", migr_fip_pool_name)
-        common.check_floating_ip_pool(nova, migr_fip_pool_name)
-
-        keypair = None
-        instance = None
-        floating_ip = None
-        sec_group = None
-        port = None
-
-        try:
-            migr_keypair_name = common.get_unique_name()
-
-            self._event_manager.progress_update(
-                "Creating migration worker instance keypair")
-
-            k = paramiko.RSAKey.generate(2048)
-            public_key = "ssh-rsa %s tmp@migration" % k.get_base64()
-            keypair = self._create_keypair(nova, migr_keypair_name, public_key)
-
-            self._event_manager.progress_update(
-                "Creating migration worker instance Neutron port")
-
-            port = self._create_neutron_port(neutron, migr_network_name)
-
-            # TODO(alexpilotti): use a single username
-            if os_type == constants.OS_TYPE_WINDOWS:
-                username = MIGR_GUEST_USERNAME_WINDOWS
-            else:
-                username = MIGR_GUEST_USERNAME
-
-            userdata = MIGR_USER_DATA % (username, public_key)
-            instance = nova.servers.create(
-                name=common.get_unique_name(),
-                image=image.id,
-                flavor=flavor,
-                key_name=migr_keypair_name,
-                userdata=userdata,
-                nics=[{'port-id': port['id']}])
-
-            self._event_manager.progress_update(
-                "Adding migration worker instance floating IP")
-
-            floating_ip = nova.floating_ips.create(pool=migr_fip_pool_name)
-            common.wait_for_instance(nova, instance.id, 'ACTIVE')
-
-            LOG.info("Floating IP: %s", floating_ip.ip)
-            instance.add_floating_ip(floating_ip)
-
-            self._event_manager.progress_update(
-                "Adding migration worker instance security group")
-
-            if os_type == constants.OS_TYPE_WINDOWS:
-                guest_port = WINRM_HTTPS_PORT
-            else:
-                guest_port = SSH_PORT
-
-            migr_sec_group_name = common.get_unique_name()
-            sec_group = nova.security_groups.create(
-                name=migr_sec_group_name, description=migr_sec_group_name)
-            nova.security_group_rules.create(
-                sec_group.id,
-                ip_protocol="tcp",
-                from_port=guest_port,
-                to_port=guest_port)
-            instance.add_security_group(sec_group.id)
-
-            self._event_manager.progress_update(
-                "Waiting for connectivity on host: %(ip)s:%(port)s" %
-                {"ip": floating_ip.ip, "port": guest_port})
-
-            utils.wait_for_port_connectivity(floating_ip.ip, guest_port)
-
-            if os_type == constants.OS_TYPE_WINDOWS:
-                password = self._get_instance_password(instance, k)
-            else:
-                password = None
-
-            return _MigrationResources(nova, neutron, keypair, instance, port,
-                                       floating_ip, guest_port, sec_group,
-                                       username, password, k)
-        except Exception as ex:
-            self._event_manager.progress_update(
-                "An error occurred, cleaning up worker resources: %s" %
-                str(ex))
-
-            if instance:
-                nova.servers.delete(instance)
-            if floating_ip:
-                nova.floating_ips.delete(floating_ip)
-            if port:
-                neutron.delete_port(port['id'])
-            if sec_group:
-                nova.security_groups.delete(sec_group.id)
-            if keypair:
-                nova.keypairs.delete(keypair.name)
-            raise
-
-    @utils.retry_on_error()
-    def _attach_volume(self, nova, cinder, instance, volume_id,
-                       volume_dev=None):
-        # volume can be either a Volume object or an id
-        volume = nova.volumes.create_server_volume(
-            instance.id, volume_id, volume_dev)
-        common.wait_for_volume(cinder, volume.id, 'in-use')
-        return volume
-
-    def _get_import_config(self, target_environment, os_type):
-        config = {}
-
-        config["glance_upload"] = target_environment.get(
-            "glance_upload", CONF.openstack_migration_provider.glance_upload)
-        config["target_disk_format"] = target_environment.get(
-            "disk_format", CONF.openstack_migration_provider.disk_format)
-        config["container_format"] = target_environment.get(
-            "container_format",
-            CONF.openstack_migration_provider.container_format)
-        config["hypervisor_type"] = target_environment.get(
-            "hypervisor_type",
-            CONF.openstack_migration_provider.hypervisor_type)
-        config["fip_pool_name"] = target_environment.get(
-            "fip_pool_name", CONF.openstack_migration_provider.fip_pool_name)
-        config["delete_disks_on_vm_termination"] = target_environment.get(
-            "delete_disks_on_vm_termination",
-            CONF.openstack_migration_provider.delete_disks_on_vm_termination)
-        config["network_map"] = target_environment.get("network_map", {})
-        config["storage_map"] = target_environment.get("storage_map", {})
-        config["keypair_name"] = target_environment.get("keypair_name")
-
-        config["migr_image_name"] = target_environment.get(
-            "migr_image_name",
-            target_environment.get("migr_image_name_map", {}).get(
-                os_type,
-                CONF.openstack_migration_provider.migr_image_name_map.get(
-                    os_type)))
-        config["migr_flavor_name"] = target_environment.get(
-            "migr_flavor_name",
-            CONF.openstack_migration_provider.migr_flavor_name)
-
-        config["migr_fip_pool_name"] = target_environment.get(
-            "migr_fip_pool_name",
-            config["fip_pool_name"] or
-            CONF.openstack_migration_provider.fip_pool_name)
-        config["migr_network_name"] = target_environment.get(
-            "migr_network_name",
-            CONF.openstack_migration_provider.migr_network_name)
-
-        config["flavor_name"] = target_environment.get(
-            "flavor_name", config["migr_flavor_name"])
-
-        if not config["migr_image_name"]:
-            raise exception.CoriolisException(
-                "No matching migration image type found")
-
-        if not config["migr_network_name"]:
-            if len(config["network_map"]) != 1:
-                raise exception.CoriolisException(
-                    'If "migr_network_name" is not provided, "network_map" '
-                    'must contain exactly one entry')
-            config["migr_network_name"] = list(
-                config["network_map"].values())[0]
-
-        return config
-
-    @utils.retry_on_error()
-    def _convert_disk_format(
-            self, source_path, destination_path, destination_format):
-        """ Converts the  disk to the provided destination_format and
-        returns the new path to the converted disk. """
-        try:
-            LOG.info("Converting disk '%s' to %s" % (
-                     source_path,
-                     destination_format))
-            utils.convert_disk_format(
-                source_path, destination_path, destination_format)
-        except Exception:
-            utils.ignore_exceptions(os.remove)(destination_path)
-            raise
-
-    def _create_images_and_volumes(self, glance, nova, cinder, config,
-                                   disks_info):
-        if not config["glance_upload"]:
-            raise exception.CoriolisException(
-                "Glance upload is currently required for migrations")
-
-        images = []
-        volumes = []
-
-        for disk_info in disks_info:
-            disk_path = disk_info["path"]
-            disk_file_info = utils.get_disk_info(disk_path)
-
-            target_disk_path = disk_path
-            if config["target_disk_format"] != disk_file_info["format"]:
-                target_disk_path = ("%s.%s" % (
-                    os.path.splitext(
-                        disk_path)[0], config["target_disk_format"]))
-                self._convert_disk_format(
-                    disk_path, target_disk_path, config["target_disk_format"])
-                disk_file_info = utils.get_disk_info(target_disk_path)
-
-                LOG.info(
-                    "Succesfully converted '%s' to %s as '%s'. "
-                    "Removing original path." % (
-                        disk_path, config["target_disk_format"],
-                        target_disk_path))
-                os.remove(disk_path)
-
-            self._event_manager.progress_update(
-                "Uploading Glance image")
-
-            disk_format = disk_file_info["format"]
-            if disk_format == "vhdx":
-                disk_format = "vhd"
-
-            image = common.create_image(
-                glance, common.get_unique_name(),
-                target_disk_path, disk_format,
-                config["container_format"],
-                config["hypervisor_type"])
-            images.append(image)
-
-            self._event_manager.progress_update(
-                "Waiting for Glance image to become active")
-            common.wait_for_image(nova, image.id)
-
-            virtual_disk_size = disk_file_info["virtual-size"]
-            if disk_format != constants.DISK_FORMAT_RAW:
-                virtual_disk_size += DISK_HEADER_SIZE
-
-            self._event_manager.progress_update(
-                "Creating Cinder volume")
-
-            volume_type = self._get_volume_type_for_disk(
-                cinder, disk_info, config["storage_map"])
-
-            volume = common.create_volume(
-                cinder, virtual_disk_size, common.get_unique_name(),
-                image.id, volume_type=volume_type)
-            volumes.append(volume)
-
-        return images, volumes
-
-    def _get_volume_type_for_disk(self, cinder, disk_info, storage_map):
-        default = CONF.openstack_migration_provider.default_cinder_volume_type
-        if not default:
-            # NOTE: needed so as to explicitly use None instead of an
-            # empty string in case a default is not configured.
-            default = None
-
-        dest_stor = None
-        source_stor = None
-        if 'storage_backend_identifier' in disk_info:
-            # if 'storage_backend_identifier' was provided, fetch its
-            # correspondent from the 'storage_map' or use the default.
-            source_stor = disk_info['storage_backend_identifier']
-            dest_stor = storage_map.get(source_stor, None)
-            if not dest_stor:
-                LOG.debug(
-                    'Unable to find mapping for storage system "%s" in the '
-                    'storage_map for volume "%s". Setting volume type to the '
-                    'configured default of \"%s\"',
-                    source_stor, disk_info['path'], default)
-                dest_stor = default
-        else:
-            # else if unspecified, just use the default volume type:
-            LOG.debug("No 'storage_backend_identifier' provided for disk %s. "
-                      "Trying to use default volume type of '%s'", default)
-            dest_stor = default
-
-        # ensure the volume type exists:
-        if dest_stor and not utils.retry_on_error()(
-                cinder.volume_types.findall)(name=dest_stor):
-            raise exception.CoriolisException(
-                'Unable to find volume type "%s" (mapped from "%s" on the '
-                'source). Please ensure the storage_map is correct' % (
-                    dest_stor, source_stor))
-
-        LOG.info("Chosen volume_type for disk '%s' is '%s'",
-                 disk_info['path'], dest_stor)
-        return dest_stor
-
-    def _create_neutron_ports(self, neutron, config, nics_info):
-        ports = []
-
-        for nic_info in nics_info:
-            origin_network_name = nic_info.get("network_name")
-            if not origin_network_name:
-                self._event_manager.progress_update(
-                    "Origin network name not provided for nic: %s, skipping" %
-                    nic_info.get("name"))
-                continue
-
-            network_name = config["network_map"].get(origin_network_name)
-            if not network_name:
-                raise exception.CoriolisException(
-                    "Network not mapped in network_map: %s" %
-                    origin_network_name)
-
-            ports.append(self._create_neutron_port(
-                neutron, network_name, nic_info.get("mac_address")))
-
-        return ports
-
-    @utils.retry_on_error()
-    def _get_replica_volumes(self, cinder, volumes_info):
-        volumes = []
-        for volume_id in [v["volume_id"] for v in volumes_info]:
-            volumes.append(cinder.volumes.get(volume_id))
-        return volumes
-
-    @utils.retry_on_error()
-    def _rename_volumes(self, cinder, volume_ids, instance_name):
-        for i, volume_id in enumerate(volume_ids):
-            new_volume_name = VOLUME_NAME_FORMAT % {
-                "instance_name": instance_name, "num": i + 1}
-            cinder.volumes.update(volume_id, name=new_volume_name)
-
-    @utils.retry_on_error()
-    def _set_bootable_volumes(self, cinder, volume_ids):
-        # TODO: check if just setting the first volume as bootable is enough
-        for volume_id in volume_ids:
-            volume = cinder.volumes.get(volume_id)
-            if not volume.bootable or volume.bootable == 'false':
-                cinder.volumes.set_bootable(volume, True)
-
-    def _create_volumes_from_replica_snapshots(self, cinder, volumes_info):
-        volumes = []
-        for volume_info in volumes_info:
-            snapshot_id = volume_info["volume_snapshot_id"]
-            volume_name = common.get_unique_name()
-
-            self._event_manager.progress_update(
-                "Creating Cinder volume from snapshot")
-
-            volume = common.create_volume(
-                cinder, None, volume_name, snapshot_id=snapshot_id)
-            volumes.append(volume)
-        return volumes
-
-    def get_os_morphing_tools(self, conn, osmorphing_info):
-        os_morphing_tools_clss = {
-            constants.OS_TYPE_LINUX: [coreos.CoreOSMorphingTools,
-                                      debian.DebianMorphingTools,
-                                      ubuntu.UbuntuMorphingTools,
-                                      openwrt.OpenWRTMorphingTools,
-                                      oracle.OracleMorphingTools,
-                                      redhat.RedHatMorphingTools,
-                                      suse.SUSEMorphingTools],
-            constants.OS_TYPE_WINDOWS: [windows.WindowsMorphingTools],
-        }
-
-        hypervisor_type = osmorphing_info['hypervisor_type']
-        os_type = osmorphing_info.get('os_type')
-        os_root_dir = osmorphing_info['os_root_dir']
-        os_root_dev = osmorphing_info['os_root_dev']
-
-        return base.get_os_morphing_tools_helper(
-            conn, os_morphing_tools_clss, hypervisor_type, os_type,
-            os_root_dir, os_root_dev, self._event_manager)
-
-    def _deploy_instance_resources(self, ctxt, connection_info,
-                                   target_environment, instance_name,
-                                   export_info, volumes_info=None,
-                                   clone_disks=False):
-        session = keystone.create_keystone_session(ctxt, connection_info)
-
-        glance_api_version = connection_info.get("image_api_version",
-                                                 common.GLANCE_API_VERSION)
-
-        nova = nova_client.Client(common.NOVA_API_VERSION, session=session)
-        glance = glance_client.Client(glance_api_version, session=session)
-        neutron = neutron_client.Client(common.NEUTRON_API_VERSION,
-                                        session=session)
-        cinder = cinder_client.Client(common.CINDER_API_VERSION,
-                                      session=session)
-
-        os_type = export_info.get('os_type')
-        LOG.info("os_type: %s", os_type)
-
-        config = self._get_import_config(target_environment, os_type)
-
-        images = []
-        volumes = []
-
-        try:
-            if not volumes_info:
-                # Migration
-                disks_info = export_info["devices"]["disks"]
-                images, volumes = self._create_images_and_volumes(
-                    glance, nova, cinder, config, disks_info)
-            else:
-                # Migration from replica
-                if not clone_disks:
-                    volumes = self._get_replica_volumes(cinder, volumes_info)
-                else:
-                    volumes = self._create_volumes_from_replica_snapshots(
-                        cinder, volumes_info)
-
-            migr_resources = self._deploy_migration_resources(
-                nova, glance, neutron, os_type, config["migr_image_name"],
-                config["migr_flavor_name"], config["migr_network_name"],
-                config["migr_fip_pool_name"])
-
-            nics_info = export_info["devices"].get("nics", [])
-
-            for i, volume in enumerate(volumes):
-                common.wait_for_volume(cinder, volume.id)
-
-                self._event_manager.progress_update(
-                    "Attaching volume to worker instance")
-
-                self._attach_volume(
-                    nova, cinder, migr_resources.get_instance(), volume.id)
-        finally:
-            if images:
-                self._event_manager.progress_update("Deleting Glance images")
-                for image in images:
-                    @utils.ignore_exceptions
-                    @utils.retry_on_error()
-                    def _del_image():
-                        image.delete()
-                    _del_image()
-
-        guest_conn_info = migr_resources.get_guest_connection_info()
-        hypervisor_type = self._get_osmorphing_hypervisor_type(
-            config["hypervisor_type"])
-
-        osmorphing_info = {"os_type": os_type,
-                           "hypervisor_type": hypervisor_type,
-                           "nics_info": nics_info}
-
-        volume_ids = [volume.id for volume in volumes]
-        instance_deployment_info = {
-            "config": config,
-            "migr_resources_dict": migr_resources.get_resources_dict(),
-            "volume_ids": volume_ids,
-            "instance_name": instance_name,
-            "nics_info": nics_info,
-            "os_type": os_type,
-            "clone_disks": clone_disks}
-
-        return {"instance_deployment_info": instance_deployment_info,
-                "osmorphing_connection_info": guest_conn_info,
-                "osmorphing_info": osmorphing_info}
-
-    def _finalize_instance_deployment(self, ctxt, connection_info,
-                                      instance_deployment_info):
-        session = keystone.create_keystone_session(ctxt, connection_info)
-        nova = nova_client.Client(common.NOVA_API_VERSION, session=session)
-        neutron = neutron_client.Client(common.NEUTRON_API_VERSION,
-                                        session=session)
-        cinder = cinder_client.Client(common.CINDER_API_VERSION,
-                                      session=session)
-
-        volume_ids = instance_deployment_info["volume_ids"]
-        instance_name = instance_deployment_info["instance_name"]
-        nics_info = instance_deployment_info["nics_info"]
-        config = instance_deployment_info["config"]
-        migr_resources_dict = instance_deployment_info["migr_resources_dict"]
-
-        migr_resources = _MigrationResources.from_resources_dict(
-            nova, neutron, migr_resources_dict)
-
-        self._event_manager.progress_update(
-            "Removing worker instance resources")
-        migr_resources.delete()
-
-        self._event_manager.progress_update("Renaming volumes")
-        self._rename_volumes(cinder, volume_ids, instance_name)
-
-        self._event_manager.progress_update(
-            "Ensuring volumes are bootable")
-        self._set_bootable_volumes(cinder, volume_ids)
-
-        self._event_manager.progress_update(
-            "Creating Neutron ports for migrated instance")
-        ports = self._create_neutron_ports(neutron, config, nics_info)
-
-        try:
-            self._event_manager.progress_update(
-                "Creating migrated instance")
-            self._create_target_instance(
-                nova, config["flavor_name"], instance_name,
-                config["keypair_name"], ports, volume_ids,
-                ephemeral_volumes=config["delete_disks_on_vm_termination"])
-        except:
-            self._event_manager.progress_update("Deleting Neutron ports")
-            for port in ports:
-                @utils.ignore_exceptions
-                @utils.retry_on_error()
-                def _del_port():
-                    neutron.delete_port(port["id"])
-                _del_port()
-
-    def _cleanup_failed_instance_deployment(self, ctxt, connection_info,
-                                            instance_deployment_info,
-                                            is_replica):
-        session = keystone.create_keystone_session(ctxt, connection_info)
-
-        volume_ids = instance_deployment_info.get("volume_ids", [])
-        clone_disks = instance_deployment_info.get("clone_disks")
-        migr_resources_dict = instance_deployment_info.get(
-            "migr_resources_dict")
-
-        if migr_resources_dict:
-            nova = nova_client.Client(common.NOVA_API_VERSION, session=session)
-            neutron = neutron_client.Client(common.NEUTRON_API_VERSION,
-                                            session=session)
-            migr_resources = _MigrationResources.from_resources_dict(
-                nova, neutron, migr_resources_dict)
-
-            @utils.ignore_exceptions
-            def _del_migr_resources():
-                migr_resources.delete()
-            _del_migr_resources()
-
-        # Don't remove replica volumes
-        if volume_ids and (not is_replica or clone_disks):
-            cinder = cinder_client.Client(common.CINDER_API_VERSION,
-                                          session=session)
-            self._event_manager.progress_update("Deleting volumes")
-            for volume_id in volume_ids:
-                @utils.ignore_exceptions
-                def _del_volume():
-                    common.delete_volume(cinder, volume_id)
-                _del_volume()
-
-    def _get_osmorphing_hypervisor_type(self, hypervisor_type):
-        if (hypervisor_type and
-                hypervisor_type.lower() == constants.HYPERVISOR_QEMU):
-            return constants.HYPERVISOR_KVM
-        elif hypervisor_type:
-            return hypervisor_type.lower()
-
-    @utils.retry_on_error(max_attempts=10, sleep_seconds=30,
-                          terminal_exceptions=[exception.NotFound])
-    def _create_target_instance(self, nova, flavor_name, instance_name,
-                                keypair_name, ports, volume_ids,
-                                ephemeral_volumes=False):
-        flavor = common.get_flavor(nova, flavor_name)
-
-        block_device_mapping = {}
-        for i, volume_id in enumerate(volume_ids):
-            # Delete volume on termination
-            block_device_mapping[
-                'vd%s' % chr(ord('a') + i)] = "%s:volume::%s" % (
-                    volume_id, ephemeral_volumes)
-
-        nics = [{'port-id': p['id']} for p in ports]
-
-        # Note: Nova requires an image even when booting from volume
-        LOG.info('Creating target instance...')
-        instance = nova.servers.create(
-            name=instance_name,
-            image='',
-            flavor=flavor,
-            key_name=keypair_name,
-            block_device_mapping=block_device_mapping,
-            nics=nics)
-
-        try:
-            common.wait_for_instance(nova, instance.id, 'ACTIVE')
-            return instance
-        except:
-            if instance:
-                nova.servers.delete(instance)
-            raise
-
-    def import_instance(self, ctxt, connection_info, target_environment,
-                        instance_name, export_info):
-        return self._deploy_instance_resources(
-            ctxt, connection_info, target_environment, instance_name,
-            export_info)
-
-    def finalize_import_instance(self, ctxt, connection_info,
-                                 instance_deployment_info):
-        return self._finalize_instance_deployment(
-            ctxt, connection_info, instance_deployment_info)
-
-    def cleanup_failed_import_instance(self, ctxt, connection_info,
-                                       instance_deployment_info):
-        return self._cleanup_failed_instance_deployment(
-            ctxt, connection_info, instance_deployment_info, is_replica=False)
-
-    def deploy_replica_instance(self, ctxt, connection_info,
-                                target_environment, instance_name, export_info,
-                                volumes_info, clone_disks):
-        return self._deploy_instance_resources(
-            ctxt, connection_info, target_environment, instance_name,
-            export_info, volumes_info, clone_disks)
-
-    def finalize_replica_instance_deployment(self, ctxt, connection_info,
-                                             instance_deployment_info):
-        return self._finalize_instance_deployment(
-            ctxt, connection_info, instance_deployment_info)
-
-    def cleanup_failed_replica_instance_deployment(self, ctxt, connection_info,
-                                                   instance_deployment_info):
-        return self._cleanup_failed_instance_deployment(
-            ctxt, connection_info, instance_deployment_info, is_replica=True)
-
-    def _update_existing_disk_volumes(self, cinder, disks_info, volumes_info):
-        for disk_info in disks_info:
-            disk_id = disk_info["id"]
-
-            vi = [v for v in volumes_info
-                  if v["disk_id"] == disk_id and v.get("volume_id")]
-            if vi:
-                volume_info = vi[0]
-                volume_id = volume_info["volume_id"]
-
-                volume = common.find_volume(cinder, volume_id)
-                if volume:
-                    virtual_disk_size_gb = math.ceil(
-                        disk_info["size_bytes"] / units.Gi)
-
-                    if virtual_disk_size_gb > volume.size:
-                        LOG.info(
-                            "Extending volume %(volume_id)s. "
-                            "Current size: %(curr_size)s GB, "
-                            "Requested size: %(requested_size)s GB",
-                            {"volume_id": volume_id,
-                             "curr_size": virtual_disk_size_gb,
-                             "requested_size": volume.size})
-                        self._event_manager.progress_update("Extending volume")
-                        common.extend_volume(
-                            cinder, volume_id, virtual_disk_size_gb * units.Gi)
-                    elif virtual_disk_size_gb < volume.size:
-                        LOG.warning(
-                            "Cannot shrink volume %(volume_id)s. "
-                            "Current size: %(curr_size)s GB, "
-                            "Requested size: %(requested_size)s GB",
-                            {"volume_id": volume_id,
-                             "curr_size": volume.size,
-                             "requested_size": virtual_disk_size_gb})
-                else:
-                    volumes_info.remove(volume_info)
-
-        return volumes_info
-
-    def _delete_removed_disk_volumes(self, cinder, disks_info, volumes_info):
-        for volume_info in volumes_info:
-            if volume_info["disk_id"] not in [
-                    d["id"] for d in disks_info if d["id"]]:
-
-                volume_id = volume_info["volume_id"]
-                volume = common.find_volume(cinder, volume_id)
-                if volume:
-                    self._event_manager.progress_update("Deleting volume")
-                    common.delete_volume(cinder, volume_id)
-                volumes_info.remove(volume_info)
-        return volumes_info
-
-    def _create_new_disk_volumes(
-            self, cinder, target_environment, disks_info,
-            volumes_info, instance_name):
-        try:
-            new_volumes = []
-            for i, disk_info in enumerate(disks_info):
-                disk_id = disk_info["id"]
-                virtual_disk_size = disk_info["size_bytes"]
-
-                if not [v for v in volumes_info if v["disk_id"] == disk_id]:
-                    self._event_manager.progress_update(
-                        "Creating volume")
-
-                    volume_name = REPLICA_VOLUME_NAME_FORMAT % {
-                        "instance_name": instance_name, "num": i + 1}
-
-                    storage_map = target_environment.get(
-                        'storage_map', {})
-                    volume_type = self._get_volume_type_for_disk(
-                        cinder, disk_info, storage_map)
-                    volume = common.create_volume(
-                        cinder, virtual_disk_size, volume_name,
-                        volume_type=volume_type)
-
-                    new_volumes.append(volume)
-                    volumes_info.append({
-                        "volume_id": volume.id,
-                        "disk_id": disk_id})
-                else:
-                    self._event_manager.progress_update(
-                        "Using previously deployed volume")
-
-            for volume in new_volumes:
-                common.wait_for_volume(cinder, volume.id)
-
-            return volumes_info
-        except:
-            for volume in new_volumes:
-                common.delete_volume(cinder, volume.id)
-            raise
-
-    def deploy_replica_disks(self, ctxt, connection_info, target_environment,
-                             instance_name, export_info, volumes_info):
-        session = keystone.create_keystone_session(ctxt, connection_info)
-
-        cinder = cinder_client.Client(common.CINDER_API_VERSION,
-                                      session=session)
-
-        disks_info = export_info["devices"]["disks"]
-
-        volumes_info = self._update_existing_disk_volumes(
-            cinder, disks_info, volumes_info)
-
-        volumes_info = self._delete_removed_disk_volumes(
-            cinder, disks_info, volumes_info)
-
-        volumes_info = self._create_new_disk_volumes(
-            cinder, target_environment, disks_info,
-            volumes_info, instance_name)
-
-        return volumes_info
-
-    def deploy_replica_target_resources(self, ctxt, connection_info,
-                                        target_environment, volumes_info):
-        session = keystone.create_keystone_session(ctxt, connection_info)
-
-        glance_api_version = connection_info.get("image_api_version",
-                                                 common.GLANCE_API_VERSION)
-        nova = nova_client.Client(common.NOVA_API_VERSION, session=session)
-        glance = glance_client.Client(glance_api_version, session=session)
-        neutron = neutron_client.Client(common.NEUTRON_API_VERSION,
-                                        session=session)
-        cinder = cinder_client.Client(common.CINDER_API_VERSION,
-                                      session=session)
-
-        # Data migration uses a Linux guest binary
-        os_type = constants.OS_TYPE_LINUX
-
-        config = self._get_import_config(target_environment, os_type)
-
-        migr_resources = self._deploy_migration_resources(
-            nova, glance, neutron, os_type, config["migr_image_name"],
-            config["migr_flavor_name"], config["migr_network_name"],
-            config["migr_fip_pool_name"])
-
-        try:
-            for i, volume_info in enumerate(volumes_info):
-                self._event_manager.progress_update(
-                    "Attaching volume to worker instance")
-
-                volume_id = volume_info["volume_id"]
-                ret_volume = self._attach_volume(
-                    nova, cinder, migr_resources.get_instance(), volume_id)
-                volume_info["volume_dev"] = ret_volume.device
-
-            return {
-                "migr_resources": migr_resources.get_resources_dict(),
-                "volumes_info": volumes_info,
-                "connection_info": migr_resources.get_guest_connection_info(),
-            }
-        except:
-            self._event_manager.progress_update(
-                "Removing worker instance resources")
-            migr_resources.delete()
-            raise
-
-    def delete_replica_target_resources(self, ctxt, connection_info,
-                                        migr_resources_dict):
-        session = keystone.create_keystone_session(ctxt, connection_info)
-
-        nova = nova_client.Client(common.NOVA_API_VERSION, session=session)
-        neutron = neutron_client.Client(common.NEUTRON_API_VERSION,
-                                        session=session)
-
-        migr_resources = _MigrationResources.from_resources_dict(
-            nova, neutron, migr_resources_dict)
-        self._event_manager.progress_update(
-            "Removing worker instance resources")
-        migr_resources.delete()
-
-    def delete_replica_disks(self, ctxt, connection_info, volumes_info):
-        session = keystone.create_keystone_session(ctxt, connection_info)
-
-        cinder = cinder_client.Client(common.CINDER_API_VERSION,
-                                      session=session)
-
-        self._event_manager.progress_update(
-            "Removing replica disk volumes")
-        for volume_info in volumes_info:
-            common.delete_volume(cinder, volume_info["volume_id"])
-
-    def create_replica_disk_snapshots(self, ctxt, connection_info,
-                                      volumes_info):
-        session = keystone.create_keystone_session(ctxt, connection_info)
-
-        cinder = cinder_client.Client(common.CINDER_API_VERSION,
-                                      session=session)
-
-        snapshots = []
-        self._event_manager.progress_update(
-            "Creating replica disk snapshots")
-        for volume_info in volumes_info:
-            snapshot = common.create_volume_snapshot(
-                cinder, volume_info["volume_id"], common.get_unique_name())
-            snapshots.append(snapshot)
-            volume_info["volume_snapshot_id"] = snapshot.id
-
-        for snapshot in snapshots:
-            common.wait_for_volume_snapshot(cinder, snapshot.id)
-
-        return volumes_info
-
-    def delete_replica_disk_snapshots(self, ctxt, connection_info,
-                                      volumes_info):
-        session = keystone.create_keystone_session(ctxt, connection_info)
-
-        cinder = cinder_client.Client(common.CINDER_API_VERSION,
-                                      session=session)
-
-        self._event_manager.progress_update(
-            "Removing replica disk snapshots")
-        for volume_info in volumes_info:
-            snapshot_id = volume_info.get("volume_snapshot_id")
-            if snapshot_id:
-                common.delete_volume_snapshot(cinder, snapshot_id)
-                common.wait_for_volume_snapshot(cinder, snapshot_id, 'deleted')
-                volume_info["volume_snapshot_id"] = None
-
-    def restore_replica_disk_snapshots(self, ctxt, connection_info,
-                                       volumes_info):
-        session = keystone.create_keystone_session(ctxt, connection_info)
-
-        cinder = cinder_client.Client(common.CINDER_API_VERSION,
-                                      session=session)
-
-        self._event_manager.progress_update(
-            "Restoring replica disk snapshots")
-
-        new_volumes = []
-        try:
-            for volume_info in volumes_info:
-                snapshot_id = volume_info.get("volume_snapshot_id")
-                if snapshot_id:
-                    original_volume = common.get_volume_from_snapshot(
-                        cinder, snapshot_id)
-
-                    volume_name = original_volume.name
-                    volume = common.create_volume(
-                        cinder, None, volume_name, snapshot_id=snapshot_id)
-                    new_volumes.append((volume_info, snapshot_id, volume))
-
-            for volume_info, snapshot_id, volume in new_volumes:
-                old_volume_id = volume_info["volume_id"]
-                common.wait_for_volume(cinder, volume.id)
-                common.delete_volume_snapshot(cinder, snapshot_id)
-                common.wait_for_volume_snapshot(cinder, snapshot_id, 'deleted')
-                common.delete_volume(cinder, old_volume_id)
-
-                volume_info["volume_id"] = volume.id
-                volume_info["volume_snapshot_id"] = None
-        except:
-            for _, _, volume in new_volumes:
-                common.delete_volume(cinder, volume.id)
-            raise
-
-        return volumes_info

+ 0 - 0
coriolis/providers/openstack/osmorphing/__init__.py


+ 0 - 8
coriolis/providers/openstack/osmorphing/coreos.py

@@ -1,8 +0,0 @@
-# Copyright 2017 Cloudbase Solutions Srl
-# All Rights Reserved.
-
-from coriolis.osmorphing import coreos as base_coreos
-
-
-class CoreOSMorphingTools(base_coreos.BaseCoreOSMorphingTools):
-    pass

+ 0 - 13
coriolis/providers/openstack/osmorphing/debian.py

@@ -1,13 +0,0 @@
-# Copyright 2016 Cloudbase Solutions Srl
-# All Rights Reserved.
-
-from coriolis import constants
-from coriolis.osmorphing import debian as base_debian
-
-
-class DebianMorphingTools(base_debian.BaseDebianMorphingTools):
-    _packages = {
-        constants.HYPERVISOR_VMWARE: [("open-vm-tools", True)],
-        # TODO: add cloud-initramfs-growroot
-        None: [("cloud-init", True)],
-    }

+ 0 - 8
coriolis/providers/openstack/osmorphing/openwrt.py

@@ -1,8 +0,0 @@
-# Copyright 2017 Cloudbase Solutions Srl
-# All Rights Reserved.
-
-from coriolis.osmorphing import openwrt as base_openwrt
-
-
-class OpenWRTMorphingTools(base_openwrt.BaseOpenWRTMorphingTools):
-    pass

+ 0 - 49
coriolis/providers/openstack/osmorphing/oracle.py

@@ -1,49 +0,0 @@
-# Copyright 2016 Cloudbase Solutions Srl
-# All Rights Reserved.
-
-from coriolis import constants
-from coriolis import exception
-from coriolis.osmorphing import oracle as base_oracle
-from coriolis.providers.openstack.osmorphing import redhat
-
-
-class OracleMorphingTools(base_oracle.BaseOracleMorphingTools,
-                          redhat.RedHatMorphingTools):
-    def _enable_cloud_init_repos(self):
-        self._yum_install(['yum-utils'])
-
-        distro, version = self.check_os()
-        major_version = version.split(".")[0]
-
-        # TODO: for ULN users, use the corresponding repos
-        # e.g.: ol7_x86_64_addons
-        self._exec_cmd_chroot(
-            "yum-config-manager --add-repo "
-            "http://public-yum.oracle.com/public-yum-ol%s.repo" %
-            major_version)
-
-        self._enable_repos = ["ol%s_software_collections" % major_version,
-                              "ol%s_addons" % major_version]
-
-        if major_version == "7":
-            try:
-                self._yum_install(["python-cheetah"], self._enable_repos)
-            except exception.CoriolisException:
-                # The python-pygments RPM required by python-cheetah is called
-                # python27-python-pygments. Force the installation.
-                self._yum_install(
-                    ["python-markdown", "python27-python-pygments"],
-                    self._enable_repos)
-
-                self._exec_cmd_chroot(
-                    "rpm -Uvh %s --nodeps" %
-                    "http://public-yum.oracle.com/repo/OracleLinux/OL7/addons/"
-                    "x86_64/getPackage/python-cheetah-2.4.1-1.el7.x86_64.rpm")
-
-    def pre_packages_install(self, package_names):
-        self._enable_repos = []
-        super(OracleMorphingTools, self).pre_packages_install(
-            package_names)
-
-        if self._platform == constants.PLATFORM_OPENSTACK:
-            self._enable_cloud_init_repos()

+ 0 - 80
coriolis/providers/openstack/osmorphing/redhat.py

@@ -1,80 +0,0 @@
-# Copyright 2016 Cloudbase Solutions Srl
-# All Rights Reserved.
-
-import os
-
-from oslo_log import log as logging
-import yaml
-
-from coriolis import constants
-from coriolis import exception
-from coriolis.osmorphing import redhat as base_redhat
-
-LOG = logging.getLogger(__name__)
-
-RELEASE_RHEL = "Red Hat Enterprise Linux Server"
-RELEASE_CENTOS = "CentOS Linux"
-RELEASE_FEDORA = "Fedora"
-
-DEFAULT_CLOUD_USER = "cloud-user"
-
-
-class RedHatMorphingTools(base_redhat.BaseRedHatMorphingTools):
-    _packages = {
-        constants.HYPERVISOR_VMWARE: [("open-vm-tools", True)],
-        constants.HYPERVISOR_HYPERV: [("hyperv-daemons", True)],
-        None: [
-            ("dracut-config-generic", False),
-            ("cloud-init", True),
-            ("cloud-utils", False),
-            ("parted", False),
-            ("git", False),
-            ("cloud-utils-growpart", False)],
-    }
-
-    def _get_default_cloud_user(self):
-        cloud_cfg_path = os.path.join(self._os_root_dir, 'etc/cloud/cloud.cfg')
-        if not self._test_path(cloud_cfg_path):
-            raise exception.CoriolisException(
-                "cloud-init config file not found: %s" % cloud_cfg_path)
-        cloud_cfg_content = self._read_file(cloud_cfg_path)
-        cloud_cfg = yaml.load(cloud_cfg_content)
-        return cloud_cfg.get('system_info', {}).get('default_user', {}).get(
-            'name', DEFAULT_CLOUD_USER)
-
-    def _configure_cloud_init(self):
-        if "cloud-init" in self.get_packages()[0]:
-            cloud_user = self._get_default_cloud_user()
-            if not self._check_user_exists(cloud_user):
-                self._exec_cmd_chroot("useradd %s" % cloud_user)
-            self._set_network_nozeroconf_config()
-            if self._has_systemd():
-                self._enable_systemd_service("cloud-init")
-
-    def _add_hyperv_ballooning_udev_rules(self):
-        udev_file = "etc/udev/rules.d/100-balloon.rules"
-        content = 'SUBSYSTEM=="memory", ACTION=="add", ATTR{state}="online"\n'
-
-        if (self._hypervisor == constants.HYPERVISOR_HYPERV and
-                not self._test_path(udev_file)):
-            self._write_file_sudo(udev_file, content)
-
-    def pre_packages_install(self, package_names):
-        super(RedHatMorphingTools, self).pre_packages_install(package_names)
-
-        distro, version = self.check_os()
-        if distro == RELEASE_RHEL and "cloud-init" in self.get_packages()[0]:
-            major_version = version.split(".")[0]
-            repo_name = "rhel-%s-server-rh-common-rpms" % major_version
-            # This is necessary for cloud-init
-            self._event_manager.progress_update(
-                "Enabling repository: %s" % repo_name)
-            self._exec_cmd_chroot(
-                "subscription-manager repos --enable %s" % repo_name)
-
-    def post_packages_install(self, package_names):
-        self._add_hyperv_ballooning_udev_rules()
-        self._run_dracut()
-        self._configure_cloud_init()
-        self._set_selinux_autorelabel()
-        super(RedHatMorphingTools, self).post_packages_install(package_names)

+ 0 - 48
coriolis/providers/openstack/osmorphing/suse.py

@@ -1,48 +0,0 @@
-# Copyright 2016 Cloudbase Solutions Srl
-# All Rights Reserved.
-
-from coriolis import constants
-from coriolis.osmorphing import suse as base_suse
-
-
-class SUSEMorphingTools(base_suse.BaseSUSEMorphingTools):
-    _packages = {
-        constants.HYPERVISOR_VMWARE: [("open-vm-tools", True)],
-        None: [("cloud-init", True)],
-    }
-
-    def pre_packages_install(self, package_names):
-        super(SUSEMorphingTools, self).pre_packages_install(package_names)
-
-        if self._platform == constants.PLATFORM_OPENSTACK:
-            # TODO: use OS version to choose the right repo
-            repo_version_map = {("SLES", "11.4"): "SLE_11_SP4",
-                                ("SLES", "11.3"): "SLE_11_SP3",
-                                ("SLES", "11.2"): "SLE_11_SP2",
-                                ("SLES", "12.1"): "SLE_12_SP1",
-                                ("SLES", "12"): "SLE_12",
-                                ("openSUSE", "13.2"): "openSUSE_13.2",
-                                ("openSUSE Leap", "42.1"):
-                                "openSUSE_Leap_42.1",
-                                ("openSUSE Tumbleweed", None):
-                                "openSUSE_Tumbleweed"}
-
-            repo_version = repo_version_map.get(
-                (self._distro, self._version_id), "SLE_12_SP1")
-
-            repo = "obs://Cloud:Tools/%s" % repo_version
-            self._event_manager.progress_update("Adding repository: %s" % repo)
-            self._exec_cmd_chroot("zypper --non-interactive addrepo -f %s "
-                                  "Cloud-Tools" % repo)
-        self._exec_cmd_chroot(
-            "zypper --non-interactive --no-gpg-checks refresh")
-
-    def _configure_cloud_init(self):
-        if "cloud-init" in self.get_packages()[0]:
-            if self._has_systemd():
-                self._enable_systemd_service("cloud-init")
-
-    def post_packages_install(self, package_names):
-        self._run_dracut()
-        self._configure_cloud_init()
-        super(SUSEMorphingTools, self).post_packages_install(package_names)

+ 0 - 16
coriolis/providers/openstack/osmorphing/ubuntu.py

@@ -1,16 +0,0 @@
-# Copyright 2016 Cloudbase Solutions Srl
-# All Rights Reserved.
-
-from coriolis import constants
-from coriolis.osmorphing import ubuntu as base_ubuntu
-
-
-class UbuntuMorphingTools(base_ubuntu.BaseUbuntuMorphingTools):
-    _packages = {
-        constants.HYPERVISOR_VMWARE: [("open-vm-tools", True)],
-        # TODO: sudo agt-get install linux-tool-<kernel release>
-        # linux-cloud-tools-<kernel release> -y
-        constants.HYPERVISOR_HYPERV: [("hv-kvp-daemon-init", True)],
-        # TODO: add cloud-initramfs-growroot
-        None: [("cloud-init", True)],
-    }

+ 0 - 228
coriolis/providers/openstack/osmorphing/windows.py

@@ -1,228 +0,0 @@
-# Copyright 2016 Cloudbase Solutions Srl
-# All Rights Reserved.
-
-import uuid
-
-from distutils import version
-from oslo_config import cfg
-from oslo_log import log as logging
-
-from coriolis import constants
-from coriolis.osmorphing import windows as base_windows
-
-opts = [
-    cfg.StrOpt('virtio_iso_url',
-               default='https://fedorapeople.org/groups/virt/virtio-win/'
-               'direct-downloads/stable-virtio/virtio-win.iso',
-               help="Location of the virtio-win ISO"),
-    cfg.StrOpt('cloudbaseinit_x64_url',
-               default="https://www.cloudbase.it/downloads/"
-               "CloudbaseInitSetup_x64.zip",
-               help="Location of the Cloudbase-Init ZIP for amd64 systems"),
-    cfg.StrOpt('cloudbaseinit_x86_url',
-               default="https://www.cloudbase.it/downloads/"
-               "CloudbaseInitSetup_x86.zip",
-               help="Location of the Cloudbase-Init ZIP for amd64 systems"),
-]
-
-CONF = cfg.CONF
-CONF.register_opts(opts, 'windows_images')
-
-LOG = logging.getLogger(__name__)
-
-SERVICE_START_AUTO = 2
-SERVICE_START_MANUAL = 3
-SERVICE_START_DISABLED = 4
-
-SERVICE_PATH_FORMAT = "HKLM:\\%s\\ControlSet001\\Services\\%s"
-CLOUDBASEINIT_SERVICE_NAME = "cloudbase-init"
-
-
-class WindowsMorphingTools(base_windows.BaseWindowsMorphingTools):
-    def pre_packages_install(self, packages_add):
-        if (not self._hypervisor or
-                self._hypervisor == constants.HYPERVISOR_KVM):
-            self._add_virtio_drivers()
-
-        if self._platform == constants.PLATFORM_OPENSTACK:
-            self._add_cloudbase_init()
-        else:
-            self._disable_cloudbase_init()
-
-    def _add_virtio_drivers(self):
-        # TODO: add support for x86
-        arch = "amd64"
-
-        CLIENT = 1
-        SERVER = 2
-
-        # Ordered by version number
-        virtio_dirs = [
-            ("xp", version.LooseVersion("5.1"), CLIENT),
-            ("2k3", version.LooseVersion("5.2"), SERVER),
-            ("2k8", version.LooseVersion("6.0"), SERVER | CLIENT),
-            ("w7", version.LooseVersion("6.1"), CLIENT),
-            ("2k8R2", version.LooseVersion("6.1"), SERVER),
-            ("w8", version.LooseVersion("6.2"), CLIENT),
-            ("2k12", version.LooseVersion("6.2"), SERVER),
-            ("w8.1", version.LooseVersion("6.3"), CLIENT),
-            ("2k12R2", version.LooseVersion("6.3"), SERVER),
-            ("w10", version.LooseVersion("10.0"), SERVER | CLIENT),
-        ]
-
-        # The list of all possible editions is huge, this is a semplification
-        if "Server" in self._edition_id:
-            edition_type = SERVER
-        else:
-            edition_type = CLIENT
-
-        drivers = ["Balloon", "NetKVM", "qxl", "qxldod", "pvpanic", "viorng",
-                   "vioscsi", "vioserial", "viostor"]
-
-        self._event_manager.progress_update("Downloading virtio-win drivers")
-
-        virtio_iso_path = "c:\\virtio-win.iso"
-        self._conn.download_file(
-            CONF.windows_images.virtio_iso_url, virtio_iso_path)
-
-        self._event_manager.progress_update("Adding virtio-win drivers")
-
-        virtio_drive = self._mount_disk_image(virtio_iso_path)
-        try:
-            for virtio_dir, dir_version, dir_edition_type in reversed(
-                    virtio_dirs):
-                if self._version_number >= dir_version and (
-                        edition_type & dir_edition_type):
-                    path = "%s:\\Balloon\\%s\\%s" % (
-                        virtio_drive, virtio_dir, arch)
-                    if self._conn.test_path(path):
-                        break
-
-            driver_paths = ["%s:\\%s\\%s\\%s" % (
-                            virtio_drive, d, virtio_dir, arch)
-                            for d in drivers]
-
-            sid = self._get_sid()
-            # Fails on Nano Server without explicitly granting permissions
-            file_repo_path = ("%sWindows\System32\DriverStore\FileRepository" %
-                              self._os_root_dir)
-            self._grant_permissions(file_repo_path, "*%s" % sid)
-            try:
-                for driver_path in driver_paths:
-                    if self._conn.test_path(driver_path):
-                        self._add_dism_driver(driver_path)
-            finally:
-                self._revoke_permissions(file_repo_path, "*%s" % sid)
-        finally:
-            self._dismount_disk_image(virtio_iso_path)
-
-    def _write_cloudbase_init_conf(self, cloudbaseinit_base_dir,
-                                   local_base_dir, com_port="COM1"):
-        LOG.info("Writing Cloudbase-Init configuration files")
-        conf_dir = "%s\\conf" % cloudbaseinit_base_dir
-        self._conn.exec_ps_command("mkdir '%s' -Force" % conf_dir,
-                                   ignore_stdout=True)
-
-        conf_file_path = "%s\\cloudbase-init.conf" % conf_dir
-
-        conf_content = (
-            "[DEFAULT]\n"
-            "username = Admin\n"
-            "groups = Administrators\n"
-            "inject_user_password = true\n"
-            "config_drive_raw_hhd = true\n"
-            "config_drive_cdrom = true\n"
-            "config_drive_vfat = true\n"
-            "bsdtar_path = %(bin_path)s\\bsdtar.exe\n"
-            "mtools_path = %(bin_path)s\n"
-            "logdir = %(log_path)s\n"
-            "logfile = cloudbase-init.log\n"
-            "default_log_levels = "
-            "comtypes=INFO,suds=INFO,iso8601=WARN,requests=WARN\n"
-            "mtu_use_dhcp_config = true\n"
-            "ntp_use_dhcp_config = true\n"
-            "allow_reboot = true\n"
-            "debug = true\n"
-            "logging_serial_port_settings = %(com_port)s,115200,N,8\n" %
-            {"bin_path": "%s\\Bin" % local_base_dir,
-             "log_path": "%s\\Log" % local_base_dir,
-             "com_port": com_port})
-
-        self._conn.write_file(conf_file_path, conf_content.encode())
-
-    def _check_cloudbase_init_exists(self, key_name):
-        reg_service_path = (SERVICE_PATH_FORMAT %
-                            (key_name, CLOUDBASEINIT_SERVICE_NAME))
-        return self._conn.exec_ps_command(
-            "Test-Path %s" % reg_service_path) == "True"
-
-    def _disable_cloudbase_init(self):
-        key_name = str(uuid.uuid4())
-        self._load_registry_hive(
-            "HKLM\%s" % key_name,
-            "%sWindows\\System32\\config\\SYSTEM" % self._os_root_dir)
-        try:
-            if self._check_cloudbase_init_exists(key_name):
-                self._event_manager.progress_update(
-                    "Disabling cloudbase-init")
-                self._set_service_start_mode(
-                    key_name, CLOUDBASEINIT_SERVICE_NAME,
-                    SERVICE_START_DISABLED)
-        finally:
-            self._unload_registry_hive("HKLM\%s" % key_name)
-
-    def _add_cloudbase_init(self):
-        # TODO: add support for x86
-        arch = "amd64"
-        arch_url_map = {"amd64": CONF.windows_images.cloudbaseinit_x64_url,
-                        "x86": CONF.windows_images.cloudbaseinit_x86_url}
-
-        self._event_manager.progress_update("Adding cloudbase-init")
-
-        key_name = str(uuid.uuid4())
-        self._load_registry_hive(
-            "HKLM\%s" % key_name,
-            "%sWindows\\System32\\config\\SYSTEM" % self._os_root_dir)
-        try:
-            if self._check_cloudbase_init_exists(key_name):
-                self._event_manager.progress_update(
-                    "Enabling cloudbase-init")
-                self._set_service_start_mode(
-                    key_name, CLOUDBASEINIT_SERVICE_NAME, SERVICE_START_AUTO)
-            else:
-                cloudbaseinit_zip_path = "c:\\cloudbaseinit.zip"
-                cloudbaseinit_base_dir = "%sCloudbase-Init" % self._os_root_dir
-
-                self._event_manager.progress_update(
-                    "Downloading cloudbase-init")
-                self._conn.download_file(arch_url_map[arch],
-                                         cloudbaseinit_zip_path)
-
-                self._event_manager.progress_update(
-                    "Installing cloudbase-init")
-                self._expand_archive(cloudbaseinit_zip_path,
-                                     cloudbaseinit_base_dir)
-
-                log_dir = "%s\\Log" % cloudbaseinit_base_dir
-                self._conn.exec_ps_command("mkdir '%s' -Force" % log_dir,
-                                           ignore_stdout=True)
-
-                local_base_dir = "C%s" % cloudbaseinit_base_dir[1:]
-                self._write_cloudbase_init_conf(
-                    cloudbaseinit_base_dir, local_base_dir)
-
-                image_path = (
-                    '""""%(path)s\\Bin\\OpenStackService.exe"""" '
-                    'cloudbase-init """"%(path)s\\Python\\Python.exe"""" -c '
-                    '""""from cloudbaseinit import shell;shell.main()"""" '
-                    '--config-file """"%(path)s\\conf\\cloudbase-init.conf""""'
-                    % {'path': local_base_dir})
-
-                self._create_service(
-                    key_name=key_name,
-                    service_name=CLOUDBASEINIT_SERVICE_NAME,
-                    image_path=image_path,
-                    display_name="Cloud Initialization Service",
-                    description="Service wrapper for cloudbase-init")
-        finally:
-            self._unload_registry_hive("HKLM\%s" % key_name)

+ 0 - 64
coriolis/providers/openstack/schemas/connection_info_schema.json

@@ -1,64 +0,0 @@
-{
-  "$schema": "http://cloudbase.it/coriolis/schemas/openstack_connection#",
-  "oneOf": [
-    {
-      "type": "object",
-      "properties": {
-        "identity_api_version": {
-          "type": "integer",
-          "minimum": 2,
-          "maximum": 3
-        },
-        "username": {
-          "type": "string"
-        },
-        "password": {
-          "type": "string"
-        },
-        "project_name": {
-          "type": "string"
-        },
-        "user_domain_name": {
-          "type": "string"
-        },
-        "project_domain_name": {
-          "type": "string"
-        },
-        "auth_url": {
-          "type": "string"
-        },
-        "allow_untrusted": {
-          "type": "boolean",
-          "default": false
-        }
-      },
-      "required": [
-        "username",
-        "password",
-        "project_name",
-        "auth_url"
-      ],
-      "additionalProperties": false
-    },
-    {
-      "type": "object",
-      "properties": {
-        "secret_ref": {
-          "type": "string",
-          "format": "uri"
-        }
-      },
-      "required": ["secret_ref"],
-      "additionalProperties": false
-    },
-    {
-      "type": "object",
-      "properties": {
-      },
-      "additionalProperties": false
-    },
-    {
-      "type": "null"
-    }
-  ]
-}

+ 0 - 57
coriolis/providers/openstack/schemas/target_environment_schema.json

@@ -1,57 +0,0 @@
-{
-  "$schema": "http://cloudbase.it/coriolis/schemas/openstack_target_environment#",
-  "oneOf": [
-    {
-      "type": "object",
-      "properties": {
-        "network_map": {
-          "type": "object"
-        },
-        "storage_map": {
-          "type": "object"
-        },
-        "glance_upload": {
-          "type": "boolean"
-        },
-        "disk_format": {
-          "type": "string"
-        },
-        "delete_disks_on_vm_termination": {
-            "type": "boolean"
-        },
-        "container_format": {
-          "type": "string"
-        },
-        "hypervisor_type": {
-          "type": "string"
-        },
-        "migr_image_name": {
-          "type": "string"
-        },
-        "migr_image_name_map": {
-          "type": "object"
-        },
-        "migr_flavor_name": {
-          "type": "string"
-        },
-        "flavor_name": {
-          "type": "string"
-        },
-        "fip_pool_name": {
-          "type": "string"
-        },
-        "migr_fip_pool_name": {
-          "type": "string"
-        },
-        "keypair_name": {
-          "type": "string"
-        }
-      },
-      "required": [
-        "network_map",
-        "flavor_name"
-      ],
-      "additionalProperties": false
-    }
-  ]
-}

+ 0 - 4
requirements.txt

@@ -19,11 +19,7 @@ paste
 pbr
 psutil
 pyOpenSSL
-python-cinderclient
-python-glanceclient>=2.0.0
 python-keystoneclient
-python-neutronclient
-python-novaclient
 python-barbicanclient
 python-swiftclient>=3.2
 pyVmomi