RikSaunderson
RikSaunderson

Reputation: 3765

Ansible - force a variable/fact to be undefined

I'm trying to run a playbook multiple times in a loop which creates AWS route53 records.

My task to create the route53 record looks like this:

- name: Create Public DNS record
  route53:
    profile: "{{ route53_profile_id }}"
    command: "{{ dns_command }}"
    zone: "{{ dns_zone }}"
    record: "{{ dns_record_name }}.{{ dns_zone }}"
    type: "{{ dns_type }}"
    value: "{{ dns_value }}"
    overwrite: "{{ dns_overwrite }}"
    ttl: "{{ dns_ttl }}"
    health_check: "{{ healthcheck.health_check.id | default(omit) }}"
    failover: "{{ dns_setting.failover | default(omit) }}"
    weight: "{{ dns_setting.weight | default(omit) }}"
    region: "{{ region | default(omit) }}"
    identifier: "{{ identifier | default(omit) }}"

My problem is that the health check isn't always defined every time.

Creation of the health check looks like this:

- name: Create healthcheck with IP address for EC2 instance
  route53_health_check:
    state: "{{ healthcheck.state | default( healthcheck_defaults.state ) }}"
    profile: "{{ route53_profile_id }}"
    region: "{{ vpc.region }}"
    ip_address: "{{ dns_value }}"
    type: "{{ healthcheck.type | default( healthcheck_defaults.type ) }}"
    resource_path: "{{ healthcheck.resource_path | default( omit ) }}"
    port: "{{ healthcheck.port | default( omit ) }}"
    security_token: "{{ healthcheck.security_token | default( omit ) }}"
    validate_certs: "{{ healthcheck.validate_certs | default( omit ) }}"
    string_match: "{{ healthcheck.string_match | default( omit ) }}"
    request_interval: "{{ healthcheck.request_interval | default( healthcheck_defaults.request_interval ) }}"
    failure_threshold: "{{ healthcheck.failure_threshold | default( healthcheck_defaults.failure_threshold ) }}"
  register: healthcheck
  when:
    - dns_type == "A"
    - dns_setting.healthcheck is defined

If the loop runs 5 times, it may only be defined in one iteration. If the health check runs then the 'healthcheck' variable contains the details of the health check, e.g. the ID. If it does not run on a given loop, the 'healthcheck' variable contains the following:

"healthcheck": {
        "changed": false, 
        "skip_reason": "Conditional check failed", 
        "skipped": true
    }

In my route53 creation, the health check is omitted if the 'healthcheck' variable is undefined. However if it is defined, ansible attempts to dereference the id parameter of the health_check parameter of healthcheck, which doesn't exist.

If I try to set health check to a default value when not in use, e.g. {} then it is still defined, and my route53 creation fails.

Is there a way to force a variable or fact to be undefined? Something like:

- name: Undefine health check
  set_fact:
      healthcheck: undef

Upvotes: 0

Views: 886

Answers (1)

Konstantin Suvorov
Konstantin Suvorov

Reputation: 68269

Try something like this:

- name: Create Public DNS record
  route53:
    ... cut ...
    health_check: "{{ healthcheck | skipped | ternary( omit, (healthcheck.health_check | default({})).id ) }}"
    ... cut ...

This will pass omit if healthcheck was skipped and healthcheck.health_check.id otherwise.

From my experience, default is not working properly with nested dicts of 2+ levels (i.e. works with mydict.myitem | default('ok') but fails with mydict.mysubdict.myitem | default('ok'), so I used the hack to default subdict to {} first to safely access id: (healthcheck.health_check | default({})).id

Upvotes: 1

Related Questions