From 3fb2feb843d70a485f0322309ae99580d5eb06a4 Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Mon, 14 Nov 2016 17:49:44 -0700 Subject: [PATCH] docs(yaml_techniques): add YAML techniques document This documents YAML and provides information about how Helm and Kubernetes interpret the YAML. --- README.md | 3 +- docs/chart_template_guide/yaml_techniques.md | 349 +++++++++++++++++++ 2 files changed, 351 insertions(+), 1 deletion(-) create mode 100644 docs/chart_template_guide/yaml_techniques.md diff --git a/README.md b/README.md index a7e2ab9fb..0581367c1 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,8 @@ including installing pre-releases. - [Subcharts and Global Values](docs/chart_template_guide/subcharts_and_globals.md) - [Debugging Templates](docs/chart_template_guide/debugging.md) - [Wrapping Up](docs/chart_template_guide/wrapping_up.md) - - [Appendix: Go Data Types](docs/chart_template_guide/data_types.md) + - [Appendix A: YAML Techniques](docs/chart_template_guide/yaml_techniques.md) + - [Appendix B: Go Data Types](docs/chart_template_guide/data_types.md) - [Architecture](docs/architecture.md) - [Developers](docs/developers.md) - [History](docs/history.md) diff --git a/docs/chart_template_guide/yaml_techniques.md b/docs/chart_template_guide/yaml_techniques.md new file mode 100644 index 000000000..57fbb47ad --- /dev/null +++ b/docs/chart_template_guide/yaml_techniques.md @@ -0,0 +1,349 @@ +# YAML Techniques + +Most of this guide has been focused on writing the template language. Here, +we'll look at the YAML format. YAML has some useful features that we, as +template authors, can use to make our templates less error prone and easier +to read. + +## Scalars and Collections + +According to the [YAML spec](http://yaml.org/spec/1.2/spec.html), there are two +types of collections, and many scalar types. + +The two types of collections are maps and sequences: + +```yaml +map: + one: 1 + two: 2 + three: 3 + +sequence: + - one + - two + - three +``` + +Scalar values are individual values (as opposed to collections) + +### Scalar Types in YAML + +In Helm's dialect of YAML, the scalar data type of a value is determined by a +complex set of rules, including the Kubernetes schema for resource definitions. +But when inferring types, the following rules tend to hold true. + +If an integer or float is an unquoted bare word, it is typically treated as +a numeric type: + +```yaml +count: 1 +size: 2.34 +``` + +But if they are quoted, they are treated as strings: + +```yaml +count: "1" # <-- string, not int +size: '2.34' # <-- string, not float +``` + +The same is true of booleans: + +```yaml +isGood: true # bool +answer: "true" # string +``` + +The word for an empty value is `null` (not `nil`). + +Note that `port: "80"` is valid YAML, and will pass through both the +template engine and the YAML parser, but will fail if Kubernetes expects +`port` to be an integer. + +In some cases, you can force a particular type inference using YAML node tags: + +```yaml +coffee: "yes, please" +age: !!str 21 +port: !!int "80" +``` + +In the above, `!!str` tells the parser that `age` is a string, even if it looks +like an int. And `port` is treated as an int, even though it is quoted. + + +## Strings in YAML + +Much of the data that we place in YAML documents are strings. YAML has more than +one way to represent a string. This section explains the ways and demonstrates +how to use some of them. + +There are three "inline" ways of declaring a string: + +```yaml +way1: bare words +way2: "double-quoted strings" +way3: 'single-quoted strings' +``` + +All inline styles must be on one line. + +- Bare words are unquoted, and are not escaped. For this reason, you have to + be careful what characters you use. +- Double-quoted strings can have specific characters escaped with `\`. For + example `"\"Hello\", she said"`. You can escape line breaks with `\n`. +- Single-quoted strings are "literal" strings, and do not use the `\` to + escape characters. The only escape sequence is `''`, which is decoded as + a single `'`. + +In addition to the one-line strings, you can declare multi-line strings: + +```yaml +coffee: | + Latte + Cappuccino + Espresso +``` + +The above will treat the value of `coffee` as a single string equivalent to +`Latte\nCappuccino\nEspresso\n`. + +Note that the first line after the `|` must be correctly indented. So we could +break the example above by doing this: + +```yaml +coffee: | + Latte + Cappuccino + Espresso + +``` + +Because `Latte` is incorrectly indented, we'd get an error like this: + +``` +Error parsing file: error converting YAML to JSON: yaml: line 7: did not find expected key +``` + +In templates, it is sometimes safer to put a fake "first line" of content in a +multi-line document just for protection from the above error: + +```yaml +coffee: | + # Commented first line + Latte + Cappuccino + Espresso + +``` + +Note that whatever that first line is, it will be preserved in the output of the +string. So if you are, for example, using this technique to inject a file's contents +into a ConfigMap, the comment should be of the type expected by whatever is +reading that entry. + +### Controlling Spaces in Multi-line Strings + +In the example above, we used `|` to indicate a multi-line string. But notice +that the content of our string was followed with a trailing `\n`. If we want +the YAML processor to strip off the trailing newline, we can add a `-` after the +`|`: + +```yaml +coffee: |- + Latte + Cappuccino + Espresso +``` + +Now the `coffee` value will be: `Latte\nCappuccino\nEspresso` (with no trailing +`\n`). + +Other times, we might want all trailing whitespace to be preserved. We can do +this with the `|+` notation: + +```yaml +coffee: |+ + Latte + Cappuccino + Espresso + + +another: value +``` + +Now the value of `coffee` will be `Latte\nCappuccino\nEspresso\n\n\n`. + +Indentation inside of a text block is preserved, and results in the preservation +of line breaks, too: + +``` +coffee: |- + Latte + 12 oz + 16 oz + Cappuccino + Espresso +``` + +In the above case, `coffee` will be `Latte\n 12 oz\n 16 oz\nCappuccino\nEspresso`. + +### Indenting and Templates + +When writing templates, you may find yourself wanting to inject the contents of +a file into the template. As we saw in previous chapters, there are two ways +of doing this: + +- Use `{{ .Files.Get "FILENAME" }}` to get the contents of a file in the chart. +- Use `{{ include "TEMPLATE" . }}` to render a template and then place its + contents into the chart. + +When inserting files into YAML, it's good to understand the multi-line rules above. +Often times, the easiest way to insert a static file is to do something like +this: + +```yaml +myfile: | +{{ .Files.Get "myfile.txt" | indent 2 }} +``` + +Note how we do the indentation above: `indent 2` tells the template engine to +indent every line in "myfile.txt" with two spaces. Note that we do not indent +that template line. That's because if we did, the file content of the first line +would be indented twice. + +### Folded Multi-line Strings + +Sometimes you want to represent a string in your YAML with multiple lines, but +want it to be treated as one long line when it is interpreted. This is called +"folding". To declare a folded block, use `>` instead of `|`: + +```yaml +coffee: > + Latte + Cappuccino + Espresso + + +``` + +The value of `coffee` above will be `Latte Cappuccino Espresso\n`. Note that all +but the last line feed will be converted to spaces. You can combine the whitespace +controls with the folded text marker, so `>-` will replace or trim all newlines. + +Note that in the folded syntax, indenting text will cause lines to be preserved. + +```yaml +coffee: >- + Latte + 12 oz + 16 oz + Cappuccino + Espresso +``` + +The above will produce `Latte\n 12 oz\n 16 oz\nCappuccino Espresso`. Note that +both the spacing and the newlines are still there. + +## Embedding Multiple Documents in One File + +It is possible to place more than one YAML documents into a single file. This +is done by prefixing a new document with `---` and ending the document with +`...` + +```yaml + +--- +document:1 +... +--- +document: 2 +... +``` + +In many cases, either the `---` or the `...` may be omitted. + +Some files in Helm cannot contain more than one doc. If, for example, more +than one document is provided inside of a `values.yaml` file, only the first +will be used. + +Template files, however, may have more than one document. When this happends, +the file (and all of its documents) is treated as one object during +template rendering. But then the resulting YAML is split into multiple +documents before it is fed to Kubernetes. + +We recommend only using multiple documents per file when it is absolutely +necessary. Having multiple documents in a file can be difficult to debug. + +## YAML is a Superset of JSON + +Because YAML is a superset of JSON, any valid JSON document _should_ be valid +YAML. + +```json +{ + "coffee": "yes, please", + "coffees": [ + "Latte", "Cappuccino", "Espresso" + ] +} +``` + +The above is another way of representing this: + +```yaml +coffee: yes, please +coffees: +- Latte +- Cappuccino +- Espresso +``` + +And the two can be mixed (with care): + +```yaml +coffee: "yes, please" +coffees: [ "Latte", "Cappuccino", "Espresso"] +``` + +All three of these should parse into the same internal representation. + +While this means that files such as `values.yaml` may contain JSON data, Helm +does not treat the file extension `.json` as a valid suffix. + +## YAML Anchors + +The YAML spec provides a way to store a reference to a value, and later +refer to that value by reference. YAML refers to this as "anchoring": + +```yaml +coffee: "yes, please" +favorite: &favoriteCoffee "Cappucino" +coffess: + - Latte + - *favoriteCoffee + - Espresso +``` + +In the above, `&favoriteCoffee` sets a reference to `Cappuccino`. Later, that +reference is used as `*favoriteCoffee`. So `coffees` becomes +`Latte, Cappuccino, Espresso`. + +While there are a few cases where anchors are useful, there is one aspect of +them that can cause subtle bugs: The first time the YAML is consumed, the +reference is expanded and then discarded. + +So if we were to decode and then re-encode the example above, the resulting +YAML would be: + +```YAML +coffee: yes, please +favorite: Cappucino +coffess: +- Latte +- Cappucino +- Espresso +``` + +Because Helm and Kubernetes often read, modify, and then rewrite YAML files, +the anchors will be lost.