reactor job notifications via slack

298 views
Skip to first unread message

schlag ify

unread,
Aug 19, 2015, 2:30:49 PM8/19/15
to Salt-users
I have a reactor configured which notifies a slack channel when jobs are executed.  The challenge I'm facing now is how to prevent reactor from notifying slack about the notification jobs themselves.   

My reactor configuration:

--snip

reactor:

  - 'salt/job/*/new':

    - /var/salt/reactor/job.sls

--snip




/var/salt/reactor/job.sls:

--snip

job_slack_salt_alerts_channel:

  local.state.sls:

    - tgt:            salt-master01

    - arg:

      - notify.slack.job

    - kwarg:

        pillar:

          arg:        "{{ data['arg']|string }}"

          fun:        "{{ data['fun']|string }}"

          jid:        "{{ data['jid']|string }}"

          minions:    "{{ data['minions']|string }}"

          target:     "{{ data['tgt']|string }}"

          timestamp:  "{{ data['_stamp']|string }}"

          user:       "{{ data['user']|string }}"

--snip




notify.slack.job:

--snip

{% set arg       = salt['pillar.get']('arg')|string %}

{% set fun       = salt['pillar.get']('fun')|string %}

{% set jid       = salt['pillar.get']('jid')|string %}

{% set minions   = salt['pillar.get']('minions')|string %}

{% set target    = salt['pillar.get']('target')|string %}

{% set timestamp = salt['pillar.get']('timestamp')|string %}

{% set user      = salt['pillar.get']('user')|string %}


job_notify_slack:

  slack.post_message:

    - channel:   alerts-testing

    - from_name: salt-master01

    - api_key:   [munged]

    - message:   |

        Job execution event at {{ timestamp }} (jid=`{{ jid }}`).  User, `{{ user }}`, executed `salt {{ target }} {{ fun }} {{ arg }}`, which targeted the following minions `{{ minions }}`.

--snip



This works well and all, except that now not only do we get notified of day to day job events, but we also get slack notifications for the notify.slack.job executions themselves (which we don't want).  I've tried filtering them out with approaches like this:


#1 Alter /var/salt/reactor/job.sls with logic that tries to read the data['arg'] variable to see if the string 'notify.slack' is there.  If it is, we don't want it rendered b/c the job is a slack notification job that we don't want to be alerted about.  This doesn't work, however and just results in errors.   I wasn't sure how to use an if statement that only renders if 'notify.slack' is NOT contained in data['arg']... {% if data['arg']|!contains:"notify.slack".. does not work and results in "SaltRenderError: Jinja syntax error: unexpected char u'!' at 18; line 1"



--snip

{% if data['arg']|contains:"notify.slack" %}

[]

{% else %}

job_slack_salt_alerts_channel:

  local.state.sls:

    - tgt:            salt-master01

    - arg:

      - notify.slack.job

    - kwarg:

        pillar:

          arg:        "{{ data['arg']|string }}"

          fun:        "{{ data['fun']|string }}"

          jid:        "{{ data['jid']|string }}"

          minions:    "{{ data['minions']|string }}"

          target:     "{{ data['tgt']|string }}"

          timestamp:  "{{ data['_stamp']|string }}"

          user:       "{{ data['user']|string }}"

{% endif %}

--snip



#2 Alter notify.slack.job with logic that does not render anything if the string `notify.slack` exists in data['arg'] (which is provided via pillar), but this fails as well.


--snip

{% if 'notify.slack' not in pillar %}

  {% set arg       = salt['pillar.get']('arg')|string %}

  {% set fun       = salt['pillar.get']('fun')|string %}

  {% set jid       = salt['pillar.get']('jid')|string %}

  {% set minions   = salt['pillar.get']('minions')|string %}

  {% set target    = salt['pillar.get']('target')|string %}

  {% set timestamp = salt['pillar.get']('timestamp')|string %}

  {% set user      = salt['pillar.get']('user')|string %}


job_notify_slack:

  slack.post_message:

    - channel:   alerts-testing

    - from_name: salt-master01

    - api_key:   [munged]

    - message:   |

        Job execution event at {{ timestamp }} (jid=`{{ jid }}`).  User, `{{ user }}`, executed `salt {{ target }} {{ fun }} {{ arg }}`, which targeted the following minions `{{ minions }}`.

{% endif %}

--snip



This is an example of a notify.slack event captured with `salt-run state.event pretty=True`:


--snip

salt/job/20150819141919464972/new       {

    "_stamp": "2015-08-19T18:19:19.467006", 

    "arg": [

        "notify.slack.job", 

        {

            "__kwarg__": true, 

            "pillar": {

                "arg": "[]", 

                "fun": "test.ping", 

                "jid": "20150819141913141242", 

                "minions": "['web01', 'web02', 'web03', 'web04', 'web05', 'web06']", 

                "target": "web*", 

                "timestamp": "2015-08-19T18:19:13.142029", 

                "user": "root"

            }

        }

    ], 

    "fun": "state.sls", 

    "jid": "20150819141919464972", 

    "minions": [

        "salt-master01"

    ], 

    "tgt": "salt-master01", 

    "tgt_type": "glob", 

    "user": "sudo_user1"

}

--snip


And this is an example of what the reactor renders as when it is reacting to a notify.slack job itself:


--snip

job_slack_salt_alerts_channel:

  local.state.sls:

    - tgt:            salt-master01

    - arg:

      - notify.slack.job

    - kwarg:

        pillar:

          arg:        "['notify.slack.job', {'pillar': {'jid': '20150819141913141242', 'target': 'web*', 'timestamp': '2015-08-19T18:19:13.142029', 'user': 'root', 'arg': '[]', 'fun': 'test.ping', 'minions': "['web01', 'web02', 'web03', 'web04', 'web05', 'web06']"}, '__kwarg__': True}]"

          fun:        "state.sls"

          jid:        "20150819141919464972"

          minions:    "['salt-master01']"

          target:     "salt-master01"

          timestamp:  "2015-08-19T18:19:19.467006"

          user:       "sudo_user1"

--snip


I basically do not want to get a slack notification if the string 'notify.slack' is in the data['arg'] event data.



Neither way I've attempted to filter this out works.  Any advice?


Thanks in advance

Colton Myers

unread,
Aug 24, 2015, 5:18:13 PM8/24/15
to salt-...@googlegroups.com
{% if data['arg']|!contains:"notify.slack"

I think the correct syntax would be `{% if not (data['arg']|contains:"notify.slack")` or something.....this feels like the correct approach, if you're still getting a syntax error we'll have to play around with it a little.

--
Colton Myers
Core Engineer, SaltStack
@basepi on Twitter/Github/IRC

--
You received this message because you are subscribed to the Google Groups "Salt-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to salt-users+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

schlag ify

unread,
Aug 25, 2015, 9:48:08 AM8/25/15
to Salt-users
thank you basepi.   

this is what my /var/salt/reactor/job.sls looks like:


--snip

{% if not (data['arg']|contains:"notify.slack") %}

job_slack_salt_alerts_channel:

  local.state.sls:

    - tgt:            salt-master01

    - arg:

      - notify.slack.job

    - kwarg:

        pillar:

          arg:        "{{ data['arg'] }}"

          fun:        "{{ data['fun'] }}"

          jid:        "{{ data['jid'] }}"

          minions:    "{{ data['minions'] }}"

          target:     "{{ data['tgt'] }}"

          timestamp:  "{{ data['_stamp'] }}"

          user:       "{{ data['user'] }}"

{% endif %}

--snip



here's what i get when i try that:


--snip

2015-08-25 09:37:30,934 [salt.master                              ][INFO    ][29436] User sudo_user1 Published command test.ping with jid 20150825093730930119

2015-08-25 09:37:30,935 [salt.master                              ][DEBUG   ][29436] Published command details {'tgt_type': 'glob', 'jid': '20150825093730930119', 'tgt': 'lnte*web*', 'ret': '', 'user': 'sudo_user1, 'arg': [], 'fun': 'test.ping'}

2015-08-25 09:37:30,935 [salt.utils.reactor                       ][ERROR   ][29431] Failed to render "/var/salt/reactor/job.sls": 

Traceback (most recent call last):

  File "/var/src/salt/local/lib/python2.7/site-packages/salt/utils/reactor.py", line 53, in render_reaction

    data=data)

  File "/var/src/salt/local/lib/python2.7/site-packages/salt/state.py", line 257, in render_template

    template, self.rend, self.opts['renderer'], **kwargs)

  File "/var/src/salt/local/lib/python2.7/site-packages/salt/template.py", line 79, in compile_template

    ret = render(input_data, saltenv, sls, **render_kwargs)

  File "/var/src/salt/local/lib/python2.7/site-packages/salt/renderers/jinja.py", line 332, in render

    **kws)

  File "/var/src/salt/local/lib/python2.7/site-packages/salt/utils/templates.py", line 121, in render_tmpl

    output = render_str(tmplstr, context, tmplpath)

  File "/var/src/salt/local/lib/python2.7/site-packages/salt/utils/templates.py", line 314, in render_jinja_tmpl

    tmplstr)

SaltRenderError: Jinja syntax error: expected token ')', got ':'; line 1


---

{% if not (data['arg']|contains:"notify.slack") %}    <======================

job_slack_salt_alerts_channel:

  local.state.sls:

    - tgt:            salt-master01

    - arg:

      - notify.slack.job

[...]

---

--snip



i'll keep playing with it to try to get somewhere



Colton Myers

unread,
Sep 3, 2015, 4:47:07 PM9/3/15
to salt-...@googlegroups.com
Wait, I'm not sure what I was thinking when I replied before. Try this instead:

{% if 'notify.slack' not in data['arg'] %}

There's no "contains" filter, you can just use `in` and `not in`.

--
Colton Myers
Core Engineer, SaltStack
@basepi on Twitter/Github/IRC
Reply all
Reply to author
Forward
0 new messages