Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

elastalert-test-rule fails with alert_text_jinja #100

Closed
mrfroggg opened this issue Apr 28, 2021 · 3 comments · Fixed by #101
Closed

elastalert-test-rule fails with alert_text_jinja #100

mrfroggg opened this issue Apr 28, 2021 · 3 comments · Fixed by #101

Comments

@mrfroggg
Copy link
Contributor

mrfroggg commented Apr 28, 2021

Elastalert2 2.0.4
Python 3.9

I'm testing alert_text using jinja templates and it fails using the elastalert-test-rule:

/opt/elastalert $ elastalert-test-rule --config config.yaml --alert toto.yaml 
Traceback (most recent call last):
  File "/usr/local/bin/elastalert-test-rule", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.9/site-packages/elastalert/test_rule.py", line 445, in main
    test_instance.run_rule_test()
  File "/usr/local/lib/python3.9/site-packages/elastalert/test_rule.py", line 420, in run_rule_test
    hits = self.test_file(copy.deepcopy(rule_yaml), args)
  File "/usr/local/lib/python3.9/copy.py", line 146, in deepcopy
    y = copier(x, memo)
  File "/usr/local/lib/python3.9/copy.py", line 230, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/usr/local/lib/python3.9/copy.py", line 172, in deepcopy
    y = _reconstruct(x, memo, *rv)
  File "/usr/local/lib/python3.9/copy.py", line 264, in _reconstruct
    y = func(*args)
  File "/usr/local/lib/python3.9/copyreg.py", line 95, in __newobj__
    return cls.__new__(cls, *args)
TypeError: __new__() missing 1 required positional argument: 'source'

But it doesn't crash when using elastalert --config config.yaml --rule toto.yaml --verbose.

I might not use it correctly, as I did not find the way refer to the rule parameter using jinja, as it doesn't put values in some of my field, but this might be another issue, as I do not see self.rule passed to the jinja renderer.

Part of the rule:

name: toto
index: [...]

type: metric_aggregation

query_key:
  - customer
  - customer.servername

buffer_time:
  minutes: 10

metric_agg_key: cpu.utilization
min_doc_count: 2
metric_agg_type: max
max_threshold: 20

alert_text: >+
   CPU Utilization with more than {{min_doc_count}} occurences ({{num_matches}}) in {{buffer_time}}
   and more than {{max_threshold}}% on {{_data['customer.servername']}}.

   Rule name: {{name}}

alert_text_type: alert_text_jinja
alert_subject: "{0} - CPU Utilization {1} occurences of more than {2}%"
alert_subject_args:
  - customer.servername
  - min_doc_count
  - max_threshold

Output from elastalert --config config.yaml --rule toto.yaml --verbose:

TESTSERVER - CPU Utilization 2 occurences of more than 20%
CPU Utilization with more than  occurrences (8) in  and more than % on TESTSERVER.
Rule name: 
@jertel
Copy link
Owner

jertel commented Apr 28, 2021

In test_rule.py it's performing a deepcopy on the loaded rule object. Inside of that object there's a Jinja "Template" instance, which is causing problems with the deepcopy function.

If we avoid deepcopying this Template object the test completes correctly. For example, in test_rule.py, the following change prevents the crash:

image

I wonder if Template objects aren't deepcopy compliant then perhaps they should be overriding the deepcopy function, but that is really outside the scope of this project.

@drakaru, as the Jinja Template PR submitter in #70, do you have any thoughts on this?

@drakaru
Copy link
Contributor

drakaru commented Apr 29, 2021

Apologies, I meant to bring this up in discussions as I ran into the same issue and wasn't sure what the best solution was.
(As an aside this was present before #70)

I had a look when I first ran into this error, Jinja templates, as you mention, are not deepcopyable: pallets/jinja#758 (comment)

We need a way of avoiding copying the templates.
Your solution does this, though I don't know what the prefered way to do this is.
Perhaps that is fine, I hadn't considered that as an option,
I was looking at decoupling the compiled template from the rule but that is... not trivial.

Before I made any changes only string templates were supported, directly from the rule yaml.
Templates loaded from a string within the rule, are not cached automatically by jinja.
Presumably this is why the compiled template is stored in the rule.

Jinja caches templates loaded from the filesystem, this required creating a jinja environment (see loaders.py:100)
https://jinja.palletsprojects.com/en/2.11.x/api/#high-level-api
I think placing it there is an error on my part, it should be part of the config (customising it via yaml is another issue)

However the rendering takes place within the alerter "create_alert_body", which only has access to the rule and the match and not to the global(?) config

  File "...\elastalert\alerts.py", line 264, in create_alert_body
    body += str(BasicMatchString(self.rule, match))
  File "...\elastalert\alerts.py", line 151, in __str__
    self._add_custom_alert_text()
  File "...\elastalert\alerts.py", line 70 in _add_custom_alert_text
      alert_text = self.rule.get("jinja_template").render(**self.match,
                                                                **{self.rule['jinja_root_name']: self.match})

@jertel
Copy link
Owner

jertel commented Apr 29, 2021

Thanks for the additional context. I'll PR my simple solution for now. We can always improve it if a better alternative comes along.

@jertel jertel linked a pull request Apr 29, 2021 that will close this issue
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 17, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants