Search code examples
ansibleyamlescapingline-breaksquoting

Ansible: How to fix to_nice_yaml output quotation and line-breaks?


I have this YAML file (I distilled my question to the bare minimum):

scalar: simple_value
empty:
list:
  - 1
  - 2
  - 3
complex:
  - first:
      one: 1
      two: 2
  - second:
      one: 3
      two: 4
weird: "{{ '{{' }} something {{ '}}' }}"
weirder: "{{ '{{' }} 'TTT' if something == 'blah' else 'FFF' {{ '}}' }}"
weirdest: "&lcub2; ansible_date_time.year &rcub2;.&lcub2; ansible_date_time.month &rcub2;.&lcub2; ansible_date_time.day &rcub2;"

and this playbook:

---
- hosts: localhost
  tasks:
    - name: Load
      include_vars:
        file: ./vars.yml
        name: object
    - name: Write
      copy:
        content: "{{ object | to_nice_yaml(indent=2) }}"
        dest: ./outv.yml

The output file is like this:

complex:
- first:
    one: 1
    two: 2
- second:
    one: 3
    two: 4
empty: null
list:
- 1
- 2
- 3
scalar: simple_value
weird: '{{ something }}'
weirder: '{{ ''TTT'' if something == ''blah'' else ''FFF'' }}'
weirdest: '&lcub2; ansible_date_time.year &rcub2;.&lcub2; ansible_date_time.month
  &rcub2;.&lcub2; ansible_date_time.day &rcub2;'

While I think that both the output and input list indentations are correct and equivalent and that the Jinja escaping is handled properly, I am not sure about weirder's value quotation. And I don't understand the line break for weirdest's value.

YAMLint says it is ok but actually restores the "normal"quotation and re-joins the line-break during the syntax check.

Is there a way to force the use of double-quotes with filter to_nice_yaml (or any other filter)?

Is there a way to avoid that line-break (or maybe have a reason for it)?


Solution

  • Regarding the line break you observe in weirdest, this is explained in the documentation:

    The to_yaml and to_nice_yaml filters use the PyYAML library which has a default 80 symbol string length limit. That causes unexpected line break after 80th symbol (if there is a space after 80th symbol) To avoid such behaviour and generate long lines, use the width option. You must use a hardcoded number to define the width, instead of a construction like float("inf"), because the filter does not support proxying Python functions.
    For example:

    {{ some_variable | to_yaml(indent=8, width=1337) }} 
    {{ some_variable | to_nice_yaml(indent=8, width=1337) }}
    

    Source: https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#formatting-data-yaml-and-json


    Then, right after this explanation in the documentation, they also point at the fact that:

    The filter does support passing through other YAML parameters. For a full list, see the PyYAML documentation.

    So there is something about the double-quoted string to get from there: default_style='"'

    Some more details can be found here.


    And so, the playbook:

    - hosts: all
      gather_facts: no
          
      tasks:
        - copy:
            content:  "{{ object | to_nice_yaml(indent=2, width=1337, default_style='\"') }}"
            dest: ./outv.yml
          vars:
            object:
              scalar: simple_value
              empty:
              list:
                - 1
                - 2
                - 3
              complex:
                - first:
                    one: 1
                    two: 2
                - second:
                    one: 3
                    two: 4
              weird: "{{ '{{' }} something {{ '}}' }}"
              weirder: "{{ '{{' }} 'TTT' if something == 'blah' else 'FFF' {{ '}}' }}"
              weirdest: "&lcub2; ansible_date_time.year &rcub2;.&lcub2; ansible_date_time.month &rcub2;.&lcub2; ansible_date_time.day &rcub2;"
    

    Gives a files outv.yml containing:

    "complex":
    - "first":
        "one": !!int "1"
        "two": !!int "2"
    - "second":
        "one": !!int "3"
        "two": !!int "4"
    "empty": !!null "null"
    "list":
    - !!int "1"
    - !!int "2"
    - !!int "3"
    "scalar": "simple_value"
    "weird": "{{ something }}"
    "weirder": "{{ 'TTT' if something == 'blah' else 'FFF' }}"
    "weirdest": "&lcub2; ansible_date_time.year &rcub2;.&lcub2; ansible_date_time.month &rcub2;.&lcub2; ansible_date_time.day &rcub2;"
    

    Note that the !!int and !!null syntaxes are called explicit typing in YAML and is explained in the linked documentation.