Skip to content

Instantly share code, notes, and snippets.

@ryanmerolle
Last active October 14, 2023 16:39
Show Gist options
  • Save ryanmerolle/f76677a6070ce56e197c8446b26d1f13 to your computer and use it in GitHub Desktop.
Save ryanmerolle/f76677a6070ce56e197c8446b26d1f13 to your computer and use it in GitHub Desktop.
netaddr jsonschema validators
#!/usr/bin/env python3
from jsonschema import Draft7Validator, exceptions
import netaddr
# Define the custom validators
def validate_ipv4(validator, ipv4, instance, schema):
try:
ip = netaddr.IPAddress(instance, version=4)
if 'ipv4WithPrefix' in schema and schema['ipv4WithPrefix']:
raise exceptions.ValidationError(f"{instance} should not be a plain IPv4 address when prefix length is expected.")
except netaddr.AddrFormatError:
yield exceptions.ValidationError(f"{instance} is not a valid IPv4 address.")
def validate_ipv4_network(validator, ipv4_network, instance, schema):
try:
net = netaddr.IPNetwork(instance, version=4)
if net.ip != net.network:
raise exceptions.ValidationError(f"{instance} is not a valid IPv4 network address.")
except netaddr.AddrFormatError:
yield exceptions.ValidationError(f"{instance} is not a valid IPv4 network address.")
def validate_multicast(validator, multicast, instance, schema):
ip = netaddr.IPAddress(instance)
if not ip.is_multicast():
yield exceptions.ValidationError(f"{instance} is not a multicast address.")
def validate_public(validator, public, instance, schema):
ip = netaddr.IPAddress(instance)
if not ip.is_unicast() or ip.is_private():
yield exceptions.ValidationError(f"{instance} is not a public address.")
def validate_private(validator, private, instance, schema):
ip = netaddr.IPAddress(instance)
if not ip.is_private():
yield exceptions.ValidationError(f"{instance} is not a private address.")
def validate_ipv4_with_prefix(validator, ipv4_with_prefix, instance, schema):
try:
ip = netaddr.IPNetwork(instance, version=4)
if ip.ip == ip.network:
raise exceptions.ValidationError(f"{instance} is a plain IPv4 network address. An IPv4 address with prefix length was expected.")
except netaddr.AddrFormatError:
yield exceptions.ValidationError(f"{instance} is not a valid IPv4 address with prefix length.")
# Add the custom validators to the meta-schema
Draft7Validator.VALIDATORS.update({
"ipv4": validate_ipv4,
"ipv4Network": validate_ipv4_network,
"multicast": validate_multicast,
"public": validate_public,
"private": validate_private,
"ipv4WithPrefix": validate_ipv4_with_prefix
})
# Define the schema using allOf
schema_example = {
"type": "string",
"allOf": [
{"ipv4": True},
{"public": True},
{"multicast": True},
]
}
# Create validator instance
validator_example = Draft7Validator(schema_example)
# Validate some examples
examples = ["192.168.1.1", "8.8.8.8", "224.0.0.1", "2001:db8:3333:4444:5555:6666:7777:8888"]
for example in examples:
for error in validator_example.iter_errors(example):
print(f"Validation Error - {error.message}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment