never: |+
   write
   YAML
  again

😍

🤬

Significant white space


// ...
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
      - containerPort: 80
# white space

Optional quotes


apiVersion: v1
kind: Pod
// ...
  - name: log-aggregator
    image: images.my-company.example/log-aggregator:v6
    resources:
      limits:
        memory: 128Mi
        cpu: 500m
# strings

Optional quotes


apiVersion: v1
kind: Pod
// ...
  - name: log-aggregator
    image: images.my-company.example/log-aggregator:v6
    resources:
      limits:
        memory: 128Mi
        cpu: 500m
# strings

Optional quotes


apiVersion: v1
kind: Pod
// ...
  - name: log-aggregator
    image: images.my-company.example/log-aggregator:v6
    resources:
      limits:
        memory: 128Mi
        cpu: 1
# strings

Optional quotes

user@host ~ $ kubectl apply -f pod.yaml
 
Error from server (BadRequest): error when creating "podinfo.yaml": Deployment in 
version "v1" cannot be handled as a Deployment: json: cannot unmarshal number into 
Go struct field Container.spec.template.spec.containers.resources.limits.cpu of type string
# strings

The Norway problem

countries:
 - GB
 - IE
 - FR
 - DE
 - NO
# Norway problem

The Norway problem

>>> from pyyaml import load
>>> load(countries)
{'countries': ['GB', 'IE', 'FR', 'DE', False]}
# Norway problem

The Norway problem

falsy:
  - N
  - n
  - no
  - NO
  - No
  - false
  - FALSE
  - False
  - off
  - OFF
  - Off
# Norway problem

The Norway problem

truey:
  - Y
  - y
  - yes
  - YES
  - Yes
  - true
  - TRUE
  - True
  - on
  - ON
  - On
# Norway problem

multiline strings

🔒 https://yaml-multiline.info

example: |
  Several lines of text,
  and also a blank line
  
  plus another line at the end.
  
  
foo: bar
# multiline string

Multiline strings

example: >+
  Several lines of text,
  and also a blank line
  
  plus another line at the end.
  
  
foo: bar

Code Transitions

user@host ~ $ yq ".example" multiline.yaml
# multiline string
example: >+
  Several lines of text,
  and also a blank line
  
  plus another line at the end.
  
  
foo: bar

Code Transitions

user@host ~ $ yq ".example" multiline.yaml
Several lines of text, and also a blank line:
plus another line at the end.


user@host ~ $
# multiline string
  • JSON
  • JSON5
  • TOML
  • XML
  • PKL
  • CUE

The alternatives

JSON

{
	"language": "json",
	"$comment": "No comment...",
	"properties": {
		"comments": "No comments",
		"multiline_strings": "No\nmultiline\nstrings",
		"raw_strings": "No \"raw\" strings",
        "other": "Commas everywhere, except in the end of lists",
        "imports": false
    }
}
# alternatives

JSON5

{
	"language": "json5",
	// You can comment!
	"properties": {
		comments: "No comments",
		multiline_strings: "Kind\
of multiline\
strings",
		"raw_strings": "No \"raw\" strings",
        "other":"Commas everywhere, including in the end of lists and objects",
        "imports": false,
    }
}
# alternatives

TOML

[language]
name="TOML"
# You can comment!

[language.properties]
comments = "yes" 
multiline_strings = """TOML has
multiline
strings"""
raw_strings = "No \"raw\" strings, as far as I have seen..."
other = "No commas"
imports = false
# alternatives

XML

<language name="XML">
	<!-- You can comment! -->
	<properties>
		<comments>yes</comments>
    	<multiline_strings>
      		XML has
			multiline
			strings
   	 	</multiline_strings>
		<raw_strings><![CDATA[
		XML has raw cdata elements, < that can contain almost anything &
		]]></raw_strings>
		<other with_attribute="some values can be defined as attributes">
      		while other things could be encoded as cdata
      	</other>
	</properties>
</language>
# alternatives

PKL

language =  "PKL",
// You can comment!
properties = {
	comments = true, /* In more ways than one */
	multiline_strings =  """
		Real
  		multiline
  		strings
  		"""
		raw_strings = #"""
  			Customizable string delimiters lets you have 
  			strings with "pretty" much any content
  			#"""#
        "other" = """
  			I must admit I have not explored PKL enough. 
  			It looks really, really promising
            PKL is also a schema language and a template language
  			"""
        "imports" = true
    }
}
# alternatives

CUE

language:  "CUE",
// You can comment!
properties: {
	comments: true, /* In more ways than one */
	multiline_strings:  """
		Real
  		multiline
  		strings
  		"""
		raw_strings: #"""
  			Customizable string delimiters lets you have 
  			strings with "pretty" much any content
  			"""#
        "other": """
  			I must admit I have not explored PKL enough. 
  			It looks really, really promising
            CUE is also a schema language and a template language
  			"""
        "imports": true
    }
}
# alternatives

CUE syntax

# cue syntax

{
  "myObject": {
    "strings": "are quoted"
    "lists": ["are", "defined", "using", "square", "brackets"]
    "numbers": [1, 0.5]
    "booleans": [true, false]
  }
}

CUE syntax

# cue syntax

but: """
  The opposite
  is not
  true
  """
"this: key": "must be quoted"
  • Indentation is not significant
  • String values must be quoted
  • Only true and false is interpreted as boolean*

CUE vs Yaml

Raw strings

"This: \"\uB212\" is the Ångstrøm symbol"
# raw strings
This: "Å" is the Ångstrøm symbol"

Raw strings

#"This: "\uB212" is the escape code for the Ångstrøm symbol"#
This: "\uB212" is the escape code for the Ångstrøm symbol
# raw strings

Raw strings

#"This: "\uB212" is the escape code for the Ångstrøm symbol. 
You can still use the escape code by adding the same number 
of pound signs: \#212B"#
This: "\uB212" is the escape code for the Ångstrøm symbol. 
You can still use the escape code by adding the same number 
of pound signs: Å
# raw strings

cue fmt

Transpiling

cue import "mydocument.yaml"
cue import "mydocument.json"

cue export "mydocument.cue" --out "yaml"
cue export "mydocument.cue" --out "json"
# transpiling

data language

There is more

Data language

Represent data in a structure

1.

2.

Schema language

Test and verify data for correctness and concistency

3.

Template language

Set default values, and generate values and structures

# more

JSON Schemas

      "livenessProbe": {
        "type": "object",
        "required": [
          "exec"
        ],
        "properties": {
          "exec": {
            "type": "object",
            "required": [
              "command"
            ],
            "properties": {
              "command": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "initialDelaySeconds": {
            "type": "integer",
            "minimum": 0
          },
          "timeoutSeconds": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
# json schema
livenessProbe:
    exec:
        command:
        - "podcli"
        - "check"
        - "http"
        - "localhost:9898/healthz"
    initialDelaySeconds: 5
    timeoutSeconds: 5

json schema

data.yaml

CUE as a schema

livenessProbe: {
    exec!: {
        command!: [...string]
    }
    initialDelaySeconds?: int & >=0
    timeoutSeconds?:      int & >=0
}
# CUE schema
livenessProbe:
    exec:
        command:
        - "podcli"
        - "check"
        - "http"
        - "localhost:9898/healthz"
    initialDelaySeconds: 5
    timeoutSeconds: 5

CUE schema

data.yaml

user@host ~ $ cue vet schema.cue data.yaml

CUE as a schema/template

livenessProbe: {
    exec!: {
        command!: [...string]
    }
    initialDelaySeconds: *5 | int & >=0 
    timeoutSeconds:      5
}
# CUE schema
livenessProbe:
    exec:
        command:
        - "podcli"
        - "check"
        - "http"
        - "localhost:9898/healthz"

CUE schema

data.yaml

user@host ~ $ cue export schema.cue data.yaml --out yaml
livenessProbe:
    exec:
        command:
        - "podcli"
        - "check"
        - "http"
        - "localhost:9898/healthz"
    initialDelaySeconds: 5
    timeoutSeconds: 5

CUE as a schema/template

livenessProbe: {
    exec!: {
        command!: [...string]
    }
    initialDelaySeconds: *5 | int & >=0 
    timeoutSeconds:      initialDelaySeconds * 2
}
# CUE schema
livenessProbe:
    exec:
        command:
        - "podcli"
        - "check"
        - "http"
        - "localhost:9898/healthz"

CUE schema

data.yaml

user@host ~ $ cue export schema.cue data.yaml --out yaml
livenessProbe:
    exec:
        command:
        - "podcli"
        - "check"
        - "http"
        - "localhost:9898/healthz"
    initialDelaySeconds: 5
    timeoutSeconds: 10

Data templates

Never write yaml again

By Bård Aase

Never write yaml again

  • 111