Merge "Placement: allow to set reserved value equal to total for inventory"
This commit is contained in:
commit
b979bcd7e4
|
@ -99,6 +99,12 @@ class InvalidInventoryCapacity(InvalidInventory):
|
|||
"The reserved value is greater than or equal to total.")
|
||||
|
||||
|
||||
class InvalidInventoryCapacityReservedCanBeTotal(InvalidInventoryCapacity):
|
||||
msg_fmt = _("Invalid inventory for '%(resource_class)s' on "
|
||||
"resource provider '%(resource_provider)s'. "
|
||||
"The reserved value is greater than total.")
|
||||
|
||||
|
||||
# An exception with this name is used on both sides of the placement/
|
||||
# nova interaction.
|
||||
class InventoryInUse(InvalidInventory):
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
"""Inventory handlers for Placement API."""
|
||||
|
||||
import copy
|
||||
import operator
|
||||
|
||||
from oslo_db import exception as db_exc
|
||||
from oslo_serialization import jsonutils
|
||||
|
@ -147,6 +148,31 @@ def _serialize_inventories(inventories, generation):
|
|||
'inventories': inventories_dict}, last_modified)
|
||||
|
||||
|
||||
def _validate_inventory_capacity(version, inventories):
|
||||
"""Validate inventory capacity.
|
||||
|
||||
:param version: request microversion.
|
||||
:param inventories: Inventory or InventoryList to validate capacities of.
|
||||
:raises: exception.InvalidInventoryCapacityReservedCanBeTotal if request
|
||||
microversion is 1.26 or higher and any inventory has capacity < 0.
|
||||
:raises: exception.InvalidInventoryCapacity if request
|
||||
microversion is lower than 1.26 and any inventory has capacity <= 0.
|
||||
"""
|
||||
if not version.matches((1, 26)):
|
||||
op = operator.le
|
||||
exc_class = exception.InvalidInventoryCapacity
|
||||
else:
|
||||
op = operator.lt
|
||||
exc_class = exception.InvalidInventoryCapacityReservedCanBeTotal
|
||||
if isinstance(inventories, rp_obj.Inventory):
|
||||
inventories = rp_obj.InventoryList(objects=[inventories])
|
||||
for inventory in inventories:
|
||||
if op(inventory.capacity, 0):
|
||||
raise exc_class(
|
||||
resource_class=inventory.resource_class,
|
||||
resource_provider=inventory.resource_provider.uuid)
|
||||
|
||||
|
||||
@wsgi_wrapper.PlacementWsgify
|
||||
@util.require_content('application/json')
|
||||
def create_inventory(req):
|
||||
|
@ -168,6 +194,8 @@ def create_inventory(req):
|
|||
**data)
|
||||
|
||||
try:
|
||||
_validate_inventory_capacity(
|
||||
req.environ[microversion.MICROVERSION_ENVIRON], inventory)
|
||||
resource_provider.add_inventory(inventory)
|
||||
except (exception.ConcurrentUpdateDetected,
|
||||
db_exc.DBDuplicateEntry) as exc:
|
||||
|
@ -305,6 +333,8 @@ def set_inventories(req):
|
|||
inventories = rp_obj.InventoryList(objects=inv_list)
|
||||
|
||||
try:
|
||||
_validate_inventory_capacity(
|
||||
req.environ[microversion.MICROVERSION_ENVIRON], inventories)
|
||||
resource_provider.set_inventory(inventories)
|
||||
except exception.ResourceClassNotFound as exc:
|
||||
raise webob.exc.HTTPBadRequest(
|
||||
|
@ -401,6 +431,8 @@ def update_inventory(req):
|
|||
**data)
|
||||
|
||||
try:
|
||||
_validate_inventory_capacity(
|
||||
req.environ[microversion.MICROVERSION_ENVIRON], inventory)
|
||||
resource_provider.update_inventory(inventory)
|
||||
except (exception.ConcurrentUpdateDetected,
|
||||
db_exc.DBDuplicateEntry) as exc:
|
||||
|
|
|
@ -68,6 +68,8 @@ VERSIONS = [
|
|||
# GET /resource_providers
|
||||
'1.25', # Adds support for granular resource requests via numbered
|
||||
# querystring groups in GET /allocation_candidates
|
||||
'1.26', # Add ability to specify inventory with reserved value equal to
|
||||
# total.
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -201,10 +201,6 @@ def _add_inventory_to_provider(ctx, rp, inv_list, to_add):
|
|||
for rc_id in to_add:
|
||||
rc_str = _RC_CACHE.string_from_id(rc_id)
|
||||
inv_record = inv_list.find(rc_str)
|
||||
if inv_record.capacity <= 0:
|
||||
raise exception.InvalidInventoryCapacity(
|
||||
resource_class=rc_str,
|
||||
resource_provider=rp.uuid)
|
||||
ins_stmt = _INV_TBL.insert().values(
|
||||
resource_provider_id=rp.id,
|
||||
resource_class_id=rc_id,
|
||||
|
@ -232,10 +228,6 @@ def _update_inventory_for_provider(ctx, rp, inv_list, to_update):
|
|||
for rc_id in to_update:
|
||||
rc_str = _RC_CACHE.string_from_id(rc_id)
|
||||
inv_record = inv_list.find(rc_str)
|
||||
if inv_record.capacity <= 0:
|
||||
raise exception.InvalidInventoryCapacity(
|
||||
resource_class=rc_str,
|
||||
resource_provider=rp.uuid)
|
||||
allocation_query = sa.select(
|
||||
[func.sum(_ALLOC_TBL.c.used).label('usage')]).\
|
||||
where(sa.and_(
|
||||
|
|
|
@ -323,3 +323,9 @@ The semantic of the (unnumbered) ``resources``, ``required``, and ``member_of``
|
|||
query parameters is unchanged: the resources, traits, and aggregate
|
||||
associations specified thereby may be satisfied by any provider in the same
|
||||
non-sharing tree or associated via the specified aggregate(s).
|
||||
|
||||
1.26 Allow inventories to have reserved value equal to total
|
||||
------------------------------------------------------------
|
||||
|
||||
Starting with this version, it is allowed to set the reserved value of the
|
||||
resource provider inventory to be equal to total.
|
||||
|
|
|
@ -584,22 +584,6 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
|
|||
self.assertEqual(1, len(new_inv_list))
|
||||
self.assertEqual(2048, new_inv_list[0].total)
|
||||
|
||||
# fail when inventory bad
|
||||
disk_inv = rp_obj.Inventory(
|
||||
resource_provider=rp,
|
||||
resource_class=fields.ResourceClass.DISK_GB,
|
||||
total=2048,
|
||||
reserved=2048)
|
||||
disk_inv.obj_set_defaults()
|
||||
error = self.assertRaises(exception.InvalidInventoryCapacity,
|
||||
rp.update_inventory, disk_inv)
|
||||
self.assertIn("Invalid inventory for '%s'"
|
||||
% fields.ResourceClass.DISK_GB, str(error))
|
||||
self.assertIn("on resource provider '%s'." % rp.uuid, str(error))
|
||||
|
||||
# generation has not bumped
|
||||
self.assertEqual(saved_generation, rp.generation)
|
||||
|
||||
# delete inventory
|
||||
rp.delete_inventory(fields.ResourceClass.DISK_GB)
|
||||
|
||||
|
@ -693,17 +677,6 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
|
|||
mock_log.warning.assert_called_once_with(
|
||||
mock.ANY, {'uuid': rp.uuid, 'resource': 'DISK_GB'})
|
||||
|
||||
def test_add_invalid_inventory(self):
|
||||
rp = self._create_provider(uuidsentinel.rp_name)
|
||||
error = self.assertRaises(
|
||||
exception.InvalidInventoryCapacity,
|
||||
tb.add_inventory, rp, fields.ResourceClass.DISK_GB, 1024,
|
||||
reserved=2048)
|
||||
self.assertIn("Invalid inventory for '%s'"
|
||||
% fields.ResourceClass.DISK_GB, str(error))
|
||||
self.assertIn("on resource provider '%s'."
|
||||
% rp.uuid, str(error))
|
||||
|
||||
def test_add_allocation_increments_generation(self):
|
||||
rp = self._create_provider(name='foo')
|
||||
tb.add_inventory(rp, DISK_INVENTORY['resource_class'],
|
||||
|
|
|
@ -649,9 +649,84 @@ tests:
|
|||
status: 400
|
||||
response_strings:
|
||||
- Unable to update inventory
|
||||
- greater than or equal to total
|
||||
response_json_paths:
|
||||
$.errors[0].title: Bad Request
|
||||
|
||||
- name: put all inventory zero capacity old microversion
|
||||
PUT: $LAST_URL
|
||||
request_headers:
|
||||
content-type: application/json
|
||||
data:
|
||||
resource_provider_generation: 6
|
||||
inventories:
|
||||
IPV4_ADDRESS:
|
||||
total: 253
|
||||
reserved: 253
|
||||
status: 400
|
||||
response_strings:
|
||||
- Unable to update inventory
|
||||
- greater than or equal to total
|
||||
response_json_paths:
|
||||
$.errors[0].title: Bad Request
|
||||
|
||||
- name: put inventory with reserved equal to total
|
||||
PUT: $LAST_URL
|
||||
request_headers:
|
||||
content-type: application/json
|
||||
openstack-api-version: placement 1.26
|
||||
data:
|
||||
resource_provider_generation: 6
|
||||
inventories:
|
||||
IPV4_ADDRESS:
|
||||
total: 253
|
||||
reserved: 253
|
||||
status: 200
|
||||
|
||||
- name: put all inventory bad capacity in new microversion
|
||||
PUT: $LAST_URL
|
||||
request_headers:
|
||||
content-type: application/json
|
||||
openstack-api-version: placement 1.26
|
||||
data:
|
||||
resource_provider_generation: 7
|
||||
inventories:
|
||||
IPV4_ADDRESS:
|
||||
total: 253
|
||||
reserved: 512
|
||||
status: 400
|
||||
response_strings:
|
||||
- Unable to update inventory
|
||||
- greater than total
|
||||
response_json_paths:
|
||||
$.errors[0].title: Bad Request
|
||||
|
||||
- name: put one inventory zero capacity old microversion
|
||||
PUT: /resource_providers/$ENVIRON['RP_UUID']/inventories/IPV4_ADDRESS
|
||||
request_headers:
|
||||
content-type: application/json
|
||||
data:
|
||||
resource_provider_generation: 7
|
||||
total: 253
|
||||
reserved: 253
|
||||
status: 400
|
||||
response_strings:
|
||||
- Unable to update inventory
|
||||
- greater than or equal to total
|
||||
response_json_paths:
|
||||
$.errors[0].title: Bad Request
|
||||
|
||||
- name: put one inventory with reserved equal to total new microversion
|
||||
PUT: $LAST_URL
|
||||
request_headers:
|
||||
content-type: application/json
|
||||
openstack-api-version: placement 1.26
|
||||
data:
|
||||
resource_provider_generation: 7
|
||||
total: 512
|
||||
reserved: 512
|
||||
status: 200
|
||||
|
||||
- name: delete all inventory bad generation
|
||||
PUT: /resource_providers/$ENVIRON['RP_UUID']/inventories
|
||||
request_headers:
|
||||
|
@ -680,7 +755,7 @@ tests:
|
|||
- name: get inventories after deletions
|
||||
GET: /resource_providers/$ENVIRON['RP_UUID']/inventories
|
||||
response_json_paths:
|
||||
$.resource_provider_generation: 8
|
||||
$.resource_provider_generation: 10
|
||||
$.inventories: {}
|
||||
|
||||
- name: post an inventory again
|
||||
|
@ -699,7 +774,7 @@ tests:
|
|||
response_headers:
|
||||
location: $SCHEME://$NETLOC/resource_providers/$ENVIRON['RP_UUID']/inventories/DISK_GB
|
||||
response_json_paths:
|
||||
$.resource_provider_generation: 9
|
||||
$.resource_provider_generation: 11
|
||||
$.total: 2048
|
||||
$.reserved: 512
|
||||
|
||||
|
@ -709,17 +784,17 @@ tests:
|
|||
content-type: application/json
|
||||
openstack-api-version: placement 1.4
|
||||
data:
|
||||
resource_provider_generation: 9
|
||||
resource_provider_generation: 11
|
||||
inventories: {}
|
||||
response_json_paths:
|
||||
$.resource_provider_generation: 10
|
||||
$.resource_provider_generation: 12
|
||||
$.inventories: {}
|
||||
status: 200
|
||||
|
||||
- name: get generation after deletion
|
||||
GET: /resource_providers/$ENVIRON['RP_UUID']/inventories
|
||||
response_json_paths:
|
||||
$.resource_provider_generation: 10
|
||||
$.resource_provider_generation: 12
|
||||
$.inventories: {}
|
||||
|
||||
- name: delete inventories earlier version
|
||||
|
|
|
@ -39,13 +39,13 @@ tests:
|
|||
response_json_paths:
|
||||
$.errors[0].title: Not Acceptable
|
||||
|
||||
- name: latest microversion is 1.25
|
||||
- name: latest microversion is 1.26
|
||||
GET: /
|
||||
request_headers:
|
||||
openstack-api-version: placement latest
|
||||
response_headers:
|
||||
vary: /openstack-api-version/
|
||||
openstack-api-version: placement 1.25
|
||||
openstack-api-version: placement 1.26
|
||||
|
||||
- name: other accept header bad version
|
||||
GET: /
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
Introduces new placement API version ``1.26``. Starting with this version
|
||||
it is allowed to define resource provider inventories with reserved value
|
||||
equal to total.
|
Loading…
Reference in New Issue