diff --git a/api-ref/source/v2/discovery-parameters.yaml b/api-ref/source/v2/discovery-parameters.yaml index 1974096455..8fe685df67 100644 --- a/api-ref/source/v2/discovery-parameters.yaml +++ b/api-ref/source/v2/discovery-parameters.yaml @@ -6,6 +6,7 @@ stores: - ``id`` - ``description`` - ``default`` + - ``read-only`` in: body required: true type: array diff --git a/api-ref/source/v2/samples/stores-list-response.json b/api-ref/source/v2/samples/stores-list-response.json index 75c372d544..ea7276d6f2 100644 --- a/api-ref/source/v2/samples/stores-list-response.json +++ b/api-ref/source/v2/samples/stores-list-response.json @@ -12,6 +12,11 @@ { "id":"cheap", "description": "Less expensive rbd store" + }, + { + "id":"read_only_store", + "description": "Read only http store", + "read-only": true } ] -} \ No newline at end of file +} diff --git a/doc/source/admin/multistores.rst b/doc/source/admin/multistores.rst index 4963b76e27..9956571193 100644 --- a/doc/source/admin/multistores.rst +++ b/doc/source/admin/multistores.rst @@ -50,17 +50,24 @@ operators to enable multiple stores support. represents the identifier for the store and value will be the type of the store. Valid values are one of ``file``, ``http``, ``rbd``, ``swift``, ``cinder``, ``sheepdog`` or ``vmware``. In order to have - multiple stores operator can specify multiple key:value separated by comma. + multiple stores operator can specify multiple key:value separated by + comma. + + Due to the special read only nature and characteristics of the + http store type, we do not encourage nor support configuring + multiple instances of the http type store even though it's + possible. + + The http store type is always treated by Glance as a read-only + store. This is indicated in the response to the ``/v2/stores/info`` + call, where an http type store will have the attribute ``read-only: + True`` in addition to the usual ``id`` and ``description`` fields. .. code-block:: ini [DEFAULT] enabled_backends = fast:rbd, cheap:rbd, shared:file, reliable:file - .. note:: Due to the special read only nature and characteristics of the - http store we do not encourage nor support configuring multiple - instances of http store even though it's possible. - * in the ``[glance_store]`` options group: * ``default_backend`` must be set to one of the identifier which are defined diff --git a/glance/api/v2/discovery.py b/glance/api/v2/discovery.py index 9577c3d7eb..4e8f993f3f 100644 --- a/glance/api/v2/discovery.py +++ b/glance/api/v2/discovery.py @@ -53,6 +53,9 @@ class InfoController(object): stores['description'] = description if backend == CONF.glance_store.default_backend: stores['default'] = "true" + # Check if http store is configured then mark it as read-only + if enabled_backends[backend] == 'http': + stores['read-only'] = "true" backends.append(stores) return {'stores': backends} diff --git a/glance/tests/unit/base.py b/glance/tests/unit/base.py index de8a24650d..f865cf75df 100644 --- a/glance/tests/unit/base.py +++ b/glance/tests/unit/base.py @@ -72,7 +72,8 @@ class MultiStoreClearingUnitTest(test_utils.BaseTestCase): :param passing_config: making store driver passes basic configurations. :returns: the number of how many store drivers been loaded. """ - self.config(enabled_backends={'file1': 'file', 'ceph1': 'rbd'}) + self.config(enabled_backends={'file1': 'file', 'ceph1': 'rbd', + 'readonly_store': 'http'}) store.register_store_opts(CONF) self.config(default_backend='file1', diff --git a/glance/tests/unit/v2/test_discovery_stores.py b/glance/tests/unit/v2/test_discovery_stores.py index 44162aaf29..6afbf748a1 100644 --- a/glance/tests/unit/v2/test_discovery_stores.py +++ b/glance/tests/unit/v2/test_discovery_stores.py @@ -39,10 +39,23 @@ class TestInfoControllers(base.MultiStoreClearingUnitTest): req) def test_get_stores(self): - available_stores = ['ceph1', 'file1'] + available_stores = ['ceph1', 'file1', 'readonly_store'] req = unit_test_utils.get_fake_request() output = self.controller.get_stores(req) self.assertIn('stores', output) for stores in output['stores']: self.assertIn('id', stores) self.assertIn(stores['id'], available_stores) + + def test_get_stores_read_only_store(self): + available_stores = ['ceph1', 'file1', 'readonly_store'] + req = unit_test_utils.get_fake_request() + output = self.controller.get_stores(req) + self.assertIn('stores', output) + for stores in output['stores']: + self.assertIn('id', stores) + self.assertIn(stores['id'], available_stores) + if stores['id'] == 'readonly_store': + self.assertTrue(stores['read-only']) + else: + self.assertIsNone(stores.get('read-only'))