Merge ""group" word should be used instead "pool""

This commit is contained in:
Jenkins 2016-03-01 20:58:30 +00:00 committed by Gerrit Code Review
commit f35742115f
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 = { create = {
'type': 'object', 'type': 'object',
'properties': { 'properties': {
'pool_group': patch_pool_group['properties']['pool_group'],
'pool': patch_pool['properties']['pool'], 'pool': patch_pool['properties']['pool'],
'capabilities': patch_capabilities['properties']['capabilities'] 'capabilities': patch_capabilities['properties']['capabilities']
}, },
# NOTE(flaper87): capabilities need not be present. Storage drivers # NOTE(flaper87): capabilities need not be present. Storage drivers
# must provide reasonable defaults. # must provide reasonable defaults.
'required': ['pool'], # NOTE(wanghao): remove pool in Newton release.
'oneOf': [{'required': ['pool_group']}, {'required': ['pool']}],
'additionalProperties': False 'additionalProperties': False
} }

View File

@ -149,6 +149,14 @@ class PoolDoesNotExist(DoesNotExist):
super(PoolDoesNotExist, self).__init__(pool=pool) 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): class FlavorDoesNotExist(DoesNotExist):
msg_format = u'Flavor {flavor} does not exist' msg_format = u'Flavor {flavor} does not exist'

View File

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

View File

@ -137,7 +137,7 @@ class PoolsController(base.PoolsBase):
pool = self.get(name) pool = self.get(name)
pools_group = self.get_pools_by_group(pool['group']) pools_group = self.get_pools_by_group(pool['group'])
flavor_ctl = self.driver.flavors_controller 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 # NOTE(flaper87): If this is the only pool in the
# group and it's being used by a flavor, don't allow # 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: if flavor is not None:
flavor = self._flavor_ctrl.get(flavor, project=project) flavor = self._flavor_ctrl.get(flavor, project=project)
pools = self._pools_ctrl.get_pools_by_group( pools = self._pools_ctrl.get_pools_by_group(
group=flavor['pool'], group=flavor['pool_group'],
detailed=True) detailed=True)
pool = select.weighted(pools) pool = select.weighted(pools)
pool = pool and pool['name'] or None pool = pool and pool['name'] or None

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -74,6 +74,8 @@ class Listing(object):
for entry in flavors: for entry in flavors:
entry['href'] = request.path + '/' + entry['name'] entry['href'] = request.path + '/' + entry['name']
# NOTE(wanghao): remove this in Newton.
entry['pool'] = entry['pool_group']
results['links'] = [ results['links'] = [
{ {
@ -99,6 +101,8 @@ class Resource(object):
validator_type = jsonschema.Draft4Validator validator_type = jsonschema.Draft4Validator
self._validators = { self._validators = {
'create': validator_type(schema.create), '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), 'pool': validator_type(schema.patch_pool),
'capabilities': validator_type(schema.patch_capabilities), 'capabilities': validator_type(schema.patch_capabilities),
} }
@ -108,7 +112,7 @@ class Resource(object):
:: ::
{"pool": "", capabilities: {...}} {"pool_group": "", capabilities: {...}}
:returns: HTTP | [200, 404] :returns: HTTP | [200, 404]
""" """
@ -121,7 +125,8 @@ class Resource(object):
data = self._ctrl.get(flavor, data = self._ctrl.get(flavor,
project=project_id, project=project_id,
detailed=detailed) detailed=detailed)
# NOTE(wanghao): remove this in Newton.
data['pool'] = data['pool_group']
except errors.FlavorDoesNotExist as ex: except errors.FlavorDoesNotExist as ex:
LOG.debug(ex) LOG.debug(ex)
raise wsgi_errors.HTTPNotFound(six.text_type(ex)) raise wsgi_errors.HTTPNotFound(six.text_type(ex))
@ -135,7 +140,7 @@ class Resource(object):
:: ::
{"pool": "my-pool", "capabilities": {}} {"pool_group": "my-pool-group", "capabilities": {}}
A capabilities object may also be provided. A capabilities object may also be provided.
@ -146,19 +151,19 @@ class Resource(object):
data = wsgi_utils.load(request) data = wsgi_utils.load(request)
wsgi_utils.validate(self._validators['create'], data) wsgi_utils.validate(self._validators['create'], data)
pool_group = data.get('pool_group') or data.get('pool')
try: try:
self._ctrl.create(flavor, self._ctrl.create(flavor,
pool=data['pool'], pool_group=pool_group,
project=project_id, project=project_id,
capabilities=data['capabilities']) capabilities=data['capabilities'])
response.status = falcon.HTTP_201 response.status = falcon.HTTP_201
response.location = request.path response.location = request.path
except errors.PoolDoesNotExist as ex: except errors.PoolGroupDoesNotExist as ex:
LOG.exception(ex) LOG.exception(ex)
description = (_(u'Flavor %(flavor)s could not be created. ' description = (_(u'Flavor %(flavor)s could not be created. '
u'Pool %(pool)s does not exist') % u'Pool group %(pool_group)s does not exist') %
dict(flavor=flavor, pool=data['pool'])) dict(flavor=flavor, pool_group=pool_group))
raise falcon.HTTPBadRequest(_('Unable to create'), description) raise falcon.HTTPBadRequest(_('Unable to create'), description)
def on_delete(self, request, response, project_id, flavor): def on_delete(self, request, response, project_id, flavor):
@ -175,7 +180,7 @@ class Resource(object):
"""Allows one to update a flavors's pool and/or capabilities. """Allows one to update a flavors's pool and/or capabilities.
This method expects the user to submit a JSON object 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 none are found, the request is flagged as bad. There is also
strict format checking through the use of strict format checking through the use of
jsonschema. Appropriate errors are returned in each case for jsonschema. Appropriate errors are returned in each case for
@ -187,11 +192,11 @@ class Resource(object):
LOG.debug(u'PATCH flavor - name: %s', flavor) LOG.debug(u'PATCH flavor - name: %s', flavor)
data = wsgi_utils.load(request) data = wsgi_utils.load(request)
EXPECT = ('pool', 'capabilities') EXPECT = ('pool_group', 'capabilities', 'pool')
if not any([(field in data) for field in EXPECT]): if not any([(field in data) for field in EXPECT]):
LOG.debug(u'PATCH flavor, bad params') LOG.debug(u'PATCH flavor, bad params')
raise wsgi_errors.HTTPBadRequestBody( raise wsgi_errors.HTTPBadRequestBody(
'One of `pool` or `capabilities` needs ' 'One of `pool_group` or `capabilities` or `pool` needs '
'to be specified' 'to be specified'
) )
@ -200,6 +205,10 @@ class Resource(object):
fields = common_utils.fields(data, EXPECT, fields = common_utils.fields(data, EXPECT,
pred=lambda v: v is not None) 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: try:
self._ctrl.update(flavor, project=project_id, **fields) self._ctrl.update(flavor, project=project_id, **fields)

View File

@ -48,7 +48,7 @@ class Listing(object):
{ {
"flavors": [ "flavors": [
{"href": "", "capabilities": {}, "pool": ""}, {"href": "", "capabilities": {}, "pool_group": ""},
... ...
], ],
"links": [ "links": [
@ -77,8 +77,11 @@ class Listing(object):
for entry in flavors: for entry in flavors:
entry['href'] = request.path + '/' + entry['name'] entry['href'] = request.path + '/' + entry['name']
pool_group = entry['pool_group']
# NOTE(wanghao): remove this in Newton.
entry['pool'] = entry['pool_group']
if detailed: if detailed:
caps = self._pools_ctrl.capabilities(group=entry['pool']) caps = self._pools_ctrl.capabilities(group=pool_group)
entry['capabilities'] = [str(cap).split('.')[-1] entry['capabilities'] = [str(cap).split('.')[-1]
for cap in caps] for cap in caps]
@ -112,6 +115,8 @@ class Resource(object):
validator_type = jsonschema.Draft4Validator validator_type = jsonschema.Draft4Validator
self._validators = { self._validators = {
'create': validator_type(schema.create), '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), 'pool': validator_type(schema.patch_pool),
'capabilities': validator_type(schema.patch_capabilities), 'capabilities': validator_type(schema.patch_capabilities),
} }
@ -132,7 +137,10 @@ class Resource(object):
try: try:
data = self._ctrl.get(flavor, project=project_id) 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] data['capabilities'] = [str(cap).split('.')[-1]
for cap in capabilities] for cap in capabilities]
@ -150,7 +158,7 @@ class Resource(object):
:: ::
{"pool": "my-pool", "capabilities": {}} {"pool_group": "my-pool-group", "capabilities": {}}
A capabilities object may also be provided. A capabilities object may also be provided.
@ -161,18 +169,18 @@ class Resource(object):
data = wsgi_utils.load(request) data = wsgi_utils.load(request)
wsgi_utils.validate(self._validators['create'], data) wsgi_utils.validate(self._validators['create'], data)
pool_group = data.get('pool_group') or data.get('pool')
try: try:
self._ctrl.create(flavor, self._ctrl.create(flavor,
pool=data['pool'], pool_group=pool_group,
project=project_id) project=project_id)
response.status = falcon.HTTP_201 response.status = falcon.HTTP_201
response.location = request.path response.location = request.path
except errors.PoolDoesNotExist as ex: except errors.PoolGroupDoesNotExist as ex:
LOG.exception(ex) LOG.exception(ex)
description = (_(u'Flavor %(flavor)s could not be created. ' description = (_(u'Flavor %(flavor)s could not be created. '
u'Pool %(pool)s does not exist') % u'Pool group %(pool_group)s does not exist') %
dict(flavor=flavor, pool=data['pool'])) dict(flavor=flavor, pool_group=pool_group))
raise falcon.HTTPBadRequest(_('Unable to create'), description) raise falcon.HTTPBadRequest(_('Unable to create'), description)
@acl.enforce("flavors:delete") @acl.enforce("flavors:delete")
@ -188,11 +196,11 @@ class Resource(object):
@acl.enforce("flavors:update") @acl.enforce("flavors:update")
def on_patch(self, request, response, project_id, flavor): 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 This method expects the user to submit a JSON object
containing 'pool'. If none is found, the request is flagged as bad. containing 'pool_group'. If none is found, the request is flagged
There is also strict format checking through the use of as bad. There is also strict format checking through the use of
jsonschema. Appropriate errors are returned in each case for jsonschema. Appropriate errors are returned in each case for
badly formatted input. badly formatted input.
@ -202,11 +210,11 @@ class Resource(object):
LOG.debug(u'PATCH flavor - name: %s', flavor) LOG.debug(u'PATCH flavor - name: %s', flavor)
data = wsgi_utils.load(request) data = wsgi_utils.load(request)
EXPECT = ('pool', ) EXPECT = ('pool_group', 'pool')
if not any([(field in data) for field in EXPECT]): if not any([(field in data) for field in EXPECT]):
LOG.debug(u'PATCH flavor, bad params') LOG.debug(u'PATCH flavor, bad params')
raise wsgi_errors.HTTPBadRequestBody( raise wsgi_errors.HTTPBadRequestBody(
'`pool` needs to be specified' '`pool_group` or `pool` needs to be specified'
) )
for field in EXPECT: for field in EXPECT:
@ -214,12 +222,17 @@ class Resource(object):
fields = common_utils.fields(data, EXPECT, fields = common_utils.fields(data, EXPECT,
pred=lambda v: v is not None) 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 resp_data = None
try: try:
self._ctrl.update(flavor, project=project_id, **fields) self._ctrl.update(flavor, project=project_id, **fields)
resp_data = self._ctrl.get(flavor, project=project_id) resp_data = self._ctrl.get(flavor, project=project_id)
capabilities = self._pools_ctrl.capabilities( capabilities = self._pools_ctrl.capabilities(
group=resp_data['pool']) group=resp_data['pool_group'])
resp_data['capabilities'] = [str(cap).split('.')[-1] resp_data['capabilities'] = [str(cap).split('.')[-1]
for cap in capabilities] for cap in capabilities]
except errors.FlavorDoesNotExist as ex: except errors.FlavorDoesNotExist as ex: