Merge "Cleanup of loadbalancers with force set" into mcp/caracal
diff --git a/octavia_tempest_plugin/common/constants.py b/octavia_tempest_plugin/common/constants.py
index e3bd83e..a33a88c 100644
--- a/octavia_tempest_plugin/common/constants.py
+++ b/octavia_tempest_plugin/common/constants.py
@@ -245,6 +245,12 @@
 COMPUTE_ZONE = 'compute_zone'
 MANAGEMENT_NETWORK = 'management_network'
 
+# Retry constants
+RETRY_ATTEMPTS = 15
+RETRY_INITIAL_DELAY = 1
+RETRY_BACKOFF = 1
+RETRY_MAX = 5
+
 # API valid fields
 SHOW_LOAD_BALANCER_RESPONSE_FIELDS = (
     ADMIN_STATE_UP, CREATED_AT, DESCRIPTION, FLAVOR_ID, ID, LISTENERS, NAME,
diff --git a/octavia_tempest_plugin/services/load_balancer/v2/base_client.py b/octavia_tempest_plugin/services/load_balancer/v2/base_client.py
index de464c3..5e2298c 100644
--- a/octavia_tempest_plugin/services/load_balancer/v2/base_client.py
+++ b/octavia_tempest_plugin/services/load_balancer/v2/base_client.py
@@ -19,6 +19,7 @@
 from tempest.lib.common import rest_client
 from tempest.lib.common.utils import test_utils
 from tempest.lib import exceptions
+import tenacity
 
 from octavia_tempest_plugin.common import constants as const
 from octavia_tempest_plugin.tests import waiters
@@ -55,6 +56,11 @@
         if not hasattr(self, cleanup_func_name):
             setattr(self, cleanup_func_name, self._cleanup_obj)
 
+    @tenacity.retry(
+        retry=tenacity.retry_if_exception_type(exceptions.Conflict),
+        wait=tenacity.wait_incrementing(
+            const.RETRY_INITIAL_DELAY, const.RETRY_BACKOFF, const.RETRY_MAX),
+        stop=tenacity.stop_after_attempt(const.RETRY_ATTEMPTS))
     def _create_object(self, parent_id=None, return_object_only=True,
                        **kwargs):
         """Create an object.
@@ -211,6 +217,11 @@
         else:
             return jsonutils.loads(body.decode('utf-8'))
 
+    @tenacity.retry(
+        retry=tenacity.retry_if_exception_type(exceptions.Conflict),
+        wait=tenacity.wait_incrementing(
+            const.RETRY_INITIAL_DELAY, const.RETRY_BACKOFF, const.RETRY_MAX),
+        stop=tenacity.stop_after_attempt(const.RETRY_ATTEMPTS))
     def _update_object(self, obj_id, parent_id=None, return_object_only=True,
                        **kwargs):
         """Update an object.
@@ -264,6 +275,11 @@
         else:
             return jsonutils.loads(body.decode('utf-8'))
 
+    @tenacity.retry(
+        retry=tenacity.retry_if_exception_type(exceptions.Conflict),
+        wait=tenacity.wait_incrementing(
+            const.RETRY_INITIAL_DELAY, const.RETRY_BACKOFF, const.RETRY_MAX),
+        stop=tenacity.stop_after_attempt(const.RETRY_ATTEMPTS))
     def _delete_obj(self, obj_id, parent_id=None, ignore_errors=False,
                     cascade=False):
         """Delete an object.
diff --git a/octavia_tempest_plugin/tests/act_stdby_scenario/v2/test_active_standby.py b/octavia_tempest_plugin/tests/act_stdby_scenario/v2/test_active_standby.py
index 3bb8a32..eab5e3f 100644
--- a/octavia_tempest_plugin/tests/act_stdby_scenario/v2/test_active_standby.py
+++ b/octavia_tempest_plugin/tests/act_stdby_scenario/v2/test_active_standby.py
@@ -31,6 +31,8 @@
 LOG = logging.getLogger(__name__)
 
 
+@testtools.skipIf(CONF.load_balancer.provider == 'tungstenfabric',
+                  "Not supported by TungstenFabric")
 @testtools.skipUnless(
     CONF.validation.run_validation,
     'Active-Standby tests will not work without run_validation enabled.')
diff --git a/octavia_tempest_plugin/tests/api/v2/test_listener.py b/octavia_tempest_plugin/tests/api/v2/test_listener.py
index b60fb20..973e641 100644
--- a/octavia_tempest_plugin/tests/api/v2/test_listener.py
+++ b/octavia_tempest_plugin/tests/api/v2/test_listener.py
@@ -82,6 +82,8 @@
     def test_tcp_listener_create(self):
         self._test_listener_create(const.TCP, 8002)
 
+    @testtools.skipIf(CONF.load_balancer.provider == 'tungstenfabric',
+                      "Not supported by TungstenFabric")
     @decorators.idempotent_id('1a6ba0d0-f309-4088-a686-dda0e9ab7e43')
     @testtools.skipUnless(
         CONF.loadbalancer_feature_enabled.prometheus_listener_enabled,
@@ -449,6 +451,8 @@
     def test_https_listener_list(self):
         self._test_listener_list(const.HTTPS, 8030)
 
+    @testtools.skipIf(CONF.load_balancer.provider == 'tungstenfabric',
+                      "Not supported by TungstenFabric")
     @decorators.idempotent_id('5473e071-8277-4ac5-9277-01ecaf46e274')
     @testtools.skipUnless(
         CONF.loadbalancer_feature_enabled.prometheus_listener_enabled,
@@ -827,6 +831,8 @@
     def test_https_listener_show(self):
         self._test_listener_show(const.HTTPS, 8051)
 
+    @testtools.skipIf(CONF.load_balancer.provider == 'tungstenfabric',
+                      "Not supported by TungstenFabric")
     @decorators.idempotent_id('b851b754-4333-4115-9063-a9fce44c2e46')
     @testtools.skipUnless(
         CONF.loadbalancer_feature_enabled.prometheus_listener_enabled,
@@ -997,6 +1003,8 @@
     def test_https_listener_update(self):
         self._test_listener_update(const.HTTPS, 8061)
 
+    @testtools.skipIf(CONF.load_balancer.provider == 'tungstenfabric',
+                      "Not supported by TungstenFabric")
     @decorators.idempotent_id('cbba6bf8-9184-4da5-95e9-5efe1f89ddf0')
     @testtools.skipUnless(
         CONF.loadbalancer_feature_enabled.prometheus_listener_enabled,
@@ -1266,6 +1274,8 @@
     def test_https_listener_delete(self):
         self._test_listener_delete(const.HTTPS, 8071)
 
+    @testtools.skipIf(CONF.load_balancer.provider == 'tungstenfabric',
+                      "Not supported by TungstenFabric")
     @decorators.idempotent_id('322a6372-6b56-4a3c-87e3-dd82074bc83e')
     @testtools.skipUnless(
         CONF.loadbalancer_feature_enabled.prometheus_listener_enabled,
diff --git a/octavia_tempest_plugin/tests/barbican_scenario/v2/test_tls_barbican.py b/octavia_tempest_plugin/tests/barbican_scenario/v2/test_tls_barbican.py
index 511c724..af84445 100644
--- a/octavia_tempest_plugin/tests/barbican_scenario/v2/test_tls_barbican.py
+++ b/octavia_tempest_plugin/tests/barbican_scenario/v2/test_tls_barbican.py
@@ -22,6 +22,7 @@
 import httpx
 from OpenSSL.crypto import X509
 from OpenSSL import SSL
+import tenacity
 
 from oslo_log import log as logging
 from oslo_utils import uuidutils
@@ -301,6 +302,7 @@
             CONF.load_balancer.check_interval,
             CONF.load_balancer.check_timeout)
 
+    @decorators.attr(type='smoke')
     @decorators.idempotent_id('887ece26-0f7b-4933-89ab-5bb00b106ee0')
     def test_basic_tls_traffic(self):
 
@@ -874,6 +876,14 @@
                                 CONF.load_balancer.build_interval,
                                 CONF.load_balancer.build_timeout)
 
+        if not CONF.load_balancer.test_with_noop:
+            waiters.wait_for_status(
+                self.mem_listener_client.show_listener,
+                self.listener_id, const.OPERATING_STATUS,
+                const.ONLINE,
+                CONF.load_balancer.build_interval,
+                CONF.load_balancer.build_timeout)
+
         # Test that no client certificate connects
         response = requests.get(
             'https://{0}:{1}'.format(self.lb_vip_address, LISTENER1_TCP_PORT),
@@ -979,6 +989,14 @@
                                 CONF.load_balancer.build_interval,
                                 CONF.load_balancer.build_timeout)
 
+        if not CONF.load_balancer.test_with_noop:
+            waiters.wait_for_status(
+                self.mem_listener_client.show_listener,
+                self.listener_id, const.OPERATING_STATUS,
+                const.ONLINE,
+                CONF.load_balancer.build_interval,
+                CONF.load_balancer.build_timeout)
+
         LISTENER2_TCP_PORT = '8443'
         listener_name = data_utils.rand_name(
             "lb_member_listener2-multi-list-client-auth")
@@ -1005,7 +1023,13 @@
                                 const.ACTIVE,
                                 CONF.load_balancer.build_interval,
                                 CONF.load_balancer.build_timeout)
-
+        if not CONF.load_balancer.test_with_noop:
+            waiters.wait_for_status(
+                self.mem_listener_client.show_listener,
+                self.listener2_id, const.OPERATING_STATUS,
+                const.ONLINE,
+                CONF.load_balancer.build_interval,
+                CONF.load_balancer.build_timeout)
         # Test that no client certificate fails to connect to listener1
         self.assertRaises(
             requests.exceptions.SSLError,
@@ -1223,6 +1247,17 @@
         self.assertEqual(expected_proto, selected_proto)
 
     def _test_http_versions_tls_traffic(self, http_version, alpn_protos):
+        @tenacity.retry(
+            retry=tenacity.retry_if_exception_type(httpx.ConnectTimeout),
+            wait=tenacity.wait_incrementing(
+                const.RETRY_INITIAL_DELAY, const.RETRY_BACKOFF, const.RETRY_MAX
+            ),
+            stop=tenacity.stop_after_attempt(const.RETRY_ATTEMPTS),
+            reraise=True,
+        )
+        def _get(client, url):
+            return client.get(url)
+
         if not self.mem_listener_client.is_version_supported(
                 self.api_version, '2.20'):
             raise self.skipException('ALPN protocols are only available on '
@@ -1249,14 +1284,24 @@
                                 const.ACTIVE,
                                 CONF.load_balancer.build_interval,
                                 CONF.load_balancer.build_timeout)
-
+        # NOTE(pas-ha): depending on what other tempest plugins are installed
+        # the eventlet might've been imported by that time, and, since
+        # dnspython 2.2.0, importing eventlet or any part of it effectively
+        # instantiates a dummy httpx.Client instance, thus pinning the ssl
+        # implementation in httpx to the eventlet's one.
+        # This leads to error in the Client() call below, as the ssl lib in
+        # this module is different from ssl lib in httpx._config,
+        # which fails isinstance check for ssl.SSLContext.
+        # Use the ssl module that is actually used by httpx to instantiate
+        # the SSL context to be used with httpx.
+        ssl = httpx._config.ssl
         context = ssl.create_default_context(cadata=self.ca_cert.public_bytes(
             serialization.Encoding.PEM).decode('utf-8'))
         context.check_hostname = False
 
         url = 'https://%s:%s' % (self.lb_vip_address, 443)
         client = httpx.Client(http2=(http_version == 'HTTP/2'), verify=context)
-        r = client.get(url)
+        r = _get(client, url)
         self.assertEqual(http_version, r.http_version)
 
     @decorators.idempotent_id('9965828d-24af-4fa0-91ae-21c6bc47ab4c')
diff --git a/octavia_tempest_plugin/tests/scenario/v2/test_traffic_ops.py b/octavia_tempest_plugin/tests/scenario/v2/test_traffic_ops.py
index a704b88..3eefb65 100644
--- a/octavia_tempest_plugin/tests/scenario/v2/test_traffic_ops.py
+++ b/octavia_tempest_plugin/tests/scenario/v2/test_traffic_ops.py
@@ -1482,6 +1482,8 @@
             number_of_retries=3),
             'Failed - all UDP retries to LB VIP has failed')
 
+    @testtools.skipIf(CONF.load_balancer.provider == 'tungstenfabric',
+                      "Not supported by TungstenFabric")
     @decorators.attr(type='slow')
     @decorators.idempotent_id('cd5aeefa-0e16-11eb-b8dc-74e5f9e2a801')
     def test_hm_op_status_changed_as_expected_on_update(self):
@@ -1568,6 +1570,8 @@
                     CONF.load_balancer.check_timeout,
                     error_ok=True, pool_id=pool_id)
 
+    @testtools.skipIf(CONF.load_balancer.provider == 'tungstenfabric',
+                      "Not supported by TungstenFabric")
     @decorators.idempotent_id('05e99fb3-2b37-478e-889b-77f1c731a471')
     @testtools.skipUnless(
         CONF.loadbalancer_feature_enabled.prometheus_listener_enabled,
diff --git a/octavia_tempest_plugin/tests/test_base.py b/octavia_tempest_plugin/tests/test_base.py
index f08cec9..ed61ddb 100644
--- a/octavia_tempest_plugin/tests/test_base.py
+++ b/octavia_tempest_plugin/tests/test_base.py
@@ -41,11 +41,6 @@
 CONF = config.CONF
 LOG = logging.getLogger(__name__)
 
-RETRY_ATTEMPTS = 15
-RETRY_INITIAL_DELAY = 1
-RETRY_BACKOFF = 1
-RETRY_MAX = 5
-
 
 class LoadBalancerBaseTest(validators.ValidatorsMixin,
                            RBAC_tests.RBACTestsMixin, test.BaseTestCase):
@@ -276,9 +271,9 @@
             cls.lb_member_2_subnet = override_subnet
 
             if (CONF.load_balancer.test_with_ipv6 and
-                    conf_lb.test_IPv6_subnet_override):
+                    conf_lb.test_ipv6_subnet_override):
                 override_ipv6_subnet = show_subnet(
-                    conf_lb.test_IPv6_subnet_override)
+                    conf_lb.test_ipv6_subnet_override)
                 cls.lb_member_vip_ipv6_subnet = override_ipv6_subnet
                 cls.lb_member_1_ipv6_subnet = override_ipv6_subnet
                 cls.lb_member_2_ipv6_subnet = override_ipv6_subnet
@@ -326,8 +321,8 @@
     @tenacity.retry(
         retry=tenacity.retry_if_exception_type(exceptions.Conflict),
         wait=tenacity.wait_incrementing(
-            RETRY_INITIAL_DELAY, RETRY_BACKOFF, RETRY_MAX),
-        stop=tenacity.stop_after_attempt(RETRY_ATTEMPTS))
+            const.RETRY_INITIAL_DELAY, const.RETRY_BACKOFF, const.RETRY_MAX),
+        stop=tenacity.stop_after_attempt(const.RETRY_ATTEMPTS))
     def _logging_delete_network(cls, net_id):
         try:
             cls.lb_mem_net_client.delete_network(net_id)
@@ -344,8 +339,8 @@
     @tenacity.retry(
         retry=tenacity.retry_if_exception_type(exceptions.Conflict),
         wait=tenacity.wait_incrementing(
-            RETRY_INITIAL_DELAY, RETRY_BACKOFF, RETRY_MAX),
-        stop=tenacity.stop_after_attempt(RETRY_ATTEMPTS))
+            const.RETRY_INITIAL_DELAY, const.RETRY_BACKOFF, const.RETRY_MAX),
+        stop=tenacity.stop_after_attempt(const.RETRY_ATTEMPTS))
     def _logging_delete_subnet(cls, subnet_id):
         try:
             cls.lb_mem_subnet_client.delete_subnet(subnet_id)