Skip to content

Commit

Permalink
feat: add more resolvers + logging + error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
MatteoVoges committed Aug 29, 2023
1 parent 53559ca commit 7fbb6f0
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 17 deletions.
7 changes: 5 additions & 2 deletions docs/pages/inventory/omegaconf.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,18 @@ We provide some basic resolvers:

* OmegaConf
* `oc.env`: access a environment variable
* `oc.select`: provide a default value for an interpolation
* `oc.select`: provide a default value for an interpolation path
* `oc.dict.keys`: get the keys of a dictionary object as a list
* `oc.dict.values`: get the values of dictionary object as a list
* Utilities
* `key`: get the name of the nodes key
* `fullkey`: get the full name of the key
* `parentkey`: get the name of the nodes parent key
* `relpath`: takes an absolute path and convert it to relative
* `tag`: creates an escaped interpolation
* `escape`: creates an escaped interpolation
* `eval`: evaluates a python statement
* `default`: takes more than one values as default values and chooses the first available
* `write`: takes a path and an object and writes (merge) object to path (works only for dicts)
* Casting and Merging
* `dict`: cast a dict inside a list into the actual dict
* `list`: put a dict inside a list with that dict
Expand Down
77 changes: 62 additions & 15 deletions kapitan/inventory/resolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,25 +68,67 @@ def to_list(input):
return list(input)


def relpath(path: str, _node_: Node):
"""resolver function, that translates an absolute yaml-path to its relativ path"""
start = _node_._get_full_key("")
start = start.replace("[", ".")
def default(*args):
output = ""
for arg in args[:-1]:
output += "${oc.select:" + str(arg) + ","

output += str(args[-1])
output += "}" * (len(args) - 1)
return output


def relpath(path: str, _node_):
"""
resolver function, that translates an absolute yaml-path to its relative path
"""

node_parts = []
path_parts = path.split(".")
start_parts = start.split(".")
relative_path = ""

i = 0
node = _node_
while node._key() is not None:
node_parts.append(node._key())
node = node._get_parent()
i += 1

node_parts.reverse()

for idx, (path_part, node_path) in enumerate(zip(path_parts, node_parts)):
if not path_part == node_path:
rel_prefix = "." * (i - idx) if idx != 0 else ""
relative_path = rel_prefix + ".".join(path_parts[idx:])
break

while path_parts and start_parts and path_parts[0] == start_parts[0]:
path_parts.pop(0)
start_parts.pop(0)
if not relative_path:
# print warning for self reference
return "SELF REFERENCE DETECTED"

# Construct relative path
rel_parts = ["."] * (len(start_parts))
reminder_path = ".".join(path_parts)
relative_interpolation = "${" + relative_path + "}"

rel_path = "".join(rel_parts) + reminder_path
return relative_interpolation

return f"${{{rel_path}}}"

def write_to_key(location: str, content: dict, _root_):
"""
resolver function to write any content to different place in the inventory
NOTE: Behavior for lists is not well defined
"""
parts = location.split(".")
key = _root_

# iterate through parts and create dicts if part not found
for part in parts:
if not hasattr(key, part):
setattr(key, part, {}) # TODO: think about list managing

# update key
key = getattr(key, part)

# update target key
key.update(content)


def helm_dep(name: str, source: str):
Expand Down Expand Up @@ -133,6 +175,8 @@ def register_resolvers(inventory_path: str) -> None:
OmegaConf.register_new_resolver("dict", to_dict, replace=replace)
OmegaConf.register_new_resolver("list", to_list, replace=replace)
OmegaConf.register_new_resolver("add", lambda x, y: x + y, replace=replace)
OmegaConf.register_new_resolver("default", default, replace=replace)
OmegaConf.register_new_resolver("write", write_to_key, replace=replace)

# kapitan helpers / templates
OmegaConf.register_new_resolver("helm_dep", helm_dep, replace=replace)
Expand All @@ -144,7 +188,7 @@ def register_resolvers(inventory_path: str) -> None:
try:
register_user_resolvers(inventory_path)
except:
logger.debug(f"Couldn't import {os.join(inventory_path, 'resolvers.py')}")
logger.warning(f"Couldn't import {os.path.join(inventory_path, 'resolvers.py')}")


def register_user_resolvers(inventory_path: str) -> None:
Expand All @@ -155,9 +199,12 @@ def register_user_resolvers(inventory_path: str) -> None:
from resolvers import pass_resolvers

funcs = pass_resolvers()
except:
except ImportError:
logger.warning("resolvers.py must contain function 'pass_resolvers()'")
return
except Exception as e:
logger.error(f"resolvers.py: {e}")
return

if not isinstance(funcs, dict):
logger.warning("pass_resolvers() should return a dict")
Expand Down

0 comments on commit 7fbb6f0

Please sign in to comment.