spantaleev / matrix-docker-ansible-deploy

🐳 Matrix (An open network for secure, decentralized communication) server setup using Ansible and Docker
GNU Affero General Public License v3.0
4.9k stars 1.04k forks source link

matrix-bot-go-neb: alertmanager message template configuration incorrectly handled by ansible #1544

Closed FabianVolkers closed 2 years ago

FabianVolkers commented 2 years ago

Hey there,

I tried to deploy the matrix go-neb bot with alertmanager configuration today using the instructions at docs/configuring-playbook-bot-go-neb.md.

Expected behaviour

The go-neb bot is completely installed and able to communicate with an alertmanager instance.

Actual behaviour

During the first run, everything seemed to work fine, but I had some configuration errors. When I attempted to redeploy the service, ansible returned the following error:

fatal: [matrix.example.com]: FAILED! => 
  msg: |-
    The conditional check 'matrix_bot_go_neb_services is not defined or matrix_bot_go_neb_services[0] is not defined' failed. The error was: An unhandled exception occurred while templating '[{'ID': 'alertmanager_service', 'Type': 'alertmanager', 'UserID': '@alertmanager-goneb-bot:{{ matrix_domain }}', 'Config': {'webhook_url': 'https://goneb.example.com/services/hooks/YWxlcnRtYW5hZ2VyX3NlcnZpY2U', 'rooms': {'!roomID:example.com': {'text_template': '{{range .Alerts -}} [{{ .Status }}] {{index .Labels "alertname" }}: {{index .Annotations "description"}} {{ end -}}', 'html_template': '{{range .Alerts -}}  {{ $severity := index .Labels "severity" }}    {{ if eq .Status "firing" }}      {{ if eq $severity "critical"}}        <font color=\'red\'><b>[FIRING - CRITICAL]</b></font>      {{ else if eq $severity "warning"}}        <font color=\'orange\'><b>[FIRING - WARNING]</b></font>      {{ else }}        <b>[FIRING - {{ $severity }}]</b>      {{ end }}    {{ else }}      <font color=\'green\'><b>[RESOLVED]</b></font>    {{ end }}  {{ index .Labels "alertname"}} : {{ index .Annotations "description"}}   <a href="{{ .GeneratorURL }}">source</a><br/>{{end -}}', 'msg_type': 'm.text'}}}}]'. Error was a <class 'ansible.errors.AnsibleError'>, original message: template error while templating string: unexpected '.'. String: {{range .Alerts -}} [{{ .Status }}] {{index .Labels "alertname" }}: {{index .Annotations "description"}} {{ end -}}

    The error appears to be in './matrix-docker-ansible-deploy/roles/matrix-bot-go-neb/tasks/validate_config.yml': line 9, column 3, but may
    be elsewhere in the file depending on the exact syntax problem.

    The offending line appears to be:

    - name: Fail if there's not at least 1 service
      ^ here

Problem

Ansible appears to attempt to template the go template string in the alertmanager configuration.

Mitigation

I managed to mitigate the issue by escaping all of the curly brackets in the template in matrix.example.com/vars.yml. A better solution should be using jinja's {% raw %} expression syntax wrapped around the entire template string, but I could not get it to work in this case.

The relevant section in the README begins at line 201.

matrix_bot_go_neb_services:
  - ID: "alertmanager_service"
    Type: "alertmanager"
    UserID: "@alertmanager-goneb-bot:{{ matrix_domain }}"
    Config:
      # This is for information purposes only. It should point to Go-NEB path as follows:
      # `/services/hooks/<base64 encoded service ID>`
      # Where in this case "service ID" is "alertmanager_service"
      # Make sure your BASE_URL can be accessed by the Alertmanager instance!
      webhook_url: "https://goneb.example.com/services/hooks/YWxlcnRtYW5hZ2VyX3NlcnZpY2U"
      # Each room will get the notification with the alert rendered with the given template
      rooms:
        "!roomID.example.com":
          text_template: "{{ '{{' }}range .Alerts -{{ '}}' }} [{{ '{{' }} .Status {{ '}}' }}] {{  '{{' }}index .Labels \"alertname\" {{' }}'}}: {{ '{{' }}index .Annotations \"description\" {{ '}}' }} {{ '{{' }} end -{{ '}}' }}"
          html_template: "{{ '{{' }}range .Alerts -{{  '}}' }}  {{ '{{' }} $severity := index .Labels \"severity\" {{ '}}' }}    {{ '{{' }} if eq .Status \"firing\" {{ '}}' }}      {{ '{{' }} if eq $severity \"critical\"{{ '}}' }}        <font color='red'><b>[FIRING - CRITICAL]</b></font>      {{ '{{' }} else if eq $severity \"warning\"{{ '}}' }}        <font color='orange'><b>[FIRING - WARNING]</b></font>      {{ '{{' }} else {{ '}}' }}        <b>[FIRING - {{ '{{' }} $severity {{ '}}' }}]</b>      {{ '{{' }} end {{ '}}' }}    {{ '{{' }} else {{ '}}' }}      <font color='green'><b>[RESOLVED]</b></font>    {{ '{{' }} end {{ '}}' }}  {{ '{{' }} index .Labels \"alertname\"{{ '}}' }} : {{ '{{' }} index .Annotations \"description\"{{ '}}' }}   <a href=\"{{ '{{' }}.GeneratorURL {{ '}}' }}\">source</a><br/>{{ '{{' }}end -{{ '}}' }}"

I'm wondering if this was a mistake on my side during the execution of the ansible-playbook or if this is something that should be added to the documentation to help people in the future.

Steps to reproduce

Environment

$ ansible-playbook --version
ansible-playbook [core 2.11.6] 
  [...]
  python version = 3.8.6 (v3.8.6:db455296be, Sep 23 2020, 13:31:39) [Clang 6.0 (clang-600.0.57)]
  jinja version = 2.11.3
  libyaml = True

$ uname -a
Darwin MacBook-Pro.local 19.6.0 Darwin Kernel Version 19.6.0: Sun Nov 14 19:58:51 PST 2021; root:xnu-6153.141.50~1/RELEASE_X86_64 x86_64
spantaleev commented 2 years ago

It's more like someone copy-pasted the original configuration, which contains Golang templates.

For us, it needs to be escaped to not clash with our Jinja2 templates, however.

Wrapping these things in {% raw %} and {% endraw %} is the proper solution.

Thanks for reporting this! :+1: