def test_distributed_lock(self):
        row_event = DistributedLockTestEvent()
        self.mech_driver._nb_ovn.idl.notify_handler.watch_event(row_event)
        worker_list = [self.mech_driver._nb_ovn, ]

        # Create 10 fake workers
        for _ in range(10):
            node_uuid = uuidutils.generate_uuid()
            db_hash_ring.add_node(node_uuid)
            fake_driver = mock.MagicMock(node_uuid=node_uuid)
            _idl = ovsdb_monitor.OvnNbIdl.from_server(
                self.ovsdb_server_mgr.get_ovsdb_connection_path(),
                'OVN_Northbound', fake_driver)
            worker = self.useFixture(
                base.ConnectionFixture(idl=_idl, timeout=10)).connection
            worker.idl.notify_handler.watch_event(row_event)
            worker.start()
            worker_list.append(worker)

        # Refresh the hash rings just in case
        [worker.idl._hash_ring.refresh() for worker in worker_list]

        # Assert we have 11 active workers in the ring
        self.assertEqual(
            11, len(db_hash_ring.get_active_nodes(
                    interval=ovn_const.HASH_RING_NODES_TIMEOUT)))

        # Trigger the event
        self.create_port()

        # Wait for the event to complete
        self.assertTrue(row_event.wait())

        # Assert that only one worker handled the event
        self.assertEqual(1, row_event.COUNTER)
示例#2
0
    def test_ovsdb_monitor_lock(self):
        """Test case to test the ovsdb monitor lock used by OvnConnection.

        This test case created another IDL connection to the NB DB using
        the ovsdb_monitor.OvnConnection.

        With this we will have 2 'ovsdb_monitor.OvnConnection's. At the
        start the lock should be with the IDL connection created by the
        'TestOVNFunctionalBase' setup() function.

        The port up/down events should be handled by the first IDL connection.
        Then we will restart the first IDL connection so that the 2nd IDL
        connection created in this test case gets the lock and it should
        handle the port up/down events.

        Please note that the "self.monitor_nb_idl_con" created by the base
        class is created using 'connection.Connection' and hence it will not
        contend for any lock.
        """
        fake_driver = mock.MagicMock()
        _idl = ovsdb_monitor.OvnNbIdl.from_server(
            self.ovsdb_server_mgr.get_ovsdb_connection_path(),
            'OVN_Northbound', fake_driver)
        tst_ovn_conn = self.useFixture(
            base.ConnectionFixture(idl=_idl, timeout=10)).connection
        tst_ovn_conn.start()

        self.mech_driver.set_port_status_up = mock.Mock()
        self.mech_driver.set_port_status_down = mock.Mock()

        with self.port(name='port') as p:
            p = p['port']
            with self.nb_idl_transaction(self.fake_api,
                                         check_error=True) as txn:
                txn.add(
                    cmd.SetLSwitchPortCommand(self.fake_api,
                                              p['id'],
                                              True,
                                              up=False))

            self._test_port_up_down_helper(p, self.mech_driver)
            fake_driver.set_port_status_up.assert_not_called()
            fake_driver.set_port_status_down.assert_not_called()

            # Now restart the mech_driver's IDL connection.
            self.mech_driver._nb_ovn.idl.force_reconnect()
            # Wait till the test_ovn_idl_conn has acquired the lock.
            n_utils.wait_until_true(lambda: tst_ovn_conn.idl.has_lock)

            self.mech_driver.set_port_status_up.reset_mock()
            self.mech_driver.set_port_status_down.reset_mock()
            fake_driver.set_port_status_up.reset_mock()
            fake_driver.set_port_status_down.reset_mock()

            self._test_port_up_down_helper(p, fake_driver)
            self.assertFalse(self.mech_driver.set_port_status_up.called)
            self.assertFalse(self.mech_driver.set_port_status_down.called)
    def test_ovsdb_monitor_lock(self):
        """Test case to test the ovsdb monitor lock used by OvnConnection.

        This test case created another IDL connection to the NB DB using
        the ovsdb_monitor.OvnConnection.

        With this we will have 2 'ovsdb_monitor.OvnConnection's. At the
        start the lock should be with the IDL connection created by the
        'TestOVNFunctionalBase' setup() function.

        The port up/down events should be handled by the first IDL connection.
        Then the first IDL connection will release the lock so that the 2nd IDL
        connection created in this test case gets the lock and it should
        handle the port up/down events. Later when 2nd IDL connection releases
        lock, first IDL connection will get the lock and handles the
        port up/down events.

        Please note that the "self.monitor_nb_idl_con" created by the base
        class is created using 'connection.Connection' and hence it will not
        contend for any lock.
        """
        fake_driver = mock.MagicMock()
        _idl = ovsdb_monitor.OvnNbIdl.from_server(
            self.ovsdb_server_mgr.get_ovsdb_connection_path(),
            'OVN_Northbound', fake_driver)
        tst_ovn_conn = self.useFixture(
            base.ConnectionFixture(idl=_idl, timeout=10)).connection
        tst_ovn_conn.start()

        port = self.create_port()

        # mech_driver will release the lock to fake test driver. During chassis
        # binding and unbinding, port status won't change(i.e will be DOWN)
        # as mech driver can't update it.
        self.mech_driver._nb_ovn.idl.set_lock(None)
        n_utils.wait_until_true(lambda: tst_ovn_conn.idl.has_lock)
        self.mech_driver._nb_ovn.idl.set_lock(
            self.mech_driver._nb_ovn.idl.event_lock_name)
        self._test_port_binding_and_status(port['id'], 'bind', 'DOWN')
        self._test_port_binding_and_status(port['id'], 'unbind', 'DOWN')

        # Fake driver will relase the lock to mech driver. Port status will be
        # updated to 'ACTIVE' for chassis binding and to 'DOWN' for chassis
        # unbinding.
        tst_ovn_conn.idl.set_lock(None)
        n_utils.wait_until_true(lambda: self.mech_driver._nb_ovn.idl.has_lock)
        self._test_port_binding_and_status(port['id'], 'bind', 'ACTIVE')
        self._test_port_binding_and_status(port['id'], 'unbind', 'DOWN')