Last active
October 14, 2023 16:39
-
-
Save ryanmerolle/f76677a6070ce56e197c8446b26d1f13 to your computer and use it in GitHub Desktop.
netaddr jsonschema validators
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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