From bd6af6a5a94242a1a9c575f6936d6932b02d2e3d Mon Sep 17 00:00:00 2001 From: Alessandro Fael Garcia Date: Wed, 7 May 2025 13:27:03 +0200 Subject: [PATCH 1/2] feat: Template support for the NGINX gzip static module Closes #380 --- CHANGELOG.md | 1 + defaults/main/template.yml | 1 + molecule/complete/converge.yml | 1 + molecule/complete_plus/converge.yml | 1 + templates/http/modules.j2 | 3 +++ templates/stream/modules.j2 | 2 +- 6 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0e96663..c4921b2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ FEATURES: - Add validation tasks to check the Ansible version, the Jinja2 version, and whether the required Ansible collections for this role are installed. - Bump the Ansible `community.general` collection to `9.2.0`, `community.crypto` collection to `2.21.1` and `community.docker` collection to `3.11.0`. +- Add templating support for the `ngx_http_gzip_static_module` NGINX module. BUG FIXES: diff --git a/defaults/main/template.yml b/defaults/main/template.yml index 0a047277..21e10fa1 100644 --- a/defaults/main/template.yml +++ b/defaults/main/template.yml @@ -579,6 +579,7 @@ nginx_config_http_template: http_version: 1.1 # Can be set to '1.0' or '1.1' min_length: 20 proxied: [] # String or a list of strings -- Can alternatively be set to 'false' + static: false # Boolean or 'always' types: [] # String or a list of strings vary: false # Boolean headers: # Configure headers diff --git a/molecule/complete/converge.yml b/molecule/complete/converge.yml index 50867625..4a43bd58 100644 --- a/molecule/complete/converge.yml +++ b/molecule/complete/converge.yml @@ -464,6 +464,7 @@ min_length: 20 proxied: - expired + static: always types: - text/html vary: false diff --git a/molecule/complete_plus/converge.yml b/molecule/complete_plus/converge.yml index c76cdcba..b34b4544 100644 --- a/molecule/complete_plus/converge.yml +++ b/molecule/complete_plus/converge.yml @@ -212,6 +212,7 @@ min_length: 20 proxied: - expired + static: false vary: false auth_jwt: enable: false diff --git a/templates/http/modules.j2 b/templates/http/modules.j2 index 190a3fd6..c3d227c0 100644 --- a/templates/http/modules.j2 +++ b/templates/http/modules.j2 @@ -71,6 +71,9 @@ gzip_min_length {{ gzip['min_length'] }}; {% if gzip['proxied'] is defined %} gzip_proxied {{ 'off' if not gzip['proxied'] else (gzip['proxied'] if gzip['proxied'] is string else gzip['proxied'] | join(' ')) }}; {% endif %} +{% if gzip['static'] is defined %}{# ngx_http_gzip_static_module #}{# This does not belong here but we are making an exception #} +gzip_static {{ (gzip['static'] | ternary('on', 'off')) if gzip['static'] is boolean else gzip['static'] if gzip['static'] == 'always' }}; +{% endif %} {% if gzip['types'] is defined %} gzip_types {{ gzip['types'] if gzip['types'] is string else gzip['types'] | join(' ') }}; {% endif %} diff --git a/templates/stream/modules.j2 b/templates/stream/modules.j2 index d8848b28..d6580370 100644 --- a/templates/stream/modules.j2 +++ b/templates/stream/modules.j2 @@ -67,7 +67,7 @@ access_log {{ 'off' if not log else log['path'] if log['path'] is defined }}{{ ( {{- (' if=' + log['if']) if log['if'] is defined }}; {% endfor %} {% endif %} -{% if log['error'] is defined %}{# This does not belong here but we are making an exception #} +{% if log['error'] is defined %}{# ngx_core_module #}{# This does not belong here but we are making an exception #} {% for log in log['error'] if (log['error'] is not mapping and log['error'] is not string) %} error_log {{ log if log is string else log['file'] }}{{ (' ' + log['level'] | string) if log['level'] is defined }}; {% else %} From 36c1ace75e55c899c3a5b3445440b452078db440 Mon Sep 17 00:00:00 2001 From: Alessandro Fael Garcia Date: Thu, 8 May 2025 10:10:12 +0200 Subject: [PATCH 2/2] chore: Fix merge conflict --- CHANGELOG.md | 6 ++++-- defaults/main/template.yml | 13 +++++++++++- molecule/complete/converge.yml | 22 ++++++++++++++++++-- molecule/complete_plus/converge.yml | 25 +++++++++++++++++++--- tasks/validate/validate.yml | 1 + templates/http/modules.j2 | 6 +++++- templates/stream/modules.j2 | 32 +++++++++++++++++++++++++++++ 7 files changed, 96 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4921b2c..c1a96971 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,15 +6,17 @@ FEATURES: - Add validation tasks to check the Ansible version, the Jinja2 version, and whether the required Ansible collections for this role are installed. - Bump the Ansible `community.general` collection to `9.2.0`, `community.crypto` collection to `2.21.1` and `community.docker` collection to `3.11.0`. -- Add templating support for the `ngx_http_gzip_static_module` NGINX module. +- Add templating support for the `ngx_http_gzip_static_module` and `ngx_stream_map_module` NGINX modules. BUG FIXES: - Fix the default path for the stream template deployment location. - Fix incompatibility when using the `listen` directive and setting both the `quic` and `so_keepalive` parameters. - Correct cleanup error when `nginx_config_cleanup_paths` is not defined. -- Disable check_mode for validation task `jinja2_version`. +- Disable check_mode for `jinja2_version` and Ansible collections validation tasks. - The default PID path has changed as of NGINX 1.27.5 and 1.28.0. +- Properly wrap `http_version` number in quotes in both the template defaults and Molecule tests. +- NGINX `set_real_ip_from` directive template parameter should be a list. TESTS: diff --git a/defaults/main/template.yml b/defaults/main/template.yml index 21e10fa1..670ea93a 100644 --- a/defaults/main/template.yml +++ b/defaults/main/template.yml @@ -436,7 +436,7 @@ nginx_config_http_template: headers_hash_bucket_size: 64 headers_hash_max_size: 512 hide_header: Date # String or a list of strings - http_version: 1.1 # Can be set to '1.0' or '1.1' + http_version: '1.1' # Can be set to '1.0' or '1.1' ignore_client_abort: false # Boolean ignore_headers: X-Accel-Redirect # String or a list of strings -- Can be set to 'X-Accel-Redirect', 'X-Accel-Expires', 'X-Accel-Limit-Rate', 'X-Accel-Buffering', 'X-Accel-Charset', 'Expires', 'Cache-Control', 'Set-Cookie' or 'Vary' intercept_errors: false # Boolean @@ -962,6 +962,17 @@ nginx_config_stream_template: inactive: 20s min_uses: 2 # Number valid: 1m + map: # Configure maps -- Available only in the 'stream' context + hash_bucket_size: 64 + hash_max_size: 2048 + mappings: # List of dictionaries + - string: $remote_addr # Required + variable: $upstream # Required + hostnames: false # Boolean + volatile: false # Boolean + content: # Dictionary or list of dictionaries + - value: default + new_value: 0 custom_directives: # String or a list of strings. Custom directive for specific use cases not covered by templates. Note: You need to include each directive in its full form. Make sure you add a semi-colon or closing curly bracket at the end of each directive. - server {}; servers: # All previous modules are also available (when allowed) in the 'servers' context. diff --git a/molecule/complete/converge.yml b/molecule/complete/converge.yml index 4a43bd58..b5e5177e 100644 --- a/molecule/complete/converge.yml +++ b/molecule/complete/converge.yml @@ -349,7 +349,7 @@ hide_header: - Date - X-Accel-Redirect - http_version: 1.1 + http_version: '1.1' ignore_client_abort: false ignore_headers: - X-Accel-Redirect @@ -460,7 +460,7 @@ comp_level: 1 disable: - '"msie6"' - http_version: 1.1 + http_version: '1.1' min_length: 20 proxied: - expired @@ -855,6 +855,24 @@ inactive: 20s min_uses: 2 valid: 1m + map: + hash_bucket_size: 128 + hash_max_size: 4096 + mappings: + - string: $hostname + variable: $stream_name + hostnames: true + volatile: true + content: + - value: example.com + new_value: 3 + - string: $host + variable: $isblockaccess_ua + content: + - value: default + new_value: 0 + - value: '"~jndi:ldap"' + new_value: 2 servers: - core: listen: diff --git a/molecule/complete_plus/converge.yml b/molecule/complete_plus/converge.yml index b34b4544..ff27c89d 100644 --- a/molecule/complete_plus/converge.yml +++ b/molecule/complete_plus/converge.yml @@ -208,7 +208,7 @@ comp_level: 1 disable: - '"msie6"' - http_version: 1.1 + http_version: '1.1' min_length: 20 proxied: - expired @@ -316,7 +316,8 @@ - value: '"~jndi:ldap"' new_value: 1 realip: - set_real_ip_from: 0.0.0.0 + set_real_ip_from: + - 0.0.0.0 real_ip_header: X-Real-IP real_ip_recursive: false rewrite: @@ -478,7 +479,7 @@ hide_header: - Date - X-Accel-Redirect - http_version: 1.1 + http_version: '1.1' ignore_client_abort: false ignore_headers: - X-Accel-Redirect @@ -769,6 +770,24 @@ inactive: 20s min_uses: 2 valid: 1m + map: + hash_bucket_size: 128 + hash_max_size: 4096 + mappings: + - string: $hostname + variable: $stream_name + hostnames: true + volatile: true + content: + - value: example.com + new_value: 3 + - string: $host + variable: $isblockaccess_ua + content: + - value: default + new_value: 0 + - value: '"~jndi:ldap"' + new_value: 2 servers: - core: listen: diff --git a/tasks/validate/validate.yml b/tasks/validate/validate.yml index e1c4337d..d7e88876 100644 --- a/tasks/validate/validate.yml +++ b/tasks/validate/validate.yml @@ -32,6 +32,7 @@ ansible.builtin.command: ansible-galaxy collection list register: collection_list changed_when: false + check_mode: false - name: Verify that the 'community.general' Ansible collection is installed on your Ansible host ansible.builtin.assert: diff --git a/templates/http/modules.j2 b/templates/http/modules.j2 index c3d227c0..1efc1e6d 100644 --- a/templates/http/modules.j2 +++ b/templates/http/modules.j2 @@ -257,8 +257,12 @@ mirror_request_body {{ mirror['request_body'] | ternary('on', 'off') }}; {# NGINX HTTP RealIP -- ngx_http_realip_module #} {% macro realip(realip) %} -{% if realip['set_real_ip_from'] is defined %} +{% if realip['set_real_ip_from'] is defined and realip['set_real_ip_from'] is not mapping %} +{% for set_real_ip_from in realip['set_real_ip_from'] if realip['set_real_ip_from'] is not string %} +set_real_ip_from {{ set_real_ip_from }}; +{% else %} set_real_ip_from {{ realip['set_real_ip_from'] }}; +{% endfor %} {% endif %} {% if realip['real_ip_header'] is defined %} real_ip_header {{ realip['real_ip_header'] }}; diff --git a/templates/stream/modules.j2 b/templates/stream/modules.j2 index d6580370..d83fe953 100644 --- a/templates/stream/modules.j2 +++ b/templates/stream/modules.j2 @@ -79,3 +79,35 @@ open_log_file_cache {{ 'off' if not log['open_log_file_cache'] else ('max=' + lo {% endif %} {% endmacro %} + +{# NGINX Stream Map -- ngx_stream_map_module #} +{% macro map(map) %}{# 'map' module is only available in the 'stream' context #} +{% if map['hash_bucket_size'] is defined %} +map_hash_bucket_size {{ map['hash_bucket_size'] }}; +{% endif %} +{% if map['hash_max_size'] is defined %} +map_hash_max_size {{ map['hash_max_size'] }}; +{% endif %} +{% if map['mappings'] is defined %} +{% for map_data in map['mappings'] %} +{% if map_data['string'] is defined and map_data['variable'] is defined %} +map {{ map_data['string'] }} {{ map_data['variable'] }} { +{% if map_data['hostnames'] is defined and map_data['hostnames'] is boolean and map_data['hostnames'] | bool %} + hostnames; +{% endif %} +{% if map_data['volatile'] is defined and map_data['volatile'] is boolean and map_data['volatile'] | bool %} + volatile; +{% endif %} +{% if map_data['content'] is defined %} +{% for content_line in map_data['content'] if map_data['content'] is not mapping %} + {{ content_line['value'] }} {{ content_line['new_value'] }}; +{% else %} + {{ map_data['content']['value'] }} {{ map_data['content']['new_value'] }}; +{% endfor %} +{% endif %} +} +{% endif %} +{% endfor %} +{% endif %} + +{% endmacro %}