Support for IPv6 tests for API

Added IPv6 everywhere where it's relevant in network API tests.
Partially implements: blueprint ipv6-api-testing-parity

Change-Id: If2baaa3f2433b88ea4a3ed6dbee61ad6ee9ad3b0
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index 7ba68f7..f2a00bb 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -65,6 +65,8 @@
         if getattr(cls, '_interface', None) == 'xml':
             if not CONF.network_feature_enabled.xml_api:
                 raise cls.skipException('XML API is not enabled')
+        if cls._ip_version == 6 and not CONF.network_feature_enabled.ipv6:
+            raise cls.skipException("IPv6 Tests are disabled.")
 
         os = cls.get_client_manager()
 
@@ -271,9 +273,11 @@
         return vip
 
     @classmethod
-    def create_member(cls, protocol_port, pool):
+    def create_member(cls, protocol_port, pool, ip_version=None):
         """Wrapper utility that returns a test member."""
-        resp, body = cls.client.create_member(address="10.0.9.46",
+        ip_version = ip_version if ip_version is not None else cls._ip_version
+        member_address = "fd00::abcd" if ip_version == 6 else "10.0.9.46"
+        resp, body = cls.client.create_member(address=member_address,
                                               protocol_port=protocol_port,
                                               pool_id=pool['id'])
         member = body['member']
diff --git a/tempest/api/network/test_allowed_address_pair.py b/tempest/api/network/test_allowed_address_pair.py
index c085c39..19bfd83 100644
--- a/tempest/api/network/test_allowed_address_pair.py
+++ b/tempest/api/network/test_allowed_address_pair.py
@@ -94,5 +94,9 @@
         self.assertEqual(mac_address, self.mac_address)
 
 
+class AllowedAddressPairIpV6TestJSON(AllowedAddressPairTestJSON):
+    _ip_version = 6
+
+
 class AllowedAddressPairTestXML(AllowedAddressPairTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/network/test_extra_dhcp_options.py b/tempest/api/network/test_extra_dhcp_options.py
index 86da9b7..6d083b3 100644
--- a/tempest/api/network/test_extra_dhcp_options.py
+++ b/tempest/api/network/test_extra_dhcp_options.py
@@ -44,17 +44,22 @@
         cls.network = cls.create_network()
         cls.subnet = cls.create_subnet(cls.network)
         cls.port = cls.create_port(cls.network)
+        cls.ip_tftp = ('123.123.123.123' if cls._ip_version == 4
+                       else '2015::dead')
+        cls.ip_server = ('123.123.123.45' if cls._ip_version == 4
+                         else '2015::badd')
+        cls.extra_dhcp_opts = [
+            {'opt_value': 'pxelinux.0', 'opt_name': 'bootfile-name'},
+            {'opt_value': cls.ip_tftp, 'opt_name': 'tftp-server'},
+            {'opt_value': cls.ip_server, 'opt_name': 'server-ip-address'}
+        ]
 
     @test.attr(type='smoke')
     def test_create_list_port_with_extra_dhcp_options(self):
         # Create a port with Extra DHCP Options
-        extra_dhcp_opts = [
-            {'opt_value': 'pxelinux.0', 'opt_name': 'bootfile-name'},
-            {'opt_value': '123.123.123.123', 'opt_name': 'tftp-server'},
-            {'opt_value': '123.123.123.45', 'opt_name': 'server-ip-address'}
-        ]
-        _, body = self.client.create_port(network_id=self.network['id'],
-                                          extra_dhcp_opts=extra_dhcp_opts)
+        _, body = self.client.create_port(
+            network_id=self.network['id'],
+            extra_dhcp_opts=self.extra_dhcp_opts)
         port_id = body['port']['id']
         self.addCleanup(self.client.delete_port, port_id)
 
@@ -63,23 +68,19 @@
         ports = body['ports']
         port = [p for p in ports if p['id'] == port_id]
         self.assertTrue(port)
-        self._confirm_extra_dhcp_options(port[0], extra_dhcp_opts)
+        self._confirm_extra_dhcp_options(port[0], self.extra_dhcp_opts)
 
     @test.attr(type='smoke')
     def test_update_show_port_with_extra_dhcp_options(self):
         # Update port with extra dhcp options
-        extra_dhcp_opts = [
-            {'opt_value': 'pxelinux.0', 'opt_name': 'bootfile-name'},
-            {'opt_value': '123.123.123.123', 'opt_name': 'tftp-server'},
-            {'opt_value': '123.123.123.45', 'opt_name': 'server-ip-address'}
-        ]
         name = data_utils.rand_name('new-port-name')
-        _, body = self.client.update_port(self.port['id'], name=name,
-                                          extra_dhcp_opts=extra_dhcp_opts)
-
+        _, body = self.client.update_port(
+            self.port['id'],
+            name=name,
+            extra_dhcp_opts=self.extra_dhcp_opts)
         # Confirm extra dhcp options were added to the port
         _, body = self.client.show_port(self.port['id'])
-        self._confirm_extra_dhcp_options(body['port'], extra_dhcp_opts)
+        self._confirm_extra_dhcp_options(body['port'], self.extra_dhcp_opts)
 
     def _confirm_extra_dhcp_options(self, port, extra_dhcp_opts):
         retrieved = port['extra_dhcp_opts']
@@ -92,3 +93,7 @@
             else:
                 self.fail('Extra DHCP option not found in port %s' %
                           str(retrieved_option))
+
+
+class ExtraDHCPOptionsIpV6TestJSON(ExtraDHCPOptionsTestJSON):
+    _ip_version = 6
diff --git a/tempest/api/network/test_load_balancer.py b/tempest/api/network/test_load_balancer.py
index baa8cad..8b8e3b1 100644
--- a/tempest/api/network/test_load_balancer.py
+++ b/tempest/api/network/test_load_balancer.py
@@ -55,7 +55,9 @@
                                  protocol_port=80,
                                  subnet=cls.subnet,
                                  pool=cls.pool)
-        cls.member = cls.create_member(80, cls.pool)
+        cls.member = cls.create_member(80, cls.pool, cls._ip_version)
+        cls.member_address = ("10.0.9.47" if cls._ip_version == 4
+                              else "2015::beef")
         cls.health_monitor = cls.create_health_monitor(delay=4,
                                                        max_retries=3,
                                                        Type="TCP",
@@ -213,13 +215,14 @@
     def test_list_members_with_filters(self):
         attr_exceptions = ['status', 'status_description']
         self._check_list_with_filter('member', attr_exceptions,
-                                     address="10.0.9.47", protocol_port=80,
+                                     address=self.member_address,
+                                     protocol_port=80,
                                      pool_id=self.pool['id'])
 
     @test.attr(type='smoke')
     def test_create_update_delete_member(self):
         # Creates a member
-        _, body = self.client.create_member(address="10.0.9.47",
+        _, body = self.client.create_member(address=self.member_address,
                                             protocol_port=80,
                                             pool_id=self.pool['id'])
         member = body['member']
@@ -419,5 +422,9 @@
         self.assertEqual(2, member['weight'])
 
 
+class LoadBalancerIpV6TestJSON(LoadBalancerTestJSON):
+    _ip_version = 6
+
+
 class LoadBalancerTestXML(LoadBalancerTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/network/test_metering_extensions.py b/tempest/api/network/test_metering_extensions.py
index 2cfb841..07ebd8c 100644
--- a/tempest/api/network/test_metering_extensions.py
+++ b/tempest/api/network/test_metering_extensions.py
@@ -43,7 +43,8 @@
         description = "metering label created by tempest"
         name = data_utils.rand_name("metering-label")
         cls.metering_label = cls.create_metering_label(name, description)
-        remote_ip_prefix = "10.0.0.0/24"
+        remote_ip_prefix = ("10.0.0.0/24" if cls._ip_version == 4
+                            else "fd02::/64")
         direction = "ingress"
         cls.metering_label_rule = cls.create_metering_label_rule(
             remote_ip_prefix, direction,
@@ -112,8 +113,10 @@
     @test.attr(type='smoke')
     def test_create_delete_metering_label_rule_with_filters(self):
         # Creates a rule
+        remote_ip_prefix = ("10.0.1.0/24" if self._ip_version == 4
+                            else "fd03::/64")
         _, body = (self.admin_client.create_metering_label_rule(
-                   remote_ip_prefix="10.0.1.0/24",
+                   remote_ip_prefix=remote_ip_prefix,
                    direction="ingress",
                    metering_label_id=self.metering_label['id']))
         metering_label_rule = body['metering_label_rule']
@@ -142,5 +145,9 @@
         self.assertFalse(metering_label_rule['excluded'])
 
 
+class MeteringIpV6JSON(MeteringJSON):
+    _ip_version = 6
+
+
 class MeteringXML(MeteringJSON):
     interface = 'xml'
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index dd81a09..1b0fd7c 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -478,13 +478,6 @@
 class NetworksIpV6TestJSON(NetworksTestJSON):
     _ip_version = 6
 
-    @classmethod
-    def resource_setup(cls):
-        if not CONF.network_feature_enabled.ipv6:
-            skip_msg = "IPv6 Tests are disabled."
-            raise cls.skipException(skip_msg)
-        super(NetworksIpV6TestJSON, cls).resource_setup()
-
     @test.attr(type='smoke')
     def test_create_delete_subnet_with_gw(self):
         net = netaddr.IPNetwork(CONF.network.tenant_network_v6_cidr)
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index d6db64d..7c5bdfe 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -276,13 +276,6 @@
     _tenant_network_cidr = CONF.network.tenant_network_v6_cidr
     _tenant_network_mask_bits = CONF.network.tenant_network_v6_mask_bits
 
-    @classmethod
-    def resource_setup(cls):
-        super(PortsIpV6TestJSON, cls).resource_setup()
-        if not CONF.network_feature_enabled.ipv6:
-            skip_msg = "IPv6 Tests are disabled."
-            raise cls.skipException(skip_msg)
-
 
 class PortsIpV6TestXML(PortsIpV6TestJSON):
     _interface = 'xml'
@@ -293,13 +286,6 @@
     _tenant_network_cidr = CONF.network.tenant_network_v6_cidr
     _tenant_network_mask_bits = CONF.network.tenant_network_v6_mask_bits
 
-    @classmethod
-    def resource_setup(cls):
-        if not CONF.network_feature_enabled.ipv6:
-            skip_msg = "IPv6 Tests are disabled."
-            raise cls.skipException(skip_msg)
-        super(PortsAdminExtendedAttrsIpV6TestJSON, cls).resource_setup()
-
 
 class PortsAdminExtendedAttrsIpV6TestXML(PortsAdminExtendedAttrsIpV6TestJSON):
     _interface = 'xml'
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index f3f25ac..2b4e60a 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -35,6 +35,9 @@
             raise cls.skipException(msg)
         admin_manager = clients.AdminManager()
         cls.identity_admin_client = admin_manager.identity_client
+        cls.tenant_cidr = (CONF.network.tenant_network_cidr
+                           if cls._ip_version == 4 else
+                           CONF.network.tenant_network_v6_cidr)
 
     def _cleanup_router(self, router):
         self.delete_router(router)
@@ -319,7 +322,7 @@
         network02 = self.create_network(
             network_name=data_utils.rand_name('router-network02-'))
         subnet01 = self.create_subnet(network01)
-        sub02_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr).next()
+        sub02_cidr = netaddr.IPNetwork(self.tenant_cidr).next()
         subnet02 = self.create_subnet(network02, cidr=sub02_cidr)
         router = self._create_router(data_utils.rand_name('router-'))
         interface01 = self._add_router_interface_with_subnet_id(router['id'],
@@ -337,3 +340,7 @@
         self.assertEqual(router_id, interface_port['device_id'])
         self.assertEqual(subnet_id,
                          interface_port['fixed_ips'][0]['subnet_id'])
+
+
+class RoutersIpV6Test(RoutersTest):
+    _ip_version = 6
diff --git a/tempest/api/network/test_routers_negative.py b/tempest/api/network/test_routers_negative.py
index 4c226af..88aa3c9 100644
--- a/tempest/api/network/test_routers_negative.py
+++ b/tempest/api/network/test_routers_negative.py
@@ -36,6 +36,9 @@
         cls.router = cls.create_router(data_utils.rand_name('router-'))
         cls.network = cls.create_network()
         cls.subnet = cls.create_subnet(cls.network)
+        cls.tenant_cidr = (CONF.network.tenant_network_cidr
+                           if cls._ip_version == 4 else
+                           CONF.network.tenant_network_v6_cidr)
 
     @test.attr(type=['negative', 'smoke'])
     def test_router_add_gateway_invalid_network_returns_404(self):
@@ -49,7 +52,7 @@
     def test_router_add_gateway_net_not_external_returns_400(self):
         alt_network = self.create_network(
             network_name=data_utils.rand_name('router-negative-'))
-        sub_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr).next()
+        sub_cidr = netaddr.IPNetwork(self.tenant_cidr).next()
         self.create_subnet(alt_network, cidr=sub_cidr)
         self.assertRaises(exceptions.BadRequest,
                           self.client.update_router,
@@ -79,3 +82,7 @@
         self.assertRaises(exceptions.Conflict,
                           self.client.delete_router,
                           self.router['id'])
+
+
+class RoutersNegativeIpV6Test(RoutersNegativeTest):
+    _ip_version = 6
diff --git a/tempest/api/network/test_security_groups.py b/tempest/api/network/test_security_groups.py
index e20b58e..47f2b52 100644
--- a/tempest/api/network/test_security_groups.py
+++ b/tempest/api/network/test_security_groups.py
@@ -221,13 +221,6 @@
     _ip_version = 6
     _tenant_network_cidr = CONF.network.tenant_network_v6_cidr
 
-    @classmethod
-    def resource_setup(cls):
-        if not CONF.network_feature_enabled.ipv6:
-            skip_msg = "IPv6 Tests are disabled."
-            raise cls.skipException(skip_msg)
-        super(SecGroupIPv6Test, cls).resource_setup()
-
 
 class SecGroupIPv6TestXML(SecGroupIPv6Test):
     _interface = 'xml'
diff --git a/tempest/api/network/test_security_groups_negative.py b/tempest/api/network/test_security_groups_negative.py
index 97e4cb7..42f7f71 100644
--- a/tempest/api/network/test_security_groups_negative.py
+++ b/tempest/api/network/test_security_groups_negative.py
@@ -197,13 +197,6 @@
     _ip_version = 6
     _tenant_network_cidr = CONF.network.tenant_network_v6_cidr
 
-    @classmethod
-    def resource_setup(cls):
-        if not CONF.network_feature_enabled.ipv6:
-            skip_msg = "IPv6 Tests are disabled."
-            raise cls.skipException(skip_msg)
-        super(NegativeSecGroupIPv6Test, cls).resource_setup()
-
 
 class NegativeSecGroupIPv6TestXML(NegativeSecGroupIPv6Test):
     _interface = 'xml'