diff --git a/CHANGELOG.md b/CHANGELOG.md
index cecf17cfcdfed7d82f26bc2efb8e166e493f1821..2d76bd4217ecef4423f62ef68e5a9275c5c19006 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Unreleased]
 
+## [1.1.2] - 2024-05-30
+### Fixed
+- attach FIP to correct virtual NIC
+### Added
+- dry-run mode
+- command-line debugging with IPython console
+
 ## [1.1.1] - 2024-05-30
 ### Fixed
 - assure correct VM NIC order
diff --git a/ci/lib.py b/ci/lib.py
index c6efd533ff68415b54acd9b03c3c465641ea9830..473d38f0be827682f3c91177a26212fa4096193d 100644
--- a/ci/lib.py
+++ b/ci/lib.py
@@ -245,20 +245,3 @@ def wait_for_ostack_volume_status(ostack_connection, volume_name_or_id, volume_s
 
 
     return int_volume_status
-
-def server_detect_floating_address(server):
-    """ return True if server has attached floating IP address otherwise False """
-    for _, i_ip_details in server.addresses.items():
-        for i_ip_detail in i_ip_details:
-            if str(i_ip_detail.get('version')) == '4' and i_ip_detail.get('OS-EXT-IPS:type') == 'floating':
-                return True
-    return False
-
-def get_server_floating_ip_port(ostack_connection, server):
-    """ set server's port where to put FIP, otherwise None """
-    for i_port in ostack_connection.network.ports(device_id=server.id):
-        for i_port_ip in i_port.fixed_ips:
-            for i_ip_prefix in ('192.', '10.', '172.'):
-                if str(i_port_ip.get('ip_address')).startswith(i_ip_prefix):
-                    return i_port
-    return None
diff --git a/ci/olib.py b/ci/olib.py
index bda0126070c4d0f82643b4549282021d79e1bbb2..2271136812b1af6a4d1fea542450bfa2c5857e09 100644
--- a/ci/olib.py
+++ b/ci/olib.py
@@ -674,3 +674,41 @@ def find_ostack_port(ostack_connection, mac_address, ip_address, description_sub
     return [i_port for i_port in project_ports if i_port.mac_address==mac_address and \
                                                   description_substr in i_port.description and \
                                                   ip_address in [i_addr.get('ip_address') for i_addr in i_port.fixed_ips]]
+
+def server_detect_floating_address(server):
+    """ return True if server has attached floating IP address otherwise False """
+    for _, i_ip_details in server.addresses.items():
+        for i_ip_detail in i_ip_details:
+            if str(i_ip_detail.get('version')) == '4' and i_ip_detail.get('OS-EXT-IPS:type') == 'floating':
+                return True
+    return False
+
+def get_server_floating_ip_port(ostack_connection, server):
+    """ set server's port where to put FIP, otherwise None """
+    for i_port in ostack_connection.network.ports(device_id=server.id):
+        for i_port_ip in i_port.fixed_ips:
+            for i_ip_prefix in ('192.', '10.', '172.'):
+                if str(i_port_ip.get('ip_address')).startswith(i_ip_prefix):
+                    return i_port
+    return None
+
+def get_server_floating_ip_properties(server):
+    """ return VM FIP properties (IP type, internal IP addr, FIP addr, MAC addr) """
+    int_address_data = {}
+    for i_net_name, i_net_addresses in server.addresses.items():
+        int_address_data.clear()
+        for i_addr_field in i_net_addresses:
+            int_ip_type = i_addr_field.get('OS-EXT-IPS:type', 'unknown')
+            for i_field_name in ('addr', 'version', 'OS-EXT-IPS-MAC:mac_addr',):
+                int_address_data[f"{int_ip_type}/{i_field_name}"] = i_addr_field.get(i_field_name, '?')
+        if "fixed/version" in int_address_data and \
+           "floating/version" in int_address_data and \
+           "fixed/OS-EXT-IPS-MAC:mac_addr" in int_address_data and \
+           "floating/OS-EXT-IPS-MAC:mac_addr" in int_address_data and \
+           int_address_data["fixed/version"] == int_address_data["floating/version"] and \
+           int_address_data["fixed/OS-EXT-IPS-MAC:mac_addr"] == int_address_data["floating/OS-EXT-IPS-MAC:mac_addr"]:
+            int_address_data["fixed/network-name"] = i_net_name
+            return int_address_data
+    return {}
+
+
diff --git a/ci/project-migrator.py b/ci/project-migrator.py
index 77446d3219ffb786e88e9d43e4bc0bfd4e306b55..52caacd4bbd1b5d072e6dd162bf11c7854e1c733 100755
--- a/ci/project-migrator.py
+++ b/ci/project-migrator.py
@@ -128,6 +128,13 @@ def main(args):
     destination_fip_network = destination_project_conn.network.find_network(args.destination_ipv4_external_network)
     lib.log_or_assert(args, "E.31 Destination cloud FIP network detected", destination_fip_network)
 
+    if args.dry_run:
+        args.logger.info("Exiting before first cloud modification operation as in dry-run mode.")
+        if args.debugging:
+            import IPython # on-purpose lazy import
+            IPython.embed()
+        return
+
     olib.duplicate_ostack_project_security_groups(args,
                                                   source_project_conn, destination_project_conn,
                                                   source_project, destination_project)
@@ -137,7 +144,7 @@ def main(args):
     args.logger.info(f"F.00 Source VM servers: {[ i_source_server.name for i_source_server in source_project_servers]}")
     for i_source_server in source_project_servers:
         i_source_server_detail = source_project_conn.compute.find_server(i_source_server.id)
-        i_source_server_has_fip = lib.server_detect_floating_address(i_source_server_detail)
+        i_source_server_fip_properties = olib.get_server_floating_ip_properties(i_source_server_detail)
 
         if args.explicit_server_names and i_source_server.name not in args.explicit_server_names:
             args.logger.info(f"F.01 server migration skipped - name:{i_source_server_detail.name} due to --explicit-server-names={args.explicit_server_names}")
@@ -229,14 +236,21 @@ def main(args):
         for i_destination_server_security_group_id, i_destination_server_security_group_name in {(i_destination_server_security_group.id, i_destination_server_security_group.name) for i_destination_server_security_group in i_destination_server_security_groups}:
             if {'name': i_destination_server_security_group_name } not in i_destination_server.security_groups:
                 destination_project_conn.add_server_security_groups(i_destination_server.id, i_destination_server_security_group_id)
-        if args.migrate_fip_addresses and i_source_server_has_fip:
+        if args.migrate_fip_addresses and i_source_server_fip_properties:
             # add FIP as source VM has it
             i_destination_server_fip = destination_project_conn.network.create_ip(floating_network_id=destination_fip_network.id)
-            lib.log_or_assert(args, f"F.39 Destination OpenStack server (name:{i_destination_server.name}) FIP is created ({i_destination_server_fip.floating_ip_address})",
+            lib.log_or_assert(args,
+                              f"F.39 Destination OpenStack server (name:{i_destination_server.name}) FIP is created ({i_destination_server_fip.floating_ip_address})",
                               i_destination_server_fip, locals())
-            i_destination_server_port = lib.get_server_floating_ip_port(destination_project_conn, i_destination_server)
-            lib.log_or_assert(args, f"F.40 Destination OpenStack server (name:{i_destination_server.name}) FIP port is detected",
-                              i_destination_server_port, locals())
+            i_destination_server_ports = olib.find_ostack_port(destination_project_conn,
+                                                               i_source_server_fip_properties['floating/OS-EXT-IPS-MAC:mac_addr'],
+                                                               i_source_server_fip_properties['fixed/addr'],
+                                                               project=destination_project)
+            lib.log_or_assert(args, f"F.40 Destination OpenStack server (name:{i_destination_server.name}) FIP port(s) are detected",
+                              i_destination_server_ports, locals())
+            lib.log_or_assert(args, f"F.40 Destination OpenStack server (name:{i_destination_server.name}) single FIP port is detected",
+                              len(i_destination_server_ports) == 1, locals())
+            i_destination_server_port = i_destination_server_ports[0]
             destination_project_conn.network.add_ip_to_port(i_destination_server_port, i_destination_server_fip)
 
         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}")
@@ -349,18 +363,23 @@ if __name__ == "__main__":
     AP.add_argument('--log-level', default="INFO", required=False,
                     choices=[i_lvl for i_lvl in dir(logging) if i_lvl.isupper() and i_lvl.isalpha()],
                     help='Executio log level (python logging)')
-    AP.add_argument('--debugging', default=False, required=False, action='store_true',
-                    help='(Optional) Enter custom development debugging mode.')
+    AP.add_argument('--dry-run', default=False, required=False,
+                    choices=["True", "true", "False", "false"],
+                    help='Migration dry-run mode. Stop before first modification action.')
+    AP.add_argument('--debugging', default=False, required=False,
+                    choices=["True", "true", "False", "false"],
+                    help='(Optional) Enter development debugging mode.')
 
     ARGS = AP.parse_args()
     ARGS.logger = logging.getLogger("project-migrator")
     ARGS.explicit_server_names = lib.get_resource_names_ids(ARGS.explicit_server_names)
     ARGS.explicit_volume_names = lib.get_resource_names_ids(ARGS.explicit_volume_names)
     ARGS.migrate_fip_addresses = str(ARGS.migrate_fip_addresses).lower() == "true"
+    ARGS.dry_run = str(ARGS.dry_run).lower() == "true"
+    ARGS.debugging = str(ARGS.debugging).lower() == "true"
+    ARGS.migrate_reuse_already_migrated_volumes = str(ARGS.migrate_reuse_already_migrated_volumes).lower() == "true"
+
     logging.basicConfig(level=getattr(logging, ARGS.log_level),
                         format='%(asctime)s %(name)s %(levelname)s %(message)s')
-    if ARGS.debugging:
-        import IPython
-        #IPython.embed()
 
     sys.exit(main(ARGS))