From 782860988dbf0e43afbcce06393c8338bc91fc7b Mon Sep 17 00:00:00 2001 From: mbakalarski <64490638+mbakalarski@users.noreply.github.com> Date: Wed, 21 Jan 2026 12:16:57 +0000 Subject: [PATCH] version 0.0.16 --- example/xr1.yaml | 14 ++++++++++++ example/{xr.yaml => xr2.yaml} | 4 ++++ function/__version__.py | 2 +- function/fn.py | 43 +++++++++++++++++++++++++++++------ 4 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 example/xr1.yaml rename example/{xr.yaml => xr2.yaml} (67%) diff --git a/example/xr1.yaml b/example/xr1.yaml new file mode 100644 index 0000000..0fafa69 --- /dev/null +++ b/example/xr1.yaml @@ -0,0 +1,14 @@ +apiVersion: eos.netclab.dev/v1alpha1 +kind: EosCommand +metadata: + name: eoscommand-2 +spec: + endpoint: ceos01.default.svc.cluster.local + removeContainer: false + cmds: + no spanning-tree vlan-id 4093-4094: {} + ip prefix-list PL-Loopback0: + seq 10 permit 10.0.0.1/32 eq 32: {} + seq 20 permit 10.0.0.2/32 eq 32: {} + router bgp 65100: + no bgp default ipv4-unicast: {} diff --git a/example/xr.yaml b/example/xr2.yaml similarity index 67% rename from example/xr.yaml rename to example/xr2.yaml index bb8a6be..46e40f0 100644 --- a/example/xr.yaml +++ b/example/xr2.yaml @@ -4,7 +4,11 @@ metadata: name: eoscommand-1 spec: endpoint: ceos01.default.svc.cluster.local + removeContainer: true cmds: + no spanning-tree vlan-id 4093-4094: {} ip prefix-list PL-Loopback0: seq 10 permit 10.0.0.1/32 eq 32: {} seq 20 permit 10.0.0.2/32 eq 32: {} + router bgp 65100: + no bgp default ipv4-unicast: {} diff --git a/function/__version__.py b/function/__version__.py index ae1ff60..cd60b9d 100644 --- a/function/__version__.py +++ b/function/__version__.py @@ -16,4 +16,4 @@ """The version of the function.""" # This is set at build time, using "hatch version" -__version__ = "0.0.15" +__version__ = "0.0.16" diff --git a/function/fn.py b/function/fn.py index 33eda66..6b151a1 100644 --- a/function/fn.py +++ b/function/fn.py @@ -43,10 +43,12 @@ async def RunFunction( rsp = response.to(req) - composite = req.observed.composite.resource - name_prefix = composite["metadata"]["name"] - fqdn = composite["spec"]["endpoint"] - cmds = composite["spec"]["cmds"] + composite = resource.struct_to_dict(req.observed.composite.resource) + name_prefix = composite.get("metadata").get("name") + composite_spec: dict = composite.get("spec") + fqdn = composite_spec.get("endpoint") + cmds = composite_spec.get("cmds") + remove_container = composite_spec.get("removeContainer") environment = resource.struct_to_dict( req.context["apiextensions.crossplane.io/environment"] @@ -86,10 +88,13 @@ async def RunFunction( } jsonrpc_create = request_json("runCmds", params=jsonrpc_create_params) - remove_path = [*path[:-1], f"no {path[-1]}"] jsonrpc_remove_params = { **JSONRPC_BASE, - "cmds": ["enable", "configure", *remove_path], + "cmds": [ + "enable", + "configure", + *build_remove_path(path, remove_container=remove_container), + ], } jsonrpc_remove = request_json("runCmds", params=jsonrpc_remove_params) @@ -113,6 +118,30 @@ async def RunFunction( return rsp +def toggle_no(cmd: str) -> str: + """To clarify intent of build_remove_path().""" + return cmd.removeprefix("no ") if cmd.startswith("no ") else f"no {cmd}" + + +def build_remove_path(path: list[str], *, remove_container: bool = False) -> list[str]: + """Create cmd for remove op.""" + head, *tail = path + + # remove the container + if remove_container and tail: + return [f"no {head}"] + + # remove nested items + if tail: + return [ + head, + *(toggle_no(cmd) for cmd in tail), + ] + + # one line path + return [toggle_no(head)] + + def jq_path(cmds: list[str]) -> str: """Create middle part of jq logic expression.""" return "".join([f".cmds[{json.dumps(c)}]" for c in cmds]) @@ -142,7 +171,7 @@ def walk_cmds(cmds: dict, path: list[str] | None = None) -> list[list[str]]: next_path = [*path, cmd] if subtree == {}: - # Leaf → emit array + # Leaf -> emit array results.append(next_path) else: # Recurse