diff --git a/openssh/libmapstack.jinja b/openssh/libmapstack.jinja new file mode 100644 index 0000000..9ea212b --- /dev/null +++ b/openssh/libmapstack.jinja @@ -0,0 +1,127 @@ +{#- -*- coding: utf-8 -*- #} +{#- vim: ft=jinja #} + +{#- Get the `tplroot` from `tpldir` #} +{%- set tplroot = tpldir.split("/")[0] %} + +{%- macro mapstack( + files, + defaults=None, + log_prefix="libmapstack: " + ) %} +{#- + Load YAML files in the order of `files` and merge successively the + values with `defaults` if the file exists. + + Parameters: + - `files`: list of files to load + + - `defaults`: default values to start the merging, they are + considered built-ins + + - `log_prefix`: prefix used in the log outputs, by default it is + `libmapstack: ` + + Each YAML file must conform to the following layout: + - a mandatory `values` key to store the configuration values + + - two optional keys to configure the use of `salt.slsutil.merge` + + - an optional `strategy` key to configure the merging strategy, + for example `strategy: 'recurse'`, the default is `smart` + + - an optional `merge_lists` key to configure if lists should be + merged or overridden for the `recurse` and `overwrite` + strategies, for example `merge_lists: 'true'` +#} +{%- set stack = defaults | default({"values": {} }, boolean=True) %} + +{%- do salt["log.debug"]( + log_prefix + ~ "built-in configuration:\n" + ~ {"values": defaults | traverse("values")} + | yaml(False) + ) %} + +{%- for yaml_filename in files %} +{%- do salt["log.debug"]( + log_prefix + ~ "load configuration values from " + ~ yaml_filename + ) %} + +{%- load_yaml as yaml_values %} +{%- include yaml_filename ignore missing %} +{%- endload %} + +{%- do salt["log.debug"]( + log_prefix + ~ "loaded configuration values from " + ~ yaml_filename + ~ ":\n" + ~ yaml_values + | yaml(False) + ) %} + +{%- if yaml_values %} +{#- Per YAML file `salt["slsutil.merge"]` options or use defaults #} +{%- set _strategy = yaml_values + | traverse( + "strategy", + defaults + | traverse( + "strategy", + "smart" + ) + ) %} +{%- set _merge_lists = yaml_values + | traverse( + "merge_lists", + defaults + | traverse( + "merge_lists", + False + ) + ) + | to_bool %} + +{#- Update only the `values`, the `salt["slsutil.merge"]` options are never updated #} +{%- do stack.update( + { + "values": salt["slsutil.merge"]( + stack["values"], + yaml_values + | traverse("values", {}), + strategy=_strategy, + merge_lists=_merge_lists, + ) + } + ) %} +{%- do salt["log.debug"]( + log_prefix + ~ "merged configuration values from " + ~ yaml_filename + ~ ", merge: strategy='" + ~ _strategy + ~ "', merge_lists='" + ~ _merge_lists + ~ "':\n" + ~ {"values": stack["values"]} + | yaml(False) + ) %} +{%- endif %} + +{%- endfor %} + +{%- do salt["log.debug"]( + log_prefix + ~ "final configuration values:\n" + ~ {"values": stack["values"]} + | yaml(False) + ) %} + +{#- Output stack as YAML, caller should use with something like #} +{#- `{%- set config = flexible_config(prefix="foo") | load_yaml %}` #} +{{ stack | yaml }} + +{%- endmacro %} diff --git a/openssh/map.jinja b/openssh/map.jinja index 3919d84..8280213 100644 --- a/openssh/map.jinja +++ b/openssh/map.jinja @@ -4,6 +4,7 @@ {#- Get the `tplroot` from `tpldir` #} {%- set tplroot = tpldir.split("/")[0] %} {%- from tplroot ~ "/libmatchers.jinja" import parse_matchers, query_map %} +{%- from tplroot ~ "/libmapstack.jinja" import mapstack %} {#- Where to lookup parameters source files #} {%- set map_sources_dir = tplroot ~ "/parameters" %} @@ -19,65 +20,22 @@ "C@" ~ tplroot, "Y:G@id", ] %} -{%- do salt["log.debug"]( - "map.jinja: built-in configuration sources:\n" - ~ {"values": { - "map_jinja": {"sources": map_sources} - } - } - | yaml(False) - ) %} {#- Allow centralised map.jinja configuration #} -{%- set _global_map_filename = "parameters/map_jinja.yaml" %} -{%- do salt["log.debug"]( - "map.jinja: load global map.jinja values from " - ~ _global_map_filename - ) %} -{%- load_yaml as global_map_settings %} -{%- include _global_map_filename ignore missing %} -{%- endload %} - -{%- if global_map_settings %} -{%- do salt["log.debug"]( - "map.jinja: configure sources from global map.jinja configuration " - ~ _global_map_filename - ~ ":\n" - ~ {"map_jinja": global_map_settings} - | yaml(False) - ) %} -{%- set map_sources = global_map_settings - | traverse( - "values:sources", - map_sources, - ) %} -{%- endif %} - +{%- set _global_param_filename = "parameters/map_jinja.yaml" %} {#- Allow per formula map.jinja configuration #} -{%- set _map_filename = map_sources_dir ~ "/map_jinja.yaml" %} -{%- do salt["log.debug"]( - "map.jinja: load per formula map.jinja values from " - ~ _map_filename - ) %} -{%- load_yaml as map_settings %} -{%- include _map_filename ignore missing %} -{%- endload %} +{%- set _formula_param_filename = map_sources_dir ~ "/map_jinja.yaml" %} -{%- if map_settings %} -{%- do salt["log.debug"]( - "map.jinja: configure sources from formula map.jinja configuration " - ~ _map_filename - ~ ":\n" - ~ {"map_jinja": map_settings} - | yaml(False) - ) %} -{%- set map_sources = map_settings - | traverse( - "values:sources", - map_sources, - ) %} -{%- endif %} +{%- set _map_settings = mapstack( + files=[_global_param_filename, _formula_param_filename], + defaults={ + "values": {"sources": map_sources} + }, + log_prefix="map.jinja configuration: ", + ) + | load_yaml %} +{%- set map_sources = _map_settings | traverse("values:sources") %} {%- do salt["log.debug"]( "map.jinja: load parameters from sources:\n" ~ map_sources @@ -101,8 +59,7 @@ {#- Make sure to track `map.jinja` configuration with `_mapdata` #} {%- do default_settings["values"].update( { - "map_jinja": map_settings - | traverse("values", {}) + "map_jinja": _map_settings["values"] } ) %}