api: Migrate to JSON Schema Draft 2020-12

OpenAPI 3.1 is a superset of JSON Schema Draft 2020-12. As a result, we
wish to migrate our current schemas to this. There are a couple of
issues to address:

- 'exclusiveMinimum' is now an integer and allows you to define an
  minimum for an exclusive range, to complement 'minimum' which is used
  for an inclusive range. We can drop it and use 'minimum' with a larger
  number (since draft 6 [1]).

- 'integer' types can now accept a fractional part but only if it's zero
  (i.e. '1.0' is permissible, '1.1' is not) (since draft 6 [1]).

- 'items' has been replaced with 'prefixItems' for describing the format
  of an array item (since draft 2020-12 [2])

[1] https://json-schema.org/draft-06/json-schema-release-notes
[2] https://json-schema.org/draft/2020-12/release-notes

Change-Id: I1486701786960eef95c5c42674bff1b2d7d686e2
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
Stephen Finucane 2024-04-15 11:17:50 +01:00
parent c382f036c3
commit 7491417323
4 changed files with 10 additions and 8 deletions

View File

@ -50,7 +50,7 @@ create = {
'rxtx_factor': { 'rxtx_factor': {
'type': ['number', 'string'], 'type': ['number', 'string'],
'pattern': r'^[0-9]+(\.[0-9]+)?$', 'pattern': r'^[0-9]+(\.[0-9]+)?$',
'minimum': 0, 'exclusiveMinimum': True, 'minimum': 1,
# maximum's value is limited to db constant's # maximum's value is limited to db constant's
# SQL_SP_FLOAT_MAX (in nova/db/constants.py) # SQL_SP_FLOAT_MAX (in nova/db/constants.py)
'maximum': 3.40282e+38 'maximum': 3.40282e+38

View File

@ -31,7 +31,7 @@ create = {
# enumerated values. It's changed to a single string value # enumerated values. It's changed to a single string value
# in 2.64. # in 2.64.
'type': 'array', 'type': 'array',
'items': [ 'prefixItems': [
{ {
'type': 'string', 'type': 'string',
'enum': ['anti-affinity', 'affinity'], 'enum': ['anti-affinity', 'affinity'],
@ -53,7 +53,9 @@ create = {
create_v215 = copy.deepcopy(create) create_v215 = copy.deepcopy(create)
policies = create_v215['properties']['server_group']['properties']['policies'] policies = create_v215['properties']['server_group']['properties']['policies']
policies['items'][0]['enum'].extend(['soft-anti-affinity', 'soft-affinity']) policies['prefixItems'][0]['enum'].extend(
['soft-anti-affinity', 'soft-affinity']
)
create_v264 = copy.deepcopy(create_v215) create_v264 = copy.deepcopy(create_v215)
del create_v264['properties']['server_group']['properties']['policies'] del create_v264['properties']['server_group']['properties']['policies']

View File

@ -271,7 +271,7 @@ class FormatChecker(jsonschema.FormatChecker):
class _SchemaValidator(object): class _SchemaValidator(object):
"""A validator class """A validator class
This class is changed from Draft4Validator to validate minimum/maximum This class is changed from Draft202012Validator to validate minimum/maximum
value of a string number(e.g. '10'). This changes can be removed when value of a string number(e.g. '10'). This changes can be removed when
we tighten up the API definition and the XML conversion. we tighten up the API definition and the XML conversion.
Also FormatCheckers are added for checking data formats which would be Also FormatCheckers are added for checking data formats which would be
@ -279,7 +279,7 @@ class _SchemaValidator(object):
""" """
validator = None validator = None
validator_org = jsonschema.Draft4Validator validator_org = jsonschema.Draft202012Validator
def __init__(self, schema, relax_additional_properties=False, def __init__(self, schema, relax_additional_properties=False,
is_body=True): is_body=True):

View File

@ -548,9 +548,9 @@ class IntegerTestCase(APIValidationTestCase):
self.check_validation_error(self.post, body={'foo': '0xffff'}, self.check_validation_error(self.post, body={'foo': '0xffff'},
expected_detail=detail) expected_detail=detail)
detail = ("Invalid input for field/attribute foo. Value: 1.0." detail = ("Invalid input for field/attribute foo. Value: 1.01."
" 1.0 is not of type 'integer', 'string'") " 1.01 is not of type 'integer', 'string'")
self.check_validation_error(self.post, body={'foo': 1.0}, self.check_validation_error(self.post, body={'foo': 1.01},
expected_detail=detail) expected_detail=detail)
detail = ("Invalid input for field/attribute foo. Value: 1.0." detail = ("Invalid input for field/attribute foo. Value: 1.0."