def test_link_multi_l2domain_to_network_mix_dualstack(self): if self.is_dhcp_agent_present(): raise self.skipException( 'Multiple VSD managed subnets linked to different l2domains ' 'in a network not supported when DHCP agent is enabled.') net_name = data_utils.rand_name('multi-vsd-mgd-dualstack') network = self.create_network(network_name=net_name) vsd_l2domain_template1 = self.vsd_create_l2domain_template( ip_type="DUALSTACK", cidr4=IPNetwork('10.0.0.0/24'), cidr6=IPNetwork('cafe:babe::/64'), dhcp_managed=True, enable_dhcpv6=True ) vsd_l2domain1 = self.vsd_create_l2domain( template=vsd_l2domain_template1) vsd_l2domain_template2 = self.vsd_create_l2domain_template( ip_type="DUALSTACK", cidr4=IPNetwork('10.1.0.0/24'), cidr6=IPNetwork('cbfe:babe::/64'), dhcp_managed=True, enable_dhcpv6=True ) vsd_l2domain2 = self.vsd_create_l2domain( template=vsd_l2domain_template2) v4_subnet = self.create_subnet( network, cidr=IPNetwork('10.0.0.0/24'), mask_bits=24, gateway=None, nuagenet=vsd_l2domain1.id, net_partition=Topology.def_netpartition) filters = { 'device_owner': 'network:dhcp:nuage', 'network_id': network['id'] } dhcp_ports = self.ports_client.list_ports(**filters)['ports'] self.assertEqual(1, len(dhcp_ports)) self.assertEqual(dhcp_ports[0]['fixed_ips'][0]['subnet_id'], v4_subnet['id']) self.assertEqual(dhcp_ports[0]['fixed_ips'][0]['ip_address'], vsd_l2domain1.gateway) v6_subnet = self.create_subnet( network, ip_version=6, cidr=IPNetwork('cbfe:babe::/64'), mask_bits=64, nuagenet=vsd_l2domain2.id, net_partition=Topology.def_netpartition) if Topology.has_dhcp_v6_support(): dhcp_ports = self.ports_client.list_ports(**filters)['ports'] self.assertEqual(2, len(dhcp_ports)) for dhcp_port in dhcp_ports: if dhcp_port['fixed_ips'][0]['subnet_id'] == v6_subnet['id']: self.assertEqual( dhcp_port['fixed_ips'][0]['ip_address'], vsd_l2domain2.ipv6_gateway)
def _given_network_linked_to_vsd_subnet(self, vsd_subnet, cidr4=None, cidr6=None, enable_dhcp=True): # create OpenStack IPv4 subnet on OpenStack based on VSD l3dom subnet net_name = data_utils.rand_name('network-') network = self.create_network(network_name=net_name) if vsd_subnet.parent_type == 'zone': subnet4 = self.create_subnet(network, cidr=cidr4, enable_dhcp=enable_dhcp, mask_bits=cidr4.prefixlen, nuagenet=vsd_subnet.id, net_partition=self.net_partition) else: subnet4 = self.create_subnet(network, gateway=None, cidr=cidr4, enable_dhcp=enable_dhcp, mask_bits=cidr4.prefixlen, nuagenet=vsd_subnet.id, net_partition=self.net_partition) # create OpenStack IPv6 subnet on OpenStack based on VSD l3dom subnet subnet6 = None if cidr6: subnet6 = self.create_subnet( network, ip_version=6, cidr=cidr6, mask_bits=IPNetwork(cidr6).prefixlen, enable_dhcp=(vsd_subnet.enable_dhcpv6 if Topology.has_dhcp_v6_support() else False), nuagenet=vsd_subnet.id, net_partition=self.net_partition) return network, subnet4, subnet6
class DNSScenarioTest(nuage_test.NuageBaseTest): default_prepare_for_connectivity = True def _test_dns_up_to_vm(self, ip_versions=None, is_l3=None): dns = {6: 'cafe:babe:cafe:babe:cafe:babe:cafe:babe', 4: '1.1.1.1'} network = self.create_network() subnet = None for ip_version in ip_versions: subnet = self.create_subnet(network, ip_version=ip_version, dns_nameservers=[dns.get(ip_version)]) if is_l3: router = self.create_router( external_network_id=CONF.network.public_network_id) self.router_attach(router, subnet) # create open-ssh security group ssh_security_group = self.create_open_ssh_security_group() server = self.create_tenant_server( [network], security_groups=[ssh_security_group], prepare_for_connectivity=True) # makes sure that all the DNSs configured. server.send(cmd="[ `cat /etc/resolv.conf | grep nameserver | " "wc -l` = {} ]".format(len(ip_versions)), timeout=300) result = server.send(cmd="cat /etc/resolv.conf | grep nameserver") for ip_version in ip_versions: self.assertIn(dns.get(ip_version), result, 'DNS={} is not configured ' 'properly.'.format(dns.get(ip_version))) @decorators.attr(type='smoke') def test_dns_up_to_vm_l2_v4(self): self._test_dns_up_to_vm(ip_versions=[4], is_l3=False) @testtools.skipIf(not Topology.has_single_stack_v6_support(), 'No singe-stack v6 supported') def test_dns_up_to_vm_l2_v6(self): self._test_dns_up_to_vm(ip_versions=[6], is_l3=False) def test_dns_up_to_vm_l3_v4(self): self._test_dns_up_to_vm(ip_versions=[4], is_l3=True) @testtools.skipIf(not Topology.has_single_stack_v6_support(), 'No singe-stack v6 supported') @decorators.attr(type='smoke') def test_dns_up_to_vm_l3_v6(self): self._test_dns_up_to_vm(ip_versions=[6], is_l3=True) @testtools.skipUnless(Topology.has_dhcp_v6_support(), 'No dhcp v6 supported') def test_dns_up_to_vm_l2_dualstack(self): self._test_dns_up_to_vm(ip_versions=[6, 4], is_l3=False) @testtools.skipUnless(Topology.has_dhcp_v6_support(), 'No dhcp v6 supported') @decorators.attr(type='smoke') def test_dns_up_to_vm_l3_dualstack(self): self._test_dns_up_to_vm(ip_versions=[6, 4], is_l3=True)
class OsManagedDualStackL3SubnetsTest(NuageBaseTest): _vsd_ipv4_address = 'address' _vsd_ipv6_address = 'IPv6Address' @classmethod def skip_checks(cls): super(OsManagedDualStackL3SubnetsTest, cls).skip_checks() if not NUAGE_FEATURES.os_managed_dualstack_subnets: raise cls.skipException( 'OS Managed Dual Stack is not supported in this release') @classmethod def setup_clients(cls): super(OsManagedDualStackL3SubnetsTest, cls).setup_clients() cls.nuage_client = NuageRestClient() def create_v6_subnet(self, network, cleanup=True, enable_dhcp=False): return self.create_subnet(network, ip_version=6, enable_dhcp=enable_dhcp, cleanup=cleanup) def _verify_ipv6_subnet_with_vsd_l2_domain(self, subnet, by_subnet): """_verify_ipv6_subnet_with_vsd_l2_domain Verifies the VSD l2 domain defined by 'by_subnet' with the openstack subnet 'subnet'. @param by_subnet: the subnet via which the l2 domain will be retrieved @param subnet: the subnet to compare the L2 domain with """ vsd_l2_domain = self.vsd.get_l2domain(by_subnet=by_subnet) self.assertIsNotNone(vsd_l2_domain) self.assertIsNone(subnet['ipv6_ra_mode']) self.assertIsNone(subnet['ipv6_address_mode']) if Topology.has_single_stack_v6_support(): self.assertEqual('DUALSTACK', vsd_l2_domain.ip_type) self.assertEqual(subnet['cidr'], vsd_l2_domain.ipv6_address) self.assertEqual(subnet.get('enable_dhcp'), vsd_l2_domain.enable_dhcpv6) else: if subnet['enable_dhcp'] or by_subnet['enable_dhcp']: self.assertEqual('DUALSTACK', vsd_l2_domain.ip_type) self.assertEqual(subnet['cidr'], vsd_l2_domain.ipv6_address) else: self.assertIsNone(vsd_l2_domain.ip_type) self.assertIsNone(vsd_l2_domain.ipv6_address) if subnet.get('enable_dhcp'): filters = { 'device_owner': 'network:dhcp:nuage', 'network_id': subnet['network_id'] } dhcp_ports = self.ports_client.list_ports(**filters)['ports'] self.assertEqual(1, len(dhcp_ports)) for fixed_ip in dhcp_ports[0]['fixed_ips']: if fixed_ip['subnet_id'] == subnet['id']: self.assertEqual(fixed_ip['ip_address'], vsd_l2_domain.ipv6_gateway) elif not Topology.is_v5: self.assertIsNone(vsd_l2_domain.ipv6_gateway) self.assertFalse(subnet['vsd_managed']) self.assertFalse(subnet['enable_dhcp'], 'IPv6 subnet MUST have enable_dhcp=FALSE') ########################################################################### # Typical ########################################################################### @decorators.attr(type='smoke') def test_os_managed_dual_stack_l3_subnet_with_vm(self): # Provision OpenStack network network = self.create_network() # When I create an IPv4 subnet ipv4_subnet = self.create_subnet(network) self.assertIsNotNone(ipv4_subnet) # Then a VSD L2 domain is created with type IPv4 vsd_l2_domain = self.vsd.get_l2domain( by_subnet=ipv4_subnet) self.assertIsNotNone(vsd_l2_domain) self.assertEqual("IPV4", vsd_l2_domain.ip_type) # When I add an IPv6 subnet ipv6_subnet = self.create_subnet( network, ip_version=6, enable_dhcp=False) self.assertIsNotNone(ipv6_subnet) # Then the VSD L2 domain is changed to IP type DualStack self._verify_ipv6_subnet_with_vsd_l2_domain( ipv6_subnet, by_subnet=ipv4_subnet) router = self.create_router() self.assertIsNotNone(router) vsd_l3_domain = self.vsd.get_l3domain(by_router_id=router['id']) self.assertIsNotNone(vsd_l3_domain) self.router_attach(router, ipv4_subnet) vsd_l3_domain.fetch() vsd_l3_subnet = self.vsd.get_subnet_from_domain( domain=vsd_l3_domain, by_subnet=ipv4_subnet) port = self.create_port(network) self._verify_port(port, subnet4=ipv4_subnet, subnet6=None), self._verify_vport_in_l3_subnet(port, vsd_l3_subnet) server1 = self.create_tenant_server(ports=[port]) self.assertIsNotNone(server1) @testtools.skipUnless(Topology.has_dhcp_v6_support(), 'No dhcp v6 supported') @decorators.attr(type='smoke') def test_os_managed_dual_stack_l3_subnet_with_dns_server(self): # Provision OpenStack network network = self.create_network() kwargs = {6: {'dns_nameservers': ['2001:4860:4860::8844', '2001:4860:4860::8888']}, 4: {'dns_nameservers': ['8.8.4.4', '8.8.8.8']}} ipv4_subnet = self.create_subnet(network, **kwargs[4]) router = self.create_router() self.router_attach(router, ipv4_subnet) ipv6_subnet = self.create_subnet(network, ip_version=6, enable_dhcp=True, **kwargs[6]) nuage_subnet = self.nuage_client.get_domain_subnet( None, None, by_subnet=ipv4_subnet) nuage_dhcpv4opt = self.nuage_client.get_dhcpoption( nuage_constants.SUBNETWORK, nuage_subnet[0]['ID'], ipv4_subnet['ip_version']) self._check_dhcp_option(nuage_dhcpv4opt, ipv4_subnet, l2=False) nuage_dhcpv6opt = self.nuage_client.get_dhcpoption( nuage_constants.SUBNETWORK, nuage_subnet[0]['ID'], ipv6_subnet['ip_version']) self._check_dhcp_option(nuage_dhcpv6opt, ipv6_subnet, l2=False) def _check_dhcp_option(self, nuage_dhcpopt, subnet, l2=True): opt_index = 0 if subnet['ip_version'] == 4 and subnet.get('gateway_ip', None) and l2: self.assertGreater(len(nuage_dhcpopt), opt_index) self.assertEqual(self.ip_to_hex( subnet['gateway_ip']), nuage_dhcpopt[opt_index]['value']) self.assertEqual(nuage_dhcpopt[opt_index]['type'], "03") self.assertEqual(nuage_dhcpopt[opt_index]['externalID'], self.nuage_client.get_vsd_external_id( subnet.get('id'))) opt_index += 1 if subnet.get('dns_nameservers'): self.assertGreater(len(nuage_dhcpopt), opt_index) self.assertEqual(nuage_dhcpopt[opt_index]['type'], "06" if subnet['ip_version'] == 4 else "17") dns1 = self.ip_to_hex(subnet['dns_nameservers'][0]) dns2 = self.ip_to_hex(subnet['dns_nameservers'][1]) ip_length = 8 if subnet['ip_version'] == 4 else 32 dhcp_dns = ([nuage_dhcpopt[opt_index]['value'][0:ip_length], nuage_dhcpopt[opt_index]['value'][ip_length:]]) self.assertIn(dns1, dhcp_dns) self.assertIn(dns2, dhcp_dns) ########################################################################### # A few smoky scenario's with subnet attach ########################################################################### # ------------------------------------------------------------------------- # Section A: attach the ipv4 subnet and check proceeding of a few scenarios # ------------------------------------------------------------------------- # eventually delete this - this is obviously elsewhere tested @decorators.attr(type='smoke') def test_dualstack_attach_ipv4_and_cleanup(self): network = self.create_network() router = self.create_router() ipv4_subnet = self.create_subnet(network) self.create_v6_subnet(network) self.router_attach(router, ipv4_subnet) @decorators.attr(type='smoke') def test_dualstack_attach_ipv4_delete_ipv6_and_cleanup(self): network = self.create_network() router = self.create_router() ipv4_subnet = self.create_subnet(network) ipv6_subnet = self.create_v6_subnet(network, cleanup=False, enable_dhcp=True) self.router_attach(router, ipv4_subnet) self.check_dhcp_port(network['id'], [4, 6]) self.delete_subnet(ipv6_subnet) self.check_dhcp_port(network['id'], [4]) @decorators.attr(type='smoke') def test_dualstack_attach_ipv4_delete_ipv6_and_recreate(self): network = self.create_network() router = self.create_router() ipv4_subnet = self.create_subnet(network) ipv6_subnet = self.create_v6_subnet(network, cleanup=False) self.router_attach(router, ipv4_subnet) # delete the ipv6 subnet self.delete_subnet(ipv6_subnet) # recreate an ipv6 subnet self.create_v6_subnet(network) # ------------------------------------------------------------------------- # Section B: attach the ipv6 subnet and check proceeding of a few scenarios # ------------------------------------------------------------------------- @decorators.attr(type='smoke') def test_pure_ipv6_attach_and_cleanup(self): network = self.create_network() router = self.create_router() ipv6_subnet = self.create_v6_subnet(network) self.router_attach(router, ipv6_subnet) @decorators.attr(type='smoke') def test_dualstack_attach_ipv6_and_cleanup(self): network = self.create_network() router = self.create_router() self.create_subnet(network) ipv6_subnet = self.create_v6_subnet(network) self.router_attach(router, ipv6_subnet) @decorators.attr(type='smoke') def test_dualstack_attach_ipv6_delete_ipv4_and_cleanup(self): network = self.create_network() router = self.create_router() ipv4_subnet = self.create_subnet(network, cleanup=False) ipv6_subnet = self.create_v6_subnet(network, enable_dhcp=True) self.router_attach(router, ipv6_subnet) self.check_dhcp_port(network['id'], [4, 6]) self.delete_subnet(ipv4_subnet) self.check_dhcp_port(network['id'], [6]) @decorators.attr(type='smoke') # This is the scenario described in OPENSTACK-1990 def test_dualstack_attach_ipv6_delete_ipv4_and_recreate(self): network = self.create_network() router = self.create_router() ipv4_subnet = self.create_subnet(network, cleanup=False) ipv6_subnet = self.create_v6_subnet(network) self.router_attach(router, ipv6_subnet) # delete the ipv4 subnet self.delete_subnet(ipv4_subnet) # recreate an ipv4 subnet self.create_subnet(network) # ------------------------------------------------------------------------- # Section C: Double attachment # ------------------------------------------------------------------------- @decorators.attr(type='smoke') def test_dualstack_attach_in_v4_then_v6_order_and_cleanup(self): network = self.create_network() router = self.create_router() ipv4_subnet = self.create_subnet(network) ipv6_subnet = self.create_v6_subnet(network) self.router_attach(router, ipv4_subnet) self.router_attach(router, ipv6_subnet) @decorators.attr(type='smoke') def test_dualstack_attach_in_v4_then_v6_order_and_cleanup_reversely(self): network = self.create_network() router = self.create_router() ipv4_subnet = self.create_subnet(network) ipv6_subnet = self.create_v6_subnet(network) filters = { 'device_owner': 'network:dhcp:nuage', 'network_id': ipv4_subnet['network_id'] } dhcp_ports = self.ports_client.list_ports(**filters)['ports'] self.assertEqual(1, len(dhcp_ports)) self.assertEqual(dhcp_ports[0]['fixed_ips'][0]['subnet_id'], ipv4_subnet['id']) self.router_attach(router, ipv4_subnet, cleanup=False) dhcp_ports = self.ports_client.list_ports(**filters)['ports'] self.assertEqual(0, len(dhcp_ports)) self.router_attach(router, ipv6_subnet) self.router_detach(router, ipv4_subnet) dhcp_ports = self.ports_client.list_ports(**filters)['ports'] self.assertEqual(0, len(dhcp_ports)) @decorators.attr(type='smoke') def test_dualstack_attach_in_v6_then_v4_order_and_cleanup(self): network = self.create_network() router = self.create_router() ipv4_subnet = self.create_subnet(network) ipv6_subnet = self.create_v6_subnet(network) self.router_attach(router, ipv6_subnet) self.router_attach(router, ipv4_subnet) @decorators.attr(type='smoke') def test_dualstack_attach_in_v6_then_v4_order_and_cleanup_reversely(self): network = self.create_network() router = self.create_router() ipv4_subnet = self.create_subnet(network) ipv6_subnet = self.create_v6_subnet(network) filters = { 'device_owner': 'network:dhcp:nuage', 'network_id': ipv4_subnet['network_id'] } dhcp_ports = self.ports_client.list_ports(**filters)['ports'] self.assertEqual(1, len(dhcp_ports)) self.assertEqual(dhcp_ports[0]['fixed_ips'][0]['subnet_id'], ipv4_subnet['id']) self.router_attach(router, ipv6_subnet, cleanup=False) dhcp_ports = self.ports_client.list_ports(**filters)['ports'] self.assertEqual(0, len(dhcp_ports)) self.router_attach(router, ipv4_subnet) self.router_detach(router, ipv6_subnet) dhcp_ports = self.ports_client.list_ports(**filters)['ports'] self.assertEqual(0, len(dhcp_ports)) @decorators.attr(type='smoke') def test_dualstack_attach_detach_check_nuage_dhcp_port(self): network = self.create_network() router = self.create_router() ipv4_subnet = self.create_subnet(network) ipv6_subnet = self.create_v6_subnet(network) filters = { 'device_owner': 'network:dhcp:nuage', 'network_id': ipv4_subnet['network_id'] } dhcp_ports = self.ports_client.list_ports(**filters)['ports'] self.assertEqual(1, len(dhcp_ports)) self.assertEqual(dhcp_ports[0]['fixed_ips'][0]['subnet_id'], ipv4_subnet['id']) self.router_attach(router, ipv6_subnet, cleanup=False) self.router_attach(router, ipv4_subnet, cleanup=False) dhcp_ports = self.ports_client.list_ports(**filters)['ports'] self.assertEqual(0, len(dhcp_ports)) self.router_detach(router, ipv6_subnet) self.router_detach(router, ipv4_subnet) dhcp_ports = self.ports_client.list_ports(**filters)['ports'] self.assertEqual(1, len(dhcp_ports)) self.assertEqual(dhcp_ports[0]['fixed_ips'][0]['subnet_id'], ipv4_subnet['id']) # ------------------------------------------------------------------------- # Section D: Special cases # ------------------------------------------------------------------------- @decorators.attr(type='smoke') def test_router_attach_ipv4_and_add_ipv6(self): network = self.create_network() router = self.create_router() ipv4_subnet = self.create_subnet(network) self.router_attach(router, ipv4_subnet, cleanup=False) # now add ipv6 subnet self.create_v6_subnet(network) # and detach ipv4 self.router_detach(router, ipv4_subnet) @decorators.attr(type='smoke') # This is the scenario described in OPENSTACK-2004 def test_router_attach_ipv6_and_add_ipv4(self): network = self.create_network() router = self.create_router() ipv6_subnet = self.create_v6_subnet(network) self.router_attach(router, ipv6_subnet, cleanup=False) # now add ipv4 subnet self.create_subnet(network) # and detach ipv6 self.router_detach(router, ipv6_subnet)
def do_test(ipv6_cidr, dhcp6_server_ip, use_allocation_pool=False): ipv6_cidr = IPNetwork(ipv6_cidr) testcase = "TC-({},{},{})".format(str(ipv6_cidr), str(dhcp6_server_ip), use_allocation_pool) if self.os_dhcp_managed: # OS DHCP managed, VSD DHCP managed vsd_l2domain_template = self.vsd_create_l2domain_template( dhcp_managed=True, ip_type="DUALSTACK", cidr4=self.cidr4, enable_dhcpv4=True, cidr6=ipv6_cidr, ipv6_gateway=dhcp6_server_ip, enable_dhcpv6=True) self._verify_vsd_l2domain_template( vsd_l2domain_template, ip_type="DUALSTACK", dhcp_managed=True, cidr4=self.cidr4, enable_dhcpv4=True, cidr6=ipv6_cidr, ipv6_gateway=dhcp6_server_ip, enable_dhcpv6=True) elif self.vsd_dhcp_managed: # OS DHCP unmanaged, VSD DHCP managed (new 6.x style) vsd_l2domain_template = self.vsd_create_l2domain_template( dhcp_managed=True, ip_type="DUALSTACK", cidr4=self.cidr4, enable_dhcpv4=False, cidr6=IPNetwork(ipv6_cidr), enable_dhcpv6=False) self._verify_vsd_l2domain_template(vsd_l2domain_template, dhcp_managed=True, ip_type="DUALSTACK", cidr4=self.cidr4, gateway=None, enable_dhcpv4=False, cidr6=ipv6_cidr, ipv6_gateway=None, enable_dhcpv6=False) else: # OS DHCP unmanaged, VSD DHCP unmanaged (legacy 5.x style) vsd_l2domain_template = self.vsd_create_l2domain_template( dhcp_managed=False) self._verify_vsd_l2domain_template(vsd_l2domain_template, dhcp_managed=False, ip_type=None, netmask=None, address=None, gateway=None, ipv6_address=None, ipv6_gateway=None) vsd_l2domain = self.vsd_create_l2domain( template=vsd_l2domain_template) self._verify_vsd_l2domain_with_template( vsd_l2domain, vsd_l2domain_template) # create OpenStack IPv6 subnet based on VSD l2dom subnet net_name = data_utils.rand_name('network-') network = self.create_network(network_name=net_name) mask_bits = ipv6_cidr.prefixlen kwargs = { 'ip_version': 6, 'cidr': ipv6_cidr, 'mask_bits': mask_bits, # gateway is not set (VSD in any case doesn't mind ...) 'enable_dhcp': (vsd_l2domain_template.enable_dhcpv6 if self.vsd_dhcp_managed and Topology.has_dhcp_v6_support() else False), 'nuagenet': vsd_l2domain.id, 'net_partition': self.net_partition } if use_allocation_pool: start6 = ipv6_cidr[10] end6 = ipv6_cidr[20] pool = {'start': start6, 'end': end6} kwargs['allocation_pools'] = [pool] else: start6 = ipv6_cidr[2] # gateway ip is cleared but # as it originally was set, allocation pool is not adjusted end6 = ipv6_cidr[-1] # :ff:ff ipv6_subnet = self.create_subnet(network, **kwargs) self.assertEqual(ipv6_cidr, IPNetwork(ipv6_subnet['cidr'])) if self.os_dhcp_managed: self.assertEqual( IPNetwork(ipv6_subnet['cidr']), IPNetwork(vsd_l2domain_template.ipv6_address)) self.assertEqual( start6, IPAddress(ipv6_subnet['allocation_pools'][0]['start']), message='testcase: ' + testcase) self.assertEqual( end6, IPAddress(ipv6_subnet['allocation_pools'][0]['end']), message='testcase: ' + testcase) kwargs = { 'cidr': self.cidr4, 'mask_bits': self.mask_bits4_unsliced, # in case we run 5.x, this is always True when VSD is # dhcp managed 'enable_dhcp': (self.os_dhcp_managed or Topology.is_v5 and self.vsd_dhcp_managed), 'gateway': None, # gateway is not set (which ~ to option 3 not set) 'nuagenet': vsd_l2domain.id, 'net_partition': self.net_partition } if use_allocation_pool: start4 = self.cidr4[10] end4 = self.cidr4[20] pool = {'start': start4, 'end': end4} kwargs['allocation_pools'] = [pool] else: start4 = self.cidr4[1] # .1 as of gateway not set. end4 = self.cidr4[-2] # .254 # create OpenStack IPv4 subnet based on VSD l2domain ipv4_subnet = self.create_subnet(network, **kwargs) self.assertEqual(str(self.cidr4), ipv4_subnet['cidr']) self.assertEqual( start4, IPAddress(ipv4_subnet['allocation_pools'][0]['start']), message='testcase: ' + testcase) self.assertEqual( end4, IPAddress(ipv4_subnet['allocation_pools'][0]['end']), message='testcase: ' + testcase) # create a port in the network - IPAM by OS port = self.create_port(network) self._verify_port(port, subnet4=None, subnet6=ipv6_subnet, status='DOWN', nuage_policy_groups=None, nuage_redirect_targets=[], nuage_floatingip=None, testcase=testcase) self._verify_vport_in_l2_domain(port, vsd_l2domain)
def is_dhcp_enabled_on_subnet(subnet): return (subnet['enable_dhcp'] and (subnet['ip_version'] == 4 or Topology.has_dhcp_v6_support()))
class OsManagedDualStackL2SubnetsTest(NuageBaseTest, nuage_test.NuageAdminNetworksTest): credentials = ['primary', 'admin'] # TODO(waelj) port to VSD helper @classmethod def setup_clients(cls): super(OsManagedDualStackL2SubnetsTest, cls).setup_clients() cls.nuage_client = NuageRestClient() def _verify_ipv6_subnet_with_vsd_l2_domain(self, subnet, by_subnet): """_verify_ipv6_subnet_with_vsd_l2_domain Verifies the VSD l2 domain defined by 'by_subnet' with the openstack subnet 'subnet'. @param by_subnet: the subnet via which the l2 domain will be retrieved @param subnet: the subnet to compare the L2 domain with """ vsd_l2_domain = self.vsd.get_l2domain(by_subnet=by_subnet) self.assertIsNotNone(vsd_l2_domain) self.assertIsNone(subnet['ipv6_ra_mode']) self.assertIsNone(subnet['ipv6_address_mode']) if Topology.has_single_stack_v6_support(): self.assertEqual('DUALSTACK', vsd_l2_domain.ip_type) self.assertEqual(subnet['cidr'], vsd_l2_domain.ipv6_address) self.assertEqual(subnet['enable_dhcp'], vsd_l2_domain.enable_dhcpv6) else: if subnet['enable_dhcp'] or by_subnet['enable_dhcp']: self.assertEqual('DUALSTACK', vsd_l2_domain.ip_type) self.assertEqual(subnet['cidr'], vsd_l2_domain.ipv6_address) else: self.assertIsNone(vsd_l2_domain.ip_type) self.assertIsNone(vsd_l2_domain.ipv6_address) if subnet['enable_dhcp']: filters = { 'device_owner': 'network:dhcp:nuage', 'network_id': subnet['network_id'] } dhcp_ports = self.ports_client.list_ports(**filters)['ports'] self.assertEqual(1, len(dhcp_ports)) for fixed_ip in dhcp_ports[0]['fixed_ips']: if fixed_ip['subnet_id'] == subnet['id']: self.assertEqual(fixed_ip['ip_address'], vsd_l2_domain.ipv6_gateway) elif Topology.is_v5: self.assertEqual(subnet['enable_dhcp'] or by_subnet['enable_dhcp'], vsd_l2_domain.dhcp_managed) else: self.assertTrue(vsd_l2_domain.dhcp_managed) self.assertIsNone(vsd_l2_domain.ipv6_gateway) self.assertFalse(subnet['vsd_managed']) # TODO(waelj) VSD-20971 / VSD-21874 # self.assertFalse(vsd_l2_domain.dualStackDynamicIPAllocation, # "VSD should not allocated IPv6 address") # TODO(waelj) port to VSD helper def _verify_vport_in_l2_domain(self, port, vsd_l2domain, **kwargs): nuage_vports = self.nuage_client.get_vport(nuage_constants.L2_DOMAIN, vsd_l2domain.id, filters='externalID', filter_values=port['id']) self.assertEqual( len(nuage_vports), 1, "Must find one VPort matching port: %s" % port['name']) nuage_vport = nuage_vports[0] self.assertThat(nuage_vport, ContainsDict({'name': Equals(port['id'])})) # verify all other kwargs as attributes (key,value) pairs for key, value in iteritems(kwargs): if isinstance(value, dict): # compare dict raise NotImplementedError if isinstance(value, list): # self.assertThat(port, ContainsDict({key: Equals(value)})) self.assertItemsEqual(port[key], value) else: self.assertThat(port, ContainsDict({key: Equals(value)})) def _verify_port(self, port, subnet4=None, subnet6=None, **kwargs): has_ipv4_ip = False has_ipv6_ip = False for fixed_ip in port['fixed_ips']: ip_address = fixed_ip['ip_address'] if subnet4 is not None and fixed_ip['subnet_id'] == subnet4['id']: self.verify_ip_in_allocation_pools(ip_address, subnet4['allocation_pools']) has_ipv4_ip = True if subnet6 is not None and fixed_ip['subnet_id'] == subnet6['id']: self.verify_ip_in_allocation_pools(ip_address, subnet6['allocation_pools']) has_ipv6_ip = True if subnet4: self.assertTrue( has_ipv4_ip, "Must have an IPv4 ip in subnet: %s" % subnet4['id']) if subnet6: self.assertTrue( has_ipv6_ip, "Must have an IPv6 ip in subnet: %s" % subnet6['id']) self.assertIsNotNone(port['mac_address']) # verify all other kwargs as attributes (key,value) pairs for key, value in iteritems(kwargs): if isinstance(value, dict): # compare dict raise NotImplementedError if isinstance(value, list): self.assertItemsEqual(port[key], value) else: self.assertThat(port, ContainsDict({key: Equals(value)})) ########################################################################### # Typical ########################################################################### @decorators.attr(type='smoke') def test_os_managed_dual_stack_subnet(self): # Provision OpenStack network network = self.create_network() # When I create an IPv4 subnet ipv4_subnet = self.create_subnet(network) self.assertIsNotNone(ipv4_subnet) # Then a VSD L2 domain is created with type IPv4 vsd_l2_domain = self.vsd.get_l2domain(by_subnet=ipv4_subnet) self.assertIsNotNone(vsd_l2_domain) self.assertEqual("IPV4", vsd_l2_domain.ip_type) # When I add an IPv6 subnet ipv6_subnet = self.create_subnet(network, ip_version=6, enable_dhcp=False) self.assertIsNotNone(ipv6_subnet) # Then the VSD L2 domain is changed to IPtype DualStack self._verify_ipv6_subnet_with_vsd_l2_domain(ipv6_subnet, ipv4_subnet) port = self.create_port(network) self._verify_port(port, subnet4=ipv4_subnet, subnet6=None), self._verify_vport_in_l2_domain(port, vsd_l2_domain) @decorators.attr(type='smoke') def test_os_managed_dual_stack_subnet_with_dhcp_managed_ipv6(self): # Provision OpenStack network network = self.create_network() # When I create an IPv4 subnet ipv4_subnet = self.create_subnet(network) self.assertIsNotNone(ipv4_subnet) # And I add an IPv6 subnet with DHCP, it should be OK ipv6_subnet = self.create_subnet(network, ip_version=6, enable_dhcp=True) self._verify_ipv6_subnet_with_vsd_l2_domain(ipv6_subnet, ipv4_subnet) @testtools.skipUnless(Topology.has_dhcp_v6_support(), 'No dhcp v6 supported') @decorators.attr(type='smoke') def test_os_managed_dual_stack_subnet_with_dns_server(self): # Provision OpenStack network network = self.create_network() kwargs = { 6: { 'dns_nameservers': ['2001:4860:4860::8844', '2001:4860:4860::8888'] }, 4: { 'dns_nameservers': ['8.8.4.4', '8.8.8.8'] } } ipv4_subnet = self.create_subnet(network, **kwargs[4]) ipv6_subnet = self.create_subnet(network, ip_version=6, enable_dhcp=True, **kwargs[6]) vsd_l2_domain = self.vsd.get_l2domain(by_subnet=ipv4_subnet) nuage_dhcpv4opt = self.nuage_client.get_dhcpoption( nuage_constants.L2_DOMAIN, vsd_l2_domain.id, ipv4_subnet['ip_version']) self._check_dhcp_option(nuage_dhcpv4opt, ipv4_subnet) nuage_dhcpv6opt = self.nuage_client.get_dhcpoption( nuage_constants.L2_DOMAIN, vsd_l2_domain.id, ipv6_subnet['ip_version']) self._check_dhcp_option(nuage_dhcpv6opt, ipv6_subnet) def _check_dhcp_option(self, nuage_dhcpopt, subnet, l2=True): opt_index = 0 if subnet['ip_version'] == 4 and subnet.get('gateway_ip', None) and l2: self.assertGreater(len(nuage_dhcpopt), opt_index) self.assertEqual(self.ip_to_hex(subnet['gateway_ip']), nuage_dhcpopt[opt_index]['value']) self.assertEqual(nuage_dhcpopt[opt_index]['type'], "03") self.assertEqual( nuage_dhcpopt[opt_index]['externalID'], self.nuage_client.get_vsd_external_id(subnet.get('id'))) opt_index += 1 if subnet.get('dns_nameservers'): self.assertGreater(len(nuage_dhcpopt), opt_index) self.assertEqual(nuage_dhcpopt[opt_index]['type'], "06" if subnet['ip_version'] == 4 else "17") dns1 = self.ip_to_hex(subnet['dns_nameservers'][0]) dns2 = self.ip_to_hex(subnet['dns_nameservers'][1]) ip_length = 8 if subnet['ip_version'] == 4 else 32 dhcp_dns = ([ nuage_dhcpopt[opt_index]['value'][0:ip_length], nuage_dhcpopt[opt_index]['value'][ip_length:] ]) self.assertIn(dns1, dhcp_dns) self.assertIn(dns2, dhcp_dns) ########################################################################### # Special cases ########################################################################### @testtools.skipIf(Topology.is_v5, 'IPv6 CIDRs are fully restricted by default from 6.0 ' 'onwards only, i.e. when expert mode is left disabled') def test_os_managed_subnet_with_invalid_ipv6_prefixlen_neg(self): # Provision OpenStack network network = self.create_network() for ipv6_cidr in ['cafe:babe::/63', 'cafe:babe::/65']: ipv6_gateway = 'cafe:babe::1' self.assertRaisesRegex(tempest_exceptions.BadRequest, MSG_INVALID_IPV6_NETMASK, self.create_subnet, network, ip_version=6, cidr=IPNetwork(ipv6_cidr), mask_bits=IPNetwork(ipv6_cidr).prefixlen, gateway=ipv6_gateway) @testtools.skipIf(not Topology.has_single_stack_v6_support(), 'There is no single-stack v6 support in current release') @decorators.attr(type='smoke') def test_os_managed_dhcp_subnet_ipv6_first(self): self._test_os_managed_subnet_ipv6_first(enable_dhcp=True) @testtools.skipIf(not Topology.has_single_stack_v6_support(), 'There is no single-stack v6 support in current release') @decorators.attr(type='smoke') def test_os_managed_no_dhcp_subnet_ipv6_first(self): self._test_os_managed_subnet_ipv6_first(enable_dhcp=False) def _test_os_managed_subnet_ipv6_first(self, enable_dhcp=None): # Provision OpenStack network network = self.create_network() # Create an IPv6 subnet ipv6_subnet = self.create_subnet(network, ip_version=6, enable_dhcp=enable_dhcp, cleanup=False) # Verify L2Dom vsd_l2_domain = self.vsd.get_l2domain( vspk_filter='externalID == "{}"'.format( ExternalId(ipv6_subnet['network_id']).at_cms_id())) self.assertIsNotNone(vsd_l2_domain) filters = { 'device_owner': 'network:dhcp:nuage', 'network_id': network['id'] } self.assertEqual(vsd_l2_domain.ip_type, 'IPV6') dhcp_ports = self.ports_client.list_ports(**filters)['ports'] if Topology.has_dhcp_v6_support(): self.assertEqual(enable_dhcp, vsd_l2_domain.enable_dhcpv6) if enable_dhcp: self.assertEqual(1, len(dhcp_ports)) self.assertEqual(dhcp_ports[0]['fixed_ips'][0]['subnet_id'], ipv6_subnet['id']) else: self.assertEqual(0, len(dhcp_ports)) # Verify port/Vport portv6 = self.create_port(network, cleanup=False) self._verify_port(portv6, subnet6=ipv6_subnet) self._verify_vport_in_l2_domain(portv6, vsd_l2_domain) # Create an IPv4 subnet in the same network ipv4_subnet = self.create_subnet(network, enable_dhcp=enable_dhcp) # Verify the L2Dom is Dualstack now vsd_l2_domain = self.vsd.get_l2domain(by_subnet=ipv6_subnet) self.assertIsNotNone(vsd_l2_domain) self.assertEqual(vsd_l2_domain.ip_type, 'DUALSTACK') dhcp_ports = self.ports_client.list_ports(**filters)['ports'] if enable_dhcp: self.assertTrue(vsd_l2_domain.enable_dhcpv4) self.assertEqual(1, len(dhcp_ports)) self.assertEqual(dhcp_ports[0]['fixed_ips'][0]['subnet_id'], ipv4_subnet['id']) self.assertEqual(dhcp_ports[0]['fixed_ips'][1]['subnet_id'], ipv6_subnet['id']) else: self.assertFalse(vsd_l2_domain.enable_dhcpv4) self.assertEqual(0, len(dhcp_ports)) # Delete Subnet/Port self.delete_port(portv6) self.delete_subnet(ipv6_subnet) vsd_l2_domain = self.vsd.get_l2domain(by_subnet=ipv4_subnet) # Verify the L2Dom self.assertIsNotNone(vsd_l2_domain) self.assertEqual(vsd_l2_domain.ip_type, 'IPV4') self.assertFalse(vsd_l2_domain.enable_dhcpv6) if enable_dhcp: self.assertEqual(1, len(dhcp_ports)) self.assertEqual(dhcp_ports[0]['fixed_ips'][0]['subnet_id'], ipv4_subnet['id']) else: self.assertEqual(0, len(dhcp_ports)) @decorators.attr(type='smoke') def test_os_managed_dhcp_subnet_ipv4_first(self): self._test_os_managed_subnet_ipv4_first(enable_dhcp=True) @decorators.attr(type='smoke') def test_os_managed_no_dhcp_subnet_ipv4_first(self): self._test_os_managed_subnet_ipv4_first(enable_dhcp=False) def _test_os_managed_subnet_ipv4_first(self, enable_dhcp=None): # Provision OpenStack network network = self.create_network() # Create an IPv4 subnet ipv4_subnet = self.create_subnet(network, ip_version=4, enable_dhcp=enable_dhcp, cleanup=False) # Verify L2Dom vsd_l2_domain = self.vsd.get_l2domain(by_subnet=ipv4_subnet) self.assertIsNotNone(vsd_l2_domain) if enable_dhcp: self.assertEqual(vsd_l2_domain.ip_type, 'IPV4') # Verify port/Vport portv4 = self.create_port(network, cleanup=False) self._verify_port(portv4, subnet4=ipv4_subnet) self._verify_vport_in_l2_domain(portv4, vsd_l2_domain) # Create an IPv6 subnet in the same network ipv6_subnet = self.create_subnet(network, enable_dhcp=enable_dhcp, ip_version=6) # Verify the L2Dom is Dualstack now vsd_l2_domain = self.vsd.get_l2domain(by_subnet=ipv4_subnet) self.assertIsNotNone(vsd_l2_domain) if enable_dhcp: self.assertEqual(vsd_l2_domain.ip_type, 'DUALSTACK') # Delete v4 Subnet/Port self.delete_port(portv4) self.delete_subnet(ipv4_subnet) vsd_l2_domain = self.vsd.get_l2domain(by_subnet=ipv6_subnet) # Verify the L2Dom if Topology.has_single_stack_v6_support(): self.assertIsNotNone(vsd_l2_domain) if enable_dhcp: self.assertEqual(vsd_l2_domain.ip_type, 'IPV6') else: self.assertIsNone(vsd_l2_domain) @decorators.attr(type='smoke') # OPENSTACK-1926 def test_os_managed_dual_stack_subnet_ipv4_create_delete_create(self): network = self.create_network() ipv4_subnet = self.create_subnet(network, cleanup=False) self.assertIsNotNone(ipv4_subnet) ipv6_subnet = self.create_subnet(network, ip_version=6, gateway=None) self.assertIsNotNone(ipv6_subnet) self.check_dhcp_port(network['id'], [4, 6]) # delete IPv4 subnet self.manager.subnets_client.delete_subnet(ipv4_subnet['id']) self.check_dhcp_port(network['id'], [6]) # create again self.create_subnet(network) @decorators.attr(type='smoke') # OPENSTACK-1926 def test_os_managed_dual_stack_subnet_ipv6_create_delete_create(self): network = self.create_network() ipv4_subnet = self.create_subnet(network) self.assertIsNotNone(ipv4_subnet) ipv6_subnet = self.create_subnet(network, ip_version=6, gateway=None, cleanup=False) self.assertIsNotNone(ipv6_subnet) self.check_dhcp_port(network['id'], [4, 6]) # delete self.manager.subnets_client.delete_subnet(ipv6_subnet['id']) self.check_dhcp_port(network['id'], [4]) # create again ipv6_subnet = self.create_subnet(network, ip_version=6, gateway=None) self.assertIsNotNone(ipv6_subnet) @decorators.attr(type='smoke') def test_os_managed_dual_stack_subnet_with_ipv4_only_ports(self): # Provision OpenStack network network = self.create_network() # When I create an IPv4 subnet ipv4_subnet = self.create_subnet(network) # And I create a port in the network self.create_port(network) # TODO(waelj) Then the port has only an IPv4 address # When I add an IPv6 subnet ipv6_subnet = self.create_subnet(network, ip_version=6, enable_dhcp=False) self.assertIsNotNone(ipv6_subnet) # TODO(waelj) Then the port has both an IPv4 and IPv6 address # And I create a port in the network self.create_port(network) # TODO(waelj) Then the port has both an IPv4 and IPv6 address # Then the VSD L2 domain is changed to IPtype DualStack self._verify_ipv6_subnet_with_vsd_l2_domain(ipv6_subnet, ipv4_subnet) @decorators.attr(type='smoke') def test_os_managed_dual_stack_subnet_no_gateway(self): # Provision OpenStack network network = self.create_network() # When I create an IPv4 subnet ipv4_subnet = self.create_subnet(network) self.assertIsNotNone(ipv4_subnet) # Then a VSD L2 domain is created with type IPv4 vsd_l2_domain = self.vsd.get_l2domain(by_subnet=ipv4_subnet) self.assertIsNotNone(vsd_l2_domain) self.assertEqual("IPV4", vsd_l2_domain.ip_type) # When I add an IPv6 subnet ipv6_subnet = self.create_subnet(network, ip_version=6, gateway=None, enable_dhcp=False) self.assertIsNotNone(ipv6_subnet) # Then the VSD L2 domain is changed to IPtype DualStack self._verify_ipv6_subnet_with_vsd_l2_domain(ipv6_subnet, ipv4_subnet) port = self.create_port(network) self._verify_port(port, subnet4=ipv4_subnet, subnet6=None), self._verify_vport_in_l2_domain(port, vsd_l2_domain) @decorators.attr(type='smoke') def test_os_managed_dual_stack_subnet_unmanaged(self): # Provision OpenStack network network = self.create_network() # When I create an IPv4 subnet ipv4_subnet = self.create_subnet(network, enable_dhcp=False) self.assertIsNotNone(ipv4_subnet) # Then a VSD L2 domain is created with type IPv4 vsd_l2_domain = self.vsd.get_l2domain(by_subnet=ipv4_subnet) self.assertIsNotNone(vsd_l2_domain) if Topology.is_v5: self.assertIsNone(vsd_l2_domain.ip_type) else: self.assertEqual(vsd_l2_domain.ip_type, 'IPV4') # When I add an IPv6 subnet ipv6_subnet = self.create_subnet(network, ip_version=6, enable_dhcp=False) self.assertIsNotNone(ipv6_subnet) # Then the VSD L2 domain is changed to IPtype DualStack self._verify_ipv6_subnet_with_vsd_l2_domain(ipv6_subnet, ipv4_subnet) port = self.create_port(network) self.assertIsNotNone(port) @decorators.attr(type='smoke') def test_no_vsd_auto_assignment_for_ipv6_addresses(self): network = self.create_network() # When I create an IPv4 subnet ipv4_subnet = self.create_subnet(network) self.assertIsNotNone(ipv4_subnet) # Then a VSD L2 domain is created with type IPv4 vsd_l2_domain = self.nuage_client.get_l2domain( by_subnet=ipv4_subnet)[0] self.assertIsNotNone(vsd_l2_domain) self.assertFalse( vsd_l2_domain['dynamicIpv6Address' if Topology. is_v5 else 'dualStackDynamicIPAllocation'], 'VSD should not allocated IPv6 address') # When I add an IPv6 subnet ipv6_cidr = IPNetwork('cafe:babe::/64') ipv6_subnet = self.create_subnet( network, cidr=ipv6_cidr, mask_bits=ipv6_cidr.prefixlen, gateway=IPAddress(ipv6_cidr.first + 1), ip_version=6, allocation_pools=[{ 'start': IPAddress('cafe:babe::a:0:0:0'), 'end': IPAddress('cafe:babe::a:ffff:ffff:ffff') }]) self.assertIsNotNone(ipv6_subnet) vsd_l2_domain = self.nuage_client.get_l2domain( by_subnet=ipv4_subnet)[0] self.assertIsNotNone(vsd_l2_domain) self.assertFalse( vsd_l2_domain['dynamicIpv6Address' if Topology. is_v5 else 'dualStackDynamicIPAllocation'], 'VSD should not allocated IPv6 address') # When I create a port outside the pool, it should succeed ip_out_of_ipv6_allocation_pool = IPAddress('cafe:babe::b:0:0:0') port_args = { 'fixed_ips': [{ 'subnet_id': ipv4_subnet['id'] }, { 'subnet_id': ipv6_subnet['id'], 'ip_address': ip_out_of_ipv6_allocation_pool }] } port = self.create_port(network, **port_args) self.assertIsNotNone(port) ######################################## # IPv6 address formats ######################################## def test_create_subnet_with_special_address_formats(self): # noinspection PyPep8 valid_ipv6 = [ ("2001:5f74:c4a5:b82e::/64", "2001:5f74:c4a5:b82e:0000:0000:0000:0001"), # valid address range, gateway full addressing - at first address ("2001:5f74:c4a5:b82e::/64", "2001:5f74:c4a5:b82e::1"), # valid address range, gateway zero's compressed addressing # - at first address ("2001:5f74:c4a5:b82e::/64", "2001:5f74:c4a5:b82e:0:000::1"), # valid address range, gateway partly compressed addressing # - at first address ("2001:5f74:c4a5:b82e::/64", "2001:5f74:c4a5:b82e:ffff:ffff:ffff:ffff"), # valid address, gateway at last address ("2001:5f74:c4a5:b82e::/64", "2001:5f74:c4a5:b82e:f483:3427:ab3e:bc21"), # valid address, gateway at random address ("2001:5F74:c4A5:B82e::/64", "2001:5f74:c4a5:b82e:f483:3427:aB3E:bC21"), # valid address, gateway at random address - mixed case ("2001:5f74:c4a5:b82e::/64", "2001:5f74:c4a5:b82e:f4:00::f"), # valid address, gateway at random address - compressed ("3ffe:0b00:0000:0001:5f74:0001:c4a5:b82e/64", "3ffe:0b00:0000:0001:5f74:0001:c4a5:ffff"), # prefix not matching bit mask ] # Provision OpenStack network network = self.create_network() # When I create an IPv4 subnet ipv4_subnet = self.create_subnet(network) self.assertIsNotNone(ipv4_subnet) for ipv6_cidr, ipv6_gateway in valid_ipv6: # When I add an IPv6 subnet ipv6_subnet = self.create_subnet( network, ip_version=6, cidr=IPNetwork(ipv6_cidr), mask_bits=IPNetwork(ipv6_cidr).prefixlen, gateway=ipv6_gateway, enable_dhcp=False, cleanup=False) self.assertIsNotNone(ipv6_subnet) # Then the VSD L2 domain is changed to IPtype DualStack self._verify_ipv6_subnet_with_vsd_l2_domain(ipv6_subnet, by_subnet=ipv4_subnet) # And I create a port in the network port = self.create_port(network, cleanup=False) self._verify_port(port, subnet4=ipv4_subnet, subnet6=ipv6_subnet), self.manager.ports_client.delete_port(port['id']) self.subnets_client.delete_subnet(ipv6_subnet['id']) ########################################################################### # Update IPv6 subnet attributes ########################################################################### @decorators.attr(type='smoke') def test_os_managed_dual_stack_subnet_update_no_vsd(self): # Update of openstack subnet attributes which are by design not # replicated to VSD network = self.create_network() # When I create an IPv4 subnet ipv4_subnet = self.create_subnet(network, enable_dhcp=False) self.assertIsNotNone(ipv4_subnet) # When I add an IPv6 subnet ipv6_subnet = self.create_subnet(network, ip_version=6, enable_dhcp=False) self.assertIsNotNone(ipv6_subnet) # Then the VSD L2 domain is changed to IPtype DualStack self._verify_ipv6_subnet_with_vsd_l2_domain(ipv6_subnet, ipv4_subnet) # Update attributes subnet_attributes = { 'name': "updated name", 'description': "My subnet description" } ipv6_subnet_updated = self.update_subnet(ipv6_subnet, enable_dhcp=False, **subnet_attributes) self.assertThat("updated name", Equals(ipv6_subnet_updated['name'])) self.assertThat("My subnet description", Equals(ipv6_subnet_updated['description'])) vsd_l2_domain = self.vsd.get_l2domain(by_subnet=ipv4_subnet) self.assertIsNotNone(vsd_l2_domain) # L2 domain description should match with network name # if it is dualstack self.assertThat( vsd_l2_domain.description, Equals(ipv4_subnet['name'] if Topology.is_v5 else network['name'])) @decorators.attr(type='smoke') # OPENSTACK-1943 def test_os_managed_dual_stack_subnet_update_gw_no_gw(self): # Provision OpenStack network network = self.create_network() # When I create an IPv4 subnet ipv4_subnet = self.create_subnet(network) self.assertIsNotNone(ipv4_subnet) # When I add an IPv6 subnet ipv6_subnet = self.create_subnet(network, ip_version=6, enable_dhcp=False) self.assertIsNotNone(ipv6_subnet) # Then the VSD L2 domain is changed to DualStack self._verify_ipv6_subnet_with_vsd_l2_domain(ipv6_subnet, ipv4_subnet) # Update attributes subnet_attributes = {'gateway_ip': None} ipv6_subnet_updated = self.update_subnet(ipv6_subnet, enable_dhcp=False, **subnet_attributes) self._verify_ipv6_subnet_with_vsd_l2_domain(ipv6_subnet_updated, ipv4_subnet) self.assertIsNone(ipv6_subnet_updated['gateway_ip']) ########################################################################### # Negative cases ########################################################################### @decorators.attr(type='negative') @decorators.attr(type='smoke') def test_os_managed_dual_stack_create_ipv6_only_port_neg(self): network = self.create_network() ipv6_subnet = self.create_subnet(network, ip_version=6, enable_dhcp=False) if Topology.has_single_stack_v6_support(): port1 = self.create_port(network) self._verify_port(port1, subnet4=None, subnet6=ipv6_subnet) port_ip = IPAddress(port1['fixed_ips'][0]['ip_address']) port_args = { 'fixed_ips': [{ 'ip_address': port_ip + 10 }, { 'ip_address': port_ip + 11 }] } port2 = self.create_port(network, **port_args) self._verify_port(port2, subnet4=None, subnet6=ipv6_subnet) else: self.assertRaisesRegex( tempest_exceptions.BadRequest, "Port can't be a pure ipv6 port. Need ipv4 fixed ip.", self.create_port, network) @testtools.skipIf(not Topology.has_single_stack_v6_support(), 'No singe-stack v6 supported') @decorators.attr(type='smoke') def test_os_managed_dual_stack_update_port_to_ipv6_only(self): network = self.create_network() self.create_subnet(network) self.create_subnet(network, ip_version=6, enable_dhcp=False) port = self.create_port(network) # 1. remove the v4 ip from the port v4_ip = next((ip for ip in port['fixed_ips'] if _is_v4_ip(ip)), None) v4_ip_a = IPAddress(v4_ip['ip_address']) v6_ip = next((ip for ip in port['fixed_ips'] if _is_v6_ip(ip)), None) v6_ip_a = IPAddress(v6_ip['ip_address']) f_ips = {'fixed_ips': [{'ip_address': v6_ip_a}]} self.update_port(port, **f_ips) # 2. add 2nd v6 ip (must succeed) f_ips = { 'fixed_ips': [{ 'ip_address': v4_ip_a }, { 'ip_address': v6_ip_a }, { 'ip_address': v6_ip_a + 1 }] } self.update_port(port, **f_ips) # 3. now remove v4 again f_ips = { 'fixed_ips': [{ 'ip_address': v6_ip_a }, { 'ip_address': v6_ip_a + 1 }] } self.update_port(port, **f_ips) ########################################################################### # Negative cases ########################################################################### @decorators.attr(type='negative') def test_subnet_with_dhcp_unmanaged_ipv6_attr_slaac_neg(self): # Provision OpenStack network network = self.create_network() # When I create an IPv4 subnet ipv4_subnet = self.create_subnet(network) self.assertIsNotNone(ipv4_subnet) # When I add an IPv6 subnet with DHCP, it should fail with BadRequest self.assertRaisesRegex( tempest_exceptions.BadRequest, "Invalid input for operation: " + "ipv6_ra_mode or ipv6_address_mode cannot be set when " "enable_dhcp is set to False.", self.create_subnet, network, ip_version=6, enable_dhcp=False, ipv6_ra_mode='slaac', ipv6_address_mode='slaac') @decorators.attr(type='negative') def test_subnet_with_dhcp_managed_ipv6_only_attr_slaac_neg(self): # Provision OpenStack network network = self.create_network() self.assertRaisesRegex( tempest_exceptions.BadRequest, "Attribute ipv6_ra_mode must be 'dhcpv6-stateful' or not set.", self.create_subnet, network, mask_bits=64, ip_version=6, enable_dhcp=True, ipv6_ra_mode='slaac', ipv6_address_mode='slaac') @decorators.attr(type='negative') def test_subnet_with_dhcp_managed_ipv6_attr_slaac_neg(self): # Provision OpenStack network network = self.create_network() # When I create an IPv4 subnet ipv4_subnet = self.create_subnet(network) self.assertIsNotNone(ipv4_subnet) # And I add an IPv6 subnet with slaac, it should fail with BadRequest self.assertRaisesRegex( tempest_exceptions.BadRequest, "Attribute ipv6_ra_mode must be 'dhcpv6-stateful' or not set.", self.create_subnet, network, mask_bits=64, ip_version=6, enable_dhcp=True, ipv6_ra_mode='slaac', ipv6_address_mode='slaac') @decorators.attr(type='negative') def test_multiple_ipv6_subnets_neg(self): # Provision OpenStack network network = self.create_network() # When I add an IPv6 subnet ipv6_subnet = self.create_subnet(network, ip_version=6, enable_dhcp=False) self.assertIsNotNone(ipv6_subnet) if Topology.has_single_stack_v6_support(): ipv6_subnet = self.create_subnet( network, cidr=IPNetwork("2fbe:4568:a:b::/64"), mask_bits=64, ip_version=6, enable_dhcp=False) self.assertIsNotNone(ipv6_subnet) else: # When I add an a second IPv6 subnet, it should fail self.assertRaisesRegex( tempest_exceptions.BadRequest, "A network with an ipv6 subnet may only have maximum " "1 ipv4 and 1 ipv6 subnet", self.create_subnet, network, cidr=IPNetwork("2fbe:4568:a:b::/64"), mask_bits=64, ip_version=6, enable_dhcp=False) @decorators.attr(type='negative') def test_dual_stack_subnet_multiple_ipv4_subnets_neg(self): # Provision OpenStack network network = self.create_network() # When I create an IPv4 subnet ipv4_subnet = self.create_subnet(network) self.assertIsNotNone(ipv4_subnet) # When I add an IPv6 subnet ipv6_subnet = self.create_subnet(network, ip_version=6, enable_dhcp=False) self.assertIsNotNone(ipv6_subnet) if Topology.is_v5: msg = ('A network with an ipv6 subnet may only have maximum 1 ipv4' ' and 1 ipv6 subnet') else: msg = ('A network can only have maximum 1 ipv4 and 1 ipv6 subnet' ' existing together') self.assertRaisesRegex(tempest_exceptions.BadRequest, msg, self.create_subnet, network) @decorators.attr(type='negative') def test_multiple_ipv4_subnets_with_ipv6_subnet_neg(self): if self.is_dhcp_agent_present(): raise self.skipException( 'Cannot run this test case when DHCP agent is enabled') # Provision OpenStack network network = self.create_network() # When I create an IPv4 subnet ipv4_subnet = self.create_subnet(network) self.assertIsNotNone(ipv4_subnet) # When I add an IPv4 subnet ipv4_subnet2 = self.create_subnet(network) self.assertIsNotNone(ipv4_subnet2) if Topology.is_v5: msg = ('A network with an ipv6 subnet may only have maximum 1 ' 'ipv4 and 1 ipv6 subnet') else: msg = ('A network can only have maximum 1 ipv4 and 1 ipv6 subnet ' 'existing together') # When I add an IPv6 subnet, it should fail self.assertRaisesRegex(tempest_exceptions.BadRequest, msg, self.create_subnet, network, cidr=IPNetwork("2fbe:4568:a:b::/64"), mask_bits=64, ip_version=6, enable_dhcp=False) @decorators.attr(type='negative') def test_delete_ipv4_subnet_with_port_from_dual_stack_subnets_neg(self): # Provision OpenStack network network = self.create_network() # When I create an IPv4 subnet ipv4_subnet = self.create_subnet(network) self.assertIsNotNone(ipv4_subnet) # And I create a port in the network port1 = self.create_port(network) self.assertIsNotNone(port1) # When I add an IPv6 subnet ipv6_subnet = self.create_subnet(network, ip_version=6, enable_dhcp=False) self.assertIsNotNone(ipv6_subnet) self.assertRaisesRegex( tempest_exceptions.Conflict, "One or more ports have an IP allocation from this subnet", self.subnets_client.delete_subnet, ipv4_subnet['id']) @decorators.attr(type='negative') def test_delete_ipv4_subnet_with_dualstack_port_neg(self): # Provision OpenStack network network = self.create_network() # When I create an IPv4 subnet ipv4_subnet = self.create_subnet(network) self.assertIsNotNone(ipv4_subnet) # And I create a port in the network port1 = self.create_port(network) self.assertIsNotNone(port1) # When I add an IPv6 subnet ipv6_subnet = self.create_subnet(network, ip_version=6, enable_dhcp=False, cleanup=False) self.assertIsNotNone(ipv6_subnet) # Then I can delete the IPv6 subnet self.subnets_client.delete_subnet(ipv6_subnet['id']) # When I add an IPv6 subnet ipv6_subnet = self.create_subnet(network, ip_version=6, enable_dhcp=False) self.assertIsNotNone(ipv6_subnet) # And I create a port in the network port2 = self.create_port(network) self.assertIsNotNone(port2) # Then I can't clean the subnet anymore self.assertRaisesRegex( tempest_exceptions.Conflict, "One or more ports have an IP allocation from this subnet", self.subnets_client.delete_subnet, ipv6_subnet['id']) ######################################## # IPv6 address formats ######################################## def test_create_subnet_invalid_ipv6_gateway_neg(self): invalid_ipv6 = [ ( # Reserved addresses # See https://www.iana.org/assignments/ # iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml "fe80:5f74:c4a5:b82e::/120", "fe80:5f74:c4a5:b82e::1", MSG_RESERVED_IPV6_ADDRESS % "fe80:5f74:c4a5:b82e::/120"), ( # Reserved addresses: 6to4 "2002:5f74:c4a5:b82e::/120", "2002:5f74:c4a5:b82e::1", (MSG_RESERVED_IPV6_ADDRESS % '2002:5f74:c4a5:b82e::/120') if Topology.is_v5 else MSG_INVALID_IPV6_NETMASK), ("2001:5f74:c4a5:b82e::/63", "2001:5f74:c4a5:b82e::1", MSG_INVALID_IPV6_NETMASK), ("::/0", "::1", "Invalid input for operation: 0 is not allowed as CIDR prefix " "length."), ("2001:5f74:c4a5:b82e::/64", "2001:5f74:c4a5:b82b:ffff:ffff:ffff:ffff", MSG_GATEWAY_NOT_IN_SUBNET_CIDR), # Gateway not valid on CIDR ("2001:5f74:c4a5:b82e::/64", "2001:5f74:c4a5:b82e::/128", MSG_GATEWAY_INVALID_IP_ADDRESS % "2001:5f74:c4a5:b82e::/128"), # Gateway should be single address ("2001:5f74:c4a5:b82e::/64", "2001:5f74:c4a5:b82e::ZZZZ", MSG_GATEWAY_INVALID_IP_ADDRESS % "2001:5f74:c4a5:b82e::ZZZZ"), # Gateway should be valid address ("2001:5f74:c4a5:b82e::/64", "169.172.0.0", MSG_INVALID_GATEWAY_FOR_IP_TYPE % "169.172.0.0"), # Gateway is an IPv4 address ] # Provision OpenStack network network = self.create_network() # When I create an IPv4 subnet ipv4_subnet = self.create_subnet(network) self.assertIsNotNone(ipv4_subnet) for ipv6_cidr, ipv6_gateway, msg in invalid_ipv6: self.assertRaisesRegex(tempest_exceptions.BadRequest, msg, self.create_subnet, network, ip_version=6, cidr=IPNetwork(ipv6_cidr), mask_bits=IPNetwork(ipv6_cidr).prefixlen, gateway=ipv6_gateway, enable_dhcp=False) def test_create_port_with_invalid_address_formats_neg(self): # Provision OpenStack network network = self.create_network() # When I create an IPv4 subnet ipv4_subnet = self.create_subnet(network) self.assertIsNotNone(ipv4_subnet) # When I add an IPv6 subnet ipv6_subnet = self.create_subnet( network, cidr=IPNetwork("2001:5f74:c4a5:b82e::/64"), mask_bits=64, ip_version=6, enable_dhcp=False) self.assertIsNotNone(ipv6_subnet) # noinspection PyPep8 invalid_ipv6 = [ ('::1', MSG_INVALID_IP_ADDRESS_FOR_SUBNET), # Loopback ('FE80::1', MSG_INVALID_IP_ADDRESS_FOR_SUBNET), # Link local address ("FF00:5f74:c4a5:b82e:ffff:ffff:ffff:ffff", MSG_INVALID_IP_ADDRESS_FOR_SUBNET), # multicast ('FF00::1', MSG_INVALID_IP_ADDRESS_FOR_SUBNET), # multicast address ('::1', MSG_INVALID_IP_ADDRESS_FOR_SUBNET), # not specified address ('::', MSG_INVALID_IP_ADDRESS_FOR_SUBNET), # empty address ("2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff", MSG_INVALID_IP_ADDRESS_FOR_SUBNET), # valid address, not in subnet ('', MSG_INVALID_INPUT_FOR_FIXED_IPS), # empty string ("2001:5f74:c4a5:b82e:ffff:ffff:ffff:ffff:ffff", MSG_INVALID_INPUT_FOR_FIXED_IPS), # invalid address, too much segments ("2001:5f74:c4a5:b82e:ffff:ffff:ffff", MSG_INVALID_INPUT_FOR_FIXED_IPS), # invalid address, seven segments ("2001;5f74.c4a5.b82e:ffff:ffff:ffff", MSG_INVALID_INPUT_FOR_FIXED_IPS), # invalid address, wrong characters ("2001:5f74:c4a5:b82e:100.12.13.1", MSG_INVALID_INPUT_FOR_FIXED_IPS ), # invalid fornmat: must have :: between hex and decimal part. ] for ipv6, msg in invalid_ipv6: port_args = { 'fixed_ips': [{ 'subnet_id': ipv4_subnet['id'], 'ip_address': IPNetwork(ipv4_subnet['cidr'])[+10] }, { 'subnet_id': ipv6_subnet['id'], 'ip_address': ipv6 }] } self.assertRaisesRegex(tempest_exceptions.BadRequest, msg % ipv6, self.create_port, network, **port_args) ########################################################################### # Update IPv6 subnet attributes - negative ########################################################################### def test_os_managed_dual_stack_subnet_update_neg(self): # Provision OpenStack network network = self.create_network() # When I create an IPv4 subnet ipv4_subnet = self.create_subnet(network, enable_dhcp=False) self.assertIsNotNone(ipv4_subnet) # When I add an IPv6 subnet ipv6_subnet = self.create_subnet(network, ip_version=6, enable_dhcp=False) self.assertIsNotNone(ipv6_subnet) self.assertRaisesRegex(tempest_exceptions.BadRequest, "Cannot update read-only attribute ip_version", self.update_subnet, ipv6_subnet, ip_version=4)
def _test_os_managed_subnet_ipv6_first(self, enable_dhcp=None): # Provision OpenStack network network = self.create_network() # Create an IPv6 subnet ipv6_subnet = self.create_subnet(network, ip_version=6, enable_dhcp=enable_dhcp, cleanup=False) # Verify L2Dom vsd_l2_domain = self.vsd.get_l2domain( vspk_filter='externalID == "{}"'.format( ExternalId(ipv6_subnet['network_id']).at_cms_id())) self.assertIsNotNone(vsd_l2_domain) filters = { 'device_owner': 'network:dhcp:nuage', 'network_id': network['id'] } self.assertEqual(vsd_l2_domain.ip_type, 'IPV6') dhcp_ports = self.ports_client.list_ports(**filters)['ports'] if Topology.has_dhcp_v6_support(): self.assertEqual(enable_dhcp, vsd_l2_domain.enable_dhcpv6) if enable_dhcp: self.assertEqual(1, len(dhcp_ports)) self.assertEqual(dhcp_ports[0]['fixed_ips'][0]['subnet_id'], ipv6_subnet['id']) else: self.assertEqual(0, len(dhcp_ports)) # Verify port/Vport portv6 = self.create_port(network, cleanup=False) self._verify_port(portv6, subnet6=ipv6_subnet) self._verify_vport_in_l2_domain(portv6, vsd_l2_domain) # Create an IPv4 subnet in the same network ipv4_subnet = self.create_subnet(network, enable_dhcp=enable_dhcp) # Verify the L2Dom is Dualstack now vsd_l2_domain = self.vsd.get_l2domain(by_subnet=ipv6_subnet) self.assertIsNotNone(vsd_l2_domain) self.assertEqual(vsd_l2_domain.ip_type, 'DUALSTACK') dhcp_ports = self.ports_client.list_ports(**filters)['ports'] if enable_dhcp: self.assertTrue(vsd_l2_domain.enable_dhcpv4) self.assertEqual(1, len(dhcp_ports)) self.assertEqual(dhcp_ports[0]['fixed_ips'][0]['subnet_id'], ipv4_subnet['id']) self.assertEqual(dhcp_ports[0]['fixed_ips'][1]['subnet_id'], ipv6_subnet['id']) else: self.assertFalse(vsd_l2_domain.enable_dhcpv4) self.assertEqual(0, len(dhcp_ports)) # Delete Subnet/Port self.delete_port(portv6) self.delete_subnet(ipv6_subnet) vsd_l2_domain = self.vsd.get_l2domain(by_subnet=ipv4_subnet) # Verify the L2Dom self.assertIsNotNone(vsd_l2_domain) self.assertEqual(vsd_l2_domain.ip_type, 'IPV4') self.assertFalse(vsd_l2_domain.enable_dhcpv6) if enable_dhcp: self.assertEqual(1, len(dhcp_ports)) self.assertEqual(dhcp_ports[0]['fixed_ips'][0]['subnet_id'], ipv4_subnet['id']) else: self.assertEqual(0, len(dhcp_ports))
def test_link_multi_l2domain_to_network_dualstack(self): net_name = data_utils.rand_name('multi-vsd-mgd-dualstack') network = self.create_network(network_name=net_name) vsd_l2domain_template1 = self.vsd_create_l2domain_template( ip_type="DUALSTACK", cidr4=IPNetwork('10.0.0.0/24'), cidr6=IPNetwork('cafe:babe::/64'), dhcp_managed=True, enable_dhcpv6=True ) vsd_l2domain1 = self.vsd_create_l2domain( template=vsd_l2domain_template1) vsd_l2domain_template2 = self.vsd_create_l2domain_template( ip_type="DUALSTACK", cidr4=IPNetwork('10.1.0.0/24'), cidr6=IPNetwork('cbfe:babe::/64'), dhcp_managed=True, enable_dhcpv6=True ) vsd_l2domain2 = self.vsd_create_l2domain( template=vsd_l2domain_template2) v4_1 = self.create_subnet( network, cidr=IPNetwork('10.0.0.0/24'), mask_bits=24, gateway=None, nuagenet=vsd_l2domain1.id, net_partition=Topology.def_netpartition) filters = { 'device_owner': 'network:dhcp:nuage', 'network_id': network['id'] } dhcp_ports = self.ports_client.list_ports(**filters)['ports'] self.assertEqual(1, len(dhcp_ports)) self.assertEqual(dhcp_ports[0]['fixed_ips'][0]['subnet_id'], v4_1['id']) self.assertEqual(dhcp_ports[0]['fixed_ips'][0]['ip_address'], vsd_l2domain1.gateway) v6_1 = self.create_subnet( network, ip_version=6, cidr=IPNetwork('cafe:babe::/64'), mask_bits=self.mask_bits6, nuagenet=vsd_l2domain1.id, net_partition=Topology.def_netpartition) if Topology.has_dhcp_v6_support(): dhcp_ports = self.ports_client.list_ports(**filters)['ports'] self.assertEqual(1, len(dhcp_ports)) self.assertEqual(dhcp_ports[0]['fixed_ips'][1]['subnet_id'], v6_1['id']) self.assertEqual(dhcp_ports[0]['fixed_ips'][1]['ip_address'], vsd_l2domain1.ipv6_gateway) if self.is_dhcp_agent_present(): self.assertRaises( exceptions.BadRequest, self.create_subnet, network, cidr=IPNetwork('10.1.0.0/24'), mask_bits=24, gateway=None, nuagenet=vsd_l2domain2.id, net_partition=Topology.def_netpartition) self.assertRaises( exceptions.BadRequest, self.create_subnet, network, ip_version=6, cidr=IPNetwork('cbfe:babe::/64'), mask_bits=64, nuagenet=vsd_l2domain2.id, net_partition=Topology.def_netpartition) else: v4_2 = self.create_subnet( network, cidr=IPNetwork('10.1.0.0/24'), mask_bits=24, gateway=None, nuagenet=vsd_l2domain2.id, net_partition=Topology.def_netpartition) if Topology.has_dhcp_v6_support(): dhcp_ports = self.ports_client.list_ports(**filters)['ports'] self.assertEqual(2, len(dhcp_ports)) for dhcp_port in dhcp_ports: if dhcp_port['fixed_ips'][0]['subnet_id'] == v4_2['id']: self.assertEqual( dhcp_port['fixed_ips'][0]['ip_address'], vsd_l2domain2.gateway) v6_2 = self.create_subnet( network, ip_version=6, cidr=IPNetwork('cbfe:babe::/64'), mask_bits=self.mask_bits6, nuagenet=vsd_l2domain2.id, net_partition=Topology.def_netpartition) if Topology.has_dhcp_v6_support(): dhcp_ports = self.ports_client.list_ports(**filters)['ports'] self.assertEqual(2, len(dhcp_ports)) for dhcp_port in dhcp_ports: if dhcp_port['fixed_ips'][1]['subnet_id'] == v6_2['id']: self.assertEqual( dhcp_port['fixed_ips'][1]['ip_address'], vsd_l2domain2.ipv6_gateway) # check ports # dualstack port of same l2domain kwargs = { 'fixed_ips': [{'subnet_id': v4_1['id']}, {'subnet_id': v6_1['id']}] } self.create_port(network, **kwargs) kwargs = { 'fixed_ips': [{'subnet_id': v4_2['id']}, {'subnet_id': v6_2['id']}] } self.create_port(network, **kwargs) kwargs = { 'fixed_ips': [{'subnet_id': v4_1['id']}, {'subnet_id': v6_2['id']}] } self.assertRaises( exceptions.BadRequest, self.create_port, network, **kwargs ) kwargs = { 'fixed_ips': [{'subnet_id': v6_1['id']}, {'subnet_id': v4_2['id']}] } self.assertRaises( exceptions.BadRequest, self.create_port, network, **kwargs )