Add capability for application charts to be used as library charts

Signed-off-by: Martin Hickey <martin.hickey@ie.ibm.com>
pull/5441/head
Martin Hickey 6 years ago
parent b1ae1acc8b
commit b74fee715e

@ -64,6 +64,16 @@ func TestTemplateCmd(t *testing.T) {
wantError: true,
golden: "output/install-chart-bad-type.txt",
},
{
name: "check chart with dependency which is an app chart acting as a library chart",
cmd: fmt.Sprintf("template '%s'", "testdata/testcharts/chart-with-template-lib-dep"),
golden: "output/template-chart-with-template-lib-dep.txt",
},
{
name: "check chart with dependency which is an app chart archive acting as a library chart",
cmd: fmt.Sprintf("template '%s'", "testdata/testcharts/chart-with-template-lib-archive-dep"),
golden: "output/template-chart-with-template-lib-archive-dep.txt",
},
}
runTestCmd(t, tests)
}

@ -0,0 +1,62 @@
---
# Source: chart-with-template-lib-archive-dep/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: chart-with-template-lib-archive-dep
chart: chart-with-template-lib-archive-dep-0.1.0
heritage: Helm
release: RELEASE-NAME
name: release-name-chart-with-template-lib-archive-dep
spec:
ports:
- name: http
port: 80
targetPort: http
selector:
app: chart-with-template-lib-archive-dep
release: RELEASE-NAME
type: ClusterIP
---
# Source: chart-with-template-lib-archive-dep/templates/deployment.yaml
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: RELEASE-NAME-chart-with-template-lib-archive-dep
labels:
app: chart-with-template-lib-archive-dep
chart: chart-with-template-lib-archive-dep-0.1.0
release: RELEASE-NAME
heritage: Helm
spec:
replicas: 1
selector:
matchLabels:
app: chart-with-template-lib-archive-dep
release: RELEASE-NAME
template:
metadata:
labels:
app: chart-with-template-lib-archive-dep
release: RELEASE-NAME
spec:
containers:
- name: chart-with-template-lib-archive-dep
image: "nginx:stable"
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
resources:
{}

@ -0,0 +1,62 @@
---
# Source: chart-with-template-lib-dep/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: chart-with-template-lib-dep
chart: chart-with-template-lib-dep-0.1.0
heritage: Helm
release: RELEASE-NAME
name: release-name-chart-with-template-lib-dep
spec:
ports:
- name: http
port: 80
targetPort: http
selector:
app: chart-with-template-lib-dep
release: RELEASE-NAME
type: ClusterIP
---
# Source: chart-with-template-lib-dep/templates/deployment.yaml
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: RELEASE-NAME-chart-with-template-lib-dep
labels:
app: chart-with-template-lib-dep
chart: chart-with-template-lib-dep-0.1.0
release: RELEASE-NAME
heritage: Helm
spec:
replicas: 1
selector:
matchLabels:
app: chart-with-template-lib-dep
release: RELEASE-NAME
template:
metadata:
labels:
app: chart-with-template-lib-dep
release: RELEASE-NAME
spec:
containers:
- name: chart-with-template-lib-dep
image: "nginx:stable"
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
resources:
{}

@ -0,0 +1,21 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj

@ -0,0 +1,6 @@
apiVersion: v1
appVersion: "1.0"
description: A Helm chart for Kubernetes
name: chart-with-template-lib-archive-dep
type: application
version: 0.1.0

@ -0,0 +1,19 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.hosts }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "chart-with-template-lib-archive-dep.fullname" . }})
export NODE_IP=$(kubectl get nodes -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get svc -w {{ template "chart-with-template-lib-archive-dep.fullname" . }}'
export SERVICE_IP=$(kubectl get svc {{ template "chart-with-template-lib-archive-dep.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods -l "app={{ template "chart-with-template-lib-archive-dep.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:80
{{- end }}

@ -0,0 +1,32 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "chart-with-template-lib-archive-dep.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "chart-with-template-lib-archive-dep.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "chart-with-template-lib-archive-dep.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}

@ -0,0 +1,51 @@
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: {{ template "chart-with-template-lib-archive-dep.fullname" . }}
labels:
app: {{ template "chart-with-template-lib-archive-dep.name" . }}
chart: {{ template "chart-with-template-lib-archive-dep.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ template "chart-with-template-lib-archive-dep.name" . }}
release: {{ .Release.Name }}
template:
metadata:
labels:
app: {{ template "chart-with-template-lib-archive-dep.name" . }}
release: {{ .Release.Name }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 80
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
resources:
{{ toYaml .Values.resources | indent 12 }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{ toYaml . | indent 8 }}
{{- end }}

@ -0,0 +1,38 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "chart-with-template-lib-archive-dep.fullname" . -}}
{{- $ingressPath := .Values.ingress.path -}}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
app: {{ template "chart-with-template-lib-archive-dep.name" . }}
chart: {{ template "chart-with-template-lib-archive-dep.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
{{- with .Values.ingress.annotations }}
annotations:
{{ toYaml . | indent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ . }}
http:
paths:
- path: {{ $ingressPath }}
backend:
serviceName: {{ $fullName }}
servicePort: http
{{- end }}
{{- end }}

@ -0,0 +1,10 @@
{{- template "common.service" (list . "chart-with-template-lib-archive-dep.service") -}}
{{- define "chart-with-template-lib-archive-dep.service" -}}
## Define overrides for your Service resource here, e.g.
# metadata:
# labels:
# custom: label
# spec:
# ports:
# - port: 8080
{{- end -}}

@ -0,0 +1,48 @@
# Default values for chart-with-template-lib-archive-dep.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
repository: nginx
tag: stable
pullPolicy: IfNotPresent
nameOverride: ""
fullnameOverride: ""
service:
type: ClusterIP
port: 80
ingress:
enabled: false
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
path: /
hosts:
- chart-example.local
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
nodeSelector: {}
tolerations: []
affinity: {}

@ -0,0 +1,21 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj

@ -0,0 +1,6 @@
apiVersion: v1
appVersion: "1.0"
description: A Helm chart for Kubernetes
name: chart-with-template-lib-dep
type: application
version: 0.1.0

@ -0,0 +1,21 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj

@ -0,0 +1,12 @@
apiVersion: v1
appVersion: 0.0.5
description: Common chartbuilding components and helpers
home: https://helm.sh
maintainers:
- email: technosophos@gmail.com
name: technosophos
- email: adnan@bitnami.com
name: prydonius
name: common
version: 0.0.5
type: library

@ -0,0 +1,831 @@
# Common: The Helm Helper Chart
This chart is designed to make it easier for you to build and maintain Helm
charts.
It provides utilities that reflect best practices of Kubernetes chart development,
making it faster for you to write charts.
## Tips
A few tips for working with Common:
- Be careful when using functions that generate random data (like `common.fullname.unique`).
They may trigger unwanted upgrades or have other side effects.
In this document, we use `RELEASE-NAME` as the name of the release.
## Resource Kinds
Kubernetes defines a variety of resource kinds, from `Secret` to `StatefulSet`.
We define some of the most common kinds in a way that lets you easily work with
them.
The resource kind templates are designed to make it much faster for you to
define _basic_ versions of these resources. They allow you to extend and modify
just what you need, without having to copy around lots of boilerplate.
To make use of these templates you must define a template that will extend the
base template (though it can be empty). The name of this template is then passed
to the base template, for example:
```yaml
{{- template "common.service" (list . "mychart.service") -}}
{{- define "mychart.service" -}}
## Define overrides for your Service resource here, e.g.
# metadata:
# labels:
# custom: label
# spec:
# ports:
# - port: 8080
{{- end -}}
```
Note that the `common.service` template defines two parameters:
- The root context (usually `.`)
- A template name containing the service definition overrides
A limitation of the Go template library is that a template can only take a
single argument. The `list` function is used to workaround this by constructing
a list or array of arguments that is passed to the template.
The `common.service` template is responsible for rendering the templates with
the root context and merging any overrides. As you can see, this makes it very
easy to create a basic `Service` resource without having to copy around the
standard metadata and labels.
Each implemented base resource is described in greater detail below.
### `common.service`
The `common.service` template creates a basic `Service` resource with the
following defaults:
- Service type (ClusterIP, NodePort, LoadBalancer) made configurable by `.Values.service.type`
- Named port `http` configured on port 80
- Selector set to `app: {{ template "common.name" }}, release: {{ .Release.Name | quote }}` to match the default used in the `Deployment` resource
Example template:
```yaml
{{- template "common.service" (list . "mychart.mail.service") -}}
{{- define "mychart.mail.service" -}}
metadata:
name: {{ template "common.fullname" . }}-mail # overrides the default name to add a suffix
labels: # appended to the labels section
protocol: mail
spec:
ports: # composes the `ports` section of the service definition.
- name: smtp
port: 25
targetPort: 25
- name: imaps
port: 993
targetPort: 993
selector: # this is appended to the default selector
protocol: mail
{{- end -}}
---
{{ template "common.service" (list . "mychart.web.service") -}}
{{- define "mychart.web.service" -}}
metadata:
name: {{ template "common.fullname" . }}-www # overrides the default name to add a suffix
labels: # appended to the labels section
protocol: www
spec:
ports: # composes the `ports` section of the service definition.
- name: www
port: 80
targetPort: 8080
{{- end -}}
```
The above template defines _two_ services: a web service and a mail service.
The most important part of a service definition is the `ports` object, which
defines the ports that this service will listen on. Most of the time,
`selector` is computed for you. But you can replace it or add to it.
The output of the example above is:
```yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: service
chart: service-0.1.0
heritage: Tiller
protocol: mail
release: release-name
name: release-name-service-mail
spec:
ports:
- name: smtp
port: 25
targetPort: 25
- name: imaps
port: 993
targetPort: 993
selector:
app: service
release: release-name
protocol: mail
type: ClusterIP
---
apiVersion: v1
kind: Service
metadata:
labels:
app: service
chart: service-0.1.0
heritage: Tiller
protocol: www
release: release-name
name: release-name-service-www
spec:
ports:
- name: www
port: 80
targetPort: 8080
type: ClusterIP
```
## `common.deployment`
The `common.deployment` template defines a basic `Deployment`. Underneath the
hood, it uses `common.container` (see next section).
By default, the pod template within the deployment defines the labels `app: {{ template "common.name" . }}`
and `release: {{ .Release.Name | quote }` as this is also used as the selector. The
standard set of labels are not used as some of these can change during upgrades,
which causes the replica sets and pods to not correctly match.
Example use:
```yaml
{{- template "common.deployment" (list . "mychart.deployment") -}}
{{- define "mychart.deployment" -}}
## Define overrides for your Deployment resource here, e.g.
spec:
replicas: {{ .Values.replicaCount }}
{{- end -}}
```
## `common.container`
The `common.container` template creates a basic `Container` spec to be used
within a `Deployment` or `ReplicaSet`. It holds the following defaults:
- The name is set to the chart name
- Uses `.Values.image` to describe the image to run, with the following spec:
```yaml
image:
repository: nginx
tag: stable
pullPolicy: IfNotPresent
```
- Exposes the named port `http` as port 80
- Lays out the compute resources using `.Values.resources`
Example use:
```yaml
{{- template "common.deployment" (list . "mychart.deployment") -}}
{{- define "mychart.deployment" -}}
## Define overrides for your Deployment resource here, e.g.
spec:
template:
spec:
containers:
- {{ template "common.container" (list . "mychart.deployment.container") }}
{{- end -}}
{{- define "mychart.deployment.container" -}}
## Define overrides for your Container here, e.g.
livenessProbe:
httpGet:
path: /
port: 80
readinessProbe:
httpGet:
path: /
port: 80
{{- end -}}
```
The above example creates a `Deployment` resource which makes use of the
`common.container` template to populate the PodSpec's container list. The usage
of this template is similar to the other resources, you must define and
reference a template that contains overrides for the container object.
The most important part of a container definition is the image you want to run.
As mentioned above, this is derived from `.Values.image` by default. It is a
best practice to define the image, tag and pull policy in your charts' values as
this makes it easy for an operator to change the image registry, or use a
specific tag or version. Another example of configuration that should be exposed
to chart operators is the container's required compute resources, as this is
also very specific to an operators environment. An example `values.yaml` for
your chart could look like:
```yaml
image:
repository: nginx
tag: stable
pullPolicy: IfNotPresent
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
```
The output of running the above values through the earlier template is:
```yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
labels:
app: deployment
chart: deployment-0.1.0
heritage: Tiller
release: release-name
name: release-name-deployment
spec:
template:
metadata:
labels:
app: deployment
spec:
containers:
- image: nginx:stable
imagePullPolicy: IfNotPresent
livenessProbe:
httpGet:
path: /
port: 80
name: deployment
ports:
- containerPort: 80
name: http
readinessProbe:
httpGet:
path: /
port: 80
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
```
## `common.configmap`
The `common.configmap` template creates an empty `ConfigMap` resource that you
can override with your configuration.
Example use:
```yaml
{{- template "common.configmap" (list . "mychart.configmap") -}}
{{- define "mychart.configmap" -}}
data:
zeus: cat
athena: cat
julius: cat
one: |-
{{ .Files.Get "file1.txt" }}
{{- end -}}
```
Output:
```yaml
apiVersion: v1
data:
athena: cat
julius: cat
one: This is a file.
zeus: cat
kind: ConfigMap
metadata:
labels:
app: configmap
chart: configmap-0.1.0
heritage: Tiller
release: release-name
name: release-name-configmap
```
## `common.secret`
The `common.secret` template creates an empty `Secret` resource that you
can override with your secrets.
Example use:
```yaml
{{- template "common.secret" (list . "mychart.secret") -}}
{{- define "mychart.secret" -}}
data:
zeus: {{ print "cat" | b64enc }}
athena: {{ print "cat" | b64enc }}
julius: {{ print "cat" | b64enc }}
one: |-
{{ .Files.Get "file1.txt" | b64enc }}
{{- end -}}
```
Output:
```yaml
apiVersion: v1
data:
athena: Y2F0
julius: Y2F0
one: VGhpcyBpcyBhIGZpbGUuCg==
zeus: Y2F0
kind: Secret
metadata:
labels:
app: secret
chart: secret-0.1.0
heritage: Tiller
release: release-name
name: release-name-secret
type: Opaque
```
## `common.ingress`
The `common.ingress` template is designed to give you a well-defined `Ingress`
resource, that can be configured using `.Values.ingress`. An example values file
that can be used to configure the `Ingress` resource is:
```yaml
ingress:
hosts:
- chart-example.local
annotations:
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
tls:
- secretName: chart-example-tls
hosts:
- chart-example.local
```
Example use:
```yaml
{{- template "common.ingress" (list . "mychart.ingress") -}}
{{- define "mychart.ingress" -}}
{{- end -}}
```
Output:
```yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
labels:
app: ingress
chart: ingress-0.1.0
heritage: Tiller
release: release-name
name: release-name-ingress
spec:
rules:
- host: chart-example.local
http:
paths:
- backend:
serviceName: release-name-ingress
servicePort: 80
path: /
tls:
- hosts:
- chart-example.local
secretName: chart-example-tls
```
## `common.persistentvolumeclaim`
`common.persistentvolumeclaim` can be used to easily add a
`PersistentVolumeClaim` resource to your chart that can be configured using
`.Values.persistence`:
| Value | Description |
| ------------------------- | ------------------------------------------------------------------------------------------------------- |
| persistence.enabled | Whether or not to claim a persistent volume. If false, `common.volume.pvc` will use an emptyDir instead |
| persistence.storageClass | `StorageClass` name |
| persistence.accessMode | Access mode for persistent volume |
| persistence.size | Size of persistent volume |
| persistence.existingClaim | If defined, `PersistentVolumeClaim` is not created and `common.volume.pvc` helper uses this claim |
An example values file that can be used to configure the
`PersistentVolumeClaim` resource is:
```yaml
persistence:
enabled: true
storageClass: fast
accessMode: ReadWriteOnce
size: 8Gi
```
Example use:
```yaml
{{- template "common.persistentvolumeclaim" (list . "mychart.persistentvolumeclaim") -}}
{{- define "mychart.persistentvolumeclaim" -}}
{{- end -}}
```
Output:
```yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
labels:
app: persistentvolumeclaim
chart: persistentvolumeclaim-0.1.0
heritage: Tiller
release: release-name
name: release-name-persistentvolumeclaim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 8Gi
storageClassName: "fast"
```
## Partial API Objects
When writing Kubernetes resources, you may find the following helpers useful to
construct parts of the spec.
### EnvVar
Use the EnvVar helpers within a container spec to simplify specifying key-value
environment variables or referencing secrets as values.
Example Use:
```yaml
{{- template "common.deployment" (list . "mychart.deployment") -}}
{{- define "mychart.deployment" -}}
spec:
template:
spec:
containers:
- {{ template "common.container" (list . "mychart.deployment.container") }}
{{- end -}}
{{- define "mychart.deployment.container" -}}
{{- $fullname := include "common.fullname" . -}}
env:
- {{ template "common.envvar.value" (list "ZEUS" "cat") }}
- {{ template "common.envvar.secret" (list "ATHENA" "secret-name" "athena") }}
{{- end -}}
```
Output:
```yaml
...
spec:
containers:
- env:
- name: ZEUS
value: cat
- name: ATHENA
valueFrom:
secretKeyRef:
key: athena
name: secret-name
...
```
### Volume
Use the Volume helpers within a `Deployment` spec to help define ConfigMap and
PersistentVolumeClaim volumes.
Example Use:
```yaml
{{- template "common.deployment" (list . "mychart.deployment") -}}
{{- define "mychart.deployment" -}}
spec:
template:
spec:
volumes:
- {{ template "common.volume.configMap" (list "config" "configmap-name") }}
- {{ template "common.volume.pvc" (list "data" "pvc-name" .Values.persistence) }}
{{- end -}}
```
Output:
```yaml
...
spec:
volumes:
- configMap:
name: configmap-name
name: config
- name: data
persistentVolumeClaim:
claimName: pvc-name
...
```
The `common.volume.pvc` helper uses the following configuration from the `.Values.persistence` object:
| Value | Description |
| ------------------------- | ----------------------------------------------------- |
| persistence.enabled | If false, creates an `emptyDir` instead |
| persistence.existingClaim | If set, uses this instead of the passed in claim name |
## Utilities
### `common.fullname`
The `common.fullname` template generates a name suitable for the `name:` field
in Kubernetes metadata. It is used like this:
```yaml
name: {{ template "common.fullname" . }}
```
The following different values can influence it:
```yaml
# By default, fullname uses '{{ .Release.Name }}-{{ .Chart.Name }}'. This
# overrides that and uses the given string instead.
fullnameOverride: "some-name"
# This adds a prefix
fullnamePrefix: "pre-"
# This appends a suffix
fullnameSuffix: "-suf"
# Global versions of the above
global:
fullnamePrefix: "pp-"
fullnameSuffix: "-ps"
```
Example output:
```yaml
---
# with the values above
name: pp-pre-some-name-suf-ps
---
# the default, for release "happy-panda" and chart "wordpress"
name: happy-panda-wordpress
```
Output of this function is truncated at 54 characters, which leaves 9 additional
characters for customized overriding. Thus you can easily extend this name
in your own charts:
```yaml
{{- define "my.fullname" -}}
{{ template "common.fullname" . }}-my-stuff
{{- end -}}
```
### `common.fullname.unique`
The `common.fullname.unique` variant of fullname appends a unique seven-character
sequence to the end of the common name field.
This takes all of the same parameters as `common.fullname`
Example template:
```yaml
uniqueName: {{ template "common.fullname.unique" . }}
```
Example output:
```yaml
uniqueName: release-name-fullname-jl0dbwx
```
It is also impacted by the prefix and suffix definitions, as well as by
`.Values.fullnameOverride`
Note that the effective maximum length of this function is 63 characters, not 54.
### `common.name`
The `common.name` template generates a name suitable for the `app` label. It is used like this:
```yaml
app: {{ template "common.name" . }}
```
The following different values can influence it:
```yaml
# By default, name uses '{{ .Chart.Name }}'. This
# overrides that and uses the given string instead.
nameOverride: "some-name"
# This adds a prefix
namePrefix: "pre-"
# This appends a suffix
nameSuffix: "-suf"
# Global versions of the above
global:
namePrefix: "pp-"
nameSuffix: "-ps"
```
Example output:
```yaml
---
# with the values above
name: pp-pre-some-name-suf-ps
---
# the default, for chart "wordpress"
name: wordpress
```
Output of this function is truncated at 54 characters, which leaves 9 additional
characters for customized overriding. Thus you can easily extend this name
in your own charts:
```yaml
{{- define "my.name" -}}
{{ template "common.name" . }}-my-stuff
{{- end -}}
```
### `common.metadata`
The `common.metadata` helper generates the `metadata:` section of a Kubernetes
resource.
This takes three objects:
- .top: top context
- .fullnameOverride: override the fullname with this name
- .metadata
- .labels: key/value list of labels
- .annotations: key/value list of annotations
- .hook: name(s) of hook(s)
It generates standard labels, annotations, hooks, and a name field.
Example template:
```yaml
{{ template "common.metadata" (dict "top" . "metadata" .Values.bio) }}
---
{{ template "common.metadata" (dict "top" . "metadata" .Values.pet "fullnameOverride" .Values.pet.fullnameOverride) }}
```
Example values:
```yaml
bio:
name: example
labels:
first: matt
last: butcher
nick: technosophos
annotations:
format: bio
destination: archive
hook: pre-install
pet:
fullnameOverride: Zeus
```
Example output:
```yaml
metadata:
name: release-name-metadata
labels:
app: metadata
heritage: "Tiller"
release: "RELEASE-NAME"
chart: metadata-0.1.0
first: "matt"
last: "butcher"
nick: "technosophos"
annotations:
"destination": "archive"
"format": "bio"
"helm.sh/hook": "pre-install"
---
metadata:
name: Zeus
labels:
app: metadata
heritage: "Tiller"
release: "RELEASE-NAME"
chart: metadata-0.1.0
annotations:
```
Most of the common templates that define a resource type (e.g. `common.configmap`
or `common.job`) use this to generate the metadata, which means they inherit
the same `labels`, `annotations`, `nameOverride`, and `hook` fields.
### `common.labelize`
`common.labelize` turns a map into a set of labels.
Example template:
```yaml
{{- $map := dict "first" "1" "second" "2" "third" "3" -}}
{{- template "common.labelize" $map -}}
```
Example output:
```yaml
first: "1"
second: "2"
third: "3"
```
### `common.labels.standard`
`common.labels.standard` prints the standard set of labels.
Example usage:
```
{{ template "common.labels.standard" . }}
```
Example output:
```yaml
app: labelizer
heritage: "Tiller"
release: "RELEASE-NAME"
chart: labelizer-0.1.0
```
### `common.hook`
The `common.hook` template is a convenience for defining hooks.
Example template:
```yaml
{{ template "common.hook" "pre-install,post-install" }}
```
Example output:
```yaml
"helm.sh/hook": "pre-install,post-install"
```
### `common.chartref`
The `common.chartref` helper prints the chart name and version, escaped to be
legal in a Kubernetes label field.
Example template:
```yaml
chartref: {{ template "common.chartref" . }}
```
For the chart `foo` with version `1.2.3-beta.55+1234`, this will render:
```yaml
chartref: foo-1.2.3-beta.55_1234
```
(Note that `+` is an illegal character in label values)

@ -0,0 +1,14 @@
{{- /*
common.chartref prints a chart name and version.
It does minimal escaping for use in Kubernetes labels.
Example output:
zookeeper-1.2.3
wordpress-3.2.1_20170219
*/ -}}
{{- define "common.chartref" -}}
{{- replace "+" "_" .Chart.Version | printf "%s-%s" .Chart.Name -}}
{{- end -}}

@ -0,0 +1,9 @@
{{- define "common.configmap.tpl" -}}
apiVersion: v1
kind: ConfigMap
{{ template "common.metadata" . }}
data: {}
{{- end -}}
{{- define "common.configmap" -}}
{{- template "common.util.merge" (append . "common.configmap.tpl") -}}
{{- end -}}

@ -0,0 +1,15 @@
{{- define "common.container.tpl" -}}
name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 80
resources:
{{ toYaml .Values.resources | indent 2 }}
{{- end -}}
{{- define "common.container" -}}
{{- /* clear new line so indentation works correctly */ -}}
{{- println "" -}}
{{- include "common.util.merge" (append . "common.container.tpl") | indent 8 -}}
{{- end -}}

@ -0,0 +1,18 @@
{{- define "common.deployment.tpl" -}}
apiVersion: extensions/v1beta1
kind: Deployment
{{ template "common.metadata" . }}
spec:
template:
metadata:
labels:
app: {{ template "common.name" . }}
release: {{ .Release.Name | quote }}
spec:
containers:
-
{{ include "common.container.tpl" . | indent 8 }}
{{- end -}}
{{- define "common.deployment" -}}
{{- template "common.util.merge" (append . "common.deployment.tpl") -}}
{{- end -}}

@ -0,0 +1,31 @@
{{- define "common.envvar.value" -}}
{{- $name := index . 0 -}}
{{- $value := index . 1 -}}
name: {{ $name }}
value: {{ default "" $value | quote }}
{{- end -}}
{{- define "common.envvar.configmap" -}}
{{- $name := index . 0 -}}
{{- $configMapName := index . 1 -}}
{{- $configMapKey := index . 2 -}}
name: {{ $name }}
valueFrom:
configMapKeyRef:
name: {{ $configMapName }}
key: {{ $configMapKey }}
{{- end -}}
{{- define "common.envvar.secret" -}}
{{- $name := index . 0 -}}
{{- $secretName := index . 1 -}}
{{- $secretKey := index . 2 -}}
name: {{ $name }}
valueFrom:
secretKeyRef:
name: {{ $secretName }}
key: {{ $secretKey }}
{{- end -}}

@ -0,0 +1,39 @@
{{- /*
fullname defines a suitably unique name for a resource by combining
the release name and the chart name.
The prevailing wisdom is that names should only contain a-z, 0-9 plus dot (.) and dash (-), and should
not exceed 63 characters.
Parameters:
- .Values.fullnameOverride: Replaces the computed name with this given name
- .Values.fullnamePrefix: Prefix
- .Values.global.fullnamePrefix: Global prefix
- .Values.fullnameSuffix: Suffix
- .Values.global.fullnameSuffix: Global suffix
The applied order is: "global prefix + prefix + name + suffix + global suffix"
Usage: 'name: "{{- template "common.fullname" . -}}"'
*/ -}}
{{- define "common.fullname"}}
{{- $global := default (dict) .Values.global -}}
{{- $base := default (printf "%s-%s" .Release.Name .Chart.Name) .Values.fullnameOverride -}}
{{- $gpre := default "" $global.fullnamePrefix -}}
{{- $pre := default "" .Values.fullnamePrefix -}}
{{- $suf := default "" .Values.fullnameSuffix -}}
{{- $gsuf := default "" $global.fullnameSuffix -}}
{{- $name := print $gpre $pre $base $suf $gsuf -}}
{{- $name | lower | trunc 54 | trimSuffix "-" -}}
{{- end -}}
{{- /*
common.fullname.unique adds a random suffix to the unique name.
This takes the same parameters as common.fullname
*/ -}}
{{- define "common.fullname.unique" -}}
{{ template "common.fullname" . }}-{{ randAlphaNum 7 | lower }}
{{- end }}

@ -0,0 +1,27 @@
{{- define "common.ingress.tpl" -}}
apiVersion: extensions/v1beta1
kind: Ingress
{{ template "common.metadata" . }}
{{- if .Values.ingress.annotations }}
annotations:
{{ include "common.annote" .Values.ingress.annotations | indent 4 }}
{{- end }}
spec:
rules:
{{- range $host := .Values.ingress.hosts }}
- host: {{ $host }}
http:
paths:
- path: /
backend:
serviceName: {{ template "common.fullname" $ }}
servicePort: 80
{{- end }}
{{- if .Values.ingress.tls }}
tls:
{{ toYaml .Values.ingress.tls | indent 4 }}
{{- end -}}
{{- end -}}
{{- define "common.ingress" -}}
{{- template "common.util.merge" (append . "common.ingress.tpl") -}}
{{- end -}}

@ -0,0 +1,10 @@
{{- /*
common.metadata creates a standard metadata header.
It creates a 'metadata:' section with name and labels.
*/ -}}
{{ define "common.metadata" -}}
metadata:
name: {{ template "common.fullname" . }}
labels:
{{ include "common.labels.standard" . | indent 4 -}}
{{- end -}}

@ -0,0 +1,18 @@
{{- /*
common.hook defines a hook.
This is to be used in a 'metadata.annotations' section.
This should be called as 'template "common.metadata.hook" "post-install"'
Any valid hook may be passed in. Separate multiple hooks with a ",".
*/ -}}
{{- define "common.hook" -}}
"helm.sh/hook": {{printf "%s" . | quote}}
{{- end -}}
{{- define "common.annote" -}}
{{- range $k, $v := . }}
{{ $k | quote }}: {{ $v | quote }}
{{- end -}}
{{- end -}}

@ -0,0 +1,28 @@
{{- /*
common.labelize takes a dict or map and generates labels.
Values will be quoted. Keys will not.
Example output:
first: "Matt"
last: "Butcher"
*/ -}}
{{- define "common.labelize" -}}
{{- range $k, $v := . }}
{{ $k }}: {{ $v | quote }}
{{- end -}}
{{- end -}}
{{- /*
common.labels.standard prints the standard Helm labels.
The standard labels are frequently used in metadata.
*/ -}}
{{- define "common.labels.standard" -}}
app: {{ template "common.name" . }}
chart: {{ template "common.chartref" . }}
heritage: {{ .Release.Service | quote }}
release: {{ .Release.Name | quote }}
{{- end -}}

@ -0,0 +1,29 @@
{{- /*
name defines a template for the name of the chart. It should be used for the `app` label.
This is common practice in many Kubernetes manifests, and is not Helm-specific.
The prevailing wisdom is that names should only contain a-z, 0-9 plus dot (.) and dash (-), and should
not exceed 63 characters.
Parameters:
- .Values.nameOverride: Replaces the computed name with this given name
- .Values.namePrefix: Prefix
- .Values.global.namePrefix: Global prefix
- .Values.nameSuffix: Suffix
- .Values.global.nameSuffix: Global suffix
The applied order is: "global prefix + prefix + name + suffix + global suffix"
Usage: 'name: "{{- template "common.name" . -}}"'
*/ -}}
{{- define "common.name"}}
{{- $global := default (dict) .Values.global -}}
{{- $base := default .Chart.Name .Values.nameOverride -}}
{{- $gpre := default "" $global.namePrefix -}}
{{- $pre := default "" .Values.namePrefix -}}
{{- $suf := default "" .Values.nameSuffix -}}
{{- $gsuf := default "" $global.nameSuffix -}}
{{- $name := print $gpre $pre $base $suf $gsuf -}}
{{- $name | lower | trunc 54 | trimSuffix "-" -}}
{{- end -}}

@ -0,0 +1,24 @@
{{- define "common.persistentvolumeclaim.tpl" -}}
apiVersion: v1
kind: PersistentVolumeClaim
{{ template "common.metadata" . }}
spec:
accessModes:
- {{ .Values.persistence.accessMode | quote }}
resources:
requests:
storage: {{ .Values.persistence.size | quote }}
{{- if .Values.persistence.storageClass }}
{{- if (eq "-" .Values.persistence.storageClass) }}
storageClassName: ""
{{- else }}
storageClassName: "{{ .Values.persistence.storageClass }}"
{{- end }}
{{- end }}
{{- end -}}
{{- define "common.persistentvolumeclaim" -}}
{{- $top := first . -}}
{{- if and $top.Values.persistence.enabled (not $top.Values.persistence.existingClaim) -}}
{{- template "common.util.merge" (append . "common.persistentvolumeclaim.tpl") -}}
{{- end -}}
{{- end -}}

@ -0,0 +1,10 @@
{{- define "common.secret.tpl" -}}
apiVersion: v1
kind: Secret
{{ template "common.metadata" . }}
type: Opaque
data: {}
{{- end -}}
{{- define "common.secret" -}}
{{- template "common.util.merge" (append . "common.secret.tpl") -}}
{{- end -}}

@ -0,0 +1,17 @@
{{- define "common.service.tpl" -}}
apiVersion: v1
kind: Service
{{ template "common.metadata" . }}
spec:
type: {{ .Values.service.type }}
ports:
- name: http
port: 80
targetPort: http
selector:
app: {{ template "common.name" . }}
release: {{ .Release.Name | quote }}
{{- end -}}
{{- define "common.service" -}}
{{- template "common.util.merge" (append . "common.service.tpl") -}}
{{- end -}}

@ -0,0 +1,15 @@
{{- /*
common.util.merge will merge two YAML templates and output the result.
This takes an array of three values:
- the top context
- the template name of the overrides (destination)
- the template name of the base (source)
*/ -}}
{{- define "common.util.merge" -}}
{{- $top := first . -}}
{{- $overrides := fromYaml (include (index . 1) $top) | default (dict ) -}}
{{- $tpl := fromYaml (include (index . 2) $top) | default (dict ) -}}
{{- toYaml (merge $overrides $tpl) -}}
{{- end -}}

@ -0,0 +1,22 @@
{{- define "common.volume.configMap" -}}
{{- $name := index . 0 -}}
{{- $configMapName := index . 1 -}}
name: {{ $name }}
configMap:
name: {{ $configMapName }}
{{- end -}}
{{- define "common.volume.pvc" -}}
{{- $name := index . 0 -}}
{{- $claimName := index . 1 -}}
{{- $persistence := index . 2 -}}
name: {{ $name }}
{{- if $persistence.enabled }}
persistentVolumeClaim:
claimName: {{ $persistence.existingClaim | default $claimName }}
{{- else }}
emptyDir: {}
{{- end -}}
{{- end -}}

@ -0,0 +1,6 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: common-configmap
data:
myvalue: "Hello World"

@ -0,0 +1,4 @@
# Default values for commons.
# This is a YAML-formatted file.
# Declare name/value pairs to be passed into your templates.
# name: value

@ -0,0 +1,19 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.hosts }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "chart-with-template-lib-dep.fullname" . }})
export NODE_IP=$(kubectl get nodes -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get svc -w {{ template "chart-with-template-lib-dep.fullname" . }}'
export SERVICE_IP=$(kubectl get svc {{ template "chart-with-template-lib-dep.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods -l "app={{ template "chart-with-template-lib-dep.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:80
{{- end }}

@ -0,0 +1,32 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "chart-with-template-lib-dep.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "chart-with-template-lib-dep.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "chart-with-template-lib-dep.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}

@ -0,0 +1,51 @@
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: {{ template "chart-with-template-lib-dep.fullname" . }}
labels:
app: {{ template "chart-with-template-lib-dep.name" . }}
chart: {{ template "chart-with-template-lib-dep.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ template "chart-with-template-lib-dep.name" . }}
release: {{ .Release.Name }}
template:
metadata:
labels:
app: {{ template "chart-with-template-lib-dep.name" . }}
release: {{ .Release.Name }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 80
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
resources:
{{ toYaml .Values.resources | indent 12 }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{ toYaml . | indent 8 }}
{{- end }}

@ -0,0 +1,38 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "chart-with-template-lib-dep.fullname" . -}}
{{- $ingressPath := .Values.ingress.path -}}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
app: {{ template "chart-with-template-lib-dep.name" . }}
chart: {{ template "chart-with-template-lib-dep.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
{{- with .Values.ingress.annotations }}
annotations:
{{ toYaml . | indent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ . }}
http:
paths:
- path: {{ $ingressPath }}
backend:
serviceName: {{ $fullName }}
servicePort: http
{{- end }}
{{- end }}

@ -0,0 +1,10 @@
{{- template "common.service" (list . "chart-with-template-lib-dep.service") -}}
{{- define "chart-with-template-lib-dep.service" -}}
## Define overrides for your Service resource here, e.g.
# metadata:
# labels:
# custom: label
# spec:
# ports:
# - port: 8080
{{- end -}}

@ -0,0 +1,48 @@
# Default values for chart-with-template-lib-dep.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
repository: nginx
tag: stable
pullPolicy: IfNotPresent
nameOverride: ""
fullnameOverride: ""
service:
type: ClusterIP
port: 80
ingress:
enabled: false
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
path: /
hosts:
- chart-example.local
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
nodeSelector: {}
tolerations: []
affinity: {}

@ -128,6 +128,10 @@ provides utilities or functions for the chart builder. A library chart differs
from an application chart because it has no resource object and is therefore not
installable.
**Note:** An application chart can be used as a library chart. This is enabled by setting the
type to `library`. The chart will then be rendered as a library chart where all utilities and
functions can be leveraged. All resource objects of the chart will not be rendered.
## Chart LICENSE, README and NOTES
Charts can also contain files that describe the installation, configuration, usage and license of a

@ -51,11 +51,30 @@ func LoadFile(name string) (*chart.Chart, error) {
}
defer raw.Close()
return LoadArchive(raw)
isLibChart, err := IsArchiveLibraryChart(raw)
if err != nil {
return nil, err
}
_, _ = raw.Seek(0, 0)
return LoadArchive(raw, isLibChart)
}
// IsArchiveLibraryChart return true if it is a library chart
func IsArchiveLibraryChart(in io.Reader) (bool, error) {
var isLibChart = false
_, err := traverse(in, false, &isLibChart)
if err != nil {
return false, err
}
return isLibChart, nil
}
// LoadArchive loads from a reader containing a compressed tar archive.
func LoadArchive(in io.Reader) (*chart.Chart, error) {
func LoadArchive(in io.Reader, isLibChart bool) (*chart.Chart, error) {
return traverse(in, true, &isLibChart)
}
func traverse(in io.Reader, loadFiles bool, isLibChart *bool) (*chart.Chart, error) {
unzipped, err := gzip.NewReader(in)
if err != nil {
return &chart.Chart{}, err
@ -100,13 +119,29 @@ func LoadArchive(in io.Reader) (*chart.Chart, error) {
return &chart.Chart{}, err
}
files = append(files, &BufferedFile{Name: n, Data: b.Bytes()})
if !loadFiles && n == "Chart.yaml" {
var err error
*isLibChart, err = IsLibraryChart(b.Bytes())
if err != nil {
return nil, errors.Wrapf(err, "cannot load Chart.yaml")
}
return nil, nil
}
if IsFileValid(n, *isLibChart) {
files = append(files, &BufferedFile{Name: n, Data: b.Bytes()})
}
b.Reset()
}
if len(files) == 0 {
if loadFiles && len(files) == 0 {
return nil, errors.New("no files in chart archive")
}
if !loadFiles {
return nil, errors.New("cannot find the chart type")
}
return LoadFiles(files)
}

@ -124,8 +124,30 @@ func LoadFiles(files []*BufferedFile) (*chart.Chart, error) {
return c, errors.Errorf("error unpacking tar in %s: expected %s, got %s", c.Name(), n, file.Name)
}
// Untar the chart and add to c.Dependencies
sc, err = LoadArchive(bytes.NewBuffer(file.Data))
var isLibChart bool
isLibChart, err = IsArchiveLibraryChart(bytes.NewBuffer(file.Data))
if err == nil {
sc, err = LoadArchive(bytes.NewBuffer(file.Data), isLibChart)
}
default:
// Need to ascertain if the subchart is a library chart as will parse files
// differently from a standard application chart
var isLibChart = false
for _, f := range files {
parts := strings.SplitN(f.Name, "/", 2)
if len(parts) < 2 {
continue
}
name := parts[1]
if name == "Chart.yaml" {
isLibChart, err = IsLibraryChart(f.Data)
if err != nil {
return c, errors.Wrapf(err, "cannot load Chart.yaml for %s in %s", n, c.Name())
}
break
}
}
// We have to trim the prefix off of every file, and ignore any file
// that is in charts/, but isn't actually a chart.
buff := make([]*BufferedFile, 0, len(files))
@ -135,7 +157,12 @@ func LoadFiles(files []*BufferedFile) (*chart.Chart, error) {
continue
}
f.Name = parts[1]
buff = append(buff, f)
// If the subchart is a library chart then will only want
// to render library and value files, and not any included template files
if IsFileValid(f.Name, isLibChart) {
buff = append(buff, f)
}
}
sc, err = LoadFiles(buff)
}
@ -143,8 +170,34 @@ func LoadFiles(files []*BufferedFile) (*chart.Chart, error) {
if err != nil {
return c, errors.Wrapf(err, "error unpacking %s in %s", n, c.Name())
}
c.AddDependency(sc)
}
return c, nil
}
// IsLibraryChart return true if it is a library chart
func IsLibraryChart(data []byte) (bool, error) {
var isLibChart = false
metadata := new(chart.Metadata)
if err := yaml.Unmarshal(data, metadata); err != nil {
return false, errors.Wrapf(err, "cannot load data")
}
if strings.EqualFold(metadata.Type, "library") {
isLibChart = true
}
return isLibChart, nil
}
// IsFileValid return true if this file is valid for library or
// application chart
func IsFileValid(filename string, isLibChart bool) bool {
if isLibChart {
if strings.HasPrefix(filepath.Base(filename), "_") || !strings.HasPrefix(filepath.Dir(filename), "template") {
return true
}
return false
}
return true
}

@ -85,7 +85,7 @@ func (cache *filesystemCache) LayersToChart(layers []ocispec.Descriptor) (*chart
}
// Construct chart object and attach metadata
ch, err := loader.LoadArchive(bytes.NewBuffer(contentRaw))
ch, err := loader.LoadArchive(bytes.NewBuffer(contentRaw), false)
if err != nil {
return nil, err
}

Loading…
Cancel
Save