Saltstack Official OpenSSH Formula
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

301 lines
9.2KB

  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 %}
  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 matchers = parse_matchers(
  70. matchers,
  71. log_prefix=log_prefix
  72. )
  73. | load_yaml %}
  74. {%- do salt["log.debug"](
  75. log_prefix
  76. ~ "built-in configuration:\n"
  77. ~ {"values": defaults | traverse("values")}
  78. | yaml(False)
  79. ) %}
  80. {%- for param_dir in dirs %}
  81. {%- for matcher in matchers %}
  82. {#- `slsutil.merge` options from #}
  83. {#- 1. the `value` #}
  84. {#- 2. the `defaults` #}
  85. {#- 3. the built-in #}
  86. {%- set strategy = matcher.value
  87. | traverse(
  88. "strategy",
  89. defaults
  90. | traverse(
  91. "strategy",
  92. "smart"
  93. )
  94. ) %}
  95. {%- set merge_lists = matcher.value
  96. | traverse(
  97. "merge_lists",
  98. defaults
  99. | traverse(
  100. "merge_lists",
  101. False
  102. )
  103. )
  104. | to_bool %}
  105. {%- if matcher.type in query_map.keys() %}
  106. {#- No value is an empty list, must be a dict for `stack.update` #}
  107. {%- set normalized_value = matcher.value | default({}, boolean=True) %}
  108. {#- Merge in `mapdata.<query>` instead of directly in `mapdata` #}
  109. {%- set is_sub_key = matcher.option | default(False) == "SUB" %}
  110. {%- if is_sub_key %}
  111. {#- Merge values with `mapdata.<key>`, `<key>` and `<key>:lookup` are merged together #}
  112. {%- set value = { matcher.query | regex_replace(":lookup$", ""): normalized_value } %}
  113. {%- else %}
  114. {%- set value = normalized_value %}
  115. {%- endif %}
  116. {%- do salt["log.debug"](
  117. log_prefix
  118. ~ "merge "
  119. ~ "sub key " * is_sub_key
  120. ~ "'"
  121. ~ matcher.query
  122. ~ "' retrieved with '"
  123. ~ matcher.query_method
  124. ~ "', merge: strategy='"
  125. ~ strategy
  126. ~ "', lists='"
  127. ~ merge_lists
  128. ~ "':\n"
  129. ~ value
  130. | yaml(False)
  131. ) %}
  132. {%- do stack.update(
  133. {
  134. "values": salt["slsutil.merge"](
  135. stack["values"],
  136. value,
  137. strategy=strategy,
  138. merge_lists=merge_lists,
  139. )
  140. }
  141. ) %}
  142. {%- else %}
  143. {#- Load YAML file matching the grain/pillar/... #}
  144. {#- Fallback to use the source name as a direct filename #}
  145. {%- if matcher.value | length == 0 %}
  146. {#- Mangle `matcher.value` to use it as literal path #}
  147. {%- set query_parts = matcher.query.split("/") %}
  148. {%- set yaml_dirname = query_parts[0:-1] | join("/") %}
  149. {%- set yaml_names = query_parts[-1] %}
  150. {%- else %}
  151. {%- set yaml_dirname = matcher.query %}
  152. {%- set yaml_names = matcher.value %}
  153. {%- endif %}
  154. {#- Some configuration return list #}
  155. {%- if yaml_names is string %}
  156. {%- set yaml_names = [yaml_names] %}
  157. {%- endif %}
  158. {#- `yaml_dirname` can be an empty string with literal path like `myconf.yaml` #}
  159. {%- set yaml_dir = [
  160. param_dir,
  161. yaml_dirname
  162. ]
  163. | select
  164. | join("/") %}
  165. {%- for yaml_name in yaml_names %}
  166. {#- Make sure to have a `.yaml` extension #}
  167. {#- Use `.rpartition` to strip last `.yaml` in `dir.yaml/file.yaml` #}
  168. {%- set yaml_filename = [
  169. yaml_dir.rstrip("/"),
  170. yaml_name.rpartition(".yaml")
  171. | reject("equalto", ".yaml")
  172. | join
  173. ~ ".yaml"
  174. ]
  175. | select
  176. | join("/") %}
  177. {%- do salt["log.debug"](
  178. log_prefix
  179. ~ "load configuration values from "
  180. ~ yaml_filename
  181. ) %}
  182. {%- load_yaml as yaml_values %}
  183. {%- include yaml_filename ignore missing %}
  184. {%- endload %}
  185. {%- if yaml_values %}
  186. {%- do salt["log.debug"](
  187. log_prefix
  188. ~ "loaded configuration values from "
  189. ~ yaml_name
  190. ~ ":\n"
  191. ~ yaml_values
  192. | yaml(False)
  193. ) %}
  194. {#- `slsutil.merge` options from #}
  195. {#- 1. the `value` #}
  196. {#- 2. the `defaults` #}
  197. {#- 3. the built-in #}
  198. {%- set strategy = yaml_values
  199. | traverse(
  200. "strategy",
  201. defaults
  202. | traverse(
  203. "strategy",
  204. "smart"
  205. )
  206. ) %}
  207. {%- set merge_lists = yaml_values
  208. | traverse(
  209. "merge_lists",
  210. defaults
  211. | traverse(
  212. "merge_lists",
  213. False
  214. )
  215. )
  216. | to_bool %}
  217. {%- do stack.update(
  218. {
  219. "values": salt["slsutil.merge"](
  220. stack["values"],
  221. yaml_values
  222. | traverse("values", {}),
  223. strategy=strategy,
  224. merge_lists=merge_lists,
  225. )
  226. }
  227. ) %}
  228. {%- do salt["log.debug"](
  229. log_prefix
  230. ~ "merged configuration values from "
  231. ~ yaml_name
  232. ~ ", merge: strategy='"
  233. ~ strategy
  234. ~ "', merge_lists='"
  235. ~ merge_lists
  236. ~ "':\n"
  237. ~ {"values": stack["values"]}
  238. | yaml(False)
  239. ) %}
  240. {%- endif %}
  241. {%- endfor %}
  242. {%- endif %}
  243. {%- endfor %}
  244. {%- endfor %}
  245. {%- do salt["log.debug"](
  246. log_prefix
  247. ~ "final configuration values:\n"
  248. ~ {"values": stack["values"]}
  249. | yaml(False)
  250. ) %}
  251. {#- Output stack as YAML, caller should use with something like #}
  252. {#- `{%- set config = mapstack(matchers=["foo"]) | load_yaml %}` #}
  253. {{ stack | yaml }}
  254. {%- endmacro %}