Embedding yaml into yaml

George Shuklin
2 min readMay 24, 2017

I got a a simple task: to save yaml as string value into an existing yaml.

In my case I needed to save ‘usedata’ (which is yaml) into Dibctl configuration file (which use yaml for configs too).

I looted a bit in the Internet and build a solution.

We have ‘inner’ yaml. Let’s say it look like this:

#cloud-config
disable_root: False
ssh_pwauth: True
chpasswd:
list: |
root: password

It’s a tricky yaml — we have a comment (and I want to preserve it inside my ‘string’, as it is a signature for cloud-init application), we have a block string element (afterlist: |).

My configuration file (‘outer’ yaml) looked like this:

env1:
nova:
flavor: "30"
nics:
- net_id: db6e78cb-99fa-4223-9a6f-3b4a9b486d9b
userdata: "userdata_here"

I need to replace userdata_here with ‘inner’ yaml and keep it as string. We can’t use quotas as we’ll loose all new line characters. We can’t just put it as a yaml — comment would be lost and ‘userdata’ should be a string, not an object (dictionary).

Solution was to use ‘block quote’ feature of YAML, with one important thing to remember: YAML care about spaces.

So we need to use |, but we need to keep spacing right. In the answer below keep attention to spaces:

env1:
nova:
flavor: "30"
nics:
- net_id: db6e78cb-99fa-4223-9a6f-3b4a9b486d9b
userdata: |
#cloud-config
disable_root: False
ssh_pwauth: True
chpasswd:
list: |
root: password

There is a nested block quotation, plus complete readability. End even jsonschema does not complain — userdata is a string, indeed:

"userdata": {"type": "string"}

A key detail here is that I made two spaces step after using |. If I make a different amount of steps, # cloud-config yaml parser would understand that ‘this is end of string’, and will skip comment and will try to parse lines below as if they were ‘outer’ yaml.

As this is not very common way to escape block strings I’d like to emphasize how spaces will be handled during parsing (I replaced spaces with dots to help counting):

....userdata: |
......#cloud-config
......disable_root: False

We have 4 spaces before userdata. We use ‘step two’ in the yaml, so next level is 6 spaces, which we placed before line #cloud-configand disable_root.

Actual string after parsing will contain no spaces, as 6 spaces (expected indentation at this level) will be trimmed from each line. If I save file with 7 spaces, 6 will be trimmed and one keeped in a string.

--

--

George Shuklin

I work at Servers.com, most of my stories are about Ansible, Ceph, Python, Openstack and Linux. My hobby is Rust.