/v1/console/execute-script to exicute simple bash command

How can i use the Icinga2 API to call a simple bash/shell command?

Example of what works

curl -k -s -u root:icinga -H 'Accept: application/json' \
 -X POST 'https://localhost:5665/v1/console/execute-script?command=get_host(NodeName).last_check_result.command&sandboxed=0&session=bb75fd7c-c686-407d-9688-582c04227756&pretty=1'

However i wish to replace the “get_host(NodeName).last_check_result.command” part with a bash/shell command.

ie. (i wish to call commands like this from the API)
$ date
Mon May 30 20:48:09 AEST 2022
$ hostname
THE-ONE-ONE-1
$ uname
Linux

https://icinga.com/docs/icinga-2/2.10/doc/12-icinga2-api/

Welcome Will,

what you want to do, we categorize as a security risk in a lot of commands and is a reason why we carefully limit the rights in the directory and the API :wink:

In short you need to define a command that uses your executable (bash/shell) and defines how to add arguments (your commands).
As soon as you defined your command object and reloaded the config you can use it via API.

You could also try to trick existing command objects to execute your command but writing a bit of config for a dedicated command object would be a lot cleaner to manage.

Thanks Dominik,

I so i have managed to add the following command object, and it seems i can run it from the API.

However, it is not returning anything like what I’m expecting. It’s as if the command itself is not executing at all.

Might you know where i am going wrong? (I wish to see what the cli command returns)

https://da.something.com:5665/v1/objects/checkcommands/list_interfaces?address=10.150.1.1

object CheckCommand “list_interfaces” {
import “plugin-check-command”
command = [ PluginDir + “/” + “check_nwc_health” ]
arguments = {
“–hostname” = “$address$”
“–protocol” = “2”
“–community” = “public”
“–mode” = “list-interfaces-detail”
}
}

Result:
{
“results”: [
{
“attrs”: {
“__name”: “list_interfaces”,
“active”: true,
“arguments”: {
“–community”: “public”,
“–hostname”: “$address$”,
“–mode”: “list-interfaces-detail”,
“–protocol”: “2”
},
“command”: [
“/usr/lib/nagios/plugins/check_nwc_health”
],
“env”: null,
“execute”: {
“arguments”: [
“checkable”,
“cr”,
“resolvedMacros”,
“useResolvedMacros”
],
“deprecated”: false,
“name”: “Internal#PluginCheck”,
“side_effect_free”: false,
“type”: “Function”
},
“ha_mode”: 0.0,
“name”: “list_interfaces”,
“original_attributes”: null,
“package”: “_etc”,
“paused”: false,
“source_location”: {
“first_column”: 0.0,
“first_line”: 1.0,
“last_column”: 36.0,
“last_line”: 1.0,
“path”: “/etc/icinga2/zones.d/global-templates/check_nwc_health.conf”
},
“templates”: [
“list_interfaces”,
“plugin-check-command”,
“plugin-check-command”
],
“timeout”: 60.0,
“type”: “CheckCommand”,
“vars”: null,
“version”: 0.0,
“zone”: “global-templates”
},
“joins”: {},
“meta”: {},
“name”: “list_interfaces”,
“type”: “CheckCommand”
}
]
}

I use the same plugin for some checks.

Is it executable?

Can you run in it manually on the target with sudo -u ICING_USER command?

Did you enable the debug log?

Here is the object definition I use:

object CheckCommand "nwc_health" {
    import "plugin-check-command"
    command = [ PluginDir + "/check_nwc_health" ]
    timeout = 1m
    arguments += {
        "--alias" = {
            description = "The alias name of a 64bit-interface (ifAlias)"
            value = "$nwc_health_alias$"
        }
        "--authpassword" = {
            description = "The authentication password for SNMPv3"
            value = "$nwc_health_authpassword$"
        }
        "--authprotocol" = {
            description = "The authentication protocol for SNMPv3 (md5|sha)"
            value = "$nwc_health_authprotocol$"
        }
        "--blacklist" = {
            description = "Blacklist some (missing/failed) components"
            value = "$nwc_health_blacklist$"
        }
        "--community" = {
            description = "SNMP community of the server (SNMP v1/2 only)"
            value = "$nwc_health_community$"
        }
        "--community2" = {
            description = "SNMP community which can be used to switch the context during runtime"
            value = "$nwc_health_community2$"
        }
        "--contextengineid" = {
            description = "The context engine id for SNMPv3 (10 to 64 hex characters)"
            value = "$nwc_health_contextengineid$"
        }
        "--contextname" = {
            description = "The context name for SNMPv3 (empty represents the default context)"
            value = "$nwc_health_contextname$"
        }
        "--critical" = {
            description = "The critical threshold"
            value = "$nwc_health_critical$"
        }
        "--criticalx" = {
            description = "The extended critical thresholds"
            repeat_key = true
            value = "$nwc_health_criticalx$"
        }
        "--domain" = {
            description = "The transport domain to use (default: udp/ipv4, other possible values: udp6, udp/ipv6, tcp, tcp4, tcp/ipv4, tcp6, tcp/ipv6)"
            value = "$nwc_health_domain$"
        }
        "--drecksptkdb" = {
            description = "This parameter must be used instead of --name, because Devel::ptkdb is stealing the latter from the command line"
            value = "$nwc_health_drecksptkdb$"
        }
        "--hostname" = {
            description = "Hostname or IP-address of the switch or router"
            value = "$nwc_health_hostname$"
        }
        "--ifspeed" = {
            description = "Override the ifspeed oid of an interface"
            value = "$nwc_health_ifspeed$"
        }
        "--ifspeedin" = {
            description = "Override the ifspeed oid of an interface (only inbound)"
            value = "$nwc_health_ifspeedin$"
        }
        "--ifspeedout" = {
            description = "Override the ifspeed oid of an interface (only outbound)"
            value = "$nwc_health_ifspeedout$"
        }
        "--lookback" = {
            description = "The amount of time you want to look back when calculating average rates. Use it for mode interface-errors or interface-usage. Without --lookback the time between two runs of check_nwc_health is the base for calculations. If you want your checkresult to be based for example on the past hour, use --lookback 3600."
            value = "$nwc_health_lookback$"
        }
        "--mitigation" = {
            description = "The parameter allows you to change a critical error to a warning."
            value = "$nwc_health_mitigation$"
        }
        "--mode" = {
            description = "Which mode should be executed. A list of all available modes can be found in the plugin documentation"
            value = "$nwc_health_mode$"
        }
        "--morphperfdata" = {
            description = "The parameter allows you to change performance data labels. It's a perl regexp and a substitution. --morphperfdata '(.*)ISATAP(.*)'='$1patasi$2'"
            value = "$nwc_health_morphperfdata$"
        }
        "--multiline" = {
            description = "Multiline output"
            set_if = "$nwc_health_multiline$"
        }
        "--name" = {
            description = "The name of an interface (ifDescr)"
            value = "$nwc_health_name$"
        }
        "--name2" = {
            description = "The secondary name of a component"
            value = "$nwc_health_name2$"
        }
        "--name3" = {
            description = "The tertiary name of a component"
            value = "$nwc_health_name3$"
        }
        "--negate" = {
            description = "The parameter allows you to map exit levels, such as warning=critical"
            value = "$nwc_health_negate$"
        }
        "--offline" = {
            description = "The maximum number of seconds since the last update of cache file before it is considered too old"
            value = "$nwc_health_offline$"
        }
        "--oids" = {
            description = "A list of oids which are downloaded and written to a cache file. Use it together with --mode oidcache"
            value = "$nwc_health_oids$"
        }
        "--port" = {
            description = "The SNMP port to use (default: 161)"
            value = "$nwc_health_port$"
        }
        "--privpassword" = {
            description = "The password for authPriv security level"
            value = "$nwc_health_privpassword$"
        }
        "--privprotocol" = {
            description = "The private protocol for SNMPv3 (des|aes|aes128|3des|3desde)"
            value = "$nwc_health_privprotocol$"
        }
        "--protocol" = {
            description = "The SNMP protocol to use (default: 2c, other possibilities: 1,3)"
            value = "$nwc_health_protocol$"
        }
        "--regexp" = {
            description = "A flag indicating that --name is a regular expression"
            set_if = "$nwc_health_regexp$"
        }
        "--report" = {
            description = "Can be used to shorten the output. Possible values are: 'long' (default), 'short' (to shorten if available), or 'html' (to produce some html outputs if available)"
            value = "$nwc_health_report$"
        }
        "--role" = {
            description = "The role of this device in a hsrp group (active/standby/listen)"
            value = "$nwc_health_role$"
        }
        "--selectedperfdata" = {
            description = "The parameter allows you to limit the list of performance data. It's a perl regexp. Only matching perfdata show up in the output."
            value = "$nwc_health_selectedperfdata$"
        }
        "--servertype" = {
            description = "The type of the network device: cisco (default). Use it if auto-detection is not possible"
            value = "$nwc_health_servertype$"
        }
        "--statefilesdir" = {
            description = "An alternate directory where the plugin can save files"
            value = "$nwc_health_statefilesdir$"
        }
        "--timeout" = {
            description = "Seconds before plugin times out (default: 15)"
            value = "$nwc_health_timeout$"
        }
        "--units" = {
            description = "One of %, B, KB, MB, GB, Bit, KBi, MBi, GBi. (used for e.g. mode interface-usage)"
            value = "$nwc_health_units$"
        }
        "--username" = {
            description = "The securityName for the USM security model (SNMPv3 only)"
            value = "$nwc_health_username$"
        }
        "--warning" = {
            description = "The warning threshold"
            value = "$nwc_health_warning$"
        }
        "--warningx" = {
            description = "The extended warning thresholds"
            repeat_key = true
            value = "$nwc_health_warningx$"
        }
        "--with-mymodules-dyn-dir" = {
            description = "A directory where own extensions can be found"
            value = "$nwc_health_mymodules-dyn-dir$"
        }
    }
    vars.check_address = {
        arguments = [  ]
        deprecated = false
        name = "<anonymous>"
        side_effect_free = false
        type = "Function"
    }
    vars.check_ipv4 = false
    vars.check_ipv6 = false
    vars.nwc_health_hostname = "$check_address$"
    vars.nwc_health_mode = "hardware-health"
}

Thanks,

And my apologies for the newb queries, It does feel close… I am giving your definition a try.

Not sure how to call this command from CLI, I do have sudo on the box. So I don’t really know how to execute this. just the syntax for the command would really help…

And I guess that is the issue I have with the API, I am not sure how to include the parameters for hostname etc. too.

Something like this I imagine… though this does not work
https://the-server.com:5665/v1/console/execute-script?verifiy=false&command=nwc_health(192.168.1.1)

Result:

{
    "results": [
        {
            "code": 500.0,
            "debug_info": {
                "first_column": 0.0,
                "first_line": 1.0,
                "last_column": 11.0,
                "last_line": 1.0,
                "path": "<1>"
            },
            "incomplete_expression": false,
            "status": "<1>: nwc_health()\n     ^^^^^^^^^^^^\nArgument is not a callable object.\n"
        }
    ]
}

according to the example here: Icinga2 Api - Icinga 2

you pass the arguments as macros - the $some_string$ in my command definition.
In your case, I guess it would look something like this:

curl -k -s -S -i -u root:icinga -H 'Accept: application/json' \
 -X POST 'https://YOUR_ICINGA_SERVER:5665/v1/actions/execute-command' \
 -d '{"type": "Service", "service": "agent!custom_service", "ttl": 15, "macros": {  "address": "192.168.1.1"}, "command": "nwc_health", "command_type": "CheckCommand" }'