Wait for router interface removal before remove router

Related-Prod: PRODX-27590
Change-Id: I0d3df8beda5caf17dd08fecdce7807cc49d6c9d6
(cherry picked from commit d9acbb516b881421ad6217e5a65e3a09d64a8be5)
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index 99742cc..fa30b40 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -19,6 +19,7 @@
 from tempest import exceptions
 from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
+from tempest.lib.common import waiters as lib_waiters
 from tempest.lib import exceptions as lib_exc
 import tempest.test
 
@@ -224,6 +225,9 @@
             test_utils.call_and_ignore_notfound_exc(
                 cls.routers_client.remove_router_interface, router['id'],
                 subnet_id=i['fixed_ips'][0]['subnet_id'])
+            lib_waiters.wait_router_interface_removed(
+                cls.ports_client, router['id'],
+                subnet_id=i['fixed_ips'][0]['subnet_id'])
         cls.routers_client.delete_router(router['id'])
 
 
diff --git a/tempest/lib/common/dynamic_creds.py b/tempest/lib/common/dynamic_creds.py
index eb18aad..6f71536 100644
--- a/tempest/lib/common/dynamic_creds.py
+++ b/tempest/lib/common/dynamic_creds.py
@@ -20,7 +20,9 @@
 from tempest.lib.common import cred_client
 from tempest.lib.common import cred_provider
 from tempest.lib.common.utils import data_utils
+from tempest.lib.common import waiters as lib_waiters
 from tempest.lib import exceptions as lib_exc
+
 from tempest.lib.services import clients
 
 LOG = logging.getLogger(__name__)
@@ -574,6 +576,9 @@
                     client.remove_router_interface(
                         creds.router['id'],
                         subnet_id=creds.subnet['id'])
+                    lib_waiters.wait_router_interface_removed(
+                        self.ports_admin_client, creds.router['id'],
+                        subnet_id=creds.subnet['id'])
                 except lib_exc.NotFound:
                     LOG.warning('router with name: %s not found for delete',
                                 creds.router['name'])
diff --git a/tempest/lib/common/waiters.py b/tempest/lib/common/waiters.py
new file mode 100644
index 0000000..1f0bdc9
--- /dev/null
+++ b/tempest/lib/common/waiters.py
@@ -0,0 +1,32 @@
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import time
+
+from tempest.lib import exceptions as lib_exc
+
+
+def wait_router_interface_removed(
+    ports_client, router_id, subnet_id, timeout=30, interval=3):
+    """Waits for router inface is removed"""
+    start_time = int(time.time())
+    while int(time.time()) - start_time < timeout:
+        try:
+            ports = ports_client.list_ports(
+                device_id=router_id,
+                fixed_ips=f"subnet_id={subnet_id}")['ports']
+            if len(ports) == 0:
+                return
+            time.sleep(interval)
+        except Exception:
+            pass
+    raise lib_exc.TimeoutException()
diff --git a/tempest/tests/lib/common/test_dynamic_creds.py b/tempest/tests/lib/common/test_dynamic_creds.py
index d3d01c0..646ec9b 100644
--- a/tempest/tests/lib/common/test_dynamic_creds.py
+++ b/tempest/tests/lib/common/test_dynamic_creds.py
@@ -741,6 +741,7 @@
         router_interface_mock = self.patch(
             'tempest.lib.services.network.routers_client.RoutersClient.'
             'add_router_interface')
+        self.patch('tempest.lib.common.waiters.wait_router_interface_removed')
         creds.get_primary_creds()
         creds.get_project_admin_creds()
         router_interface_mock.assert_called_once_with('1234', subnet_id='1234')