# Looking for a more elegant way to declare complex variables

**URL:** <https://forum.ansible.com/t/looking-for-a-more-elegant-way-to-declare-complex-variables/26076>\
**Category:** Ansible Project\
**Created:** [November 20, 2017, 4:49am UTC](https://forum.ansible.com/t/looking-for-a-more-elegant-way-to-declare-complex-variables/26076 "2017-11-20T04:49:20Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Behrang](https://avatars.discourse-cdn.com/v4/letter/b/ed655f/32.png) [@Behrang](https://forum.ansible.com/u/Behrang)\
**Post date:** [November 20, 2017, 4:49am UTC](https://forum.ansible.com/t/looking-for-a-more-elegant-way-to-declare-complex-variables/26076/1 "2017-11-20T04:49:20Z")

</div>

Sensu is monitoring services like Nagios and the things it should monitor can be configured with [JSON check definition files](https://sensuapp.org/docs/1.1/guides/getting-started/intro-to-checks.html).

A JSON check definition file can have one or more check definitions. Here is a simplified example:

```auto
{
  "checks": {
    "cron": {
      "command": "check-process.rb -p cron",      
      "interval": 60
    }
  }
}

```

Let’s say I have defined the following template for generating check files:

```auto
{
  "checks": {
    {% for check_def in item.check_defs %}
        "{{ check_def.name }}": {
    	  "command": "{{ check_def.command }}",
          "interval": {{ check_def.check_interval }}
        }{{ ',' if not loop.last else '' }}
    {% endfor %}
  }
}

```

I apply this template a task like this:

```auto
- copy:
    content: "{{ lookup('template', 'check_def.json.j2') | to_nice_json }}"
    dest: "{{ somewhere }}"    
  with_items: "{{ check_sets }}"
  notify: Restart Sensu

```

The `check_sets` variable is defined similar to:

```auto
  vars:
    services:
      - foo
      - bar
      - baz

  tasks:    
      set_fact:
        check_defs: >
          {{
            check_defs|default([]) + [
              {
                'name' : 'my-check-def-for' + item.name,
                'command' : 'check-process.rb',
                'command_args' : '-p ' + item
              }
            ]
          }}
      with_items: "{{ services }}"

```

I find this approach to defining `check_defs` to be ugly for several reasons:

1- It is not declarative (e.g. `check_defs|default([])` as well as appending items to the list are not declarative).

2- I don’t like the string concat logic using `+` and using quotes around hardcoded strings

3- For newcomers, it is not easy to understand what is going on

If I use a static list, I have to repeat some variables/values. For example:

```auto
check_defs:
	- name: my-check-def-for-foo
	  command: check-process.rb
	  command_args: -p foo

```

Here `foo` is repeated twice.

Also users might diverge from the naming convention. For example by providing:

```auto
check_defs:
	- name: foo-check
	  command: check-process.rb
	  command_args: -p foo

```

Is there a more elegant way to declare the `check_defs` variable that doesn’t have any of these drawbacks?

Thanks in advance.

---

<div class="post-metadata">

**Author:** ![shankerbalan](https://avatars.discourse-cdn.com/v4/letter/s/c68b51/32.png) [@shankerbalan](https://forum.ansible.com/u/shankerbalan)\
**Post date:** [November 20, 2017, 10:28am UTC](https://forum.ansible.com/t/looking-for-a-more-elegant-way-to-declare-complex-variables/26076/2 "2017-11-20T10:28:11Z")

</div>

Hi Behrang,

Comments inline...

> Sensu is monitoring services like Nagios and the things it should monitor can be configured with JSON check definition files.
> 
> A JSON check definition file can have one or more check definitions. Here is a simplified example:
> 
> {  
> &nbsp;&nbsp;"checks": {  
> &nbsp;&nbsp;&nbsp;&nbsp;"cron": {  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"command": "check-process.rb -p cron",  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"interval": 60  
> &nbsp;&nbsp;&nbsp;&nbsp;}  
> &nbsp;&nbsp;}  
> }
> 
> Let's say I have defined the following template for generating check files:
> 
> {  
> &nbsp;&nbsp;"checks": {  
> &nbsp;&nbsp;&nbsp;&nbsp;{% for check\_def in item.check\_defs %}  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"{{ check\_def.name }}": {  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"command": "{{ check\_def.command }}",  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"interval": {{ check\_def.check\_interval }}  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}{{ ',' if not loop.last else '' }}  
> &nbsp;&nbsp;&nbsp;&nbsp;{% endfor %}  
> &nbsp;&nbsp;}  
> }

\<snipped a lot\>

I am using Ansible to manage checks.json myself but am doing so with the Sensu module from  
[http://docs.ansible.com/ansible/latest/sensu\_check\_module.html](http://docs.ansible.com/ansible/latest/sensu_check_module.html) as below:

name: Updating checks in - /etc/sensu/conf.d/{{sensu\_check\_filename|default(check\_filename)}}  
&nbsp;&nbsp;sensu\_check:  
&nbsp;&nbsp;&nbsp;&nbsp;#path: "{{ sensu\_check\_filename|default(check\_filename) }}"  
&nbsp;&nbsp;&nbsp;&nbsp;path: /etc/sensu/conf.d/checks.json  
&nbsp;&nbsp;&nbsp;&nbsp;name: "{{ item.name }}"  
&nbsp;&nbsp;&nbsp;&nbsp;command: "{{ item.command }}"  
&nbsp;&nbsp;&nbsp;&nbsp;interval: "{{ item.interval|default(check\_interval) }}"  
&nbsp;&nbsp;&nbsp;&nbsp;metric: "{{ item.metric | default('no') }}"  
&nbsp;&nbsp;&nbsp;&nbsp;handle: "{{ item.handle | default('yes') }}"  
&nbsp;&nbsp;&nbsp;&nbsp;occurrences: "{{ item.occurrences | default(check\_occurrences) }}"  
&nbsp;&nbsp;&nbsp;&nbsp;timeout: "{{ item.timeout | default(check\_timeout) }}"  
&nbsp;&nbsp;&nbsp;&nbsp;dependencies: "{{ item.dependencies | default(omit) }}"  
&nbsp;&nbsp;&nbsp;&nbsp;subscribers: "{{ item.subscribers|default(default\_subscribers) }}"  
&nbsp;&nbsp;&nbsp;&nbsp;handlers: "{{ item.handlers | default(omit) }}"  
&nbsp;&nbsp;&nbsp;&nbsp;refresh: "{{ item.refresh | default(check\_refresh) }}"  
&nbsp;&nbsp;&nbsp;&nbsp;state: "{{ item.state | default('present') }}"  
&nbsp;&nbsp;&nbsp;&nbsp;standalone: "{{ item.standalone | default('no') }}"  
&nbsp;&nbsp;&nbsp;&nbsp;ttl: "{{ item.ttl | default(900) }}"  
&nbsp;&nbsp;&nbsp;&nbsp;aggregate: "{{ item.aggregate | default('no') }}"  
&nbsp;&nbsp;&nbsp;&nbsp;subdue\_begin: "{{ item.subdue\_begin | default(omit) }}"  
&nbsp;&nbsp;&nbsp;&nbsp;subdue\_end: "{{ item.subdue\_end | default(omit) }}"  
&nbsp;&nbsp;&nbsp;&nbsp;source: "{{ item.source | default(omit) }}"  
&nbsp;&nbsp;&nbsp;&nbsp;low\_flap\_threshold: "{{ item.low\_flap\_threshold | default(omit) }}"  
&nbsp;&nbsp;&nbsp;&nbsp;high\_flap\_threshold: "{{ item.high\_flap\_threshold | default(omit) }}"  
&nbsp;&nbsp;notify:  
&nbsp;&nbsp;&nbsp;&nbsp;- restart\_sensu\_server  
&nbsp;&nbsp;&nbsp;&nbsp;- restart\_sensu\_client  
&nbsp;&nbsp;&nbsp;&nbsp;- restart\_sensu\_api  
&nbsp;&nbsp;with\_items: "{{ \_sensu\_check\_list|sort }}"

Is there any particular reason why you chose to use a template?

Regards.  
@shankerbalan

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/ansible/original/1X/1882d9a01da5d8996a862359b0913cc568a39b84.svg) [@system](https://forum.ansible.com/u/system)\
**Post date:** [November 20, 2017, 2:51pm UTC](https://forum.ansible.com/t/looking-for-a-more-elegant-way-to-declare-complex-variables/26076/3 "2017-11-20T14:51:21Z")

</div>

Just a note, this task does x2 transformations it does not need to, if  
you use template directly you avoid many problems.

so instead of:  
- copy:  
&nbsp;&nbsp;&nbsp;&nbsp;content: "{{ lookup('template', 'check\_def.json.j2') | to\_nice\_json }}"  
&nbsp;&nbsp;&nbsp;&nbsp;dest: "{{ somewhere }}"  
&nbsp;&nbsp;with\_items: "{{ check\_sets }}"  
&nbsp;&nbsp;notify: Restart Sensu

use:  
- template: src=check\_def.json.j2 dest={{somewhere}}  
&nbsp;&nbsp;with\_items: "{{ check\_sets }}"  
&nbsp;&nbsp;notify: Restart Sensu

---

<div class="post-metadata">

**Author:** ![Behrang](https://avatars.discourse-cdn.com/v4/letter/b/ed655f/32.png) [@Behrang](https://forum.ansible.com/u/Behrang)\
**Post date:** [November 20, 2017, 10:37pm UTC](https://forum.ansible.com/t/looking-for-a-more-elegant-way-to-declare-complex-variables/26076/4 "2017-11-20T22:37:15Z")

</div>

I want to pretty print the generated JSON file. Otherwise I would have used the template module.

---

<div class="post-metadata">

**Author:** ![Behrang](https://avatars.discourse-cdn.com/v4/letter/b/ed655f/32.png) [@Behrang](https://forum.ansible.com/u/Behrang)\
**Post date:** [November 20, 2017, 10:38pm UTC](https://forum.ansible.com/t/looking-for-a-more-elegant-way-to-declare-complex-variables/26076/5 "2017-11-20T22:38:06Z")

</div>

Oops. I didn’t know this module existed. I am maintaining a set of scripts that was written before 2.0 and this module were released.
