From 3ace1d08ba015dca0c9453588deb4c89f184cc78 Mon Sep 17 00:00:00 2001 From: Graeme Campbell Date: Tue, 16 Jul 2024 14:46:20 +1200 Subject: [PATCH] Fix RFC compliance of identityref value types The current code is not compliant to Netconf RFC - RFC6020 https://datatracker.ietf.org/doc/html/rfc6020#section-9.10.5 Also restconf is not compliant to a similar RFC - RFC7951 https://datatracker.ietf.org/doc/html/rfc7951#section-6.8 This change fixes the XML generation tool pyang-apteryx-xml.py to generate enough information so that Netconf and Restconf can set identyref type values with the correct reference information. A basic model test.xml, was modified to set the new the XML properties on a basic type. --- models/test.xml | 2 +- pyang-apteryx-xml.py | 35 +++++++++++++++++++++++++++++++++++ schema.c | 18 ++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/models/test.xml b/models/test.xml index 3bdced8..0b532e7 100644 --- a/models/test.xml +++ b/models/test.xml @@ -67,7 +67,7 @@ - + diff --git a/pyang-apteryx-xml.py b/pyang-apteryx-xml.py index f8c4b4a..ef875a4 100644 --- a/pyang-apteryx-xml.py +++ b/pyang-apteryx-xml.py @@ -315,6 +315,40 @@ def node_descendant_of(self, node, keyword): node = node.parent return False + def value_attrib_identityref(self, res, ntype): + if hasattr(ntype, "i_type_spec") and hasattr(ntype.i_type_spec, "idbases"): + for ch in ntype.i_type_spec.idbases: + sp_parts = ch.arg.split(':', 2); + if ch.i_module.i_prefixes is not None: + for pref, mname in ch.i_module.i_prefixes.items(): + if pref == sp_parts[0]: + module_name = mname[:][0] + subm = ch.i_module.i_ctx.get_module(module_name) + if subm is not None: + ns = subm.search_one('namespace') + if ns is not None and subm.i_prefix is not None: + res.attrib["idref_href"] = ns.arg + res.attrib["idref_prefix"] = subm.i_prefix + res.attrib["idref_module"] = module_name + return + + def value_identityref(self, node, res): + ntype = node.search_one("type") + if ntype and ntype.i_typedef is not None: + ntype = ntype.i_typedef.search_one("type") + if ntype is not None: + if ntype.arg == "identityref": + self.value_attrib_identityref(res, ntype) + if ntype.arg == "union" and hasattr(ntype, "i_type_spec"): + if (hasattr(ntype.i_type_spec, "types")): + base_idref = True + for ch in ntype.i_type_spec.types: + if ch.arg != "identityref": + base_idref = False + break + if base_idref and hasattr(ch, "i_type_spec"): + self.value_attrib_identityref(res, ch) + def sample_element(self, node, parent, module, path): if path is None: return parent, module, None @@ -335,6 +369,7 @@ def sample_element(self, node, parent, module, path): if node.keyword == 'rpc' or node.keyword == 'action': res.attrib["mode"] = "rwx" if node.keyword == 'leaf': + self.value_identityref(node, res) if node.i_config: res.attrib["mode"] = "rw" elif self.node_descendant_of(node, "input"): diff --git a/schema.c b/schema.c index a3fb1a3..7d47f27 100644 --- a/schema.c +++ b/schema.c @@ -3587,9 +3587,27 @@ _sch_gnode_to_json (sch_instance * instance, sch_node * schema, xmlNs *ns, GNode else if (APTERYX_HAS_VALUE (node)) { char *value = g_strdup (APTERYX_VALUE (node) ? APTERYX_VALUE (node) : ""); + if (flags & SCH_F_JSON_TYPES) { value = sch_translate_to (schema, value); + } + + if (value) + { + /* Check to see if the schema has any identityref information */ + xmlChar *idref_module = xmlGetProp ((xmlNode *)schema, (const xmlChar *)"idref_module"); + if (idref_module) + { + char *temp = value; + value = g_strdup_printf ("%s:%s", (char *) idref_module, value); + g_free (temp); + xmlFree (idref_module); + } + } + + if (flags & SCH_F_JSON_TYPES) + { data = encode_json_type (schema, value); } else