blob: 35e1f0315696a2b4f2e7a4628e7a812ff723cfd1 [file] [log] [blame]
Radek Krejcia1339602017-11-02 13:52:38 +01001"""
2NETCONF data helper functions
3File: data.py
4Author: Radek Krejci <rkrejci@cesnet.cz>
5"""
6
7import json
8import os
9
Radek Krejci0f793fe2018-02-14 08:33:45 +010010import yang
Radek Krejcia1339602017-11-02 13:52:38 +010011import netconf2 as nc
Radek Krejci38b0a0b2018-08-03 10:17:03 +020012from .schemas import make_schema_key
13
Radek Krejcia1339602017-11-02 13:52:38 +010014
Radek Krejci4d3896c2018-01-08 17:10:43 +010015def infoBuiltInType(base):
16 return {
Radek Krejci6e772b22018-01-25 13:28:57 +010017 - 1 : 'error',
18 0 : 'derived',
19 1 : 'binary',
20 2 : 'bits',
21 3 : 'boolean',
22 4 : 'decimal64',
23 5 : 'empty',
24 6 : 'enumeration',
25 7 : 'identityref',
26 8 : 'instance-identifier',
27 9 : 'leafref',
Radek Krejci4d3896c2018-01-08 17:10:43 +010028 10: 'string',
29 11: 'union',
30 12: 'int8',
31 13: 'uint8',
32 14: 'int16',
33 15: 'uint16',
34 16: 'int32',
35 17: 'uint32',
36 18: 'int64',
37 19: 'uint64',
38 }[base]
39
Radek Krejci6e772b22018-01-25 13:28:57 +010040
41def schemaInfoType(schema, info):
42 info["datatype"] = schema.type().der().name()
43 info["datatypebase"] = infoBuiltInType(schema.type().base())
44
45
Radek Krejcid0ce4cf2018-02-09 14:44:34 +010046def typeValues(type, result):
47 while type.der():
48 if type.base() == 2:
49 # bits
50 if type.info().bits().count():
51 for bit in type.info().bits().bit():
52 result.append(bit.name())
53 elif type.base() == 6:
54 # enumeration
55 if type.info().enums().count():
56 for enm in type.info().enums().enm():
57 result.append(enm.name())
58 else:
59 return result
60 type = type.der().type()
61
62 return result
63
Radek Krejci6e772b22018-01-25 13:28:57 +010064def schemaInfoNode(schema):
65 info = {}
66
67 info["type"] = schema.nodetype()
Radek Krejciad45e572018-02-21 10:54:54 +010068 if schema.module().rev_size():
69 info["module"] = schema.module().name() + '@' + schema.module().rev().date()
70 else:
71 info["module"] = schema.module().name()
Radek Krejci6e772b22018-01-25 13:28:57 +010072 info["name"] = schema.name()
73 info["dsc"] = schema.dsc()
Radek Krejci0f793fe2018-02-14 08:33:45 +010074 info["config"] = True if schema.flags() & yang.LYS_CONFIG_W else False
Radek Krejci6e772b22018-01-25 13:28:57 +010075 if info["type"] == 1:
76 info["presence"] = schema.subtype().presence()
77 info["path"] = schema.path()
78
Radek Krejci0f793fe2018-02-14 08:33:45 +010079 if info["type"] == yang.LYS_LEAF:
Radek Krejci6e772b22018-01-25 13:28:57 +010080 schemaInfoType(schema.subtype(), info)
Radek Krejci6c18e392018-08-23 13:21:29 +020081 info["key"] = False if schema.subtype().is_key() == None else True
Radek Krejci6e772b22018-01-25 13:28:57 +010082 dflt = schema.subtype().dflt()
83 if dflt:
84 info["default"] = dflt
85 else:
86 tpdf = schema.subtype().type().der()
87 while tpdf and not tpdf.dflt():
88 tpdf = tpdf.type().der()
89 if tpdf:
90 info["default"] = tpdf.dflt()
Radek Krejci0f793fe2018-02-14 08:33:45 +010091 elif info["type"] == yang.LYS_LEAFLIST:
Radek Krejci6e772b22018-01-25 13:28:57 +010092 schemaInfoType(schema.subtype(), info)
Radek Krejci010475d2018-03-08 13:14:19 +010093 if schema.flags() & yang.LYS_USERORDERED:
94 info["ordered"] = True;
Radek Krejci0f793fe2018-02-14 08:33:45 +010095 elif info["type"] == yang.LYS_LIST:
Radek Krejci010475d2018-03-08 13:14:19 +010096 if schema.flags() & yang.LYS_USERORDERED:
97 info["ordered"] = True;
Radek Krejci6e772b22018-01-25 13:28:57 +010098 info["keys"] = []
99 for key in schema.subtype().keys():
100 info["keys"].append(key.name())
101
102 return info
103
Radek Krejci4d3896c2018-01-08 17:10:43 +0100104
Radek Krejci30ce1592018-03-01 14:44:14 +0100105def _sortChildren(node):
106 sorted = []
107 for index, item in enumerate(node["children"]):
108 sorted.append(item)
109 if item["info"]["type"] == yang.LYS_LIST:
110 removed = 0
Radek Krejci010475d2018-03-08 13:14:19 +0100111 if "ordered" in item["info"]:
112 item["order"] = removed
Radek Krejci30ce1592018-03-01 14:44:14 +0100113 for i, instance in enumerate(node["children"][index + 1:]):
114 if item["info"]["name"] == instance["info"]["name"] and item["info"]["module"] == instance["info"]["module"]:
115 sorted.append(node["children"].pop(index + 1 + i - removed))
116 removed += 1;
Radek Krejci010475d2018-03-08 13:14:19 +0100117 if "ordered" in item["info"]:
118 instance["order"] = removed
Radek Krejci30ce1592018-03-01 14:44:14 +0100119 if item["info"]["type"] == yang.LYS_LEAFLIST:
120 lastLeafList = len(sorted) - 1
121 item["first"] = True
122 removed = 0
Radek Krejci010475d2018-03-08 13:14:19 +0100123 if "ordered" in item["info"]:
124 item["order"] = removed
Radek Krejci30ce1592018-03-01 14:44:14 +0100125 for i, instance in enumerate(node["children"][index + 1:]):
126 if item["info"]["name"] == instance["info"]["name"] and item["info"]["module"] == instance["info"]["module"]:
127 instance["first"] = False
128 sorted.append(node["children"].pop(index + 1 + i - removed))
129 removed += 1;
Radek Krejci010475d2018-03-08 13:14:19 +0100130 if "ordered" in item["info"]:
131 instance["order"] = removed
Radek Krejci30ce1592018-03-01 14:44:14 +0100132 node["children"] = sorted
133 last = node["children"][len(node["children"]) - 1]
134 if last["info"]["type"] == yang.LYS_LEAFLIST:
135 node["children"][lastLeafList]["last"] = True
136 for item in node["children"][lastLeafList + 1:]:
137 item["lastLeafList"] = True;
138 else:
139 last["last"] = True
140
141
Radek Krejci27134982017-11-10 15:42:00 +0100142def dataInfoNode(node, parent=None, recursion=False):
Radek Krejcia1339602017-11-02 13:52:38 +0100143 schema = node.schema()
144 casted = node.subtype()
145
146 if node.dflt():
147 return None
148
Radek Krejci6e772b22018-01-25 13:28:57 +0100149 info = schemaInfoNode(schema);
Radek Krejcia1339602017-11-02 13:52:38 +0100150
151 result = {}
Radek Krejci30ce1592018-03-01 14:44:14 +0100152 if info["type"] == yang.LYS_LEAF or info["type"] == yang.LYS_LEAFLIST:
Radek Krejcia1339602017-11-02 13:52:38 +0100153 result["value"] = casted.value_str()
Radek Krejci38b0a0b2018-08-03 10:17:03 +0200154 if info["datatypebase"] == "identityref":
155 info["refmodule"] = make_schema_key(casted.value().ident().module())
Radek Krejcia1339602017-11-02 13:52:38 +0100156 elif recursion:
157 result["children"] = []
158 if node.child():
159 for child in node.child().tree_for():
Radek Krejci27134982017-11-10 15:42:00 +0100160 childNode = dataInfoNode(child, result, True)
Radek Krejcia1339602017-11-02 13:52:38 +0100161 if not childNode:
162 continue
Radek Krejcia1339602017-11-02 13:52:38 +0100163 result["children"].append(childNode)
Radek Krejci30ce1592018-03-01 14:44:14 +0100164 # sort list instances
165 _sortChildren(result)
Radek Krejci0f793fe2018-02-14 08:33:45 +0100166 if info["type"] == yang.LYS_LIST:
Radek Krejcid82dfe22018-01-05 13:20:31 +0100167 result["keys"] = []
168 index = 0
169 for key in schema.subtype().keys():
170 if len(result["children"]) <= index:
171 break
172 if key.subtype().name() == result["children"][index]["info"]["name"]:
173 result["keys"].append(result["children"][index]["value"])
Radek Krejcid82dfe22018-01-05 13:20:31 +0100174 index = index + 1
Radek Krejcia1339602017-11-02 13:52:38 +0100175 result["info"] = info
176 result["path"] = node.path()
177
178 return result
179
180def dataInfoSubtree(data, path, recursion=False):
181 try:
182 node = data.find_path(path).data()[0]
183 except:
184 return(json.dumps({'success': False, 'error-msg': 'Invalid data path.'}))
185
186 result = dataInfoNode(node)
187 if not result:
188 return(json.dumps({'success': False, 'error-msg': 'Path refers to a default node.'}))
189
190 result["children"] = []
191 if node.child():
192 for child in node.child().tree_for():
Radek Krejci27134982017-11-10 15:42:00 +0100193 childNode = dataInfoNode(child, result, recursion)
Radek Krejcia1339602017-11-02 13:52:38 +0100194 if not childNode:
195 continue
Radek Krejcia1339602017-11-02 13:52:38 +0100196 result["children"].append(childNode)
Radek Krejci30ce1592018-03-01 14:44:14 +0100197 _sortChildren(result)
Radek Krejcia1339602017-11-02 13:52:38 +0100198
199 return(json.dumps({'success': True, 'data': result}))
200
201
202def dataInfoRoots(data, recursion=False):
Radek Krejci27134982017-11-10 15:42:00 +0100203 top = {}
204 top["children"] = []
Radek Krejcia1339602017-11-02 13:52:38 +0100205 for root in data.tree_for():
Radek Krejci27134982017-11-10 15:42:00 +0100206 rootNode = dataInfoNode(root, top, recursion)
Radek Krejcia1339602017-11-02 13:52:38 +0100207 if not rootNode:
208 continue
Radek Krejcid0fac3b2018-03-13 16:55:47 +0100209 if not recursion:
210 rootNode['subtreeRoot'] = True
Radek Krejci27134982017-11-10 15:42:00 +0100211 top["children"].append(rootNode)
Radek Krejci30ce1592018-03-01 14:44:14 +0100212 _sortChildren(top)
Radek Krejci4d3896c2018-01-08 17:10:43 +0100213 return(json.dumps({'success': True, 'data': top["children"]}))