Radek Krejci | a133960 | 2017-11-02 13:52:38 +0100 | [diff] [blame] | 1 | """ |
| 2 | NETCONF data helper functions |
| 3 | File: data.py |
| 4 | Author: Radek Krejci <rkrejci@cesnet.cz> |
| 5 | """ |
| 6 | |
| 7 | import json |
| 8 | import os |
| 9 | |
Radek Krejci | 0f793fe | 2018-02-14 08:33:45 +0100 | [diff] [blame] | 10 | import yang |
Radek Krejci | a133960 | 2017-11-02 13:52:38 +0100 | [diff] [blame] | 11 | import netconf2 as nc |
| 12 | |
Radek Krejci | 4d3896c | 2018-01-08 17:10:43 +0100 | [diff] [blame] | 13 | def infoBuiltInType(base): |
| 14 | return { |
Radek Krejci | 6e772b2 | 2018-01-25 13:28:57 +0100 | [diff] [blame] | 15 | - 1 : 'error', |
| 16 | 0 : 'derived', |
| 17 | 1 : 'binary', |
| 18 | 2 : 'bits', |
| 19 | 3 : 'boolean', |
| 20 | 4 : 'decimal64', |
| 21 | 5 : 'empty', |
| 22 | 6 : 'enumeration', |
| 23 | 7 : 'identityref', |
| 24 | 8 : 'instance-identifier', |
| 25 | 9 : 'leafref', |
Radek Krejci | 4d3896c | 2018-01-08 17:10:43 +0100 | [diff] [blame] | 26 | 10: 'string', |
| 27 | 11: 'union', |
| 28 | 12: 'int8', |
| 29 | 13: 'uint8', |
| 30 | 14: 'int16', |
| 31 | 15: 'uint16', |
| 32 | 16: 'int32', |
| 33 | 17: 'uint32', |
| 34 | 18: 'int64', |
| 35 | 19: 'uint64', |
| 36 | }[base] |
| 37 | |
Radek Krejci | 6e772b2 | 2018-01-25 13:28:57 +0100 | [diff] [blame] | 38 | |
| 39 | def schemaInfoType(schema, info): |
| 40 | info["datatype"] = schema.type().der().name() |
| 41 | info["datatypebase"] = infoBuiltInType(schema.type().base()) |
| 42 | |
| 43 | |
Radek Krejci | d0ce4cf | 2018-02-09 14:44:34 +0100 | [diff] [blame] | 44 | def typeValues(type, result): |
| 45 | while type.der(): |
| 46 | if type.base() == 2: |
| 47 | # bits |
| 48 | if type.info().bits().count(): |
| 49 | for bit in type.info().bits().bit(): |
| 50 | result.append(bit.name()) |
| 51 | elif type.base() == 6: |
| 52 | # enumeration |
| 53 | if type.info().enums().count(): |
| 54 | for enm in type.info().enums().enm(): |
| 55 | result.append(enm.name()) |
| 56 | else: |
| 57 | return result |
| 58 | type = type.der().type() |
| 59 | |
| 60 | return result |
| 61 | |
Radek Krejci | 6e772b2 | 2018-01-25 13:28:57 +0100 | [diff] [blame] | 62 | def schemaInfoNode(schema): |
| 63 | info = {} |
| 64 | |
| 65 | info["type"] = schema.nodetype() |
Radek Krejci | ad45e57 | 2018-02-21 10:54:54 +0100 | [diff] [blame] | 66 | if schema.module().rev_size(): |
| 67 | info["module"] = schema.module().name() + '@' + schema.module().rev().date() |
| 68 | else: |
| 69 | info["module"] = schema.module().name() |
Radek Krejci | 6e772b2 | 2018-01-25 13:28:57 +0100 | [diff] [blame] | 70 | info["name"] = schema.name() |
| 71 | info["dsc"] = schema.dsc() |
Radek Krejci | 0f793fe | 2018-02-14 08:33:45 +0100 | [diff] [blame] | 72 | info["config"] = True if schema.flags() & yang.LYS_CONFIG_W else False |
Radek Krejci | 6e772b2 | 2018-01-25 13:28:57 +0100 | [diff] [blame] | 73 | if info["type"] == 1: |
| 74 | info["presence"] = schema.subtype().presence() |
| 75 | info["path"] = schema.path() |
| 76 | |
Radek Krejci | 0f793fe | 2018-02-14 08:33:45 +0100 | [diff] [blame] | 77 | if info["type"] == yang.LYS_LEAF: |
Radek Krejci | 6e772b2 | 2018-01-25 13:28:57 +0100 | [diff] [blame] | 78 | schemaInfoType(schema.subtype(), info) |
| 79 | info["key"] = False if schema.subtype().is_key() == -1 else True |
| 80 | dflt = schema.subtype().dflt() |
| 81 | if dflt: |
| 82 | info["default"] = dflt |
| 83 | else: |
| 84 | tpdf = schema.subtype().type().der() |
| 85 | while tpdf and not tpdf.dflt(): |
| 86 | tpdf = tpdf.type().der() |
| 87 | if tpdf: |
| 88 | info["default"] = tpdf.dflt() |
Radek Krejci | 0f793fe | 2018-02-14 08:33:45 +0100 | [diff] [blame] | 89 | elif info["type"] == yang.LYS_LEAFLIST: |
Radek Krejci | 6e772b2 | 2018-01-25 13:28:57 +0100 | [diff] [blame] | 90 | schemaInfoType(schema.subtype(), info) |
Radek Krejci | 010475d | 2018-03-08 13:14:19 +0100 | [diff] [blame] | 91 | if schema.flags() & yang.LYS_USERORDERED: |
| 92 | info["ordered"] = True; |
Radek Krejci | 0f793fe | 2018-02-14 08:33:45 +0100 | [diff] [blame] | 93 | elif info["type"] == yang.LYS_LIST: |
Radek Krejci | 010475d | 2018-03-08 13:14:19 +0100 | [diff] [blame] | 94 | if schema.flags() & yang.LYS_USERORDERED: |
| 95 | info["ordered"] = True; |
Radek Krejci | 6e772b2 | 2018-01-25 13:28:57 +0100 | [diff] [blame] | 96 | info["keys"] = [] |
| 97 | for key in schema.subtype().keys(): |
| 98 | info["keys"].append(key.name()) |
| 99 | |
| 100 | return info |
| 101 | |
Radek Krejci | 4d3896c | 2018-01-08 17:10:43 +0100 | [diff] [blame] | 102 | |
Radek Krejci | 30ce159 | 2018-03-01 14:44:14 +0100 | [diff] [blame] | 103 | def _sortChildren(node): |
| 104 | sorted = [] |
| 105 | for index, item in enumerate(node["children"]): |
| 106 | sorted.append(item) |
| 107 | if item["info"]["type"] == yang.LYS_LIST: |
| 108 | removed = 0 |
Radek Krejci | 010475d | 2018-03-08 13:14:19 +0100 | [diff] [blame] | 109 | if "ordered" in item["info"]: |
| 110 | item["order"] = removed |
Radek Krejci | 30ce159 | 2018-03-01 14:44:14 +0100 | [diff] [blame] | 111 | for i, instance in enumerate(node["children"][index + 1:]): |
| 112 | if item["info"]["name"] == instance["info"]["name"] and item["info"]["module"] == instance["info"]["module"]: |
| 113 | sorted.append(node["children"].pop(index + 1 + i - removed)) |
| 114 | removed += 1; |
Radek Krejci | 010475d | 2018-03-08 13:14:19 +0100 | [diff] [blame] | 115 | if "ordered" in item["info"]: |
| 116 | instance["order"] = removed |
Radek Krejci | 30ce159 | 2018-03-01 14:44:14 +0100 | [diff] [blame] | 117 | if item["info"]["type"] == yang.LYS_LEAFLIST: |
| 118 | lastLeafList = len(sorted) - 1 |
| 119 | item["first"] = True |
| 120 | removed = 0 |
Radek Krejci | 010475d | 2018-03-08 13:14:19 +0100 | [diff] [blame] | 121 | if "ordered" in item["info"]: |
| 122 | item["order"] = removed |
Radek Krejci | 30ce159 | 2018-03-01 14:44:14 +0100 | [diff] [blame] | 123 | for i, instance in enumerate(node["children"][index + 1:]): |
| 124 | if item["info"]["name"] == instance["info"]["name"] and item["info"]["module"] == instance["info"]["module"]: |
| 125 | instance["first"] = False |
| 126 | sorted.append(node["children"].pop(index + 1 + i - removed)) |
| 127 | removed += 1; |
Radek Krejci | 010475d | 2018-03-08 13:14:19 +0100 | [diff] [blame] | 128 | if "ordered" in item["info"]: |
| 129 | instance["order"] = removed |
Radek Krejci | 30ce159 | 2018-03-01 14:44:14 +0100 | [diff] [blame] | 130 | node["children"] = sorted |
| 131 | last = node["children"][len(node["children"]) - 1] |
| 132 | if last["info"]["type"] == yang.LYS_LEAFLIST: |
| 133 | node["children"][lastLeafList]["last"] = True |
| 134 | for item in node["children"][lastLeafList + 1:]: |
| 135 | item["lastLeafList"] = True; |
| 136 | else: |
| 137 | last["last"] = True |
| 138 | |
| 139 | |
Radek Krejci | 2713498 | 2017-11-10 15:42:00 +0100 | [diff] [blame] | 140 | def dataInfoNode(node, parent=None, recursion=False): |
Radek Krejci | a133960 | 2017-11-02 13:52:38 +0100 | [diff] [blame] | 141 | schema = node.schema() |
| 142 | casted = node.subtype() |
| 143 | |
| 144 | if node.dflt(): |
| 145 | return None |
| 146 | |
Radek Krejci | 6e772b2 | 2018-01-25 13:28:57 +0100 | [diff] [blame] | 147 | info = schemaInfoNode(schema); |
Radek Krejci | a133960 | 2017-11-02 13:52:38 +0100 | [diff] [blame] | 148 | |
| 149 | result = {} |
Radek Krejci | 30ce159 | 2018-03-01 14:44:14 +0100 | [diff] [blame] | 150 | if info["type"] == yang.LYS_LEAF or info["type"] == yang.LYS_LEAFLIST: |
Radek Krejci | a133960 | 2017-11-02 13:52:38 +0100 | [diff] [blame] | 151 | result["value"] = casted.value_str() |
| 152 | elif recursion: |
| 153 | result["children"] = [] |
| 154 | if node.child(): |
| 155 | for child in node.child().tree_for(): |
Radek Krejci | 2713498 | 2017-11-10 15:42:00 +0100 | [diff] [blame] | 156 | childNode = dataInfoNode(child, result, True) |
Radek Krejci | a133960 | 2017-11-02 13:52:38 +0100 | [diff] [blame] | 157 | if not childNode: |
| 158 | continue |
Radek Krejci | a133960 | 2017-11-02 13:52:38 +0100 | [diff] [blame] | 159 | result["children"].append(childNode) |
Radek Krejci | 30ce159 | 2018-03-01 14:44:14 +0100 | [diff] [blame] | 160 | # sort list instances |
| 161 | _sortChildren(result) |
Radek Krejci | 0f793fe | 2018-02-14 08:33:45 +0100 | [diff] [blame] | 162 | if info["type"] == yang.LYS_LIST: |
Radek Krejci | d82dfe2 | 2018-01-05 13:20:31 +0100 | [diff] [blame] | 163 | result["keys"] = [] |
| 164 | index = 0 |
| 165 | for key in schema.subtype().keys(): |
| 166 | if len(result["children"]) <= index: |
| 167 | break |
| 168 | if key.subtype().name() == result["children"][index]["info"]["name"]: |
| 169 | result["keys"].append(result["children"][index]["value"]) |
Radek Krejci | d82dfe2 | 2018-01-05 13:20:31 +0100 | [diff] [blame] | 170 | index = index + 1 |
Radek Krejci | a133960 | 2017-11-02 13:52:38 +0100 | [diff] [blame] | 171 | result["info"] = info |
| 172 | result["path"] = node.path() |
| 173 | |
| 174 | return result |
| 175 | |
| 176 | def dataInfoSubtree(data, path, recursion=False): |
| 177 | try: |
| 178 | node = data.find_path(path).data()[0] |
| 179 | except: |
| 180 | return(json.dumps({'success': False, 'error-msg': 'Invalid data path.'})) |
| 181 | |
| 182 | result = dataInfoNode(node) |
| 183 | if not result: |
| 184 | return(json.dumps({'success': False, 'error-msg': 'Path refers to a default node.'})) |
| 185 | |
| 186 | result["children"] = [] |
| 187 | if node.child(): |
| 188 | for child in node.child().tree_for(): |
Radek Krejci | 2713498 | 2017-11-10 15:42:00 +0100 | [diff] [blame] | 189 | childNode = dataInfoNode(child, result, recursion) |
Radek Krejci | a133960 | 2017-11-02 13:52:38 +0100 | [diff] [blame] | 190 | if not childNode: |
| 191 | continue |
Radek Krejci | a133960 | 2017-11-02 13:52:38 +0100 | [diff] [blame] | 192 | result["children"].append(childNode) |
Radek Krejci | 30ce159 | 2018-03-01 14:44:14 +0100 | [diff] [blame] | 193 | _sortChildren(result) |
Radek Krejci | a133960 | 2017-11-02 13:52:38 +0100 | [diff] [blame] | 194 | |
| 195 | return(json.dumps({'success': True, 'data': result})) |
| 196 | |
| 197 | |
| 198 | def dataInfoRoots(data, recursion=False): |
Radek Krejci | 2713498 | 2017-11-10 15:42:00 +0100 | [diff] [blame] | 199 | top = {} |
| 200 | top["children"] = [] |
Radek Krejci | a133960 | 2017-11-02 13:52:38 +0100 | [diff] [blame] | 201 | for root in data.tree_for(): |
Radek Krejci | 2713498 | 2017-11-10 15:42:00 +0100 | [diff] [blame] | 202 | rootNode = dataInfoNode(root, top, recursion) |
Radek Krejci | a133960 | 2017-11-02 13:52:38 +0100 | [diff] [blame] | 203 | if not rootNode: |
| 204 | continue |
Radek Krejci | d0fac3b | 2018-03-13 16:55:47 +0100 | [diff] [blame^] | 205 | if not recursion: |
| 206 | rootNode['subtreeRoot'] = True |
Radek Krejci | 2713498 | 2017-11-10 15:42:00 +0100 | [diff] [blame] | 207 | top["children"].append(rootNode) |
Radek Krejci | 30ce159 | 2018-03-01 14:44:14 +0100 | [diff] [blame] | 208 | _sortChildren(top) |
Radek Krejci | 4d3896c | 2018-01-08 17:10:43 +0100 | [diff] [blame] | 209 | return(json.dumps({'success': True, 'data': top["children"]})) |