PageSourceSearch

https://andygol-helm.netlify.app/assets/js/56ec861b.71f763e0.js

js andygol-helm.netlify.app collected 2026-10-03 10:31:01 UTC 23,623 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunkhelm_www=self.webpackChunkhelm_www||[]).push([["39082"],{81589(e,n,t){t.r(n),t.d(n,{metadata:()=>i,default:()=>h,frontMatter:()=>s,contentTitle:()=>l,toc:()=>c,assets:()=>r});var i=JSON.parse('{"id":"chart_template_guide/control_structures","title":"Flow Control","description":"A quick overview on the flow structure within templates.","source":"@site/docs/chart_template_guide/control_structures.md","sourceDirName":"chart_template_guide","slug":"/chart_template_guide/control_structures","permalink":"/docs/chart_template_guide/control_structures","draft":false,"unlisted":false,"editUrl":"https://github.com/helm/helm-www/blob/main/docs/chart_template_guide/control_structures.md","tags":[],"version":"current","sidebarPosition":7,"frontMatter":{"title":"Flow Control","description":"A quick overview on the flow structure within templates.","sidebar_position":7},"sidebar":"tutorialSidebar","previous":{"title":"Template Function List","permalink":"/docs/chart_template_guide/function_list"},"next":{"title":"Variables","permalink":"/docs/chart_template_guide/variables"}}'),o=t(74848),a=t(28453);let s={title:"Flow Control",description:"A quick overview on the flow structure within templates.",sidebar_position:7},l,r={},c=[{value:"If/Else",id:"ifelse",level:2},{value:"Controlling Whitespace",id:"controlling-whitespace",level:2},{value:"Modifying scope using <code>with</code>",id:"modifying-scope-using-with",level:2},{value:"Looping with the <code>range</code> action",id:"looping-with-the-range-action",level:2}];function d(e){let n={a:"a",blockquote:"blockquote",code:"code",em:"em",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,a.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.p,{children:"Control structures (called \"actions\" in template parlance) provide you, the\ntemplate author, with the ability to control the flow of a template's\ngeneration. Helm's template language provides the following control structures:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"if"}),"/",(0,o.jsx)(n.code,{children:"else"})," for creating conditional blocks"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"with"})," to specify a scope"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"range"}),', which provides a "for each"-style loop']}),"\n"]}),"\n",(0,o.jsx)(n.p,{children:"In addition to these, it provides a few actions for declaring and using named\ntemplate segments:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"define"})," declares a new named template inside of your template"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"template"})," imports a named template"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"block"})," declares a special kind of fillable template area"]}),"\n"]}),"\n",(0,o.jsxs)(n.p,{children:["In this section, we'll talk about ",(0,o.jsx)(n.code,{children:"if"}),", ",(0,o.jsx)(n.code,{children:"with"}),", and ",(0,o.jsx)(n.code,{children:"range"}),'. The others are\ncovered in the "Named Templates" section later in this guide.']}),"\n",(0,o.jsx)(n.h2,{id:"ifelse",children:"If/Else"}),"\n",(0,o.jsxs)(n.p,{children:["The first control structure we'll look at is for conditionally including blocks\nof text in a template. This is the ",(0,o.jsx)(n.code,{children:"if"}),"/",(0,o.jsx)(n.code,{children:"else"})," block."]}),"\n",(0,o.jsx)(n.p,{children:"The basic structure for a conditional looks like this:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{children:"{{ if PIPELINE }}\n  # Do something\n{{ else if OTHER PIPELINE }}\n  # Do something else\n{{ else }}\n  # Default case\n{{ end }}\n"})}),"\n",(0,o.jsxs)(n.p,{children:["Notice that we're now talking about ",(0,o.jsx)(n.em,{children:"pipelines"})," instead of values. The reason\nfor this is to make it clear that control structures can execute an entire\npipeline, not just evaluate a value."]}),"\n",(0,o.jsxs)(n.p,{children:["A pipeline is evaluated as ",(0,o.jsx)(n.em,{children:"false"})," if the value is:"]}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"a boolean false"}),"\n",(0,o.jsx)(n.li,{children:"a numeric zero"}),"\n",(0,o.jsx)(n.li,{children:"an empty string"}),"\n",(0,o.jsxs)(n.li,{children:["a ",(0,o.jsx)(n.code,{children:"nil"})," (empty or null)"]}),"\n",(0,o.jsxs)(n.li,{children:["an empty collection (",(0,o.jsx)(n.code,{children:"map"}),", ",(0,o.jsx)(n.code,{children:"slice"}),", ",(0,o.jsx)(n.code,{children:"tuple"}),", ",(0,o.jsx)(n.code,{children:"dict"}),", ",(0,o.jsx)(n.code,{children:"array"}),")"]}),"\n"]}),"\n",(0,o.jsx)(n.p,{children:"Under all other conditions, the condition is true."}
1),"\n",(0,o.jsx)(n.p,{children:"Let's add a simple conditional to our ConfigMap. We'll add another setting if\nthe drink is set to coffee:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'apiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: {{ .Release.Name }}-configmap\ndata:\n  myvalue: "Hello World"\n  drink: {{ .Values.favorite.drink | default "tea" | quote }}\n  food: {{ .Values.favorite.food | upper | quote }}\n  {{ if eq .Values.favorite.drink "coffee" }}mug: "true"{{ end }}\n'})}),"\n",(0,o.jsxs)(n.p,{children:["Since we commented out ",(0,o.jsx)(n.code,{children:"drink: coffee"})," in our last example, the output should\nnot include a ",(0,o.jsx)(n.code,{children:'mug: "true"'})," flag. But if we add that line back into our\n",(0,o.jsx)(n.code,{children:"values.yaml"})," file, the output should look like this:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'# Source: mychart/templates/configmap.yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: eyewitness-elk-configmap\ndata:\n  myvalue: "Hello World"\n  drink: "coffee"\n  food: "PIZZA"\n  mug: "true"\n'})}),"\n",(0,o.jsx)(n.h2,{id:"controlling-whitespace",children:"Controlling Whitespace"}),"\n",(0,o.jsx)(n.p,{children:"While we're looking at conditionals, we should take a quick look at the way\nwhitespace is controlled in templates. Let's take the previous example and\nformat it to be a little easier to read:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'apiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: {{ .Release.Name }}-configmap\ndata:\n  myvalue: "Hello World"\n  drink: {{ .Values.favorite.drink | default "tea" | quote }}\n  food: {{ .Values.favorite.food | upper | quote }}\n  {{ if eq .Values.favorite.drink "coffee" }}\n    mug: "true"\n  {{ end }}\n'})}),"\n",(0,o.jsx)(n.p,{children:"Initially, this looks good. But if we run it through the template engine, we'll\nget an unfortunate result:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-console",children:'$ helm install --dry-run --debug ./mychart\nSERVER: "localhost:44134"\nCHART PATH: /Users/mattbutcher/Code/Go/src/helm.sh/helm/_scratch/mychart\nError: YAML parse error on mychart/templates/configmap.yaml: error converting YAML to JSON: yaml: line 9: did not find expected key\n'})}),"\n",(0,o.jsx)(n.p,{children:"What happened? We generated incorrect YAML because of the whitespacing above."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'# Source: mychart/templates/configmap.yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: eyewitness-elk-configmap\ndata:\n  myvalue: "Hello World"\n  drink: "coffee"\n  food: "PIZZA"\n    mug: "true"\n'})}),"\n",(0,o.jsxs)(n.p,{children:[(0,o.jsx)(n.code,{children:"mug"})," is incorrectly indented. Let's simply out-dent that one line, and re-run:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'apiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: {{ .Release.Name }}-configmap\ndata:\n  myvalue: "Hello World"\n  drink: {{ .Values.favorite.drink | default "tea" | quote }}\n  food: {{ .Values.favorite.food | upper | quote }}\n  {{ if eq .Values.favorite.drink "coffee" }}\n  mug: "true"\n  {{ end }}\n'})}),"\n",(0,o.jsx)(n.p,{children:"When we sent that, we'll get YAML that is valid, but still looks a little funny:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'# Source: mychart/templates/configmap.yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: telling-chimp-configmap\ndata:\n  myvalue: "Hello World"\n  drink: "coffee"\n  food: "PIZZA"\n\n  mug: "true"\n\n'})}),"\n",(0,o.jsxs)(n.p,{children:["Notice that we received a few empty lines in our YAML. Why? When the template\nengine runs, it ",(0,o.jsx)(n.em,{children:"removes"})," the contents inside of ",(0,o.jsx)(n.code,{children:"{{"})," and ",(0,o.jsx)(n.code,{children:"}}"}),", but it leaves\nthe remaining whitespace exactly as is."]}),"\n",(0,o.jsx)(n.p,{children:"YAML ascribes meaning to whitespace, so managing the whitespace becomes pretty\nimportant. Fortunately, Helm templates have a few tools to help."}),"\n",(0,o.jsxs)(n.p,{children:["First, the curly brace syntax of template declarations can be modified with\nspecial characters to tell the template engine to chomp whitespace. ",(0,o.jsx)(n.code,{children:"{{- "})," (with\nthe dash and space added) indicates that whitespace should be chomped left,\nwhile ",(0,o.jsx)(n.code,{children:" -}}"})," means whitespace to the right should be consumed. ",(0,o.jsx)(n.em,{children:"Be careful!\nNewlines are whitespace!"})]}),"\n",(0,o.jsxs)(n.blockquote,{children:["\n",(0,o.jsxs)(n.p,{children:["Make sure there is a space between the ",(0,o.jsx)(n.code,{children:"-"})," and the rest of your directive.\n",(0,o.jsx)(n.code,{children:"{{- 3 }}"}),' means "trim left whitespace and print 3" while ',(0,o.jsx)(n.code,{children:"{{-3 }}"}),' means\n"print -3".']}),"\n"]}),"\n",(0,o.jsx)(n.p,{children:"Using this syntax, we can modify our template to get rid of those new lines:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'apiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: {{ .Release.Name }}-configmap\ndata:\n  myvalue: "Hello World"\n  drink: {{ .Values.favorite.drink | default "tea" | quote }}\n  food: {{ .Values.favorite.food | upper | quote }}\n  {{- if eq .Values.favorite.drink "coffee" }}\n  mug: "true"\n  {{- end }}\n'})}),"\n",(0,o.jsxs)(n.p,{children:["Just for the sake of making this point clear, let's adjust the above, and\nsubstitute an ",(0,o.jsx)(n.code,{children:"*"})," for each whitespace that will be deleted following this rule.\nAn ",(0,o.jsx)(n.code,{children:"*"})," at the end of the line indicates a newline character that would be\nremoved"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'apiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: {{ .Release.Name }}-configmap\ndata:\n  myvalue: "Hello World"\n  drink: {{ .Values.favorite.drink | default "tea" | quote }}\n  food: {{ .Values.favorite.food | upper | quote }}*\n**{{- if eq .Values.favorite.drink "coffee" }}\n  mug: "true"*\n**{{- end }}\n\n'})}),"\n",(0,o.jsx)(n.p,{children:"Keeping that in mind, we can run our template through Helm and see the result:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'# Source: mychart/templates/configmap.yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: clunky-cat-configmap\ndata:\n  myvalue: "Hello World"\n  drink: "coffee"\n  food: "PIZZA"\n  mug: "true"\n'})}),"\n",(0,o.jsx)(n.p,{children:"Be careful with the chomping modifiers. It is easy to accidentally do things\nlike this:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'  food: {{ .Values.favorite.food | upper | quote }}\n  {{- if eq .Values.favorite.drink "coffee" -}}\n  mug: "true"\n  {{- end -}}\n\n'})}),"\n",(0,o.jsxs)(n.p,{children:["That will produce ",(0,o.jsx)(n.code,{children:'food: "PIZZA"mug: "true"'}
1)," because it consumed newlines on both\nsides."]}),"\n",(0,o.jsxs)(n.blockquote,{children:["\n",(0,o.jsxs)(n.p,{children:["For the details on whitespace control in templates, see the ",(0,o.jsx)(n.a,{href:"https://godoc.org/text/template",children:"Official Go\ntemplate documentation"})]}),"\n"]}),"\n",(0,o.jsxs)(n.p,{children:["Finally, sometimes it's easier to tell the template system how to indent for you\ninstead of trying to master the spacing of template directives. For that reason,\nyou may sometimes find it useful to use the ",(0,o.jsx)(n.code,{children:"indent"})," function (",(0,o.jsx)(n.code,{children:'{{ indent 2 "mug:true" }}'}),")."]}),"\n",(0,o.jsxs)(n.h2,{id:"modifying-scope-using-with",children:["Modifying scope using ",(0,o.jsx)(n.code,{children:"with"})]}),"\n",(0,o.jsxs)(n.p,{children:["The next control structure to look at is the ",(0,o.jsx)(n.code,{children:"with"})," action. This controls\nvariable scoping. Recall that ",(0,o.jsx)(n.code,{children:"."})," is a reference to ",(0,o.jsx)(n.em,{children:"the current scope"}),". So\n",(0,o.jsx)(n.code,{children:".Values"})," tells the template to find the ",(0,o.jsx)(n.code,{children:"Values"})," object in the current scope."]}),"\n",(0,o.jsxs)(n.p,{children:["The syntax for ",(0,o.jsx)(n.code,{children:"with"})," is similar to a simple ",(0,o.jsx)(n.code,{children:"if"})," statement:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{children:"{{ with PIPELINE }}\n  # restricted scope\n{{ end }}\n"})}),"\n",(0,o.jsxs)(n.p,{children:["Scopes can be changed. ",(0,o.jsx)(n.code,{children:"with"})," can allow you to set the current scope (",(0,o.jsx)(n.code,{children:"."}),") to a\nparticular object. For example, we've been working with ",(0,o.jsx)(n.code,{children:".Values.favorite"}),".\nLet's rewrite our ConfigMap to alter the ",(0,o.jsx)(n.code,{children:"."})," scope to point to\n",(0,o.jsx)(n.code,{children:".Values.favorite"}),":"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'apiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: {{ .Release.Name }}-configmap\ndata:\n  myvalue: "Hello World"\n  {{- with .Values.favorite }}\n  drink: {{ .drink | default "tea" | quote }}\n  food: {{ .food | upper | quote }}\n  {{- end }}\n'})}),"\n",(0,o.jsxs)(n.p,{children:["Note that this example omits the ",(0,o.jsx)(n.code,{children:"mug"})," output from the previous exercise\nto focus on ",(0,o.jsx)(n.code,{children:"with"})," scoping. The ",(0,o.jsx)(n.code,{children:"with"})," block only executes if\n",(0,o.jsx)(n.code,{children:".Values.favorite"})," is not empty, so a separate outer ",(0,o.jsx)(n.code,{children:"if"})," guard is not\nneeded."]}),"\n",(0,o.jsxs)(n.p,{children:["Notice that now we can reference ",(0,o.jsx)(n.code,{children:".drink"})," and ",(0,o.jsx)(n.code,{children:".food"})," without qualifying them.\nThat is because the ",(0,o.jsx)(n.code,{children:"with"})," statement sets ",(0,o.jsx)(n.code,{children:"."})," to point to ",(0,o.jsx)(n.code,{children:".Values.favorite"}),".\nThe ",(0,o.jsx)(n.code,{children:"."})," is reset to its previous scope after ",(0,o.jsx)(n.code,{children:"{{ end }}"}),"."]}),"\n",(0,o.jsxs)(n.p,{children:["But here's a note of caution! Inside of the restricted scope, you will not be\nable to access the other objects from the parent scope using ",(0,o.jsx)(n.code,{children:"."}),". This, for\nexample, will fail:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'  {{- with .Values.favorite }}\n  drink: {{ .drink | default "tea" | quote }}\n  food: {{ .food | upper | quote }}\n  release: {{ .Release.Name }}\n  {{- end }}\n'})}),"\n",(0,o.jsxs)(n.p,{children:["It will produce an error because ",(0,o.jsx)(n.code,{children:"Release.Name"})," is not inside of the restricted\nscope for ",(0,o.jsx)(n.code,{children:"."}),". However, if we swap the last two lines, all will work as expected\nbecause the scope is reset after ",(0,o.jsx)(n.code,{children:"{{ end }}"}),"."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'  {{- with .Values.favorite }}\n  drink: {{ .drink | default "tea" | quote }}\n  food: {{ .food | upper | quote }}\n  {{- end }}\n  release: {{ .Release.Name }}\n'})}),"\n",(0,o.jsxs)(n.p,{children:["Or, we can use ",(0,o.jsx)(n.code,{children:"$"})," for accessing the object ",(0,o.jsx)(n.code,{children:"Release.Name"})," from the parent\nscope. ",(0,o.jsx)(n.code,{children:"$"})," is mapped to the root scope when template execution begins and it\ndoes not change during template execution. The following would work as well:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'  {{- with .Values.favorite }}\n  drink: {{ .drink | default "tea" | quote }}\n  food: {{ .food | upper | quote }}\n  release: {{ $.Release.Name }}\n  {{- end }}\n'})}),"\n",(0,o.jsxs)(n.p,{children:["After looking at ",(0,o.jsx)(n.code,{children:"range"}),", we will take a look at template variables, which offer\none solution to the scoping issue above."]}),"\n",(0,o.jsxs)(n.h2,{id:"looping-with-the-range-action",children:["Looping with the ",(0,o.jsx)(n.code,{children:"range"})," action"]}),"\n",(0,o.jsxs)(n.p,{children:["Many programming languages have support for looping using ",(0,o.jsx)(n.code,{children:"for"})," loops, ",(0,o.jsx)(n.code,{children:"foreach"}),"\nloops, or similar functional mechanisms. In Helm's template language, the way to\niterate through a collection is to use the ",(0,o.jsx)(n.code,{children:"range"})," operator."]}),"\n",(0,o.jsxs)(n.p,{children:["To start, let's add a list of pizza toppings to our ",(0,o.jsx)(n.code,{children:"values.yaml"})," file:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:"favorite:\n  drink: coffee\n  food: pizza\npizzaToppings:\n  - mushrooms\n  - cheese\n  - peppers\n  - onions\n  - pineapple\n"})}),"\n",(0,o.jsxs)(n.p,{children:["Now we have a list (called a ",(0,o.jsx)(n.code,{children:"slice"})," in templates) of ",(0,o.jsx)(n.code,{children:"pizzaToppings"}),". We can\nmodify our template to print this list into our ConfigMap:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'apiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: {{ .Release.Name }}-configmap\ndata:\n  myvalue: "Hello World"\n  {{- with .Values.favorite }}\n  drink: {{ .drink | default "tea" | quote }}\n  food: {{ .food | upper | quote }}\n  {{- end }}\n  toppings: |-\n    {{- range .Values.pizzaToppings }}\n    - {{ . | title | quote }}\n    {{- end }}\n\n'})}),"\n",(0,o.jsxs)(n.p,{children:["We can use ",(0,o.jsx)(n.code,{children:"$"})," for accessing the list ",(0,o.jsx)(n.code,{children:"Values.pizzaToppings"})," from the parent\nscope. ",(0,o.jsx)(n.code,{children:"$"})," is mapped to the root scope when template execution begins and it\ndoes not change during template execution. The following would work as well:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'apiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: {{ .Release.Name }}-configmap\ndata:\n  myvalue: "Hello World"\n  {{- with .Values.favorite }}\n  drink: {{ .drink | default "tea" | quote }}\n  food: {{ .food | upper | quote }}\n  toppings: |-\n    {{- range $.Values.pizzaToppings }}\n    - {{ . | title | quote }}\n    {{- end }}\n  {{- end }}\n'})}),"\n",(0,o.jsxs)(n.p,{children:["Let's take a closer look at the ",(0,o.jsx)(n.code,{children:"toppings:"})," list. The ",(0,o.jsx)(n.code,{children:"range"}),' function will\n"range over" (iterate through) the ',(0,o.jsx)(n.code,{children:"pizzaToppings"})," list. But now something\ninteresting happens. Just like ",(0,o.jsx)(n.code,{children:"with"})," sets the scope of ",(0,o.jsx)(n.code,{children:"."}),", so does a ",(0,o.jsx)(n.code,{children:"range"}
1),"\noperator. Each time through the loop, ",(0,o.jsx)(n.code,{children:"."})," is set to the current pizza topping.\nThat is, the first time, ",(0,o.jsx)(n.code,{children:"."})," is set to ",(0,o.jsx)(n.code,{children:"mushrooms"}),". The second iteration it is\nset to ",(0,o.jsx)(n.code,{children:"cheese"}),", and so on."]}),"\n",(0,o.jsxs)(n.p,{children:["We can send the value of ",(0,o.jsx)(n.code,{children:"."})," directly down a pipeline, so when we do ",(0,o.jsx)(n.code,{children:"{{ . | title | quote }}"}),", it sends ",(0,o.jsx)(n.code,{children:"."})," to ",(0,o.jsx)(n.code,{children:"title"})," (title case function) and then to\n",(0,o.jsx)(n.code,{children:"quote"}),". If we run this template, the output will be:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'# Source: mychart/templates/configmap.yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: edgy-dragonfly-configmap\ndata:\n  myvalue: "Hello World"\n  drink: "coffee"\n  food: "PIZZA"\n  toppings: |-\n    - "Mushrooms"\n    - "Cheese"\n    - "Peppers"\n    - "Onions"\n    - "Pineapple"\n'})}),"\n",(0,o.jsxs)(n.p,{children:["Now, in this example we've done something tricky. The ",(0,o.jsx)(n.code,{children:"toppings: |-"})," line is\ndeclaring a multi-line string. So our list of toppings is actually not a YAML\nlist. It's a big string. Why would we do this? Because the data in ConfigMaps\n",(0,o.jsx)(n.code,{children:"data"})," is composed of key/value pairs, where both the key and the value are\nsimple strings. To understand why this is the case, take a look at the\n",(0,o.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/configuration/configmap/",children:"Kubernetes ConfigMap docs"}),".\nFor us, though, this detail doesn't matter much."]}),"\n",(0,o.jsxs)(n.blockquote,{children:["\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"|-"})," marker in YAML takes a multi-line string. This can be a useful\ntechnique for embedding big blocks of data inside of your manifests, as\nexemplified here."]}),"\n"]}),"\n",(0,o.jsxs)(n.p,{children:["Sometimes it's useful to be able to quickly make a list inside of your template,\nand then iterate over that list. Helm templates have a function to make this\neasy: ",(0,o.jsx)(n.code,{children:"tuple"}),". In computer science, a tuple is a list-like collection of fixed\nsize, but with arbitrary data types. This roughly conveys the way a ",(0,o.jsx)(n.code,{children:"tuple"})," is\nused."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'  sizes: |-\n    {{- range tuple "small" "medium" "large" }}\n    - {{ . }}\n    {{- end }}\n'})}),"\n",(0,o.jsx)(n.p,{children:"The above will produce this:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:"  sizes: |-\n    - small\n    - medium\n    - large\n"})}),"\n",(0,o.jsxs)(n.p,{children:["In addition to lists and tuples, ",(0,o.jsx)(n.code,{children:"range"})," can be used to iterate over collections\nthat have a key and a value (like a ",(0,o.jsx)(n.code,{children:"map"})," or ",(0,o.jsx)(n.code,{children:"dict"}),"). We'll see how to do that\nin the next section when we introduce template variables."]})]})}function h(e={}){let{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}},28453(e,n,t){t.d(n,{R:()=>s,x:()=>l});var i=t(96540);let o={},a=i.createContext(o);function s(e){let n=i.useContext(a);return i.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:s(e.components),i.createElement(a.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.