diff --git a/ci/lib.py b/ci/lib.py index c60a1fe4d71418aa66eac8eaac3df264acf1cacf..3ac628e768c8890915b39ad3d6318c6df12ec1ba 100644 --- a/ci/lib.py +++ b/ci/lib.py @@ -49,33 +49,6 @@ def get_ostack_project_names(project_name): return project_name.split('->', 1) return project_name, project_name -def get_destination_network(source_network): - """ LUT for networks """ - network_mapping = { - # shared - "78-128-250-pers-proj-net" : "internal-ipv4-general-private", - "147-251-115-pers-proj-net" : "internal-ipv4-general-private", - "public-muni-v6-432" : "external-ipv6-general-public", - # external - "public-muni-147-251-21-GROUP": "external-ipv4-general-public", - "public-cesnet-78-128-250-PERSONAL": "external-ipv4-general-public", - "public-cesnet-78-128-251-GROUP": "external-ipv4-general-public", - "provider-public-cerit-sc-147-251-253": "external-ipv4-general-public", - "public-muni-147-251-115-PERSONAL": "external-ipv4-general-public", - "public-muni-147-251-124-GROUP": "external-ipv4-general-public", - "public-cesnet-195-113-167-GROUP": "external-ipv4-general-public", - "public-muni-147-251-11-128-254": "external-ipv4-general-public", - "public-muni-CERIT-FI-147-251-88-132-254": "external-ipv4-general-public", - "public-muni-CSIRT-MU-217-69-96-64-240": "external-ipv4-general-public", - "public-muni-csirt-147-251-125-16-31": "external-ipv4-general-public", - "provider-public-cerit-sc-147-251-254": "external-ipv4-general-public", - # group project internal network - "group-project-network": "group-project-network" - } - if source_network in network_mapping.keys(): - return network_mapping[source_network] - return None - def get_destination_subnet(source_subnet): """ LUT for networks """ subnet_mapping = { @@ -451,82 +424,10 @@ def get_server_block_device_mapping(args, server_volume_attachment, server_volum -def create_destination_networking(args, src_ostack_conn, dst_ostack_conn, src_project, dst_project, src_network_name): - """ Create matching OpenStack networking (network, subnet, router) """ - # read source network details - src_network = src_ostack_conn.network.find_network(src_network_name, project_id=src_project.id) - # read matching subnets details - src_subnets = [ src_ostack_conn.network.find_subnet(i_src_subnet_id) for i_src_subnet_id in src_network.subnet_ids ] - # read linked routers - src_network_router_ports = [ i_src_router_port for i_src_router_port in src_ostack_conn.list_ports(filters={'network_id': src_network.id}) if i_src_router_port.device_owner == 'network:router_interface' ] - src_network_routers_subnets = [ (src_ostack_conn.network.find_router(router_port.device_id), [rp_fixed_ip['subnet_id'] for rp_fixed_ip in router_port.fixed_ips if 'subnet_id' in rp_fixed_ip]) for router_port in src_network_router_ports ] - - - # read external network - dst_ext_network = dst_ostack_conn.network.find_network(args.destination_ipv4_external_network) - - # create network - dst_network_name = get_dst_resource_name(args, src_network_name) - dst_network = dst_ostack_conn.network.find_network(dst_network_name, - project_id=dst_project.id) - if not dst_network: - dst_network = dst_ostack_conn.network.create_network(name=dst_network_name, - project_id=dst_project.id, - mtu=src_network.mtu, - description=get_dst_resource_desc(args, - src_network.description, - src_network.id), - port_security_enabled=src_network.is_port_security_enabled) - - # create subnets - dst_subnets = [] - subnet_mapping = {} - for i_src_subnet in src_subnets: - i_dst_subnet_name = get_dst_resource_name(args, i_src_subnet.name) - i_dst_subnet = dst_ostack_conn.network.find_subnet(i_dst_subnet_name, project_id=dst_project.id) - if not i_dst_subnet: - i_dst_subnet = dst_ostack_conn.network.create_subnet(network_id=dst_network.id, - name=i_dst_subnet_name, - cidr=i_src_subnet.cidr, - ip_version=i_src_subnet.ip_version, - enable_dhcp=i_src_subnet.is_dhcp_enabled, - project_id=dst_project.id, - allocation_pools=i_src_subnet.allocation_pools, - gateway_ip=i_src_subnet.gateway_ip, - host_routes=i_src_subnet.host_routes, - dns_nameservers=i_src_subnet.dns_nameservers, - description=get_dst_resource_desc(args, - i_src_subnet.description, - i_src_subnet.id)) - subnet_mapping[i_src_subnet.id] = i_dst_subnet.id - dst_subnets.append(i_dst_subnet) - - # create router(s) and associate with subnet(s) (if needed) - dst_network_routers = [] - for i_src_network_router, i_src_network_router_subnets in src_network_routers_subnets: - - i_dst_network_router_name = get_dst_resource_name(args, i_src_network_router.name) - i_dst_network_router = dst_ostack_conn.network.find_router(i_dst_network_router_name, - project_id=dst_project.id) - if not i_dst_network_router: - i_dst_network_router = dst_ostack_conn.network.create_router(name=i_dst_network_router_name, - description=get_dst_resource_desc(args, - i_src_network_router.description, - i_src_network_router.id), - project_id=dst_project.id, - external_gateway_info={"network_id": dst_ext_network.id}) - for i_src_network_router_subnet in i_src_network_router_subnets: - # TODO: Principally there may be also foreign subnets, find more general solution - if i_src_network_router_subnet in subnet_mapping: - dst_ostack_conn.add_router_interface(i_dst_network_router, subnet_id=subnet_mapping[i_src_network_router_subnet]) - - dst_network_routers.append(i_dst_network_router) - - return dst_network, dst_subnets, dst_network_routers - - def describe_server_network_connection(args, dst_ostack_conn, netaddr_dict): - """ """ + """ create ostack server to network connection via network id or fixed-ip + retults in single dictionary fed to conn.compute.create_server(...networks=[ <>, ...]) + """ # netaddr_dict{ 'dst-network': Network, # 'src-network-addresses': {'network-name': <source-network-name>, # 'addresses': [ ... ]} } diff --git a/ci/olib.py b/ci/olib.py new file mode 100644 index 0000000000000000000000000000000000000000..4504afbc3e91191761fbe37ca7e7773c81573a12 --- /dev/null +++ b/ci/olib.py @@ -0,0 +1,127 @@ +""" OpenStack migrator - OpenStack library """ + +from lib import log_or_assert, get_dst_resource_name, get_dst_resource_desc + +def get_destination_network(source_network): + """ LUT for networks """ + network_mapping = { + # shared + "78-128-250-pers-proj-net" : "internal-ipv4-general-private", + "147-251-115-pers-proj-net" : "internal-ipv4-general-private", + "public-muni-v6-432" : "external-ipv6-general-public", + # external + "public-muni-147-251-21-GROUP": "external-ipv4-general-public", + "public-cesnet-78-128-250-PERSONAL": "external-ipv4-general-public", + "public-cesnet-78-128-251-GROUP": "external-ipv4-general-public", + "provider-public-cerit-sc-147-251-253": "external-ipv4-general-public", + "public-muni-147-251-115-PERSONAL": "external-ipv4-general-public", + "public-muni-147-251-124-GROUP": "external-ipv4-general-public", + "public-cesnet-195-113-167-GROUP": "external-ipv4-general-public", + "public-muni-147-251-11-128-254": "external-ipv4-general-public", + "public-muni-CERIT-FI-147-251-88-132-254": "external-ipv4-general-public", + "public-muni-CSIRT-MU-217-69-96-64-240": "external-ipv4-general-public", + "public-muni-csirt-147-251-125-16-31": "external-ipv4-general-public", + "provider-public-cerit-sc-147-251-254": "external-ipv4-general-public", + # group project internal network + "group-project-network": "group-project-network" + } + if source_network in network_mapping: + return network_mapping[source_network] + return None + +def create_destination_networking(args, src_ostack_conn, dst_ostack_conn, src_project, dst_project, src_network_name): + """ Create matching OpenStack networking (network, subnet, router) """ + # read source network details + src_network = src_ostack_conn.network.find_network(src_network_name, project_id=src_project.id) + # read matching subnets details + src_subnets = [ src_ostack_conn.network.find_subnet(i_src_subnet_id) for i_src_subnet_id in src_network.subnet_ids ] + # read linked routers + src_network_router_ports = [ i_src_router_port for i_src_router_port in src_ostack_conn.list_ports(filters={'network_id': src_network.id}) if i_src_router_port.device_owner == 'network:router_interface' ] + src_network_routers_subnets = [ (src_ostack_conn.network.find_router(router_port.device_id), [rp_fixed_ip['subnet_id'] for rp_fixed_ip in router_port.fixed_ips if 'subnet_id' in rp_fixed_ip]) for router_port in src_network_router_ports ] + + + # read external network + dst_ext_network = dst_ostack_conn.network.find_network(args.destination_ipv4_external_network) + + # create network + dst_network_name = get_dst_resource_name(args, src_network_name) + dst_network = dst_ostack_conn.network.find_network(dst_network_name, + project_id=dst_project.id) + if not dst_network: + dst_network = dst_ostack_conn.network.create_network(name=dst_network_name, + project_id=dst_project.id, + mtu=src_network.mtu, + description=get_dst_resource_desc(args, + src_network.description, + src_network.id), + port_security_enabled=src_network.is_port_security_enabled) + + # create subnets + dst_subnets = [] + subnet_mapping = {} + for i_src_subnet in src_subnets: + i_dst_subnet_name = get_dst_resource_name(args, i_src_subnet.name) + i_dst_subnet = dst_ostack_conn.network.find_subnet(i_dst_subnet_name, project_id=dst_project.id) + if not i_dst_subnet: + i_dst_subnet = dst_ostack_conn.network.create_subnet(network_id=dst_network.id, + name=i_dst_subnet_name, + cidr=i_src_subnet.cidr, + ip_version=i_src_subnet.ip_version, + enable_dhcp=i_src_subnet.is_dhcp_enabled, + project_id=dst_project.id, + allocation_pools=i_src_subnet.allocation_pools, + gateway_ip=i_src_subnet.gateway_ip, + host_routes=i_src_subnet.host_routes, + dns_nameservers=i_src_subnet.dns_nameservers, + description=get_dst_resource_desc(args, + i_src_subnet.description, + i_src_subnet.id)) + subnet_mapping[i_src_subnet.id] = i_dst_subnet.id + dst_subnets.append(i_dst_subnet) + + # create router(s) and associate with subnet(s) (if needed) + dst_network_routers = [] + for i_src_network_router, i_src_network_router_subnets in src_network_routers_subnets: + + i_dst_network_router_name = get_dst_resource_name(args, i_src_network_router.name) + i_dst_network_router = dst_ostack_conn.network.find_router(i_dst_network_router_name, + project_id=dst_project.id) + if not i_dst_network_router: + i_dst_network_router = dst_ostack_conn.network.create_router(name=i_dst_network_router_name, + description=get_dst_resource_desc(args, + i_src_network_router.description, + i_src_network_router.id), + project_id=dst_project.id, + external_gateway_info={"network_id": dst_ext_network.id}) + for i_src_network_router_subnet in i_src_network_router_subnets: + # TODO: Principally there may be also foreign subnets, find more general solution + if i_src_network_router_subnet in subnet_mapping: + dst_ostack_conn.add_router_interface(i_dst_network_router, subnet_id=subnet_mapping[i_src_network_router_subnet]) + + dst_network_routers.append(i_dst_network_router) + + return dst_network, dst_subnets, dst_network_routers + +def get_or_create_dst_server_networking(args, + source_project_conn, destination_project_conn, + source_project, destination_project, + source_server_detail): + """ assure created server networking (get or create) """ + server_network_addresses = [] + for i_source_network_name, i_source_network_addresses in source_server_detail.addresses.items(): + i_destination_network_name = get_destination_network(i_source_network_name) + + if not i_destination_network_name: + # if network is not mapped we need to create matching one + i_dst_network, _, _ = create_destination_networking(args, + source_project_conn, destination_project_conn, + source_project, destination_project, + i_source_network_name) + i_destination_network = destination_project_conn.network.find_network(i_destination_network_name or i_dst_network.id, + project_id=destination_project.id) + log_or_assert(args, f"F.3 Destination network exists ({i_destination_network})", i_destination_network) + + server_network_addresses.append({'dst-network': i_destination_network, + 'src-network-addresses': {'network-name': i_source_network_name, + 'addresses': i_source_network_addresses}}) + return server_network_addresses diff --git a/ci/project-migrator.py b/ci/project-migrator.py index b90a1be95c1acebb968e458d76bd9a154d148a8d..a512196b0592546bdee86bec7589651f0699b34f 100755 --- a/ci/project-migrator.py +++ b/ci/project-migrator.py @@ -38,6 +38,7 @@ import sys import lib import clib +import olib def main(args): """ main project migration loop """ @@ -159,23 +160,12 @@ def main(args): f"addresses: {i_source_server_detail.addresses}") # network/subnet/router detection & creation - i_destination_server_network_addresses = [] - for i_source_network_name, i_source_network_addresses in i_source_server_detail.addresses.items(): - i_destination_network_name = lib.get_destination_network(i_source_network_name) - - if not i_destination_network_name: - # if network is not mapped we need to create matching one - i_dst_network, i_dst_subnets, i_dst_routers = lib.create_destination_networking(args, - source_project_conn, destination_project_conn, - source_project, destination_project, - i_source_network_name) - i_destination_network = destination_project_conn.network.find_network(i_destination_network_name or i_dst_network.id, - project_id=destination_project.id) - lib.log_or_assert(args, f"F.3 Destination network exists ({i_destination_network})", i_destination_network) - - i_destination_server_network_addresses.append({'dst-network': i_destination_network, - 'src-network-addresses': {'network-name': i_source_network_name, - 'addresses': i_source_network_addresses}}) + i_destination_server_network_addresses = \ + olib.get_or_create_dst_server_networking(args, + source_project_conn, destination_project_conn, + source_project, destination_project, + i_source_server_detail) + # flavor detection i_source_server_flavor_name = i_source_server_detail.flavor.name @@ -183,8 +173,9 @@ def main(args): lib.log_or_assert(args, f"F.5 Source to Destination flavor mapping succeeeded ({i_source_server_flavor_name}->{i_destination_server_flavor_name})", i_destination_server_flavor_name) - lib.log_or_assert(args, "F.6 Destination OpenStack flavor exists", - [ i_flavor for i_flavor in destination_project_flavors if i_flavor.name == i_destination_server_flavor_name ]) + lib.log_or_assert(args, + "F.6 Destination OpenStack flavor exists", + [ i_flavor for i_flavor in destination_project_flavors if i_flavor.name == i_destination_server_flavor_name ]) # keypair detection / creation i_source_server_keypair = lib.get_source_keypair(source_keypairs, i_source_server_detail.key_name, i_source_server_detail.user_id) @@ -316,7 +307,9 @@ def main(args): i_destination_server_block_device_mapping['destination']['volume_id'] = i_new_volume.id for i_destination_server_block_device_mapping in i_server_block_device_mappings: - lib.log_or_assert(args, "F.31 Destination OpenStack volume IDs properly stored", i_destination_server_block_device_mapping['destination']['volume_id']) + lib.log_or_assert(args, + f"F.31 Destination OpenStack volume IDs properly stored (id:{i_destination_server_block_device_mapping['destination']['volume_id']})", + i_destination_server_block_device_mapping['destination']['volume_id']) # VM stop, wait for SHUTOFF if i_source_server_detail.status != 'SHUTOFF': @@ -385,6 +378,7 @@ def main(args): args.logger.info(f"F.41 Source OpenStack server name:{i_source_server_detail.name} migrated into destination one name:{i_destination_server.name} id:{i_destination_server.id}") + # EXPLICIT OpenStack volume migration if args.explicit_volume_names: for i_source_volume_name in args.explicit_volume_names: i_source_volume = source_project_conn.block_storage.find_volume(i_source_volume_name)