Merge "Clean up DMaaP BusController SSL CSIT warnings"
[integration/csit.git] / scripts / sdnc / netconf-pnp-simulator / netconf-config / subscriber.py
1 #!/usr/bin/env python3
2
3 __author__ = "Mislav Novakovic <mislav.novakovic@sartura.hr>"
4 __copyright__ = "Copyright 2018, Deutsche Telekom AG"
5 __license__ = "Apache 2.0"
6
7 # Licensed under the Apache License, Version 2.0 (the "License");
8 # you may not use this file except in compliance with the License.
9 # You may obtain a copy of the License at
10 #
11 #     http://www.apache.org/licenses/LICENSE-2.0
12 #
13 # Unless required by applicable law or agreed to in writing, software
14 # distributed under the License is distributed on an "AS IS" BASIS,
15 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 # See the License for the specific language governing permissions and
17 # limitations under the License.
18
19 # This sample application demonstrates use of Python programming language bindings for sysrepo library.
20 # Original c application was rewritten in Python to show similarities and differences
21 # between the two.
22 #
23 # Most notable difference is in the very different nature of languages, c is weakly statically typed language
24 # while Python is strongly dynamically typed. Python code is much easier to read and logic easier to comprehend
25 # for smaller scripts. Memory safety is not an issue but lower performance can be expected.
26 #
27 # The original c implementation is also available in the source, so one can refer to it to evaluate trade-offs.
28
29 import sysrepo as sr
30 import sys
31
32
33 # Helper function for printing changes given operation, old and new value.
34 def print_change(op, old_val, new_val):
35     if op == sr.SR_OP_CREATED:
36         print(f"CREATED: {new_val.to_string()}")
37     elif op == sr.SR_OP_DELETED:
38         print(f"DELETED: {old_val.to_string()}")
39     elif op == sr.SR_OP_MODIFIED:
40         print(f"MODIFIED: {old_val.to_string()} to {new_val.to_string()}")
41     elif op == sr.SR_OP_MOVED:
42         print(f"MOVED: {new_val.xpath()} after {old_val.xpath()}")
43
44
45 # Helper function for printing events.
46 def ev_to_str(ev):
47     if ev == sr.SR_EV_VERIFY:
48         return "verify"
49     elif ev == sr.SR_EV_APPLY:
50         return "apply"
51     elif ev == sr.SR_EV_ABORT:
52         return "abort"
53     else:
54         return "unknown"
55
56
57 # Function to print current configuration state.
58 # It does so by loading all the items of a session and printing them out.
59 def print_current_config(session, module_name):
60     select_xpath = f"/{module_name}:*//*"
61
62     values = session.get_items(select_xpath)
63
64     if values is not None:
65         print("========== BEGIN CONFIG ==========")
66         for i in range(values.val_cnt()):
67             print(values.val(i).to_string(), end='')
68         print("=========== END CONFIG ===========")
69
70
71 # Function to be called for subscribed client of given session whenever configuration changes.
72 def module_change_cb(sess, module_name, event, private_ctx):
73     try:
74         print("========== Notification " + ev_to_str(event) + " =============================================")
75         if event == sr.SR_EV_APPLY:
76             print_current_config(sess, module_name)
77
78         print("========== CHANGES: =============================================")
79
80         change_path = f"/{module_name}:*"
81
82         it = sess.get_changes_iter(change_path)
83
84         while True:
85             change = sess.get_change_next(it)
86             if change is None:
87                 break
88             print_change(change.oper(), change.old_val(), change.new_val())
89
90         print("========== END OF CHANGES =======================================")
91     except Exception as e:
92         print(e)
93
94     return sr.SR_ERR_OK
95
96
97 def main():
98     # Notable difference between c implementation is using exception mechanism for open handling unexpected events.
99     # Here it is useful because `Connection`, `Session` and `Subscribe` could throw an exception.
100     try:
101         module_name = "ietf-interfaces"
102         if len(sys.argv) > 1:
103             module_name = sys.argv[1]
104         else:
105             print("\nYou can pass the module name to be subscribed as the first argument")
106
107         print(f"Application will watch for changes in {module_name}")
108
109         # connect to sysrepo
110         conn = sr.Connection(module_name)
111
112         # start session
113         sess = sr.Session(conn)
114
115         # subscribe for changes in running config */
116         subscribe = sr.Subscribe(sess)
117
118         subscribe.module_change_subscribe(module_name, module_change_cb)
119
120         try:
121             print_current_config(sess, module_name)
122         except Exception as e:
123             print(e)
124
125         print("========== STARTUP CONFIG APPLIED AS RUNNING ==========")
126
127         sr.global_loop()
128
129         print("Application exit requested, exiting.")
130
131     except Exception as e:
132         print(e)
133
134
135 if __name__ == '__main__':
136     main()