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 | |
| 10 | import libyang as ly |
| 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 | |
| 44 | def schemaInfoNode(schema): |
| 45 | info = {} |
| 46 | |
| 47 | info["type"] = schema.nodetype() |
| 48 | info["module"] = schema.module().name() |
| 49 | info["name"] = schema.name() |
| 50 | info["dsc"] = schema.dsc() |
| 51 | info["config"] = True if schema.flags() & ly.LYS_CONFIG_W else False |
| 52 | if info["type"] == 1: |
| 53 | info["presence"] = schema.subtype().presence() |
| 54 | info["path"] = schema.path() |
| 55 | |
| 56 | if info["type"] == ly.LYS_LEAF: |
| 57 | schemaInfoType(schema.subtype(), info) |
| 58 | info["key"] = False if schema.subtype().is_key() == -1 else True |
| 59 | dflt = schema.subtype().dflt() |
| 60 | if dflt: |
| 61 | info["default"] = dflt |
| 62 | else: |
| 63 | tpdf = schema.subtype().type().der() |
| 64 | while tpdf and not tpdf.dflt(): |
| 65 | tpdf = tpdf.type().der() |
| 66 | if tpdf: |
| 67 | info["default"] = tpdf.dflt() |
| 68 | elif info["type"] == ly.LYS_LEAFLIST: |
| 69 | schemaInfoType(schema.subtype(), info) |
| 70 | elif info["type"] == ly.LYS_LIST: |
| 71 | info["keys"] = [] |
| 72 | for key in schema.subtype().keys(): |
| 73 | info["keys"].append(key.name()) |
| 74 | |
| 75 | return info |
| 76 | |
Radek Krejci | 4d3896c | 2018-01-08 17:10:43 +0100 | [diff] [blame] | 77 | |
Radek Krejci | 2713498 | 2017-11-10 15:42:00 +0100 | [diff] [blame] | 78 | def dataInfoNode(node, parent=None, recursion=False): |
Radek Krejci | a133960 | 2017-11-02 13:52:38 +0100 | [diff] [blame] | 79 | schema = node.schema() |
| 80 | casted = node.subtype() |
| 81 | |
| 82 | if node.dflt(): |
| 83 | return None |
| 84 | |
Radek Krejci | 2713498 | 2017-11-10 15:42:00 +0100 | [diff] [blame] | 85 | if parent and schema.nodetype() == ly.LYS_LEAFLIST: |
| 86 | # find previous instance and just add value |
| 87 | for child in parent["children"]: |
| 88 | if child["info"]["name"] == schema.name(): |
| 89 | child["value"].append(casted.value_str()) |
| 90 | if not node.next(): |
| 91 | child["last"] = True |
| 92 | return None |
| 93 | |
Radek Krejci | 6e772b2 | 2018-01-25 13:28:57 +0100 | [diff] [blame^] | 94 | info = schemaInfoNode(schema); |
Radek Krejci | a133960 | 2017-11-02 13:52:38 +0100 | [diff] [blame] | 95 | |
| 96 | result = {} |
Radek Krejci | 2713498 | 2017-11-10 15:42:00 +0100 | [diff] [blame] | 97 | if info["type"] == ly.LYS_LEAF: |
Radek Krejci | a133960 | 2017-11-02 13:52:38 +0100 | [diff] [blame] | 98 | result["value"] = casted.value_str() |
Radek Krejci | 2713498 | 2017-11-10 15:42:00 +0100 | [diff] [blame] | 99 | elif info["type"] == ly.LYS_LEAFLIST: |
| 100 | result["value"] = [casted.value_str()] |
Radek Krejci | a133960 | 2017-11-02 13:52:38 +0100 | [diff] [blame] | 101 | elif recursion: |
| 102 | result["children"] = [] |
| 103 | if node.child(): |
| 104 | for child in node.child().tree_for(): |
Radek Krejci | 2713498 | 2017-11-10 15:42:00 +0100 | [diff] [blame] | 105 | childNode = dataInfoNode(child, result, True) |
Radek Krejci | a133960 | 2017-11-02 13:52:38 +0100 | [diff] [blame] | 106 | if not childNode: |
| 107 | continue |
| 108 | if not child.next(): |
| 109 | childNode["last"] = True |
| 110 | result["children"].append(childNode) |
Radek Krejci | d82dfe2 | 2018-01-05 13:20:31 +0100 | [diff] [blame] | 111 | |
| 112 | if info["type"] == ly.LYS_LIST: |
| 113 | result["keys"] = [] |
| 114 | index = 0 |
| 115 | for key in schema.subtype().keys(): |
| 116 | if len(result["children"]) <= index: |
| 117 | break |
| 118 | if key.subtype().name() == result["children"][index]["info"]["name"]: |
| 119 | result["keys"].append(result["children"][index]["value"]) |
Radek Krejci | d82dfe2 | 2018-01-05 13:20:31 +0100 | [diff] [blame] | 120 | index = index + 1 |
Radek Krejci | a133960 | 2017-11-02 13:52:38 +0100 | [diff] [blame] | 121 | result["info"] = info |
| 122 | result["path"] = node.path() |
| 123 | |
| 124 | return result |
| 125 | |
| 126 | def dataInfoSubtree(data, path, recursion=False): |
| 127 | try: |
| 128 | node = data.find_path(path).data()[0] |
| 129 | except: |
| 130 | return(json.dumps({'success': False, 'error-msg': 'Invalid data path.'})) |
| 131 | |
| 132 | result = dataInfoNode(node) |
| 133 | if not result: |
| 134 | return(json.dumps({'success': False, 'error-msg': 'Path refers to a default node.'})) |
| 135 | |
| 136 | result["children"] = [] |
| 137 | if node.child(): |
| 138 | for child in node.child().tree_for(): |
Radek Krejci | 2713498 | 2017-11-10 15:42:00 +0100 | [diff] [blame] | 139 | childNode = dataInfoNode(child, result, recursion) |
Radek Krejci | a133960 | 2017-11-02 13:52:38 +0100 | [diff] [blame] | 140 | if not childNode: |
| 141 | continue |
| 142 | if not child.next(): |
| 143 | childNode["last"] = True |
| 144 | result["children"].append(childNode) |
| 145 | |
| 146 | return(json.dumps({'success': True, 'data': result})) |
| 147 | |
| 148 | |
| 149 | def dataInfoRoots(data, recursion=False): |
Radek Krejci | 2713498 | 2017-11-10 15:42:00 +0100 | [diff] [blame] | 150 | top = {} |
| 151 | top["children"] = [] |
Radek Krejci | a133960 | 2017-11-02 13:52:38 +0100 | [diff] [blame] | 152 | for root in data.tree_for(): |
Radek Krejci | 2713498 | 2017-11-10 15:42:00 +0100 | [diff] [blame] | 153 | rootNode = dataInfoNode(root, top, recursion) |
Radek Krejci | a133960 | 2017-11-02 13:52:38 +0100 | [diff] [blame] | 154 | if not rootNode: |
| 155 | continue |
| 156 | if not root.next(): |
| 157 | rootNode["last"] = True |
Radek Krejci | 2713498 | 2017-11-10 15:42:00 +0100 | [diff] [blame] | 158 | top["children"].append(rootNode) |
Radek Krejci | a133960 | 2017-11-02 13:52:38 +0100 | [diff] [blame] | 159 | |
Radek Krejci | 4d3896c | 2018-01-08 17:10:43 +0100 | [diff] [blame] | 160 | return(json.dumps({'success': True, 'data': top["children"]})) |