#!/usr/bin/env python3 # Adapted from: https://enix.io/en/blog/pxe-talos/ import functools import json import pathlib import requests import yaml NODES = pathlib.Path("nodes") SCHEMATICS = pathlib.Path("schematics") @functools.cache def get_schematic_id(schematic: str): """Lookup the schematic id associated with a given schematic""" r = requests.post("https://factory.talos.dev/schematics", data=schematic) r.raise_for_status() data = r.json() return data["id"] def schematic_constructor(loader: yaml.SafeLoader, node: yaml.nodes.ScalarNode): """Load specified schematic file and get the assocatied schematic id""" filename = loader.construct_scalar(node) try: schematic = SCHEMATICS.joinpath(filename).with_suffix(".yaml").read_text() return get_schematic_id(schematic) except Exception: raise yaml.MarkedYAMLError("Failed to load schematic", node.start_mark) def get_loader(): """Add special constructors to yaml loader""" loader = yaml.SafeLoader loader.add_constructor("!schematic", schematic_constructor) return loader @functools.cache def get_defaults(directory: pathlib.Path, root: pathlib.Path): """Compute the defaults from the provided directory and parents.""" try: with open(directory.joinpath("_defaults.yaml")) as fyaml: yml_data = yaml.load(fyaml, Loader=get_loader()) except OSError: yml_data = {} # Stop recursion when reaching root directory if directory != root: return get_defaults(directory.parent, root) | yml_data else: return yml_data def walk_files(root: pathlib.Path): """Get all files that do not start with and underscore""" for dirpath, _dirnames, filenames in root.walk(): for fn in filenames: if not fn.startswith("_"): yield dirpath.joinpath(fn) def main(): data = [] for fullname in walk_files(NODES): filename = str(fullname.relative_to(NODES).parent) + "/" + fullname.stem with open(fullname) as fyaml: yml_data = yaml.load(fyaml, Loader=get_loader()) yml_data = get_defaults(fullname.parent, NODES) | yml_data yml_data["hostname"] = fullname.stem yml_data["filename"] = filename data.append(yml_data) # Dump everything to json print(json.dumps(data)) if __name__ == "__main__": main()