コード例 #1
0
class TestNeutronDriver(unittest.TestCase):

    def setUp(self):
        self.neutron_client = mock.MagicMock()
        self.network = network_response
        self.ports = port_response
        self.neutron_client.list_networks.return_value = self.network
        self.neutron_client.list_ports.return_value = self.ports
        self.driver = NeutronDriver(poll_time=0)

    def test_list_networks(self):
        """Test conversion of complex network objects to tables."""
        network_list = self.neutron_client.list_networks()
        network_tuple_list = \
            self.driver._get_tuple_list(network_list,
                                        self.driver.NEUTRON_NETWORKS)
        network_tuple = network_tuple_list[0]
        network_subnet_tuples = self.driver.network_subnet

        self.assertIsNotNone(network_tuple_list)
        self.assertEquals(1, len(network_tuple_list))
        self.assertEquals(1, len(network_subnet_tuples))

        key_to_index = self.driver.network_key_position_map()
        logging.info("key_to_index: " + str(key_to_index))
        logging.info("network: " + str(network_tuple))
        subnet_tuple_guid = network_tuple[key_to_index['subnets']]

        guid_key = network_subnet_tuples[0][0]
        guid_value = network_subnet_tuples[0][1]

        name = network_tuple[key_to_index['name']]
        status = network_tuple[key_to_index['status']]
        provider_physical_network = \
            network_tuple[key_to_index['provider:physical_network']]
        admin_state_up = network_tuple[key_to_index['admin_state_up']]
        tenant_id = network_tuple[key_to_index['tenant_id']]
        provider_network_type = \
            network_tuple[key_to_index['provider:network_type']]
        router_external = network_tuple[key_to_index['router:external']]
        shared = network_tuple[key_to_index['shared']]
        id = network_tuple[key_to_index['id']]
        provider_segmentation_id = \
            network_tuple[key_to_index['provider:segmentation_id']]

        self.assertEquals('ACTIVE', status)
        self.assertIsNotNone(subnet_tuple_guid)
        self.assertEqual(guid_key, subnet_tuple_guid)
        self.assertEqual('4cef03d0-1d02-40bb-8c99-2f442aac6ab0',
                         guid_value)
        self.assertEquals('test-network',
                          name)
        self.assertEquals('None', provider_physical_network)
        self.assertEquals('True', admin_state_up)
        self.assertEquals('570fe78a1dc54cffa053bd802984ede2',
                          tenant_id)
        self.assertEquals('gre', provider_network_type)
        self.assertEquals('False', router_external)
        self.assertEquals('False', shared)
        self.assertEquals('240ff9df-df35-43ae-9df5-27fae87f2492',
                          id)
        self.assertEquals(4, provider_segmentation_id)

    def test_list_ports(self):
        """Test conversion of complex port objects to tuples."""
        port_list = self.neutron_client.list_ports()
        port_tuple_list = \
            self.driver._get_tuple_list(port_list,
                                        self.driver.NEUTRON_PORTS)
        self.port_address_pairs = self.driver.port_address_pairs

        self.port_security_groups = self.driver.port_security_groups
        self.port_binding_capabilities = self.driver.port_binding_capabilities
        self.port_extra_dhcp_opts = self.driver.port_extra_dhcp_opts
        self.port_fixed_ips = self.driver.port_fixed_ips
        self.assertIsNotNone(port_tuple_list)
        self.assertEquals(1, len(port_tuple_list))

        # Input
        # [{"status": "ACTIVE",'+
        #    '"binding:host_id": "havana", "name": "",' +
        #    '"allowed_address_pairs": [],'+
        #    '"admin_state_up": True, ' +
        #    '"network_id": "240ff9df-df35-43ae-9df5-27fae87f2492",'+
        #    '"tenant_id": "570fe78a1dc54cffa053bd802984ede2",
        #     "extra_dhcp_opts": [],'+
        #    '"binding:vif_type": "ovs",' +
        #    '"device_owner": "network:router_interface",'+
        #    '"binding:capabilities": {"port_filter": True},' +
        #    '"mac_address": "fa:16:3e:ab:90:df",'+
        #    '"fixed_ips": [{"subnet_id":
        #    "4cef03d0-1d02-40bb-8c99-2f442aac6ab0",' +
        #    '"ip_address":"90.0.0.1"}],'+
        #    '"id": "0a2ce569-85a8-45ec-abb3-0d4b34ff69ba",
        #     "security_groups": [],'+
        #    '"device_id": "864e4acf-bf8e-4664-8cf7-ad5daa95681e"}]}')

        # Output
        # [('ACTIVE', 'havana', '', '90a579ea-ea45-11e3-a085-000c292422e8',
        #   'True',
        #   '240ff9df-df35-43ae-9df5-27fae87f2492',
        #   '570fe78a1dc54cffa053bd802984ede2',
        #   '90a5b5a4-ea45-11e3-a085-000c292422e8', 'ovs',
        #   'network:router_interface',
        #   '90a5f564-ea45-11e3-a085-000c292422e8', 'fa:16:3e:ab:90:df',
        #   '90a63222-ea45-11e3-a085-000c292422e8',
        #   '0a2ce569-85a8-45ec-abb3-0d4b34ff69ba',
        #   '90a6397a-ea45-11e3-a085-000c292422e8',
        #   '864e4acf-bf8e-4664-8cf7-ad5daa95681e')]

        status = port_tuple_list[0][0]
        binding_host_id = port_tuple_list[0][1]
        name = port_tuple_list[0][2]

        guid_allowed_address_pairs = port_tuple_list[0][3]
        guid_allowed_address_pairs_expected = self.port_address_pairs[0]

        admin_state_up = port_tuple_list[0][4]
        network_id = port_tuple_list[0][5]
        tenant_id = port_tuple_list[0][6]
        guid_extra_dhcp_opts = port_tuple_list[0][7]
        guid_extra_dhcp_opts_expected = self.port_extra_dhcp_opts[0][0]
        extra_dhcp_opts_value_actual = self.port_extra_dhcp_opts[0][1]

        binding_vif_type = port_tuple_list[0][8]
        device_owner = port_tuple_list[0][9]

        guid_binding_capabilities = port_tuple_list[0][10]
        guid_binding_capabilities_expected = \
            self.port_binding_capabilities[0][0]
        binding_capabilities_key_actual = self.port_binding_capabilities[0][1]
        binding_capabilities_value_actual = \
            self.port_binding_capabilities[0][2]

        mac_address = port_tuple_list[0][11]
        guid_fixed_ips = port_tuple_list[0][12]
        guid_fixed_ips_expected = self.port_fixed_ips[0][0]
        fixed_ips_key_one = self.port_fixed_ips[0][1]
        fixed_ips_value_one = self.port_fixed_ips[0][2]
        fixed_ips_key_two = self.port_fixed_ips[1][1]
        fixed_ips_value_two = self.port_fixed_ips[1][2]

        id = port_tuple_list[0][13]
        guid_security_groups = port_tuple_list[0][14]
        guid_security_groups_expected = self.port_security_groups[0][0]
        security_groups_value = self.port_security_groups[0][1]
        device_id = port_tuple_list[0][15]

        self.assertEqual('ACTIVE', status)
        self.assertEqual('havana', binding_host_id)
        self.assertEqual('', name)
        self.assertEqual(guid_allowed_address_pairs_expected[0],
                         guid_allowed_address_pairs)

        self.assertEqual(1, len(self.port_address_pairs))
        self.assertEqual('', self.port_address_pairs[0][1])
        self.assertEqual('True', admin_state_up)
        self.assertEqual('240ff9df-df35-43ae-9df5-27fae87f2492', network_id)
        self.assertEqual('570fe78a1dc54cffa053bd802984ede2', tenant_id)

        self.assertEqual(guid_extra_dhcp_opts_expected, guid_extra_dhcp_opts)
        self.assertEqual(1, len(self.port_extra_dhcp_opts))
        self.assertEqual('', extra_dhcp_opts_value_actual)

        self.assertEqual(guid_binding_capabilities_expected,
                         guid_binding_capabilities)
        self.assertEqual(1, len(self.port_binding_capabilities))
        self.assertEqual('port_filter', binding_capabilities_key_actual)
        self.assertEqual('True', binding_capabilities_value_actual)

        self.assertEqual('ovs', binding_vif_type)
        self.assertEqual('network:router_interface', device_owner)

        #    '"fixed_ips": [{"subnet_id":
        #    "4cef03d0-1d02-40bb-8c99-2f442aac6ab0",' +
        #    '"ip_address":"90.0.0.1"}],'+
        self.assertEqual(guid_fixed_ips_expected, guid_fixed_ips)
        self.assertEqual(2, len(self.port_fixed_ips))
        self.assertEqual('subnet_id', fixed_ips_key_one)
        self.assertEqual('4cef03d0-1d02-40bb-8c99-2f442aac6ab0',
                         fixed_ips_value_one)
        self.assertEqual('ip_address', fixed_ips_key_two)
        self.assertEqual('90.0.0.1', fixed_ips_value_two)

        self.assertEqual('fa:16:3e:ab:90:df', mac_address)
        self.assertEqual('0a2ce569-85a8-45ec-abb3-0d4b34ff69ba', id)

        self.assertEqual(guid_security_groups_expected,
                         guid_security_groups)
        self.assertEqual(1, len(self.port_security_groups))
        self.assertEqual('', security_groups_value)

        self.assertEqual('864e4acf-bf8e-4664-8cf7-ad5daa95681e', device_id)

    #### Tests for DataSourceDriver
    # Note: these tests are really testing the functionality of the class
    #  DataSourceDriver, but it's useful to use an actual subclass so
    #  we can test the functionality end-to-end.  We use Neutron for
    #  that subclass.  Leaving it in this file so that it is clear
    #  that when the Neutron driver changes, these tests may need
    #  to change as well.  Tried to minimize the number of changes
    #  necessary.

    def setup_polling(self, debug_mode=False):
        """Setup polling tests."""
        cage = congress.dse.d6cage.d6Cage()
        # so that we exit once test finishes; all other threads are forced
        #    to be daemons
        cage.daemon = True
        cage.start()

        # Create mock of Neutron client so we can control data
        mock_factory = mox.Mox()
        neutron_client = mock_factory.CreateMock(
            neutronclient.v2_0.client.Client)
        neutron_client.list_networks().InAnyOrder(1).AndReturn(network1)
        neutron_client.list_ports().InAnyOrder(1).AndReturn(port_response)
        neutron_client.list_networks().InAnyOrder(2).AndReturn(network2)
        neutron_client.list_ports().InAnyOrder(2).AndReturn(port_response)
        mock_factory.ReplayAll()

        # Create modules (without auto-polling)
        cage.loadModule("NeutronDriver",
                        helper.data_module_path("neutron_driver.py"))
        cage.loadModule("PolicyDriver", helper.policy_module_path())
        cage.createservice(name="policy", moduleName="PolicyDriver")
        cage.createservice(name="neutron", moduleName="NeutronDriver",
                           args={'poll_time': 0,
                                 'client': neutron_client})
        policy = cage.service_object('policy')

        # Make it so that we get detailed info from policy engine
        if debug_mode:
            policy.debug_mode()

        # insert rule into policy to make testing easier.
        #   (Some of the IDs are auto-generated each time we convert)
        policy.insert(create_network_group('p'))

        # create some garbage data
        network_key_to_index = NeutronDriver.network_key_position_map()
        network_max_index = max(network_key_to_index.values())
        args1 = ['1'] * (network_max_index + 1)
        args2 = ['2'] * (network_max_index + 1)
        args1 = ",".join(args1)
        args2 = ",".join(args2)
        fake_networks = [
            'neutron:networks({})'.format(args1),
            'neutron:networks({})'.format(args2)]

        # answer to query above for network1
        datalog1 = \
            ('p("240ff9df-df35-43ae-9df5-27fae87f2492") '
             'p("340ff9df-df35-43ae-9df5-27fae87f2492") '
             'p("440ff9df-df35-43ae-9df5-27fae87f2492")')

        # answer to query above for network2
        datalog2 = \
            ('p("240ff9df-df35-43ae-9df5-27fae87f2492") '
             'p("640ff9df-df35-43ae-9df5-27fae87f2492") '
             'p("540ff9df-df35-43ae-9df5-27fae87f2492")')

        # return value
        d = {}
        d['cage'] = cage
        d['datalog1'] = datalog1
        d['datalog2'] = datalog2
        d['fake_networks'] = fake_networks
        return d

    def test_subscribe_poll(self):
        """Test subscribing before polling.  The common case."""
        info = self.setup_polling()
        cage = info['cage']
        policy = cage.service_object('policy')
        neutron = cage.service_object('neutron')
        datalog1 = info['datalog1']
        datalog2 = info['datalog2']

        # subscribe
        policy.subscribe('neutron', 'networks', callback=policy.receive_data)
        helper.pause()  # so that subscription messages are processed

        # poll 1
        neutron.poll()
        helper.pause()  # so that data updates are processed
        e = helper.db_equal(policy.select('p(x)'), datalog1)
        self.assertTrue(e, 'Neutron insertion 1')

        # poll 2
        neutron.poll()
        helper.pause()
        e = helper.db_equal(policy.select('p(x)'), datalog2)
        self.assertTrue(e, 'Neutron insertion 2')

    def test_policy_initialization(self):
        """Test subscribing before polling.  The common case."""
        info = self.setup_polling()
        cage = info['cage']
        policy = cage.service_object('policy')
        neutron = cage.service_object('neutron')
        datalog1 = info['datalog1']
        fake_networks = info['fake_networks']

        # add garbage to policy
        for formula in fake_networks:
            logging.debug("Inserting fake_network: " + str(formula))
            policy.insert(formula)

        # subscribe
        policy.subscribe('neutron', 'networks', callback=policy.receive_data)
        helper.pause()  # so that subscription messages are processed

        # poll 1
        neutron.poll()
        helper.pause()  # so that data updates are processed
        e = helper.db_equal(policy.select('p(x)'), datalog1)
        self.assertTrue(e, 'Neutron insertion 1')

    def test_poll_subscribe(self):
        """Test polling before subscribing."""
        info = self.setup_polling()
        cage = info['cage']
        policy = cage.service_object('policy')
        neutron = cage.service_object('neutron')
        datalog1 = info['datalog1']
        datalog2 = info['datalog2']
        fake_networks = info['fake_networks']

        # add garbage to policy
        for formula in fake_networks:
            logging.debug("Inserting fake_network: " + str(formula))
            policy.insert(formula)

        # poll 1 and then subscribe; should still see first result
        neutron.poll()
        helper.pause()  # so that data is sent
        policy.subscribe('neutron', 'networks', callback=policy.receive_data)
        helper.pause()  # so that data updates are processed
        e = helper.db_equal(policy.select('p(x)'), datalog1)
        self.assertTrue(e, 'Neutron insertion 1')

        # poll 2
        neutron.poll()
        helper.pause()
        e = helper.db_equal(policy.select('p(x)'), datalog2)
        self.assertTrue(e, 'Neutron insertion 2')

    def test_double_poll_subscribe(self):
        """Test double polling before subscribing."""
        info = self.setup_polling()
        cage = info['cage']
        policy = cage.service_object('policy')
        neutron = cage.service_object('neutron')
        datalog2 = info['datalog2']

        # poll twice and then subscribe: should see 2nd result
        neutron.poll()
        helper.pause()
        neutron.poll()
        helper.pause()
        policy.subscribe('neutron', 'networks', callback=policy.receive_data)
        helper.pause()  # so that messages are processed
        e = helper.db_equal(policy.select('p(x)'), datalog2)
        self.assertTrue(e, 'Neutron insertion 2')

    def test_policy_recovery(self):
        """Test policy crashing and recovering (sort of)."""
        info = self.setup_polling()
        cage = info['cage']
        policy = cage.service_object('policy')
        neutron = cage.service_object('neutron')
        datalog1 = info['datalog1']

        # get initial data
        policy.subscribe('neutron', 'networks', callback=policy.receive_data)
        helper.pause()
        neutron.poll()
        helper.pause()
        e = helper.db_equal(policy.select('p(x)'), datalog1)
        self.assertTrue(e, 'Neutron insertion 1')

        # clear out policy's neutron:networks data (to simulate crashing)
        policy.initialize(['neutron:networks'], [])
        # subscribe again (without unsubscribing)
        policy.subscribe('neutron', 'networks', callback=policy.receive_data)
        helper.pause()
        # should get same data
        e = helper.db_equal(policy.select('p(x)'), datalog1)
        self.assertTrue(e, 'Neutron insertion 1')