1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
|
"""
Module showcasing various operations on resources exposed
through Coriolis' endpoints API.
"""
import json
import jsonschema
from keystoneauth1.identity import v3
from keystoneauth1 import session as ksession
from coriolisclient import client as coriolis_client
CORIOLIS_CONNECTION_INFO = {
"auth_url": "http://127.0.0.1:5000/v3",
"username": "admin",
"password": "foCVs9hnoSB32dMVNtMLHLaOLDquJUoz1N3p53dd",
"project_name": "admin",
"user_domain_name": "default",
"project_domain_name": "default"
}
# IDs of pre-existing Coriolis endpoints for both platforms.
# Samples relating to endpoint management can be found in 'endpoint_samples.py'
AZURE_ENDPOINT_ID = "67ae217c-d125-498d-82bc-690916900258"
OCI_ENDPOINT_ID = "885fe551-4502-4f55-b24c-1aae96b9ae24"
# Set of options related to the source Azure environment:
AZURE_SOURCE_OPTIONS = {
"location": "westus",
"resource_group": "testing-resgroup"
}
# Set of options related to the destination OCI environment:
OCI_DESTINATION_OPTIONS = {
"availability_domain": "mQqX:EU-FRANKFURT-1-AD-3",
"compartment": "<OCID of compartment>",
"vcn_compartment": "<OCID of compartment housing VCNs>",
}
# Mapping between identifiers of networks on the source Azure to VCNs
# in the destination OCI to be used for the NICs of the Migrated VM(s):
NETWORK_MAP = {
"azure-test-network/azure-test-subnet": "<OCI network OCID>"
}
# Mappings between identifiers of storage elements on the source Azure
# and available storage typs on the destination OCI to be used for the
# disks of the Migrated VM(s):
STORAGE_MAPPINGS = {
"default": "standard",
"backend_mappings": {
"Premium_LRS": "standard"
},
"disk_mappings": {
"<ID of disk>": "<mapping for specific disk>"
}
}
def get_schema_for_plugin(coriolis, platform_type, schema_type):
"""
Returns a JSON schema detailing params expected by a given plugin.
:param platform_type: type of platform (e.g. 'openstack', 'oci', 'azure')
:param schema_type: schema type(e.g. 'connection', 'source', 'destination')
:return: dict() containiGng the requrested JSON schema
"""
provider_schema_type_map = {
"destination": 1,
"source": 2,
"connection": 16
}
return coriolis.providers.schemas_list(
platform_type, provider_schema_type_map[schema_type]).to_dict()
def check_mapped_networks_exist(coriolis, destination_endpoint, network_map,
destination_environment=None):
"""
Checks whether all of the mapped networks exist on the destination.
:param destination_endpoint: destination endpoint object or ID
:param network_map: network mapping dict
:param destination_environment: optional environment options for target
:raises: Exception if a network is not found.
"""
networks = coriolis.endpoint_networks.list(
destination_endpoint, environment=destination_environment)
for mapped_net in network_map.values():
matches = [
net for net in networks
if net.id == mapped_net or net.name == mapped_net]
if not matches:
raise Exception(
"Could not find network '%s' on the destination. Available "
"networks are: %s" % (mapped_net, networks))
def check_mapped_storage_exists(coriolis, destination_endpoint,
storage_mappings,
destination_environment=None):
"""
Checks whether all of the mapped storage types exist on the destination.
:param destination_endpoint: destination endpoint object or ID
:param storage_mappings: storage mappings dict
:param destination_environment: optional environment options for target
:raises: Exception if storage is not found.
"""
storage = coriolis.endpoint_storage.list(
destination_endpoint, environment=destination_environment)
def _check_stor(storage_name_or_id):
matches = [
stor for stor in storage
if (stor.id == storage_name_or_id or
stor.name == storage_name_or_id)]
if not matches:
raise Exception(
"Could not find storage type '%s' in: %s" % (
storage_name_or_id, storage))
return matches[0]
# check default:
default = storage_mappings.get('default')
if default is not None:
_check_stor(default)
# check backend mappings:
backend_mappings = storage_mappings.get('backend_mappings', {})
for mapped_storage in backend_mappings.values():
_check_stor(mapped_storage)
# check per-disk mappings:
for mapped_storage in storage_mappings.get('disk_mappings', {}).values():
_check_stor(mapped_storage)
def get_linux_vms_for_endpoint(coriolis, source_endpoint, source_options=None):
""" Returns a list of the names/IDs of Linux VMs on a source endpoint """
vms = coriolis.endpoint_instances.list(
source_endpoint, env=source_options)
return [vm for vm in vms if vm.os_type == 'linux']
def check_vm_network_mapping(coriolis, source_endpoint, vm_name_or_id,
network_map, source_options=None):
"""
Fetches detailed info on the given source VM and checks that all of its
NICs have an appropriate mapping in the given network_map
:param source_endpoint: source endpoint name or ID
:param vm_id: identifier (name or ID) of the the VM on the source
:param network_map: network mapping
:param source_options: added source environment options
"""
vm_info = coriolis.endpoint_instances.get(
source_endpoint, vm_name_or_id, env=source_options)
for nic in vm_info['devices']['nics']:
if nic['network_name'] not in network_map.values():
raise Exception(
"Mapped network for NIC with MAC '%s' not found: %s" % (
nic['mac_address'], nic['network_name']))
def main():
session = ksession.Session(
auth=v3.Password(**CORIOLIS_CONNECTION_INFO))
coriolis = coriolis_client.Client(session=session)
# fetch and validate options for Azure:
azure_schema = get_schema_for_plugin(
'coriolis', 'azure', 'source')
# NOTE: this parameter validation is also done in any API
# call involving the Azure source options:
jsonschema.validate(AZURE_SOURCE_OPTIONS, azure_schema)
# fetch and validate options schema for OCI:
oci_schema = get_schema_for_plugin(
'coriolis', 'oci', 'destination')
# NOTE: this parameter validation is also done in any API
# call involving the OCI destination options:
jsonschema.validate(OCI_DESTINATION_OPTIONS, oci_schema)
# list all available options on source or target:
azure_options = coriolis.endpoint_source_options.list(
AZURE_ENDPOINT_ID, environment=AZURE_SOURCE_OPTIONS)
print("Avaialble Azure options are: ", json.dumps(azure_options, indent=4))
oci_options = coriolis.endpoint_destination_options.list(
OCI_ENDPOINT_ID, environment=OCI_DESTINATION_OPTIONS)
print("Avaialble OCI options are: ", json.dumps(oci_options, indent=4))
# check all mapped networks and storage exist:
check_mapped_networks_exist(
coriolis, OCI_ENDPOINT_ID, NETWORK_MAP,
destination_environment=OCI_DESTINATION_OPTIONS)
check_mapped_storage_exists(
coriolis, OCI_ENDPOINT_ID, NETWORK_MAP,
destination_environment=OCI_DESTINATION_OPTIONS)
# get list of Linux VMs off of Azure:
azure_linux_vms = get_linux_vms_for_endpoint(
coriolis, AZURE_ENDPOINT_ID, source_options=AZURE_SOURCE_OPTIONS)
print("Linux VMs currently on Azure: %s" % azure_linux_vms)
# check network mapping:
if azure_linux_vms:
vm_name = azure_linux_vms[0].instance_name
check_vm_network_mapping(
coriolis, AZURE_ENDPOINT_ID, vm_name, NETWORK_MAP,
source_options=AZURE_SOURCE_OPTIONS)
|