Skip to content

Commit

Permalink
feat(exec): Add json output filter
Browse files Browse the repository at this point in the history
  • Loading branch information
MrKevinWeiss committed Sep 12, 2023
1 parent 984ad53 commit ab5b90c
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 7 deletions.
53 changes: 53 additions & 0 deletions src/inet_nm/_helpers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Interactive user prompts and general basic helpers."""

import json
import os
import readline
import sys
Expand Down Expand Up @@ -223,3 +224,55 @@ def nm_print(*args, **kwargs):
def nm_input(*args, **kwargs):
"""Abstraction of input."""
return input(*args, **kwargs)


def nm_extract_valid_jsons(text):
"""
Extract valid JSON strings from a given text.
This function iterates through the provided text character by character,
keeping track of the opening and closing braces to extract potential JSON strings.
It then validates each potential JSON string and returns a list of valid
JSON objects.
Args:
- text (str): The input text containing potential JSON strings.
Returns:
- list: A list of valid JSON objects.
Example:
>>> x = 'Log output 123\\n{ "a": 1} foobar\\nmore log stuff'
>>> x += '\\n{\\n "b": 2, "c": 3,\\n"d": [{"e": 5}]\\n} and so on\\nblah blah'
>>> nm_extract_valid_jsons(x)
[{'a': 1}, {'b': 2, 'c': 3, 'd': [{'e': 5}]}]
"""

def extract_potential_jsons(text):
potential_jsons = []
brace_count = 0
start_index = -1

for i, char in enumerate(text):
if char == "{":
if brace_count == 0:
start_index = i
brace_count += 1
elif char == "}":
brace_count -= 1
if brace_count == 0 and start_index != -1:
potential_jsons.append(text[start_index : i + 1])

return potential_jsons

potential_jsons = extract_potential_jsons(text)

valid_jsons = []
for potential in potential_jsons:
try:
valid_json = json.loads(potential)
valid_jsons.append(valid_json)
except json.JSONDecodeError:
pass

return valid_jsons
8 changes: 8 additions & 0 deletions src/inet_nm/cli_exec.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ def main():
default=None,
help="Filter all lines with regex.",
)
parser.add_argument(
"-j",
"--json-filter",
action="store_true",
help="Capture only json output.",
)

cfg.config_arg(parser)
chk.check_args(parser)
Expand All @@ -51,6 +57,7 @@ def main():
seq = kwargs.pop("seq")
force = kwargs.pop("force")
output_filter = kwargs.pop("output_filter")
json_filter = kwargs.pop("json_filter")
nodes = rh.sanity_check("/bin/bash", **kwargs)

extra_env = rh.node_env_vars(args.config)
Expand All @@ -62,6 +69,7 @@ def main():
) as runner:
runner.cmd = cmd
runner.output_filter = output_filter
runner.json_filter = json_filter
runner.run()
except KeyboardInterrupt:
print()
Expand Down
46 changes: 39 additions & 7 deletions src/inet_nm/runner_apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
NmTmuxWindowedRunner: Runs tmux with individual windows for each node.
"""

import json
import os
import re
import subprocess
import time
from typing import Dict

from inet_nm._helpers import nm_print
from inet_nm._helpers import nm_extract_valid_jsons, nm_print
from inet_nm.data_types import NmNode
from inet_nm.runner_base import NmNodesRunner

Expand All @@ -31,6 +32,7 @@ class NmShellRunner(NmNodesRunner):
cmd = "echo $NM_IDX"
SETUP_WAIT = 0.1
output_filter = None
json_filter = False
results = []

@staticmethod
Expand Down Expand Up @@ -65,6 +67,27 @@ def get_output(process):

return rc

@staticmethod
def _run_command_json(cmd, uid, board, idx, env):
# Run subprocess command to completion and capture output
result = subprocess.run(
cmd,
env=env,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
data = nm_extract_valid_jsons(result.stdout.decode())
result_output = {
"uid": uid,
"board": board,
"idx": idx,
"data": data,
"stdout": result.stdout.decode(),
"result": result.returncode,
}
return result_output

def func(self, node: NmNode, idx: int, env: Dict[str, str]):
"""Execute shell commands on nodes.
Expand Down Expand Up @@ -93,19 +116,28 @@ def func(self, node: NmNode, idx: int, env: Dict[str, str]):
regex_str = None
else:
regex_str = re.compile(self.output_filter)
res = NmShellRunner._run_command(
cmd, prefix=prefix, env=full_env, regex_str=regex_str
)
if self.output_filter is None:
if self.json_filter:
res = NmShellRunner._run_command_json(
cmd, node.uid, node.board, idx, env=full_env
)
self.results.append(res)
else:
res = NmShellRunner._run_command(
cmd, prefix=prefix, env=full_env, regex_str=regex_str
)
if self.output_filter is None and not self.json_filter:
self.results.append(f"RESULT:{prefix}{res}")

def post(self):
"""Run after the operations on nodes have completed.
It prints the results of the commands executed on nodes.
"""
for result in self.results:
nm_print(result)
if self.json_filter:
nm_print(json.dumps(self.results, indent=2, sort_keys=True))
else:
for result in self.results:
nm_print(result)


class NmTmuxBaseRunner(NmNodesRunner):
Expand Down

0 comments on commit ab5b90c

Please sign in to comment.