How do I add a pipe the vertical bar (|) into a yaml file from Python

Viewed 1703

I have a task. I need to write python code to generate a yaml file for kubernetes. So far I have been using pyyaml and it works fine. Here is my generated yaml file:

apiVersion: v1
kind: ConfigMap
data:
  info: 
    name: hostname.com
    aio-max-nr: 262144
    cpu:
      cpuLogicalCores: 4
    memory:
      memTotal: 33567170560
    net.core.somaxconn: 1024
    ...

However, when I try to create this configMap the error is that info expects a string() but not a map. So I explored a bit and it seem the easiest way to resolve this is to add a pipe after info like this:

apiVersion: v1
kind: ConfigMap
data:
  info: | # this will translate everything in data into a string but still keep the format in yaml file for readability
    name: hostname.com
    aio-max-nr: 262144
    cpu:
      cpuLogicalCores: 4
    memory:
      memTotal: 33567170560
    net.core.somaxconn: 1024
    ...

This way, my configmap is created successfully. My struggling is I dont know how to add that pipe bar from python code. Here I manually added it, but I want to automate this whole process.

part of the python code I wrote is, pretend data is a dict():

content = dict()
content["apiVersion"] = "v1"
content["kind"] = "ConfigMap"
data = {...}
info = {"info": data}
content["data"] = info

# Get all contents ready. Now write into a yaml file
fileName = "out.yaml"
with open(fileName, 'w') as outfile:
    yaml.dump(content, outfile, default_flow_style=False)   

I searched online and found a lot of cases, but none of them fits my needs. Thanks in advance.

1 Answers

The pipe makes the contained values a string. That string is not processed by YAML, even if it contains data with YAML syntax. Consequently, you will need to give a string as value.

Since the string contains data in YAML syntax, you can create the string by processing the contained data with YAML in a previous step. To make PyYAML dump the scalar in literal block style (i.e. with |), you need a custom representer:

import yaml, sys
from yaml.resolver import BaseResolver

class AsLiteral(str):
  pass

def represent_literal(dumper, data):
  return dumper.represent_scalar(BaseResolver.DEFAULT_SCALAR_TAG,
      data, style="|")

yaml.add_representer(AsLiteral, represent_literal)

info = {
  "name": "hostname.com",
  "aio-max-nr": 262144,
  "cpu": {
    "cpuLogicalCores": 4
  }
}

info_str = AsLiteral(yaml.dump(info))

data = {
  "apiVersion": "v1",
  "kind": "ConfigMap",
  "data": {
    "info": info_str
  }
}

yaml.dump(data, sys.stdout)

By putting the rendered YAML data into the type AsLiteral, the registered custom representer will be called which will set the desired style to |.

Related