Answers: <p>Okay, so it turns out this wasn't my problem, but I know the answer to the question I asked:</p>
  
  <p>The file <code>/opt/sensu/embedded/lib/ruby/gems/2.4.0/gems/sensu-plugins-microsoft-teams-2.0.0/bin/handler-microsoft-teams.rb</code> defines a function <code>get_setting</code>, which looks like this:</p>
  
  <pre><code>def get_setting(name)
    settings[config[:json_config]][name]
  end
  </code></pre>
  
  <p><code>config[:json_config]</code> is the string passed with the <code>-j</code> switch.</p>
  
  <p>On to <code>config</code>: the file <code>/opt/sensu/embedded/lib/ruby/gems/2.4.0/gems/sensu-plugin-2.7.1/lib/sensu-handler.rb</code> requires <code>sensu-plugin/utils</code>, which defines the following:</p>
  
  <pre><code>module Sensu
    module Plugin
      module Utils # rubocop:disable Metrics/ModuleLength
        def config_files
          if ENV['SENSU_LOADED_TEMPFILE'] &amp;&amp; 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
  ...
  </code></pre>
  
  <p>So <code>settings</code> is going to load all JSON files nested anywhere under <code>/etc/sensu/conf.d/</code> and deep-merge them. Beyond that, the path is not relevant to Sensu's ability to load it using the string <code>slack</code>; 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: <a href="https://docs.sensu.io/sensu-core/1.8/reference/configuration/" rel="nofollow noreferrer">https://docs.sensu.io/sensu-core/1.8/reference/configuration/</a>.</p>
  
  <p>I looked at my log files, and it does seem to be finding and loading the files I had optimistically placed under <code>/etc/sensu/conf.d/teams.d/</code>, but it's not working.</p>
  
  <p>Before I found the answer documented here, I took a stab and renamed the directory from <code>teams.d</code> to <code>microsoft-teams.d</code>, and the configuration object defined within from <code>teams</code> to <code>microsoft-teams</code>. 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 <code>microsoft</code> prefix.</p>
  
Answers: CC BY-SA 4.0
Answers: 2019-09-25T18:32:26.680Z
Answers: 2019-09-25T18:32:26.680Z
Answers: JakeRobb
Body: <p>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.</p>
  
  <p>In the <code>/etc/sensu/conf.d/handlers.json</code>, we have Slack notifications configured as follows:</p>
  
  <pre><code>...
  "slack" : {
      "type": "pipe",
      "command": "handler-slack.rb -j slack",
      "filters": [
          "occurrences"
      ]
  },
  ....
  </code></pre>
  
  <p>That <code>-j slack</code> tells the handler to load a JSON config file which is located at <code>/etc/sensu/conf.d/slack.d/slack.json</code>.</p>
  
  <p>The Teams handler is configured similarly:</p>
  
  <pre><code>...
  "microsoft-teams" : {
      "type": "pipe",
      "command": "handler-microsoft-teams.rb -j microsoft-teams",
      "filters": [
          "occurrences"
      ]
  },
  ...
  </code></pre>
  
  <p>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:</p>
  
  <pre><code>/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 &lt;class:Handler&gt;'
  </code></pre>
  
  <p><code>payload_template</code> 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. </p>
  
  <p>So, my question is this: how does the Slack plugin go from the string passed to the <code>-j</code> argument (<code>slack</code>) to the path <code>/etc/sensu/conf.d/slack.d/slack.json</code>? 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.</p>
  
  <p>(Yes, I'm aware of Sensu Go and would like to upgrade; that's not an option on my current timeline.)</p>
  
Tags: <sensu>
Title: How do Sensu handler notification plugins determine the path of their JSON config files?
UserDisplayName: JakeRobb
ThreadText: # How do Sensu handler notification plugins determine the path of their JSON config files?
  
  (Asked by: username_0 on 2019-09-25)
  
  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.)
  
  **Tags:** sensu
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_0 on 2019-09-25. Score: 2 | Accepted answer
  
  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.
  
  
  ---
  
  