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)