From 2e96f3423a2619cd2aa9d188de513723416c15e6 Mon Sep 17 00:00:00 2001 From: Marek Gradzki Date: Wed, 18 Apr 2018 08:19:36 +0200 Subject: HC2VPP-313: examples using nnclient library Shows how to configure VPP using nnclient library. Requires following changes to ODL Netconf (HC2VPP-312): - support: https://git.opendaylight.org/gerrit/#/c/69606/ - various fixes to make ODL Netconf compatible with nnclient: https://git.opendaylight.org/gerrit/#/c/71181/ and ncclient library with the following change: https://github.com/marekgr/ncclient/commit/fbc31b06daf114c11dcb6bf1bcfac9127b2e0062 Change-Id: I3dceb8ead6e6f558a3c76f6c1c3b0ba5f7c52f93 Signed-off-by: Marek Gradzki --- examples/ncclient/Readme.txt | 41 ++++ examples/ncclient/acl/copy_config_acl.xml | 182 ++++++++++++++++++ examples/ncclient/acl/copy_config_acl_update.xml | 209 +++++++++++++++++++++ examples/ncclient/acl/expected_config_acl.xml | 183 ++++++++++++++++++ .../ncclient/acl/expected_config_acl_update.xml | 209 +++++++++++++++++++++ examples/ncclient/acl/test_acl.sh | 18 ++ examples/ncclient/acl/test_acl_update.sh | 20 ++ examples/ncclient/copy_config.py | 39 ++++ examples/ncclient/get.py | 39 ++++ examples/ncclient/get_config.py | 39 ++++ examples/ncclient/nat/copy_config_nat.xml | 82 ++++++++ examples/ncclient/nat/copy_config_nat_update.xml | 103 ++++++++++ examples/ncclient/nat/expected_config_nat.xml | 82 ++++++++ .../ncclient/nat/expected_config_nat_update.xml | 103 ++++++++++ examples/ncclient/nat/test_nat.sh | 18 ++ examples/ncclient/nat/test_nat_update.sh | 20 ++ examples/ncclient/test_copy_config.sh | 36 ++++ examples/ncclient/xmldiffs.py | 107 +++++++++++ 18 files changed, 1530 insertions(+) create mode 100644 examples/ncclient/Readme.txt create mode 100644 examples/ncclient/acl/copy_config_acl.xml create mode 100644 examples/ncclient/acl/copy_config_acl_update.xml create mode 100644 examples/ncclient/acl/expected_config_acl.xml create mode 100644 examples/ncclient/acl/expected_config_acl_update.xml create mode 100755 examples/ncclient/acl/test_acl.sh create mode 100755 examples/ncclient/acl/test_acl_update.sh create mode 100755 examples/ncclient/copy_config.py create mode 100755 examples/ncclient/get.py create mode 100755 examples/ncclient/get_config.py create mode 100644 examples/ncclient/nat/copy_config_nat.xml create mode 100644 examples/ncclient/nat/copy_config_nat_update.xml create mode 100644 examples/ncclient/nat/expected_config_nat.xml create mode 100644 examples/ncclient/nat/expected_config_nat_update.xml create mode 100755 examples/ncclient/nat/test_nat.sh create mode 100755 examples/ncclient/nat/test_nat_update.sh create mode 100755 examples/ncclient/test_copy_config.sh create mode 100755 examples/ncclient/xmldiffs.py diff --git a/examples/ncclient/Readme.txt b/examples/ncclient/Readme.txt new file mode 100644 index 000000000..7e1c54075 --- /dev/null +++ b/examples/ncclient/Readme.txt @@ -0,0 +1,41 @@ +Building +---------- + +1) Custom ODL Oxygen build: +git clone https://git.opendaylight.org/gerrit/netconf +cd netconf +git checkout -b honeycomb +git reset --hard release/oxygen +# copy-config support: +git fetch https://git.opendaylight.org/gerrit/netconf refs/changes/06/69606/1 && git cherry-pick FETCH_HEAD +# ncclient support: +git fetch https://git.opendaylight.org/gerrit/netconf refs/changes/81/71181/1 && git cherry-pick FETCH_HEAD +mvn clean install -pl netconf/netconf-util,netconf/netconf-netty-util,netconf/mdsal-netconf-connector + +2) Build vpp-integration module from hc2vpp project: +cd hc2vpp +mvn clean install -pl vpp-integration/minimal-distribution + +3) (optional) Build honeycomb package +./packaging/deb/xenial/debuild.sh + +4) Build ncclient +git clone -b honeycomb https://github.com/marekgr/ncclient.git +cd ncclient +sudo python setup.py install + + +Running examples +---------- + +ACL: +./acl/test_acl.sh +./acl/test_acl_updates.sh + +NAT: +./acl/test_nat.sh +./acl/test_nat_updates.sh + +Suggestions: +Remember that HC by default persists config and restores it after restart. +You can disable this behaviour using config/honeycomb.json. diff --git a/examples/ncclient/acl/copy_config_acl.xml b/examples/ncclient/acl/copy_config_acl.xml new file mode 100644 index 000000000..d2177d643 --- /dev/null +++ b/examples/ncclient/acl/copy_config_acl.xml @@ -0,0 +1,182 @@ + + + + + + 0 + + + + + + local0 + x:ethernetCsmacd + false + + + loop1 + for testing purposes + 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 + + + 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 + + + imcp-v6-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 + + + 192.168.2.1/24 + 192.168.2.2/32 + + + 5487 + 1 + + + 6745 + 87 + + + + + + + + + + + + tcp-acl + 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 + + + imcp-rule + + + 192.168.2.1/24 + 192.168.2.2/32 + + + 8 + 5 + + + 3 + 1 + + + + + + + + + + + + diff --git a/examples/ncclient/acl/copy_config_acl_update.xml b/examples/ncclient/acl/copy_config_acl_update.xml new file mode 100644 index 000000000..1a30ece94 --- /dev/null +++ b/examples/ncclient/acl/copy_config_acl_update.xml @@ -0,0 +1,209 @@ + + + + + + 0 + + + + + + local0 + x:ethernetCsmacd + false + + + loop1 + for testing purposes + x:loopback + + 00:ff:ff:ff:ff:ff + + + + + x:vpp-macip-acl + macip-acl + + + + + + loop2 + for testing purposes + 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 + + + imcp-v6-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 + + + 192.168.2.1/24 + 192.168.2.2/32 + + + 5486 + 11 + + + + + + + + + + + + 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 + + + + + + + + + + + + diff --git a/examples/ncclient/acl/expected_config_acl.xml b/examples/ncclient/acl/expected_config_acl.xml new file mode 100644 index 000000000..735e0f43d --- /dev/null +++ b/examples/ncclient/acl/expected_config_acl.xml @@ -0,0 +1,183 @@ + + + + + + 0 + + + + + + local0 + x:ethernetCsmacd + false + + + loop1 + for testing purposes + 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 + + + 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 + + + imcp-v6-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 + + + 192.168.2.1/24 + 192.168.2.2/32 + + + 5487 + 1 + + + 6745 + 87 + + + + + + + + + + + + tcp-acl + 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 + + + imcp-rule + + + 192.168.2.1/24 + 192.168.2.2/32 + + + 8 + 5 + + + 3 + 1 + + + + + + + + + + + + diff --git a/examples/ncclient/acl/expected_config_acl_update.xml b/examples/ncclient/acl/expected_config_acl_update.xml new file mode 100644 index 000000000..17f76ff69 --- /dev/null +++ b/examples/ncclient/acl/expected_config_acl_update.xml @@ -0,0 +1,209 @@ + + + + + + 0 + + + + + + local0 + x:ethernetCsmacd + false + + + loop1 + for testing purposes + x:loopback + + 00:ff:ff:ff:ff:ff + + + + + x:vpp-macip-acl + macip-acl + + + + + + loop2 + for testing purposes + 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 + + + imcp-v6-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 + + + 192.168.2.1/24 + 192.168.2.2/32 + + + 5486 + 11 + + + + + + + + + + + + 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 + + + + + + + + + + + + diff --git a/examples/ncclient/acl/test_acl.sh b/examples/ncclient/acl/test_acl.sh new file mode 100755 index 000000000..aedb842af --- /dev/null +++ b/examples/ncclient/acl/test_acl.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# +# Copyright (c) 2018 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_copy_config.sh ${DIR_NAME}/copy_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 new file mode 100755 index 000000000..6dedbfeaa --- /dev/null +++ b/examples/ncclient/acl/test_acl_update.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# +# Copyright (c) 2018 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_copy_config.sh ${DIR_NAME}/copy_config_acl.xml ${DIR_NAME}/expected_config_acl.xml + +${DIR_NAME}/../test_copy_config.sh ${DIR_NAME}/copy_config_acl_update.xml ${DIR_NAME}/expected_config_acl_update.xml diff --git a/examples/ncclient/copy_config.py b/examples/ncclient/copy_config.py new file mode 100755 index 000000000..e2e95c6c2 --- /dev/null +++ b/examples/ncclient/copy_config.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python2 +# +# Copyright (c) 2018 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. + +import argparse +import logging +from ncclient import manager + +_SOURCE_TEMPLATE = """%s""" + + +def _copy_config(config_filename, host='localhost', port=2831, username='admin', password='admin'): + with manager.connect(host=host, port=port, username=username, password=password, hostkey_verify=False) as m: + logger.info("Connected to HC") + with open(config_filename, 'r') as f: + ret = m.copy_config(target='candidate', source=_SOURCE_TEMPLATE % f.read()) + logger.debug("CopyConfig successful:\n%s" % ret) + ret = m.commit() + logger.debug("Commit successful:\n%s", ret) + + +if __name__ == '__main__': + logger = logging.getLogger("hc2vpp.examples.copy_config") + logging.basicConfig(level=logging.WARNING) + argparser = argparse.ArgumentParser(description="Configures VPP using RPC") + argparser.add_argument('config_filename', help="name of XML file with element") + args = argparser.parse_args() + _copy_config(args.config_filename) diff --git a/examples/ncclient/get.py b/examples/ncclient/get.py new file mode 100755 index 000000000..9fe4ab854 --- /dev/null +++ b/examples/ncclient/get.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python2 +# +# Copyright (c) 2018 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. + +import argparse +import logging +from ncclient import manager + + +def _get(reply_filename=None, host='localhost', port=2831, username='admin', password='admin'): + with manager.connect(host=host, port=port, username=username, password=password, hostkey_verify=False) as m: + logger.info("Connected to HC") + state = m.get() + logger.debug("Get successful:\n%s" % state) + if reply_filename: + with open(reply_filename, 'w') as f: + f.write(state.data_xml) + else: + print state.data_xml + + +if __name__ == '__main__': + logger = logging.getLogger("hc2vpp.examples.get") + logging.basicConfig(level=logging.WARNING) + argparser = argparse.ArgumentParser(description="Obtains VPP state data using RPC") + argparser.add_argument('--reply_filename', help="name of XML file to store received state data") + args = argparser.parse_args() + _get(args.reply_filename) diff --git a/examples/ncclient/get_config.py b/examples/ncclient/get_config.py new file mode 100755 index 000000000..5fdb6da3a --- /dev/null +++ b/examples/ncclient/get_config.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python2 +# +# Copyright (c) 2018 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. + +import argparse +import logging +from ncclient import manager + + +def _get_config(reply_filename=None, host='localhost', port=2831, username='admin', password='admin'): + with manager.connect(host=host, port=port, username=username, password=password, hostkey_verify=False) as m: + logger.info("Connected to HC") + config = m.get_config(source='running') + logger.debug("GetConfig successful:\n%s" % config) + if reply_filename: + with open(reply_filename, 'w') as f: + f.write(config.data_xml) + else: + print config.data_xml + + +if __name__ == '__main__': + logger = logging.getLogger("hc2vpp.examples.get_config") + logging.basicConfig(level=logging.WARNING) + argparser = argparse.ArgumentParser(description="Obtains VPP configuration using RPC") + argparser.add_argument('--reply_filename', help="name of XML file to store received configuration") + args = argparser.parse_args() + _get_config(args.reply_filename) diff --git a/examples/ncclient/nat/copy_config_nat.xml b/examples/ncclient/nat/copy_config_nat.xml new file mode 100644 index 000000000..d1441b07f --- /dev/null +++ b/examples/ncclient/nat/copy_config_nat.xml @@ -0,0 +1,82 @@ + + + + + + 0 + + 2 + 172.16.2.123/32 + + + 3 + 10.10.10.1/30 + nat64 + + + 1 + 172.16.2.0/30 + + + + 1 + 10.1.1.3 + static + 6 + + 5678 + + + 1234 + + 2001:db8:85a3::8a2e:370:7334 + + + + 0 + 2001:db8:122:300::/56 + + + + + + + local0 + x:ethernetCsmacd + false + + + loop1 + for testing purposes + x:loopback + + 01:ff:ff:ff:ff:ff + + + + true + + + + + loop0 + for testing purposes + x:loopback + + 00:ff:ff:ff:ff:ff + + + + true + false + + + + + diff --git a/examples/ncclient/nat/copy_config_nat_update.xml b/examples/ncclient/nat/copy_config_nat_update.xml new file mode 100644 index 000000000..6b346cf80 --- /dev/null +++ b/examples/ncclient/nat/copy_config_nat_update.xml @@ -0,0 +1,103 @@ + + + + + + 0 + + 2 + 172.15.2.123/32 + + + 3 + 10.10.10.1/30 + nat64 + + + 5 + 172.16.2.0/30 + + + 6 + 1.2.3.4/32 + nat64 + + + + 1 + 10.1.1.3 + static + 6 + + 5678 + + + 1234 + + 2001:db8:85a3::8a2e:370:7334 + + + + 0 + 2001:db8:122:300::/56 + + + + + + + local0 + x:ethernetCsmacd + false + + + loop3 + for testing purposes + x:loopback + + 03:ff:ff:ff:ff:ff + + + + true + + + + + loop2 + for testing purposes + x:loopback + + 02:ff:ff:ff:ff:ff + + + + true + false + + + + + loop1 + for testing purposes + x:loopback + + 01:ff:ff:ff:ff:ff + + + + loop0 + for testing purposes + x:loopback + + 00:ff:ff:ff:ff:ff + + + + diff --git a/examples/ncclient/nat/expected_config_nat.xml b/examples/ncclient/nat/expected_config_nat.xml new file mode 100644 index 000000000..35a51bc1e --- /dev/null +++ b/examples/ncclient/nat/expected_config_nat.xml @@ -0,0 +1,82 @@ + + + + + + 0 + + 2 + 172.16.2.123/32 + + + 3 + 10.10.10.1/30 + nat64 + + + 1 + 172.16.2.0/30 + + + + 1 + 10.1.1.3 + static + 6 + + 5678 + + + 1234 + + 2001:db8:85a3::8a2e:370:7334 + + + + 0 + 2001:db8:122:300::/56 + + + + + + + local0 + x:ethernetCsmacd + false + + + loop1 + for testing purposes + x:loopback + + 01:ff:ff:ff:ff:ff + + + + true + + + + + loop0 + for testing purposes + x:loopback + + 00:ff:ff:ff:ff:ff + + + + true + false + + + + + diff --git a/examples/ncclient/nat/expected_config_nat_update.xml b/examples/ncclient/nat/expected_config_nat_update.xml new file mode 100644 index 000000000..41891e088 --- /dev/null +++ b/examples/ncclient/nat/expected_config_nat_update.xml @@ -0,0 +1,103 @@ + + + + + + 0 + + 6 + 1.2.3.4/32 + nat64 + + + 5 + 172.16.2.0/30 + + + 2 + 172.15.2.123/32 + + + 3 + 10.10.10.1/30 + nat64 + + + + 1 + 10.1.1.3 + static + 6 + + 5678 + + + 1234 + + 2001:db8:85a3::8a2e:370:7334 + + + + 0 + 2001:db8:122:300::/56 + + + + + + + local0 + x:ethernetCsmacd + false + + + loop1 + for testing purposes + x:loopback + + 01:ff:ff:ff:ff:ff + + + + loop2 + for testing purposes + x:loopback + + 02:ff:ff:ff:ff:ff + + + + true + false + + + + + loop3 + for testing purposes + x:loopback + + 03:ff:ff:ff:ff:ff + + + + true + + + + + loop0 + for testing purposes + x:loopback + + 00:ff:ff:ff:ff:ff + + + + diff --git a/examples/ncclient/nat/test_nat.sh b/examples/ncclient/nat/test_nat.sh new file mode 100755 index 000000000..272a1d6d9 --- /dev/null +++ b/examples/ncclient/nat/test_nat.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# +# Copyright (c) 2018 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_copy_config.sh ${DIR_NAME}/copy_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 new file mode 100755 index 000000000..b37e4c6a9 --- /dev/null +++ b/examples/ncclient/nat/test_nat_update.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# +# Copyright (c) 2018 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_copy_config.sh ${DIR_NAME}/copy_config_nat.xml ${DIR_NAME}/expected_config_nat.xml + +${DIR_NAME}/../test_copy_config.sh ${DIR_NAME}/copy_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 new file mode 100755 index 000000000..2b751d50c --- /dev/null +++ b/examples/ncclient/test_copy_config.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# +# Copyright (c) 2018 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 + +DIR_NAME=$(dirname $0) + +${DIR_NAME}/copy_config.py $1 +${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 +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 new file mode 100755 index 000000000..b78fa8fc9 --- /dev/null +++ b/examples/ncclient/xmldiffs.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python +""" +Usage: {prog} [OPTION] FILE1 FILE2 + +Compare two XML files, ignoring element and attribute order. + +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 xml.etree.ElementTree as ET +from tempfile import NamedTemporaryFile +import subprocess + +def attr_str(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) + 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): + children = node.getchildren() + text = (node.text or "").strip() + tail = (node.tail or "").strip() + + if children or text: + children.sort(key=node_key) + + stream.write(indent("<" + node_str(node) + ">\n", level)) + + if text: + stream.write(indent(text + "\n", level)) + + for child in children: + write_sorted(stream, child, level + 1) + + stream.write(indent("\n", level)) + else: + stream.write(indent("<" + node_str(node) + "/>\n", level)) + + 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: + # Python 3 + def unicode_writer(fp): + return fp + +def xmldiffs(file1, file2, diffargs=["-u"]): + tree = ET.parse(file1) + tmp1 = unicode_writer(NamedTemporaryFile('w')) + write_sorted(tmp1, tree.getroot()) + tmp1.flush() + + tree = ET.parse(file2) + tmp2 = unicode_writer(NamedTemporaryFile('w')) + write_sorted(tmp2, tree.getroot()) + tmp2.flush() + + args = [ "diff" ] + args += diffargs + 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)) + + if '-h' in args or '--help' in args: + print_usage(prog) + exit(0) + + if len(args) < 2: + print_usage(prog) + exit(1) + + file2 = args.pop(-1) + file1 = args.pop(-1) + diffargs = args if args else ["-u"] + + exit(xmldiffs(file1, file2, diffargs)) -- cgit 1.2.3-korg