When variable is vaulted, to_nice_yaml renders output differently

Hi everyone, :waving_hand:

I’m a bit puzzled and would appreciate some input.

I’ve got a variable (network_key) containing a list of integers (nested in a dictionary, but that shouldn’t matter). This is eventually piped through the to_nice_yaml filter to create a yaml file on the target host.

If I vault network_key, the to_nice_yaml filter renders this as a string. If I do not vault network_key, it’s rendered as list of integers.

Here’s a (hopefully) minimal example:

- name: MVCE
  hosts: localhost
  gather_facts: false
  vars:
    instances_plain:
      - name: foo
        configuration:
          advanced:
            network_key: [1, 2, 3, 4, 5, 6]
    instances_vaulted:
      - name: foo
        configuration:
          advanced:
            network_key: !vault |
              $ANSIBLE_VAULT;1.1;AES256
              34666637333931303435643035393963386164323635663163343166643766653962613562376632
              3532363434356235383538666230373937353032653734610a383235393263386330626434356533
              35376239373131396465633838396562616335386263653233626566303432353434386139333666
              3835633961386332640a376463643737653031383031633136386264363161373665316366306363
              35653131663264633431643637313165336263623832373434353534666533663737
  tasks:
    - copy:
        content: "{{ item.configuration | to_nice_yaml }}"
        dest: /tmp/instances_plain.yml
      loop: "{{ instances_plain }}"

    - copy:
        content: "{{ item.configuration | to_nice_yaml }}"
        dest: /tmp/instances_vaulted.yml
      loop: "{{ instances_vaulted }}"
$ ansible-playbook test.yml 
PLAY [MVCE] *******************************************************************************************************

TASK [copy] *******************************************************************************************************
changed: [localhost] => (item={'name': 'foo', 'configuration': {'advanced': {'network_key': [1, 2, 3, 4, 5, 6]}}})

TASK [copy] *******************************************************************************************************
changed: [localhost] => (item={'name': 'foo', 'configuration': {'advanced': {'network_key': '[1, 2, 3, 4, 5, 6]'}}})

PLAY RECAP ********************************************************************************************************
localhost                  : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

$ cat /tmp/instances_plain.yml 
advanced:
    network_key:
    - 1
    - 2
    - 3
    - 4
    - 5
    - 6

$ cat /tmp/instances_vaulted.yml 
advanced:
    network_key: '[1, 2, 3, 4, 5, 6]'

network_key does not contain any quotes (i.e. it’s not a string, it’s a list of integers):

$ yq ".[0].vars.instances_vaulted[0].configuration.advanced.network_key" test.yml | ansible-vault decrypt 
Decryption successful
[1, 2, 3, 4, 5, 6]

The vault password is 123456 in case you want to reproduce this.

I’d like to know if (and how) I can make the to_nice_yaml treat variable the same, not matter if it’s are vaulted or not.
But I’m also curious what the cause for the behaviour is. I’m pretty sure I’m overlooking something quite obvious.

Cheers!

1 Like

All vaults are assumed to be strings, if you want a specific type you should cast in the template varname|int

1 Like

That’s what I figured, thanks for the clarification!

I’ve confused myself with

- name: MVCE
  hosts: localhost
  gather_facts: false
  vars:
    instances_vaulted:
      - name: foo
        configuration:
          advanced:
            network_key: !vault |
              $ANSIBLE_VAULT;1.1;AES256
              34666637333931303435643035393963386164323635663163343166643766653962613562376632
              3532363434356235383538666230373937353032653734610a383235393263386330626434356533
              35376239373131396465633838396562616335386263653233626566303432353434386139333666
              3835633961386332640a376463643737653031383031633136386264363161373665316366306363
              35653131663264633431643637313165336263623832373434353534666533663737
  tasks:
    - copy:
        content: |
          network_key: {{ instances_vaulted[0].configuration.advanced.network_key }}
        dest: /tmp/single_var.yml

resulting in

$ cat /tmp/single_var.yml 
network_key: [1, 2, 3, 4, 5, 6]

But the fact that there are not quotes around [1, 2, 3, 4, 5, 6] does not imply that it’s no a string. It’s just more obvious when using to_nice_yaml since it implicitly adds quotes.

Thanks again for your help!

type_debug is your friend when it comes to figuring out what the ‘real’ type is. Also note that >= 2.19 versions of core are a LOT better at preserving intended types and avoid much stringification. Vaults still are assumed to be strings.

1 Like

Very much appreciated. Thanks a bunch for your input!