Skip to content

Commit

Permalink
Ability to process a str expression directly as a list
Browse files Browse the repository at this point in the history
With this change, the following expression:

```
all:
  getValue: .path.to.list -> .elem == "something"
```

can be simplified to:

```
all: .path.to.list -> .elem == "something"
```

This commit also make clearer when the webhook won't apply any change to
the K8S manifest that is processing. This applies when using the webhook
in cli mode.
  • Loading branch information
jordi authored and jordipiqueselles committed Jun 1, 2024
1 parent 78d4634 commit c43633e
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 13 deletions.
23 changes: 12 additions & 11 deletions generic_k8s_webhook/config_parser/operator_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

class MetaOperatorParser:
def __init__(self, list_op_parser_classes: list[type], raw_str_parser: expr_parser.IRawStringParser) -> None:
self.dict_op_parser = {}
self.dict_op_parser: dict[str, OperatorParser] = {}
for op_parser_class in list_op_parser_classes:
# Make sure that op_parser_class is a proper "OperatorParser" derived class
if (
Expand All @@ -25,15 +25,17 @@ def __init__(self, list_op_parser_classes: list[type], raw_str_parser: expr_pars

self.raw_str_parser = raw_str_parser

def parse(self, op_spec: dict | str, path_op: str) -> operators.Operator:
def parse(self, op_spec: dict | str | list, path_op: str) -> operators.Operator:
if isinstance(op_spec, dict):
return self._parse_dict(op_spec, path_op)
if isinstance(op_spec, str):
return self._parse_str(op_spec, path_op)
if isinstance(op_spec, list):
return self._parse_list(op_spec, path_op)
raise RuntimeError(f"Cannot parse the type {type(op_spec)}. It must be dict or str")

def _parse_dict(self, op_spec: dict, path_op: str) -> operators.Operator:
"""It's used to parse a structured operator. Example:
"""It's used to parse a structured operator with a well defined key. Example:
```yaml
sum:
Expand Down Expand Up @@ -63,6 +65,12 @@ def _parse_str(self, op_spec: str, path_op: str) -> operators.Operator:
except Exception as e:
raise ParsingException(f"Error when parsing {path_op}") from e

def _parse_list(self, op_spec: list, path_op: str) -> operators.Operator:
if "list" not in self.dict_op_parser:
raise RuntimeError(f"Couldn't find the 'list' parser to parse the list in {path_op}")
list_parser = self.dict_op_parser["list"]
return list_parser.parse(op_spec, path_op)


class OperatorParser(abc.ABC):
def __init__(self, meta_op_parser: MetaOperatorParser) -> None:
Expand All @@ -80,14 +88,7 @@ def get_name(cls) -> str:

class BinaryOpParser(OperatorParser):
def parse(self, op_inputs: dict | list, path_op: str) -> operators.BinaryOp:
if isinstance(op_inputs, list):
list_parser = ListParser(self.meta_op_parser)
args = list_parser.parse(op_inputs, path_op)
elif isinstance(op_inputs, dict):
args = self.meta_op_parser.parse(op_inputs, path_op)
else:
raise ValueError(f"Expected dict or list as input, but got {op_inputs}")

args = self.meta_op_parser.parse(op_inputs, path_op)
try:
return self.get_operator_cls()(args)
except TypeError as e:
Expand Down
7 changes: 5 additions & 2 deletions generic_k8s_webhook/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ def cli(args):
accept, patch = webhook.process_manifest(k8s_manifest)
if not accept:
sys.exit(1)
# Show the patch if it's not None
if patch:
# Show the patch if it's not None
if args.show_patch:
print(json.dumps(patch.patch, indent=2))
else:
print(yaml.dump(patch.apply(k8s_manifest), indent=2))
else:
logging.info("No changes")
sys.exit(0)
logging.error(
f"Couldn't find a webhook called {args.wh_name}. "
Expand Down Expand Up @@ -95,11 +97,12 @@ def parse_args() -> argparse.ArgumentParser:

def main():
args = parse_args()
logging.basicConfig(format="%(asctime)s,%(msecs)03d %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s")
if args.verbose > 0:
logging.basicConfig(
format="%(asctime)s,%(msecs)03d %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s", level=logging.INFO
)
else:
logging.basicConfig(format="%(asctime)s,%(msecs)03d %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s")
args.func(args)


Expand Down
28 changes: 28 additions & 0 deletions tests/conditions_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -314,3 +314,31 @@ test_suites:
- name: istio
maxCPU: 2
expected_result: [true]
- name: BINARY_OP_ON_STR_LIST_MAP
tests:
- schemas: [v1beta1]
cases:
- condition:
all: .nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution.*.preference.matchExpressions.* -> .key != "myKey"
context:
- nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- preference:
matchExpressions:
- key: key1
- preference:
matchExpressions:
- key: key2
expected_result: true
- condition:
all: .nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution.*.preference.matchExpressions.* -> .key != "myKey"
context:
- nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- preference:
matchExpressions:
- key: key1
- preference:
matchExpressions:
- key: myKey
expected_result: false

0 comments on commit c43633e

Please sign in to comment.