Icinga / ansible-collection-icinga

Collection to setup and manage components of the Icinga software stack
Apache License 2.0
43 stars 35 forks source link

Bug when using variables in `imports` #317

Open lucagubler opened 1 month ago

lucagubler commented 1 month ago

Hi all

I want to create a Service which imports a Service Template. We have four different Service Templates, depending on the priority. My idea was to add a variable to the host and then import the specified service template.

Here's an example Host object:

object Host "host.example.com" {
  import "priority1-host"

  address = "192.168.1.10"
  vars.nb["monitoring_icinga"] = true
  vars.nb["tenant"] = "UMBRELLA"
  vars.nb["config"] = {
    checks = [ "check_service_123", ]
  }
  vars.nb["priority"] = "priority1"
  vars.nb["platform"] = "Ubuntu-22-04"
  vars.nb["service_priority"] = "priority1-service"
}

And here's the Service object that I want to create:

  - name: CPU
    type: Service
    file: zones.d/main/services/services.conf
    apply: true
    imports:
      - host.vars.nb.service_priority
    check_command: check_load
    command_endpoint: host.name
    assign:
      - linux-hosts in host.groups
    vars:
      notification: true

The problem is that the icinga2_object.py script adds the import as string, not as variable. So the rendered config looks like this:

apply Service "CPU" {
  import "host.vars.nb.service_priority"

  check_command = "check_load"
  command_endpoint = host.name
  assign where "linux-hosts" in host.groups
  vars.notification = true
}

But it should look like this (import without quotes):

apply Service "CPU" {
  import host.vars.nb.service_priority

  check_command = "check_load"
  command_endpoint = host.name
  assign where "linux-hosts" in host.groups
  vars.notification = true
}

I'm not quite sure how this can be solved. Because sometimes the import should be a string, e.g. if I import priority1-service directly, but if it's a variable, it should be without quotes...

lucagubler commented 1 month ago

This is a fix for the current issue, but it's not generic enough. Can you think of other cases when quotes are not necessary in the import statement?

#
# imports?
#
if 'imports' in obj:
    for item in obj['imports']:
        if item.startswith('host.vars'):
            object_content += '  import ' + str(item) + '\n'
        else:
            object_content += '  import "' + str(item) + '"\n'
    object_content += '\n'
mkayontour commented 1 month ago

I didn't know this was even possible within the DSL. Thanks, we basically need to detect if it is a custom var and then apply it. Does it work with constants as well? :D I need to check if there's more clauses possible.

lucagubler commented 1 month ago

@mkayontour Yes, I just verified that it also works with constants. Here's an example:

constants.conf

const ServiceTemplate = "generic-service"

services.conf

apply Service "CPU" {
  import ServiceTemplate

  check_command = "check_load"
  command_endpoint = host.name
  assign where "linux-hosts" in host.groups
  vars.notification = true
}