feat: convert `template-formula` to `arvados-formula`
[arvados-formula.git] / arvados / libtofs.jinja
diff --git a/arvados/libtofs.jinja b/arvados/libtofs.jinja
new file mode 100644 (file)
index 0000000..0668925
--- /dev/null
@@ -0,0 +1,112 @@
+{%- macro files_switch(source_files,
+                       lookup=None,
+                       default_files_switch=['id', 'os_family'],
+                       indent_width=6,
+                       use_subpath=False) %}
+  {#-
+    Returns a valid value for the "source" parameter of a "file.managed"
+    state function. This makes easier the usage of the Template Override and
+    Files Switch (TOFS) pattern.
+
+    Params:
+      * source_files: ordered list of files to look for
+      * lookup: key under '<tplroot>:tofs:source_files' to prepend to the
+        list of source files
+      * default_files_switch: if there's no config (e.g. pillar)
+        '<tplroot>:tofs:files_switch' this is the ordered list of grains to
+        use as selector switch of the directories under
+        "<path_prefix>/files"
+      * indent_width: indentation of the result value to conform to YAML
+      * use_subpath: defaults to `False` but if set, lookup the source file
+        recursively from the current state directory up to `tplroot`
+
+    Example (based on a `tplroot` of `xxx`):
+
+    If we have a state:
+
+      Deploy configuration:
+        file.managed:
+          - name: /etc/yyy/zzz.conf
+          - source: {{ files_switch(['/etc/yyy/zzz.conf', '/etc/yyy/zzz.conf.jinja'],
+                                    lookup='Deploy configuration'
+                    ) }}
+          - template: jinja
+
+    In a minion with id=theminion and os_family=RedHat, it's going to be
+    rendered as:
+
+      Deploy configuration:
+        file.managed:
+          - name: /etc/yyy/zzz.conf
+          - source:
+            - salt://xxx/files/theminion/etc/yyy/zzz.conf
+            - salt://xxx/files/theminion/etc/yyy/zzz.conf.jinja
+            - salt://xxx/files/RedHat/etc/yyy/zzz.conf
+            - salt://xxx/files/RedHat/etc/yyy/zzz.conf.jinja
+            - salt://xxx/files/default/etc/yyy/zzz.conf
+            - salt://xxx/files/default/etc/yyy/zzz.conf.jinja
+          - template: jinja
+  #}
+  {#- Get the `tplroot` from `tpldir` #}
+  {%- set tplroot = tpldir.split('/')[0] %}
+  {%- set path_prefix = salt['config.get'](tplroot ~ ':tofs:path_prefix', tplroot) %}
+  {%- set files_dir = salt['config.get'](tplroot ~ ':tofs:dirs:files', 'files') %}
+  {%- set files_switch_list = salt['config.get'](
+      tplroot ~ ':tofs:files_switch',
+      default_files_switch
+  ) %}
+  {#- Lookup source_files (v2), files (v1), or fallback to an empty list #}
+  {%- set src_files = salt['config.get'](
+      tplroot ~ ':tofs:source_files:' ~ lookup,
+      salt['config.get'](tplroot ~ ':tofs:files:' ~ lookup, [])
+  ) %}
+  {#- Append the default source_files #}
+  {%- set src_files = src_files + source_files %}
+  {#- Only add to [''] when supporting older TOFS implementations #}
+  {%- set path_prefix_exts = [''] %}
+  {%- if use_subpath and tplroot != tpldir %}
+    {#- Walk directory tree to find {{ files_dir }} #}
+    {%- set subpath_parts = tpldir.lstrip(tplroot).lstrip('/').split('/') %}
+    {%- for path in subpath_parts %}
+      {%- set subpath = subpath_parts[0:loop.index] | join('/') %}
+      {%- do path_prefix_exts.append('/' ~ subpath) %}
+    {%- endfor %}
+  {%- endif %}
+  {%- for path_prefix_ext in path_prefix_exts|reverse %}
+    {%- set path_prefix_inc_ext = path_prefix ~ path_prefix_ext %}
+    {#- For older TOFS implementation, use `files_switch` from the config #}
+    {#- Use the default, new method otherwise #}
+    {%- set fsl = salt['config.get'](
+        tplroot ~ path_prefix_ext|replace('/', ':') ~ ':files_switch',
+        files_switch_list
+    ) %}
+    {#- Append an empty value to evaluate as `default` in the loop below #}
+    {%- if '' not in fsl %}
+      {%- set fsl = fsl + [''] %}
+    {%- endif %}
+    {%- for fs in fsl %}
+      {%- for src_file in src_files %}
+        {%- if fs %}
+          {%- set fs_dirs = salt['config.get'](fs, fs) %}
+        {%- else %}
+          {%- set fs_dirs = salt['config.get'](tplroot ~ ':tofs:dirs:default', 'default') %}
+        {%- endif %}
+        {#- Force the `config.get` lookup result as a list where necessary #}
+        {#- since we need to also handle grains that are lists #}
+        {%- if fs_dirs is string %}
+          {%- set fs_dirs = [fs_dirs] %}
+        {%- endif %}
+        {%- for fs_dir in fs_dirs %}
+          {%- set url = [
+              '- salt:/',
+              path_prefix_inc_ext.strip('/'),
+              files_dir.strip('/'),
+              fs_dir.strip('/'),
+              src_file.strip('/'),
+          ] | select | join('/') %}
+{{ url | indent(indent_width, true) }}
+        {%- endfor %}
+      {%- endfor %}
+    {%- endfor %}
+  {%- endfor %}
+{%- endmacro %}