How to escape commas in Icinga array argument

738 views Asked by At

I have a Python script that takes a variable amount of integers and does some work with them. The values are passed to the script with the command-line argument -s. When I run the script locally, it works fine:

python check_myScript.py -s 1 2 3 4

Internally, the integers are turned into a comma-separated array using this code:

# /usr/lib/naios/plugins/check_myScript.py

import argparse
parser = argparse.ArgumentParser
parser.add_argument('-s', '--myNumbers', nargs='*', default="")
args = parser.parse_args()

If I then call print args.myNumbers in the script, I end up with an array that looks like this:

['1', '2', '3', '4']

I have been unable to get this same output on Icinga Web. I am suspecting that this has something to do with how Icinga resolves macros. My code is as follows:

# /etc/icinga2/conf.d/myScript.conf

# . . .

object Service "myService" {
  import "generic-service"
  host_name = "myHost"
  check_command = "myCheckCommand"
  vars.someNumbers = "1,2,3,4"
}
#/etc/icinga2/conf.d/commands.conf

# . . .

object CheckCommand "myCheckCommand" {
  command = [PluginDir + "/check_myScript.py",]
  arguments = {"-s" = "$someNumbers$"}
}

Here are some of the inputs I have tried for vars.someNumbers = and their corresponding outputs:

        INPUT       |         OUTPUT
----------------------------------------------
  "'1' '2' '3' '4'" → ["'1' '2' '3' '4'"]
"['1' '2' '3' '4']" → ["['1' '2' '3' '4']"]
"['1','2','3','4']" → ["['1', '2', '3', '4']"]
  ['1','2','3','4'] → error
          [1,2,3,4] → ['4']
          [1 2 3 4] → error
          "1,2,3,4" → ['1, 2, 3, 4']

Update: After much fiddling, I managed to get the arrays to look the same. I first had to change the arguments part of my check command to disable repeat keys:

arguments = {
    "-s" = { 
        value = "$someNumbers$"
        repeat_key = false
    }
}

And I had to use the input ["1", "2", "3", "4"]. (Interestingly, ['1', '2', '3', '4'] does not work, so there is apparently a difference between single and double quotes.)

However, there is a new problem: my .join() method behaves differently on Icinga than on my local machine. On my local machine, after the .join(), I get:

1,2,3,4

whereas on Icinga, I get:

1, 2, 3, 4 (notice the spaces)

I have tried adding .replace(" ","") to my .join() command, but it has no effect.

Update 2: Icinga seems to have some weird obsession with commas and spaces. This test illustrates the issue:

# test.py

sentence = ['this','is','a','sentence']
print sentence           # → ['this', 'is', 'a', 'sentence']
print '-'.join(sentence) # → this-is-a-sentence
print ','.join(sentence) # → this, is, a, sentence

Here's an even simpler example of the issue:

print "I,don't,want,spaces!" # → I, don't, want, spaces!

Try as I might, I have not yet been able to remove the spaces (which is a problem for my application as it is supposed to dynamically build a URL with passed-in parameters).

Update 3: My current workaround for my particular situation is to use %2C in my .join() method, which is the URL encoding for a comma.

1

There are 1 answers

0
lazyfrosch On

I guess the best way is to use an Array in Icinga 2

object Service "myService" {
  import "generic-service"
  host_name = "myHost"
  check_command = "myCheckCommand"
  vars.someNumbers = [1, 2, 3, 4]
}

Then with repeat_key false it should work.

arguments = {
    "-s" = { 
        value = "$someNumbers$"
        repeat_key = false
    }
}

Please be aware that Icinga 2 won't allow you to inject "spaces" to separate parts of the command line. This is a security feature, so you can not add any shell code.

Icinga 2 is building a argument list to execute, so that spaces are included into a single argument.

You could also do a split in Icinga 2, but that is advanced usage:

vars.someNumbers = "1,2,3,4"

object CheckCommand "myCheckCommand" {
  command = [PluginDir + "/check_myScript.py",]
  arguments = {
    "-s" = { 
      value = {{ 
        return macro("$someNumbers$").split(",")
      }}
      repeat_key = false
  }
}