Merge "[jsonschema] Require specifying additionalProperties
explicitly"
This commit is contained in:
commit
2480e5da0e
@ -79,7 +79,8 @@ class CeilometerSampleGenerator(context.Context):
|
|||||||
"created_at": {
|
"created_at": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"additionalProperties": False
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"batch_size": {
|
"batch_size": {
|
||||||
|
@ -73,12 +73,15 @@ class HeatDataplane(context.Context):
|
|||||||
},
|
},
|
||||||
"files": {
|
"files": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"additionalProperties": True
|
||||||
},
|
},
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"additionalProperties": True
|
||||||
},
|
},
|
||||||
"context_parameters": {
|
"context_parameters": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"additionalProperties": True
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"additionalProperties": False
|
"additionalProperties": False
|
||||||
|
@ -39,7 +39,8 @@ class EC2ServerGenerator(context.Context):
|
|||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"additionalProperties": False
|
||||||
},
|
},
|
||||||
"flavor": {
|
"flavor": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@ -47,7 +48,8 @@ class EC2ServerGenerator(context.Context):
|
|||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"additionalProperties": False
|
||||||
},
|
},
|
||||||
"servers_per_tenant": {
|
"servers_per_tenant": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
|
@ -70,12 +70,13 @@ class ShareNetworks(context.Context):
|
|||||||
"properties": {
|
"properties": {
|
||||||
"use_share_networks": {
|
"use_share_networks": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "specifies whether manila should use share "
|
"description": "Specifies whether manila should use share "
|
||||||
"networks for share creation or not."},
|
"networks for share creation or not."},
|
||||||
|
|
||||||
"share_networks": {
|
"share_networks": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": SHARE_NETWORKS_ARG_DESCR
|
"description": SHARE_NETWORKS_ARG_DESCR,
|
||||||
|
"additionalProperties": True
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"additionalProperties": False
|
"additionalProperties": False
|
||||||
|
@ -48,7 +48,8 @@ class MonascaMetricGenerator(context.Context):
|
|||||||
"url": {
|
"url": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"additionalProperties": False
|
||||||
},
|
},
|
||||||
"metrics_per_tenant": {
|
"metrics_per_tenant": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
@ -65,7 +66,8 @@ class MonascaMetricGenerator(context.Context):
|
|||||||
"value_meta_value": {
|
"value_meta_value": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"additionalProperties": False
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -48,7 +48,8 @@ class Router(context.Context):
|
|||||||
"properties": {
|
"properties": {
|
||||||
"network_id": {"type": "string"},
|
"network_id": {"type": "string"},
|
||||||
"enable_snat": {"type": "boolean"}
|
"enable_snat": {"type": "boolean"}
|
||||||
}
|
},
|
||||||
|
"additionalProperties": False
|
||||||
},
|
},
|
||||||
"network_id": {
|
"network_id": {
|
||||||
"description": "Network ID",
|
"description": "Network ID",
|
||||||
@ -62,7 +63,8 @@ class Router(context.Context):
|
|||||||
"properties": {
|
"properties": {
|
||||||
"ip_address": {"type": "string"},
|
"ip_address": {"type": "string"},
|
||||||
"subnet_id": {"type": "string"}
|
"subnet_id": {"type": "string"}
|
||||||
}
|
},
|
||||||
|
"additionalProperties": False,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"distributed": {
|
"distributed": {
|
||||||
|
@ -32,7 +32,8 @@ class Lbaas(context.Context):
|
|||||||
"$schema": consts.JSON_SCHEMA,
|
"$schema": consts.JSON_SCHEMA,
|
||||||
"properties": {
|
"properties": {
|
||||||
"pool": {
|
"pool": {
|
||||||
"type": "object"
|
"type": "object",
|
||||||
|
"additionalProperties": True
|
||||||
},
|
},
|
||||||
"lbaas_version": {
|
"lbaas_version": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
|
@ -38,14 +38,16 @@ class ServerGenerator(context.Context):
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": {"type": "string"}
|
"name": {"type": "string"}
|
||||||
}
|
},
|
||||||
|
"additionalProperties": False
|
||||||
},
|
},
|
||||||
"flavor": {
|
"flavor": {
|
||||||
"description": "Name of flavor to boot server(s) with.",
|
"description": "Name of flavor to boot server(s) with.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": {"type": "string"}
|
"name": {"type": "string"}
|
||||||
}
|
},
|
||||||
|
"additionalProperties": False
|
||||||
},
|
},
|
||||||
"servers_per_tenant": {
|
"servers_per_tenant": {
|
||||||
"description": "Number of servers to boot in each Tenant.",
|
"description": "Number of servers to boot in each Tenant.",
|
||||||
@ -60,11 +62,18 @@ class ServerGenerator(context.Context):
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"description": "List of networks to attach to server.",
|
"description": "List of networks to attach to server.",
|
||||||
"items": {"oneOf": [
|
"items": {"oneOf": [
|
||||||
{"type": "object",
|
{
|
||||||
"properties": {"net-id": {"type": "string"}},
|
"type": "object",
|
||||||
"description": "Network ID in a format like OpenStack API"
|
"properties": {"net-id": {"type": "string"}},
|
||||||
" expects to see."},
|
"description": "Network ID in a format like OpenStack "
|
||||||
{"type": "string", "description": "Network ID."}]},
|
"API expects to see.",
|
||||||
|
"additionalProperties": False
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Network ID."
|
||||||
|
}
|
||||||
|
]},
|
||||||
"minItems": 1
|
"minItems": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -77,10 +77,12 @@ class SaharaCluster(context.Context):
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_configs": {
|
"node_configs": {
|
||||||
"type": "object"
|
"type": "object",
|
||||||
|
"additionalProperties": True
|
||||||
},
|
},
|
||||||
"cluster_configs": {
|
"cluster_configs": {
|
||||||
"type": "object"
|
"type": "object",
|
||||||
|
"additionalProperties": True
|
||||||
},
|
},
|
||||||
"enable_anti_affinity": {
|
"enable_anti_affinity": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
@ -34,6 +34,7 @@ class ProfilesGenerator(context.Context):
|
|||||||
},
|
},
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"additionalProperties": True,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": False,
|
"additionalProperties": False,
|
||||||
|
@ -55,7 +55,8 @@ class BaseCustomImageGenerator(context.Context):
|
|||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"additionalProperties": False
|
||||||
},
|
},
|
||||||
"flavor": {
|
"flavor": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@ -63,7 +64,8 @@ class BaseCustomImageGenerator(context.Context):
|
|||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"additionalProperties": False
|
||||||
},
|
},
|
||||||
"username": {
|
"username": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
@ -49,7 +49,8 @@ class AuditTemplateGenerator(context.Context):
|
|||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"additionalProperties": False
|
||||||
},
|
},
|
||||||
"strategy": {
|
"strategy": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@ -57,9 +58,11 @@ class AuditTemplateGenerator(context.Context):
|
|||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"additionalProperties": False
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"additionalProperties": False,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
import json
|
||||||
|
|
||||||
from rally.common.plugin import plugin
|
from rally.common.plugin import plugin
|
||||||
from rally import plugins
|
from rally import plugins
|
||||||
@ -35,9 +36,10 @@ class ConfigSchemasTestCase(test.TestCase):
|
|||||||
def fail(self, p, schema, msg):
|
def fail(self, p, schema, msg):
|
||||||
super(ConfigSchemasTestCase, self).fail(
|
super(ConfigSchemasTestCase, self).fail(
|
||||||
"Config schema of plugin '%s' (%s) is invalid. %s "
|
"Config schema of plugin '%s' (%s) is invalid. %s "
|
||||||
"(Schema: %s)" % (p.get_name(),
|
"Schema: \n%s" % (p.get_name(),
|
||||||
"%s.%s" % (p.__module__, p.__name__),
|
"%s.%s" % (p.__module__, p.__name__),
|
||||||
msg, schema))
|
msg,
|
||||||
|
json.dumps(schema, indent=3)))
|
||||||
|
|
||||||
def _check_anyOf_or_oneOf(self, p, schema, definitions):
|
def _check_anyOf_or_oneOf(self, p, schema, definitions):
|
||||||
if "anyOf" in schema or "oneOf" in schema:
|
if "anyOf" in schema or "oneOf" in schema:
|
||||||
@ -61,6 +63,11 @@ class ConfigSchemasTestCase(test.TestCase):
|
|||||||
if unexpected_keys:
|
if unexpected_keys:
|
||||||
self.fail(p, schema, ("Found unexpected key(s) for object type: "
|
self.fail(p, schema, ("Found unexpected key(s) for object type: "
|
||||||
"%s." % ", ".join(unexpected_keys)))
|
"%s." % ", ".join(unexpected_keys)))
|
||||||
|
if "additionalProperties" not in schema:
|
||||||
|
self.fail(p, schema,
|
||||||
|
"'additionalProperties' is required field for objects. "
|
||||||
|
"Specify `'additionalProperties': True` explicitly to "
|
||||||
|
"accept not validated properties.")
|
||||||
|
|
||||||
if "patternProperties" in schema:
|
if "patternProperties" in schema:
|
||||||
if "properties" in schema:
|
if "properties" in schema:
|
||||||
@ -147,7 +154,7 @@ class ConfigSchemasTestCase(test.TestCase):
|
|||||||
pass
|
pass
|
||||||
elif schema == {}:
|
elif schema == {}:
|
||||||
# NOTE(andreykurilin): an empty dict means that the user can
|
# NOTE(andreykurilin): an empty dict means that the user can
|
||||||
# transmit whatever he want in whatever he want format. It is
|
# transmit whatever he wants in whatever he wants format. It is
|
||||||
# not the case which we want to support.
|
# not the case which we want to support.
|
||||||
self.fail(p, schema, "Empty schema is not allowed.")
|
self.fail(p, schema, "Empty schema is not allowed.")
|
||||||
elif "$ref" in schema:
|
elif "$ref" in schema:
|
||||||
@ -161,7 +168,7 @@ class ConfigSchemasTestCase(test.TestCase):
|
|||||||
@plugins.ensure_plugins_are_loaded
|
@plugins.ensure_plugins_are_loaded
|
||||||
def test_schema_is_valid(self):
|
def test_schema_is_valid(self):
|
||||||
for p in plugin.Plugin.get_all():
|
for p in plugin.Plugin.get_all():
|
||||||
if not hasattr(p, "CONFIG_SCHEMA"):
|
if not hasattr(p, "CONFIG_SCHEMA") or "tests.unit" in p.__module__:
|
||||||
continue
|
continue
|
||||||
# allow only top level definitions
|
# allow only top level definitions
|
||||||
definitions = p.CONFIG_SCHEMA.get("definitions", {})
|
definitions = p.CONFIG_SCHEMA.get("definitions", {})
|
||||||
|
Loading…
Reference in New Issue
Block a user