Assign where dictionary key exists in a nested dictionary - possible?

  • Version used (icinga2 --version) r2.13.2-1
  • Operating System and version: Debian 11
  • Enabled features (icinga2 feature list): api checker command ido-mysql influxdb mainlog notification
  • Icinga Web 2 version and modules (System - About) N/A

Hello all. It’s been a while.

I have these custom variables in the Host object:

  vars.http["example.com"] = {
    http_sni = true
    http_ssl = true
    http_uri = "/"
    http_string = "Wordpress"
    ssl_cert_warn = 30
  }
  vars.http["api.example.com"] = {
    http_sni = true
    http_ssl = true
    http_uri = "/_health"
    http_string = "ok"
    ssl_cert_warn = 30
  }

I want to create an Apply for rule for certificate checks, but want to assign where the http_ssl key is set to true or just simply exists. The problem here is though, that we’re running against a nested dictionaries so the following won’t work:

assign where host.vars.http.http_ssl

To handle the different entries, (I suppose) a wildcard or something similar would be needed:

assign where host.vars.http[*].http_ssl

But obviously that doesn’t work.

I hope you see what I am trying to do.

Is this the right approach or am I over-complicating things? Maybe there’s an easier solution to this? :slight_smile:

You could have a look at apply ... for rules and instead of using in host.vars.dictionary there directly, call a function that filters that dict.

Disclaimer: I didn’t test this so take it with a grain of salt, but hopefully it’s a hint into the right direction.

Thanks for the reply, but writing a function (I took a look at DSL: Flatten a nested dictionary with a function for apply for rules) would complicate things rather than making it easier.
Unless you have a straightforward example of such a function at hand? :wink:

Oh and I can’t use “if” inside the apply rule because it is managed by puppet-icinga2.

@jbrost I was trying an alternative, which would use a variable retrieved from the dictionary in the assign where part. However this doesn’t seem to work (only works for host.vars ?):

In Host object:

  vars.http["example.com"] = {
    http_sni = true
    http_ssl = true
    http_uri = "/"
    http_string = "Wordpress"
    ssl_cert_warn = 30
  }
  vars.http["api.example.com"] = {
    http_sni = true
    http_ssl = true
    http_uri = "/_health"
    http_string = "ok"
    ssl_cert_warn = 30
  }

Apply Rule:

apply Service "http " for (servername => config in host.vars.http) {
  import "generic-service"

  check_command = "http"
  vars.http_vhost = servername
  vars += config

  assign where host.vars.http && vars.http_string
}

The error:

[2022-06-07 11:29:42 +0200] critical/config: Error: Error while evaluating expression: Tried to access undefined script variable 'vars'
Location: in /etc/icinga2/zones.d/global-templates/applyrules/test.conf: 37:40-37:43
/etc/icinga2/zones.d/global-templates/applyrules/test.conf(37):   assign where host.vars.check_http && vars.http_string
                                                                                                       ^^^^
/etc/icinga2/zones.d/global-templates/applyrules/test.conf(38): }
/etc/icinga2/zones.d/global-templates/applyrules/test.conf(39): 

Is there any way I can work with variables (even newly created variables inside the Apply context) and use them in assign where or ignore where ?

Looks like I found a way :man_dancing:
By using config as dictionary identifier and then followed by the actual variable, I can create an apply rule which is only applied when certain variables are set in the dictionary.

apply Service "http " for (servername => config in host.vars.http) {
  import "generic-service"

  check_command = "http"
  vars.http_vhost = servername
  vars += config

  assign where host.vars.http && config.http_string
}

Works fine in my test environment with Icinga 2 2.13.2. :smiley: