github.com/felipejfc/helm@v2.1.2+incompatible/docs/chart_template_guide/named_templates.md (about)

     1  # Named Templates
     2  
     3  It is time to move beyond one template, and begin to create others. In this section, we will see how to define _named templates_ in one file, and then use them elsewhere. A _named template_ (sometimes called a _partial_ or a _subtemplate_) is simply a template defined inside of a file, and given a name. We'll see two ways to create them, and a few different ways to use them.
     4  
     5  In the "Conditionals and Loops" section we introduced three actions for declaring and managing templates: `define`, `template`, and `block`. In this section, we'll cover those three actions, and also introduce a special-purpose `include` function that works similarly to the `template` action.
     6  
     7  ## Partials and `_` files
     8  
     9  So far, we've used one file, and that one file has contained a single template. But Helm's template language allows you to create named embedded templates, that can be accessed by name elsewhere.
    10  
    11  Before we get to the nuts-and-bolts of writing those templates, there is file naming convention that deserves mention:
    12  
    13  - Most files in `templates/` are treated as if they contain Kubernetes manifests
    14  - The `NOTES.txt` is one exception
    15  - But files whose name begins with an underscore (`_`) are assumed to _not_ have a manifest inside. The rendered version of these files is not sent to Kubernetes.
    16  
    17  These files are used to store partials and helpers. In fact, when we first created `mychart`, we saw a file called `_helpers.tpl`. That file is the default location for template partials.
    18  
    19  ## Declaring and using templates with `define` and `template`
    20  
    21  The `define` action allows us to create a named template inside of a template file. Its syntax goes like this:
    22  
    23  ```yaml
    24  {{ define "MY_NAME" }}
    25    # body of template here
    26  {{ end }}
    27  ```
    28  
    29  For example, we can define a template to encapsulate a Kubernetes block of labels:
    30  
    31  ```yaml
    32  {{- define "my_labels" }}
    33    labels:
    34      generator: helm
    35      date: {{ now | htmlDate }}
    36  {{- end }}
    37  ```
    38  
    39  Now we can embed this template inside of our existing ConfigMap, and then include it with the `template` action:
    40  
    41  ```
    42  {{- define "my_labels" }}
    43    labels:
    44      generator: helm
    45      date: {{ now | htmlDate }}
    46  {{- end }}
    47  apiVersion: v1
    48  kind: ConfigMap
    49  metadata:
    50    name: {{ .Release.Name }}-configmap
    51    {{- template "my_labels" }}
    52  data:
    53    myvalue: "Hello World"
    54    {{- range $key, $val := .Values.favorite }}
    55    {{ $key }}: {{ $val | quote }}
    56    {{- end }}
    57  ```
    58  
    59  When the template engine reads this file, it will store away the reference to `my_labels` until `template "my_labels"` is called. Then it will render that template inline. So the result will look like this:
    60  
    61  ```yaml
    62  # Source: mychart/templates/configmap.yaml
    63  apiVersion: v1
    64  kind: ConfigMap
    65  metadata:
    66    name: running-panda-configmap
    67    labels:
    68      generator: helm
    69      date: 2016-11-02
    70  data:
    71    myvalue: "Hello World"
    72    drink: "coffee"
    73    food: "pizza"
    74  ```
    75  
    76  Conventionally, Helm charts put these templates inside of a partials file, usually `_helpers.tpl`. Let's move this function there:
    77  
    78  ```yaml
    79  {{/* Generate basic labels */}}
    80  {{- define "my_labels" }}
    81    labels:
    82      generator: helm
    83      date: {{ now | htmlDate }}
    84  {{- end }}
    85  ```
    86  
    87  By convention, `define` functions should have a simple documentation block (`{{/* ... */}}`) describing what they do.
    88  
    89  Even though this definition is in `_helpers.tpl`, it can still be accessed in `configmap.yaml`:
    90  
    91  ```yaml
    92  apiVersion: v1
    93  kind: ConfigMap
    94  metadata:
    95    name: {{ .Release.Name }}-configmap
    96    {{- template "my_labels" }}
    97  data:
    98    myvalue: "Hello World"
    99    {{- range $key, $val := .Values.favorite }}
   100    {{ $key }}: {{ $val | quote }}
   101    {{- end }}
   102  ```
   103  
   104  There is one _really important detail_ to keep in mind when naming templates: **template names are global**. If you declare two templates with the same name, whichever one is loaded last will be the one used. Because templates in subcharts are compiled together with top-level templates, you should be careful to name your templates with chart-specific names.
   105  
   106  One popular naming convention is to prefix each defined template with the name of the chart: `{{ define "mychart.labels" }}` or `{{ define "mychart_labels" }}`.
   107  
   108  ## Setting the scope of a template
   109  
   110  In the template we defined above, we did not use any objects. We just used functions. Let's modify our defined template to include the chart name and chart version:
   111  
   112  ```yaml
   113  {{/* Generate basic labels */}}
   114  {{- define "my_labels" }}
   115    labels:
   116      generator: helm
   117      date: {{ now | htmlDate }}
   118      chart: {{ .Chart.Name }}
   119      version: {{ .Chart.Version }}
   120  {{- end }}
   121  ```
   122  
   123  If we render this, the result will not be what we expect:
   124  
   125  ```yaml
   126  # Source: mychart/templates/configmap.yaml
   127  apiVersion: v1
   128  kind: ConfigMap
   129  metadata:
   130    name: moldy-jaguar-configmap
   131    labels:
   132      generator: helm
   133      date: 2016-11-02
   134      chart:
   135      version:
   136  ```
   137  
   138  What happened to the name and version? They weren't in the scope for our defined template. When a named template (created with `define`) is rendered, it will receive the scope passed in by the `template` call. In our example, we included the template like this:
   139  
   140  ```
   141  {{- template "my_labels" }}
   142  ```
   143  
   144  No scope was passed in, so within the template we cannot access anything in `.`. This is easy enough to fix, though. We simply pass a scope to the template:
   145  
   146  ```yaml
   147  apiVersion: v1
   148  kind: ConfigMap
   149  metadata:
   150    name: {{ .Release.Name }}-configmap
   151    {{- template "my_labels" . }}
   152  ```
   153  
   154  Note that we pass `.` at the end of the `template` call. We could just as easily pass `.Values` or `.Values.favorite` or whatever scope we want. But what we want is the top-level scope.
   155  
   156  Now when we execute this template with `helm install --dry-run --debug ./mychart`, we get this:
   157  
   158  ```yaml
   159  # Source: mychart/templates/configmap.yaml
   160  apiVersion: v1
   161  kind: ConfigMap
   162  metadata:
   163    name: plinking-anaco-configmap
   164    labels:
   165      generator: helm
   166      date: 2016-11-02
   167      chart: mychart
   168      version: 0.1.0
   169  ```
   170  
   171  Now `{{ .Chart.Name }}` resolves to `mychart`, and `{{ .Chart.Version }}` resolves to `0.1.0`.
   172  
   173  ## Creating override-able sections with `block`
   174  
   175  Say we want to create a template in our `_helpers.tpl` file, but then override part of its behavior in our template. This is what blocks are for. Sometimes we don't want to just insert a template with `template`, but we want to sketch out a default and let another template override our default. This makes it possible for one chart to define a base template, but allow another chart to strategically override some of its behavior.
   176  
   177  Blocks are declared like this:
   178  
   179  ```yaml
   180  {{ block "NAME" PIPELINE }}
   181  {{ end }}
   182  ```
   183  
   184  Here, "NAME" is the name that a `define` block can use to override it, and PIPELINE is the pipeline that will set the scope. So let's rewrite our `labels:` section to use this strategy. We'll create a basic labels section in our `_helpers.tpl` file, but add some extra labels in the `configmap.yaml` template.
   185  
   186  Let's start with `_helpers.tpl`:
   187  
   188  ```
   189  {{- define "my_labels" }}
   190    labels:
   191      chart: {{ .Chart.Name }}
   192      version: {{ .Chart.Version }}
   193      {{ block "my_extra_labels" . }}extras: false{{ end }}
   194  {{- end `u}}
   195  ```
   196  
   197  Inside of our `my_labels` template, we now declare a block called `my_extra_labels`. By default, this section will have one extra label: `extras: false`. If we were to execute this using the same `configmap.yaml` file from last time, we'd get this:
   198  
   199  ```yaml
   200  # Source: mychart/templates/configmap.yaml
   201  apiVersion: v1
   202  kind: ConfigMap
   203  metadata:
   204    name: tinseled-womba-configmap
   205    labels:
   206      chart: mychart
   207      version: 0.1.0
   208      extras: false
   209  data:
   210    myvalue: "Hello World"
   211    drink: "coffee"
   212    food: "pizza"
   213  ```
   214  
   215  But inside of our `configmap.yaml` template, we can override `my_extra_labels`:
   216  
   217  ```yaml
   218  {{- define "my_extra_labels" }}chart: {{ .Chart.Name }}{{ end -}}
   219  apiVersion: v1
   220  kind: ConfigMap
   221  metadata:
   222    name: {{ .Release.Name }}-configmap
   223    {{- template "my_labels" . }}
   224  data:
   225    myvalue: "Hello World"
   226    {{- range $key, $val := .Values.favorite }}
   227    {{ $key }}: {{ $val | quote }}
   228    {{- end }}
   229  ```
   230  
   231  On the first line, we redefine `my_extra_labels` to include `chart: {{ .Chart.Name }}`. If we
   232  run this, we will get:
   233  
   234  ```yaml
   235  # Source: mychart/templates/configmap.yaml
   236  apiVersion: v1
   237  kind: ConfigMap
   238  metadata:
   239    name: ignorant-scorp-configmap
   240    labels:
   241      chart: mychart
   242      version: 0.1.0
   243      chart: mychart
   244  data:
   245    myvalue: "Hello World"
   246    drink: "coffee"
   247    food: "pizza"
   248  ```
   249  
   250  Gone is the `extras: false` section, since that part of the template is now overridden by our new template, which placed `chart: mychart` into the output.
   251  
   252  Blocks are not frequently used in Helm charts. But they do provide one mechanism for creating "abstract" charts, and then selectively overriding parts of the abstract template with concrete implementations.
   253  
   254  ## The `include` function
   255  
   256  Say we've defined a simple template that looks like this:
   257  
   258  ```
   259  {{- define "mychart_app" -}}
   260  app_name: {{ .Chart.Name }}
   261  app_version: "{{ .Chart.Version} }+{{ .Release.Time.Seconds }}"
   262  {{- end -}}
   263  ```
   264  
   265  Now say I want to insert this both into the `labels:` section of my template, and also the `data:` section:
   266  
   267  ```yaml
   268  apiVersion: v1
   269  kind: ConfigMap
   270  metadata:
   271    name: {{ .Release.Name }}-configmap
   272    labels:
   273      {{ template "mychart_app" .}}
   274  data:
   275    myvalue: "Hello World"
   276    {{- range $key, $val := .Values.favorite }}
   277    {{ $key }}: {{ $val | quote }}
   278    {{- end }}
   279    {{ template "mychart_app" . }}
   280  
   281  ```
   282  
   283  The output will not be what we expect:
   284  
   285  ```yaml
   286  # Source: mychart/templates/configmap.yaml
   287  apiVersion: v1
   288  kind: ConfigMap
   289  metadata:
   290    name: measly-whippet-configmap
   291    labels:
   292      app_name: mychart
   293  app_version: "0.1.0+1478129847"
   294  data:
   295    myvalue: "Hello World"
   296    drink: "coffee"
   297    food: "pizza"
   298    app_name: mychart
   299  app_version: "0.1.0+1478129847"
   300  ```
   301  
   302  Note that the indentation on `app_version` is wrong in both places. Why? Because the template that is substituted in has the text aligned to the right. 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.
   303  
   304  To work around this case, Helm provides an alternative to `template` that will import the contents of a template into the present pipeline where it can be passed along to other functions in the pipeline.
   305  
   306  Here's the example above, corrected to use `indent` to indent the `mychart_app` template correctly:
   307  
   308  ```yaml
   309  apiVersion: v1
   310  kind: ConfigMap
   311  metadata:
   312    name: {{ .Release.Name }}-configmap
   313    labels:
   314  {{ include "mychart_app" . | indent 4 }}
   315  data:
   316    myvalue: "Hello World"
   317    {{- range $key, $val := .Values.favorite }}
   318    {{ $key }}: {{ $val | quote }}
   319    {{- end }}
   320  {{ include "mychart_app" . | indent 2 }}
   321  ```
   322  
   323  Now the produced YAML is correctly indented for each section:
   324  
   325  ```yaml
   326  # Source: mychart/templates/configmap.yaml
   327  apiVersion: v1
   328  kind: ConfigMap
   329  metadata:
   330    name: edgy-mole-configmap
   331    labels:
   332      app_name: mychart
   333      app_version: "0.1.0+1478129987"
   334  data:
   335    myvalue: "Hello World"
   336    drink: "coffee"
   337    food: "pizza"
   338    app_name: mychart
   339    app_version: "0.1.0+1478129987"
   340  ```
   341  
   342  > It is considered preferable to use `include` over `template` in Helm templates simply so that the output formatting can be handled better for YAML documents.
   343  
   344  Sometimes we want to import content, but not as templates. That is, we want to import files verbatim. We can achieve this by accessing files through the `.Files` object described in the next section.