Merge "Fix testing IPv6 VIP network connectivity"
diff --git a/devstack/plugin.sh b/devstack/plugin.sh
index 5eac133..fb4e932 100644
--- a/devstack/plugin.sh
+++ b/devstack/plugin.sh
@@ -24,6 +24,15 @@
         ${DEST}/octavia-tempest-plugin/octavia_tempest_plugin/contrib/test_server/test_server.go
 }
 
+function _configure_tempest {
+    if [ -n "$Q_ROUTER_NAME" ]; then
+        iniset $TEMPEST_CONFIG load_balancer default_router "$Q_ROUTER_NAME"
+    fi
+    if [ -n "$SUBNETPOOL_NAME_V6" ]; then
+        iniset $TEMPEST_CONFIG load_balancer default_ipv6_subnetpool "$SUBNETPOOL_NAME_V6"
+    fi
+}
+
 if [[ "$1" == "stack" ]]; then
     case "$2" in
         install)
@@ -40,6 +49,7 @@
         test-config)
             echo_summary "Building backend test server"
             build_backend_test_server
+            _configure_tempest
             ;;
     esac
 fi
diff --git a/octavia_tempest_plugin/config.py b/octavia_tempest_plugin/config.py
index f44bf96..7af7a1f 100644
--- a/octavia_tempest_plugin/config.py
+++ b/octavia_tempest_plugin/config.py
@@ -179,6 +179,13 @@
     cfg.StrOpt('member_2_ipv6_subnet_cidr',
                default='fd77:1457:4cf0:26a8::/64',
                help='CIDR format subnet to use for the member 1 ipv6 subnet.'),
+    cfg.StrOpt('default_router',
+               default='router1',
+               help='The default router connected to the public network.'),
+    cfg.StrOpt('default_ipv6_subnetpool',
+               default='shared-default-subnetpool-v6',
+               help='The default IPv6 subnetpool to use when creating the '
+                    'IPv6 VIP subnet.'),
     # Amphora specific options
     cfg.StrOpt('amphora_ssh_user',
                default='ubuntu',
diff --git a/octavia_tempest_plugin/tests/test_base.py b/octavia_tempest_plugin/tests/test_base.py
index 887c644..d14ab58 100644
--- a/octavia_tempest_plugin/tests/test_base.py
+++ b/octavia_tempest_plugin/tests/test_base.py
@@ -131,6 +131,8 @@
         cls.mem_flavor_client = cls.os_roles_lb_member.flavor_client
         cls.mem_provider_client = cls.os_roles_lb_member.provider_client
         cls.os_admin_servers_client = cls.os_admin.servers_client
+        cls.os_admin_routers_client = cls.os_admin.routers_client
+        cls.os_admin_subnetpools_client = cls.os_admin.subnetpools_client
         cls.lb_admin_flavor_capabilities_client = (
             cls.os_roles_lb_admin.flavor_capabilities_client)
         cls.lb_admin_availability_zone_capabilities_client = (
@@ -327,33 +329,38 @@
 
         # Create tenant VIP IPv6 subnet
         if CONF.load_balancer.test_with_ipv6:
-            # See if ipv6-private-subnet exists and use it if so.
-            priv_ipv6_subnet = cls.os_admin.subnets_client.list_subnets(
-                name='ipv6-private-subnet')['subnets']
-
             cls.lb_member_vip_ipv6_subnet_stateful = False
-            if len(priv_ipv6_subnet) == 1:
-                if (priv_ipv6_subnet[0]['ipv6_address_mode'] ==
-                        'dhcpv6-stateful'):
-                    cls.lb_member_vip_ipv6_subnet_stateful = True
-                cls.lb_member_vip_ipv6_subnet = priv_ipv6_subnet[0]
-                cls.lb_member_vip_ipv6_net = {
-                    'id': priv_ipv6_subnet[0]['network_id']}
-            else:
-                subnet_kwargs = {
-                    'name': data_utils.rand_name("lb_member_vip_ipv6_subnet"),
-                    'network_id': cls.lb_member_vip_net['id'],
-                    'cidr': CONF.load_balancer.vip_ipv6_subnet_cidr,
-                    'ip_version': 6}
-                result = cls.lb_mem_subnet_client.create_subnet(
-                    **subnet_kwargs)
-                cls.lb_member_vip_ipv6_net = cls.lb_member_vip_net
-                cls.lb_member_vip_ipv6_subnet = result['subnet']
-                cls.addClassResourceCleanup(
-                    waiters.wait_for_not_found,
-                    cls._logging_delete_subnet,
-                    cls.lb_mem_subnet_client.show_subnet,
-                    cls.lb_member_vip_ipv6_subnet['id'])
+            cls.lb_member_vip_ipv6_subnet_use_subnetpool = False
+            subnet_kwargs = {
+                'name': data_utils.rand_name("lb_member_vip_ipv6_subnet"),
+                'network_id': cls.lb_member_vip_net['id'],
+                'ip_version': 6}
+
+            # Use a CIDR from devstack's default IPv6 subnetpool if it exists,
+            # the subnetpool's cidr is routable from the devstack node
+            # through the default router
+            subnetpool_name = CONF.load_balancer.default_ipv6_subnetpool
+            if subnetpool_name:
+                subnetpool = cls.os_admin_subnetpools_client.list_subnetpools(
+                    name=subnetpool_name)['subnetpools']
+                if len(subnetpool) == 1:
+                    subnetpool = subnetpool[0]
+                    subnet_kwargs['subnetpool_id'] = subnetpool['id']
+                    cls.lb_member_vip_ipv6_subnet_use_subnetpool = True
+
+            if 'subnetpool_id' not in subnet_kwargs:
+                subnet_kwargs['cidr'] = (
+                    CONF.load_balancer.vip_ipv6_subnet_cidr)
+
+            result = cls.lb_mem_subnet_client.create_subnet(
+                **subnet_kwargs)
+            cls.lb_member_vip_ipv6_net = cls.lb_member_vip_net
+            cls.lb_member_vip_ipv6_subnet = result['subnet']
+            cls.addClassResourceCleanup(
+                waiters.wait_for_not_found,
+                cls._logging_delete_subnet,
+                cls.lb_mem_subnet_client.show_subnet,
+                cls.lb_member_vip_ipv6_subnet['id'])
 
             LOG.info('lb_member_vip_ipv6_subnet: {}'.format(
                 cls.lb_member_vip_ipv6_subnet))
@@ -743,6 +750,30 @@
             cls.lb_member_router['id'],
             subnet_id=cls.lb_member_vip_subnet['id'])
 
+        if (CONF.load_balancer.test_with_ipv6 and
+                CONF.load_balancer.default_router and
+                cls.lb_member_vip_ipv6_subnet_use_subnetpool):
+
+            router_name = CONF.load_balancer.default_router
+            # if lb_member_vip_ipv6_subnet uses devstack's subnetpool,
+            # plug the subnet into the default router
+            router = cls.os_admin.routers_client.list_routers(
+                name=router_name)['routers']
+
+            if len(router) == 1:
+                router = router[0]
+
+                # Add IPv6 VIP subnet to router1
+                cls.os_admin_routers_client.add_router_interface(
+                    router['id'],
+                    subnet_id=cls.lb_member_vip_ipv6_subnet['id'])
+                cls.addClassResourceCleanup(
+                    waiters.wait_for_not_found,
+                    cls.os_admin_routers_client.remove_router_interface,
+                    cls.os_admin_routers_client.remove_router_interface,
+                    router['id'],
+                    subnet_id=cls.lb_member_vip_ipv6_subnet['id'])
+
         # Add member subnet 1 to router
         cls.lb_mem_routers_client.add_router_interface(
             cls.lb_member_router['id'],