Set current host/service variables from within a check function (which can be retrieved by REST api)

Dear Icinga team.

I’m trying to find a solution so that a check-function can initialize, set a service variable which can be seen outside the function, that is be visible to REST api query and Icinga Web console.
Is there a way to initialize the variable condition_text for host/service as i try to describe in below code pragma ?
There might be namespace/scope issue or i simply miss the working variable accessor …
Any hint would be highly welcome.
Best regards
Michael


apply Service "irpc-scenario-" for ( instance => conf  in host.vars.scenarios ) {
  check_command = "dummy"
  /* preset condition variables */
  vars.condition_state=0
  vars.condition_text="No condition is not met"
  oPtrServiceSelf = get_service(host.name, service.name )
  vars.dummy_state = {{
        oPtrServiceSelf = get_service(host.name, service.name )
        ... doing a lot...
        /* Try to update a service variable to indicate that condition is met*/
        if (lCondition) {
              this.vars.condition_text="Yes, that condition was found TRUE"
              this.vars.condition_state=1
              /* also tried 
              vars.condition_text="Yes, that condition was found TRUE"
              vars.condition_state=1
              */
              /* also tried 
              oPtrServiceSelf.vars.condition_text="Yes, that condition was found TRUE"
              oPtrServiceSelf.vars.condition_state=1
              */
        }
  }}
 ...
assign where host.vars.scenarios

}

There’s no safe way of doing this inside the DSL, nothing will trigger events like known from a real REST API call. If you would go that route, the daemon could easily crash because of missing input sanitizers. You can and should access objects to calculate something at runtime, and use the returned value for your check parameters or outputs. Your direction is a dangerous one and I don’t think we will add such things to the core DSL.

Cheers,
Michael

Hi Michael.
Thanks a lot for the guidance, i’ll take your advice serious and will not follow that way.
Maybe my hint to REST was a bit misleading as i only want to express that any assignment inside a lambda function is somehow working but obviously cannot update a service vars attribute.
Actually I’ve found way which seem to work as i just let a Lambda function calculate a service vars attribute.

template Service "irpc-scenario" {
  vars.dummy_state = {{
        return scenario_conditionmatrix(get_service(host.name, service.name ), macro("$condition_matrix$"), "state" )
    }}

  vars.dummy_text = {{
        return scenario_conditionmatrix(get_service(host.name, service.name ), macro("$condition_matrix$"), "text"  )
    }}

  vars.metadata_application = {{
        return scenario_conditionmatrix(get_service(host.name, service.name ), macro("$condition_matrix$"), "application" )
    }}

}

Unfortunately the scenario_conditionmatrix function is a bit costly and i’m looking for an option not to have the need to call this function three times but only once. So far i didn’t found a working solution.
The idea is to let the function return an array-pointer holding all results need in one shot and then have the results assigned in the service…
My last try (is not working and) looks like:

template Service "irpc-scenario" {
 /* pass self object-reference and condition_matrix ...*/
  vars.dummy_result=scenario_conditionmatrix(get_service(vars.host_name, vars.name ), vars.condition_matrix)
  vars.dummy_state=vars.dummy_result[0]
  vars.dummy_text=vars.dummy_result[1]
  vars.metdata_application=vars.dummy_result[2]
}

Do you have any idea , solution ?
Thx again for the helful comments on my topics.
Best regards
Michael

Hi,

currently there’s no way to “generate” vars from a function in order to not call those functions that often. A similar problem is with the cluster checks described in the docs. I’m not sure if it is possible to change vars into the Dictionary and Function object type - many underlaying code parts would be affected by this, and I’m not sure about the impact.

There’s also ideas to allow DSL-alike check result calculations and what not, but that also requires code changes and new features. I don’t think that this will become reality in 2019 though.

Right now, I don’t see a way rather than calling everything in their specific scope - and to avoid the many custom variables. It may be a better option to pre-fill them from an external script.

Cheers,
Michael

Hi.

I’ve been digging into the same topic and got to approximately the same end result.
I am using a function to generate state and output for a service based on other services, but I cannot return both and make use of them.

My only solution was to return them separately by calling the same function twice.

Is there a better way that is implemented since 2019?

The Working example looks like this:

    var service = this    
    vars.dummy_state = {{ ItgixSCO.processSCOcheck(service, "state") }}
    vars.dummy_text = {{ ItgixSCO.processSCOcheck(service, "text") }}

and the function return loooks like this at the moment:

        if (return_mode == "state") {
            return final_state
        }
        if (return_mode == "text") {
            return text
        }

Non-working examples that only call the function once:

I’ve tried to return both as a dictionary like so, but I could not use them in the service, because it always says I’m trying to access a key from type Function

        var result = {
            dummy_state = final_state
            dummy_text = text
        }
        return result
var result = {{ ItgixSCO.testSCO(service) }}
vars.dummy_text = result.dummy_text
vars.dummy_state = result.dummy_state

I get the following error doing so:

critical/config: Error: Invalid field access (for value of type 'Function'): 'dummy_text'

Just for the record, I’ve also tried to assign the return values as vars in the same way a for looped service would assign them like vars += result, but this did not work as well. Would be neat if it did.

Best Regards,
Alexander

Hi Alexander.
Happy to see your adoption of the scenario concept.
Indeed we haven’t found a working solution to assign a function array response to different vars.
What we did is to optimize the function so that query for state/text is most effective.
In our implementation we also wanted to export somehow the check which is triggering the CRITICAL scenario state change. We ended up doin this by a parse-able plugin-output.

HTH
Michael

Thanks for the reply Michael,

We’ll optimize it on other levels.

Best Regards,
Alexander