prometheus-community / ansible

Ansible Collection for Prometheus
https://prometheus-community.github.io/ansible/
Apache License 2.0
328 stars 116 forks source link

fix: do not use namespace in node exporter systemd template #390

Open bigjazzsound opened 3 weeks ago

bigjazzsound commented 3 weeks ago

I'm using ansible-core version 2.16.7 and the latest version of the collection.

When I run the task to install/config node-exporter:

- name: Manage node-exporter
  ansible.builtin.include_role:
    name: prometheus.prometheus.node_exporter

I get this error:

TASK [prometheus.prometheus.node_exporter : Copy the node_exporter systemd service file] *****************************************************************************
task path: <redacted>/collections/ansible_collections/prometheus/prometheus/roles/node_exporter/tasks/configure.yml:2
<redacted>
The full traceback is:
Traceback (most recent call last):
  File "<redacted>/venv/lib/python3.12/site-packages/ansible/template/__init__.py", line 1010, in do_template
    res = myenv.concat(rf)
          ^^^^^^^^^^^^^^^^
  File "<redacted>/venv/lib/python3.12/site-packages/ansible/template/native_helpers.py", line 83, in ansible_concat
    return ''.join([to_text(v) for v in nodes])
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<template>", line 156, in root
  File "<redacted>/venv/lib/python3.12/site-packages/ansible/template/__init__.py", line 381, in call
    return super().call(obj, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<redacted>/venv/lib/python3.12/site-packages/jinja2/runtime.py", line 303, in call
    return __obj(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^
TypeError: 'str' object is not callable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<redacted>/venv/lib/python3.12/site-packages/ansible/plugins/action/template.py", line 152, in run
    resultant = templar.do_template(template_data, preserve_trailing_newlines=True, escape_backslashes=False, overrides=overrides)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<redacted>/venv/lib/python3.12/site-packages/ansible/template/__init__.py", line 1021, in do_template
    raise AnsibleError("Unexpected templating type error occurred on (%s): %s" % (to_native(data), to_native(te)), orig_exc=te)
ansible.errors.AnsibleError: Unexpected templating type error occurred on ({{ ansible_managed | comment }}

[Unit]
Description=Prometheus Node Exporter
After=network-online.target

[Service]
Type=simple
User={{ node_exporter_system_user }}
Group={{ node_exporter_system_group }}
ExecStart={{ node_exporter_binary_install_dir }}/node_exporter \
{% for collector in node_exporter_enabled_collectors -%}
{%   if not collector is mapping %}
    '--collector.{{ collector }}' \
{%   else -%}
{%     set name, options = (collector.items()|list)[0] -%}
    '--collector.{{ name }}' \
{%     for k,v in options|dictsort %}
    '--collector.{{ name }}.{{ k }}={{ v }}' \
{%     endfor -%}
{%   endif -%}
{% endfor -%}
{% for collector in node_exporter_disabled_collectors %}
    '--no-collector.{{ collector }}' \
{% endfor %}
{% if node_exporter_tls_server_config | length > 0 or node_exporter_http_server_config | length > 0 or node_exporter_basic_auth_users | length > 0 %}
    {% if node_exporter_version is version('1.5.0', '>=') %}
    '--web.config.file=/etc/node_exporter/config.yaml' \
    {% else %}
    '--web.config=/etc/node_exporter/config.yaml' \
    {% endif %}
{% endif %}
{% if node_exporter_web_disable_exporter_metrics %}
    '--web.disable-exporter-metrics' \
{% endif %}
{% if node_exporter_version is version('1.5.0', '>=') and
      node_exporter_web_listen_address is iterable and
      node_exporter_web_listen_address is not mapping and
      node_exporter_web_listen_address is not string %}
{%   for address in node_exporter_web_listen_address %}
    '--web.listen-address={{ address }}' \
{%   endfor %}
{% else %}
    '--web.listen-address={{ node_exporter_web_listen_address }}' \
{% endif %}
    '--web.telemetry-path={{ node_exporter_web_telemetry_path }}'

SyslogIdentifier=node_exporter
Restart=always
RestartSec=1
StartLimitInterval=0

{% set ns = namespace(protect_home = 'yes') %}
{% for m in ansible_mounts if m.mount.startswith('/home') %}
{%   set ns.protect_home = 'read-only' %}
{% endfor %}
{% if node_exporter_textfile_dir.startswith('/home') %}
{%   set ns.protect_home = 'read-only' %}
{% endif %}
ProtectHome={{ ns.protect_home }}
NoNewPrivileges=yes

{% if (ansible_facts.packages.systemd | first).version is version('232', '>=') %}
ProtectSystem=strict
ProtectControlGroups=true
ProtectKernelModules=true
ProtectKernelTunables=yes
{% else %}
ProtectSystem=full
{% endif %}

[Install]
WantedBy=multi-user.target
): 'str' object is not callable. 'str' object is not callable
fatal: [dev-factory-svc-tenable-scan-candidate]: FAILED! => changed=false 
  msg: |-
    AnsibleError: Unexpected templating type error occurred on ({{ ansible_managed | comment }}

    [Unit]
    Description=Prometheus Node Exporter
    After=network-online.target

    [Service]
    Type=simple
    User={{ node_exporter_system_user }}
    Group={{ node_exporter_system_group }}
    ExecStart={{ node_exporter_binary_install_dir }}/node_exporter \
    {% for collector in node_exporter_enabled_collectors -%}
    {%   if not collector is mapping %}
        '--collector.{{ collector }}' \
    {%   else -%}
    {%     set name, options = (collector.items()|list)[0] -%}
        '--collector.{{ name }}' \
    {%     for k,v in options|dictsort %}
        '--collector.{{ name }}.{{ k }}={{ v }}' \
    {%     endfor -%}
    {%   endif -%}
    {% endfor -%}
    {% for collector in node_exporter_disabled_collectors %}
        '--no-collector.{{ collector }}' \
    {% endfor %}
    {% if node_exporter_tls_server_config | length > 0 or node_exporter_http_server_config | length > 0 or node_exporter_basic_auth_users | length > 0 %}
        {% if node_exporter_version is version('1.5.0', '>=') %}
        '--web.config.file=/etc/node_exporter/config.yaml' \
        {% else %}
        '--web.config=/etc/node_exporter/config.yaml' \
        {% endif %}
    {% endif %}
    {% if node_exporter_web_disable_exporter_metrics %}
        '--web.disable-exporter-metrics' \
    {% endif %}
    {% if node_exporter_version is version('1.5.0', '>=') and
          node_exporter_web_listen_address is iterable and
          node_exporter_web_listen_address is not mapping and
          node_exporter_web_listen_address is not string %}
    {%   for address in node_exporter_web_listen_address %}
        '--web.listen-address={{ address }}' \
    {%   endfor %}
    {% else %}
        '--web.listen-address={{ node_exporter_web_listen_address }}' \
    {% endif %}
        '--web.telemetry-path={{ node_exporter_web_telemetry_path }}'

    SyslogIdentifier=node_exporter
    Restart=always
    RestartSec=1
    StartLimitInterval=0

    {% set ns = namespace(protect_home = 'yes') %}
    {% for m in ansible_mounts if m.mount.startswith('/home') %}
    {%   set ns.protect_home = 'read-only' %}
    {% endfor %}
    {% if node_exporter_textfile_dir.startswith('/home') %}
    {%   set ns.protect_home = 'read-only' %}
    {% endif %}
    ProtectHome={{ ns.protect_home }}
    NoNewPrivileges=yes

    {% if (ansible_facts.packages.systemd | first).version is version('232', '>=') %}
    ProtectSystem=strict
    ProtectControlGroups=true
    ProtectKernelModules=true
    ProtectKernelTunables=yes
    {% else %}
    ProtectSystem=full
    {% endif %}

    [Install]
    WantedBy=multi-user.target
    ): 'str' object is not callable. 'str' object is not callable

Removing the use of jinja namespaces fixes the error.