diff --git a/test/infamy/netconf.py b/test/infamy/netconf.py index 8d000122d..c82fc33ae 100644 --- a/test/infamy/netconf.py +++ b/test/infamy/netconf.py @@ -367,14 +367,19 @@ def call_dict(self, modname, call): lyd = mod.parse_data_dict(call, rpc=True) return self.call(lyd.print_mem("xml", with_siblings=True, pretty=False)) - def call_action(self, xpath): - """Call NETCONF action (contextualized RPC), XML version""" + def call_action(self, xpath, input_data=None): + """Call NETCONF action (contextualized RPC), XML version. + + If `input_data` is supplied, it's set at the action's xpath as + the action's input leaves. Defaults to an empty input for + actions that take no parameters. + """ action={} pattern = r"^/(?P[^:]+):(?P[^/]+)" match = re.search(pattern, xpath) module = match.group('module') modpath = f"/{match.group('module')}:{match.group('path')}" - libyang.xpath_set(action, xpath, {}) + libyang.xpath_set(action, xpath, input_data or {}) mod = self.ly.get_module(module) lyd = mod.parse_data_dict(action, rpc=True) xml = "" + lyd.print_mem("xml", with_siblings=True, pretty=False) + "" diff --git a/test/infamy/restconf.py b/test/infamy/restconf.py index 2e4bdce9c..ed7ec0f96 100644 --- a/test/infamy/restconf.py +++ b/test/infamy/restconf.py @@ -452,12 +452,26 @@ def copy(self, source, target, retries=3): def reboot(self): self.call_rpc("ietf-system:system-restart") - def call_action(self, xpath): + def call_action(self, xpath, input_data=None): path = xpath_to_uri(xpath) url = f"{self.restconf_url}/data{path}" + + # RFC 8040 wraps action input as {":input": {...}}. + # The action's module is the prefix of the closest namespaced + # xpath segment; for "/a:foo/b:bar/baz" that's "b". + body = None + if input_data: + module = None + for seg in xpath.split("/"): + if ":" in seg: + module = seg.split(":", 1)[0] + if not module: + raise ValueError(f"cannot determine action module from {xpath}") + body = {f"{module}:input": input_data} + response = requests_workaround_post( url, - json=None, + json=body, headers=self.headers, auth=self.auth, verify=False diff --git a/test/infamy/transport.py b/test/infamy/transport.py index 04efa387d..2f6cc1848 100644 --- a/test/infamy/transport.py +++ b/test/infamy/transport.py @@ -47,7 +47,13 @@ def call_dict(self, module, call): pass @abstractmethod - def call_action(self, xpath): + def call_action(self, xpath, input_data=None): + """Invoke a YANG action at `xpath`. + + `input_data`, if supplied, is a dict of input leaves (e.g. + ``{"state": "on"}``). Backends wrap it in the protocol-specific + envelope; actions that take no input may omit the argument. + """ pass def __getitem__(self, key):