DSL: not all objects are defined yet when the script is executing

Hello.

I have created dummy service which covers 3 services of the real 3-4 nodes. I need to have the alert even if only one of the services failed:

apply Service "app_api_region" {
  import "generic-service"
  var location = host.vars.location

  display_name = "App API " + location
  check_command = "dummy"

  var is_app_api_service = function(service) use(location) { service.zone == location && service.name == "app_api"}
  vars.fetched_services = get_objects(Service).filter(is_app_api_service)

  vars.dummy_state = {{
    var total_state = 0
    var fetched_services = macro("$fetched_services$")

    for (service in fetched_services) {
        total_state += service.state
    }

    if (total_state > 0) {
        return 2
    } else {
        return 0
    }
  }}

  vars.dummy_text = {{
    var output = "App API:\n"
    var fetched_services = macro("$fetched_services$")
    for (service in fetched_services) {
        output += service.host.display_name + ": " + service.last_check_result.output + "\n"
    }
    return output
  }}
  assign where host.vars.role == "some_role"
}

But it worked very odd. And result of the filter was different after each reloading of the service.
When I debugged it with “debugger” I realised that not all objects have been initialised yet when the script has been executed:

# icinga2 daemon -X
...
<1> => location
"stage1"
<2> => var is_app_api_service = function(service) use(location) { service.zone == location && service.name == "app_api"}
null
<3> => vars.fetched_services = get_objects(Service).filter(is_app_api_service)
null
<4> => len(vars.fetched_services)
0.000000
<5> => len(get_objects(Service))
41.000000

And from console it works pretty good:

Icinga 2 (version: 2.11.2-1)
Type $help to view available commands.
<1> => var host.vars.location = "stage1"
null
<2> => var location = host.vars.location
null
<3> => var location = "stage1"
null
<4> => var is_app_api_service = function(service) use(location) { service.zone == location && service.name == "app_api"}
null
<5> => vars.fetched_services = get_objects(Service).filter(is_app_api_service)
null
<6> => len(vars.fetched_services)
2.000000
<7> => len(get_objects(Service))
69.000000

I also tried to do this with CheckCommand with the same result:

<6> => len(get_objects(Service))
0.000000

What am I doing wrong?

This is located in the wrong scope. It is executed just once by the config compiler, but never run at runtime when all service objects are available. At this stage, you have a high chance to not have all service objects available when the function get_objects is executed.

Move this into the runtime lambda function.

Cheers,
Michael

1 Like