Skip to content

Commit

Permalink
Add support for RPC operations
Browse files Browse the repository at this point in the history
  • Loading branch information
carlgsmith committed Jul 1, 2024
1 parent 04adebc commit c78b5b6
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 13 deletions.
1 change: 1 addition & 0 deletions apteryx-xml.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ bool sch_is_leaf_list (sch_node * node);
char *sch_list_key (sch_node * node);
bool sch_is_readable (sch_node * node);
bool sch_is_writable (sch_node * node);
bool sch_is_executable (sch_node * node);
bool sch_is_hidden (sch_node * node);
bool sch_is_config (sch_node * node);
bool sch_is_proxy (sch_node * node);
Expand Down
3 changes: 2 additions & 1 deletion models/namespace.map
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#<namespace> <root node>
http://test.com/ns/yang/testing-2 /t2:test
http://test.com/ns/yang/testing-3 /t3:test
http://test.com/ns/yang/testing-3 /t3:test
http://test.com/ns/yang/testing-4 /t4:test
56 changes: 56 additions & 0 deletions models/rpc.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
local apteryx = require('apteryx')

local function reboot(path, input)
if input["language"] ~= nil then
-- generate results for test cases
if input["language"] ~= 'en-US' then
if input["language"]:find("-") then
return false, "do not support language " .. input["language"]
elseif input["language"] == "" then
return false, false, false
else
return false
end
end
end
apteryx.set_tree ("/system/reboot-info", {
["reboot-time"] = input["delay"] or nil,
["message"] = input["message"] or nil,
["language"] = input["language"] or nil,
})
return true
end

local function get_reboot_info(path, input)
local info = apteryx.get_tree("/system/reboot-info")
return {
["reboot-time"] = info["reboot-time"] or nil,
["message"] = info["message"] or nil,
["language"] = info["language"] or nil,
}
end

local function reset_state(path, input)
local delay = input["delay"]
apteryx.set("/t4:test/state/age", delay)
return true
end

local function get_reset_time(path, input)
return { ["last-reset"] = apteryx.get("/t4:test/state/age") }
end

local function set_age(path, input)
local user = path:match('/t4:test/state/users/([^/]+)')
local age = input["age"]
apteryx.set("/t4:test/state/users/" .. user .. "/age", age)
return true
end

return {
["/operations/t4:reboot"] = reboot,
["/operations/t4:get-reboot-info"] = get_reboot_info,
["/t4:test/state/reset"] = reset_state,
["/t4:test/state/get-last-reset-time"] = get_reset_time,
["/t4:test/state/users/*/set-age"] = set_age,
}
50 changes: 50 additions & 0 deletions models/test4:rpc.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?xml version='1.0' encoding='UTF-8'?>
<MODULE xmlns="http://test.com/ns/yang/testing-4"
xmlns:test="http://test.com/ns/yang/testing"
xmlns:t4="http://test.com/ns/yang/testing-4"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://github.com/alliedtelesis/apteryx-xml https://github.com/alliedtelesis/apteryx-xml/releases/download/v1.2/apteryx.xsd"
model="testing-4" organization="Test 4 Ltd" version="2024-02-01">
<NODE name="test" help="This is a test node in the testing-4 namespace">
<NODE name="state" help="State">
<NODE name="age" mode="r" help="a string"/>
<NODE name="reset" mode="wx" help="Reset state">
<NODE name="input" help="Input parameters">
<NODE name="delay" mode="w" help="Number of seconds to wait before starting the reset" range="0..4294967295"/>
</NODE>
</NODE>
<NODE name="get-last-reset-time" mode="rwx" help="Retrieve the last interface reset time">
<NODE name="output" help="Output parameters">
<NODE name="last-reset" mode="r" help="Time of the last reset" range="0..4294967295"/>
</NODE>
</NODE>
<NODE name="users" help="This is a list of users">
<NODE name="*" help="The user entry with key name">
<NODE name="name" mode="rw" help="This is the name of the user"/>
<NODE name="age" mode="rw" help="Age of the user" range="0..4294967295"/>
<NODE name="set-age" mode="wx" help="Set the users age">
<NODE name="input" help="Input parameters">
<NODE name="age" mode="w" help="New age" range="0..4294967295"/>
</NODE>
</NODE>
</NODE>
</NODE>
</NODE>
</NODE>
<test:NODE name="operations" help="Container for all operation resources.">
<NODE name="reboot" mode="wx" help="Reboot operation.">
<NODE name="input" help="Input parameters">
<NODE name="delay" mode="w" help="Number of seconds to wait before initiating the reboot operation." range="0..4294967295"/>
<NODE name="message" mode="w" help="Log message to display when reboot is started."/>
<NODE name="language" mode="w" help="Language identifier string."/>
</NODE>
</NODE>
<NODE name="get-reboot-info" mode="rx" help="Retrieve parameters used in the last reboot operation.">
<NODE name="output" help="Output parameters">
<NODE name="reboot-time" mode="r" help="The 'delay' parameter used in the last reboot operation." range="0..4294967295"/>
<NODE name="message" mode="r" help="The 'message' parameter used in the last reboot operation."/>
<NODE name="language" mode="r" help="The 'language' parameter used in the last reboot operation."/>
</NODE>
</NODE>
</test:NODE>
</MODULE>
35 changes: 35 additions & 0 deletions pyang-apteryx-xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ def emit(self, ctx, modules, fd):
"case": self.case,
"list": self.list,
"leaf-list": self.leaf_list,
"action": self.rpc,
"rpc": self.rpc,
"input": self.rpc,
"output": self.rpc,
}
self.enum_name = ctx.opts.enum_name

Expand Down Expand Up @@ -249,6 +253,24 @@ def process_children(self, node, elem, module, path, omit=[]):
self.node_handler.get(ch.keyword, self.ignore)(
ch, elem, module, path)

def rpc(self, node, elem, module, path):
if (node.keyword == 'input' or node.keyword == 'output') and len(node.substmts) == 0:
return
parent = elem
if node.keyword == 'rpc':
root = elem
while root.find('..'):
root = root.find('..')
parent = root.find(".//NODE[@name='operations']")
if parent is None:
parent = etree.SubElement(root, "NODE")
parent.attrib = OrderedDict()
parent.attrib["name"] = "operations"
nel, newm, path = self.sample_element(node, parent, module, path)
if path is None:
return
self.process_children(node, nel, newm, path)

def container(self, node, elem, module, path):
nel, newm, path = self.sample_element(node, elem, module, path)
if path is None:
Expand Down Expand Up @@ -286,6 +308,13 @@ def node_in_namespace(self, node, ns):
return True
return False

def node_descendant_of(self, node, keyword):
while node.parent is not None:
if node.parent.keyword == keyword:
return True
node = node.parent
return False

def sample_element(self, node, parent, module, path):
if path is None:
return parent, module, None
Expand All @@ -303,9 +332,15 @@ def sample_element(self, node, parent, module, path):
res = etree.SubElement(parent, "{" + ns.arg + "}NODE")
res.attrib = OrderedDict()
res.attrib["name"] = node.arg
if node.keyword == 'rpc' or node.keyword == 'action':
res.attrib["mode"] = "rwx"
if node.keyword == 'leaf':
if node.i_config:
res.attrib["mode"] = "rw"
elif self.node_descendant_of(node, "input"):
res.attrib["mode"] = "w"
elif self.node_descendant_of(node, "output"):
res.attrib["mode"] = "r"
else:
res.attrib["mode"] = "r"
if node.i_default is not None:
Expand Down
40 changes: 28 additions & 12 deletions schema.c
Original file line number Diff line number Diff line change
Expand Up @@ -1742,6 +1742,20 @@ sch_is_writable (sch_node * node)
return access;
}

bool
sch_is_executable (sch_node * node)
{
xmlNode *xml = (xmlNode *) node;
bool access = false;
char *mode = (char *) xmlGetProp (xml, (xmlChar *) "mode");
if (mode && strchr (mode, 'x') != NULL)
{
access = true;
}
free (mode);
return access;
}

bool
sch_is_hidden (sch_node * node)
{
Expand Down Expand Up @@ -2521,6 +2535,7 @@ static GNode *
_sch_path_to_gnode (sch_instance * instance, sch_node ** rschema, xmlNs *ns, const char *path, int flags, int depth)
{
sch_node *schema = rschema && *rschema ? *rschema : xmlDocGetRootElement (instance->doc);
xmlNs *nns = NULL;
const char *next = NULL;
GNode *node = NULL;
GNode *rnode = NULL;
Expand Down Expand Up @@ -2551,7 +2566,7 @@ _sch_path_to_gnode (sch_instance * instance, sch_node ** rschema, xmlNs *ns, con
if (colon)
{
colon[0] = '\0';
xmlNs *nns = _sch_lookup_ns (instance, schema, name, flags, false);
nns = _sch_lookup_ns (instance, schema, name, flags, false);
if (!nns)
{
/* No namespace found assume the node is supposed to have a colon in it */
Expand Down Expand Up @@ -2610,7 +2625,7 @@ _sch_path_to_gnode (sch_instance * instance, sch_node ** rschema, xmlNs *ns, con
if (colon)
{
colon[0] = '\0';
xmlNs *nns = _sch_lookup_ns (instance, schema, name, flags, false);
nns = _sch_lookup_ns (instance, schema, name, flags, false);
if (!nns)
{
/* No namespace found assume the node is supposed to have a colon in it */
Expand Down Expand Up @@ -2675,29 +2690,30 @@ _sch_path_to_gnode (sch_instance * instance, sch_node ** rschema, xmlNs *ns, con
}
}

/* Check RPC's are not bypassed */
if (schema && next && next[0] != '\0' && sch_is_executable (schema))
{
DEBUG (flags, "Tried to access parameter node of RPC\n");
schema = NULL;
}

if (schema == NULL)
{
ERROR (flags, SCH_E_NOSCHEMANODE, "No schema match for %s%s%s\n", ns ? (char *) ns->prefix : "",
ns ? ":" : "", name);
goto exit;
}

/* Create node */
if (depth == 0 || is_proxy)
/* Create node - include namespace node mapping if required */
if (depth == 0 || nns || is_proxy)
{
if (ns && ns->prefix && !_sch_ns_native (instance, ns))
{
if (is_proxy)
rnode = APTERYX_NODE (NULL, g_strdup_printf ("%s:%s", ns->prefix, name));
else
rnode = APTERYX_NODE (NULL, g_strdup_printf ("/%s:%s", ns->prefix, name));
rnode = APTERYX_NODE (NULL, g_strdup_printf ("%s%s:%s", depth == 0 ? "/" : "", ns->prefix, name));
}
else
{
if (is_proxy)
rnode = APTERYX_NODE (NULL, g_strdup (name));
else
rnode = APTERYX_NODE (NULL, g_strdup_printf ("/%s", name));
rnode = APTERYX_NODE (NULL, g_strdup_printf ("%s%s", depth == 0 ? "/" : "", name));
}
DEBUG (flags, "%*s%s\n", depth * 2, " ", APTERYX_NAME (rnode));
}
Expand Down

0 comments on commit c78b5b6

Please sign in to comment.