From 498be1107120dd7a9a8df5443b74689fbe95f61a Mon Sep 17 00:00:00 2001 From: Michal Cmarada Date: Wed, 23 Jan 2019 11:41:26 +0100 Subject: Update ncclient examples - added optional parameter host for copy_config, get_config and edit-config. - added basic tests for interfaces: - loopback interface - af-packet interface - tap interface - added diff_xml.py to find differences between two sets of config. It supports both full xml comparison and comparison based on xPath - added example diff between running and candidate config (interfaces) - fixed formatting and namespaces Change-Id: If6dd7a76fab538735ab92c67f9457326fbcba7ec Signed-off-by: Michal Cmarada --- examples/ncclient/acl/config_acl.xml | 196 ++++++++++---------- examples/ncclient/acl/config_acl_update.xml | 204 ++++----------------- examples/ncclient/acl/config_invalid_acl.xml | 6 +- examples/ncclient/acl/expected_config_acl.xml | 196 ++++++++++---------- .../ncclient/acl/expected_config_acl_update.xml | 204 ++++----------------- examples/ncclient/acl/test_acl.sh | 2 +- examples/ncclient/acl/test_acl_update.sh | 4 +- examples/ncclient/bd/config_bd.xml | 8 +- examples/ncclient/bd/expected_config_bd.xml | 8 +- examples/ncclient/bd/test_bd.sh | 2 +- examples/ncclient/copy_config.py | 4 +- examples/ncclient/diff_xml.py | 139 ++++++++++++++ examples/ncclient/edit_config.py | 3 +- examples/ncclient/get_config.py | 16 +- .../candidate_config_af_packet_interface.xml | 86 +++++++++ .../af-packet/edit_config_af_packet_interface.xml | 34 ++++ .../interfaces/af-packet/test_diff_af_packet.sh | 18 ++ .../interfaces/af-packet/test_edit_af_packet.sh | 23 +++ .../loop/candidate_config_loop_interface.xml | 61 ++++++ .../interfaces/loop/edit_config_loop_interface.xml | 33 ++++ .../ncclient/interfaces/loop/test_diff_loopback.sh | 18 ++ .../ncclient/interfaces/loop/test_edit_loopback.sh | 20 ++ .../tap/candidate_config_tap_interface.xml | 77 ++++++++ .../interfaces/tap/edit_config_tap_interface.xml | 34 ++++ examples/ncclient/interfaces/tap/test_diff_tap.sh | 18 ++ examples/ncclient/interfaces/tap/test_edit_tap.sh | 20 ++ examples/ncclient/nat/config_nat.xml | 14 +- examples/ncclient/nat/config_nat_update.xml | 24 +-- examples/ncclient/nat/expected_config_nat.xml | 14 +- .../ncclient/nat/expected_config_nat_update.xml | 24 +-- examples/ncclient/nat/test_nat.sh | 2 +- examples/ncclient/nat/test_nat_update.sh | 4 +- examples/ncclient/test_copy_config.sh | 5 +- examples/ncclient/test_diff_config.sh | 33 ++++ examples/ncclient/test_edit_config.sh | 37 ++++ examples/ncclient/xmldiffs.py | 59 ++++-- 36 files changed, 1057 insertions(+), 593 deletions(-) create mode 100755 examples/ncclient/diff_xml.py create mode 100644 examples/ncclient/interfaces/af-packet/candidate_config_af_packet_interface.xml create mode 100644 examples/ncclient/interfaces/af-packet/edit_config_af_packet_interface.xml create mode 100755 examples/ncclient/interfaces/af-packet/test_diff_af_packet.sh create mode 100755 examples/ncclient/interfaces/af-packet/test_edit_af_packet.sh create mode 100644 examples/ncclient/interfaces/loop/candidate_config_loop_interface.xml create mode 100644 examples/ncclient/interfaces/loop/edit_config_loop_interface.xml create mode 100755 examples/ncclient/interfaces/loop/test_diff_loopback.sh create mode 100755 examples/ncclient/interfaces/loop/test_edit_loopback.sh create mode 100644 examples/ncclient/interfaces/tap/candidate_config_tap_interface.xml create mode 100644 examples/ncclient/interfaces/tap/edit_config_tap_interface.xml create mode 100755 examples/ncclient/interfaces/tap/test_diff_tap.sh create mode 100755 examples/ncclient/interfaces/tap/test_edit_tap.sh create mode 100755 examples/ncclient/test_diff_config.sh create mode 100755 examples/ncclient/test_edit_config.sh diff --git a/examples/ncclient/acl/config_acl.xml b/examples/ncclient/acl/config_acl.xml index ed4d9b4e5..826a83e08 100644 --- a/examples/ncclient/acl/config_acl.xml +++ b/examples/ncclient/acl/config_acl.xml @@ -18,59 +18,53 @@ loop1 for testing purposes - x:loopback - + x:loopback + 00:ff:ff:ff:ff:ff - - - - x:vpp-acl - tcp-acl - - - x:vpp-acl - udp-acl - - - x:vpp-macip-acl - macip-acl - - - - + - macip-acl - x:vpp-macip-acl - + tcp-acl + - macip-rule + tcp-rule - + + + cwr + + + 1 + 5487 + + + 87 + 6745 + + cwr ece urg + + + 192.168.2.1/24 192.168.2.2/32 - aa:aa:aa:aa:aa:aa - ff:00:00:00:00:00 - + - + accept - + + x:vpp-acl - icmp-v6-acl - x:vpp-acl - + icmp-v6-acl + - imcp-v6-rule + imcp-v6-rule - - 2001:0db8:0a0b:12f0:0000:0000:0000:0001/64 - 2001:0db8:0a0b:12f0:0000:0000:0000:0002/48 - + + 8 5 @@ -79,84 +73,77 @@ 3 1 - - + + + + 2001:0db8:0a0b:12f0:0000:0000:0000:0001/64 + 2001:0db8:0a0b:12f0:0000:0000:0000:0002/48 + - + accept - + + x:vpp-acl - udp-acl - x:vpp-acl - + macip-acl + - udp-rule + macip-rule - - 192.168.2.1/24 + + ff:00:00:00:00:00 + aa:aa:aa:aa:aa:aa + + 192.168.2.2/32 - - - 5487 - 1 - - - 6745 - 87 - - - + - + accept - + + x:vpp-macip-acl - tcp-acl - x:vpp-acl - + udp-acl + - tcp-rule + udp-rule - + + + 1 + 5487 + + + 87 + 6745 + + + 192.168.2.1/24 192.168.2.2/32 - - - 5487 - 1 - - - 6745 - 87 - - 1 - 7 - - + - + accept - + + x:vpp-acl - icmp-acl - x:vpp-acl - + icmp-acl + - imcp-rule + imcp-rule - - 192.168.2.1/24 - 192.168.2.2/32 - + + 8 5 @@ -165,14 +152,37 @@ 3 1 - - + + + + 192.168.2.1/24 + 192.168.2.2/32 + - + accept - + + x:vpp-acl - + + + local0 + + + + tcp-acl + + + udp-acl + + + macip-acl + + + + + + diff --git a/examples/ncclient/acl/config_acl_update.xml b/examples/ncclient/acl/config_acl_update.xml index 379e4f42d..5541e1cdb 100644 --- a/examples/ncclient/acl/config_acl_update.xml +++ b/examples/ncclient/acl/config_acl_update.xml @@ -18,188 +18,64 @@ loop1 for testing purposes - x:loopback - + x:loopback + 00:ff:ff:ff:ff:ff - - - - x:vpp-macip-acl - macip-acl - - - loop2 for testing purposes - x:loopback - + x:loopback + aa:ff:ff:ff:ff:ff - - - - x:vpp-acl - tcp-acl2 - - - x:vpp-acl - udp-acl - - - - - - macip-acl - x:vpp-macip-acl - - - macip-rule - - - 192.168.2.2/32 - aa:aa:aa:aa:aa:aa - ff:00:00:00:00:00 - - - - - - - - + - icmp-v6-acl - x:vpp-acl - + tcp-acl + - imcp-v6-rule + tcp-rule - - 2001:0db8:0a0b:12f0:0000:0000:0000:0001/64 - - 2001:0db8:0a0b:12f0:0000:0000:0000:0002/48 - - - 8 - 5 - - - 3 - 1 - - - - - - - - - - - - udp-acl - x:vpp-acl - - - udp-rule - - + + + cwr + + + 1 + 5487 + + + 87 + 6745 + + cwr ece urg + + 192.168.2.1/24 192.168.2.2/32 - - - 5486 - 11 - - - + - + accept - + + x:vpp-acl - - tcp-acl2 - x:vpp-acl - - - tcp-rule - - - 192.168.2.1/24 - 192.168.2.2/32 - - - 5487 - 1 - - - 6745 - 87 - - 1 - 7 - - - - - - - - - - - icmp-acl - x:vpp-acl - - - renamed-imcp-rule - - - 192.168.2.1/24 - 192.168.2.2/32 - - - 8 - 5 - - - 3 - 1 - - - - - - - - - - new-icmp-rule - - - 10.1.1.1/24 - 10.2.2.2/32 - - - 4 - 9 - - - - - - - - - - - + + + loop2 + + + + tcp-acl + + + + + + diff --git a/examples/ncclient/acl/config_invalid_acl.xml b/examples/ncclient/acl/config_invalid_acl.xml index f1ea8035e..215d9a1b7 100644 --- a/examples/ncclient/acl/config_invalid_acl.xml +++ b/examples/ncclient/acl/config_invalid_acl.xml @@ -1,8 +1,8 @@ - + acl0 - ipv4-acl + x:ipv4-acl - + diff --git a/examples/ncclient/acl/expected_config_acl.xml b/examples/ncclient/acl/expected_config_acl.xml index 54e3d914e..a6f40e63e 100644 --- a/examples/ncclient/acl/expected_config_acl.xml +++ b/examples/ncclient/acl/expected_config_acl.xml @@ -33,59 +33,53 @@ loop1 for testing purposes - x:loopback - + x:loopback + 00:ff:ff:ff:ff:ff - - - - x:vpp-acl - tcp-acl - - - x:vpp-acl - udp-acl - - - x:vpp-macip-acl - macip-acl - - - - + - macip-acl - x:vpp-macip-acl - + tcp-acl + - macip-rule + tcp-rule - + + + cwr + + + 1 + 5487 + + + 87 + 6745 + + cwr ece urg + + + 192.168.2.1/24 192.168.2.2/32 - aa:aa:aa:aa:aa:aa - ff:00:00:00:00:00 - + - + accept - + + x:vpp-acl - icmp-v6-acl - x:vpp-acl - + icmp-v6-acl + - imcp-v6-rule + imcp-v6-rule - - 2001:0db8:0a0b:12f0:0000:0000:0000:0001/64 - 2001:0db8:0a0b:12f0:0000:0000:0000:0002/48 - + + 8 5 @@ -94,84 +88,77 @@ 3 1 - - + + + + 2001:0db8:0a0b:12f0:0000:0000:0000:0001/64 + 2001:0db8:0a0b:12f0:0000:0000:0000:0002/48 + - + accept - + + x:vpp-acl - udp-acl - x:vpp-acl - + macip-acl + - udp-rule + macip-rule - - 192.168.2.1/24 + + ff:00:00:00:00:00 + aa:aa:aa:aa:aa:aa + + 192.168.2.2/32 - - - 5487 - 1 - - - 6745 - 87 - - - + - + accept - + + x:vpp-macip-acl - tcp-acl - x:vpp-acl - + udp-acl + - tcp-rule + udp-rule - + + + 1 + 5487 + + + 87 + 6745 + + + 192.168.2.1/24 192.168.2.2/32 - - - 5487 - 1 - - - 6745 - 87 - - 1 - 7 - - + - + accept - + + x:vpp-acl - icmp-acl - x:vpp-acl - + icmp-acl + - imcp-rule + imcp-rule - - 192.168.2.1/24 - 192.168.2.2/32 - + + 8 5 @@ -180,14 +167,37 @@ 3 1 - - + + + + 192.168.2.1/24 + 192.168.2.2/32 + - + accept - + + x:vpp-acl - + + + local0 + + + + tcp-acl + + + udp-acl + + + macip-acl + + + + + + diff --git a/examples/ncclient/acl/expected_config_acl_update.xml b/examples/ncclient/acl/expected_config_acl_update.xml index eefef19a5..71013b5f0 100644 --- a/examples/ncclient/acl/expected_config_acl_update.xml +++ b/examples/ncclient/acl/expected_config_acl_update.xml @@ -33,188 +33,64 @@ loop1 for testing purposes - x:loopback - + x:loopback + 00:ff:ff:ff:ff:ff - - - - x:vpp-macip-acl - macip-acl - - - loop2 for testing purposes - x:loopback - + x:loopback + aa:ff:ff:ff:ff:ff - - - - x:vpp-acl - tcp-acl2 - - - x:vpp-acl - udp-acl - - - - - - macip-acl - x:vpp-macip-acl - - - macip-rule - - - 192.168.2.2/32 - aa:aa:aa:aa:aa:aa - ff:00:00:00:00:00 - - - - - - - - + - icmp-v6-acl - x:vpp-acl - + tcp-acl + - imcp-v6-rule + tcp-rule - - 2001:0db8:0a0b:12f0:0000:0000:0000:0001/64 - - 2001:0db8:0a0b:12f0:0000:0000:0000:0002/48 - - - 8 - 5 - - - 3 - 1 - - - - - - - - - - - - udp-acl - x:vpp-acl - - - udp-rule - - + + + cwr + + + 1 + 5487 + + + 87 + 6745 + + cwr ece urg + + 192.168.2.1/24 192.168.2.2/32 - - - 5486 - 11 - - - + - + accept - + + x:vpp-acl - - tcp-acl2 - x:vpp-acl - - - tcp-rule - - - 192.168.2.1/24 - 192.168.2.2/32 - - - 5487 - 1 - - - 6745 - 87 - - 1 - 7 - - - - - - - - - - - icmp-acl - x:vpp-acl - - - renamed-imcp-rule - - - 192.168.2.1/24 - 192.168.2.2/32 - - - 8 - 5 - - - 3 - 1 - - - - - - - - - - new-icmp-rule - - - 10.1.1.1/24 - 10.2.2.2/32 - - - 4 - 9 - - - - - - - - - - - + + + loop2 + + + + tcp-acl + + + + + + diff --git a/examples/ncclient/acl/test_acl.sh b/examples/ncclient/acl/test_acl.sh index e55296ebd..f9610695c 100755 --- a/examples/ncclient/acl/test_acl.sh +++ b/examples/ncclient/acl/test_acl.sh @@ -15,4 +15,4 @@ DIR_NAME=$(dirname $0) -${DIR_NAME}/../test_copy_config.sh ${DIR_NAME}/config_acl.xml ${DIR_NAME}/expected_config_acl.xml +${DIR_NAME}/../test_copy_config.sh ${DIR_NAME}/config_acl.xml ${DIR_NAME}/expected_config_acl.xml * diff --git a/examples/ncclient/acl/test_acl_update.sh b/examples/ncclient/acl/test_acl_update.sh index cb62c183e..2a266dbb7 100755 --- a/examples/ncclient/acl/test_acl_update.sh +++ b/examples/ncclient/acl/test_acl_update.sh @@ -15,6 +15,6 @@ DIR_NAME=$(dirname $0) -${DIR_NAME}/../test_copy_config.sh ${DIR_NAME}/config_acl.xml ${DIR_NAME}/expected_config_acl.xml +${DIR_NAME}/../test_copy_config.sh ${DIR_NAME}/config_acl.xml ${DIR_NAME}/expected_config_acl.xml * -${DIR_NAME}/../test_copy_config.sh ${DIR_NAME}/config_acl_update.xml ${DIR_NAME}/expected_config_acl_update.xml +${DIR_NAME}/../test_copy_config.sh ${DIR_NAME}/config_acl_update.xml ${DIR_NAME}/expected_config_acl_update.xml * diff --git a/examples/ncclient/bd/config_bd.xml b/examples/ncclient/bd/config_bd.xml index 17f221b7a..b4e7955df 100644 --- a/examples/ncclient/bd/config_bd.xml +++ b/examples/ncclient/bd/config_bd.xml @@ -17,16 +17,16 @@ loop1 - x:loopback - + x:loopback + 00:ff:ff:ff:ff:ff - + test_bd - + test_bd diff --git a/examples/ncclient/bd/expected_config_bd.xml b/examples/ncclient/bd/expected_config_bd.xml index 3ad69d872..f5aa765b3 100644 --- a/examples/ncclient/bd/expected_config_bd.xml +++ b/examples/ncclient/bd/expected_config_bd.xml @@ -32,16 +32,16 @@ loop1 - x:loopback - + x:loopback + 00:ff:ff:ff:ff:ff - + test_bd - + test_bd diff --git a/examples/ncclient/bd/test_bd.sh b/examples/ncclient/bd/test_bd.sh index 6b3ac8fe2..180d85e48 100755 --- a/examples/ncclient/bd/test_bd.sh +++ b/examples/ncclient/bd/test_bd.sh @@ -15,4 +15,4 @@ DIR_NAME=$(dirname $0) -${DIR_NAME}/../test_copy_config.sh ${DIR_NAME}/config_bd.xml ${DIR_NAME}/expected_config_bd.xml +${DIR_NAME}/../test_copy_config.sh ${DIR_NAME}/config_bd.xml ${DIR_NAME}/expected_config_bd.xml * diff --git a/examples/ncclient/copy_config.py b/examples/ncclient/copy_config.py index f397aaa44..84b7a4a6c 100755 --- a/examples/ncclient/copy_config.py +++ b/examples/ncclient/copy_config.py @@ -15,6 +15,7 @@ import argparse import logging + from ncclient import manager _SOURCE_TEMPLATE = """%s""" @@ -34,6 +35,7 @@ if __name__ == '__main__': argparser = argparse.ArgumentParser(description="Configures VPP using RPC") argparser.add_argument('config_filename', help="name of XML file with element") argparser.add_argument('--verbose', help="increase output verbosity", action="store_true") + argparser.add_argument('--host', default="localhost", help="host/node for which to write element") args = argparser.parse_args() logger = logging.getLogger("hc2vpp.examples.copy_config") @@ -42,4 +44,4 @@ if __name__ == '__main__': else: logging.basicConfig(level=logging.INFO) - _copy_config(args.config_filename) + _copy_config(args.config_filename, host=args.host) diff --git a/examples/ncclient/diff_xml.py b/examples/ncclient/diff_xml.py new file mode 100755 index 000000000..e21773425 --- /dev/null +++ b/examples/ncclient/diff_xml.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python +# +# Copyright (c) 2019 Cisco and/or its affiliates. +# 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. + +""" +Usage: {prog} [OPTION] FILE1 FILE2 xPath + +Compare two XML files, while sorting elements. + +xPath optional parameter +example: + ./{{urn:ietf:params:xml:ns:yang:ietf-interfaces}}interfaces/ + {{urn:ietf:params:xml:ns:yang:ietf-interfaces}}interface[ + {{urn:ietf:params:xml:ns:yang:ietf-interfaces}}name='loop0'] +""" +import os +import re +import subprocess +import sys +from tempfile import NamedTemporaryFile +from xml.etree import ElementTree +from xml.etree.ElementTree import Element + +TAG_PATTERN = re.compile(r"""({(?P[a-zA-Z0-9.:@\-/]+)}(?P[0-9a-zA-Z\-]+))|(?P[0-9a-zA-Z\-]+)""", + re.VERBOSE) +PREFIX_PATTERN = re.compile(r"""(((urn)|(.+://))[a-zA-Z0-9.:@\-/]+[:/](?P[0-9a-zA-Z\-]+))""", re.VERBOSE) + +if sys.version_info < (3, 0): + # Python 2 + import codecs + + def unicode_writer(fp): + return codecs.getwriter('utf-8')(fp) +else: + # Python 3 + def unicode_writer(fp): + return fp + + +def print_usage(program): + print(__doc__.format(prog=program).strip()) + + +def parse_namespace(namespace): + """ + Extracts module name fom namespace. + example: + urn:ietf:params:xml:ns:yang:ietf-nat -> ietf-nat + http://fd.io/hc2vpp/yang/vpp-fib-table-management -> vpp-fib-table-management + https://fd.io/hc2vpp/yang/vpp-fib-table-management -> vpp-fib-table-management + :param namespace: namespace in urn or http format + :return: module name from namespace + """ + matcher = PREFIX_PATTERN.match(namespace) + if matcher.group("prefix"): + return matcher.group("prefix").lower() + + +def sort(xml_element): + """ + Sorts elements in xml in alphabetical order. + :param xml_element: root element of xml + """ + if not isinstance(xml_element, Element): + exit(-1) + xml_element[:] = sorted(xml_element, key=lambda child: child.tag) + + mo = TAG_PATTERN.match(xml_element.tag) + if mo.group("namespace") and mo.group("tag") and not mo.group("namespace").__contains__( + "urn:ietf:params:xml:ns:netconf:base:1.0"): + ElementTree.register_namespace(parse_namespace(mo.group("namespace")), mo.group("namespace")) + + for element in xml_element: + sort(element) + + +def diff_xml(xml1, xml2, xpath): + """ + Resolves differences between two xml files. + :param xml1: input file left side (original) + :param xml2: input file right side (to compare with) + :param xpath: xpath of element to read. example: + ./{urn:ietf:params:xml:ns:yang:ietf-interfaces}interfaces/{ \ + urn:ietf:params:xml:ns:yang:ietf-interfaces}interface[{ \ + urn:ietf:params:xml:ns:yang:ietf-interfaces}name='loop0'] + :return: diff of input files + """ + ElementTree.register_namespace("nc", "urn:ietf:params:xml:ns:netconf:base:1.0") + tmp1 = unicode_writer(NamedTemporaryFile('w')) + normalize_xml(tmp1, ElementTree.parse(xml1), xpath) + + tmp2 = unicode_writer(NamedTemporaryFile('w')) + normalize_xml(tmp2, ElementTree.parse(xml2), xpath) + + return subprocess.call(["diff", "-u", "-s", "-d", "--label", xml1, "--label", xml2, tmp1.name, tmp2.name]) + + +def normalize_xml(tmp, tree, xpath): + root = tree.getroot() if (xpath == "*") else tree.getroot().find(xPath) + sort(root) + xml_str = ElementTree.tostring(root, encoding="utf-8", method="xml") + tmp.write(xml_str.decode("utf-8")) + tmp.flush() + # format and normalize output using xmllint + # cmd: xmllint --exc-c14n [file_name] -o [file_name] + subprocess.call(["xmllint", "--format", tmp.name, "-o", tmp.name]) + + +if __name__ == '__main__': + args = sys.argv + prog = os.path.basename(args.pop(0)) + + if '-h' in args or '--help' in args: + print_usage(prog) + exit(0) + + if len(args) < 2: + print_usage(prog) + exit(1) + args.reverse() + file1 = args.pop(-1) + file2 = args.pop(-1) + if len(args) > 2: + xPath = args.pop(-1) + else: + xPath = "*" + + exit(diff_xml(file1, file2, xPath)) diff --git a/examples/ncclient/edit_config.py b/examples/ncclient/edit_config.py index 598770738..a1b148f50 100755 --- a/examples/ncclient/edit_config.py +++ b/examples/ncclient/edit_config.py @@ -40,6 +40,7 @@ if __name__ == '__main__': argparser.add_argument('-c', '--commit', help="commits candidate configuration", action="store_true") argparser.add_argument('--verbose', help="increase output verbosity", action="store_true") + argparser.add_argument('--host', default="localhost", help="host/node for which to write element") args = argparser.parse_args() logger = logging.getLogger("hc2vpp.examples.edit_config") @@ -48,4 +49,4 @@ if __name__ == '__main__': else: logging.basicConfig(level=logging.INFO) - _edit_config(args.config_filename, validate=args.validate, commit=args.commit) + _edit_config(args.config_filename, validate=args.validate, commit=args.commit, host=args.host) diff --git a/examples/ncclient/get_config.py b/examples/ncclient/get_config.py index 631926ebb..3eb4fecd3 100755 --- a/examples/ncclient/get_config.py +++ b/examples/ncclient/get_config.py @@ -34,12 +34,20 @@ if __name__ == '__main__': argparser = argparse.ArgumentParser(description="Obtains VPP configuration using RPC") argparser.add_argument('--reply_filename', help="name of XML file to store received configuration") argparser.add_argument('--verbose', help="increase output verbosity", action="store_true") + argparser.add_argument('--host', default="localhost", help="host/node for which to write element") + argparser.add_argument('--simple', help="decrease output verbosity", action="store_true") args = argparser.parse_args() logger = logging.getLogger("hc2vpp.examples.get_config") - if args.verbose: - logging.basicConfig(level=logging.DEBUG) + + if args.simple: + logging.basicConfig(level=logging.ERROR) else: - logging.basicConfig(level=logging.INFO) + if args.verbose: + logging.basicConfig(level=logging.DEBUG) + else: + logging.basicConfig(level=logging.INFO) + + - _get_config(args.reply_filename) + _get_config(args.reply_filename, host=args.host) diff --git a/examples/ncclient/interfaces/af-packet/candidate_config_af_packet_interface.xml b/examples/ncclient/interfaces/af-packet/candidate_config_af_packet_interface.xml new file mode 100644 index 000000000..dd2a458b1 --- /dev/null +++ b/examples/ncclient/interfaces/af-packet/candidate_config_af_packet_interface.xml @@ -0,0 +1,86 @@ + + + + + + + + 0 + + 0 + + + + + + + + 0 + ipv4 + ipv4-VRF:0 +
+ + 0 + ipv6 + ipv6-VRF:0 +
+
+
+ + + local0 + x:ethernetCsmacd + false + + + GigabitEthernet0/9/0 + x:ethernetCsmacd + false + + 9206 + + + + host-vethAF + VethAF host interface + + vethAF + + +
+ 10.2.0.2 + 24 +
+
+ x:af-packet +
+
+ + + false + + + + + 0 + + + + false + +
+ diff --git a/examples/ncclient/interfaces/af-packet/edit_config_af_packet_interface.xml b/examples/ncclient/interfaces/af-packet/edit_config_af_packet_interface.xml new file mode 100644 index 000000000..f8c43673f --- /dev/null +++ b/examples/ncclient/interfaces/af-packet/edit_config_af_packet_interface.xml @@ -0,0 +1,34 @@ + + + + + + host-vethAF + VethAF host interface + + vethAF + + x:af-packet + +
+ 10.2.0.2 + 24 +
+
+
+
+
diff --git a/examples/ncclient/interfaces/af-packet/test_diff_af_packet.sh b/examples/ncclient/interfaces/af-packet/test_diff_af_packet.sh new file mode 100755 index 000000000..8bce3b6fa --- /dev/null +++ b/examples/ncclient/interfaces/af-packet/test_diff_af_packet.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# +# Copyright (c) 2019 Cisco and/or its affiliates. +# 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. + +DIR_NAME=$(dirname $0) + +${DIR_NAME}/../../test_diff_config.sh ${DIR_NAME}/candidate_config_af_packet_interface.xml diff --git a/examples/ncclient/interfaces/af-packet/test_edit_af_packet.sh b/examples/ncclient/interfaces/af-packet/test_edit_af_packet.sh new file mode 100755 index 000000000..058d47825 --- /dev/null +++ b/examples/ncclient/interfaces/af-packet/test_edit_af_packet.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# +# Copyright (c) 2019 Cisco and/or its affiliates. +# 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. + +DIR_NAME=$(dirname $0) + +# create linux side of AF-packet interface +sudo ip link add vethAF type veth peer name vethFA +xPath="./{urn:ietf:params:xml:ns:yang:ietf-interfaces}interfaces/\ +{urn:ietf:params:xml:ns:yang:ietf-interfaces}interface[{urn:ietf:params:xml:ns:yang:ietf-interfaces}name='host-vethAF']" + +${DIR_NAME}/../../test_edit_config.sh ${DIR_NAME}/edit_config_af_packet_interface.xml ${DIR_NAME}/edit_config_af_packet_interface.xml ${xPath} diff --git a/examples/ncclient/interfaces/loop/candidate_config_loop_interface.xml b/examples/ncclient/interfaces/loop/candidate_config_loop_interface.xml new file mode 100644 index 000000000..c477ad288 --- /dev/null +++ b/examples/ncclient/interfaces/loop/candidate_config_loop_interface.xml @@ -0,0 +1,61 @@ + + + + + + 0 + ipv4 + ipv4-VRF:0 +
+ + 0 + ipv6 + ipv6-VRF:0 +
+
+
+ + + local0 + x:ethernetCsmacd + false + + + loop0 + x:loopback + true + +
+ 10.0.0.1 + 24 +
+
+ + +
+
+ + + + 0 + + 0 + + + + + + + false + + + + + 0 + + + + false + +
+ diff --git a/examples/ncclient/interfaces/loop/edit_config_loop_interface.xml b/examples/ncclient/interfaces/loop/edit_config_loop_interface.xml new file mode 100644 index 000000000..9dfeeadb1 --- /dev/null +++ b/examples/ncclient/interfaces/loop/edit_config_loop_interface.xml @@ -0,0 +1,33 @@ + + + + + + loop0 + x:loopback + true + +
+ 10.0.0.1 + 24 +
+
+ + +
+
+
diff --git a/examples/ncclient/interfaces/loop/test_diff_loopback.sh b/examples/ncclient/interfaces/loop/test_diff_loopback.sh new file mode 100755 index 000000000..fdc07ec4a --- /dev/null +++ b/examples/ncclient/interfaces/loop/test_diff_loopback.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# +# Copyright (c) 2019 Cisco and/or its affiliates. +# 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. + +DIR_NAME=$(dirname $0) + +${DIR_NAME}/../../test_diff_config.sh ${DIR_NAME}/candidate_config_loop_interface.xml diff --git a/examples/ncclient/interfaces/loop/test_edit_loopback.sh b/examples/ncclient/interfaces/loop/test_edit_loopback.sh new file mode 100755 index 000000000..757d65609 --- /dev/null +++ b/examples/ncclient/interfaces/loop/test_edit_loopback.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# +# Copyright (c) 2019 Cisco and/or its affiliates. +# 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. + +DIR_NAME=$(dirname $0) +xPath="./{urn:ietf:params:xml:ns:yang:ietf-interfaces}interfaces/\ +{urn:ietf:params:xml:ns:yang:ietf-interfaces}interface[{urn:ietf:params:xml:ns:yang:ietf-interfaces}name='loop0']" + +${DIR_NAME}/../../test_edit_config.sh ${DIR_NAME}/edit_config_loop_interface.xml ${DIR_NAME}/edit_config_loop_interface.xml ${xPath} diff --git a/examples/ncclient/interfaces/tap/candidate_config_tap_interface.xml b/examples/ncclient/interfaces/tap/candidate_config_tap_interface.xml new file mode 100644 index 000000000..7d0a5d667 --- /dev/null +++ b/examples/ncclient/interfaces/tap/candidate_config_tap_interface.xml @@ -0,0 +1,77 @@ + + + + + + + + 0 + ipv4 + ipv4-VRF:0 +
+ + 0 + ipv6 + ipv6-VRF:0 +
+
+
+ + + local0 + x:ethernetCsmacd + false + + + tap1 + TAP 1 test interface + + tap1 + + +
+ 10.1.0.3 + 24 +
+
+ x:tap +
+
+ + + + 0 + + 0 + + + + + + + false + + + + + 0 + + + + false + +
diff --git a/examples/ncclient/interfaces/tap/edit_config_tap_interface.xml b/examples/ncclient/interfaces/tap/edit_config_tap_interface.xml new file mode 100644 index 000000000..4f03ef262 --- /dev/null +++ b/examples/ncclient/interfaces/tap/edit_config_tap_interface.xml @@ -0,0 +1,34 @@ + + + + + + tap1 + TAP 1 test interface + + tap1 + + x:tap + +
+ 10.1.0.3 + 24 +
+
+
+
+
diff --git a/examples/ncclient/interfaces/tap/test_diff_tap.sh b/examples/ncclient/interfaces/tap/test_diff_tap.sh new file mode 100755 index 000000000..6da56f6b1 --- /dev/null +++ b/examples/ncclient/interfaces/tap/test_diff_tap.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# +# Copyright (c) 2019 Cisco and/or its affiliates. +# 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. + +DIR_NAME=$(dirname $0) + +${DIR_NAME}/../../test_diff_config.sh ${DIR_NAME}/candidate_config_tap_interface.xml diff --git a/examples/ncclient/interfaces/tap/test_edit_tap.sh b/examples/ncclient/interfaces/tap/test_edit_tap.sh new file mode 100755 index 000000000..1a752cbf5 --- /dev/null +++ b/examples/ncclient/interfaces/tap/test_edit_tap.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# +# Copyright (c) 2019 Cisco and/or its affiliates. +# 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. + +DIR_NAME=$(dirname $0) +xPath="./{urn:ietf:params:xml:ns:yang:ietf-interfaces}interfaces/\ +{urn:ietf:params:xml:ns:yang:ietf-interfaces}interface[{urn:ietf:params:xml:ns:yang:ietf-interfaces}name='tap1']" + +${DIR_NAME}/../../test_edit_config.sh ${DIR_NAME}/edit_config_tap_interface.xml ${DIR_NAME}/edit_config_tap_interface.xml ${xPath} diff --git a/examples/ncclient/nat/config_nat.xml b/examples/ncclient/nat/config_nat.xml index 74f4020b2..690eb5886 100644 --- a/examples/ncclient/nat/config_nat.xml +++ b/examples/ncclient/nat/config_nat.xml @@ -8,11 +8,11 @@ loop1 for testing purposes - x:loopback - + x:loopback + 01:ff:ff:ff:ff:ff - + true @@ -21,11 +21,11 @@ loop0 for testing purposes - x:loopback - + x:loopback + 00:ff:ff:ff:ff:ff - + true false @@ -45,7 +45,7 @@ 3 10.10.10.1/30 - nat64 + nat64 2 diff --git a/examples/ncclient/nat/config_nat_update.xml b/examples/ncclient/nat/config_nat_update.xml index 96a6e9dbe..ca3c36672 100644 --- a/examples/ncclient/nat/config_nat_update.xml +++ b/examples/ncclient/nat/config_nat_update.xml @@ -8,19 +8,19 @@ loop1 for testing purposes - x:loopback - + x:loopback + 01:ff:ff:ff:ff:ff loop2 for testing purposes - x:loopback - + x:loopback + 02:ff:ff:ff:ff:ff - + true false @@ -30,11 +30,11 @@ loop3 for testing purposes - x:loopback - + x:loopback + 03:ff:ff:ff:ff:ff - + true @@ -43,8 +43,8 @@ loop0 for testing purposes - x:loopback - + x:loopback + 00:ff:ff:ff:ff:ff @@ -61,7 +61,7 @@ 6 1.2.3.4/32 - nat64 + nat64 5 @@ -70,7 +70,7 @@ 3 10.10.10.1/30 - nat64 + nat64 2 diff --git a/examples/ncclient/nat/expected_config_nat.xml b/examples/ncclient/nat/expected_config_nat.xml index f42eddbdb..55d15a274 100644 --- a/examples/ncclient/nat/expected_config_nat.xml +++ b/examples/ncclient/nat/expected_config_nat.xml @@ -23,11 +23,11 @@ loop1 for testing purposes - x:loopback - + x:loopback + 01:ff:ff:ff:ff:ff - + true @@ -36,11 +36,11 @@ loop0 for testing purposes - x:loopback - + x:loopback + 00:ff:ff:ff:ff:ff - + true false @@ -60,7 +60,7 @@ 3 10.10.10.1/30 - nat64 + nat64 2 diff --git a/examples/ncclient/nat/expected_config_nat_update.xml b/examples/ncclient/nat/expected_config_nat_update.xml index cf21408d2..426e6bc79 100644 --- a/examples/ncclient/nat/expected_config_nat_update.xml +++ b/examples/ncclient/nat/expected_config_nat_update.xml @@ -23,19 +23,19 @@ loop1 for testing purposes - x:loopback - + x:loopback + 01:ff:ff:ff:ff:ff loop2 for testing purposes - x:loopback - + x:loopback + 02:ff:ff:ff:ff:ff - + true false @@ -45,11 +45,11 @@ loop3 for testing purposes - x:loopback - + x:loopback + 03:ff:ff:ff:ff:ff - + true @@ -58,8 +58,8 @@ loop0 for testing purposes - x:loopback - + x:loopback + 00:ff:ff:ff:ff:ff @@ -76,7 +76,7 @@ 6 1.2.3.4/32 - nat64 + nat64 5 @@ -85,7 +85,7 @@ 3 10.10.10.1/30 - nat64 + nat64 2 diff --git a/examples/ncclient/nat/test_nat.sh b/examples/ncclient/nat/test_nat.sh index b9ec896ce..37f8047f8 100755 --- a/examples/ncclient/nat/test_nat.sh +++ b/examples/ncclient/nat/test_nat.sh @@ -15,4 +15,4 @@ DIR_NAME=$(dirname $0) -${DIR_NAME}/../test_copy_config.sh ${DIR_NAME}/config_nat.xml ${DIR_NAME}/expected_config_nat.xml +${DIR_NAME}/../test_copy_config.sh ${DIR_NAME}/config_nat.xml ${DIR_NAME}/expected_config_nat.xml * diff --git a/examples/ncclient/nat/test_nat_update.sh b/examples/ncclient/nat/test_nat_update.sh index c5ae446b6..5c6b527a3 100755 --- a/examples/ncclient/nat/test_nat_update.sh +++ b/examples/ncclient/nat/test_nat_update.sh @@ -15,6 +15,6 @@ DIR_NAME=$(dirname $0) -${DIR_NAME}/../test_copy_config.sh ${DIR_NAME}/config_nat.xml ${DIR_NAME}/expected_config_nat.xml +${DIR_NAME}/../test_copy_config.sh ${DIR_NAME}/config_nat.xml ${DIR_NAME}/expected_config_nat.xml * -${DIR_NAME}/../test_copy_config.sh ${DIR_NAME}/config_nat_update.xml ${DIR_NAME}/expected_config_nat_update.xml +${DIR_NAME}/../test_copy_config.sh ${DIR_NAME}/config_nat_update.xml ${DIR_NAME}/expected_config_nat_update.xml * diff --git a/examples/ncclient/test_copy_config.sh b/examples/ncclient/test_copy_config.sh index 2b751d50c..bf70c8260 100755 --- a/examples/ncclient/test_copy_config.sh +++ b/examples/ncclient/test_copy_config.sh @@ -15,6 +15,7 @@ # # $1 config element for RPC # $2 expected running config +# $3 xPath to verify config against DIR_NAME=$(dirname $0) @@ -23,10 +24,10 @@ ${DIR_NAME}/get_config.py --reply_filename _actual_config.xml # fixme: find better xml comparison tool # xmldiffs does not work well when difference occurs on deep level -${DIR_NAME}/xmldiffs.py $2 _actual_config.xml +${DIR_NAME}/xmldiffs.py $2 _actual_config.xml $3 ret_code=$? -if [ $ret_code == 0 ]; then +if [[ ${ret_code} == 0 ]]; then echo " successful" rm _actual_config.xml exit 0 diff --git a/examples/ncclient/test_diff_config.sh b/examples/ncclient/test_diff_config.sh new file mode 100755 index 000000000..9180064c2 --- /dev/null +++ b/examples/ncclient/test_diff_config.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# +# Copyright (c) 2019 Cisco and/or its affiliates. +# 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. +# +# $1 candidate config element to diff against actual config +# $2 xPath to verify config against + +DIR_NAME=$(dirname $0) + +${DIR_NAME}/get_config.py --reply_filename _actual_config.xml --simple + +echo "Differences in running and candidate config:" + +${DIR_NAME}/diff_xml.py $1 _actual_config.xml $2 +ret_code=$? + +if [[ ${ret_code} == 0 ]]; then + exit 0 +fi +rm _actual_config.xml +echo "finished." +exit 0 diff --git a/examples/ncclient/test_edit_config.sh b/examples/ncclient/test_edit_config.sh new file mode 100755 index 000000000..a13570933 --- /dev/null +++ b/examples/ncclient/test_edit_config.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# +# Copyright (c) 2019 Cisco and/or its affiliates. +# 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. +# +# $1 config element for RPC +# $2 expected running config +# $3 xPath to verify config against + +DIR_NAME=$(dirname $0) + +${DIR_NAME}/edit_config.py $1 -c +${DIR_NAME}/get_config.py --reply_filename _actual_config.xml + +# fixme: find better xml comparison tool +# xmldiffs does not work well when difference occurs on deep level +${DIR_NAME}/xmldiffs.py $2 _actual_config.xml $3 +ret_code=$? + +if [[ ${ret_code} == 0 ]]; then + echo " successful" + rm _actual_config.xml + exit 0 +fi + +echo " failed" +exit 1 diff --git a/examples/ncclient/xmldiffs.py b/examples/ncclient/xmldiffs.py index b78fa8fc9..6e43b3f3c 100755 --- a/examples/ncclient/xmldiffs.py +++ b/examples/ncclient/xmldiffs.py @@ -1,40 +1,53 @@ #!/usr/bin/env python """ -Usage: {prog} [OPTION] FILE1 FILE2 +Usage: {prog} [OPTION] FILE1 FILE2 xPath Compare two XML files, ignoring element and attribute order. +xPath a valid path should be defined or wildcard "*" should be used. +example: + ./{{urn:ietf:params:xml:ns:yang:ietf-interfaces}}interfaces/ + {{urn:ietf:params:xml:ns:yang:ietf-interfaces}}interface[ + {{urn:ietf:params:xml:ns:yang:ietf-interfaces}}name='loop0'] + Any extra options are passed to the `diff' command. Copyright (c) 2017, Johannes H. Jensen. License: BSD, see LICENSE for more details. """ from __future__ import print_function, unicode_literals -import sys + import os -import io +import subprocess +import sys import xml.etree.ElementTree as ET from tempfile import NamedTemporaryFile -import subprocess + def attr_str(k, v): - return "{}=\"{}\"".format(k,v) + return "{}=\"{}\"".format(k, v) + def node_str(n): attrs = sorted(n.attrib.items()) - astr = " ".join(attr_str(k,v) for k,v in attrs) + astr = " ".join(attr_str(k, v) for k, v in attrs) s = n.tag if astr: s += " " + astr return s + def node_key(n): return node_str(n) + def indent(s, level): return " " * level + s + def write_sorted(stream, node, level=0): + if node is None: + return children = node.getchildren() text = (node.text or "").strip() tail = (node.tail or "").strip() @@ -57,9 +70,11 @@ def write_sorted(stream, node, level=0): if tail: stream.write(indent(tail + "\n", level)) + if sys.version_info < (3, 0): # Python 2 import codecs + def unicode_writer(fp): return codecs.getwriter('utf-8')(fp) else: @@ -67,27 +82,37 @@ else: def unicode_writer(fp): return fp -def xmldiffs(file1, file2, diffargs=["-u"]): + +def xmldiffs(file1, file2, xpath="*", diffargs=["-u"]): tree = ET.parse(file1) tmp1 = unicode_writer(NamedTemporaryFile('w')) - write_sorted(tmp1, tree.getroot()) + if xpath == "*": + write_sorted(tmp1, tree.getroot()) + else: + write_sorted(tmp1, tree.getroot().find(xpath)) + tmp1.flush() tree = ET.parse(file2) tmp2 = unicode_writer(NamedTemporaryFile('w')) - write_sorted(tmp2, tree.getroot()) + if xpath == "*": + write_sorted(tmp2, tree.getroot()) + else: + write_sorted(tmp2, tree.getroot().find(xpath)) tmp2.flush() - args = [ "diff" ] + args = ["diff"] args += diffargs - args += [ "--label", file1, "--label", file2 ] - args += [ tmp1.name, tmp2.name ] + args += ["--label", file1, "--label", file2] + args += [tmp1.name, tmp2.name] return subprocess.call(args) + def print_usage(prog): print(__doc__.format(prog=prog).strip()) + if __name__ == '__main__': args = sys.argv prog = os.path.basename(args.pop(0)) @@ -96,12 +121,16 @@ if __name__ == '__main__': print_usage(prog) exit(0) - if len(args) < 2: + if len(args) < 3: print_usage(prog) exit(1) + xPath = args.pop(-1) file2 = args.pop(-1) file1 = args.pop(-1) - diffargs = args if args else ["-u"] - exit(xmldiffs(file1, file2, diffargs)) + xPath = xPath if xPath else "*" + + diffargs = args if args else ["-u", "-s"] + + exit(xmldiffs(file1, file2, xPath, diffargs)) -- cgit 1.2.3-korg