Adds existence verification for config values

Multisite config values (realm, zonegroup, zone) are written
to ceph.conf as the defaults without verifying their existence, this
causes failure for commands which use the default values.

Closes-Bug: #1987127
Change-Id: I0ab4df34f0000339227e5d5b80352355ea7bd36e
This commit is contained in:
utkarshbhatthere 2022-08-20 00:30:42 +05:30
parent 44fee84d4d
commit e97e3607e2
No known key found for this signature in database
GPG Key ID: 8AFC279E7CD87430
4 changed files with 62 additions and 5 deletions

View File

@ -18,6 +18,7 @@ import socket
import tempfile import tempfile
import shutil import shutil
import multisite
from charmhelpers.contrib.openstack import context from charmhelpers.contrib.openstack import context
from charmhelpers.contrib.hahelpers.cluster import ( from charmhelpers.contrib.hahelpers.cluster import (
determine_api_port, determine_api_port,
@ -307,9 +308,17 @@ class MonContext(context.CephContext):
if self.context_complete(ctxt): if self.context_complete(ctxt):
# Multi-site zone configuration is optional, # Multi-site zone configuration is optional,
# so add after assessment # so add after assessment
ctxt['rgw_zone'] = config('zone') zone = config('zone')
ctxt['rgw_zonegroup'] = config('zonegroup') zonegroup = config('zonegroup')
ctxt['rgw_realm'] = config('realm') realm = config('realm')
log("config: zone {} zonegroup {} realm {}"
.format(zone, zonegroup, realm), level=DEBUG)
if zone in multisite.plain_list('zone'):
ctxt['rgw_zone'] = zone
if zonegroup in multisite.plain_list('zonegroup'):
ctxt['rgw_zonegroup'] = zonegroup
if realm in multisite.plain_list('realm'):
ctxt['rgw_realm'] = realm
return ctxt return ctxt
return {} return {}

View File

@ -810,6 +810,7 @@ def master_relation_joined(relation_id=None):
'Mutation detected. Restarting {}.'.format(service_name()), 'Mutation detected. Restarting {}.'.format(service_name()),
'INFO') 'INFO')
multisite.update_period(zonegroup=zonegroup, zone=zone) multisite.update_period(zonegroup=zonegroup, zone=zone)
CONFIGS.write_all()
service_restart(service_name()) service_restart(service_name())
leader_set(restart_nonce=str(uuid.uuid4())) leader_set(restart_nonce=str(uuid.uuid4()))
else: else:
@ -898,6 +899,7 @@ def slave_relation_changed(relation_id=None, unit=None):
'Mutation detected. Restarting {}.'.format(service_name()), 'Mutation detected. Restarting {}.'.format(service_name()),
'INFO') 'INFO')
multisite.update_period(zonegroup=zonegroup, zone=zone) multisite.update_period(zonegroup=zonegroup, zone=zone)
CONFIGS.write_all()
service_restart(service_name()) service_restart(service_name())
leader_set(restart_nonce=str(uuid.uuid4())) leader_set(restart_nonce=str(uuid.uuid4()))
else: else:

View File

@ -81,6 +81,35 @@ def _list(key):
return [] return []
def plain_list(key):
"""Simple Implementation for list_*, where execution may fail expectedly.
On failure, retries are not attempted and empty list is returned.
:param key: string for required resource (zone, zonegroup, realm, user)
:type key: str
:return: list of specified entities found
:rtype: list
"""
cmd = [
RGW_ADMIN, '--id={}'.format(_key_name()),
key, 'list'
]
try:
result = json.loads(subprocess.check_output(
cmd, stderr=subprocess.PIPE
).decode('UTF-8'))
hookenv.log("Results: {}".format(result), level=hookenv.DEBUG)
if isinstance(result, dict):
return result['{}s'.format(key)]
else:
return result
except subprocess.CalledProcessError:
return []
except TypeError:
return []
@decorators.retry_on_exception(num_retries=5, base_delay=3, @decorators.retry_on_exception(num_retries=5, base_delay=3,
exc_type=ValueError) exc_type=ValueError)
def list_zones(retry_on_empty=False): def list_zones(retry_on_empty=False):
@ -646,7 +675,7 @@ def get_local_zone(zonegroup):
if zonegroup_info is None: if zonegroup_info is None:
hookenv.log("Failed to fetch zonegroup ({}) info".format(zonegroup), hookenv.log("Failed to fetch zonegroup ({}) info".format(zonegroup),
level=hookenv.ERROR) level=hookenv.ERROR)
return None return None, None
# zonegroup info always contains self name and zones list so fetching # zonegroup info always contains self name and zones list so fetching
# directly is safe. # directly is safe.
@ -660,7 +689,7 @@ def get_local_zone(zonegroup):
"No local zone configured for zonegroup ({})".format(zonegroup), "No local zone configured for zonegroup ({})".format(zonegroup),
level=hookenv.ERROR level=hookenv.ERROR
) )
return None return None, None
def rename_multisite_config(zonegroups, new_zonegroup_name, def rename_multisite_config(zonegroups, new_zonegroup_name,

View File

@ -33,6 +33,7 @@ TO_PATCH = [
'determine_api_port', 'determine_api_port',
'cmp_pkgrevno', 'cmp_pkgrevno',
'leader_get', 'leader_get',
'multisite',
'utils', 'utils',
] ]
@ -83,6 +84,17 @@ class MonContextTest(CharmTestCase):
self.test_config.set('zonegroup', 'zonegroup1') self.test_config.set('zonegroup', 'zonegroup1')
self.test_config.set('realm', 'realmX') self.test_config.set('realm', 'realmX')
@staticmethod
def plain_list_stub(key):
if key == "zone":
return ["default"]
if key == "zonegroup":
return ["zonegroup1"]
if key == "realm":
return ["realmX"]
else:
return []
@patch.object(ceph, 'config', lambda *args: @patch.object(ceph, 'config', lambda *args:
'{"client.radosgw.gateway": {"rgw init timeout": 60}}') '{"client.radosgw.gateway": {"rgw init timeout": 60}}')
@patch.object(context, 'ensure_host_resolvable_v6') @patch.object(context, 'ensure_host_resolvable_v6')
@ -104,6 +116,7 @@ class MonContextTest(CharmTestCase):
self.relation_get.side_effect = _relation_get self.relation_get.side_effect = _relation_get
self.relation_ids.return_value = ['mon:6'] self.relation_ids.return_value = ['mon:6']
self.related_units.return_value = ['ceph/0', 'ceph/1', 'ceph/2'] self.related_units.return_value = ['ceph/0', 'ceph/1', 'ceph/2']
self.multisite.plain_list = self.plain_list_stub
self.determine_api_port.return_value = 70 self.determine_api_port.return_value = 70
expect = { expect = {
'auth_supported': 'cephx', 'auth_supported': 'cephx',
@ -156,6 +169,7 @@ class MonContextTest(CharmTestCase):
self.relation_get.side_effect = _relation_get self.relation_get.side_effect = _relation_get
self.relation_ids.return_value = ['mon:6'] self.relation_ids.return_value = ['mon:6']
self.multisite.plain_list = self.plain_list_stub
self.related_units.return_value = ['ceph-proxy/0'] self.related_units.return_value = ['ceph-proxy/0']
self.determine_api_port.return_value = 70 self.determine_api_port.return_value = 70
expect = { expect = {
@ -219,6 +233,7 @@ class MonContextTest(CharmTestCase):
self.relation_get.side_effect = _relation_get self.relation_get.side_effect = _relation_get
self.relation_ids.return_value = ['mon:6'] self.relation_ids.return_value = ['mon:6']
self.related_units.return_value = ['ceph/0', 'ceph/1', 'ceph/2'] self.related_units.return_value = ['ceph/0', 'ceph/1', 'ceph/2']
self.multisite.plain_list = self.plain_list_stub
self.determine_api_port.return_value = 70 self.determine_api_port.return_value = 70
expect = { expect = {
'auth_supported': 'none', 'auth_supported': 'none',
@ -264,6 +279,7 @@ class MonContextTest(CharmTestCase):
self.relation_ids.return_value = ['mon:6'] self.relation_ids.return_value = ['mon:6']
self.related_units.return_value = ['ceph/0', 'ceph/1', 'ceph/2'] self.related_units.return_value = ['ceph/0', 'ceph/1', 'ceph/2']
self.determine_api_port.return_value = 70 self.determine_api_port.return_value = 70
self.multisite.plain_list = self.plain_list_stub
expect = { expect = {
'auth_supported': 'cephx', 'auth_supported': 'cephx',
'hostname': 'testhost', 'hostname': 'testhost',
@ -365,6 +381,7 @@ class MonContextTest(CharmTestCase):
self.relation_get.side_effect = _relation_get self.relation_get.side_effect = _relation_get
self.relation_ids.return_value = ['mon:6'] self.relation_ids.return_value = ['mon:6']
self.related_units.return_value = ['ceph/0', 'ceph/1', 'ceph/2'] self.related_units.return_value = ['ceph/0', 'ceph/1', 'ceph/2']
self.multisite.plain_list = self.plain_list_stub
self.determine_api_port.return_value = 70 self.determine_api_port.return_value = 70
expect = { expect = {
'auth_supported': 'cephx', 'auth_supported': 'cephx',