Merge "Use the application data bag to set id and id_service notifications"

This commit is contained in:
Zuul 2021-10-08 14:23:07 +00:00 committed by Gerrit Code Review
commit 1874a999ec
4 changed files with 66 additions and 17 deletions

View File

@ -427,7 +427,7 @@ def db_departed_or_broken():
def identity_changed(relation_id=None, remote_unit=None): def identity_changed(relation_id=None, remote_unit=None):
notifications_checksums = {} notifications_checksums = {}
notifications_endpoints = {} notifications_endpoints = {}
if is_elected_leader(CLUSTER_RES): if is_leader():
if not is_db_ready(): if not is_db_ready():
log("identity-service-relation-changed hook fired before db " log("identity-service-relation-changed hook fired before db "
"ready - deferring until db ready", level=WARNING) "ready - deferring until db ready", level=WARNING)

View File

@ -2240,6 +2240,20 @@ def send_id_service_notifications(data):
relation_settings={ relation_settings={
'catalog_ttl': config('catalog-cache-expiration'), 'catalog_ttl': config('catalog-cache-expiration'),
'ep_changed': json.dumps(changed, sort_keys=True)}) 'ep_changed': json.dumps(changed, sort_keys=True)})
# As a first step in resolving a race condition when updating
# identity and identity-notifications (LP: #1902264), start sending
# this data into the application data-bag instead of just the
# per-unit relation data. The consuming charms will need updating
# to look in the app data bag as well.
#
# After the charms consuming thie relation have been updated,
# it will be possible to remove the per-relation set above.
relation_set(
relation_id=rid,
relation_settings={
'catalog_ttl': config('catalog-cache-expiration'),
'ep_changed': json.dumps(changed, sort_keys=True)},
app=True)
def send_notifications(checksum_data, endpoint_data, force=False): def send_notifications(checksum_data, endpoint_data, force=False):
@ -2262,7 +2276,7 @@ def send_id_notifications(data, force=False):
:param force: Determines whether a trigger value is set to ensure the :param force: Determines whether a trigger value is set to ensure the
remote hook is fired. remote hook is fired.
""" """
if not data or not is_elected_leader(CLUSTER_RES): if not data or not is_leader():
log("Not sending notifications (no data or not leader)", level=INFO) log("Not sending notifications (no data or not leader)", level=INFO)
return return
@ -2311,6 +2325,17 @@ def send_id_notifications(data, force=False):
level=DEBUG) level=DEBUG)
for rid in rel_ids: for rid in rel_ids:
relation_set(relation_id=rid, relation_settings=_notifications) relation_set(relation_id=rid, relation_settings=_notifications)
# As a first step in resolving a race condition when updating
# identity and identity-notifications (LP: #1902264), start sending
# this data into the application data-bag instead of just the
# per-unit relation data. The consuming charms will need updating
# to look in the app data bag as well.
#
# After the charms consuming thie relation have been updated,
# it will be possible to remove the per-relation set above.
relation_set(relation_id=rid,
relation_settings=_notifications,
app=True)
def is_db_ready(use_current_context=False, db_rel=None): def is_db_ready(use_current_context=False, db_rel=None):

View File

@ -466,7 +466,7 @@ class KeystoneRelationTests(CharmTestCase):
@patch('keystone_utils.log') @patch('keystone_utils.log')
def test_identity_changed_no_leader(self, mock_log): def test_identity_changed_no_leader(self, mock_log):
self.is_elected_leader.return_value = False self.is_leader.return_value = False
hooks.identity_changed( hooks.identity_changed(
relation_id='identity-service:0', relation_id='identity-service:0',
remote_unit='unit/0') remote_unit='unit/0')

View File

@ -893,32 +893,50 @@ class TestKeystoneUtils(CharmTestCase):
@patch.object(utils, 'relation_set') @patch.object(utils, 'relation_set')
@patch.object(utils, 'relation_get') @patch.object(utils, 'relation_get')
@patch.object(utils, 'relation_ids') @patch.object(utils, 'relation_ids')
@patch.object(utils, 'is_elected_leader') @patch.object(utils, 'is_leader')
def test_send_id_notifications(self, mock_is_elected_leader, def test_send_id_notifications(self, mock_is_leader,
mock_relation_ids, mock_relation_get, mock_relation_ids, mock_relation_get,
mock_relation_set, mock_uuid): mock_relation_set, mock_uuid):
checksums = {'foo-endpoint-changed': 1} checksums = {'foo-endpoint-changed': 1}
relation_id = 'testrel:0' relation_id = 'testrel:0'
mock_uuid.uuid4.return_value = '1234' mock_uuid.uuid4.return_value = '1234'
mock_relation_ids.return_value = [relation_id] mock_relation_ids.return_value = [relation_id]
mock_is_elected_leader.return_value = False mock_is_leader.return_value = False
utils.send_id_notifications(checksums) utils.send_id_notifications(checksums)
self.assertFalse(mock_relation_set.called) self.assertFalse(mock_relation_set.called)
mock_is_elected_leader.return_value = True mock_is_leader.return_value = True
utils.send_id_notifications({}) utils.send_id_notifications({})
self.assertFalse(mock_relation_set.called) self.assertFalse(mock_relation_set.called)
utils.send_id_notifications(checksums) utils.send_id_notifications(checksums)
self.assertTrue(mock_relation_set.called) self.assertTrue(mock_relation_set.called)
mock_relation_set.assert_called_once_with(relation_id=relation_id, mock_relation_set.assert_has_calls([
relation_settings=checksums) call(
relation_id=relation_id,
relation_settings=checksums,
app=True
),
call(
relation_id=relation_id,
relation_settings=checksums
),
], any_order=True)
mock_relation_set.reset_mock() mock_relation_set.reset_mock()
utils.send_id_notifications(checksums, force=True) utils.send_id_notifications(checksums, force=True)
self.assertTrue(mock_relation_set.called) self.assertTrue(mock_relation_set.called)
checksums['trigger'] = '1234' checksums['trigger'] = '1234'
mock_relation_set.assert_called_once_with(relation_id=relation_id, mock_relation_set.assert_has_calls([
relation_settings=checksums) call(
relation_id=relation_id,
relation_settings=checksums,
app=True
),
call(
relation_id=relation_id,
relation_settings=checksums
),
], any_order=True)
@patch.object(utils, 'service_endpoint_dict') @patch.object(utils, 'service_endpoint_dict')
@patch.object(utils, 'relation_ids') @patch.object(utils, 'relation_ids')
@ -984,7 +1002,8 @@ class TestKeystoneUtils(CharmTestCase):
'ep_changed': 'ep_changed':
('{"neutron": {"internal": ' ('{"neutron": {"internal": '
'"http://neutron.demo.com:9696"}}') '"http://neutron.demo.com:9696"}}')
} },
app=True
), ),
call( call(
relation_id='identity-service:2', relation_id='identity-service:2',
@ -994,7 +1013,8 @@ class TestKeystoneUtils(CharmTestCase):
('{"neutron": {"internal": ' ('{"neutron": {"internal": '
'"http://neutron.demo.com:9696"},' '"http://neutron.demo.com:9696"},'
' "placement": {"internal": "http://demo.com"}}') ' "placement": {"internal": "http://demo.com"}}')
} },
app=True
) )
], any_order=True) ], any_order=True)
@ -1009,7 +1029,8 @@ class TestKeystoneUtils(CharmTestCase):
'catalog_ttl': 60, 'catalog_ttl': 60,
'ep_changed': 'ep_changed':
'{"neutron": {"internal": "http://demo.com"}}' '{"neutron": {"internal": "http://demo.com"}}'
} },
app=True
), ),
call( call(
relation_id='identity-service:2', relation_id='identity-service:2',
@ -1017,7 +1038,8 @@ class TestKeystoneUtils(CharmTestCase):
'catalog_ttl': 60, 'catalog_ttl': 60,
'ep_changed': 'ep_changed':
'{"neutron": {"internal": "http://demo.com"}}' '{"neutron": {"internal": "http://demo.com"}}'
} },
app=True
) )
] ]
mock_relation_set.assert_has_calls( mock_relation_set.assert_has_calls(
@ -1036,7 +1058,8 @@ class TestKeystoneUtils(CharmTestCase):
'catalog_ttl': 60, 'catalog_ttl': 60,
'ep_changed': 'ep_changed':
'{"neutron": {"internal": "http://demo.com"}}' '{"neutron": {"internal": "http://demo.com"}}'
} },
app=True
), ),
call( call(
relation_id='identity-service:2', relation_id='identity-service:2',
@ -1046,7 +1069,8 @@ class TestKeystoneUtils(CharmTestCase):
'{"neutron": {"internal": "http://demo.com"}, ' '{"neutron": {"internal": "http://demo.com"}, '
'"placement": {"internal": "http://demo.com"}}' '"placement": {"internal": "http://demo.com"}}'
) )
} },
app=True
) )
] ]
mock_relation_set.assert_has_calls( mock_relation_set.assert_has_calls(