###################################################################### # Copyright 2015 The Kubernetes Authors All rights reserved. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ###################################################################### """Helper functions for Schema Validation.""" import jsonschema DEFAULT = "default" PROPERTIES = "properties" REF = "$ref" REQUIRED = "required" def OnlyValidateProperties(validator_class): """Takes a validator and makes it process only the 'properties' top level. Args: validator_class: A class to add a new validator to Returns: A validator_class that will validate properties against things under the top level "properties" field """ def PropertiesValidator(unused_validator, inputs, instance, schema): if inputs is None: inputs = {} for error in validator_class(schema).iter_errors(instance, inputs): yield error # This makes sure the only keyword jsonschema will validate is 'properties' new_validators = ClearValidatorMap(validator_class.VALIDATORS) new_validators.update({PROPERTIES: PropertiesValidator}) return jsonschema.validators.extend( validator_class, new_validators) def ExtendWithDefault(validator_class): """Takes a validator and makes it set default values on properties. Args: validator_class: A class to add our overridden validators to Returns: A validator_class that will set default values and ignore required fields """ def SetDefaultsInProperties(validator, properties, instance, unused_schema): if properties is None: properties = {} SetDefaults(validator, properties, instance) return jsonschema.validators.extend( validator_class, {PROPERTIES: SetDefaultsInProperties, REQUIRED: IgnoreKeyword}) def SetDefaults(validator, properties, instance): """Populate the default values of properties. Args: validator: A generator that validates the "properties" keyword properties: User properties on which to set defaults instance: Piece of user schema containing "properties" """ if not properties: return for dm_property, subschema in properties.iteritems(): # If the property already has a value, we don't need it's default if dm_property in instance: return # The ordering of these conditions assumes that '$ref' blocks override # all other schema info, which is what the jsonschema library assumes. # If the subschema has a reference, # see if that reference defines a 'default' value if REF in subschema: out = ResolveReferencedDefault(validator, subschema[REF]) instance.setdefault(dm_property, out) # Otherwise, see if the subschema has a 'default' value elif DEFAULT in subschema: instance.setdefault(dm_property, subschema[DEFAULT]) def ResolveReferencedDefault(validator, ref): """Resolves a reference, and returns any default value it defines. Args: validator: A generator the validates the "$ref" keyword ref: The target of the "$ref" keyword Returns: The value of the 'default' field found in the referenced schema, or None """ with validator.resolver.resolving(ref) as resolved: if DEFAULT in resolved: return resolved[DEFAULT] def ClearValidatorMap(validators): """Remaps all JsonSchema validators to make them do nothing.""" ignore_validators = {} for keyword in validators: ignore_validators.update({keyword: IgnoreKeyword}) return ignore_validators def IgnoreKeyword( unused_validator, unused_required, unused_instance, unused_schema): """Validator for JsonSchema that does nothing.""" pass