Introduction to Helm -- part 2: template engine
Background
上篇介绍了why Helm 和package management feature, 本篇讨论如何使用Helm template engine.
Debug
local try and error: 即时generate当前template:
1 | # cd mychart |
Go tempalte提供printf
打印object, 如打印Values
object.
1 | {{ printf "%#v" $.Values }} |
Go template
Objects
Templates are executed by applying them to a data structure.
Text Template + Go Object = 结果
The current object is represented as .
, e.g 若object是string
:
则render: {{ . }}
若当前object有Name
field, 为string, 则: {{ .Name }}
.
关于Object传递到template:
1 | type Student struct { |
Cursor 和 Context
When execution begins, $
is set to the data argument passed to Execute; “Dot”代表当前cursor.
Execution of the template walks the structure and sets the cursor, represented by a period ‘.’ and called “dot”, to the value at the current location in the structure as execution proceeds.
Cursor即当前object/context,会变化: 如range, with 会设置不同的object, 到其内层template中.
range
, with
包裹的template: 无法access外层Object,需要定义变量: 即这两者会让scope缩小(由输入的Object $
变为某个sub Object)
Variables
1 | type Person struct { |
传入的Object为email
string, 无法access外层Object, 如Person’s name: 需要定义变量.
with
也类似: 以下输出都是”output”
1 | {{with "output"}}{{printf "%q" .}}{{end}} |
Named template
Tempalte内还可定义named template:
1 | {{define "T1"}}ONE{{end}} |
Pipeline
类似Linux的pipeline, 将多个component chain在一起:
A pipeline may be “chained” by separating a sequence of commands with pipeline characters ‘|’. In a chained pipeline, the result of each command is passed as the last argument of the following command. The output of the final command in the pipeline is the value of the pipeline.
A command is:
- a simple value (argument) or
- a function or
- method call
当前cmd的last input是上一个cmd的output
1 | # A function call. The printf parameters are identical to fmt.Printf from Go. |
Flow Control
两类:
control structures:
- if/else
- range
- with
同时还有action
:
- define: declares a new named template inside of your template
- template: imports a named template
注: include
是function, 可用在pipeline中,因此一般用include
而不是template
The include
function allows you to bring in another template, and then pass the results to other template functions.
“Because template is an action, and not a function, there is no way to pass the output of a template call to other functions; the data is simply inserted inline.”
if/else
:
1 | {{ if PIPELINE }} |
关于false
condition:
- boolean false
- 0
- nil
- empty string, slice, map, etc
with
用来modify scope的:
1 | {{ with PIPELINE }} |
例子见下面:
range
values:
1 | favorite: |
1 | apiVersion: v1 |
注意{{ . | title | quote }}
, scope在range
之后发生了改变: 变为list element.
Whitespace
if/else
和range
很常见, 但Go template engine会产生些unexpected whitespace(包含space和换行):
When the template engine runs, it removes the contents inside of , but it leaves the remaining whitespace exactly as is.
1 | food: "cake" |
会生成额外的换行(由if
而来):
1 | food: "PIZZA" |
解决方法是:
-
{{- `(with the dash and space added): whitespace should be chomped left: 消除左whitespace直到遇到非whitespace字符: * ` -}}
: 消除右whitespace直到非whitespace字符
效果示意:
1 | apiVersion: v1 |
-
*
代表删除的whitespace! -
if
行没有产生实际内容(仅仅控制内容产生),{{-
消除其whitespace -
end
行也同样没有内容,不消除会多出一个空行.
e.g:
1 | drink: {{ .Values.favorite.drink | default "tea" | quote }} |
values为:
1 | favorite: |
输出:
1 | drink: "coffee" |
Be careful! Newlines are whitespace!
还可以用 ident
来控制空格, 如:
1 | {{ include "api-service-tpl.rollout.env.common" . | indent 12 }} |
Helm doc: Flow Control 里讲解的很清楚.
Data type and Frequent Functions
Variables in templates are typed(因为Go是typed):
- string
- bool
- int
- float64
- byte array
- object/struct
- list: immutable
- dict: a string-keyed map (
map[string]interface{}
), where the value is one of the previous types
function建立在data type基石上, 理解一门语言的data type至关重要.
Helm template function有两部分:
- Go Template Function
- sprig function for Go Template
全部Helm function在Template Function List
一些常见函数:
1 | # if .Bar empty/non-exist, set to "foo" |
下一篇谈Helm template相关的advanced features.
Reference
Go text/template
Helm from basics to advanced — part II
Values Files