diff --git a/hooks/glance_contexts.py b/hooks/glance_contexts.py index 46ef5179..3f71f842 100644 --- a/hooks/glance_contexts.py +++ b/hooks/glance_contexts.py @@ -164,6 +164,68 @@ class CinderStoreContext(OSContextGenerator): return {} +class MultiBackendContext(OSContextGenerator): + + def _get_ceph_config(self): + ceph_ctx = CephGlanceContext()() + if not ceph_ctx: + return + ctx = { + "rbd_store_chunk_size": 8, + "rbd_store_pool": ceph_ctx["rbd_pool"], + "rbd_store_user": ceph_ctx["rbd_user"], + "rados_connect_timeout": 0, + "rbd_store_ceph_conf": "/etc/ceph/ceph.conf", + } + return ctx + + def _get_swift_config(self): + swift_ctx = ObjectStoreContext()() + if not swift_ctx or swift_ctx.get("swift_store", False) is False: + return + ctx = { + "default_swift_reference": "swift", + "swift_store_config_file": "/etc/glance/glance-swift.conf", + "swift_store_create_container_on_put": "true", + } + return ctx + + def __call__(self): + ctxt = { + "enabled_backend_configs": {}, + "enabled_backends": None, + "default_store_backend": None, + } + backends = [] + + local_fs = config('filesystem-store-datadir') + if local_fs: + backends.append("local:file") + ctxt["enabled_backend_configs"]["local"] = { + "filesystem_store_datadir": local_fs, + "store_description": "Local filesystem store", + } + ceph_ctx = self._get_ceph_config() + if ceph_ctx: + backends.append("ceph:rbd") + ctxt["enabled_backend_configs"]["ceph"] = ceph_ctx + ctxt["default_store_backend"] = "ceph" + + swift_ctx = self._get_swift_config() + if swift_ctx: + backends.append("swift:swift") + ctxt["enabled_backend_configs"]["swift"] = swift_ctx + if not ctxt["default_store_backend"]: + ctxt["default_store_backend"] = "swift" + + if local_fs and not ctxt["default_store_backend"]: + ctxt["default_store_backend"] = "local" + + if len(backends) > 0: + ctxt["enabled_backends"] = ", ".join(backends) + return ctxt + + class MultiStoreContext(OSContextGenerator): def __call__(self): diff --git a/hooks/glance_utils.py b/hooks/glance_utils.py index c3ef0bd8..ac6d7b01 100644 --- a/hooks/glance_utils.py +++ b/hooks/glance_utils.py @@ -183,6 +183,7 @@ CONFIG_FILES = OrderedDict([ glance_contexts.GlanceIPv6Context(), context.WorkerConfigContext(), glance_contexts.MultiStoreContext(), + glance_contexts.MultiBackendContext(), context.OSConfigFlagContext( charm_flag='api-config-flags', template_flag='api_config_flags'), diff --git a/templates/stein/glance-api.conf b/templates/stein/glance-api.conf index 6b445c35..32757fb0 100644 --- a/templates/stein/glance-api.conf +++ b/templates/stein/glance-api.conf @@ -41,7 +41,15 @@ db_enforce_mysql_charset = False image_size_cap = {{ image_size_cap }} {% endif -%} +{% if enabled_backends %} +enabled_backends = {{ enabled_backends }} +{% endif %} + [glance_store] +{% if default_store_backend %} +default_backend = {{ default_store_backend }} +{% endif %} + {%- if use_internal_endpoints %} catalog_info = {{ volume_catalog_info }} {%- endif %} @@ -96,3 +104,10 @@ auth_endpoint = {{ service_protocol }}://{{ service_host }}:{{ service_port }}/v {% include "section-oslo-middleware" %} {% include "parts/section-storage" %} + +{% for name, cfg in enabled_backend_configs.items() %} +[{{name}}] +{% for key, val in cfg.items() -%} +{{ key }} = {{ val }} +{% endfor -%} +{% endfor%} diff --git a/unit_tests/test_glance_contexts.py b/unit_tests/test_glance_contexts.py index ea5021dd..538f6ba7 100644 --- a/unit_tests/test_glance_contexts.py +++ b/unit_tests/test_glance_contexts.py @@ -192,6 +192,141 @@ class TestGlanceContexts(CharmTestCase): {'known_stores': "glance.store.filesystem.Store," "glance.store.http.Store"}) + def test_multi_backend_no_relations_no_data_dir(self): + self.relation_ids.return_value = [] + self.is_relation_made.return_value = False + data_dir = '' + conf_dict = { + 'filesystem-store-datadir': data_dir, + } + self.config.side_effect = lambda x: conf_dict.get(x) + self.assertEqual( + contexts.MultiBackendContext()(), + { + 'enabled_backend_configs': {}, + 'enabled_backends': None, + 'default_store_backend': None, + }) + + def test_multi_backend_no_relations(self): + self.relation_ids.return_value = [] + self.is_relation_made.return_value = False + data_dir = '/some/data/dir' + conf_dict = { + 'filesystem-store-datadir': data_dir, + } + self.config.side_effect = lambda x: conf_dict.get(x) + self.assertEqual( + contexts.MultiBackendContext()(), + { + 'enabled_backend_configs': { + 'local': { + 'filesystem_store_datadir': data_dir, + 'store_description': 'Local filesystem store', + } + }, + 'enabled_backends': 'local:file', + 'default_store_backend': 'local', + }) + + def test_multi_backend_with_swift(self): + self.maxDiff = None + self.relation_ids.return_value = ["object-store:0"] + self.is_relation_made.return_value = False + data_dir = '/some/data/dir' + conf_dict = { + 'filesystem-store-datadir': data_dir, + } + swift_conf = "/etc/glance/glance-swift.conf" + self.config.side_effect = lambda x: conf_dict.get(x) + self.assertEqual( + contexts.MultiBackendContext()(), + { + 'enabled_backend_configs': { + 'local': { + 'filesystem_store_datadir': data_dir, + 'store_description': 'Local filesystem store', + }, + 'swift': { + "default_swift_reference": "swift", + "swift_store_config_file": swift_conf, + "swift_store_create_container_on_put": "true", + } + }, + 'enabled_backends': 'local:file, swift:swift', + 'default_store_backend': 'swift', + }) + + def test_multi_backend_with_ceph_no_swift(self): + self.maxDiff = None + self.relation_ids.return_value = [] + self.is_relation_made.return_value = True + service = 'glance' + self.service_name.return_value = service + data_dir = '/some/data/dir' + conf_dict = { + 'filesystem-store-datadir': data_dir, + 'rbd-pool-name': 'mypool', + } + self.config.side_effect = lambda x: conf_dict.get(x) + self.assertEqual( + contexts.MultiBackendContext()(), + { + 'enabled_backend_configs': { + 'local': { + 'filesystem_store_datadir': data_dir, + 'store_description': 'Local filesystem store', + }, + 'ceph': { + "rbd_store_chunk_size": 8, + "rbd_store_pool": 'mypool', + "rbd_store_user": service, + "rados_connect_timeout": 0, + "rbd_store_ceph_conf": "/etc/ceph/ceph.conf", + } + }, + 'enabled_backends': 'local:file, ceph:rbd', + 'default_store_backend': 'ceph', + }) + + def test_multi_backend_with_ceph_and_swift(self): + self.maxDiff = None + self.relation_ids.return_value = ["object-store:0"] + self.is_relation_made.return_value = True + service = 'glance' + self.service_name.return_value = service + data_dir = '/some/data/dir' + swift_conf = "/etc/glance/glance-swift.conf" + conf_dict = { + 'filesystem-store-datadir': data_dir, + 'rbd-pool-name': 'mypool', + } + self.config.side_effect = lambda x: conf_dict.get(x) + self.assertEqual( + contexts.MultiBackendContext()(), + { + 'enabled_backend_configs': { + 'local': { + 'filesystem_store_datadir': data_dir, + 'store_description': 'Local filesystem store', + }, + 'ceph': { + "rbd_store_chunk_size": 8, + "rbd_store_pool": 'mypool', + "rbd_store_user": service, + "rados_connect_timeout": 0, + "rbd_store_ceph_conf": "/etc/ceph/ceph.conf", + }, + 'swift': { + "default_swift_reference": "swift", + "swift_store_config_file": swift_conf, + "swift_store_create_container_on_put": "true", + } + }, + 'enabled_backends': 'local:file, ceph:rbd, swift:swift', + 'default_store_backend': 'ceph', + }) + @patch('charmhelpers.contrib.openstack.context.relation_ids') @patch('charmhelpers.contrib.hahelpers.cluster.config_get') @patch('charmhelpers.contrib.openstack.context.https')