Skip to content

Commit d5262ea

Browse files
Sammynb
Sammy
authored and
nb
committed
feat(tofs): first implemetation + tplroot
First implementation of TOFS for: nginx_config, passenger_config, servers_config and snippets Introduced tplroot on modified files as well Fixed GH link of nginx.conf file in docs/TOFS_pattern.rst Fixed test for snippets name pillar
1 parent b9f78aa commit d5262ea

12 files changed

+196
-33
lines changed

Diff for: docs/TOFS_pattern.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ Using SaltStack is a simple and effective way to implement configuration managem
3939

4040
To avoid this situation we can use the `pillar mechanism <http://docs.saltstack.com/en/latest/topics/pillar/>`_, which is designed to provide controlled access to data from the minions based on some selection rules. As pillar data could be easily integrated in the `Jinja <http://docs.saltstack.com/en/latest/topics/tutorials/pillar.html>`_ templates, it is a good mechanism to store values to be used in the final rendering of state files and templates.
4141

42-
There are a variety of approaches on the usage of pillar and templates as seen in the `saltstack-formulas <https://github.com/saltstack-formulas>`_' repositories. `Some <https://github.com/saltstack-formulas/nginx-formula/pull/18>`_ `developments <https://github.com/saltstack-formulas/php-formula/pull/14>`_ stress the initial purpose of pillar data into a storage for most of the possible variables for a determined system configuration. This, in my opinion, is shifting too much load from the original template files approach. Adding up some `non-trivial Jinja <https://github.com/spsoit/nginx-formula/blob/81de880fe0276dd9488ffa15bc78944c0fc2b919/nginx/files/nginx.conf>`_ code as essential part of composing the state file definitely makes SaltStack state files (hence formulas) more difficult to read. The extreme of this approach is that we could end up with a new render mechanism, implemented in Jinja, storing everything needed in pillar data to compose configurations. Additionally, we are establishing a strong dependency with the Jinja renderer.
42+
There are a variety of approaches on the usage of pillar and templates as seen in the `saltstack-formulas <https://github.com/saltstack-formulas>`_' repositories. `Some <https://github.com/saltstack-formulas/nginx-formula/pull/18>`_ `developments <https://github.com/saltstack-formulas/php-formula/pull/14>`_ stress the initial purpose of pillar data into a storage for most of the possible variables for a determined system configuration. This, in my opinion, is shifting too much load from the original template files approach. Adding up some `non-trivial Jinja <https://github.com/saltstack-formulas/nginx-formula/blob/f74254c07e188bd448eaf1c5f9c802d78c4c005e/nginx/files/default/nginx.conf>`_ code as essential part of composing the state file definitely makes SaltStack state files (hence formulas) more difficult to read. The extreme of this approach is that we could end up with a new render mechanism, implemented in Jinja, storing everything needed in pillar data to compose configurations. Additionally, we are establishing a strong dependency with the Jinja renderer.
4343

4444
In opposition to the *put the code in file_roots and the data in pillars* approach, there is the *pillar as a store for a set of key-values* approach. A full-blown configuration file abstracted in pillar and jinja is complicated to develop, understand and maintain. I think a better and simpler approach is to keep a configuration file templated using just a basic (non-extensive but extensible) set of pillar values.
4545

@@ -432,7 +432,7 @@ The list of ``source_files`` can be given:
432432
Resulting in:
433433

434434
.. code-block:: sls
435-
435+
436436
- source:
437437
- salt://ntp/files/theminion/etc/ntp.conf.jinja
438438
- salt://ntp/files/theminion/etc/ntp.conf_alt.jinja

Diff for: nginx/config.sls

+11-7
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
#
33
# Manages the main nginx server configuration file.
44

5-
{% from 'nginx/map.jinja' import nginx, sls_block with context %}
5+
{%- set tplroot = tpldir.split('/')[0] %}
6+
{%- from tplroot ~ '/map.jinja' import nginx, sls_block with context %}
7+
{%- from tplroot ~ '/libtofs.jinja' import files_switch with context %}
68
79
{% if nginx.install_from_source %}
810
nginx_log_dir:
@@ -12,16 +14,18 @@ nginx_log_dir:
1214
- group: {{ nginx.server.config.user }}
1315
{% endif %}
1416
15-
{% if 'source_path' in nginx.server.config %}
16-
{% set source_path = nginx.server.config.source_path %}
17-
{% else %}
18-
{% set source_path = 'salt://nginx/files/nginx.conf' %}
19-
{% endif %}
2017
nginx_config:
2118
file.managed:
2219
{{ sls_block(nginx.server.opts) }}
2320
- name: {{ nginx.lookup.conf_file }}
24-
- source: {{ source_path }}
21+
- source:
22+
{% if 'source_path' in nginx.server.config %}
23+
- {{ nginx.server.config.source_path }}
24+
{% endif %}
25+
{{ files_switch(['nginx.conf'],
26+
'nginx_config_file_managed'
27+
)
28+
}}
2529
- template: jinja
2630
{% if 'source_path' not in nginx.server.config %}
2731
- context:
File renamed without changes.
File renamed without changes.
File renamed without changes.

Diff for: nginx/libtofs.jinja

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
{%- macro files_switch(source_files,
2+
lookup=None,
3+
default_files_switch=['id', 'os_family'],
4+
indent_width=6,
5+
v1_path_prefix='') %}
6+
{#-
7+
Returns a valid value for the "source" parameter of a "file.managed"
8+
state function. This makes easier the usage of the Template Override and
9+
Files Switch (TOFS) pattern.
10+
11+
Params:
12+
* source_files: ordered list of files to look for
13+
* lookup: key under '<tplroot>:tofs:source_files' to override
14+
list of source files
15+
* default_files_switch: if there's no config (e.g. pillar)
16+
'<tplroot>:tofs:files_switch' this is the ordered list of grains to
17+
use as selector switch of the directories under
18+
"<path_prefix>/files"
19+
* indent_witdh: indentation of the result value to conform to YAML
20+
* v1_path_prefix: (deprecated) only used for injecting a path prefix into
21+
the source, to support older TOFS configs
22+
23+
Example (based on a `tplroot` of `xxx`):
24+
25+
If we have a state:
26+
27+
Deploy configuration:
28+
file.managed:
29+
- name: /etc/yyy/zzz.conf
30+
- source: {{ files_switch(['/etc/yyy/zzz.conf', '/etc/yyy/zzz.conf.jinja'],
31+
lookup='Deploy configuration'
32+
) }}
33+
- template: jinja
34+
35+
In a minion with id=theminion and os_family=RedHat, it's going to be
36+
rendered as:
37+
38+
Deploy configuration:
39+
file.managed:
40+
- name: /etc/yyy/zzz.conf
41+
- source:
42+
- salt://xxx/files/theminion/etc/yyy/zzz.conf
43+
- salt://xxx/files/theminion/etc/yyy/zzz.conf.jinja
44+
- salt://xxx/files/RedHat/etc/yyy/zzz.conf
45+
- salt://xxx/files/RedHat/etc/yyy/zzz.conf.jinja
46+
- salt://xxx/files/default/etc/yyy/zzz.conf
47+
- salt://xxx/files/default/etc/yyy/zzz.conf.jinja
48+
- template: jinja
49+
#}
50+
{#- Get the `tplroot` from `tpldir` #}
51+
{%- set tplroot = tpldir.split('/')[0] %}
52+
{%- set path_prefix = salt['config.get'](tplroot ~ ':tofs:path_prefix', tplroot) %}
53+
{%- set files_dir = salt['config.get'](tplroot ~ ':tofs:dirs:files', 'files') %}
54+
{%- set files_switch_list = salt['config.get'](
55+
tplroot ~ ':tofs:files_switch',
56+
default_files_switch
57+
) %}
58+
{#- Lookup source_files (v2), files (v1), or fallback to source_files parameter #}
59+
{%- set src_files = salt['config.get'](
60+
tplroot ~ ':tofs:source_files:' ~ lookup,
61+
salt['config.get'](
62+
tplroot ~ ':tofs:files:' ~ lookup,
63+
source_files
64+
)
65+
) %}
66+
{#- Only add to [''] when supporting older TOFS implementations #}
67+
{%- set path_prefix_exts = [''] %}
68+
{%- if v1_path_prefix != '' %}
69+
{%- do path_prefix_exts.append(v1_path_prefix) %}
70+
{%- endif %}
71+
{%- for path_prefix_ext in path_prefix_exts %}
72+
{%- set path_prefix_inc_ext = path_prefix ~ path_prefix_ext %}
73+
{#- For older TOFS implementation, use `files_switch` from the config #}
74+
{#- Use the default, new method otherwise #}
75+
{%- set fsl = salt['config.get'](
76+
tplroot ~ path_prefix_ext|replace('/', ':') ~ ':files_switch',
77+
files_switch_list
78+
) %}
79+
{#- Append an empty value to evaluate as `default` in the loop below #}
80+
{%- if '' not in fsl %}
81+
{%- do fsl.append('') %}
82+
{%- endif %}
83+
{%- for fs in fsl %}
84+
{%- for src_file in src_files %}
85+
{%- if fs %}
86+
{%- set fs_dir = salt['config.get'](fs, fs) %}
87+
{%- else %}
88+
{%- set fs_dir = salt['config.get'](tplroot ~ ':tofs:dirs:default', 'default') %}
89+
{%- endif %}
90+
{%- set url = [
91+
'- salt:/',
92+
path_prefix_inc_ext.strip('/'),
93+
files_dir.strip('/'),
94+
fs_dir.strip('/'),
95+
src_file.strip('/'),
96+
] | select | join('/') %}
97+
{{ url | indent(indent_width, true) }}
98+
{%- endfor %}
99+
{%- endfor %}
100+
{%- endfor %}
101+
{%- endmacro %}

Diff for: nginx/passenger.sls

+7-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
# Manages installation of passenger from repo.
44
# Requires install_from_phusionpassenger = True
55

6-
{% from 'nginx/map.jinja' import nginx, sls_block with context %}
6+
{%- set tplroot = tpldir.split('/')[0] %}
7+
{%- from tplroot ~ '/map.jinja' import nginx, sls_block with context %}
8+
{%- from tplroot ~ '/libtofs.jinja' import files_switch with context %}
79
810
{% if salt['grains.get']('os_family') in ['Debian', 'RedHat'] %}
911
include:
@@ -27,7 +29,10 @@ passenger_config:
2729
file.managed:
2830
{{ sls_block(nginx.server.opts) }}
2931
- name: {{ nginx.lookup.passenger_config_file }}
30-
- source: salt://nginx/files/nginx.conf
32+
- source: {{ files_switch(['nginx.conf'],
33+
'passenger_config_file_managed'
34+
)
35+
}}
3136
- template: jinja
3237
- context:
3338
config: {{ nginx.passenger|json() }}

Diff for: nginx/servers.sls

+4-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
#
33
# Manages virtual hosts and their relationship to the nginx service.
44

5-
{% from 'nginx/map.jinja' import nginx, sls_block with context %}
6-
{% from 'nginx/servers_config.sls' import server_states with context %}
7-
{% from 'nginx/service.sls' import service_function with context %}
5+
{%- set tplroot = tpldir.split('/')[0] %}
6+
{%- from tplroot ~ '/map.jinja' import nginx, sls_block with context %}
7+
{%- from tplroot ~ '/servers_config.sls' import server_states with context %}
8+
{%- from tplroot ~ '/service.sls' import service_function with context %}
89
910
{% macro file_requisites(states) %}
1011
{%- for state in states %}

Diff for: nginx/servers_config.sls

+15-9
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22
#
33
# Manages the configuration of virtual host files.
44

5-
{% from 'nginx/map.jinja' import nginx, sls_block with context %}
5+
{#- Get the `tplroot` from `tpldir` #}
6+
{%- set tplroot = tpldir.split('/')[0] %}
7+
{%- from tplroot ~ '/map.jinja' import nginx, sls_block with context %}
8+
{%- from tplroot ~ '/libtofs.jinja' import files_switch with context %}
9+
610
{% set server_states = [] %}
711
812
# Simple path concatenation.
@@ -100,17 +104,19 @@ nginx_server_available_dir:
100104
file.absent:
101105
- name: {{ server_curpath(server) }}
102106
{% else %}
103-
{% if settings.config != None and settings.enabled == True %}
104-
{% if 'source_path' in settings.config %}
105-
{% set source_path = settings.config.source_path %}
106-
{% else %}
107-
{% set source_path = 'salt://nginx/files/server.conf' %}
108-
{% endif %}
107+
{% if settings.enabled == True %}
109108
{{ conf_state_id }}:
110109
file.managed:
111110
{{ sls_block(nginx.servers.managed_opts) }}
112111
- name: {{ server_curpath(server) }}
113-
- source: {{ source_path }}
112+
- source:
113+
{%- if 'source_path' in settings.config %}
114+
- {{ settings.config.source_path }}
115+
{%- endif %}
116+
{{ files_switch([server, 'server.conf'],
117+
'server_conf_file_managed'
118+
)
119+
}}
114120
- makedirs: True
115121
- template: jinja
116122
- require_in:
@@ -138,7 +144,7 @@ nginx_server_available_dir:
138144
{% else %}
139145
{{ manage_status(server, settings.enabled, False) }}
140146
{% endif %}
141-
{% if settings.config != None and settings.enabled == True %}
147+
{% if settings.enabled == True %}
142148
- require:
143149
- file: {{ conf_state_id }}
144150
{% endif %}

Diff for: nginx/service.sls

+8-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
#
33
# Manages the nginx service.
44

5-
{% from 'nginx/map.jinja' import nginx, sls_block with context %}
5+
{%- set tplroot = tpldir.split('/')[0] %}
6+
{%- from tplroot ~ '/map.jinja' import nginx, sls_block with context %}
7+
{%- from tplroot ~ '/libtofs.jinja' import files_switch with context %}
8+
69
{% set service_function = {True:'running', False:'dead'}.get(nginx.service.enable) %}
710
811
include:
@@ -16,7 +19,10 @@ include:
1619
nginx_systemd_service_file:
1720
file.managed:
1821
- name: /lib/systemd/system/nginx.service
19-
- source: salt://nginx/files/nginx.service
22+
- source: {{ files_switch(['nginx.service'],
23+
'nginx_systemd_service_file'
24+
)
25+
}}
2026
{% endif %}
2127
2228
nginx_service:

Diff for: nginx/snippets.sls

+8-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
#
33
# Manages creation of snippets
44

5-
{% from 'nginx/map.jinja' import nginx, sls_block with context %}
5+
{%- set tplroot = tpldir.split('/')[0] %}
6+
{%- from tplroot ~ '/map.jinja' import nginx, sls_block with context %}
7+
{%- from tplroot ~ '/libtofs.jinja' import files_switch with context %}
68
79
nginx_snippets_dir:
810
file.directory:
@@ -12,8 +14,11 @@ nginx_snippets_dir:
1214
{% for snippet, config in nginx.snippets.items() %}
1315
nginx_snippet_{{ snippet }}:
1416
file.managed:
15-
- name: {{ nginx.lookup.snippets_dir }}/{{ snippet }}.conf
16-
- source: salt://nginx/files/server.conf
17+
- name: {{ nginx.lookup.snippets_dir ~ '/' ~ snippet ~ '.conf' }}
18+
- source: {{ files_switch([ snippet, 'server.conf' ],
19+
'nginx_snippet_file_managed'
20+
)
21+
}}
1722
- template: jinja
1823
- context:
1924
config: {{ config|json() }}

Diff for: pillar.example

+40-5
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ nginx:
6060
##--- --- - - - - - - -- - - - - -- - - --- -- - -- - - - -- - - - - -- - - - -- - - - -- - ##
6161
## You can use snippets to define often repeated configuration once and include it later
6262
## The letsencrypt example below is consumed by "- include: 'snippets/letsencrypt.conf'"
63+
## Files or Templates can be retrieved by TOFS with snippet name ( Fallback to server.conf )
6364
##--- --- - - - - - - -- - - -- -- - - --- -- - -- - - - -- - - - - -- - - - -- - - - -- - ##
6465
snippets:
6566
letsencrypt:
@@ -85,20 +86,21 @@ nginx:
8586
- server: 127.0.0.1:19999
8687
- keepalive: 64
8788

88-
8989
server:
9090
opts: {} # this partially exposes file.managed parameters as they relate to the main nginx.conf file
9191

9292
#-- - - - - -- - - -- - - - - -- - - -- - - - -- - - - - - -- - - - - - -- - - - - -- - - - - -- - - #
9393
# nginx.conf (main server) declarations
9494
# dictionaries map to blocks {} and lists cause the same declaration to repeat with different values
9595
# see also http://nginx.org/en/docs/example.html
96+
# Nginx config file or template can be retrieved by TOFS ( Fallback to nginx.conf )
9697
#-- - - - - -- - - -- - - - - -- - - -- - - - -- - - - - - -- - - - - - -- - - - - -- - - - - -- - - #
9798
config:
9899
include: 'snippets/letsencrypt.conf'
99-
source_path: salt://path_to_nginx_conf_file/nginx.conf # IMPORTANT: This option is mutually exclusive with the rest of the
100-
# options; if it is found other options (worker_processes: 4 and so
101-
# on) are not processed and just upload the file from source
100+
source_path: salt://path_to_nginx_conf_file/nginx.conf # IMPORTANT: This option is mutually exclusive with TOFS and
101+
# the rest of the options; if it is found other options
102+
# (worker_processes: 4 and so on) are not processed
103+
# and just upload the file from source
102104
worker_processes: 4
103105
load_module: modules/ngx_http_lua_module.so # pass as very first in configuration; otherwise nginx will fail to start
104106
#pid: /var/run/nginx.pid # Directory location must exist (i.e. it's /run/nginx.pid on EL7)
@@ -218,7 +220,8 @@ nginx:
218220
available_dir: /etc/nginx/sites-available
219221
enabled_dir: /etc/nginx/sites-enabled
220222
config:
221-
source_path: salt://path-to-site-file/mysite2
223+
source_path: salt://path-to-site-file/mysite2 # IMPORTANT: This field is mutually exclusive with TOFS
224+
# and other config options, it just uploads the specified file
222225

223226
# Below configuration becomes handy if you want to create custom configuration files
224227
# for example if you want to create /usr/local/etc/nginx/http_options.conf with
@@ -277,7 +280,39 @@ nginx:
277280
# Passenger configuration
278281
# Default passenger configuration is provided, and will be deployed in
279282
# /etc/nginx/conf.d/passenger.conf
283+
# Passenger conf can be retrieved by TOFS ( Fallback to nginx.conf )
280284
passenger:
281285
passenger_root: /usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini
282286
passenger_ruby: /usr/bin/ruby
283287
passenger_instance_registry_dir: /var/run/passenger-instreg
288+
289+
tofs:
290+
# The files_switch key serves as a selector for alternative
291+
# directories under the formula files directory. See TOFS pattern
292+
# doc for more info.
293+
# Note: Any value not evaluated by `config.get` will be used literally.
294+
# This can be used to set custom paths, as many levels deep as required.
295+
# files_switch:
296+
# - any/path/can/be/used/here
297+
# - id
298+
# - role
299+
# - osfinger
300+
# - os
301+
# - os_family
302+
# All aspects of path/file resolution are customisable using the options below.
303+
# This is unnecessary in most cases; there are sensible defaults.
304+
# path_prefix: template_alt
305+
# dirs:
306+
# files: files_alt
307+
# default: default_alt
308+
source_files:
309+
nginx_config_file_managed:
310+
- alt_nginx.conf
311+
passenger_config_file_managed:
312+
- alt_nginx.conf
313+
server_conf_file_managed:
314+
- alt_server.conf
315+
nginx_systemd_service_file:
316+
- alt_nginx.service
317+
nginx_snippet_file_managed:
318+
- alt_server.conf

0 commit comments

Comments
 (0)