class BaremetalTrunkTest(network_mixin.NetworkMixin, l3.L3Mixin,
                         sg_mixin.SGMixin):
    credentials = ['admin']
    personality = 'NUAGE_210_WBX_48_S'

    @classmethod
    def setUpClass(cls):
        super(BaremetalTrunkTest, cls).setUpClass()
        if (CONF.nuage_sut.nuage_baremetal_driver ==
                constants.BAREMETAL_DRIVER_BRIDGE):
            cls.expected_vport_type = constants.VPORT_TYPE_BRIDGE
        elif (CONF.nuage_sut.nuage_baremetal_driver ==
              constants.BAREMETAL_DRIVER_HOST):
            cls.expected_vport_type = constants.VPORT_TYPE_HOST
        else:
            raise Exception("Unexpected configuration of "
                            "'nuage_baremetal_driver'")
        cls.expected_vlan_normal = 0
        cls.expected_vlan_transparent = 4095

    @classmethod
    def skip_checks(cls):
        super(BaremetalTrunkTest, cls).skip_checks()
        if not CONF.service_available.neutron:
            # this check prevents this test to be run in unittests
            raise cls.skipException("Neutron support is required")

    @classmethod
    def setup_clients(cls):
        super(BaremetalTrunkTest, cls).setup_clients()
        cls.vsd_client = NuageRestClient()

    @classmethod
    def resource_setup(cls):
        super(BaremetalTrunkTest, cls).resource_setup()
        # Only gateway here, to support parallel testing each tests makes its
        # own gateway port so no VLAN overlap should occur.
        cls.gateway = cls.vsd_client.create_gateway(
            data_utils.rand_name(name='vsg'),
            data_utils.rand_name(name='sys_id'), cls.personality)[0]

    @classmethod
    def resource_cleanup(cls):
        super(BaremetalTrunkTest, cls).resource_cleanup()
        cls.vsd_client.delete_gateway(cls.gateway['ID'])

    def setUp(self):
        self.name = data_utils.rand_name("test_trunk_baremetal")
        super(BaremetalTrunkTest, self).setUp()
        gw_port_name = data_utils.rand_name(name='gw-port')
        self.gw_port = self.vsd_client.create_gateway_port(
            gw_port_name,
            gw_port_name,
            'ACCESS',
            self.gateway['ID'],
            extra_params={'VLANRange': '0-4095'})[0]
        self.parent_network = self.create_network(name="parent " + self.name)
        self.parent_subnet = self.create_subnet('10.20.30.0/24',
                                                self.parent_network['id'],
                                                name="parent " + self.name)
        self.security_group = self.create_security_group(name=self.name)
        self.binding_data = {
            'binding:host_id': 'dummy',
            'binding:profile': {
                "local_link_information": [{
                    "port_id":
                    self.gw_port['name'],
                    "switch_info":
                    self.gateway['systemID']
                }]
            }
        }
        self.unbinding_data = {
            'binding:host_id': None,
            'binding:profile': None,
            'device_owner': ''
        }

    def _get_vsd_vport(self, port, router, subnet):
        if router:
            parent_resource = constants.SUBNETWORK
        else:
            parent_resource = constants.L2_DOMAIN
        filters, filter_values = self.vsd_client.get_subnet_filters(subnet)
        vsd_vport_parent = self.vsd_client.get_global_resource(
            parent_resource, filters=filters, filter_values=filter_values)[0]
        vsd_vports = self.vsd_client.get_vport(parent_resource,
                                               vsd_vport_parent['ID'],
                                               filters='externalID',
                                               filter_values=port['id'])
        if vsd_vports:
            return vsd_vports[0]
        else:
            return None

    def _get_vsd_vlan(self, vport):
        vsd_vlan = self.vsd_client.get_bridge_port_gateway_vlan(vport)
        return vsd_vlan[0]

    @decorators.attr(type='smoke')
    def test_single_subport_l2(self):
        self._test_trunking(router=False, number_subports=1)

    def test_multiple_subports_l2(self):
        self._test_trunking(router=False, number_subports=2)

    @decorators.attr(type='smoke')
    def test_single_subport_l3(self):
        self._test_trunking(router=True, number_subports=1)

    def test_multiple_subport_l3(self):
        self._test_trunking(router=True, number_subports=2)

    @decorators.attr(type=['negative'])
    def test_single_subport_negative_same_vlan(self):
        self.assertRaises(exceptions.BadRequest,
                          self._test_trunking,
                          router=False,
                          number_subports=1,
                          segmentation_ids=[0])

    @decorators.attr(type=['negative'])
    @testtools.skipUnless(Topology.has_vlan_transparency_support(),
                          'Test skipped as no vlan transparency supported')
    def test_single_subport_negative_vlan_transparent(self):
        # the network of the parent port cannot be vlan transparent

        temp_network = self.parent_network
        temp_subnet = self.parent_subnet
        try:
            self.parent_network = self.create_network(name="vlan_transparent",
                                                      vlan_transparent=True)
            self.parent_subnet = self.create_subnet(
                '10.20.30.0/24',
                self.parent_network['id'],
                name="vlan_transparent parent")

            self.assertRaises(exceptions.BadRequest,
                              self._test_trunking,
                              router=False,
                              number_subports=1,
                              segmentation_ids=[0])
        finally:
            self.parent_network = temp_network
            self.parent_subnet = temp_subnet

    @decorators.attr(type=['negative'])
    def test_single_subport_negative_no_subnet(self):
        # Note: this test currently seems to fail at the wrong time
        # The parent port must have a fixed ip
        self.delete_subnet(self.parent_subnet['id'])
        try:
            self.assertRaises(exceptions.BadRequest,
                              self._test_trunking,
                              router=False,
                              number_subports=1,
                              segmentation_ids=[0])
        finally:
            self.parent_subnet = self.create_subnet('10.20.30.0/24',
                                                    self.parent_network['id'],
                                                    name="parent " + self.name)

    @decorators.attr(type=['negative'])
    def test_single_subport_negative_different_vnic(self):
        # A subport must have the same vnic type as the parent
        self.assertRaises(exceptions.Conflict,
                          self._test_trunking,
                          router=False,
                          number_subports=1,
                          vnic_type_sub='normal')

    @decorators.attr(type=['negative'])
    def test_single_subport_negative_same_network(self):
        # A subport cannot be on the same network as the parent port
        self.assertRaises(exceptions.Conflict,
                          self._test_trunking,
                          router=False,
                          number_subports=1,
                          create_subnets=False)

    def _test_trunking(self,
                       router,
                       number_subports,
                       segmentation_ids=None,
                       vnic_type_sub=None,
                       create_subnets=True):
        if router:
            router = self.create_router(name='router ' + self.name)
            self.add_router_interface(router['id'], self.parent_subnet['id'])
        create_data = {
            'security_groups': [self.security_group['id']],
            'binding:vnic_type': 'baremetal'
        }
        parent = self.create_port(self.parent_network['id'], **create_data)
        subports = []
        if vnic_type_sub:
            create_data['binding:vnic_type'] = vnic_type_sub
        for i in range(number_subports):
            if not create_subnets:
                network = self.parent_network
                subnet = self.parent_subnet
            else:
                network = self.create_network(name="sub " + self.name)
                subnet = self.create_subnet('11.21.31.0/24',
                                            network['id'],
                                            name="sub " + self.name)
            if router:
                router_sub = self.create_router(name='sub_router ' + self.name)
                self.add_router_interface(router_sub['id'], subnet['id'])
            else:
                router_sub = None
            port = self.create_port(network['id'], **create_data)
            if segmentation_ids:
                segmentation_id = segmentation_ids[i]
            else:
                segmentation_id = i + 10
            subports.append({
                'network': network,
                'subnet': subnet,
                'port': port,
                'segmentation_id': segmentation_id,
                'router': router_sub
            })
        create_data = {'name': self.name}
        trunk = self.create_trunk(parent_port_id=parent['id'],
                                  subports=None,
                                  **create_data)

        for i in range(number_subports):
            subport = {
                'port_id': subports[i]['port']['id'],
                'segmentation_type': 'vlan',
                'segmentation_id': subports[i]['segmentation_id']
            }
            self.add_subports(trunk['id'], [subport])
            self.assertEqual(
                'trunk:subport',
                self.get_port(subports[i]['port']['id'])['device_owner'])
            # Assert no resources have been created on VSD, unbound trunk!
            self.assertIsNone(
                self._get_vsd_vport(subports[i]['port'],
                                    router=router,
                                    subnet=subports[i]['subnet']))
        # Assert no resource has been created on VSD for parent, unbound trunk!
        self.assertIsNone(
            self._get_vsd_vport(parent,
                                router=router,
                                subnet=self.parent_subnet))

        # Bind trunk parent
        self.update_port(port_id=parent['id'], **self.binding_data)
        self.addCleanup(self.update_port,
                        port_id=parent['id'],
                        **self.unbinding_data)

        # Assert binding of parent and sub port
        self.assertEqual(self.binding_data['binding:host_id'],
                         self.get_port(parent['id'])['binding:host_id'])
        for i in range(number_subports):
            self.assertEqual(
                self.binding_data['binding:host_id'],
                self.get_port(subports[i]['port']['id'])['binding:host_id'])

        # Assert creation of vsd port
        parent_vsd = self._get_vsd_vport(parent,
                                         router=router,
                                         subnet=self.parent_subnet)
        self.assertIsNotNone(parent_vsd)
        for i in range(number_subports):
            sub_vsd = self._get_vsd_vport(subports[i]['port'],
                                          router=router,
                                          subnet=subports[i]['subnet'])
            self.assertIsNotNone(sub_vsd)
            self.assertEqual(subports[i]['segmentation_id'],
                             self._get_vsd_vlan(sub_vsd)['value'])

        # Check VLAN on VSD
        self.assertEqual(0, self._get_vsd_vlan(parent_vsd)['value'])
class BaremetalPortsTest(network_mixin.NetworkMixin, l3.L3Mixin,
                         sg_mixin.SGMixin):
    credentials = ['admin']
    personality = 'VSG'

    PG_NAME = (constants.NUAGE_PLCY_GRP_ALLOW_ALL_HW
               if Topology.has_unified_pg_for_all_support() else
               'PG_FOR_LESS_SECURITY')

    @classmethod
    def setUpClass(cls):
        super(BaremetalPortsTest, cls).setUpClass()
        if (CONF.nuage_sut.nuage_baremetal_driver ==
                constants.BAREMETAL_DRIVER_BRIDGE):
            cls.expected_vport_type = constants.VPORT_TYPE_BRIDGE
        elif (CONF.nuage_sut.nuage_baremetal_driver ==
              constants.BAREMETAL_DRIVER_HOST):
            cls.expected_vport_type = constants.VPORT_TYPE_HOST
        else:
            raise Exception("Unexpected configuration of "
                            "'nuage_baremetal_driver'")
        cls.expected_vlan_normal = 0
        cls.expected_vlan_transparent = 4095

    @classmethod
    def skip_checks(cls):
        super(BaremetalPortsTest, cls).skip_checks()
        if not CONF.service_available.neutron:
            # this check prevents this test to be run in unittests
            raise cls.skipException("Neutron support is required")

    @classmethod
    def setup_clients(cls):
        super(BaremetalPortsTest, cls).setup_clients()
        cls.vsd_client = NuageRestClient()

    @classmethod
    def resource_setup(cls):
        super(BaremetalPortsTest, cls).resource_setup()
        # Only gateway here, to support parallel testing each tests makes its
        # own gateway port so no VLAN overlap should occur.
        cls.gateway = cls.vsd_client.create_gateway(
            data_utils.rand_name(name='vsg'),
            data_utils.rand_name(name='sys_id'), cls.personality)[0]

    @classmethod
    def resource_cleanup(cls):
        super(BaremetalPortsTest, cls).resource_cleanup()
        cls.vsd_client.delete_gateway(cls.gateway['ID'])

    def setUp(self):
        super(BaremetalPortsTest, self).setUp()
        gw_port_name = data_utils.rand_name(name='gw-port')
        self.gw_port = self.vsd_client.create_gateway_port(
            gw_port_name,
            gw_port_name,
            'ACCESS',
            self.gateway['ID'],
            extra_params={'VLANRange': '0-4095'})[0]
        self.binding_data = {
            'binding:vnic_type': 'baremetal',
            'binding:host_id': 'dummy',
            'binding:profile': {
                "local_link_information": [{
                    "port_id":
                    self.gw_port['name'],
                    "switch_info":
                    self.gateway['systemID']
                }]
            }
        }
        gw_port_name1 = data_utils.rand_name(name='gw-port')
        self.gw_port1 = self.vsd_client.create_gateway_port(
            gw_port_name1,
            gw_port_name1,
            'ACCESS',
            self.gateway['ID'],
            extra_params={'VLANRange': '0-4095'})[0]
        self.binding_data1 = {
            'binding:vnic_type': 'baremetal',
            'binding:host_id': 'dummy',
            'binding:profile': {
                "local_link_information": [{
                    "port_id":
                    self.gw_port1['name'],
                    "switch_info":
                    self.gateway['systemID']
                }]
            }
        }

    def test_baremetal_port_l3_create(self):
        topology = self._create_topology(with_router=True)
        self._test_baremetal_port(topology, update=False)

    @testtools.skipUnless(Topology.has_vlan_transparency_support(),
                          'Test skipped as no vlan transparency supported')
    def test_baremetal_port_l3_create_vlan_transparent(self):
        topology = self._create_topology(with_router=True,
                                         vlan_transparent=True)
        self._test_baremetal_port(topology,
                                  update=False,
                                  vlan_transparent=True)

    @decorators.attr(type='smoke')
    def test_baremetal_port_l3_update(self):
        topology = self._create_topology(with_router=True)
        self._test_baremetal_port(topology, update=True)

    @testtools.skipUnless(Topology.has_vlan_transparency_support(),
                          'Test skipped as no vlan transparency supported')
    def test_baremetal_port_l3_update_vlan_transparent(self):
        topology = self._create_topology(with_router=True,
                                         vlan_transparent=True)
        self._test_baremetal_port(topology, update=True, vlan_transparent=True)

    @decorators.attr(type='smoke')
    def test_baremetal_port_l2_create(self):
        topology = self._create_topology(with_router=False)
        self._test_baremetal_port(topology, update=False)

    @decorators.attr(type='smoke')
    def test_baremetal_port_l2_create_vlan_transparent(self):
        topology = self._create_topology(with_router=False,
                                         vlan_transparent=True)
        self._test_baremetal_port(topology,
                                  update=False,
                                  vlan_transparent=True)

    def test_baremetal_port_l2_update(self):
        topology = self._create_topology(with_router=False)
        self._test_baremetal_port(topology, update=True)

    def test_baremetal_port_l2_update_vlan_transparent(self):
        topology = self._create_topology(with_router=False,
                                         vlan_transparent=True)
        self._test_baremetal_port(topology, update=True, vlan_transparent=True)

    @testtools.skip("Currently unknown how to trigger vport resolution")
    def test_router_attach(self):
        topology = self._create_topology(with_router=False)
        port = self.create_port(topology.network['id'], **self.binding_data)
        topology.baremetal_port = port
        with self.router(attached_subnets=[topology.subnet['id']]) as router:
            topology.router = router
            self._validate_vsd(topology)

    @testtools.skip("Currently not supported")
    def test_port_dhcp_opts_create(self):
        topology = self._create_topology()
        data = {
            'security_groups': [topology.security_group['id']],
            'extra_dhcp_opts': [{
                'opt_name': 'tftp-server',
                'opt_value': '192.168.0.3'
            }]
        }
        data.update(self.binding_data)
        baremetal_port = self.create_port(topology.network['id'], **data)
        # Workaround for https://bugs.launchpad.net/neutron/+bug/1698852
        topology.baremetal_port = self.get_port(baremetal_port['id'])
        self._validate_dhcp_option(topology)

    @testtools.skip("Currently not supported")
    def test_port_dhcp_opts_update(self):
        topology = self._create_topology()
        create_data = {'security_groups': [topology.security_group['id']]}
        create_data.update(self.binding_data)
        data = {
            'extra_dhcp_opts': [{
                'opt_name': 'tftp-server',
                'opt_value': '192.168.0.3'
            }]
        }
        baremetal_port = self.create_port(topology.network['id'],
                                          **create_data)
        baremetal_port = self.update_port(baremetal_port['id'], **data)
        topology.baremetal_port = baremetal_port
        self._validate_dhcp_option(topology)

    @decorators.attr(type='negative')
    def test_fail_create_with_default_sg(self):
        topology = self._create_topology()
        # Creating baremetal port with default sg should fail
        # as it has rules with remote-group-id
        self.assertRaises(lib_exc.BadRequest, self.create_port,
                          topology.network['id'], **self.binding_data)

    @decorators.attr(type='negative')
    def test_fail_create_with_sg_used_by_vm(self):
        topology = self._create_topology(with_router=True, with_port=True)
        # update a normal port with binding and sg
        # this will result in port binding
        data = {
            'security_groups': [topology.security_group['id']],
            'device_owner': 'compute:nova',
            'device_id': topology.normal_port['id'],
            'binding:host_id': 'dummy'
        }
        self.update_port(topology.normal_port['id'], **data)
        self.assertRaises(lib_exc.BadRequest, self.create_port,
                          topology.network['id'], **self.binding_data)
        data = {'security_groups': []}
        self.update_port(topology.normal_port['id'], **data)

    @decorators.attr(type='negative')
    def test_fail_create_with_non_existent_gw(self):
        topology = self._create_topology()
        data = {
            'security_groups': [topology.security_group['id']],
            'binding:vnic_type': 'baremetal',
            'binding:host_id': 'dummy',
            'binding:profile': {
                "local_link_information": [{
                    "port_id": self.gw_port['name'],
                    "switch_info": '123.123.123.123'
                }]
            }
        }
        self.assertRaises(lib_exc.BadRequest, self.create_port,
                          topology.network['id'], **data)

    @decorators.attr(type='negative')
    def test_fail_create_with_non_existent_port(self):
        topology = self._create_topology()
        data = {
            'security_groups': [topology.security_group['id']],
            'binding:vnic_type': 'baremetal',
            'binding:host_id': 'dummy',
            'binding:profile': {
                "local_link_information": [{
                    "port_id":
                    data_utils.rand_name(name='gw-port'),
                    "switch_info":
                    self.gateway['systemID']
                }]
            }
        }
        self.assertRaises(lib_exc.BadRequest, self.create_port,
                          topology.network['id'], **data)

    @decorators.attr(type='smoke')
    def test_l2_create_without_psec(self):
        topology = self._create_topology()
        create_data = {
            'port_security_enabled': False,
            'binding:vnic_type': 'baremetal',
            'binding:host_id': 'dummy',
            'binding:profile': {
                "local_link_information": [{
                    "port_id":
                    self.gw_port['name'],
                    "switch_info":
                    self.gateway['systemID']
                }]
            }
        }
        baremetal_port = self.create_port(topology.network['id'],
                                          **create_data)
        topology.baremetal_port = baremetal_port
        self._validate_baremetal_vport(topology)
        self._validate_vlan(topology, vlan_transparent=False)
        self._validate_interface(topology)
        if Topology.is_v5:
            self._validate_policygroup(topology, self.PG_NAME)
        else:
            # Add normal port and check there are two PG_ALLOW_ALL
            # (software and hardware)
            create_data = {'port_security_enabled': False}
            topology.normal_port = self.create_port(topology.network['id'],
                                                    **create_data)
            self._validate_policygroup(topology, pg_name=self.PG_NAME)
            create_data = {
                'port_security_enabled': False,
                'binding:vnic_type': 'baremetal',
                'binding:host_id': 'dummy',
                'binding:profile': {
                    "local_link_information": [{
                        "port_id":
                        self.gw_port1['name'],
                        "switch_info":
                        self.gateway['systemID']
                    }]
                }
            }
            topology.baremetal_port = self.create_port(topology.network['id'],
                                                       **create_data)
            self._validate_policygroup(topology,
                                       pg_name=self.PG_NAME,
                                       vport_num=2)

    @decorators.attr(type='smoke')
    def test_l2_update_without_psec(self):
        topology = self._create_topology()
        create_data = {
            'port_security_enabled': False,
            'binding:vnic_type': 'baremetal',
        }
        baremetal_port = self.create_port(topology.network['id'],
                                          **create_data)
        update_data = {
            'binding:host_id': 'dummy',
            'binding:profile': {
                "local_link_information": [{
                    "port_id":
                    self.gw_port['name'],
                    "switch_info":
                    self.gateway['systemID']
                }]
            }
        }
        baremetal_port = self.update_port(baremetal_port['id'], **update_data)
        topology.baremetal_port = baremetal_port
        self._validate_baremetal_vport(topology)
        self._validate_vlan(topology, vlan_transparent=False)
        self._validate_interface(topology)
        self._validate_policygroup(topology, pg_name=self.PG_NAME)

    @testtools.skipIf(Topology.is_v5,
                      'Skipping in 5.x - test was added for refactored '
                      'PG_FOR_LESS_SECURITY and sriov defaultPG in 6.0')
    @decorators.attr(type='smoke')
    def test_l3_create_without_psec(self):
        topology = self._create_topology(with_router=True)
        create_data = {
            'port_security_enabled': False,
            'binding:vnic_type': 'baremetal',
            'binding:host_id': 'dummy',
            'binding:profile': {
                "local_link_information": [{
                    "port_id":
                    self.gw_port['name'],
                    "switch_info":
                    self.gateway['systemID']
                }]
            }
        }
        baremetal_port = self.create_port(topology.network['id'],
                                          **create_data)
        topology.baremetal_port = baremetal_port
        self._validate_baremetal_vport(topology)
        self._validate_vlan(topology, vlan_transparent=False)
        self._validate_interface(topology)
        # Add normal port and check there are two PG_ALLOW_ALL
        # (software and hardware)
        create_data = {'port_security_enabled': False}
        topology.normal_port = self.create_port(topology.network['id'],
                                                **create_data)
        self._validate_policygroup(
            topology, pg_name=constants.NUAGE_PLCY_GRP_ALLOW_ALL_HW)
        create_data = {
            'port_security_enabled': False,
            'binding:vnic_type': 'baremetal',
            'binding:host_id': 'dummy',
            'binding:profile': {
                "local_link_information": [{
                    "port_id":
                    self.gw_port1['name'],
                    "switch_info":
                    self.gateway['systemID']
                }]
            }
        }
        topology.baremetal_port = self.create_port(topology.network['id'],
                                                   **create_data)
        self._validate_policygroup(
            topology,
            pg_name=constants.NUAGE_PLCY_GRP_ALLOW_ALL_HW,
            vport_num=2)

    @testtools.skipIf(Topology.is_v5,
                      'Skipping in 5.x - test was added for refactored '
                      'PG_FOR_LESS_SECURITY and sriov defaultPG in 6.0')
    @decorators.attr(type='smoke')
    def test_l3_update_without_psec(self):
        topology = self._create_topology(with_router=True)
        create_data = {
            'port_security_enabled': False,
            'binding:vnic_type': 'baremetal',
        }
        baremetal_port = self.create_port(topology.network['id'],
                                          **create_data)
        update_data = {
            'binding:host_id': 'dummy',
            'binding:profile': {
                "local_link_information": [{
                    "port_id":
                    self.gw_port['name'],
                    "switch_info":
                    self.gateway['systemID']
                }]
            }
        }
        baremetal_port = self.update_port(baremetal_port['id'], **update_data)
        topology.baremetal_port = baremetal_port
        self._validate_baremetal_vport(topology)
        self._validate_vlan(topology, vlan_transparent=False)
        self._validate_interface(topology)
        self._validate_policygroup(
            topology, pg_name=constants.NUAGE_PLCY_GRP_ALLOW_ALL_HW)

    def _create_topology(self,
                         with_router=False,
                         with_port=False,
                         vlan_transparent=False,
                         with_security_group=True):
        router = port = security_group = None
        if with_router:
            router = self.create_router()
        if vlan_transparent:
            network = self.create_network(vlan_transparent=True)
        else:
            network = self.create_network()
        subnet = self.create_subnet('10.20.30.0/24', network['id'])
        if with_router:
            self.add_router_interface(router['id'], subnet_id=subnet['id'])
        if with_port:
            port = self.create_port(network['id'])
        if with_security_group:
            security_group = self.create_security_group()
        return BaremetalTopology(self.vsd_client, network, subnet, router,
                                 port, security_group)

    def _test_baremetal_port(self,
                             topology,
                             update=False,
                             vlan_transparent=False):
        create_data = {'security_groups': [topology.security_group['id']]}
        if not update:
            create_data.update(self.binding_data)

        with self.port(topology.network['id'], **create_data) as bm_port:
            topology.baremetal_port = bm_port
            if update:
                self.update_port(bm_port['id'],
                                 as_admin=True,
                                 **self.binding_data)
            self._validate_vsd(topology, vlan_transparent=vlan_transparent)

    # Validation part

    def _validate_vsd(self, topology, vlan_transparent=False):
        self._validate_baremetal_vport(topology)
        self._validate_vlan(topology, vlan_transparent=vlan_transparent)
        self._validate_interface(topology)
        self._validate_policygroup(topology)

    def _validate_baremetal_vport(self, topology):
        self.assertThat(topology.vsd_baremetal_vport['type'],
                        matchers.Equals(self.expected_vport_type),
                        message="Vport has wrong type")

    def _validate_vlan(self, topology, vlan_transparent=False):
        vsd_vlan = self.vsd_client.get_gateway_vlan_by_id(
            topology.vsd_baremetal_vport['VLANID'])
        if vlan_transparent:
            self.assertThat(vsd_vlan['value'],
                            matchers.Equals(self.expected_vlan_transparent),
                            message="Vport has unexpected vlan")
        else:
            self.assertThat(vsd_vlan['value'],
                            matchers.Equals(self.expected_vlan_normal),
                            message="Vport has unexpected vlan")

    def _validate_interface(self, topology):
        vsd_vport = topology.vsd_baremetal_vport
        neutron_port = topology.baremetal_port

        if vsd_vport['type'] == constants.VPORT_TYPE_HOST:
            self.assertThat(topology.vsd_baremetal_interface['MAC'],
                            matchers.Equals(neutron_port['mac_address']))
            self.assertThat(
                topology.vsd_baremetal_interface['IPAddress'],
                matchers.Equals(neutron_port['fixed_ips'][0]['ip_address']))

    def _validate_policygroup(self, topology, pg_name=None, vport_num=1):
        if topology.normal_port is not None or self.is_dhcp_agent_present():
            expected_pgs = 2  # Expecting software + hardware
        else:
            expected_pgs = 1  # Expecting only hardware

        if not Topology.has_unified_pg_for_all_support():
            if self.is_dhcp_agent_present():
                expected_pgs += 1  # Extra PG for dhcp agent

                # Repeated check in case of agent
                for attempt in range(Topology.nbr_retries_for_test_robustness):
                    if len(topology.get_vsd_policygroups(
                            True)) == expected_pgs:
                        break
                    else:
                        LOG.error("Unexpected amount of PGs found, "
                                  "expected {} found {} "
                                  "(attempt {})".format(
                                      expected_pgs,
                                      len(topology.vsd_policygroups),
                                      attempt + 1))
                        time.sleep(1)

        self.assertThat(topology.get_vsd_policygroups(True),
                        matchers.HasLength(expected_pgs),
                        message="Unexpected amount of PGs found")
        for pg in topology.vsd_policygroups:
            if pg['type'] == 'HARDWARE':
                vsd_policygroup = pg
                break
        else:
            self.fail("Could not find HARDWARE policy group.")
        self.assertThat(vsd_policygroup['type'], matchers.Equals('HARDWARE'))
        if Topology.has_unified_pg_for_all_support():
            if pg_name:
                self.assertEqual(pg_name, vsd_policygroup['name'])
                self.assertEqual(pg_name, vsd_policygroup['description'])
                self.assertEqual(
                    "hw:" + (ExternalId(
                        constants.NUAGE_PLCY_GRP_ALLOW_ALL).at_cms_id()),
                    vsd_policygroup['externalID'])
            else:
                self.assertEqual(topology.security_group['id'] + "_HARDWARE",
                                 vsd_policygroup['name'])
                self.assertEqual(topology.security_group['name'],
                                 vsd_policygroup['description'])
                self.assertEqual(
                    "hw:" +
                    (ExternalId(topology.security_group['id']).at_cms_id()),
                    vsd_policygroup['externalID'])

            vsd_pg_vports = self.vsd_client.get_vport(constants.POLICYGROUP,
                                                      vsd_policygroup['ID'])
            self.assertThat(vsd_pg_vports,
                            matchers.HasLength(vport_num),
                            message="Expected to find exactly {} "
                            "vport in PG".format(vport_num))
            for vsd_pg_vport in vsd_pg_vports:
                if vsd_pg_vport['ID'] == topology.vsd_baremetal_vport['ID']:
                    break
            else:
                self.fail("Vport should be part of HARDWARE PG")
        else:
            if pg_name:
                self.assertThat(vsd_policygroup['name'],
                                matchers.Contains(pg_name))

            vsd_pg_vports = self.vsd_client.get_vport(constants.POLICYGROUP,
                                                      vsd_policygroup['ID'])
            self.assertThat(vsd_pg_vports,
                            matchers.HasLength(1),
                            message="Expected to find exactly 1 vport in PG")
            self.assertThat(vsd_pg_vports[0]['ID'],
                            matchers.Equals(
                                topology.vsd_baremetal_vport['ID']),
                            message="Vport should be part of HARDWARE PG")

    def _validate_interconnect(self, topology):
        self.assertThat(topology.vsd_policygroups,
                        matchers.HasLength(2),
                        message="Expected 2 PGs: 1 hardware, 1 software")
        vsd_policygroups = {pg['type']: pg for pg in topology.vsd_policygroups}
        egress_entries = topology.vsd_egress_acl_entries
        for rule in egress_entries:
            if (rule['locationID'] == vsd_policygroups['SOFTWARE']['ID'] and
                    rule['networkID'] == vsd_policygroups['HARDWARE']['ID']):
                break
        else:
            self.fail("Could not find interlink egress rule.")

    def _validate_dhcp_option(self, topology):
        self.assertThat(topology.vsd_baremetal_dhcp_opts,
                        matchers.HasLength(2))

        DHCP_ROUTER_OPT = 3
        DHCP_SERVER_NAME_OPT = 66
        for dhcp_opt in topology.vsd_baremetal_dhcp_opts:
            if dhcp_opt['actualType'] == DHCP_ROUTER_OPT:
                self.assertThat(dhcp_opt['actualValues'][0],
                                matchers.Equals(topology.subnet['gateway_ip']))
            elif dhcp_opt['actualType'] == DHCP_SERVER_NAME_OPT:
                os_dhcp_opt = topology.baremetal_port['extra_dhcp_opts'][0]
                self.assertThat(dhcp_opt['actualValues'][0],
                                matchers.Equals(os_dhcp_opt['opt_value']))
示例#3
0
class VlanTransparentConnectivityTest(NuageBaseTest):

    default_prepare_for_connectivity = True

    @classmethod
    def setup_clients(cls):
        super(VlanTransparentConnectivityTest, cls).setup_clients()
        cls.nuage_client = NuageRestClient()
        cls.client = NuageNetworkClientJSON(cls.os_primary.auth_provider,
                                            **cls.os_primary.default_params)

    @testtools.skipUnless(CONF.nuage_sut.image_is_advanced,
                          "Advanced image is required to run this test.")
    def test_l2_transparent_network(self):
        kwargs = {'vlan_transparent': 'true'}
        network = self.create_network(**kwargs)
        self.create_subnet(network, gateway=None)

        # create open-ssh security group
        ssh_security_group = self.create_open_ssh_security_group()

        # Launch tenant servers in OpenStack network
        vm1 = self.create_tenant_server([network],
                                        security_groups=[ssh_security_group],
                                        prepare_for_connectivity=True)
        vm2 = self.create_tenant_server([network],
                                        security_groups=[ssh_security_group],
                                        prepare_for_connectivity=True)

        vm1_ip = '13.13.13.13/24'
        vm2_ip = '13.13.13.14/24'
        ping_tgt = IPNetwork(vm2_ip)

        vm1.configure_vlan_interface(vm1_ip, 'eth1', vlan='10')
        vm2.configure_vlan_interface(vm2_ip, 'eth1', vlan='10')

        self.assert_ping(vm1,
                         vm2,
                         network,
                         address=str(ping_tgt.ip),
                         interface='eth1.10')

    @testtools.skipUnless(Topology.has_vlan_transparency_support(),
                          'Test skipped as no vlan transparency supported')
    @skip_because(bug='OPENSTACK-2325')
    def test_l3_transparent_network(self):
        kwargs = {'vlan_transparent': 'true'}
        router = self.create_public_router()
        network = self.create_network(**kwargs)
        subnet = self.create_subnet(network)
        self.router_attach(router, subnet)

        # create open-ssh security group
        ssh_security_group = self.create_open_ssh_security_group()

        vm1 = self.create_tenant_server([network],
                                        security_groups=[ssh_security_group],
                                        prepare_for_connectivity=True)

        vm2 = self.create_tenant_server([network],
                                        security_groups=[ssh_security_group],
                                        prepare_for_connectivity=True)

        vm1_ip = '13.13.13.13/24'
        vm2_ip = '13.13.13.14/24'
        ping_tgt = IPNetwork(vm2_ip)

        vm1.configure_vlan_interface(vm1_ip, 'eth0', vlan='10')
        vm2.configure_vlan_interface(vm2_ip, 'eth0', vlan='10')

        self.assert_ping(vm1,
                         vm2,
                         network,
                         address=str(ping_tgt.ip),
                         interface='eth0.10')