Skip to content

Commit

Permalink
refactor: add util functions for interface
Browse files Browse the repository at this point in the history
  • Loading branch information
MatteoVoges committed Jan 17, 2024
1 parent 96e385c commit f3c17ba
Show file tree
Hide file tree
Showing 12 changed files with 77 additions and 56 deletions.
22 changes: 6 additions & 16 deletions kapitan/inventory/inv_reclass.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,29 +40,19 @@ def render_targets(self, targets: list = None, ignore_class_notfound: bool = Fal
rendered_inventory = _reclass.inventory()

# store parameters and classes
for name, rendered_target in rendered_inventory["nodes"].items():
self.targets[name].parameters = rendered_target["parameters"]
for target_name, rendered_target in rendered_inventory["nodes"].items():
self.targets[target_name].parameters = rendered_target["parameters"]

for class_name, referenced_targets in rendered_inventory["classes"].items():
for target_name in referenced_targets:
self.targets[target_name].classes += class_name

except ReclassException as e:
if isinstance(e, NotFoundError):
logger.error("Inventory reclass error: inventory not found")
else:
logger.error(f"Inventory reclass error: {e.message}")
raise InventoryError(e.message)

def get_targets(self, target_names: list) -> dict:

for target_name in target_names:
target = self.targets.get(target_name)
if not target:
raise InventoryError(f"target '{target_name}' not found")

if not target.parameters:
# reclass has no optimization for rendering only some specific targets,
# so we have to render the whole inventory
self.render_targets()

return {name: target.parameters for name, target in self.targets.items() if name in target_names}


def get_reclass_config(inventory_path: str) -> dict:
Expand Down
55 changes: 43 additions & 12 deletions kapitan/inventory/inventory.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import time
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import overload, Union

from kapitan.errors import KapitanError
from kapitan.reclass.reclass.values import item
Expand All @@ -23,6 +24,7 @@ class InventoryTarget:
path: str
composed_name: str
parameters: dict = field(default_factory=dict)
classes: list = field(default_factory=list)


class Inventory(ABC):
Expand All @@ -40,16 +42,17 @@ def __init__(self, path: str = path, compose_target_name: bool = False):

@property
def inventory(self) -> dict:
if not self.targets:
return self.render_targets()
return {name: target.parameters for name, target in self.targets.items()}

@abstractmethod
def render_targets(self, targets: list = None, ignore_class_notfound: bool = False) -> dict:
"""
create the inventory depending on which backend gets used
get all targets from inventory
targets will be rendered
"""
raise NotImplementedError
if not self.targets:
self.search_targets()

inventory = self.get_targets([*self.targets.keys()])

return {target_name: {"parameters": target.parameters, "classes": target.classes}
for target_name, target in inventory.items()}

def search_targets(self) -> dict:
"""
Expand Down Expand Up @@ -84,16 +87,44 @@ def search_targets(self) -> dict:

return self.targets

def get_target(self, target_name: str) -> dict:
def get_target(self, target_name: str) -> InventoryTarget:
"""
helper function to get parameters for a specific target
helper function to get rendered InventoryTarget object for single target
"""
return self.get_targets([target_name])[target_name]

@abstractmethod
def get_targets(self, target_names: list) -> dict:
"""
helper function to get parameters for multiple targets
helper function to get rendered InventoryTarget objects for multiple targets
"""
targets_to_render = []

for target_name in target_names:
target = self.targets.get(target_name)
if not target:
raise InventoryError(f"target '{target_name}' not found")

if not target.parameters:
targets_to_render.append(target)

self.render_targets(targets_to_render)

return {name: target for name, target in self.targets.items() if name in target_names}

def get_parameters(self, target_names: Union[str, list]) -> dict:
"""
helper function to get rendered parameters for single target or multiple targets
"""
if type(target_names) is str:
target = self.get_target(target_names)
return target.parameters

return {name: target.parameters for name, target in self.get_targets(target_names)}

@abstractmethod
def render_targets(self, targets: list = None, ignore_class_notfound: bool = False):
"""
create the inventory depending on which backend gets used
"""
raise NotImplementedError

Expand Down
22 changes: 11 additions & 11 deletions kapitan/refs/cmd_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def ref_write(args, ref_controller):
recipients = [dict((("name", name),)) for name in args.recipients]
if args.target_name:
inv = get_inventory(args.inventory_path)
kap_inv_params = inv.get_target(args.target_name)["kapitan"]
kap_inv_params = inv.get_parameters(args.target_name)["kapitan"]
if "secrets" not in kap_inv_params:
raise KapitanError(
"parameters.kapitan.secrets not defined in inventory of target {}".format(
Expand Down Expand Up @@ -96,7 +96,7 @@ def ref_write(args, ref_controller):
key = args.key
if args.target_name:
inv = get_inventory(args.inventory_path)
kap_inv_params = inv.get_target(args.target_name)["kapitan"]
kap_inv_params = inv.get_parameters(args.target_name)["kapitan"]
if "secrets" not in kap_inv_params:
raise KapitanError(
"parameters.kapitan.secrets not defined in inventory of target {}".format(
Expand Down Expand Up @@ -124,7 +124,7 @@ def ref_write(args, ref_controller):
key = args.key
if args.target_name:
inv = get_inventory(args.inventory_path)
kap_inv_params = inv.get_target(args.target_name)["kapitan"]
kap_inv_params = inv.get_parameters(args.target_name)["kapitan"]
if "secrets" not in kap_inv_params:
raise KapitanError(
"parameters.kapitan.secrets not defined in inventory of target {}".format(
Expand Down Expand Up @@ -153,7 +153,7 @@ def ref_write(args, ref_controller):
key = args.key
if args.target_name:
inv = get_inventory(args.inventory_path)
kap_inv_params = inv.get_target(args.target_name)["kapitan"]
kap_inv_params = inv.get_parameters(args.target_name)["kapitan"]
if "secrets" not in kap_inv_params:
raise KapitanError(
"parameters.kapitan.secrets not defined in inventory of target {}".format(
Expand Down Expand Up @@ -197,7 +197,7 @@ def ref_write(args, ref_controller):
encoding = "original"
if args.target_name:
inv = get_inventory(args.inventory_path)
kap_inv_params = inv.get_target(args.target_name)["kapitan"]
kap_inv_params = inv.get_parameters(args.target_name)["kapitan"]
if "secrets" not in kap_inv_params:
raise KapitanError(
"parameters.kapitan.secrets not defined in inventory of target {}".format(
Expand Down Expand Up @@ -252,7 +252,7 @@ def ref_write(args, ref_controller):
vault_params = {}
if args.target_name:
inv = get_inventory(args.inventory_path)
kap_inv_params = inv.get_target(args.target_name)["kapitan"]
kap_inv_params = inv.get_parameters(args.target_name)["kapitan"]
if "secrets" not in kap_inv_params:
raise KapitanError("parameters.kapitan.secrets not defined in {}".format(args.target_name))

Expand Down Expand Up @@ -324,7 +324,7 @@ def secret_update(args, ref_controller):
]
if args.target_name:
inv = get_inventory(args.inventory_path)
kap_inv_params = inv.get_target(args.target_name)["kapitan"]
kap_inv_params = inv.get_parameters(args.target_name)["kapitan"]
if "secrets" not in kap_inv_params:
raise KapitanError("parameters.kapitan.secrets not defined in {}".format(args.target_name))

Expand Down Expand Up @@ -352,7 +352,7 @@ def secret_update(args, ref_controller):
key = args.key
if args.target_name:
inv = get_inventory(args.inventory_path)
kap_inv_params = inv.get_target(args.target_name)["kapitan"]
kap_inv_params = inv.get_parameters(args.target_name)["kapitan"]
if "secrets" not in kap_inv_params:
raise KapitanError("parameters.kapitan.secrets not defined in {}".format(args.target_name))

Expand All @@ -378,7 +378,7 @@ def secret_update(args, ref_controller):
key = args.key
if args.target_name:
inv = get_inventory(args.inventory_path)
kap_inv_params = inv.get_target(args.target_name)["kapitan"]
kap_inv_params = inv.get_parameters(args.target_name)["kapitan"]
if "secrets" not in kap_inv_params:
raise KapitanError("parameters.kapitan.secrets not defined in {}".format(args.target_name))

Expand All @@ -404,7 +404,7 @@ def secret_update(args, ref_controller):
key = args.key
if args.target_name:
inv = get_inventory(args.inventory_path)
kap_inv_params = inv.get_target(args.target_name)["kapitan"]
kap_inv_params = inv.get_parameters(args.target_name)["kapitan"]
if "secrets" not in kap_inv_params:
raise KapitanError("parameters.kapitan.secrets not defined in {}".format(args.target_name))

Expand Down Expand Up @@ -467,7 +467,7 @@ def secret_update_validate(args, ref_controller):
ret_code = 0

for target_name, token_paths in target_token_paths.items():
kap_inv_params = inv.get_target(target_name)["kapitan"]
kap_inv_params = inv.get_parameters(target_name)["kapitan"]
if "secrets" not in kap_inv_params:
raise KapitanError("parameters.kapitan.secrets not defined in {}".format(target_name))

Expand Down
2 changes: 1 addition & 1 deletion kapitan/refs/secrets/awskms.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def from_params(cls, data, ref_params):
if target_name is None:
raise ValueError("target_name not set")

target_inv = cached.inv.get_target(target_name)
target_inv = cached.inv.get_parameters(target_name)
if target_inv is None:
raise ValueError("target_inv not set")

Expand Down
2 changes: 1 addition & 1 deletion kapitan/refs/secrets/azkms.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def from_params(cls, data, ref_params):
if target_name is None:
raise ValueError("target_name not set")

target_inv = cached.inv.get_target(target_name)
target_inv = cached.inv.get_parameters(target_name)

key = target_inv["kapitan"]["secrets"]["azkms"]["key"]
return cls(data, key, **ref_params.kwargs)
Expand Down
2 changes: 1 addition & 1 deletion kapitan/refs/secrets/gkms.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def from_params(cls, data, ref_params):
if target_name is None:
raise ValueError("target_name not set")

target_inv = cached.inv.get_target(target_name)
target_inv = cached.inv.get_parameters(target_name)

key = target_inv["kapitan"]["secrets"]["gkms"]["key"]
return cls(data, key, **ref_params.kwargs)
Expand Down
2 changes: 1 addition & 1 deletion kapitan/refs/secrets/gpg.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def from_params(cls, data, ref_params):
if target_name is None:
raise ValueError("target_name not set")

target_inv = cached.inv.get_target(target_name)
target_inv = cached.inv.get_parameters(target_name)

if "secrets" not in target_inv["kapitan"]:
raise KapitanError(
Expand Down
2 changes: 1 addition & 1 deletion kapitan/refs/secrets/vaultkv.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def from_params(cls, data, ref_params):
if target_name is None:
raise ValueError("target_name not set")

target_inv = cached.inv.get_target(target_name)
target_inv = cached.inv.get_parameters(target_name)

try:
vault_params = target_inv["kapitan"]["secrets"]["vaultkv"]
Expand Down
2 changes: 1 addition & 1 deletion kapitan/refs/secrets/vaulttransit.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def from_params(cls, data, ref_params):
if target_name is None:
raise ValueError("target_name not set")

target_inv = cached.inv.get_target(target_name)
target_inv = cached.inv.get_parameters(target_name)

ref_params.kwargs["vault_params"] = target_inv["kapitan"]["secrets"]["vaulttransit"]

Expand Down
9 changes: 5 additions & 4 deletions kapitan/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ def search_imports(cwd, import_str, search_paths):
return normalised_path, normalised_path_content.encode()


def inventory(search_paths: list, target, inventory_path: str = None):
def inventory(search_paths: list, target_name: str = None, inventory_path: str = "./inventory"):
"""
Reads inventory (set by inventory_path) in search_paths.
set nodes_uri to change reclass nodes_uri the default value
Expand Down Expand Up @@ -276,8 +276,9 @@ def inventory(search_paths: list, target, inventory_path: str = None):

inv = get_inventory(full_inv_path)

if target:
return {"parameters": inv.get_target(target)}
if target_name:
target = inv.get_target(target_name)
return {"parameters": target.parameters, "classes": target.classes}

return inv.inventory

Expand All @@ -287,7 +288,7 @@ def generate_inventory(args):
inv = get_inventory(args.inventory_path)

if args.target_name:
inv = inv.get_target(args.target_name)
inv = inv.get_parameters(args.target_name)
if args.pattern:
pattern = args.pattern.split(".")
inv = deep_get(inv, pattern)
Expand Down
11 changes: 5 additions & 6 deletions kapitan/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,15 +250,15 @@ def generate_inv_cache_hashes(inventory_path, targets, cache_paths):
for target in targets:
try:
cached.inv_cache["inventory"][target] = {}
cached.inv_cache["inventory"][target] = dictionary_hash(inv.get_target(target))
cached.inv_cache["inventory"][target] = dictionary_hash(inv.get_parameters(target))
except KeyError:
raise CompileError(f"target not found: {target}")
else:
for target in inv.targets.keys():
cached.inv_cache["inventory"][target] = {}
cached.inv_cache["inventory"][target] = dictionary_hash(inv.get_target(target))
cached.inv_cache["inventory"][target] = dictionary_hash(inv.get_parameters(target))

compile_obj = inv.get_target(target)["kapitan"]["compile"]
compile_obj = inv.get_parameters(target)["kapitan"]["compile"]
for obj in compile_obj:
for input_path in obj["input_paths"]:
base_folder = os.path.dirname(input_path).split("/")[0]
Expand Down Expand Up @@ -374,8 +374,7 @@ def load_target_inventory(inventory_path, targets, ignore_class_notfound=False):

for target_name in targets_list:
try:
target_obj = inv.get_target(target_name)
target_obj = target_obj.get("kapitan")
target_obj = inv.get_parameters(target_name).get("kapitan")
# check if parameters.kapitan is empty
if not target_obj:
raise InventoryError(f"InventoryError: {target_name}: parameters.kapitan has no assignment")
Expand Down Expand Up @@ -410,7 +409,7 @@ def search_targets(inventory_path, targets, labels):
matched_all_labels = False
for label, value in labels_dict.items():
try:
if inv.get_target(target_name)["kapitan"]["labels"][label] == value:
if inv.get_parameters(target_name)["kapitan"]["labels"][label] == value:
matched_all_labels = True
continue
except KeyError:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ def test_compile_not_matching_targets(self):
def test_compile_vars_target_missing(self):
inventory_path = "inventory"
target_filename = "minikube-es"
target_obj = get_inventory(inventory_path).get_target(target_filename)["kapitan"]
target_obj = get_inventory(inventory_path).get_parameters(target_filename)["kapitan"]
# delete vars.target
del target_obj["vars"]["target"]

Expand Down

0 comments on commit f3c17ba

Please sign in to comment.