Answers: <blockquote>
    <p>Q: " Prevent misspelled variables passed to Ansible roles ... remove the defaults/main.yml, ... But then I can't take advantage of the benefits of having defaults. Are there other solutions?</p>
  </blockquote>
  
  <p>A: Yes. Tell <em>include_role</em> to read other file <a href="https://docs.ansible.com/ansible/latest/modules/include_role_module.html#parameters" rel="nofollow noreferrer"><em>defaults_from</em></a>. Fit the content of this file to your needs. For example</p>
  
  <pre><code>- include_role:
      name: foo
      defaults_from: main_special.yml
    vars:
      fooo_version: "2.0"
  </code></pre>
  
Answers: CC BY-SA 4.0
Answers: 2019-07-31T01:24:13.793Z
Answers: I believe this suffers from the same problems. If I loaded defaults from `main_special.yml` using `defaults_from`, and then specified `fooo_version: "2.0"` expecting it to override the default software version, I'm going to silently have problems.
Answers: Ryan O.
Answers: CC BY-SA 4.0
Answers: 2019-07-30T21:10:55.160Z
Answers: 2019-07-30T21:10:55.160Z
Answers: Vladimir Botka
Answers: <p>I came up with what I think is a pretty good solution.</p>
  
  <p>First, it requires the addition of this to each role:</p>
  
  <pre><code>- assert:
      that: "{{ item.key }} is defined"
      fail_msg: "Attempted to override an unknown variable: {{ item.key }}"
      quiet: yes
    loop: "{{ q('dict', override) }}"
  
  - set_fact: { "{{ item.key }}":"{{ item.value }}" }
    loop: "{{ q('dict', override) }}"
  </code></pre>
  
  <p>I added those two tasks to a file, <code>override.yml</code> within <code>ansible/tasks/</code>, and then used <code>include_tasks</code> to dynamically include that file only when <code>override</code> is actually defined:</p>
  
  <pre><code>- include_tasks: "tasks/override.yml"
    when: override is defined
  </code></pre>
  
  <p>Second, it requires that when you override defaults with <code>import_role</code> that you do the following:</p>
  
  <pre><code>- include_role:
      name: foo
    vars:
      override:
        fooo_version: "2.0"
  </code></pre>
  
  <p>The first block of code now loops through the passed <code>override</code> dictionary, and verifies that each key already is defined as a variable. So in the above example, the assert would fail because <code>fooo_version</code> is not defined. It then loops through the <code>override</code> dictionary a second time and uses <code>set_fact</code> to set the value of each key:val pair in the dictionary.</p>
  
Answers: CC BY-SA 4.0
Answers: 2019-07-31T03:00:27.767Z
Answers: 2019-07-31T04:40:20.723Z
Answers: 2019-07-31T04:40:20.723Z
Answers: Ryan O.
Body: <p>I'm looking for strategies to mitigate silent errors related to misspelled or otherwise mistyped variables being passed to Ansible roles.</p>
  
  <p>So for example, I have a role with a defaults/main.yml:</p>
  
  <pre><code>foo_version: "1.0"
  </code></pre>
  
  <p>Within the tasks/main.yml:</p>
  
  <pre><code>- get_url:
      url: "https://foo.com/foo-{{ foo_version }}.tar.gz"
      dest: /tmp/
  </code></pre>
  
  <p>Now in my main playbook, if I do this, it will install the default version, 1.0:</p>
  
  <pre><code>- include_role: name=foo
  </code></pre>
  
  <p>If I do this, it will install version 2.0:</p>
  
  <pre><code>- include_role: name=foo
    vars:
      foo_version: "2.0"
  </code></pre>
  
  <p>So far so good. But if I do this by accident, it will install 1.0 without my realizing it:</p>
  
  <pre><code>- include_role: name=foo
    vars:
      fooo_version: "2.0"
  </code></pre>
  
  <p>The only "solution" I've thought of is to remove the defaults/main.yml, in which case it would fail in the last case because <code>foo_version</code> would remain undefined. But then I can't take advantage of the benefits of having defaults.</p>
  
  <p>Are there other solutions? Thanks!</p>
  
Tags: <ansible>
Title: Prevent misspelled variables passed to Ansible roles
UserDisplayName: Ryan O.
ThreadText: # Prevent misspelled variables passed to Ansible roles
  
  (Asked by: username_0 on 2019-07-30)
  
  I'm looking for strategies to mitigate silent errors related to misspelled or otherwise mistyped variables being passed to Ansible roles.
  
  So for example, I have a role with a defaults/main.yml:
  
  ```
  foo_version: "1.0"
  
  ```
  
  Within the tasks/main.yml:
  
  ```
  - get_url:
      url: "https://foo.com/foo-{{ foo_version }}.tar.gz"
      dest: /tmp/
  
  ```
  
  Now in my main playbook, if I do this, it will install the default version, 1.0:
  
  ```
  - include_role: name=foo
  
  ```
  
  If I do this, it will install version 2.0:
  
  ```
  - include_role: name=foo
    vars:
      foo_version: "2.0"
  
  ```
  
  So far so good. But if I do this by accident, it will install 1.0 without my realizing it:
  
  ```
  - include_role: name=foo
    vars:
      fooo_version: "2.0"
  
  ```
  
  The only "solution" I've thought of is to remove the defaults/main.yml, in which case it would fail in the last case because `foo_version` would remain undefined. But then I can't take advantage of the benefits of having defaults.
  
  Are there other solutions? Thanks!
  
  **Tags:** ansible
  
  
  ---
  
  ## 2 answers
  
  ### Answer by username_1 on 2019-07-30. Score: 1
  
  > Q: " Prevent misspelled variables passed to Ansible roles ... remove the defaults/main.yml, ... But then I can't take advantage of the benefits of having defaults. Are there other solutions?
  
  A: Yes. Tell *include\_role* to read other file [*defaults\_from*](https://docs.ansible.com/ansible/latest/modules/include_role_module.html#parameters). Fit the content of this file to your needs. For example
  
  ```
  - include_role:
      name: foo
      defaults_from: main_special.yml
    vars:
      fooo_version: "2.0"
  
  ```
  
  > **Comments:**
  > **username_0**: I believe this suffers from the same problems. If I loaded defaults from `main_special.yml` using `defaults_from`, and then specified `fooo_version: "2.0"` expecting it to override the default software version, I'm going to silently have problems.  
  
  ---
  
  ### Answer by username_0 on 2019-07-31. Score: 0
  
  I came up with what I think is a pretty good solution.
  
  First, it requires the addition of this to each role:
  
  ```
  - assert:
      that: "{{ item.key }} is defined"
      fail_msg: "Attempted to override an unknown variable: {{ item.key }}"
      quiet: yes
    loop: "{{ q('dict', override) }}"
  
  - set_fact: { "{{ item.key }}":"{{ item.value }}" }
    loop: "{{ q('dict', override) }}"
  
  ```
  
  I added those two tasks to a file, `override.yml` within `ansible/tasks/`, and then used `include_tasks` to dynamically include that file only when `override` is actually defined:
  
  ```
  - include_tasks: "tasks/override.yml"
    when: override is defined
  
  ```
  
  Second, it requires that when you override defaults with `import_role` that you do the following:
  
  ```
  - include_role:
      name: foo
    vars:
      override:
        fooo_version: "2.0"
  
  ```
  
  The first block of code now loops through the passed `override` dictionary, and verifies that each key already is defined as a variable. So in the above example, the assert would fail because `fooo_version` is not defined. It then loops through the `override` dictionary a second time and uses `set_fact` to set the value of each key:val pair in the dictionary.
  
  
  ---
  
  