Saltstack Official OpenSSH Formula
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

316 lines
9.9KB

  1. {#- -*- coding: utf-8 -*- #}
  2. {#- vim: ft=jinja #}
  3. {#- Get the `tplroot` from `tpldir` #}
  4. {%- set tplroot = tpldir.split("/")[0] %}
  5. {%- from tplroot ~ "/libmatchers.jinja" import parse_matchers, query_map with context %}
  6. {%- set _default_config_dirs = [
  7. "parameters/",
  8. tplroot ~ "/parameters"
  9. ] %}
  10. {%- macro mapstack(
  11. matchers,
  12. defaults=None,
  13. dirs=_default_config_dirs,
  14. log_prefix="libmapstack: "
  15. ) %}
  16. {#-
  17. Load configuration in the order of `matchers` and merge
  18. successively the values with `defaults`.
  19. The `matchers` are processed using `libmatchers.jinja` to select
  20. the configuration sources from where the values are loaded.
  21. Parameters:
  22. - `matchers`: list of matchers in the form
  23. `[<TYPE>[:<OPTION>[:<DELIMITER>]]@]<QUERY>`
  24. - `defaults`: dictionary of default values to start the merging,
  25. they are considered built-ins. It must conform to the same
  26. layout as the YAML files: a mandatory `values` key and two
  27. optional `strategy` and `merge_lists` keys.
  28. - `dirs`: list of directory where to look-up the configuration
  29. file matching the matchers, by default a global `salt://parameters/`
  30. and a per formula `salt://<tplroot>/parameters`
  31. - `log_prefix`: prefix used in the log outputs, by default it is
  32. `libmapstack: `
  33. Example: On a Debian system with `roles=["nginx/server", "telegraf"]`
  34. {%- set settings = mapstack(
  35. matchers=[
  36. "Y:G@os_family",
  37. "I@" ~ tplroot,
  38. "Y:C@roles",
  39. ],
  40. dirs=["defaults", tplroot ~ "/parameters"],
  41. )
  42. | load_yaml %}
  43. This will merge the values:
  44. - starting with the default empty dictionary `{}` (no
  45. `defaults` parameter)
  46. - from the YAML files
  47. - `salt://defaults/os_family/Debian.yaml`
  48. - `salt://{{ tplroot }}/parameters/os_family/Debian.yaml`
  49. - from the pillar `salt["pillar.get"](tplroot)`
  50. - from the `nginx/server` YAML files:
  51. - `salt://defaults/roles/nginx/server.yaml`
  52. - `salt://{{ tplroot }}/parameters/roles/nginx/server.yaml`
  53. - from the `telegraf` YAML files:
  54. - `salt://defaults/roles/telegraf.yaml`
  55. - `salt://{{ tplroot }}/parameters/roles/telegraf.yaml`
  56. Each YAML file and the `defaults` parameters must conform to the
  57. following layout:
  58. - a mandatory `values` key to store the configuration values
  59. - two optional keys to configure the use of `salt.slsutil.merge`
  60. - an optional `strategy` key to configure the merging
  61. strategy, for example `strategy: 'recurse'`, the default is
  62. `smart`
  63. - an optional `merge_lists` key to configure if lists should
  64. be merged or overridden for the `recurse` and `overwrite`
  65. strategies, for example `merge_lists: 'true'`
  66. #}
  67. {%- set stack = defaults | default({"values": {} }, boolean=True) %}
  68. {#- Build configuration file names based on matchers #}
  69. {%- set config_get_strategy = salt["config.get"](tplroot ~ ":strategy", None) %}
  70. {%- set matchers = parse_matchers(
  71. matchers,
  72. config_get_strategy=config_get_strategy,
  73. log_prefix=log_prefix
  74. )
  75. | load_yaml %}
  76. {%- do salt["log.debug"](
  77. log_prefix
  78. ~ "built-in configuration:\n"
  79. ~ {"values": defaults | traverse("values")}
  80. | yaml(False)
  81. ) %}
  82. {%- for param_dir in dirs %}
  83. {%- for matcher in matchers %}
  84. {#- `slsutil.merge` options from #}
  85. {#- 1. the `value` #}
  86. {#- 2. the `defaults` #}
  87. {#- 3. the built-in #}
  88. {%- set strategy = matcher.value
  89. | traverse(
  90. "strategy",
  91. defaults
  92. | traverse(
  93. "strategy",
  94. "smart"
  95. )
  96. ) %}
  97. {%- set merge_lists = matcher.value
  98. | traverse(
  99. "merge_lists",
  100. defaults
  101. | traverse(
  102. "merge_lists",
  103. False
  104. )
  105. )
  106. | to_bool %}
  107. {%- if matcher.type in query_map.keys() %}
  108. {#- No value is an empty list, must be a dict for `stack.update` #}
  109. {%- set normalized_value = matcher.value | default({}, boolean=True) %}
  110. {#- Merge in `mapdata.<query>` instead of directly in `mapdata` #}
  111. {%- set is_sub_key = matcher.option | default(False) == "SUB" %}
  112. {%- if is_sub_key %}
  113. {#- Merge values with `mapdata.<key>`, `<key>` and `<key>:lookup` are merged together #}
  114. {%- set value = { matcher.query | regex_replace(":lookup$", ""): normalized_value } %}
  115. {%- else %}
  116. {%- set value = normalized_value %}
  117. {%- endif %}
  118. {%- do salt["log.debug"](
  119. log_prefix
  120. ~ "merge "
  121. ~ "sub key " * is_sub_key
  122. ~ "'"
  123. ~ matcher.query
  124. ~ "' retrieved with '"
  125. ~ matcher.query_method
  126. ~ "', merge: strategy='"
  127. ~ strategy
  128. ~ "', lists='"
  129. ~ merge_lists
  130. ~ "':\n"
  131. ~ value
  132. | yaml(False)
  133. ) %}
  134. {%- do stack.update(
  135. {
  136. "values": salt["slsutil.merge"](
  137. stack["values"],
  138. value,
  139. strategy=strategy,
  140. merge_lists=merge_lists,
  141. )
  142. }
  143. ) %}
  144. {%- else %}
  145. {#- Load YAML file matching the grain/pillar/... #}
  146. {#- Fallback to use the source name as a direct filename #}
  147. {%- if matcher.value is sequence and matcher.value | length == 0 %}
  148. {#- Mangle `matcher.value` to use it as literal path #}
  149. {%- set query_parts = matcher.query.split("/") %}
  150. {%- set yaml_dirname = query_parts[0:-1] | join("/") %}
  151. {%- set yaml_names = query_parts[-1] %}
  152. {%- else %}
  153. {%- set yaml_dirname = matcher.query %}
  154. {%- set yaml_names = matcher.value %}
  155. {%- endif %}
  156. {#- Some configuration return list #}
  157. {%- if yaml_names is string %}
  158. {%- set yaml_names = [yaml_names] %}
  159. {%- elif yaml_names is sequence %}
  160. {#- Convert to strings if it's a sequence of numbers #}
  161. {%- set yaml_names = yaml_names | map("string") | list %}
  162. {%- else %}
  163. {%- set yaml_names = [yaml_names | string] %}
  164. {%- endif %}
  165. {#- Try to load a `.yaml.jinja` file for each `.yaml` file #}
  166. {%- set all_yaml_names = [] %}
  167. {%- for name in yaml_names %}
  168. {%- set extension = name.rpartition(".")[2] %}
  169. {%- if extension not in ["yaml", "jinja"] %}
  170. {%- do all_yaml_names.extend([name ~ ".yaml", name ~ ".yaml.jinja"]) %}
  171. {%- elif extension == "yaml" %}
  172. {%- do all_yaml_names.extend([name, name ~ ".jinja"]) %}
  173. {%- else %}
  174. {%- do all_yaml_names.append(name) %}
  175. {%- endif %}
  176. {%- endfor %}
  177. {#- `yaml_dirname` can be an empty string with literal path like `myconf.yaml` #}
  178. {%- set yaml_dir = [
  179. param_dir,
  180. yaml_dirname
  181. ]
  182. | select
  183. | join("/") %}
  184. {%- for yaml_name in all_yaml_names %}
  185. {%- set yaml_filename = [
  186. yaml_dir.rstrip("/"),
  187. yaml_name
  188. ]
  189. | select
  190. | join("/") %}
  191. {%- do salt["log.debug"](
  192. log_prefix
  193. ~ "load configuration values from "
  194. ~ yaml_filename
  195. ) %}
  196. {%- load_yaml as yaml_values %}
  197. {%- include yaml_filename ignore missing %}
  198. {%- endload %}
  199. {%- if yaml_values %}
  200. {%- do salt["log.debug"](
  201. log_prefix
  202. ~ "loaded configuration values from "
  203. ~ yaml_filename
  204. ~ ":\n"
  205. ~ yaml_values
  206. | yaml(False)
  207. ) %}
  208. {#- `slsutil.merge` options from #}
  209. {#- 1. the `value` #}
  210. {#- 2. the `defaults` #}
  211. {#- 3. the built-in #}
  212. {%- set strategy = yaml_values
  213. | traverse(
  214. "strategy",
  215. defaults
  216. | traverse(
  217. "strategy",
  218. "smart"
  219. )
  220. ) %}
  221. {%- set merge_lists = yaml_values
  222. | traverse(
  223. "merge_lists",
  224. defaults
  225. | traverse(
  226. "merge_lists",
  227. False
  228. )
  229. )
  230. | to_bool %}
  231. {%- do stack.update(
  232. {
  233. "values": salt["slsutil.merge"](
  234. stack["values"],
  235. yaml_values
  236. | traverse("values", {}),
  237. strategy=strategy,
  238. merge_lists=merge_lists,
  239. )
  240. }
  241. ) %}
  242. {%- do salt["log.debug"](
  243. log_prefix
  244. ~ "merged configuration values from "
  245. ~ yaml_filename
  246. ~ ", merge: strategy='"
  247. ~ strategy
  248. ~ "', merge_lists='"
  249. ~ merge_lists
  250. ~ "':\n"
  251. ~ {"values": stack["values"]}
  252. | yaml(False)
  253. ) %}
  254. {%- endif %}
  255. {%- endfor %}
  256. {%- endif %}
  257. {%- endfor %}
  258. {%- endfor %}
  259. {%- do salt["log.debug"](
  260. log_prefix
  261. ~ "final configuration values:\n"
  262. ~ {"values": stack["values"]}
  263. | yaml(False)
  264. ) %}
  265. {#- Output stack as YAML, caller should use with something like #}
  266. {#- `{%- set config = mapstack(matchers=["foo"]) | load_yaml %}` #}
  267. {{ stack | yaml }}
  268. {%- endmacro %}