"group" word should be used instead "pool"

Currently, when creating a new flavor, here
it need to set pool group name for the first
argument "pool".
For making clear between a pool and pool group,
So we should replace "pool" word with "pool_group"
at all the places.

According the discussion in IRC, for giving users time
to mirgate, we will support 'pool' and 'pool_group'
both in M, and will remove 'pool' in N.

APIImpact

Change-Id: Id4c976a1fc9cc7fb9b72482b4e3a7f7f80f94492
Closes-Bug: #1504959
This commit is contained in:
wanghao 2016-01-29 15:38:28 +08:00
parent a425e1104d
commit f204280187
12 changed files with 175 additions and 127 deletions

View File

@ -38,14 +38,26 @@ patch_pool = {
}
}
patch_pool_group = {
'type': 'object',
'properties': {
'pool_group': {
'type': 'string'
},
'additionalProperties': False
}
}
create = {
'type': 'object',
'properties': {
'pool_group': patch_pool_group['properties']['pool_group'],
'pool': patch_pool['properties']['pool'],
'capabilities': patch_capabilities['properties']['capabilities']
},
# NOTE(flaper87): capabilities need not be present. Storage drivers
# must provide reasonable defaults.
'required': ['pool'],
# NOTE(wanghao): remove pool in Newton release.
'oneOf': [{'required': ['pool_group']}, {'required': ['pool']}],
'additionalProperties': False
}

View File

@ -149,6 +149,14 @@ class PoolDoesNotExist(DoesNotExist):
super(PoolDoesNotExist, self).__init__(pool=pool)
class PoolGroupDoesNotExist(DoesNotExist):
msg_format = u'Pool group {pool_group} does not exist'
def __init__(self, pool_group):
super(PoolGroupDoesNotExist, self).__init__(pool_group=pool_group)
class FlavorDoesNotExist(DoesNotExist):
msg_format = u'Flavor {flavor} does not exist'

View File

@ -16,7 +16,7 @@
Schema:
'n': name :: six.text_type
'p': project :: six.text_type
's': storage pool :: six.text_type
's': storage pool_group :: six.text_type
'c': capabilities :: dict
"""
@ -56,13 +56,13 @@ class FlavorsController(base.FlavorsBase):
unique=True)
self._col.ensure_index(FLAVORS_STORAGE_POOL_INDEX,
background=True,
name='flavors_storage_pool_name')
name='flavors_storage_pool_group_name')
self._pools_ctrl = self.driver.pools_controller
@utils.raises_conn_error
def _list_by_pool(self, pool, limit=10, detailed=False):
query = {'s': pool}
def _list_by_pool_group(self, pool_group, limit=10, detailed=False):
query = {'s': pool_group}
cursor = self._col.find(query, projection=_field_spec(detailed),
limit=limit).sort('n', 1)
@ -97,16 +97,18 @@ class FlavorsController(base.FlavorsBase):
return _normalize(res, detailed)
@utils.raises_conn_error
def create(self, name, pool, project=None, capabilities=None):
def create(self, name, pool_group, project=None, capabilities=None):
# NOTE(flaper87): Check if there are pools in this group.
# Should there be a `group_exists` method?
if not list(self._pools_ctrl.get_pools_by_group(pool)):
raise errors.PoolDoesNotExist(pool)
# NOTE(wanghao): Since we didn't pass the group name just pool name,
# so we don't need to get the pool by group.
if not list(self._pools_ctrl.get_pools_by_group(pool_group)):
raise errors.PoolGroupDoesNotExist(pool_group)
capabilities = {} if capabilities is None else capabilities
self._col.update({'n': name, 'p': project},
{'$set': {'s': pool, 'c': capabilities}},
{'$set': {'s': pool_group, 'c': capabilities}},
upsert=True)
@utils.raises_conn_error
@ -114,16 +116,16 @@ class FlavorsController(base.FlavorsBase):
return self._col.find_one({'n': name, 'p': project}) is not None
@utils.raises_conn_error
def update(self, name, project=None, pool=None, capabilities=None):
def update(self, name, project=None, pool_group=None, capabilities=None):
fields = {}
if capabilities is not None:
fields['c'] = capabilities
if pool is not None:
fields['s'] = pool
if pool_group is not None:
fields['s'] = pool_group
assert fields, '`pool` or `capabilities` not found in kwargs'
assert fields, '`pool_group` or `capabilities` not found in kwargs'
res = self._col.update({'n': name, 'p': project},
{'$set': fields},
upsert=False)
@ -144,7 +146,7 @@ class FlavorsController(base.FlavorsBase):
def _normalize(flavor, detailed=False):
ret = {
'name': flavor['n'],
'pool': flavor['s'],
'pool_group': flavor['s'],
}
if detailed:

View File

@ -137,7 +137,7 @@ class PoolsController(base.PoolsBase):
pool = self.get(name)
pools_group = self.get_pools_by_group(pool['group'])
flavor_ctl = self.driver.flavors_controller
res = list(flavor_ctl._list_by_pool(pool['group']))
res = list(flavor_ctl._list_by_pool_group(pool['group']))
# NOTE(flaper87): If this is the only pool in the
# group and it's being used by a flavor, don't allow

View File

@ -490,7 +490,7 @@ class Catalog(object):
if flavor is not None:
flavor = self._flavor_ctrl.get(flavor, project=project)
pools = self._pools_ctrl.get_pools_by_group(
group=flavor['pool'],
group=flavor['pool_group'],
detailed=True)
pool = select.weighted(pools)
pool = pool and pool['name'] or None

View File

@ -71,21 +71,22 @@ class FlavorsController(base.FlavorsBase):
return _normalize(flavor, detailed)
@utils.raises_conn_error
def create(self, name, pool, project=None, capabilities=None):
def create(self, name, pool_group, project=None, capabilities=None):
cap = None if capabilities is None else utils.json_encode(capabilities)
try:
stmt = sa.sql.expression.insert(tables.Flavors).values(
name=name, pool=pool, project=project, capabilities=cap
name=name, pool_group=pool_group, project=project,
capabilities=cap
)
self.driver.connection.execute(stmt)
except sa.exc.IntegrityError:
if not self._pools_ctrl.get_pools_by_group(pool):
raise errors.PoolDoesNotExist(pool)
if not self._pools_ctrl.get_pools_by_group(pool_group):
raise errors.PoolGroupDoesNotExist(pool_group)
# TODO(flaper87): merge update/create into a single
# method with introduction of upsert
self.update(name, pool=pool,
self.update(name, pool_group=pool_group,
project=project,
capabilities=cap)
@ -98,16 +99,16 @@ class FlavorsController(base.FlavorsBase):
return self.driver.connection.execute(stmt).fetchone() is not None
@utils.raises_conn_error
def update(self, name, project=None, pool=None, capabilities=None):
def update(self, name, project=None, pool_group=None, capabilities=None):
fields = {}
if capabilities is not None:
fields['capabilities'] = capabilities
if pool is not None:
fields['pool'] = pool
if pool_group is not None:
fields['pool_group'] = pool_group
assert fields, '`pool` or `capabilities` not found in kwargs'
assert fields, '`pool_group` or `capabilities` not found in kwargs'
if 'capabilities' in fields:
fields['capabilities'] = utils.json_encode(fields['capabilities'])
@ -136,7 +137,7 @@ class FlavorsController(base.FlavorsBase):
def _normalize(flavor, detailed=False):
ret = {
'name': flavor[0],
'pool': flavor[2],
'pool_group': flavor[2],
}
if detailed:

View File

@ -46,7 +46,7 @@ Pools = sa.Table('Pools', metadata,
Flavors = sa.Table('Flavors', metadata,
sa.Column('name', sa.String(64), primary_key=True),
sa.Column('project', sa.String(64)),
sa.Column('pool', sa.ForeignKey('PoolGroup.name',
sa.Column('pool_group', sa.ForeignKey('PoolGroup.name',
ondelete='CASCADE'),
nullable=False),
sa.Column('capabilities', sa.Text()))

View File

@ -1424,8 +1424,8 @@ class FlavorsControllerTest(ControllerBaseTest):
self.assertIn('name', flavor)
self.assertEqual(xname, flavor['name'])
self.assertNotIn('project', flavor)
self.assertIn('pool', flavor)
self.assertEqual(xpool, flavor['pool'])
self.assertIn('pool_group', flavor)
self.assertEqual(xpool, flavor['pool_group'])
def test_create_replaces_on_duplicate_insert(self):
name = str(uuid.uuid1())
@ -1493,18 +1493,18 @@ class FlavorsControllerTest(ControllerBaseTest):
detailed=True)
p = 'olympic'
group = 'sports'
pool_group = 'sports'
self.pools_controller.create(p, 100, 'localhost2',
group=group, options={})
group=pool_group, options={})
self.addCleanup(self.pools_controller.delete, p)
new_capabilities = {'fifo': False}
self.flavors_controller.update(name, project=self.project,
pool=group,
pool_group=pool_group,
capabilities={'fifo': False})
res = self.flavors_controller.get(name, project=self.project,
detailed=True)
self._flavors_expects(res, name, self.project, group)
self._flavors_expects(res, name, self.project, pool_group)
self.assertEqual(new_capabilities, res['capabilities'])
def test_delete_works(self):
@ -1529,13 +1529,15 @@ class FlavorsControllerTest(ControllerBaseTest):
name_gen = lambda i: chr(ord('A') + i)
for i in range(15):
pool = str(i)
pool_group = pool
uri = 'localhost:2701' + pool
self.pools_controller.create(pool, 100, uri,
group=pool, options={})
group=pool_group, options={})
self.addCleanup(self.pools_controller.delete, pool)
self.flavors_controller.create(name_gen(i), project=self.project,
pool=pool, capabilities={})
pool_group=pool_group,
capabilities={})
def get_res(**kwargs):
cursor = self.flavors_controller.list(project=self.project,

View File

@ -24,7 +24,7 @@ from zaqar.tests.unit.transport.wsgi import base
@contextlib.contextmanager
def flavor(test, name, pool, capabilities={}):
def flavor(test, name, pool_group, capabilities={}):
"""A context manager for constructing a flavor for use in testing.
Deletes the flavor after exiting the context.
@ -32,27 +32,27 @@ def flavor(test, name, pool, capabilities={}):
:param test: Must expose simulate_* methods
:param name: Name for this flavor
:type name: six.text_type
:type pool: six.text_type
:type pool_group: six.text_type
:type capabilities: dict
:returns: (name, uri, capabilities)
:rtype: see above
"""
doc = {'pool': pool, 'capabilities': capabilities}
doc = {'pool_group': pool_group, 'capabilities': capabilities}
path = test.url_prefix + '/flavors/' + name
test.simulate_put(path, body=jsonutils.dumps(doc))
try:
yield name, pool, capabilities
yield name, pool_group, capabilities
finally:
test.simulate_delete(path)
@contextlib.contextmanager
def flavors(test, count, pool):
def flavors(test, count, pool_group):
"""A context manager for constructing flavors for use in testing.
Deletes the flavors after exiting the context.
@ -60,7 +60,7 @@ def flavors(test, count, pool):
:param test: Must expose simulate_* methods
:param count: Number of pools to create
:type count: int
:returns: (paths, pool, capabilities)
:returns: (paths, pool_group, capabilities)
:rtype: ([six.text_type], [six.text_type], [dict])
"""
@ -69,7 +69,7 @@ def flavors(test, count, pool):
args = sorted([(base + str(i), {str(i): i}, str(i)) for i in range(count)],
key=lambda tup: tup[2])
for path, capabilities, _ in args:
doc = {'pool': pool, 'capabilities': capabilities}
doc = {'pool_group': pool_group, 'capabilities': capabilities}
test.simulate_put(path, body=jsonutils.dumps(doc))
try:
@ -99,7 +99,7 @@ class TestFlavorsMongoDB(base.V1_1Base):
self.simulate_put(self.pool_path, body=jsonutils.dumps(self.pool_doc))
self.flavor = 'test-flavor'
self.doc = {'capabilities': {}, 'pool': self.pool_group}
self.doc = {'capabilities': {}, 'pool_group': self.pool_group}
self.flavor_path = self.url_prefix + '/flavors/' + self.flavor
self.simulate_put(self.flavor_path, body=jsonutils.dumps(self.doc))
self.assertEqual(falcon.HTTP_201, self.srmock.status)
@ -114,7 +114,7 @@ class TestFlavorsMongoDB(base.V1_1Base):
def test_put_flavor_works(self):
name = str(uuid.uuid1())
with flavor(self, name, self.doc['pool']):
with flavor(self, name, self.doc['pool_group']):
self.assertEqual(falcon.HTTP_201, self.srmock.status)
def test_put_raises_if_missing_fields(self):
@ -130,13 +130,13 @@ class TestFlavorsMongoDB(base.V1_1Base):
def test_put_raises_if_invalid_pool(self, pool):
path = self.url_prefix + '/flavors/' + str(uuid.uuid1())
self.simulate_put(path,
body=jsonutils.dumps({'pool': pool}))
body=jsonutils.dumps({'pool_group': pool}))
self.assertEqual(falcon.HTTP_400, self.srmock.status)
@ddt.data(-1, 'wee', [])
def test_put_raises_if_invalid_capabilities(self, capabilities):
path = self.url_prefix + '/flavors/' + str(uuid.uuid1())
doc = {'pool': 'a', 'capabilities': capabilities}
doc = {'pool_group': 'a', 'capabilities': capabilities}
self.simulate_put(path, body=jsonutils.dumps(doc))
self.assertEqual(falcon.HTTP_400, self.srmock.status)
@ -150,9 +150,9 @@ class TestFlavorsMongoDB(base.V1_1Base):
result = self.simulate_get(self.flavor_path)
self.assertEqual(falcon.HTTP_200, self.srmock.status)
doc = jsonutils.loads(result[0])
self.assertEqual(expect['pool'], doc['pool'])
self.assertEqual(expect['pool_group'], doc['pool_group'])
def test_create_flavor_no_pool(self):
def test_create_flavor_no_pool_group(self):
self.simulate_delete(self.flavor_path)
self.assertEqual(falcon.HTTP_204, self.srmock.status)
@ -164,7 +164,7 @@ class TestFlavorsMongoDB(base.V1_1Base):
self.assertEqual(falcon.HTTP_400, self.srmock.status)
self.assertEqual(
{'description': 'Flavor test-flavor could not be created. '
'Pool mypool-group does not exist',
'Pool group mypool-group does not exist',
'title': 'Unable to create'},
jsonutils.loads(resp[0]))
@ -183,23 +183,23 @@ class TestFlavorsMongoDB(base.V1_1Base):
self.assertIn('href', flavor)
self.assertIn('name', flavor)
self.assertEqual(xhref, flavor['href'])
self.assertIn('pool', flavor)
self.assertEqual(xpool, flavor['pool'])
self.assertIn('pool_group', flavor)
self.assertEqual(xpool, flavor['pool_group'])
def test_get_works(self):
result = self.simulate_get(self.flavor_path)
self.assertEqual(falcon.HTTP_200, self.srmock.status)
pool = jsonutils.loads(result[0])
self._flavor_expect(pool, self.flavor_path, self.doc['pool'])
flavor = jsonutils.loads(result[0])
self._flavor_expect(flavor, self.flavor_path, self.doc['pool_group'])
def test_detailed_get_works(self):
result = self.simulate_get(self.flavor_path,
query_string='detailed=True')
self.assertEqual(falcon.HTTP_200, self.srmock.status)
pool = jsonutils.loads(result[0])
self._flavor_expect(pool, self.flavor_path, self.doc['pool'])
self.assertIn('capabilities', pool)
self.assertEqual({}, pool['capabilities'])
flavor = jsonutils.loads(result[0])
self._flavor_expect(flavor, self.flavor_path, self.doc['pool_group'])
self.assertIn('capabilities', flavor)
self.assertEqual({}, flavor['capabilities'])
def test_patch_raises_if_missing_fields(self):
self.simulate_patch(self.flavor_path,
@ -214,23 +214,23 @@ class TestFlavorsMongoDB(base.V1_1Base):
result = self.simulate_get(self.flavor_path,
query_string='detailed=True')
self.assertEqual(falcon.HTTP_200, self.srmock.status)
pool = jsonutils.loads(result[0])
self._flavor_expect(pool, self.flavor_path, doc['pool'])
self.assertEqual(doc['capabilities'], pool['capabilities'])
flavor = jsonutils.loads(result[0])
self._flavor_expect(flavor, self.flavor_path, doc['pool_group'])
self.assertEqual(doc['capabilities'], flavor['capabilities'])
def test_patch_works(self):
doc = {'pool': 'my-pool', 'capabilities': {'a': 1}}
doc = {'pool_group': 'my-pool-group', 'capabilities': {'a': 1}}
self._patch_test(doc)
def test_patch_works_with_extra_fields(self):
doc = {'pool': 'my-pool', 'capabilities': {'a': 1},
doc = {'pool_group': 'my-pool-group', 'capabilities': {'a': 1},
'location': 100, 'partition': 'taco'}
self._patch_test(doc)
@ddt.data(-1, 2**32+1, [])
def test_patch_raises_400_on_invalid_pool(self, pool):
def test_patch_raises_400_on_invalid_pool_group(self, pool_group):
self.simulate_patch(self.flavor_path,
body=jsonutils.dumps({'pool': pool}))
body=jsonutils.dumps({'pool_group': pool_group}))
self.assertEqual(falcon.HTTP_400, self.srmock.status)
@ddt.data(-1, 'wee', [])
@ -241,7 +241,7 @@ class TestFlavorsMongoDB(base.V1_1Base):
def test_patch_raises_404_if_flavor_not_found(self):
self.simulate_patch(self.url_prefix + '/flavors/notexists',
body=jsonutils.dumps({'pool': 'test'}))
body=jsonutils.dumps({'pool_group': 'test'}))
self.assertEqual(self.srmock.status, falcon.HTTP_404)
def test_empty_listing(self):
@ -261,7 +261,7 @@ class TestFlavorsMongoDB(base.V1_1Base):
if marker:
query += '&marker={2}'.format(marker)
with flavors(self, count, self.doc['pool']) as expected:
with flavors(self, count, self.doc['pool_group']) as expected:
result = self.simulate_get(self.url_prefix + '/flavors',
query_string=query)
self.assertEqual(falcon.HTTP_200, self.srmock.status)
@ -297,7 +297,7 @@ class TestFlavorsMongoDB(base.V1_1Base):
for i, s in enumerate(flavors_list + next_flavors_list):
expect = expected[i]
path, capabilities = expect[:2]
self._flavor_expect(s, path, self.doc['pool'])
self._flavor_expect(s, path, self.doc['pool_group'])
if detailed:
self.assertIn('capabilities', s)
self.assertEqual(s['capabilities'], capabilities)
@ -317,14 +317,14 @@ class TestFlavorsMongoDB(base.V1_1Base):
def test_listing_marker_is_respected(self):
self.simulate_delete(self.flavor_path)
with flavors(self, 10, self.doc['pool']) as expected:
with flavors(self, 10, self.doc['pool_group']) as expected:
result = self.simulate_get(self.url_prefix + '/flavors',
query_string='marker=3')
self.assertEqual(falcon.HTTP_200, self.srmock.status)
flavor_list = jsonutils.loads(result[0])['flavors']
self.assertEqual(6, len(flavor_list))
path, capabilities = expected[4][:2]
self._flavor_expect(flavor_list[0], path, self.doc['pool'])
self._flavor_expect(flavor_list[0], path, self.doc['pool_group'])
def test_queue_create_works(self):
metadata = {'_flavor': self.flavor}

View File

@ -24,7 +24,7 @@ from zaqar.tests.unit.transport.wsgi import base
@contextlib.contextmanager
def flavor(test, name, pool):
def flavor(test, name, pool_group):
"""A context manager for constructing a flavor for use in testing.
Deletes the flavor after exiting the context.
@ -38,20 +38,20 @@ def flavor(test, name, pool):
"""
doc = {'pool': pool}
doc = {'pool_group': pool_group}
path = test.url_prefix + '/flavors/' + name
test.simulate_put(path, body=jsonutils.dumps(doc))
try:
yield name, pool
yield name, pool_group
finally:
test.simulate_delete(path)
@contextlib.contextmanager
def flavors(test, count, pool):
def flavors(test, count, pool_group):
"""A context manager for constructing flavors for use in testing.
Deletes the flavors after exiting the context.
@ -59,7 +59,7 @@ def flavors(test, count, pool):
:param test: Must expose simulate_* methods
:param count: Number of pools to create
:type count: int
:returns: (paths, pool, capabilities)
:returns: (paths, pool_group, capabilities)
:rtype: ([six.text_type], [six.text_type], [dict])
"""
@ -68,7 +68,7 @@ def flavors(test, count, pool):
args = sorted([(base + str(i), str(i)) for i in range(count)],
key=lambda tup: tup[1])
for path, _ in args:
doc = {'pool': pool}
doc = {'pool_group': pool_group}
test.simulate_put(path, body=jsonutils.dumps(doc))
try:
@ -98,7 +98,7 @@ class TestFlavorsMongoDB(base.V2Base):
self.simulate_put(self.pool_path, body=jsonutils.dumps(self.pool_doc))
self.flavor = 'test-flavor'
self.doc = {'capabilities': {}, 'pool': self.pool_group}
self.doc = {'capabilities': {}, 'pool_group': self.pool_group}
self.flavor_path = self.url_prefix + '/flavors/' + self.flavor
self.simulate_put(self.flavor_path, body=jsonutils.dumps(self.doc))
self.assertEqual(falcon.HTTP_201, self.srmock.status)
@ -113,7 +113,7 @@ class TestFlavorsMongoDB(base.V2Base):
def test_put_flavor_works(self):
name = str(uuid.uuid1())
with flavor(self, name, self.doc['pool']):
with flavor(self, name, self.doc['pool_group']):
self.assertEqual(falcon.HTTP_201, self.srmock.status)
def test_put_raises_if_missing_fields(self):
@ -126,16 +126,16 @@ class TestFlavorsMongoDB(base.V2Base):
self.assertEqual(falcon.HTTP_400, self.srmock.status)
@ddt.data(1, 2**32+1, [])
def test_put_raises_if_invalid_pool(self, pool):
def test_put_raises_if_invalid_pool(self, pool_group):
path = self.url_prefix + '/flavors/' + str(uuid.uuid1())
self.simulate_put(path,
body=jsonutils.dumps({'pool': pool}))
body=jsonutils.dumps({'pool_group': pool_group}))
self.assertEqual(falcon.HTTP_400, self.srmock.status)
@ddt.data(-1, 'wee', [])
def test_put_raises_if_invalid_capabilities(self, capabilities):
path = self.url_prefix + '/flavors/' + str(uuid.uuid1())
doc = {'pool': 'a', 'capabilities': capabilities}
doc = {'pool_group': 'a', 'capabilities': capabilities}
self.simulate_put(path, body=jsonutils.dumps(doc))
self.assertEqual(falcon.HTTP_400, self.srmock.status)
@ -149,9 +149,9 @@ class TestFlavorsMongoDB(base.V2Base):
result = self.simulate_get(self.flavor_path)
self.assertEqual(falcon.HTTP_200, self.srmock.status)
doc = jsonutils.loads(result[0])
self.assertEqual(expect['pool'], doc['pool'])
self.assertEqual(expect['pool_group'], doc['pool_group'])
def test_create_flavor_no_pool(self):
def test_create_flavor_no_pool_group(self):
self.simulate_delete(self.flavor_path)
self.assertEqual(falcon.HTTP_204, self.srmock.status)
@ -163,7 +163,7 @@ class TestFlavorsMongoDB(base.V2Base):
self.assertEqual(falcon.HTTP_400, self.srmock.status)
self.assertEqual(
{'description': 'Flavor test-flavor could not be created. '
'Pool mypool-group does not exist',
'Pool group mypool-group does not exist',
'title': 'Unable to create'},
jsonutils.loads(resp[0]))
@ -178,22 +178,22 @@ class TestFlavorsMongoDB(base.V2Base):
self.simulate_get(self.url_prefix + '/flavors/nonexisting')
self.assertEqual(falcon.HTTP_404, self.srmock.status)
def _flavor_expect(self, flavor, xhref, xpool):
def _flavor_expect(self, flavor, xhref, xpool_group):
self.assertIn('href', flavor)
self.assertIn('name', flavor)
self.assertEqual(xhref, flavor['href'])
self.assertIn('pool', flavor)
self.assertEqual(xpool, flavor['pool'])
self.assertIn('pool_group', flavor)
self.assertEqual(xpool_group, flavor['pool_group'])
def test_get_works(self):
result = self.simulate_get(self.flavor_path)
self.assertEqual(falcon.HTTP_200, self.srmock.status)
pool = jsonutils.loads(result[0])
self._flavor_expect(pool, self.flavor_path, self.doc['pool'])
flavor = jsonutils.loads(result[0])
self._flavor_expect(flavor, self.flavor_path, self.doc['pool_group'])
store_caps = ['FIFO', 'CLAIMS', 'DURABILITY',
'AOD', 'HIGH_THROUGHPUT']
self.assertEqual(store_caps, pool['capabilities'])
self.assertEqual(store_caps, flavor['capabilities'])
def test_patch_raises_if_missing_fields(self):
self.simulate_patch(self.flavor_path,
@ -205,28 +205,29 @@ class TestFlavorsMongoDB(base.V2Base):
body=jsonutils.dumps(doc))
self.assertEqual(falcon.HTTP_200, self.srmock.status)
updated_flavor = jsonutils.loads(result[0])
self._flavor_expect(updated_flavor, self.flavor_path, doc['pool'])
self._flavor_expect(updated_flavor, self.flavor_path,
doc['pool_group'])
self.assertEqual(doc['capabilities'], updated_flavor['capabilities'])
result = self.simulate_get(self.flavor_path)
self.assertEqual(falcon.HTTP_200, self.srmock.status)
flavor = jsonutils.loads(result[0])
self._flavor_expect(flavor, self.flavor_path, doc['pool'])
self._flavor_expect(flavor, self.flavor_path, doc['pool_group'])
self.assertEqual(doc['capabilities'], flavor['capabilities'])
def test_patch_works(self):
doc = {'pool': 'mypool', 'capabilities': []}
doc = {'pool_group': 'mypoolgroup', 'capabilities': []}
self._patch_test(doc)
def test_patch_works_with_extra_fields(self):
doc = {'pool': 'mypool', 'capabilities': [],
doc = {'pool_group': 'mypoolgroup', 'capabilities': [],
'location': 100, 'partition': 'taco'}
self._patch_test(doc)
@ddt.data(-1, 2**32+1, [])
def test_patch_raises_400_on_invalid_pool(self, pool):
def test_patch_raises_400_on_invalid_pool_group(self, pool_group):
self.simulate_patch(self.flavor_path,
body=jsonutils.dumps({'pool': pool}))
body=jsonutils.dumps({'pool_group': pool_group}))
self.assertEqual(falcon.HTTP_400, self.srmock.status)
@ddt.data(-1, 'wee', [])
@ -237,7 +238,7 @@ class TestFlavorsMongoDB(base.V2Base):
def test_patch_raises_404_if_flavor_not_found(self):
self.simulate_patch(self.url_prefix + '/flavors/notexists',
body=jsonutils.dumps({'pool': 'test'}))
body=jsonutils.dumps({'pool_group': 'test'}))
self.assertEqual(falcon.HTTP_404, self.srmock.status)
def test_empty_listing(self):
@ -257,7 +258,7 @@ class TestFlavorsMongoDB(base.V2Base):
if marker:
query += '&marker={2}'.format(marker)
with flavors(self, count, self.doc['pool']) as expected:
with flavors(self, count, self.doc['pool_group']) as expected:
result = self.simulate_get(self.url_prefix + '/flavors',
query_string=query)
self.assertEqual(falcon.HTTP_200, self.srmock.status)
@ -295,7 +296,7 @@ class TestFlavorsMongoDB(base.V2Base):
path = expect[0]
capabilities = ['FIFO', 'CLAIMS', 'DURABILITY',
'AOD', 'HIGH_THROUGHPUT']
self._flavor_expect(s, path, self.doc['pool'])
self._flavor_expect(s, path, self.doc['pool_group'])
if detailed:
self.assertIn('capabilities', s)
self.assertEqual(s['capabilities'], capabilities)
@ -315,14 +316,14 @@ class TestFlavorsMongoDB(base.V2Base):
def test_listing_marker_is_respected(self):
self.simulate_delete(self.flavor_path)
with flavors(self, 10, self.doc['pool']) as expected:
with flavors(self, 10, self.doc['pool_group']) as expected:
result = self.simulate_get(self.url_prefix + '/flavors',
query_string='marker=3')
self.assertEqual(falcon.HTTP_200, self.srmock.status)
flavor_list = jsonutils.loads(result[0])['flavors']
self.assertEqual(6, len(flavor_list))
path, capabilities = expected[4][:2]
self._flavor_expect(flavor_list[0], path, self.doc['pool'])
self._flavor_expect(flavor_list[0], path, self.doc['pool_group'])
def test_queue_create_works(self):
metadata = {'_flavor': self.flavor}

View File

@ -73,6 +73,8 @@ class Listing(object):
for entry in flavors:
entry['href'] = request.path + '/' + entry['name']
# NOTE(wanghao): remove this in Newton.
entry['pool'] = entry['pool_group']
results['links'] = [
{
@ -98,6 +100,8 @@ class Resource(object):
validator_type = jsonschema.Draft4Validator
self._validators = {
'create': validator_type(schema.create),
'pool_group': validator_type(schema.patch_pool_group),
# NOTE(wanghao): Remove this in Newton.
'pool': validator_type(schema.patch_pool),
'capabilities': validator_type(schema.patch_capabilities),
}
@ -107,7 +111,7 @@ class Resource(object):
::
{"pool": "", capabilities: {...}}
{"pool_group": "", capabilities: {...}}
:returns: HTTP | [200, 404]
"""
@ -120,7 +124,8 @@ class Resource(object):
data = self._ctrl.get(flavor,
project=project_id,
detailed=detailed)
# NOTE(wanghao): remove this in Newton.
data['pool'] = data['pool_group']
except errors.FlavorDoesNotExist as ex:
LOG.debug(ex)
raise falcon.HTTPNotFound()
@ -134,7 +139,7 @@ class Resource(object):
::
{"pool": "my-pool", "capabilities": {}}
{"pool_group": "my-pool-group", "capabilities": {}}
A capabilities object may also be provided.
@ -145,19 +150,19 @@ class Resource(object):
data = wsgi_utils.load(request)
wsgi_utils.validate(self._validators['create'], data)
pool_group = data.get('pool_group') or data.get('pool')
try:
self._ctrl.create(flavor,
pool=data['pool'],
pool_group=pool_group,
project=project_id,
capabilities=data['capabilities'])
response.status = falcon.HTTP_201
response.location = request.path
except errors.PoolDoesNotExist as ex:
except errors.PoolGroupDoesNotExist as ex:
LOG.exception(ex)
description = (_(u'Flavor %(flavor)s could not be created. '
u'Pool %(pool)s does not exist') %
dict(flavor=flavor, pool=data['pool']))
u'Pool group %(pool_group)s does not exist') %
dict(flavor=flavor, pool_group=pool_group))
raise falcon.HTTPBadRequest(_('Unable to create'), description)
def on_delete(self, request, response, project_id, flavor):
@ -174,7 +179,7 @@ class Resource(object):
"""Allows one to update a flavors's pool and/or capabilities.
This method expects the user to submit a JSON object
containing at least one of: 'pool', 'capabilities'. If
containing at least one of: 'pool_group', 'capabilities'. If
none are found, the request is flagged as bad. There is also
strict format checking through the use of
jsonschema. Appropriate errors are returned in each case for
@ -186,11 +191,11 @@ class Resource(object):
LOG.debug(u'PATCH flavor - name: %s', flavor)
data = wsgi_utils.load(request)
EXPECT = ('pool', 'capabilities')
EXPECT = ('pool_group', 'capabilities', 'pool')
if not any([(field in data) for field in EXPECT]):
LOG.debug(u'PATCH flavor, bad params')
raise wsgi_errors.HTTPBadRequestBody(
'One of `pool` or `capabilities` needs '
'One of `pool_group` or `capabilities` or `pool` needs '
'to be specified'
)
@ -199,6 +204,10 @@ class Resource(object):
fields = common_utils.fields(data, EXPECT,
pred=lambda v: v is not None)
# NOTE(wanghao): remove this in Newton.
if fields.get('pool') and fields.get('pool_group') is None:
fields['pool_group'] = fields.get('pool')
fields.pop('pool')
try:
self._ctrl.update(flavor, project=project_id, **fields)

View File

@ -47,7 +47,7 @@ class Listing(object):
{
"flavors": [
{"href": "", "capabilities": {}, "pool": ""},
{"href": "", "capabilities": {}, "pool_group": ""},
...
],
"links": [
@ -76,8 +76,11 @@ class Listing(object):
for entry in flavors:
entry['href'] = request.path + '/' + entry['name']
pool_group = entry['pool_group']
# NOTE(wanghao): remove this in Newton.
entry['pool'] = entry['pool_group']
if detailed:
caps = self._pools_ctrl.capabilities(group=entry['pool'])
caps = self._pools_ctrl.capabilities(group=pool_group)
entry['capabilities'] = [str(cap).split('.')[-1]
for cap in caps]
@ -111,6 +114,8 @@ class Resource(object):
validator_type = jsonschema.Draft4Validator
self._validators = {
'create': validator_type(schema.create),
'pool_group': validator_type(schema.patch_pool_group),
# NOTE(wanghao): Remove this in Newton.
'pool': validator_type(schema.patch_pool),
'capabilities': validator_type(schema.patch_capabilities),
}
@ -131,7 +136,10 @@ class Resource(object):
try:
data = self._ctrl.get(flavor, project=project_id)
capabilities = self._pools_ctrl.capabilities(group=data['pool'])
pool_group = data['pool_group']
# NOTE(wanghao): remove this in Newton.
data['pool'] = data['pool_group']
capabilities = self._pools_ctrl.capabilities(group=pool_group)
data['capabilities'] = [str(cap).split('.')[-1]
for cap in capabilities]
@ -149,7 +157,7 @@ class Resource(object):
::
{"pool": "my-pool", "capabilities": {}}
{"pool_group": "my-pool-group", "capabilities": {}}
A capabilities object may also be provided.
@ -160,18 +168,18 @@ class Resource(object):
data = wsgi_utils.load(request)
wsgi_utils.validate(self._validators['create'], data)
pool_group = data.get('pool_group') or data.get('pool')
try:
self._ctrl.create(flavor,
pool=data['pool'],
pool_group=pool_group,
project=project_id)
response.status = falcon.HTTP_201
response.location = request.path
except errors.PoolDoesNotExist as ex:
except errors.PoolGroupDoesNotExist as ex:
LOG.exception(ex)
description = (_(u'Flavor %(flavor)s could not be created. '
u'Pool %(pool)s does not exist') %
dict(flavor=flavor, pool=data['pool']))
u'Pool group %(pool_group)s does not exist') %
dict(flavor=flavor, pool_group=pool_group))
raise falcon.HTTPBadRequest(_('Unable to create'), description)
@acl.enforce("flavors:delete")
@ -187,11 +195,11 @@ class Resource(object):
@acl.enforce("flavors:update")
def on_patch(self, request, response, project_id, flavor):
"""Allows one to update a flavors's pool.
"""Allows one to update a flavors's pool_group.
This method expects the user to submit a JSON object
containing 'pool'. If none is found, the request is flagged as bad.
There is also strict format checking through the use of
containing 'pool_group'. If none is found, the request is flagged
as bad. There is also strict format checking through the use of
jsonschema. Appropriate errors are returned in each case for
badly formatted input.
@ -201,11 +209,11 @@ class Resource(object):
LOG.debug(u'PATCH flavor - name: %s', flavor)
data = wsgi_utils.load(request)
EXPECT = ('pool', )
EXPECT = ('pool_group', 'pool')
if not any([(field in data) for field in EXPECT]):
LOG.debug(u'PATCH flavor, bad params')
raise wsgi_errors.HTTPBadRequestBody(
'`pool` needs to be specified'
'`pool_group` or `pool` needs to be specified'
)
for field in EXPECT:
@ -213,12 +221,17 @@ class Resource(object):
fields = common_utils.fields(data, EXPECT,
pred=lambda v: v is not None)
# NOTE(wanghao): remove this in Newton.
if fields.get('pool') and fields.get('pool_group') is None:
fields['pool_group'] = fields.get('pool')
fields.pop('pool')
resp_data = None
try:
self._ctrl.update(flavor, project=project_id, **fields)
resp_data = self._ctrl.get(flavor, project=project_id)
capabilities = self._pools_ctrl.capabilities(
group=resp_data['pool'])
group=resp_data['pool_group'])
resp_data['capabilities'] = [str(cap).split('.')[-1]
for cap in capabilities]
except errors.FlavorDoesNotExist as ex: