Thank again. I have tested and verified that this works fine today. Inline lookups in vars section of tasks is pretty powerful and cool. The extra query to look for existence of rule with my_id becomes part of the same task to create/update the rule. For inspiration this is how I did it
First I have an ansible rule definition variable which stays neutral with regards to conditions and specific content of value_raw. Just vars that get populated later. I just focus on expanding the value_raw functionality as we need them. If value_raw needs curly or square brackets around this must be added later as otherwise ansible insists on parsing the var and the format gets messed up.
cmk_rule_definition_threads:
properties:
description: Configure monitoring of number of threads
ruleset: checkgroup_parameters:threads
value_raw: >-
{% if cmk_rule.value.levels is defined %}
'levels': (
'levels', (
{{ cmk_rule.value.levels.warn }},
{{ cmk_rule.value.levels.crit }}
)
),
{% endif %}
{% if cmk_rule.value.levels_percent is defined %}
'levels_percent': (
'levels', (
{{ cmk_rule.value.levels_percent.warn }},
{{ cmk_rule.value.levels_percent.crit }}
)
),
{% endif %}
Then I have a list of vars which I use to populate rule defs like above. here I can adjust levels and conditions etc so I can reuse the above def. One of these for each actual rule I want
my_rules_list:
- id: df8a6007-6146-46d2-b438-6bedd38d8692 # I also use uuid as my_id
type: cmk_rule_definition_threads
value:
levels:
warn: 40000
crit: 50000
conditions:
hosts:
- myhost
In the loop of my_rules_list i build up the condition section first
- name: create rule condition
ansible.builtin.set_fact:
rule_conditions: >
{
{% if cmk_rule.conditions.services is defined %}
'service_description': {
'match_on': [
{% for service in cmk_rule.conditions.services %}
'{{ service }}',
{% endfor %}
],
'operator': 'one_of',
},
{% endif %}
{% if cmk_rule.conditions.hosts is defined %}
'host_name': {
'match_on': [
{% for host in cmk_rule.conditions.hosts %}
'{{ host }}',
{% endfor %}
],
'operator': 'one_of',
},
{% endif %}
{% if cmk_rule.conditions.host_label_groups is defined %}
'host_label_groups': [
{% for label_group in cmk_rule.conditions.host_label_groups %}
{'label_group': [
{% for label in label_group.label_group %}
{'label': '{{ label.label }}',
'operator': '{{ label.operator }}' },
{% endfor %}
],
'operator': '{{ label_group.operator }}' },
{% endfor %}
],
{% endif %}
}
Then finally I put it all together. Look up the rule def, create the comment with my_id and finally lookup any existing rules in checkmk server with that id which determines if I pass the rule_id (update )or not (insert) to the rule module. So now I handle updates/inserts with guaranteed idempotency and no dups. Deletes and ordering etc is not implemented yet
- name: "configure rule {{ cmk_rule.type }} {{ cmk_rule.id | default('') }}"
checkmk.general.rule:
rule:
rule_id: "{{ cmk_rule.id if existing_rule_id is defined else omit }}"
conditions: "{{ rule_conditions }}"
properties: "{{ rule.properties | add_key_value({'comment': comment }) }}"
value_raw: "{{ ('{' ~ rule.value_raw ~ '}' if rule.wrap_value | default(true) else rule.value_raw) | string }}"
location:
folder: "{{ host_group.dir }}"
ruleset: "{{ rule.ruleset }}"
vars:
rule: "{{ lookup('ansible.builtin.vars', cmk_rule.type) }}"
comment: "{{ 'Ansible managed - client_rule_id=' ~ cmk_rule.id if cmk_rule.id is defined else 'Ansible managed' }}"
existing_rule_id: "{{ lookup('checkmk.general.rules',ruleset=rule.ruleset,comment_regex=cmk_rule.id) | map(attribute='id') | first }}"
notify: activate checkmk
–Henning