2

So, we're transitioning from Slack to MSTeams. I'm tasked with updating our Sensu configuration so that alerts get sent to MSTeams channels instead of Slack channels.

In the /etc/sensu/conf.d/handlers.json, we have Slack notifications configured as follows:

...
"slack" : {
    "type": "pipe",
    "command": "handler-slack.rb -j slack",
    "filters": [
        "occurrences"
    ]
},
....

That -j slack tells the handler to load a JSON config file which is located at /etc/sensu/conf.d/slack.d/slack.json.

The Teams handler is configured similarly:

...
"microsoft-teams" : {
    "type": "pipe",
    "command": "handler-microsoft-teams.rb -j microsoft-teams",
    "filters": [
        "occurrences"
    ]
},
...

But when Sensu tries to pass a notification to the Teams handler, I get an error that leads me to believe that the JSON config wasn't loaded:

/opt/sensu/embedded/lib/ruby/gems/2.4.0/gems/sensu-plugins-microsoft-teams-2.0.0/bin/handler-microsoft-teams.rb:104:in `get_setting': undefined method `[]' for nil:NilClass (NoMethodError)
    from /opt/sensu/embedded/lib/ruby/gems/2.4.0/gems/sensu-plugins-microsoft-teams-2.0.0/bin/handler-microsoft-teams.rb:28:in `payload_template'
    from /opt/sensu/embedded/lib/ruby/gems/2.4.0/gems/sensu-plugins-microsoft-teams-2.0.0/bin/handler-microsoft-teams.rb:108:in `handle'
    from /opt/sensu/embedded/lib/ruby/gems/2.4.0/gems/sensu-plugin-2.7.1/lib/sensu-handler.rb:89:in `block in <class:Handler>'

payload_template is the first setting that handler-microsoft-teams.rb attempts to load. It is not specified in my JSON, and the code is written to treat it as optional.

So, my question is this: how does the Slack plugin go from the string passed to the -j argument (slack) to the path /etc/sensu/conf.d/slack.d/slack.json? And how do I determine the equivalent path magic for the Teams plugin? I don't know if this magic is inherent in Ruby (in which I'm a non-expert), Sensu, sensu-plugins, or something else. I've been digging in code for a while now and I'm coming up empty.

(Yes, I'm aware of Sensu Go and would like to upgrade; that's not an option on my current timeline.)

Pierre.Vriens
  • 7,205
  • 14
  • 37
  • 84
JakeRobb
  • 151
  • 7

1 Answers1

2

Okay, so it turns out this wasn't my problem, but I know the answer to the question I asked:

The file /opt/sensu/embedded/lib/ruby/gems/2.4.0/gems/sensu-plugins-microsoft-teams-2.0.0/bin/handler-microsoft-teams.rb defines a function get_setting, which looks like this:

def get_setting(name)
  settings[config[:json_config]][name]
end

config[:json_config] is the string passed with the -j switch.

On to config: the file /opt/sensu/embedded/lib/ruby/gems/2.4.0/gems/sensu-plugin-2.7.1/lib/sensu-handler.rb requires sensu-plugin/utils, which defines the following:

module Sensu
  module Plugin
    module Utils # rubocop:disable Metrics/ModuleLength
      def config_files
        if ENV['SENSU_LOADED_TEMPFILE'] && File.file?(ENV['SENSU_LOADED_TEMPFILE'])
          IO.read(ENV['SENSU_LOADED_TEMPFILE']).split(':')
        elsif ENV['SENSU_CONFIG_FILES']
          ENV['SENSU_CONFIG_FILES'].split(':')
        else
          ['/etc/sensu/config.json'] + Dir['/etc/sensu/conf.d/**/*.json']
        end
      end

      def load_config(filename)
        JSON.parse(File.open(filename, 'r').read)
      rescue
        {}
      end

      def settings
        @settings ||= config_files.map { |f| load_config(f) }.reduce { |a, b| deep_merge(a, b) }
      end
...

So settings is going to load all JSON files nested anywhere under /etc/sensu/conf.d/ and deep-merge them. Beyond that, the path is not relevant to Sensu's ability to load it using the string slack; that's the name of the entry in the JSON payload. This mechanism is common to all Sensu config, not just handler plugins. Documentation is here: https://docs.sensu.io/sensu-core/1.8/reference/configuration/.

I looked at my log files, and it does seem to be finding and loading the files I had optimistically placed under /etc/sensu/conf.d/teams.d/, but it's not working.

Before I found the answer documented here, I took a stab and renamed the directory from teams.d to microsoft-teams.d, and the configuration object defined within from teams to microsoft-teams. I don't know why that would have had any effect, but it's working now. Maybe I had fat-fingered or copypasta'd something and resolved that inadvertently in the process of adding the microsoft prefix.

JakeRobb
  • 151
  • 7