def test_touch_nodes_from_host(self): nodes = self._add_nodes_and_assert_exists(count=3) # Add another node from a different host with mock.patch.object(ovn_hash_ring_db, 'CONF') as mock_conf: mock_conf.host = 'another-host-' + uuidutils.generate_uuid() another_host_node = self._add_nodes_and_assert_exists()[0] # Assert that updated_at isn't updated yet for node in nodes: node_db = self._get_node_row(node) self.assertEqual(node_db.created_at, node_db.updated_at) # Assert the same for the node from another host node_db = self._get_node_row(another_host_node) self.assertEqual(node_db.created_at, node_db.updated_at) # Touch the nodes from our host time.sleep(1) ovn_hash_ring_db.touch_nodes_from_host(self.admin_ctx, HASH_RING_TEST_GROUP) # Assert that updated_at is now updated for node in nodes: node_db = self._get_node_row(node) self.assertGreater(node_db.updated_at, node_db.created_at) # Assert that the node from another host hasn't been touched # (updated_at is not updated) node_db = self._get_node_row(another_host_node) self.assertEqual(node_db.created_at, node_db.updated_at)
def test_touch_nodes_from_host_different_groups(self): another_group = 'another_test_group' group1 = self._add_nodes_and_assert_exists(count=3) group2 = self._add_nodes_and_assert_exists(count=2, group_name=another_group) # Assert that updated_at isn't updated yet for node in group1 + group2: node_db = self._get_node_row(node) self.assertEqual(node_db.created_at, node_db.updated_at) # Touch the nodes from group1 time.sleep(1) ovn_hash_ring_db.touch_nodes_from_host(self.admin_ctx, HASH_RING_TEST_GROUP) # Assert that updated_at was updated for group1 for node in group1: node_db = self._get_node_row(node) self.assertGreater(node_db.updated_at, node_db.created_at) # Assert that updated_at wasn't updated for group2 for node in group2: node_db = self._get_node_row(node) self.assertEqual(node_db.created_at, node_db.updated_at)
def test_active_nodes(self): self._add_nodes_and_assert_exists(count=3) # Add another node from a different host with mock.patch.object(ovn_hash_ring_db, 'CONF') as mock_conf: mock_conf.host = 'another-host-' + uuidutils.generate_uuid() another_host_node = self._add_nodes_and_assert_exists()[0] # Assert all nodes are active (within 60 seconds) self.assertEqual( 4, len( ovn_hash_ring_db.get_active_nodes( self.admin_ctx, interval=60, group_name=HASH_RING_TEST_GROUP))) # Substract 60 seconds from utcnow() and touch the nodes from our host time.sleep(1) fake_utcnow = timeutils.utcnow() - datetime.timedelta(seconds=60) with mock.patch.object(timeutils, 'utcnow') as mock_utcnow: mock_utcnow.return_value = fake_utcnow ovn_hash_ring_db.touch_nodes_from_host(self.admin_ctx, HASH_RING_TEST_GROUP) # Now assert that all nodes from our host are seeing as offline. # Only the node from another host should be active active_nodes = ovn_hash_ring_db.get_active_nodes( self.admin_ctx, interval=60, group_name=HASH_RING_TEST_GROUP) self.assertEqual(1, len(active_nodes)) self.assertEqual(another_host_node, active_nodes[0].node_uuid)
def test_ring_rebalance(self): # Use pre-defined UUIDs to make the hashes predictable node_1_uuid = db_hash_ring.add_node(self.admin_ctx, HASH_RING_TEST_GROUP, 'node-1') node_2_uuid = db_hash_ring.add_node(self.admin_ctx, HASH_RING_TEST_GROUP, 'node-2') # Add another node from a different host with mock.patch.object(db_hash_ring, 'CONF') as mock_conf: mock_conf.host = 'another-host-52359446-c366' another_host_node = db_hash_ring.add_node(self.admin_ctx, HASH_RING_TEST_GROUP, 'another-host') # Assert all nodes are alive in the ring self.hash_ring_manager.refresh() self.assertEqual(3, len(self.hash_ring_manager._hash_ring.nodes)) # Hash certain values against the nodes hash_dict_before = { node_1_uuid: 'fake-uuid', node_2_uuid: 'fake-uuid-0', another_host_node: 'fake-uuid-ABCDE' } self._verify_hashes(hash_dict_before) # Mock utcnow() as the HASH_RING_NODES_TIMEOUT have expired # already and touch the nodes from our host fake_utcnow = timeutils.utcnow() - datetime.timedelta( seconds=constants.HASH_RING_NODES_TIMEOUT) with mock.patch.object(timeutils, 'utcnow') as mock_utcnow: mock_utcnow.return_value = fake_utcnow db_hash_ring.touch_nodes_from_host(self.admin_ctx, HASH_RING_TEST_GROUP) # Now assert that the ring was re-balanced and only the node from # another host is marked as alive self.hash_ring_manager.refresh() self.assertEqual([another_host_node], list(self.hash_ring_manager._hash_ring.nodes.keys())) # Now only "another_host_node" is alive, all values should hash to it hash_dict_after_rebalance = { another_host_node: 'fake-uuid', another_host_node: 'fake-uuid-0', another_host_node: 'fake-uuid-ABCDE' } self._verify_hashes(hash_dict_after_rebalance) # Now touch the nodes so they appear active again db_hash_ring.touch_nodes_from_host(self.admin_ctx, HASH_RING_TEST_GROUP) self.hash_ring_manager.refresh() # The ring should re-balance and as it was before self._verify_hashes(hash_dict_before)
def test__wait_startup_before_caching(self): db_hash_ring.add_node(self.admin_ctx, HASH_RING_TEST_GROUP, 'node-1') db_hash_ring.add_node(self.admin_ctx, HASH_RING_TEST_GROUP, 'node-2') # Assert it will return True until created_at != updated_at self.assertTrue(self.hash_ring_manager._wait_startup_before_caching) self.assertTrue(self.hash_ring_manager._cache_startup_timeout) # Touch the nodes (== update the updated_at column) db_hash_ring.touch_nodes_from_host(self.admin_ctx, HASH_RING_TEST_GROUP) # Assert it's now False. Waiting is not needed anymore self.assertFalse(self.hash_ring_manager._wait_startup_before_caching) self.assertFalse(self.hash_ring_manager._cache_startup_timeout) # Now assert that since the _cache_startup_timeout has been # flipped, we no longer will read from the database with mock.patch.object(hash_ring_manager.db_hash_ring, 'get_active_nodes') as get_nodes_mock: self.assertFalse( self.hash_ring_manager._wait_startup_before_caching) self.assertFalse(get_nodes_mock.called)
def touch_hash_ring_nodes(self): # NOTE(lucasagomes): Note that we do not rely on the OVSDB lock # here because we want the maintenance tasks from each instance to # execute this task. hash_ring_db.touch_nodes_from_host(self.ctx, self._group)