Skip to content

Commit

Permalink
Merge "Extending stores-detail API"
Browse files Browse the repository at this point in the history
  • Loading branch information
Zuul authored and openstack-gerrit committed Aug 24, 2022
2 parents 480ea38 + b0d727d commit 5c675bd
Show file tree
Hide file tree
Showing 6 changed files with 210 additions and 23 deletions.
31 changes: 29 additions & 2 deletions api-ref/source/v2/samples/stores-list-detail-response.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,41 @@
"description": "More expensive store with data redundancy",
"default": true,
"properties": {
"pool": "pool1"
"pool": "pool1",
"chunk_size": 65536,
"thin_provisioning": false
}
},
{
"id":"cheap",
"type": "file",
"description": "Less expensive store for seldom-used images",
"properties": {}
"properties": {
"datadir": "fdir",
"chunk_size": 65536,
"thin_provisioning": false
}
},
{
"id":"fast",
"type": "cinder",
"description": "Reasonably-priced fast store",
"properties": {
"volume_type": "volume1",
"use_multipath": false
}
},
{
"id":"slow",
"type": "swift",
"description": "Entry-level store balancing price and speed",
"properties": {
"container": "container1",
"large_object_size": 52428,
"large_object_chunk_size": 204800
}
}


]
}
75 changes: 65 additions & 10 deletions glance/api/v2/discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,24 +77,79 @@ def get_stores(self, req):

return {'stores': backends}

@staticmethod
def _get_rbd_properties(store_detail):
return {
'chunk_size': store_detail.chunk_size,
'pool': store_detail.pool,
'thin_provisioning': store_detail.thin_provisioning
}

@staticmethod
def _get_file_properties(store_detail):
return {
'data_dir': store_detail.datadir,
'chunk_size': store_detail.chunk_size,
'thin_provisioning': store_detail.thin_provisioning
}

@staticmethod
def _get_cinder_properties(store_detail):
return {
'volume_type': store_detail.store_conf.cinder_volume_type,
'use_multipath': store_detail.store_conf.cinder_use_multipath
}

@staticmethod
def _get_swift_properties(store_detail):
return {
'container': store_detail.container,
'large_object_size': store_detail.large_object_size,
'large_object_chunk_size': store_detail.large_object_chunk_size
}

@staticmethod
def _get_s3_properties(store_detail):
return {
's3_store_large_object_size':
store_detail.s3_store_large_object_size,
's3_store_large_object_chunk_size':
store_detail.s3_store_large_object_chunk_size,
's3_store_thread_pools':
store_detail.s3_store_thread_pools
}

@staticmethod
def _get_http_properties(store_detail):
# NOTE(mrjoshi): Thre are no useful properties
# to be exposed.
return {}

def get_stores_detail(self, req):
enabled_backends = CONF.enabled_backends
stores = self.get_stores(req).get('stores')
try:
api_policy.DiscoveryAPIPolicy(
req.context,
enforcer=self.policy).stores_info_detail()

store_mapper = {
'rbd': self._get_rbd_properties,
'file': self._get_file_properties,
'cinder': self._get_cinder_properties,
'swift': self._get_swift_properties,
's3': self._get_s3_properties,
'http': self._get_http_properties
}

for store in stores:
store['type'] = enabled_backends[store['id']]
store['properties'] = {}
if store['type'] == 'rbd':
store_detail = g_store.get_store_from_store_identifier(
store['id'])
store['properties'] = {'chunk_size':
store_detail.chunk_size,
'pool': store_detail.pool,
'thin_provisioning':
store_detail.thin_provisioning}
store_type = enabled_backends[store['id']]
store['type'] = store_type
store_detail = g_store.get_store_from_store_identifier(
store['id'])
store['properties'] = store_mapper.get(store_type)(
store_detail)

except exception.Forbidden as e:
LOG.debug("User not permitted to view details")
raise webob.exc.HTTPForbidden(explanation=e.msg)
Expand Down
66 changes: 66 additions & 0 deletions glance/tests/functional/v2/test_discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
# under the License.

import fixtures
import http.client as http

from oslo_utils import units

Expand Down Expand Up @@ -96,3 +97,68 @@ def test_quota_with_usage(self):
expected['image_count_total']['usage'] = 1
expected['image_size_total']['usage'] = 1
self._assert_usage(expected)

def test_stores(self):
# NOTE(mrjoshi): As this is a functional test, we are
# testing the functionality with file stores.

self.start_server()

# If user is admin or non-admin the store list will be
# displayed.
stores = self.api_get('/v2/info/stores').json['stores']
expected = {
"stores": [
{
"id": "store1",
"default": "true"
},
{
"id": "store2"
},
{
"id": "store3"
}]}

self.assertEqual(expected['stores'], stores)

# If user is admin the store list will be displayed
# along with store properties.
stores = self.api_get('/v2/info/stores/detail').json['stores']
expected = {
"stores": [
{
"id": "store1",
"default": "true",
"type": "file",
"properties": {
"data_dir": self._store_dir('store1'),
"chunk_size": 65536,
"thin_provisioning": False
}
},
{
"id": "store2",
"type": "file",
"properties": {
"data_dir": self._store_dir('store2'),
"chunk_size": 65536,
"thin_provisioning": False
}
},
{
"id": "store3",
"type": "file",
"properties": {
"data_dir": self._store_dir('store3'),
"chunk_size": 65536,
"thin_provisioning": False
}
}]}

self.assertEqual(expected['stores'], stores)

# If user is non-admin 403 Error response will be returned.
response = self.api_get('/v2/info/stores/detail',
headers={'X-Roles': 'member'})
self.assertEqual(http.FORBIDDEN, response.status_code)
19 changes: 18 additions & 1 deletion glance/tests/unit/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
from unittest import mock

import glance_store as store
from glance_store._drivers import cinder
from glance_store._drivers import rbd as rbd_store
from glance_store._drivers import swift
from glance_store import location
from oslo_concurrency import lockutils
from oslo_config import cfg
Expand Down Expand Up @@ -74,21 +76,36 @@ def _create_multi_stores(self, passing_config=True):
rbd_store.rados = mock.MagicMock()
rbd_store.rbd = mock.MagicMock()
rbd_store.Store._set_url_prefix = mock.MagicMock()
cinder.cinderclient = mock.MagicMock()
cinder.Store.get_cinderclient = mock.MagicMock()
swift.swiftclient = mock.MagicMock()
swift.BaseStore.get_store_connection = mock.MagicMock()
self.config(enabled_backends={'fast': 'file', 'cheap': 'file',
'readonly_store': 'http',
'fast-cinder': 'cinder',
'fast-rbd': 'rbd'})
'fast-rbd': 'rbd', 'reliable': 'swift'})
store.register_store_opts(CONF)

self.config(default_backend='fast',
group='glance_store')

self.config(filesystem_store_datadir=self.test_dir,
filesystem_thin_provisioning=False,
filesystem_store_chunk_size=65536,
group='fast')
self.config(filesystem_store_datadir=self.test_dir2,
filesystem_thin_provisioning=False,
filesystem_store_chunk_size=65536,
group='cheap')
self.config(rbd_store_chunk_size=8688388, rbd_store_pool='images',
rbd_thin_provisioning=False, group='fast-rbd')
self.config(cinder_volume_type='lvmdriver-1',
cinder_use_multipath=False, group='fast-cinder')
self.config(swift_store_container='glance',
swift_store_large_object_size=524288000,
swift_store_large_object_chunk_size=204800000,
group='reliable')

store.create_multi_stores(CONF)


Expand Down
34 changes: 24 additions & 10 deletions glance/tests/unit/v2/test_discovery_stores.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def test_get_stores_with_enabled_backends_empty(self):

def test_get_stores(self):
available_stores = ['cheap', 'fast', 'readonly_store', 'fast-cinder',
'fast-rbd']
'fast-rbd', 'reliable']
req = unit_test_utils.get_fake_request()
output = self.controller.get_stores(req)
self.assertIn('stores', output)
Expand All @@ -50,7 +50,7 @@ def test_get_stores(self):

def test_get_stores_read_only_store(self):
available_stores = ['cheap', 'fast', 'readonly_store', 'fast-cinder',
'fast-rbd']
'fast-rbd', 'reliable']
req = unit_test_utils.get_fake_request()
output = self.controller.get_stores(req)
self.assertIn('stores', output)
Expand All @@ -77,22 +77,36 @@ def test_get_stores_reserved_stores_excluded(self):

def test_get_stores_detail(self):
available_stores = ['cheap', 'fast', 'readonly_store', 'fast-cinder',
'fast-rbd']
available_store_type = ['file', 'file', 'http', 'cinder', 'rbd']
'fast-rbd', 'reliable']
available_store_type = ['file', 'file', 'http', 'cinder', 'rbd',
'swift']
req = unit_test_utils.get_fake_request(roles=['admin'])
output = self.controller.get_stores_detail(req)
self.assertEqual(len(CONF.enabled_backends), len(output['stores']))
self.assertIn('stores', output)
for stores in output['stores']:
self.assertIn('id', stores)
self.assertIn(stores['id'], available_stores)
self.assertIn(stores['type'], available_store_type)
self.assertIsNotNone(stores['properties'])
if stores['id'] == 'fast-rbd':
self.assertIn('chunk_size', stores['properties'])
self.assertIn('pool', stores['properties'])
self.assertIn('thin_provisioning', stores['properties'])
else:
self.assertEqual({}, stores['properties'])

def test_get_stores_detail_properties(self):
store_attributes = {'rbd': ['chunk_size', 'pool', 'thin_provisioning'],
'file': ['data_dir', 'chunk_size',
'thin_provisioning'],
'cinder': ['volume_type', 'use_multipath'],
'swift': ['container',
'large_object_size',
'large_object_chunk_size'],
'http': []}
req = unit_test_utils.get_fake_request(roles=['admin'])
output = self.controller.get_stores_detail(req)
self.assertEqual(len(CONF.enabled_backends), len(output['stores']))
self.assertIn('stores', output)
for store in output['stores']:
actual_attribute = list(store['properties'].keys())
expected_attribute = store_attributes[store['type']]
self.assertEqual(actual_attribute, expected_attribute)

def test_get_stores_detail_non_admin(self):
req = unit_test_utils.get_fake_request()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
features:
- |
This release brings expansion in the functionality of
stores-detail API. The stores detail API will list the
way each store is configured, whereas previously this
worked only for rbd store. The API remains admin-only
by default as it exposes backend information.

0 comments on commit 5c675bd

Please sign in to comment.