Adds primary/secondary multisite relation

A new relation with primary/secondary nomenclature is added and the
old master/slave relation is marked as *Deprecated*. In future,
master/slave relation would be completely removed.

Change-Id: I9cda48b74a20aaa9a41baedc79332bfaf13951d3
func-test-pr: https://github.com/openstack-charmers/zaza-openstack-tests/pull/926
This commit is contained in:
utkarshbhatthere 2022-09-22 11:39:37 +00:00
parent c1c9531a7f
commit 367a2aedcb
8 changed files with 96 additions and 53 deletions

View File

@ -340,7 +340,7 @@ def mon_relation(rid=None, unit=None):
# NOTE(jamespage): # NOTE(jamespage):
# Multi-site deployments need to defer restart as the # Multi-site deployments need to defer restart as the
# zone is not created until the master relation is # zone is not created until the primary relation is
# joined; restarting here will cause a restart burst # joined; restarting here will cause a restart burst
# in systemd and stop the process restarting once # in systemd and stop the process restarting once
# zone configuration is complete. # zone configuration is complete.
@ -690,8 +690,8 @@ def radosgw_user_changed(relation_id=None):
'daemon-id': socket.gethostname()}) 'daemon-id': socket.gethostname()})
@hooks.hook('master-relation-joined') @hooks.hook('primary-relation-joined')
def master_relation_joined(relation_id=None): def primary_relation_joined(relation_id=None):
if not ready_for_service(legacy=False): if not ready_for_service(legacy=False):
log('unit not ready, deferring multisite configuration') log('unit not ready, deferring multisite configuration')
return return
@ -742,9 +742,9 @@ def master_relation_joined(relation_id=None):
multisite.create_realm(realm, default=True) multisite.create_realm(realm, default=True)
mutation = True mutation = True
# Migration if master site has buckets configured. # Migration if primary site has buckets configured.
# Migration involves renaming existing zone/zongroups such that existing # Migration involves renaming existing zone/zongroups such that existing
# buckets and their objects can be preserved on the master site. # buckets and their objects can be preserved on the primary site.
if multisite.check_cluster_has_buckets() is True: if multisite.check_cluster_has_buckets() is True:
log('Migrating to multisite with zone ({}) and zonegroup ({})' log('Migrating to multisite with zone ({}) and zonegroup ({})'
.format(zone, zonegroup), level=DEBUG) .format(zone, zonegroup), level=DEBUG)
@ -821,8 +821,8 @@ def master_relation_joined(relation_id=None):
secret=secret) secret=secret)
@hooks.hook('master-relation-departed') @hooks.hook('primary-relation-departed')
@hooks.hook('slave-relation-departed') @hooks.hook('secondary-relation-departed')
def multisite_relation_departed(): def multisite_relation_departed():
if not is_leader(): if not is_leader():
log('Cannot remove multisite relation, this unit is not the leader') log('Cannot remove multisite relation, this unit is not the leader')
@ -868,8 +868,8 @@ def multisite_relation_departed():
raise RuntimeError("Residual multisite config at local site.") raise RuntimeError("Residual multisite config at local site.")
@hooks.hook('slave-relation-changed') @hooks.hook('secondary-relation-changed')
def slave_relation_changed(relation_id=None, unit=None): def secondary_relation_changed(relation_id=None, unit=None):
if not is_leader(): if not is_leader():
log('Cannot setup multisite configuration, this unit is not the ' log('Cannot setup multisite configuration, this unit is not the '
'leader') 'leader')
@ -884,7 +884,7 @@ def slave_relation_changed(relation_id=None, unit=None):
master_data.get('access_key'), master_data.get('access_key'),
master_data.get('secret'), master_data.get('secret'),
master_data.get('url'))): master_data.get('url'))):
log("Defer processing until master RGW has provided required data") log("Defer processing until primary RGW has provided required data")
return return
public_url = '{}:{}'.format( public_url = '{}:{}'.format(
@ -933,6 +933,9 @@ def slave_relation_changed(relation_id=None, unit=None):
if zone not in multisite.list_zones(): if zone not in multisite.list_zones():
log('zone {} not found, creating now'.format(zone)) log('zone {} not found, creating now'.format(zone))
multisite.pull_period(url=master_data['url'],
access_key=master_data['access_key'],
secret=master_data['secret'])
multisite.create_zone(zone, multisite.create_zone(zone,
endpoints=endpoints, endpoints=endpoints,
default=False, master=False, default=False, master=False,
@ -953,6 +956,27 @@ def slave_relation_changed(relation_id=None, unit=None):
log('No mutation detected.', 'INFO') log('No mutation detected.', 'INFO')
@hooks.hook('master-relation-departed')
@hooks.hook('slave-relation-departed')
def master_slave_relation_departed():
log("departed relation is deprecated", "WARN")
multisite_relation_departed()
@hooks.hook('master-relation-joined')
def master_relation_joined(relation_id=None):
log("This relation is deprecated, use primary-secondary relation instead",
"WARN")
primary_relation_joined(relation_id)
@hooks.hook('slave-relation-changed')
def slave_relation_changed(relation_id=None, unit=None):
log("This relation is deprecated, use primary-secondary relation instead",
"WARN")
secondary_relation_changed(relation_id, unit)
@hooks.hook('leader-settings-changed') @hooks.hook('leader-settings-changed')
def leader_settings_changed(): def leader_settings_changed():
# NOTE: leader unit will only ever set leader storage # NOTE: leader unit will only ever set leader storage
@ -962,19 +986,30 @@ def leader_settings_changed():
if restart_nonce_changed(leader_get('restart_nonce')): if restart_nonce_changed(leader_get('restart_nonce')):
service_restart(service_name()) service_restart(service_name())
if not is_leader(): if not is_leader():
# Deprecated Master/Slave relation
for r_id in relation_ids('master'): for r_id in relation_ids('master'):
master_relation_joined(r_id) master_relation_joined(r_id)
# Primary/Secondary relation
for r_id in relation_ids('primary'):
primary_relation_joined(r_id)
for r_id in relation_ids('radosgw-user'): for r_id in relation_ids('radosgw-user'):
radosgw_user_changed(r_id) radosgw_user_changed(r_id)
def process_multisite_relations(): def process_multisite_relations():
"""Re-trigger any pending master/slave relations""" """Re-trigger any pending multisite relations"""
# Deprecated Master/Slave relation
for r_id in relation_ids('master'): for r_id in relation_ids('master'):
master_relation_joined(r_id) master_relation_joined(r_id)
for r_id in relation_ids('slave'): for r_id in relation_ids('slave'):
for unit in related_units(r_id): for unit in related_units(r_id):
slave_relation_changed(r_id, unit) slave_relation_changed(r_id, unit)
# Primary/Secondary relation
for r_id in relation_ids('primary'):
primary_relation_joined(r_id)
for r_id in relation_ids('secondary'):
for unit in related_units(r_id):
secondary_relation_changed(r_id, unit)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -218,10 +218,14 @@ def check_optional_config_and_relations(configs):
leader_get('secret'), leader_get('secret'),
leader_get('restart_nonce')) leader_get('restart_nonce'))
# An operator may have deployed both relations
primary_rids = relation_ids('master') + relation_ids('primary')
secondary_rids = relation_ids('slave') + relation_ids('secondary')
multisite_rids = primary_rids + secondary_rids
# Any realm or zonegroup config is present, multisite checks can be done. # Any realm or zonegroup config is present, multisite checks can be done.
# zone config can't be used because it's used by default. # zone config can't be used because it's used by default.
if config('realm') or config('zonegroup') or relation_ids('master') \ if config('realm') or config('zonegroup') or multisite_rids:
or relation_ids('slave'):
# All of Realm, zonegroup, and zone must be configured. # All of Realm, zonegroup, and zone must be configured.
if not all(multisite_config): if not all(multisite_config):
return ('blocked', return ('blocked',
@ -229,14 +233,14 @@ def check_optional_config_and_relations(configs):
'(realm={realm}, zonegroup={zonegroup}' '(realm={realm}, zonegroup={zonegroup}'
', zone={zone})'.format(**config())) ', zone={zone})'.format(**config()))
# Master/Slave Relation should be configured. # Primary/Secondary Relation should be configured.
if not (relation_ids('master') or relation_ids('slave')): if not multisite_rids:
return ('blocked', return ('blocked',
'multi-site configuration but master/slave ' 'multi-site configuration but primary/secondary '
'relation missing') 'relation missing')
# Primary site status check # Primary site status check
if relation_ids('master'): if primary_rids:
# Migration: The system is not multisite already. # Migration: The system is not multisite already.
if not multisite.is_multisite_configured(config('zone'), if not multisite.is_multisite_configured(config('zone'),
config('zonegroup')): config('zonegroup')):
@ -261,7 +265,7 @@ def check_optional_config_and_relations(configs):
'waiting for configuration of master zone') 'waiting for configuration of master zone')
# Secondary site status check # Secondary site status check
if relation_ids('slave'): if secondary_rids:
# Migration: The system is not multisite already. # Migration: The system is not multisite already.
if not multisite.is_multisite_configured(config('zone'), if not multisite.is_multisite_configured(config('zone'),
config('zonegroup')): config('zonegroup')):
@ -270,7 +274,7 @@ def check_optional_config_and_relations(configs):
"Non-Pristine RGW site can't be used as secondary") "Non-Pristine RGW site can't be used as secondary")
multisite_ready = False multisite_ready = False
for rid in relation_ids('slave'): for rid in secondary_rids:
for unit in related_units(rid): for unit in related_units(rid):
if relation_get('url', unit=unit, rid=rid): if relation_get('url', unit=unit, rid=rid):
multisite_ready = True multisite_ready = True

View File

@ -30,6 +30,8 @@ requires:
interface: tls-certificates interface: tls-certificates
slave: slave:
interface: radosgw-multisite interface: radosgw-multisite
secondary:
interface: radosgw-multisite
provides: provides:
nrpe-external-master: nrpe-external-master:
interface: nrpe-external-master interface: nrpe-external-master
@ -38,6 +40,8 @@ provides:
interface: http interface: http
master: master:
interface: radosgw-multisite interface: radosgw-multisite
primary:
interface: radosgw-multisite
object-store: object-store:
interface: swift-proxy interface: swift-proxy
radosgw-user: radosgw-user:

View File

@ -609,21 +609,21 @@ class MiscMultisiteTests(CharmTestCase):
'related_units', 'related_units',
'leader_get', 'leader_get',
'is_leader', 'is_leader',
'master_relation_joined', 'primary_relation_joined',
'slave_relation_changed', 'secondary_relation_changed',
'service_restart', 'service_restart',
'service_name', 'service_name',
'multisite' 'multisite'
] ]
_relation_ids = { _relation_ids = {
'master': ['master:1'], 'primary': ['primary:1'],
'slave': ['slave:1'], 'secondary': ['secondary:1'],
} }
_related_units = { _related_units = {
'master:1': ['rgw/0', 'rgw/1'], 'primary:1': ['rgw/0', 'rgw/1'],
'slave:1': ['rgw-s/0', 'rgw-s/1'], 'secondary:1': ['rgw-s/0', 'rgw-s/1'],
} }
def setUp(self): def setUp(self):
@ -642,14 +642,14 @@ class MiscMultisiteTests(CharmTestCase):
self.is_leader.return_value = False self.is_leader.return_value = False
ceph_hooks.leader_settings_changed() ceph_hooks.leader_settings_changed()
self.service_restart.assert_called_once_with('rgw@hostname') self.service_restart.assert_called_once_with('rgw@hostname')
self.master_relation_joined.assert_called_once_with('master:1') self.primary_relation_joined.assert_called_once_with('primary:1')
def test_process_multisite_relations(self): def test_process_multisite_relations(self):
ceph_hooks.process_multisite_relations() ceph_hooks.process_multisite_relations()
self.master_relation_joined.assert_called_once_with('master:1') self.primary_relation_joined.assert_called_once_with('primary:1')
self.slave_relation_changed.assert_has_calls([ self.secondary_relation_changed.assert_has_calls([
call('slave:1', 'rgw-s/0'), call('secondary:1', 'rgw-s/0'),
call('slave:1', 'rgw-s/1'), call('secondary:1', 'rgw-s/1'),
]) ])
@ -684,7 +684,7 @@ class CephRadosMultisiteTests(CharmTestCase):
self.systemd_based_radosgw.return_value = True self.systemd_based_radosgw.return_value = True
class MasterMultisiteTests(CephRadosMultisiteTests): class PrimaryMultisiteTests(CephRadosMultisiteTests):
_complete_config = { _complete_config = {
'realm': 'testrealm', 'realm': 'testrealm',
@ -703,8 +703,8 @@ class MasterMultisiteTests(CephRadosMultisiteTests):
'restart_nonce': 'foobar', 'restart_nonce': 'foobar',
} }
def test_master_relation_joined_missing_config(self): def test_primary_relation_joined_missing_config(self):
ceph_hooks.master_relation_joined('master:1') ceph_hooks.primary_relation_joined('primary:1')
self.config.assert_has_calls([ self.config.assert_has_calls([
call('realm'), call('realm'),
call('zonegroup'), call('zonegroup'),
@ -712,7 +712,7 @@ class MasterMultisiteTests(CephRadosMultisiteTests):
]) ])
self.relation_set.assert_not_called() self.relation_set.assert_not_called()
def test_master_relation_joined_create_everything(self): def test_primary_relation_joined_create_everything(self):
for k, v in self._complete_config.items(): for k, v in self._complete_config.items():
self.test_config.set(k, v) self.test_config.set(k, v)
self.listen_port.return_value = 80 self.listen_port.return_value = 80
@ -725,7 +725,7 @@ class MasterMultisiteTests(CephRadosMultisiteTests):
self.multisite.create_system_user.return_value = ( self.multisite.create_system_user.return_value = (
'mykey', 'mysecret', 'mykey', 'mysecret',
) )
ceph_hooks.master_relation_joined('master:1') ceph_hooks.primary_relation_joined('primary:1')
self.config.assert_has_calls([ self.config.assert_has_calls([
call('realm'), call('realm'),
call('zonegroup'), call('zonegroup'),
@ -768,12 +768,12 @@ class MasterMultisiteTests(CephRadosMultisiteTests):
call(restart_nonce=ANY), call(restart_nonce=ANY),
]) ])
self.relation_set.assert_called_with( self.relation_set.assert_called_with(
relation_id='master:1', relation_id='primary:1',
access_key='mykey', access_key='mykey',
secret='mysecret', secret='mysecret',
) )
def test_master_relation_joined_create_nothing(self): def test_primary_relation_joined_create_nothing(self):
for k, v in self._complete_config.items(): for k, v in self._complete_config.items():
self.test_config.set(k, v) self.test_config.set(k, v)
self.is_leader.return_value = True self.is_leader.return_value = True
@ -786,7 +786,7 @@ class MasterMultisiteTests(CephRadosMultisiteTests):
self.multisite.list_users.return_value = [ self.multisite.list_users.return_value = [
ceph_hooks.MULTISITE_SYSTEM_USER ceph_hooks.MULTISITE_SYSTEM_USER
] ]
ceph_hooks.master_relation_joined('master:1') ceph_hooks.primary_relation_joined('primary:1')
self.multisite.create_realm.assert_not_called() self.multisite.create_realm.assert_not_called()
self.multisite.create_zonegroup.assert_not_called() self.multisite.create_zonegroup.assert_not_called()
self.multisite.create_zone.assert_not_called() self.multisite.create_zone.assert_not_called()
@ -795,15 +795,15 @@ class MasterMultisiteTests(CephRadosMultisiteTests):
self.service_restart.assert_not_called() self.service_restart.assert_not_called()
self.leader_set.assert_not_called() self.leader_set.assert_not_called()
def test_master_relation_joined_not_leader(self): def test_primary_relation_joined_not_leader(self):
for k, v in self._complete_config.items(): for k, v in self._complete_config.items():
self.test_config.set(k, v) self.test_config.set(k, v)
self.listen_port.return_value = 80 self.listen_port.return_value = 80
self.is_leader.return_value = False self.is_leader.return_value = False
self.leader_get.side_effect = lambda attr: self._leader_data.get(attr) self.leader_get.side_effect = lambda attr: self._leader_data.get(attr)
ceph_hooks.master_relation_joined('master:1') ceph_hooks.primary_relation_joined('primary:1')
self.relation_set.assert_called_once_with( self.relation_set.assert_called_once_with(
relation_id='master:1', relation_id='primary:1',
realm='testrealm', realm='testrealm',
zonegroup='testzonegroup', zonegroup='testzonegroup',
url='http://rgw:80', url='http://rgw:80',
@ -833,7 +833,7 @@ class MasterMultisiteTests(CephRadosMultisiteTests):
) )
class SlaveMultisiteTests(CephRadosMultisiteTests): class SecondaryMultisiteTests(CephRadosMultisiteTests):
_complete_config = { _complete_config = {
'realm': 'testrealm', 'realm': 'testrealm',
@ -846,7 +846,7 @@ class SlaveMultisiteTests(CephRadosMultisiteTests):
'zonegroup': 'testzonegroup', 'zonegroup': 'testzonegroup',
'access_key': 'anotherkey', 'access_key': 'anotherkey',
'secret': 'anothersecret', 'secret': 'anothersecret',
'url': 'http://master:80' 'url': 'http://primary:80'
} }
_test_bad_relation = { _test_bad_relation = {
@ -854,10 +854,10 @@ class SlaveMultisiteTests(CephRadosMultisiteTests):
'zonegroup': 'anotherzg', 'zonegroup': 'anotherzg',
'access_key': 'anotherkey', 'access_key': 'anotherkey',
'secret': 'anothersecret', 'secret': 'anothersecret',
'url': 'http://master:80' 'url': 'http://primary:80'
} }
def test_slave_relation_changed(self): def test_secondary_relation_changed(self):
for k, v in self._complete_config.items(): for k, v in self._complete_config.items():
self.test_config.set(k, v) self.test_config.set(k, v)
self.is_leader.return_value = True self.is_leader.return_value = True
@ -867,7 +867,7 @@ class SlaveMultisiteTests(CephRadosMultisiteTests):
self.multisite.list_realms.return_value = [] self.multisite.list_realms.return_value = []
self.multisite.list_zones.return_value = [] self.multisite.list_zones.return_value = []
self.multisite.check_cluster_has_buckets.return_value = False self.multisite.check_cluster_has_buckets.return_value = False
ceph_hooks.slave_relation_changed('slave:1', 'rgw/0') ceph_hooks.secondary_relation_changed('secondary:1', 'rgw/0')
self.config.assert_has_calls([ self.config.assert_has_calls([
call('realm'), call('realm'),
call('zonegroup'), call('zonegroup'),
@ -878,7 +878,7 @@ class SlaveMultisiteTests(CephRadosMultisiteTests):
access_key=self._test_relation['access_key'], access_key=self._test_relation['access_key'],
secret=self._test_relation['secret'], secret=self._test_relation['secret'],
) )
self.multisite.pull_period.assert_called_once_with( self.multisite.pull_period.assert_called_with(
url=self._test_relation['url'], url=self._test_relation['url'],
access_key=self._test_relation['access_key'], access_key=self._test_relation['access_key'],
secret=self._test_relation['secret'], secret=self._test_relation['secret'],
@ -902,20 +902,20 @@ class SlaveMultisiteTests(CephRadosMultisiteTests):
self.service_restart.assert_called_once() self.service_restart.assert_called_once()
self.leader_set.assert_called_once_with(restart_nonce=ANY) self.leader_set.assert_called_once_with(restart_nonce=ANY)
def test_slave_relation_changed_incomplete_relation(self): def test_secondary_relation_changed_incomplete_relation(self):
for k, v in self._complete_config.items(): for k, v in self._complete_config.items():
self.test_config.set(k, v) self.test_config.set(k, v)
self.is_leader.return_value = True self.is_leader.return_value = True
self.relation_get.return_value = {} self.relation_get.return_value = {}
ceph_hooks.slave_relation_changed('slave:1', 'rgw/0') ceph_hooks.secondary_relation_changed('secondary:1', 'rgw/0')
self.config.assert_not_called() self.config.assert_not_called()
def test_slave_relation_changed_mismatching_config(self): def test_secondary_relation_changed_mismatching_config(self):
for k, v in self._complete_config.items(): for k, v in self._complete_config.items():
self.test_config.set(k, v) self.test_config.set(k, v)
self.is_leader.return_value = True self.is_leader.return_value = True
self.relation_get.return_value = self._test_bad_relation self.relation_get.return_value = self._test_bad_relation
ceph_hooks.slave_relation_changed('slave:1', 'rgw/0') ceph_hooks.secondary_relation_changed('secondary:1', 'rgw/0')
self.config.assert_has_calls([ self.config.assert_has_calls([
call('realm'), call('realm'),
call('zonegroup'), call('zonegroup'),
@ -923,9 +923,9 @@ class SlaveMultisiteTests(CephRadosMultisiteTests):
]) ])
self.multisite.list_realms.assert_not_called() self.multisite.list_realms.assert_not_called()
def test_slave_relation_changed_not_leader(self): def test_secondary_relation_changed_not_leader(self):
self.is_leader.return_value = False self.is_leader.return_value = False
ceph_hooks.slave_relation_changed('slave:1', 'rgw/0') ceph_hooks.secondary_relation_changed('secondary:1', 'rgw/0')
self.relation_get.assert_not_called() self.relation_get.assert_not_called()
@patch.object(ceph_hooks, 'apt_install') @patch.object(ceph_hooks, 'apt_install')