************* Library Usage ************* .. testsetup:: import os os.chdir("../examples") For better understanding, look at the :ref:`examples` and `Yangson library `_ ======= Yangson ======= `Yangson `_ is a Python3 library for working with JSON-encoded [RFC7951]_ configuration and state data modelled using the YANG [RFC7895]_ data modelling language. Here `Yangson` is used to work with data model and validate loaded Json data against it. Import necessary python modules. .. doctest:: >>> from json import load >>> from yangson.datamodel import DataModel Initialize the YANG data model. It can be done easily by reading YANG library data [RFC7895]_ from a file: .. doctest:: >>> model = DataModel.from_file('../yang-modules/yanglib.json', ["../yang-modules"]) Load data from Json-encoded file [RFC7951]_ .. doctest:: >>> with open('example-data.json') as infile: ... ri = load(infile) >>> json_data = model.from_raw(ri) Validate data against the data model: .. doctest:: >>> json_data.validate() >>> json_data = json_data.add_defaults() Now the data are valid and you can work with it. --------------------------------------------------------- ============== Resolvers-YANG ============== YANG modules ^^^^^^^^^^^^ :: yang-modules/ ├── cznic-deckard.yang ├── cznic-deckard.yinx ├── cznic-dns-parameters.yang ├── cznic-dns-parameters.yinx ├── cznic-dns-rdata.yang ├── cznic-dns-rdata.yinx ├── cznic-resolver-common.yang ├── cznic-resolver-common.yinx ├── cznic-resolver-knot.yang ├── cznic-resolver-knot.yinx ├── cznic-resolver-unbound.yang ├── cznic-resolver-unbound.yinx ├── iana-dns-class-rr-type.yang ├── ietf-inet-types@2013-07-15.yang ├── ietf-netconf-acm@2012-02-22.yang ├── ietf-yang-library@2016-06-21.yang ├── ietf-yang-types@2013-07-15.yang ├── Makefile ├── model.tree ├── yanglib-deckard.json └── yanglib.json Library ^^^^^^^ :: resolvers_yang/ ├── __init__.py ├── kresd/ │   ├── __init__.py │   └── kresd_conf_gen.py ├── unbound/ | ├── __init__.py | ├── unbound_conf_gen.py | └── unbound_conf_loader.py ├── errors.py ├── parser.py └── regex.py Knot-Resolver modules --------------------- ^^^^^^^^^^^^^^^^^ kresd_conf_gen.py ^^^^^^^^^^^^^^^^^ .. automodule:: kresd.kresd_conf_gen Import ``kresd.kresd_conf_gen`` module which contains ``generate`` function to generate Knot-Resolver configuration strings from valid python dictionary loaded from Json. Returns string. .. doctest:: >>> from resolvers_yang.kresd import kresd_conf_gen .. autofunction:: generate Call ``kresd_conf_gen.generate()`` functions to create kresd_conf string. .. doctest:: >>> kresd_conf = kresd_conf_gen.generate(json_data) >>> print(kresd_conf) # doctest: +NORMALIZE_WHITESPACE net = {'127.0.0.1@53', '::1@53', '198.51.100.1@8853'} net.outgoing_v6('2001:db8:0:2::1') net.ipv6 = true net.ipv4 = true net.bufsize(4096) user('jetconf','wheel') modules.load('hints') hints.set("localhost 127.0.0.1") hints.set("localhost ::1") hints.set("loopback 127.0.0.1") hints.add_hosts('/etc/hosts') hints.root({['a.root-servers.net'] = {'198.41.0.4', '2001:503:ba3e::2:30'}}) hints.root_file('/etc/resolver/root.hints') mode('strict') option('NO_MINIMIZE', false) reorder_RR(true) option('ALLOW_LOCAL', true) verbose(true) trust_anchors.add('. IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5') trust_anchors.add('. IN DS 20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D') trust_anchors.add('. IN DNSKEY 257 3 8 AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQbSEW0O8gcCjFFVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh/RStIoO8g0NfnfL2MTJRkxoXbfDaUeVPQuYEhg37NZWAJQ9VnMVDxP/VHL496M/QZxkjf5/Efucp2gaDX6RS6CXpoY68LsvPVjR0ZSwzz1apAzvN9dlzEheX7ICJBBtuA6G3LQpzW5hOA2hzCTMjJPJ8LbqF6dsV6DoBQzgul0sGIcGOYl7OyQdXfZ57relSQageu+ipAdTTJ25AsRTAoub8ONGcLmqrAmRLKBP1dfwhYB4N7knNnulqQxA+Uk1ihz0=') trust_anchors.negative = {'bad.example.com', 'worse.example.com'} cache.open(104857600) cache.max_ttl(172800) cache.min_ttl(0) modules.load('prefill') prefill.config({['.'] = {url = 'https://www.internic.net/domain/root.zone', ca_file = '/etc/pki/tls/certs/ca-bundle.crt', interval = 86400}}) modules = {dns64 = '64:ff9b::'} Unbound modules --------------- ^^^^^^^^^^^^^^^^^^^^^^^^ unbound_conf_gen.py ^^^^^^^^^^^^^^^^^^^^^^^^ .. automodule:: unbound.unbound_conf_gen Import ``unbound.unbound_conf_gen`` module which contains ``generate`` function to generate Unbound configuration strings from valid python dictionary loaded from Json. Returns string. .. doctest:: >>> from resolvers_yang.unbound import unbound_conf_gen .. autofunction:: generate Call ``unbound_conf_gen.generate()`` functions to create unbound_conf string. .. doctest:: >>> unbound_conf = unbound_conf_gen.generate(json_data) >>> print(unbound_conf) # doctest: +NORMALIZE_WHITESPACE server: interface: 127.0.0.1@53 interface: ::1@53 interface: 198.51.100.1@8853 outgoing-interface: 2001:db8:0:2::1 do-ip6: yes do-ip4: yes edns-buffer-size: 4096 username: "jetconf" verbosity: 2 trust-anchor: ". IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5" trust-anchor: ". IN DS 20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D" trust-anchor: ". IN DNSKEY 257 3 8 AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQbSEW0O8gcCjFFVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh/RStIoO8g0NfnfL2MTJRkxoXbfDaUeVPQuYEhg37NZWAJQ9VnMVDxP/VHL496M/QZxkjf5/Efucp2gaDX6RS6CXpoY68LsvPVjR0ZSwzz1apAzvN9dlzEheX7ICJBBtuA6G3LQpzW5hOA2hzCTMjJPJ8LbqF6dsV6DoBQzgul0sGIcGOYl7OyQdXfZ57relSQageu+ipAdTTJ25AsRTAoub8ONGcLmqrAmRLKBP1dfwhYB4N7knNnulqQxA+Uk1ihz0=" domain-insecure: "bad.example.com" domain-insecure: "worse.example.com" msg-cache-size: 104857600 cache-max-ttl: 172800 cache-min-ttl: 0 val-override-date: "20181028131530" dns64-prefix: 64:ff9b::/96 root-hints: "/etc/resolver/root.hints" harden-glue: yes qname-minimisation: yes rrset-roundrobin: yes do-not-query-localhost: no stub-zone: name: "stub.example.com" stub-addr: "192.0.2.1@53" stub-zone: name: "stub.example.net" stub-addr: "198.51.100.1@53" ``unbound_conf`` and ``kresd_conf`` are raw strings , which can be save as text files. .. doctest:: >>> with open("unbound.conf", "w") as unb_file: ... unb_file.write(unbound_conf) 1264 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ unbound_conf_loader.py ^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. automodule:: unbound.unbound_conf_loader Import ``unbound.unbound_conf_loader`` class which contains ``load`` function for loading Unbound configuration string to python dictionary, which can be validate against `resolvers-yang` data model and save as Json file. .. doctest:: >>> from resolvers_yang.unbound import unbound_conf_loader .. autofunction:: load Input parameter of ``load`` function is string loaded from ``unbound.conf`` file. Returns python dictionary. .. doctest:: >>> with open("unbound.conf", "r") as unb_file: ... unbconf_data = unb_file.read() Call ``load`` function to load configuration string to dictionary. .. doctest:: >>> json_data = unbound_conf_loader.load(unbconf_data) >>> json_data {'cznic-resolver-common:dns-resolver': {'server': {'user-name': 'jetconf'}, 'network': {'listen-interfaces': [{'name': 'interface0', 'ip-address': '127.0.0.1', 'port': 53}, {'name': 'interface1', 'ip-address': '::1', 'port': 53}, {'name': 'interface2', 'ip-address': '198.51.100.1', 'port': 8853}], 'source-address': {'ipv6': '2001:db8:0:2::1'}, 'udp-payload-size': 4096, 'recursion-transport': {'l2-protocols': 'ipv4 ipv6'}}, 'resolver': {'stub-zones': [{'domain': 'stub.example.com', 'nameserver': '192.0.2.1', 'port': 53}, {'domain': 'stub.example.net', 'nameserver': '198.51.100.1', 'port': 53}], 'options': {'glue-checking': True, 'qname-minimisation': True, 'reorder-rrset': True, 'query-loopback': True}, 'hints': {'root-zone-file': '/etc/resolver/root.hints'}}, 'logging': {'verbosity': 2}, 'dnssec': {'trust-anchors': [{'domain': '.', 'auto-update': True, 'trust-anchor': [{'id': 0, 'ds': {'algorithm': 'RSASHA256', 'digest': '49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5', 'digest-type': 'SHA-256', 'key-tag': 19036}}, {'id': 1, 'ds': {'algorithm': 'RSASHA256', 'digest': 'E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D', 'digest-type': 'SHA-256', 'key-tag': 20326}}, {'id': 2, 'dnskey': {'algorithm': 'RSASHA256', 'flags': 'ZONE SEP', 'protocol': 3, 'public-key': 'AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQbSEW0O8gcCjFFVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh/RStIoO8g0NfnfL2MTJRkxoXbfDaUeVPQuYEhg37NZWAJQ9VnMVDxP/VHL496M/QZxkjf5/Efucp2gaDX6RS6CXpoY68LsvPVjR0ZSwzz1apAzvN9dlzEheX7ICJBBtuA6G3LQpzW5hOA2hzCTMjJPJ8LbqF6dsV6DoBQzgul0sGIcGOYl7OyQdXfZ57relSQageu+ipAdTTJ25AsRTAoub8ONGcLmqrAmRLKBP1dfwhYB4N7knNnulqQxA+Uk1ihz0='}}]}], 'negative-trust-anchors': ['bad.example.com', 'worse.example.com']}, 'cache': {'max-size': 104857600, 'max-ttl': 172800, 'min-ttl': 0}, 'debugging': {'cznic-resolver-unbound:val-override-date': '2018-10-28T13:15:30Z'}, 'dns64': {'prefix': '64:ff9b::/96'}}} ``json_data`` variable is python dictionary, which can be easily validate against data model by ``Yangson`` library and saved to Json-encoded file. .. doctest:: >>> model_data = model.from_raw(json_data) >>> model_data.validate() .. doctest:: >>> from json import dump >>> with open("unbound-data.json", 'w') as json_file: ... dump(json_data, json_file, indent=2, sort_keys=False) .. testcleanup:: os.remove("unbound-data.json") os.remove("unbound.conf") os.chdir("../..")