Parcourir la source

Removes the Azure provider

Alessandro Pilotti il y a 9 ans
Parent
commit
95f38e6c1f

+ 0 - 1013
coriolis/providers/azure/__init__.py

@@ -1,1013 +0,0 @@
-# Copyright 2016 Cloudbase Solutions Srl
-# All Rights Reserved.
-
-""" This module defines the Azure Resource Manager Importer and Exporter. """
-
-import collections
-import contextlib
-import math
-import os
-import os.path as path
-import re
-import tempfile
-import time
-import traceback
-
-import paramiko
-import requests
-from azure.mgmt import compute, network, storage
-from azure.mgmt.resource import resources
-from azure.storage import blob
-from msrestazure import azure_active_directory, azure_exceptions
-from oslo_config import cfg
-from oslo_log import log as logging
-from oslo_utils import units
-
-from coriolis import constants
-from coriolis import events
-from coriolis import exception
-from coriolis.osmorphing import manager as osmorpher
-from coriolis.providers import base
-from coriolis.providers.azure import utils as azutils
-from coriolis.providers.azure import exceptions as azexceptions
-from coriolis import schemas
-from coriolis import utils
-
-
-OPTIONS = [
-    # TODO: AzureStack soon: default for "auth_url", used in client creation.
-    cfg.StrOpt("default_auth_url",
-               default="https://management.core.windows.net/",
-               help="The API endpoint to authenticate and perform operations"
-                    "against."),
-    cfg.StrOpt("migr_location",
-               default="westus",
-               help="The default Azure location to migrate to "
-                    "when no location is specified through the "
-                    "target_environment."),
-    cfg.StrOpt("migr_subnet_name",
-               default="coriolis-worknet",
-               help="Name of the subnet to be used by worker instances."),
-    cfg.StrOpt("migr_container_name",
-               default="coriolis",
-               help="Name of the azure storage container which"
-                    "will support the migration."),
-    cfg.StrOpt("default_migration_hostname",
-               default="migratedinst",
-               help="Default hostname to be used in case the hostname of the "
-                    "instance being migrated does not conform with Azure's "
-                    "standards (no special characters of maximum length 15)."),
-    cfg.DictOpt("worker_volume_count_to_size_map",
-                default=collections.OrderedDict([
-                    (2, compute.models.VirtualMachineSizeTypes.standard_d1),
-                    (4, compute.models.VirtualMachineSizeTypes.standard_d2),
-                    (8, compute.models.VirtualMachineSizeTypes.standard_d3),
-                    (16, compute.models.VirtualMachineSizeTypes.standard_d4),
-                    (32, compute.models.VirtualMachineSizeTypes.standard_d5_v2)
-                ]),
-                help="Mapping between the number of volumes supported by "
-                     "an Azure instance size and its name (with correct "
-                     "capitalization and underscores) as show here: "
-                     "https://azure.microsoft.com/en-us/documentation/"
-                     "articles/virtual-machines-windows-sizes/"),
-    cfg.DictOpt("migr_image_sku_map",
-                default={
-                    constants.OS_TYPE_LINUX: "14.04.3-LTS",
-                    constants.OS_TYPE_WINDOWS: "2012-R2-Datacenter"
-                },
-                help="Mapping of image SKUs to be used for migration workers "
-                     "with respect to the type of OS being migrated.")
-]
-
-CONF = cfg.CONF
-CONF.register_opts(OPTIONS, "azure_migration_provider")
-
-LOG = logging.getLogger(__name__)
-
-MIGRATION_RESGROUP_NAME_FORMAT = "coriolis-migration-%s"
-MIGRATION_WORKER_NAME_FORMAT = "coriolis-worker-%s"
-AZURE_DISK_NAME_FORMAT = "%s.vhd"
-MIGRATION_WORKER_NIC_NAME_FORMAT = "coriolis-worker-nic-%s"
-MIGRATION_WORKER_PIP_NAME_FORMAT = "coriolis-worker-pip-%s"
-MIGRATION_NETWORK_NAME_FORMAT = "coriolis-migrnet-%s"
-
-BLOB_PATH_FORMAT = "https://%s.blob.core.windows.net/%s/%s"
-
-SSH_PUBKEY_FORMAT = "ssh-rsa %s tmp@migration"
-SSH_PUBKEY_FILEPATH_FORMAT = "/home/%s/.ssh/authorized_keys"
-
-PROVIDERS_NAME_MAP = {
-    x: "Microsoft." + x.capitalize()
-    for x in ["compute", "network"]
-}
-
-WORKER_VM_IMAGE_VERSION = "latest"
-
-WORKER_IMAGES_MAP = {
-    constants.OS_TYPE_LINUX: {
-        "version": WORKER_VM_IMAGE_VERSION,
-        "publisher": "canonical",
-        "offer": "UbuntuServer"
-    },
-    constants.OS_TYPE_WINDOWS: {
-        "version": WORKER_VM_IMAGE_VERSION,
-        "publisher": "MicrosoftWindowsServer",
-        "offer": "WindowsServer"
-    },
-}
-
-AZURE_OSTYPES_MAP = {
-    "linux":   compute.models.OperatingSystemTypes.linux,
-    "windows": compute.models.OperatingSystemTypes.windows
-}
-
-WINRM_EXTENSION_FILES_BASE_URI = (
-    # TODO: not fetch off github
-    "https://raw.githubusercontent.com/cloudbase/coriolis-resources/master/azure/")
-
-WINRM_EXTENSION_FILE_URIS = [
-    WINRM_EXTENSION_FILES_BASE_URI + f
-    for f in ["ConfigureWinRM.ps1", "makecert.exe", "winrmconf.cmd"]
-]
-
-WORKER_USERNAME = "coriolis"
-
-# NOTE: connection_info
-CREDENTIALS_CATEGORIES = ["user_credentials", "service_principal_credentials"]
-USER_CREDENTIALS_FIELDS = ["username", "password"]
-SP_CREDENTIALS_FIELDS = ["client_id", "client_secret", "tenant_id"]
-
-# An AzureStorageBlob is identified by its unique name and URI on Azure.
-AzureStorageBlob = collections.namedtuple(
-    "AzureStorageBlob", "name uri")
-
-# An AzureWorkerOSProfile is identified by the compute.models.OSProfile, the
-# authentication token to the machine (ssh key or cert thubprint), the port
-# awaiting the respective connection, as well as a list of
-# compute.models.VirtualMachineExtension's required by the worker.
-AzureWorkerOSProfile = collections.namedtuple(
-    "AzureWorkerOSProfile", "profile token port extensions")
-
-# An AzureWorkerInstance is identified by its unique name, ip address, port,
-# username, password, authentication token and its list of datadisks.
-AzureWorkerInstance = collections.namedtuple(
-    "AzureWorkerInstance", "name ip port username password pkey datadisks")
-
-
-class ImportProvider(base.BaseImportProvider):
-    """ Provides import capabilities. """
-    platform = constants.PLATFORM_AZURE_RM
-
-    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)
-
-    def validate_connection_info(self, connection_info):
-        """ Validates the provided connection information. """
-        LOG.info("Validating connection info: %s", connection_info)
-
-        super(ImportProvider, self).validate_connection_info(connection_info)
-
-        # NOTE: considering we cannot check the validity of the credentials per
-        # se if a secret href is provided here, we simply return on the spot:
-        if "secret_ref" in connection_info:
-            return
-
-        try:
-            # NOTE: attempt to register to a provider to ensure credentials
-            # are indeed actually valid.
-            resc = self._get_resource_client(connection_info)
-            utils.retry_on_error()(azutils.checked(resc.providers.register))(
-                PROVIDERS_NAME_MAP["compute"])
-        except (KeyError, azure_exceptions.CloudError,
-                azexceptions.AzureOperationException) as ex:
-
-            raise exception.InvalidInput(
-                "Invalid or incomplete Azure credentials provided")
-
-    def _get_cloud_credentials(self, connection_info):
-        """ returns the msrestazure.azure_active_directory.Credentials
-        implementation for the given connection_info. Should both user/pass and
-        service principal details be provided, the user/pass auth flow is
-        preffered.
-        """
-        user_creds, sp_creds = [connection_info.get(x, {}) for x in
-                                CREDENTIALS_CATEGORIES]
-
-        if user_creds and all([x in user_creds for x in
-                               USER_CREDENTIALS_FIELDS]):
-            return azure_active_directory.UserPassCredentials(
-                user_creds["username"],
-                user_creds["password"]
-            )
-
-        if sp_creds and all([x in sp_creds for x in
-                             SP_CREDENTIALS_FIELDS]):
-            return azure_active_directory.ServicePrincipalCredentials(
-                client_id=sp_creds["client_id"],
-                secret=sp_creds["client_secred"],
-                tenent=sp_creds["tenant_id"]
-            )
-
-        # NOTE: this ending raise is redundant considering the schema-based
-        # validation; but allows for another layer of validation considering
-        # a possible discrepancy between the schema and the code...
-        raise azexceptions.AzureOperationException(
-            msg="Either 'user_credentials' or 'service_principal_credentials' "
-            "must be specified in 'connection_info'.",
-            code=-1)
-
-    def _get_compute_client(self, connection_info):
-        """ Returns an azure.mgmt.compute.ComputeManagementClient.
-        """
-        return compute.ComputeManagementClient(
-            self._get_cloud_credentials(connection_info),
-            connection_info["subscription_id"])
-
-    def _get_network_client(self, connection_info):
-        """ Returns an azure.mgmt.network.NetworkResourceProviderClient. """
-        return network.NetworkManagementClient(
-            self._get_cloud_credentials(connection_info),
-            connection_info["subscription_id"])
-
-    def _get_storage_client(self, connection_info):
-        """ Returns an azure.mgmt.storage.StorageManagementClient. """
-        return storage.StorageManagementClient(
-            self._get_cloud_credentials(connection_info),
-            connection_info["subscription_id"])
-
-    def _get_resource_client(self, connection_info):
-        """ Returns an azure.mgmt.resource.ResourceManagementClient. """
-        return resources.ResourceManagementClient(
-            self._get_cloud_credentials(connection_info),
-            connection_info["subscription_id"])
-
-    def _get_page_blob_client(self, target_environment):
-        """ Returns an azure.storage.blob.PageBlobService client. """
-        return blob.PageBlobService(
-            account_name=target_environment["storage"]["account"],
-            account_key=target_environment["storage"]["key"]
-        )
-
-    def _get_block_blob_client(self, target_environment):
-        """ Returns an azure.storage.blob.PageBlobService client. """
-        return blob.BlockBlobService(
-            account_name=target_environment["storage"]["account"],
-            account_key=target_environment["storage"]["key"]
-        )
-
-    def _delete_recovery_disk(self, target_environment, vm_name):
-        """ Removes the recovery disk block blob for the given
-        instance name.
-        """
-        blobd = self._get_block_blob_client(target_environment)
-        cont_name = CONF.azure_migration_provider.migr_container_name
-
-        blob_names = [b.name
-                      for b in blobd.list_blobs(cont_name)
-                      if re.match(r"%s\..*\.status" % vm_name, b.name)]
-        if len(blob_names) > 1:
-            self._event_manager.progress_update(
-                "VM \"%s\" has more than one recovery disk. "
-                "Skipped deleting any to avoid adverse loss")
-
-        if len(blob_names) == 1:
-            blobd.delete_blob(cont_name, blob_names[0])
-
-    @utils.retry_on_error()
-    def _upload_disk(self, target_environment, disk_path, upload_name):
-        """ Uploads the disk from the provided path to an Azure blob
-        and returns the corresponding AzureStorageBlob.
-        """
-        self._event_manager.progress_update(
-            "Uploading disk from \"%s\" as \"%s\"" % (disk_path, upload_name))
-
-        def progressf(curr, total):
-            LOG.debug("Uploading '%s': %d/%d.", upload_name, curr, total)
-
-        blobd = self._get_page_blob_client(target_environment)
-
-        stor_name = target_environment["storage"]["account"]
-        cont_name = CONF.azure_migration_provider.migr_container_name
-        disk_uri = BLOB_PATH_FORMAT % (stor_name, cont_name, upload_name)
-
-        blobd.create_blob_from_path(
-            cont_name, upload_name, disk_path, progress_callback=progressf)
-
-        return AzureStorageBlob(
-            name=upload_name,
-            uri=disk_uri
-        )
-
-    @utils.retry_on_error()
-    def _create_migration_network(self, connection_info, target_environment,
-                                  migration_id):
-        """ Creates the virtual network to be used for the migration and
-        returns the response from its creation operation.
-        """
-        self._event_manager.progress_update(
-            "Creating migration network")
-
-        awaited = azutils.awaited(timeout=150)
-        netc = self._get_network_client(connection_info)
-        resgroup = MIGRATION_RESGROUP_NAME_FORMAT % migration_id
-        vn_name = MIGRATION_NETWORK_NAME_FORMAT % migration_id
-
-        awaited(netc.virtual_networks.create_or_update)(
-            resgroup,
-            vn_name,
-            network.models.VirtualNetwork(
-                location=target_environment.get(
-                    "location",
-                    CONF.azure_migration_provider.migr_location),
-                address_space=network.models.AddressSpace(
-                    # NOTE: can safely be completely arbitrary:
-                    address_prefixes=["10.0.0.0/16"]
-                ),
-                subnets=[
-                    network.models.Subnet(
-                        name=CONF.azure_migration_provider.migr_subnet_name,
-                        # NOTE: can safely be completely arbitrary:
-                        address_prefix='10.0.0.0/24'
-                    )
-                ]
-            ),
-        )
-
-        return azutils.checked(netc.virtual_networks.get)(resgroup, vn_name)
-
-    @utils.retry_on_error(
-        terminal_exceptions=[azexceptions.FatalAzureOperationException])
-    def _wait_for_vm(self, connection_info, resgroup, vm_name, period=30):
-        """ Blocks until the given VM has been started. """
-        vmclient = self._get_compute_client(connection_info).virtual_machines
-        state = azutils.checked(vmclient.get)(resgroup, vm_name)
-
-        while state.provisioning_state != "Succeeded":
-            if state.provisioning_state not in ("Creating", "Updating"):
-                raise azexceptions.FatalAzureOperationException(
-                    code=-1,
-                    msg="Awaited VM '%s' has reached an invalid state: %s" %
-                    (vm_name, state.provisioning_state)
-                )
-
-            time.sleep(period)
-            state = azutils.checked(vmclient.get)(resgroup, vm_name)
-
-    def _get_worker_osprofile(self, os_type, location, worker_name):
-        """ Returns the AzureWorkerOSProfile associated to the worker instance
-        on Azure. For Linux workers, the returned authentication token is a
-        paramiko.RSAKey the machine has been configured with.
-        For windows workers, the configured password is returned.
-        """
-        if os_type == constants.OS_TYPE_LINUX:
-            return self._get_linux_worker_osprofile(worker_name)
-        elif os_type == constants.OS_TYPE_WINDOWS:
-            return self._get_windows_worker_osprofile(
-                location, worker_name)
-
-        raise azexceptions.FatalAzureOperationException(
-            code=-1,
-            msg="Unsupported migration OS type '%s'." % os_type
-        )
-
-    def _get_linux_worker_osprofile(self, worker_name):
-        """ Returns the AzureWorkerOSProfile afferent to a Linux worker. """
-        LOG.info("Linux chosen as worker '%s' OS.", worker_name)
-
-        key = paramiko.RSAKey.generate(2048)
-
-        os_profile = compute.models.OSProfile(
-            admin_username=WORKER_USERNAME,
-            # NOTE: intentional lack of 'admin_password' provided so
-            # as to enable passwordless sudo on the target machine.
-            computer_name=worker_name,
-            linux_configuration=compute.models.LinuxConfiguration(
-                disable_password_authentication=True,
-                ssh=compute.models.SshConfiguration(
-                    public_keys=[compute.models.SshPublicKey(
-                        key_data=SSH_PUBKEY_FORMAT % key.get_base64(),
-                        path=SSH_PUBKEY_FILEPATH_FORMAT % WORKER_USERNAME
-                    )],
-                ),
-            )
-        )
-
-        return AzureWorkerOSProfile(
-            profile=os_profile,
-            token=key,
-            port=22,  # NOTE: default port used on Azure-provided images.
-            extensions=[]
-        )
-
-    def _get_windows_worker_osprofile(self, location, worker_name):
-        """ Returns the AzureWorkerOSProfile afferent to a Windows worker. """
-        LOG.info("Windows was chosen as worker '%s' OS.", worker_name)
-
-        password = azutils.get_random_password()
-        os_profile = compute.models.OSProfile(
-            computer_name=azutils.normalize_hostname(worker_name),
-            admin_username=WORKER_USERNAME,
-            admin_password=password,
-            windows_configuration=compute.models.WindowsConfiguration(
-                provision_vm_agent=True,
-                enable_automatic_updates=False,
-            )
-        )
-
-        winrm_extension = compute.models.VirtualMachineExtension(
-            location,
-            publisher=PROVIDERS_NAME_MAP["compute"],
-            virtual_machine_extension_type="CustomScriptExtension",
-            type_handler_version="1.4",
-            settings=dict(
-                fileUris=WINRM_EXTENSION_FILE_URIS,
-                commandToExecute="powershell -ExecutionPolicy Unrestricted "
-                                 "-file ConfigureWinRM.ps1 "
-                                 "*.%s.cloudapp.azure.com" % location
-            ),
-        )
-
-        return AzureWorkerOSProfile(
-            profile=os_profile,
-            token=password,
-            port=5986,  # NOTE: default port opened via the extension
-            extensions=[winrm_extension]
-        )
-
-    @utils.retry_on_error()
-    def _create_nic(self, connection_info, resgroup, nic_name,
-                    location, ip_configs):
-        """ Creates a network interface with the specified params.
-
-        NOTE: Azure does unfortunately not allow for the setting of MAC
-        addresses. A NIC's MAC is determined when the VM the NIC is attached
-        to is booted.
-        """
-
-        awaited = azutils.awaited(timeout=200)
-        net_client = self._get_network_client(connection_info)
-
-        nic = network.models.NetworkInterface(
-            location=location,
-            ip_configurations=ip_configs
-        )
-
-        awaited(net_client.network_interfaces.create_or_update)(
-            resgroup,
-            nic_name,
-            nic
-        )
-
-        return azutils.checked(net_client.network_interfaces.get)(
-            resgroup, nic_name)
-
-    @utils.retry_on_error()
-    def _create_public_ip(self, connection_info, resgroup, ip_name, location):
-        awaited = azutils.awaited(timeout=90)
-        net_client = self._get_network_client(connection_info)
-
-        awaited(net_client.public_ip_addresses.create_or_update)(
-            resgroup,
-            ip_name,
-            network.models.PublicIPAddress(
-                location=location,
-                public_ip_allocation_method=network.models.IPAllocationMethod.dynamic,
-            ),
-        )
-
-        return azutils.checked(net_client.public_ip_addresses.get)(
-            resgroup, ip_name)
-
-    def _convert_to_vhd(self, disk_path):
-        """ Converts the disk file given by its path to a fixed VHD and returns
-        the path of the resulting disk.
-
-        Does NOT check if it already is a VHD.
-        """
-        newpath = "%s.%s" % (
-            path.splitext(disk_path)[0],
-            constants.DISK_FORMAT_VHD
-        )
-
-        try:
-            utils.convert_disk_format(
-                disk_path, newpath,
-                constants.DISK_FORMAT_VHD,
-                preallocated=True
-            )
-        except Exception as ex:
-            raise azexceptions.FatalAzureOperationException(
-                code=-1,
-                msg="Unable to convert disk '%s' to fixed VHD." % disk_path
-            ) from ex
-
-        return newpath
-
-    def _migrate_disk(self, target_environment, lun,
-                      disk_path, upload_name):
-        """ Moves the given disk file to Azure storage as a page blob. """
-        disk_file_info = utils.get_disk_info(disk_path)
-
-        upload_path = disk_path
-
-        # convert disk if necessary:
-        if disk_file_info["format"] != constants.DISK_FORMAT_VHD:
-            self._event_manager.progress_update(
-                "Converting disk \"%s\" from \"%s\" to \"%s\"" %
-                (upload_name, disk_file_info["format"],
-                 constants.DISK_FORMAT_VHD))
-
-            upload_path = self._convert_to_vhd(disk_path)
-            os.remove(disk_path)
-
-        try:
-            blb = self._upload_disk(
-                target_environment, upload_path, upload_name)
-        except Exception as ex:
-            # NOTE: _upload_disk is set to retry, so it's game over here:
-            raise azexceptions.FatalAzureOperationException(
-                code=-1,
-                msg="Failed to upload disk '%s' to Azure." % upload_name
-            ) from ex
-        finally:
-            os.remove(upload_path)
-
-        return compute.models.DataDisk(
-            lun=lun,
-            name=blb.name,
-            caching=compute.models.CachingTypes.none,
-            vhd=compute.models.VirtualHardDisk(uri=blb.uri),
-            # NOTE: we must force Azure to resize the disk itself to ensure the
-            # 1MB internal size alignment without which the VM will not boot.
-            # Maximum granularity for specifying disk size on Azure is 1GB.
-            disk_size_gb=math.ceil(disk_file_info["virtual-size"] / units.Gi) + 2,
-            create_option=compute.models.DiskCreateOptionTypes.attach,
-        )
-
-    @utils.retry_on_error()
-    def _get_subnet(self, connection_info, resgroup, vn_name, sub_name):
-        """ Fetches information for the specified subnet. """
-        net_client = self._get_network_client(connection_info)
-
-        return azutils.checked(net_client.subnets.get)(
-            resgroup, vn_name, sub_name)
-
-    @utils.retry_on_error()
-    def _get_pub_ip(self, connection_info, resgroup, ip_name):
-        """ Fetches information for the given public IP address. """
-        net_client = self._get_network_client(connection_info)
-
-        return azutils.checked(net_client.public_ip_addresses.get)(
-            resgroup, ip_name)
-
-    def _get_worker_size(self, worker_name, ndisks):
-        """ Returns the required size of the worker needed to handle
-        the migration/transformation of the data disks. """
-        mapping = CONF.azure_migration_provider.worker_volume_count_to_size_map
-        volsmap = collections.OrderedDict(
-            [(n, mapping[n]) for n in sorted(mapping.keys())])
-
-        for maxvols, size in volsmap.items():
-            if ndisks <= maxvols:
-                self._event_manager.progress_update(
-                    "Migration worker size chosen as \"%s\"" %
-                    str(size).split(".")[-1])
-
-                return size
-
-        raise azexceptions.FatalAzureOperationException(
-            code=-1,
-            msg=("No Azure size suitable for migrating the instance "
-                 "as it has too many volumes (%d).", ndisks)
-        )
-
-    @utils.retry_on_error(
-        terminal_exceptions=[azexceptions.FatalAzureOperationException])
-    def _create_migration_worker(self, connection_info, target_environment,
-                                 export_info, migration_id, datadisks):
-        """ Creates and returns the connection information of the worker which
-        will perform the final operations on the migrating VM.
-        """
-        resgroup = MIGRATION_RESGROUP_NAME_FORMAT % migration_id
-        worker_name = MIGRATION_WORKER_NAME_FORMAT % migration_id
-
-        self._event_manager.progress_update("Creating migration worker")
-
-        awaited = azutils.awaited(timeout=600)
-        location = target_environment.get(
-            "location", CONF.azure_migration_provider.migr_location)
-        location = azutils.normalize_location(location)
-
-        # create the NIC and public IP:
-        self._event_manager.progress_update(
-            "Creating migration worker Public IP")
-
-        ip_name = MIGRATION_WORKER_PIP_NAME_FORMAT % migration_id
-        pub_ip = self._create_public_ip(connection_info, resgroup,
-                                        ip_name, location)
-
-        self._event_manager.progress_update(
-            "Creating migration worker NIC")
-
-        nic_name = MIGRATION_WORKER_NIC_NAME_FORMAT % migration_id
-        nic = self._create_nic(
-            connection_info, resgroup, nic_name, location,
-            ip_configs=[
-                network.models.NetworkInterfaceIPConfiguration(
-                    name=nic_name + "-ipconf",
-                    subnet=self._get_subnet(
-                        connection_info,
-                        resgroup,
-                        MIGRATION_NETWORK_NAME_FORMAT % migration_id,
-                        CONF.azure_migration_provider.migr_subnet_name
-                    ),
-                    private_ip_allocation_method=network.models.IPAllocationMethod.dynamic,
-                    public_ip_address=pub_ip,
-                )
-            ]
-        )
-
-        # create the worker:
-        worker_disk_name = AZURE_DISK_NAME_FORMAT % worker_name
-        computec = self._get_compute_client(connection_info)
-        worker_osprofile = self._get_worker_osprofile(
-            export_info["os_type"], location, worker_name)
-        worker_img = WORKER_IMAGES_MAP[export_info["os_type"]]
-        target_env_sku_map = target_environment.get("migr_image_sku_map", {})
-        conf_sku = CONF.azure_migration_provider.migr_image_sku_map.get(
-            export_info["os_type"])
-        worker_img_sku = target_environment.get(
-            "migr_image_sku",
-            target_env_sku_map.get(export_info["os_type"], conf_sku))
-
-
-        awaited(computec.virtual_machines.create_or_update)(
-            resgroup,
-            worker_name,
-            compute.models.VirtualMachine(
-                location=location,
-                os_profile=worker_osprofile.profile,
-                hardware_profile=compute.models.HardwareProfile(
-                    self._get_worker_size(worker_name, len(datadisks))
-                ),
-                network_profile=compute.models.NetworkProfile(
-                    network_interfaces=[
-                        compute.models.NetworkInterfaceReference(
-                            id=nic.id,
-                        ),
-                    ]
-                ),
-                storage_profile=compute.models.StorageProfile(
-                    os_disk=compute.models.OSDisk(
-                        caching=compute.models.CachingTypes.none,
-                        create_option=compute.models.DiskCreateOptionTypes.from_image,
-                        name=worker_disk_name,
-                        vhd=compute.models.VirtualHardDisk(
-                            BLOB_PATH_FORMAT % (
-                                target_environment["storage"]["account"],
-                                CONF.azure_migration_provider.migr_container_name,
-                                worker_disk_name
-                            )
-                        ),
-                    ),
-                    data_disks=datadisks,
-                    image_reference=compute.models.ImageReference(
-                        publisher=worker_img["publisher"],
-                        offer=worker_img["offer"],
-                        sku=worker_img_sku,
-                        version=worker_img["version"]
-                    )
-                )
-            )
-        )
-
-        self._event_manager.progress_update(
-            "Waiting for migration worker to start")
-        self._wait_for_vm(connection_info, resgroup, worker_name)
-        self._event_manager.progress_update(
-            "Migration worker has started succesfully")
-
-        # add any neccessary extensions to the Worker:
-        for ext in worker_osprofile.extensions:
-            self._event_manager.progress_update(
-                "Creating Worker VM extensions \"%s\"" % ext.name)
-
-            awaited(computec.virtual_machine_extensions.create_or_update)(
-                resgroup,
-                worker_name,
-                ext.name,
-                ext
-            )
-
-        # fetch the instance's allocated ip:
-        pub_ip = self._get_pub_ip(connection_info, resgroup, ip_name)
-
-        return AzureWorkerInstance(
-            name=worker_name,
-            ip=pub_ip.ip_address,
-            port=worker_osprofile.port,
-            datadisks=datadisks,
-            username=worker_osprofile.profile.admin_username,
-            password=worker_osprofile.profile.admin_password,
-            pkey=worker_osprofile.token
-        )
-
-    def _get_migration_os_profile(self, os_type, instance_name):
-        computer_name = instance_name
-        if os_type == constants.OS_TYPE_WINDOWS:
-            computer_name = azutils.normalize_hostname(instance_name)
-
-        profile = compute.models.OSProfile(
-            computer_name=computer_name,
-            # NOTE: here we are forced to provide a username and password to
-            # the API. These values will be ignored by the Azure agent as
-            # provisioning is turned off in the agent's configuration in
-            # the osmorphing stage.
-            admin_username="coriolis",
-            admin_password=azutils.get_random_password()
-        )
-
-        if os_type == constants.OS_TYPE_WINDOWS:
-            profile.windows_configuration = (
-                compute.models.WindowsConfiguration(
-                    provision_vm_agent=True,
-                    enable_automatic_updates=False,
-                )
-            )
-
-        return profile
-
-    def import_instance(self, ctxt, connection_info, target_environment,
-                        instance_name, export_info):
-        """ Runs the process of importing the instance to Azure. """
-        self._event_manager.progress_update(
-            "Importing instance \"%s\"" % instance_name)
-
-        awaited = azutils.awaited(300)
-        location = target_environment.get(
-            "location", CONF.azure_migration_provider.migr_location)
-        location = azutils.normalize_location(location)
-
-        migration_id = azutils.get_unique_id()[:10]
-        resgroup = MIGRATION_RESGROUP_NAME_FORMAT % migration_id
-
-        worker_info = None
-
-        try:
-            # setup storage container:
-            cont_name = CONF.azure_migration_provider.migr_container_name
-            self._event_manager.progress_update(
-                "Creating migration storage container \"%s\"" % cont_name)
-
-            blobd = self._get_page_blob_client(target_environment)
-            utils.retry_on_error()(blobd.create_container)(
-                cont_name, public_access=blob.PublicAccess.Container)
-
-            # migrate the instance's attached volumes:
-            datadisks = []
-            for lun, disk in enumerate(export_info["devices"]["disks"]):
-                LOG.info("Processing instance disk number %d", (lun + 1))
-
-                disk_name = AZURE_DISK_NAME_FORMAT % (
-                    instance_name + "_" + str(lun))
-                try:
-                    datadisk = self._migrate_disk(
-                        target_environment, lun, disk["path"], disk_name)
-                except:
-                    raise
-                else:
-                    datadisks.append(datadisk)
-
-            # setup migration resource group:
-            self._event_manager.progress_update(
-                "Creating migration resource group \"%s\"" % resgroup)
-
-            resc = self._get_resource_client(connection_info)
-            utils.retry_on_error()(
-                azutils.checked(resc.resource_groups.create_or_update))(
-                    resgroup,
-                    resources.models.ResourceGroup(location))
-
-            # create the migration network:
-            self._create_migration_network(
-                connection_info, target_environment, migration_id)
-
-            # create the worker:
-            worker_info = self._create_migration_worker(
-                connection_info, target_environment, export_info,
-                migration_id, datadisks)
-
-            # morph the images:
-            self._event_manager.progress_update(
-                "Preparing instance for new environment")
-
-            osmorpher.morph_image(
-                worker_info._asdict(),
-                export_info["os_type"],
-                constants.HYPERVISOR_HYPERV,
-                constants.PLATFORM_AZURE_RM,
-                None,
-                self._event_manager,
-                ignore_devices=["/dev/sdb"]
-            )
-
-            # delete the worker:
-            self._event_manager.progress_update("Deleting migration worker")
-            vmclient = self._get_compute_client(
-                connection_info).virtual_machines
-            utils.retry_on_error()(awaited(vmclient.delete))(
-                resgroup, worker_info.name)
-
-            # setup vm nics:
-            self._event_manager.progress_update(
-                "Setting up instance NICs")
-
-            nics = []
-            for i, nic in enumerate(export_info["devices"].get("nics", [])):
-                nic_name = nic.get("name", "%s-NIC-%d" % (instance_name, i + 1))
-                net_name = nic.get("network_name", None)
-                subnet_name = nic.get("subnet_name", None)
-                add_public_ip = False
-
-                if not net_name:
-                    net = target_environment.get("destination_network", {})
-                    net_name = net.get("name", None)
-
-                    if not net or not net_name:
-                        raise azexceptions.FatalAzureOperationException(
-                            code=-1,
-                            msg="A network to which to perform the migration "
-                                "must be specified within the target "
-                                "environment in order to add NIC '%s' to "
-                                "instance '%s'." % (
-                                    nic_name, instance_name)
-                        )
-
-                    LOG.info("'network_name' not provided for NIC '%s'. "
-                             "Attempting to attach to migration network '%s'.",
-                             nic_name, net_name)
-
-                    net_name = target_environment["destination_network"]["name"]
-                    subnet_name = target_environment[
-                        "destination_network"]["subnet"]
-                    add_public_ip = target_environment[
-                        "destination_network"]["is_public_network"]
-
-                else:
-                    network_map = target_environment.get("network_map", [])
-                    if not network_map:
-                        raise azexceptions.FatalAzureOperationException(
-                            code=-1,
-                            msg="A network map must be specified within the "
-                                "target environment in order to map the "
-                                "network of nic '%s', namely '%s'." % (
-                                    nic_name, net_name
-                                )
-                        )
-
-                    net = None
-                    for netm in network_map:
-                        if netm["source_network"] == net_name:
-                            net = netm
-                    if not net:
-                        raise azexceptions.FatalAzureOperationException(
-                            code=-1,
-                            msg="Cannot find suitable network name "
-                                "for attaching nic '%s' within the network "
-                                "map under the name '%s'" % (
-                                    nic_name, nic.get("network_name")
-                                )
-                        )
-
-                    net_name = net["destination_network"]
-                    subnet_name = net["destination_subnet"]
-                    add_public_ip = net["is_public_network"]
-
-                nic_name = azutils.normalize_resource_name(nic_name)
-
-                nic_ip_config = network.models.NetworkInterfaceIPConfiguration(
-                    name=nic_name + "-ipconf",
-                    subnet=self._get_subnet(
-                        connection_info,
-                        target_environment["resource_group"],
-                        net_name,
-                        subnet_name
-                    ),
-                    private_ip_allocation_method=network.models.IPAllocationMethod.dynamic,
-                )
-
-                if add_public_ip:
-                    ip_name = "%s-pip" % nic_name
-                    pub_ip = self._create_public_ip(
-                        connection_info,
-                        target_environment["resource_group"],
-                        ip_name, location
-                    )
-
-                    nic_ip_config.public_ip_address = pub_ip
-
-                nics.append(self._create_nic(
-                    connection_info,
-                    target_environment["resource_group"],
-                    nic_name,
-                    location,
-                    ip_configs=[nic_ip_config],
-                ))
-
-            # create the VM:
-            self._event_manager.progress_update(
-                "Starting migrated instance as \"%s\"" %
-                    azutils.normalize_resource_name(instance_name))
-
-            disk_name = AZURE_DISK_NAME_FORMAT % (
-                "".join(instance_name) + "_os_disk")
-            vm_profile = self._get_migration_os_profile(
-                export_info["os_type"], instance_name)
-
-            vmclient = self._get_compute_client(
-                connection_info).virtual_machines
-            utils.retry_on_error()(awaited(vmclient.create_or_update))(
-                target_environment["resource_group"],
-                azutils.normalize_resource_name(instance_name),
-                compute.models.VirtualMachine(
-                    location=location,
-                    os_profile=vm_profile,
-                    hardware_profile=compute.models.HardwareProfile(
-                        vm_size=compute.models.VirtualMachineSizeTypes(
-                            target_environment["size"]
-                        )
-                    ),
-                    network_profile=compute.models.NetworkProfile(
-                        network_interfaces=[compute.models.NetworkInterfaceReference(x.id)
-                                            for x in nics]
-                    ),
-                    storage_profile=compute.models.StorageProfile(
-                        os_disk=compute.models.OSDisk(
-                            name=disk_name,
-                            os_type=AZURE_OSTYPES_MAP[export_info["os_type"]],
-                            caching=compute.models.CachingTypes.none,
-                            create_option=compute.models.DiskCreateOptionTypes.from_image,
-                            # NOTE: we are guaranteed that the first disk is
-                            # the one with the OS inside it:
-                            image=worker_info.datadisks[0].vhd,
-                            vhd=compute.models.VirtualHardDisk(
-                                BLOB_PATH_FORMAT % (
-                                    target_environment["storage"]["account"],
-                                    CONF.azure_migration_provider.migr_container_name,
-                                    disk_name
-                                )
-                            ),
-                        ),
-                        # NOTE: we are guaranteed that the first disk in the
-                        # export_info is the one with the OS inside of it,
-                        # thus the rest are the datadisks:
-                        data_disks=worker_info.datadisks[1:],
-                    )
-                ),
-            )
-        except:
-            self._cleanup(connection_info, target_environment,
-                          resgroup, worker_info)
-            LOG.error(
-                "Exception occurred during import:\n" + traceback.format_exc())
-            raise
-        finally:
-            self._cleanup(connection_info, target_environment,
-                          resgroup, worker_info)
-
-    @utils.retry_on_error()
-    def _cleanup(self, connection_info, target_environment,
-                 migration_resgroup, worker_info):
-        """ Cleans up all resources for the migration. Is idempotent. """
-        awaited = azutils.awaited()
-
-        self._event_manager.progress_update("Cleaning up migration resource group")
-        resc = self._get_resource_client(connection_info)
-
-        # check if the migration resource group still exists:
-        if resc.resource_groups.check_existence(migration_resgroup):
-            # then, delete it:
-            awaited(resc.resource_groups.delete)(migration_resgroup)
-
-        if not worker_info:
-            # it means that the worker never got defined, and we may return:
-            return
-
-        worker_name = worker_info.name
-
-        # lastly, delete the worker's disks:
-        # delete worker disks:
-        blobd = self._get_page_blob_client(target_environment)
-        cont_name = CONF.azure_migration_provider.migr_container_name
-        blob_name = AZURE_DISK_NAME_FORMAT % worker_name
-
-        if blobd.exists(cont_name, blob_name):
-            blobd.delete_blob(cont_name, blob_name)
-
-        self._delete_recovery_disk(target_environment, worker_name)

+ 0 - 20
coriolis/providers/azure/exceptions.py

@@ -1,20 +0,0 @@
-# Copyright 2016 Cloudbase Solutions Srl
-# All Rights Reserved.
-
-"""
-Defines various exceptions which may arise during migrations to/from Azure.
-"""
-
-from coriolis import exception
-from coriolis.i18n import _
-
-
-class AzureOperationException(exception.CoriolisException):
-    """ Simply wraps a standard CoriolisException. """
-    message = _("Azure operation failed with code: %(code)d. "
-                "Error message: %(msg)s.")
-
-
-class FatalAzureOperationException(AzureOperationException):
-    """ Extends AzureOperationExceptions to indicate fatal errors. """
-    pass

+ 0 - 57
coriolis/providers/azure/schemas/connection_info_schema.json

@@ -1,57 +0,0 @@
-{
-  "$schema": "http://cloudbase.it/coriolis/schemas/azure_connection#",
-  "type": "object",
-  "properties": {
-    "secret_ref": {
-      "type": "string"
-    },
-    "subscription_id": {
-      "type": "string"
-    },
-    "user_credentials": {
-      "type": "object",
-      "properties": {
-        "username": {
-          "type": "string"
-        },
-        "password": {
-          "type": "string"
-        }
-      },
-      "required": [
-        "username",
-        "password"
-      ]
-    },
-    "service_principal_credentials": {
-      "type": "object",
-      "properties": {
-        "client_id": {
-          "type": "string"
-        },
-        "client_secret": {
-          "type": "string"
-        },
-        "tenant_id": {
-          "type": "string"
-        }
-      },
-      "required": [
-        "client_id",
-        "client_secret",
-        "tenant_id"
-      ]
-    }
-  },
-  "oneOf": [
-    {
-      "required": ["secret_ref"]
-    },
-    {
-      "required": ["subscription_id", "user_credentials"]
-    },
-    {
-      "required": ["subscription_id", "service_principal_credentials"]
-    }
-  ]
-}

+ 0 - 98
coriolis/providers/azure/schemas/target_environment_schema.json

@@ -1,98 +0,0 @@
-{
-  "$schema": "http://cloudbase.it/coriolis/schemas/azure_target_environment#",
-  "type": "object",
-  "properties": {
-    "secret_ref": {
-      "type": "string"
-    },
-    "size": {
-      "type": "string"
-    },
-    "location": {
-      "type": "string"
-    },
-    "resource_group": {
-      "type": "string"
-    },
-    "storage": {
-      "type": "object",
-      "properties": {
-        "account": {
-          "type": "string"
-        },
-        "key": {
-          "type": "string"
-        },
-        "container": {
-          "type": "string"
-        }
-      },
-      "required": [
-        "account",
-        "key"
-      ]
-    },
-    "migr_image_sku": {
-        "type": "string"
-    },
-    "migr_image_sku_map": {
-        "type": "object"
-    },
-    "network_map": {
-      "type": "array",
-      "items": {
-        "type": "object",
-        "properties": {
-          "source_network": {
-            "type": "string"
-          },
-          "destination_network": {
-            "type": "string"
-          },
-          "destination_subnet_name": {
-            "type": "string"
-          },
-          "is_public_network": {
-            "type": "boolean"
-          }
-        },
-        "required": [
-          "source_network",
-          "destination_network",
-          "destination_subnet",
-          "is_public_network"
-        ]
-      }
-    },
-    "destination_network": {
-      "type": "object",
-      "properties": {
-        "name": {
-          "type": "string"
-        },
-        "subnet": {
-          "type": "string"
-        },
-        "is_public_network": {
-          "type": "boolean"
-        }
-      },
-      "required": [
-        "name",
-        "subnet",
-        "is_public_network"
-      ]
-    }
-  },
-  "oneOf": [
-    {
-      "required": ["secret_ref"]
-    },
-    {
-      "required": ["size", "location", "resource_group", "storage", "destination_network"]
-    },
-    {
-      "required": ["size", "location", "resource_group", "storage", "network_map"]
-    }
-  ]
-}

+ 0 - 101
coriolis/providers/azure/utils.py

@@ -1,101 +0,0 @@
-# Copyright 2016 Cloudbase Solutions Srl
-# All Rights Reserved.
-
-"""
-General utility functions for performing Azure operations.
-"""
-
-import functools
-import random
-import string
-import uuid
-
-from oslo_config import cfg
-from oslo_log import log as logging
-
-
-CONF = cfg.CONF
-LOG = logging.getLogger(__name__)
-
-
-def get_random_password():
-    """ Returns a random password compatible with the minimal requirements of
-    Azure to be used for worker instances (namely, to contain 8+ characters
-    with any 3 of: a character (lower or uppoercase), digit or special symbol).
-    """
-    upper = random.choice(string.ascii_uppercase)
-    lower = random.choice(string.ascii_lowercase)
-    digit = random.choice(string.digits)
-
-    return "%s%s%s%s" % (
-        upper, digit, lower, get_unique_id()
-    )
-
-
-def get_unique_id():
-    """ Returns a generically Azure-friendly ID. """
-    return "".join([x for x in str(uuid.uuid4()) if x.isalnum()])
-
-
-def normalize_resource_name(name):
-    """ Normalizes a resource name.
-
-    Constraints are:
-        - alphanumeric characters or '.', '-', '_'
-        - maximum length is 80
-    """
-    return "".join([x for x in name if x.isalnum() or x in ['.', '-', '_']])
-
-
-def normalize_hostname(hostname):
-    """ Normalizes the provided hostname for Azure.
-
-    Constraints are:
-        - no special characters
-        - maximum length of 15
-    """
-    new = "".join([x for x in hostname if x.isalnum])
-    if not new:
-        new = CONF.azure_migration_provider.default_migration_hostname
-        LOG.info("Cannot normalize instance hostname '%s' for Azure. "
-                 "Defaulting to using '%s'.", hostname, new)
-
-    if len(new) > 15:
-        new = new[:15]
-
-    if new != hostname:
-        LOG.info("Normalized instance hostname '%s' to '%s' "
-                 "for booting instance on Azure.", new, hostname)
-
-    return new
-
-
-def normalize_location(location):
-    """ Normalizes a location for azure. """
-    return "".join([x.lower() for x in location if x.isalnum()])
-
-
-def checked(operation):
-    """ Forces raw status code check on an Azure operation. """
-    @functools.wraps(operation)
-    def _checked(*args, **kwargs):
-        resp = operation(*args, raw=True, **kwargs)
-
-        return resp.output
-
-    return _checked
-
-
-def awaited(timeout=90):
-    """ Awaits for the result of the given operation. """
-
-    def _awaited(operation):
-        @functools.wraps(operation)
-        def _await(*args, **kwargs):
-            resp = operation(
-                *args, long_running_operation_timeout=timeout, **kwargs)
-
-            return resp.result()
-        return _await
-
-    return _awaited

+ 0 - 7
requirements.txt

@@ -27,10 +27,3 @@ PyYAML
 requests
 sqlalchemy
 webob
-msrest==0.4.0
-msrestazure==0.4.1
-azure-mgmt-compute==0.30.0rc5
-azure-mgmt-network==0.30.0rc5
-azure-mgmt-resource==0.30.0rc5
-azure-mgmt-storage==0.30.0rc5
-azure-storage==0.32.0