diff --git a/actions.yaml b/actions.yaml index 90a05216..abe46ad2 100644 --- a/actions.yaml +++ b/actions.yaml @@ -1,7 +1,7 @@ pause: description: Pause the ceph-radosgw unit. resume: - descrpition: Resume the ceph-radosgw unit. + description: Resume the ceph-radosgw unit. promote: description: Promote the zone associated with the local units to master/default (multi-site). readonly: diff --git a/hooks/ceph_rgw.py b/hooks/ceph_rgw.py index 463c281f..d3a98604 100644 --- a/hooks/ceph_rgw.py +++ b/hooks/ceph_rgw.py @@ -79,6 +79,10 @@ def import_radosgw_key(key, name=None): return False +def normalize_pool_name(pool): + return pool[1:] if pool.startswith('.') else pool + + def get_create_rgw_pools_rq(prefix=None): """Pre-create RGW pools so that they have the correct settings. @@ -101,6 +105,8 @@ def get_create_rgw_pools_rq(prefix=None): w = weights.get(pool, 0.10) if prefix: pool = "{prefix}{pool}".format(prefix=prefix, pool=pool) + + pool = normalize_pool_name(pool) if pg_num > 0: rq.add_op_create_pool(name=pool, replica_count=replicas, pg_num=pg_num, group='objects', @@ -162,7 +168,7 @@ def get_create_rgw_pools_rq(prefix=None): # the function arguments. Until then we need to build the dict # prior to the function call. kwargs = { - 'name': pool, + 'name': normalize_pool_name(pool), 'erasure_profile': profile_name, 'weight': bucket_weight, 'group': "objects", @@ -178,7 +184,7 @@ def get_create_rgw_pools_rq(prefix=None): # the function arguments. Until then we need to build the dict # prior to the function call. kwargs = { - 'name': pool, + 'name': normalize_pool_name(pool), 'replica_count': replicas, 'weight': bucket_weight, 'group': 'objects', @@ -209,7 +215,8 @@ def get_create_rgw_pools_rq(prefix=None): for pool in light: _add_light_pool(rq, pool, pg_num, prefix) - _add_light_pool(rq, '.rgw.root', pg_num) + # RadosGW creates this pool automatically from Quincy on. + # _add_light_pool(rq, '.rgw.root', pg_num) if config('restrict-ceph-pools'): rq.add_op_request_access_to_group(name="objects", diff --git a/hooks/charmhelpers/contrib/openstack/cert_utils.py b/hooks/charmhelpers/contrib/openstack/cert_utils.py index a25ca995..6620f59f 100644 --- a/hooks/charmhelpers/contrib/openstack/cert_utils.py +++ b/hooks/charmhelpers/contrib/openstack/cert_utils.py @@ -414,18 +414,27 @@ def get_requests_for_local_unit(relation_name=None): is_legacy_request = set(sent).intersection(legacy_keys) for unit in related_units(rid): data = relation_get(rid=rid, unit=unit) - if data.get(raw_certs_key): - bundles.append({ - 'ca': data['ca'], - 'chain': data.get('chain'), - 'certs': json.loads(data[raw_certs_key])}) - elif is_legacy_request: - bundles.append({ - 'ca': data['ca'], - 'chain': data.get('chain'), - 'certs': {sent['common_name']: - {'cert': data.get(local_name + '.server.cert'), - 'key': data.get(local_name + '.server.key')}}}) + # Note: Bug#2028683 - data may not be available if the certificates + # relation hasn't been populated by the providing charm. If no 'ca' + # in the data then don't attempt the bundle at all. + if data.get('ca'): + if data.get(raw_certs_key): + bundles.append({ + 'ca': data['ca'], + 'chain': data.get('chain'), + 'certs': json.loads(data[raw_certs_key]) + }) + elif is_legacy_request: + bundles.append({ + 'ca': data['ca'], + 'chain': data.get('chain'), + 'certs': { + sent['common_name']: { + 'cert': data.get(local_name + '.server.cert'), + 'key': data.get(local_name + '.server.key') + } + } + }) return bundles diff --git a/hooks/charmhelpers/core/unitdata.py b/hooks/charmhelpers/core/unitdata.py index 8f4bbc61..dac757f1 100644 --- a/hooks/charmhelpers/core/unitdata.py +++ b/hooks/charmhelpers/core/unitdata.py @@ -151,6 +151,7 @@ import contextlib import datetime import itertools import json +import logging import os import pprint import sqlite3 @@ -521,6 +522,41 @@ _KV = None def kv(): global _KV + + # If we are running unit tests, it is useful to go into memory-backed KV store to + # avoid concurrency issues when running multiple tests. This is not a + # problem when juju is running normally. + + env_var = os.environ.get("CHARM_HELPERS_TESTMODE", "auto").lower() + if env_var not in ["auto", "no", "yes"]: + logging.warning(f"Unknown value for CHARM_HELPERS_TESTMODE '{env_var}', assuming 'no'") + env_var = "no" + + if env_var == "no": + in_memory_db = False + elif env_var == "yes": + in_memory_db = True + elif env_var == "auto": + # If UNIT_STATE_DB is set, respect this request + if "UNIT_STATE_DB" in os.environ: + in_memory_db = False + # Autodetect normal juju execution by looking for juju variables + elif "JUJU_CHARM_DIR" in os.environ or "JUJU_UNIT_NAME" in os.environ: + in_memory_db = False + else: + # We are probably running in unit test mode + logging.warning("Auto-detected unit test environment for KV store.") + in_memory_db = True + else: + # Help the linter realise that in_memory_db is always set + raise Exception("Cannot reach this line") + if _KV is None: - _KV = Storage() + if in_memory_db: + _KV = Storage(":memory:") + else: + _KV = Storage() + else: + if in_memory_db and _KV.db_path != ":memory:": + logging.warning("Running with in_memory_db and KV is not set to :memory:") return _KV diff --git a/lib/charms_ceph/utils.py b/lib/charms_ceph/utils.py index 01fb9ac9..41eff9b4 100644 --- a/lib/charms_ceph/utils.py +++ b/lib/charms_ceph/utils.py @@ -1223,6 +1223,11 @@ def get_upgrade_key(): return get_named_key('upgrade-osd', _upgrade_caps) +def is_internal_client(name): + keys = ('osd-upgrade', 'osd-removal', 'admin', 'rbd-mirror', 'mds') + return any(name.startswith(key) for key in keys) + + def get_named_key(name, caps=None, pool_list=None): """Retrieve a specific named cephx key. @@ -1236,7 +1241,8 @@ def get_named_key(name, caps=None, pool_list=None): key = ceph_auth_get(key_name) if key: - upgrade_key_caps(key_name, caps) + if is_internal_client(name): + upgrade_key_caps(key_name, caps) return key log("Creating new key for {}".format(name), level=DEBUG) diff --git a/unit_tests/test_ceph.py b/unit_tests/test_ceph.py index 28e73402..98e3d37a 100644 --- a/unit_tests/test_ceph.py +++ b/unit_tests/test_ceph.py @@ -107,9 +107,6 @@ class CephRadosGWCephTests(CharmTestCase): call('us-east.rgw.buckets.index', replica_count=3, pg_num=10, weight=None, group='objects', namespace=None, app_name='rgw', max_bytes=None, max_objects=None), - call('.rgw.root', replica_count=3, pg_num=10, weight=None, - group='objects', namespace=None, app_name='rgw', - max_bytes=None, max_objects=None), ]) # confirm operation with bluestore compression @@ -163,9 +160,6 @@ class CephRadosGWCephTests(CharmTestCase): call('us-east.rgw.buckets.index', replica_count=3, pg_num=10, weight=None, group='objects', namespace=None, app_name='rgw', max_bytes=None, max_objects=None), - call('.rgw.root', replica_count=3, pg_num=10, weight=None, - group='objects', namespace=None, app_name='rgw', - max_bytes=None, max_objects=None), ]) @patch.object(utils.context, 'CephBlueStoreCompressionContext') @@ -228,9 +222,6 @@ class CephRadosGWCephTests(CharmTestCase): call('default.rgw.buckets.index', replica_count=3, pg_num=None, weight=3.0, group='objects', namespace=None, app_name='rgw', max_bytes=None, max_objects=None), - call('.rgw.root', replica_count=3, pg_num=None, weight=0.1, - group='objects', namespace=None, app_name='rgw', - max_bytes=None, max_objects=None), ]) mock_request_access.assert_called_with(key_name='radosgw.gateway', name='objects', @@ -287,9 +278,6 @@ class CephRadosGWCephTests(CharmTestCase): call('default.rgw.buckets.index', replica_count=3, pg_num=None, weight=3.0, group='objects', namespace=None, app_name='rgw', max_bytes=None, max_objects=None), - call('.rgw.root', replica_count=3, pg_num=None, weight=0.1, - group='objects', namespace=None, app_name='rgw', - max_bytes=None, max_objects=None), ]) @patch.object(utils.context, 'CephBlueStoreCompressionContext') @@ -365,9 +353,7 @@ class CephRadosGWCephTests(CharmTestCase): call(weight=3.00, replica_count=3, name='default.rgw.buckets.index', group='objects', app_name='rgw'), - call(weight=0.10, replica_count=3, name='.rgw.root', - group='objects', app_name='rgw')], - ) + ]) mock_request_access.assert_called_with(key_name='radosgw.gateway', name='objects', permission='rwx')