mirror of
https://github.com/truenas/charts.git
synced 2024-04-21 15:21:45 +00:00
add lifecycle
This commit is contained in:
@@ -0,0 +1,242 @@
|
||||
suite: container lifecycle test
|
||||
templates:
|
||||
- common.yaml
|
||||
tests:
|
||||
- it: should pass with lifecycle
|
||||
set:
|
||||
image: &image
|
||||
repository: nginx
|
||||
tag: 1.19.0
|
||||
pullPolicy: IfNotPresent
|
||||
workload:
|
||||
workload-name:
|
||||
enabled: true
|
||||
primary: true
|
||||
type: Deployment
|
||||
podSpec:
|
||||
containers:
|
||||
container-name1:
|
||||
enabled: true
|
||||
primary: true
|
||||
imageSelector: image
|
||||
lifecycle:
|
||||
postStart:
|
||||
type: exec
|
||||
command:
|
||||
- echo
|
||||
- hello
|
||||
preStop:
|
||||
type: http
|
||||
port: 80
|
||||
asserts:
|
||||
- documentIndex: &deploymentDoc 0
|
||||
isKind:
|
||||
of: Deployment
|
||||
- documentIndex: *deploymentDoc
|
||||
isAPIVersion:
|
||||
of: apps/v1
|
||||
- documentIndex: *deploymentDoc
|
||||
isSubset:
|
||||
path: spec.template.spec.containers[0]
|
||||
content:
|
||||
lifecycle:
|
||||
postStart:
|
||||
exec:
|
||||
command:
|
||||
- echo
|
||||
- hello
|
||||
preStop:
|
||||
httpGet:
|
||||
port: 80
|
||||
path: /
|
||||
scheme: HTTP
|
||||
|
||||
- it: should pass with lifecycle
|
||||
set:
|
||||
image: *image
|
||||
some_command: ./some_command
|
||||
some_port: 80
|
||||
some_host: some_host
|
||||
some_scheme: HTTPS
|
||||
some_path: /api/v1
|
||||
some_value: some_value
|
||||
workload:
|
||||
workload-name:
|
||||
enabled: true
|
||||
primary: true
|
||||
type: Deployment
|
||||
podSpec:
|
||||
containers:
|
||||
container-name1:
|
||||
enabled: true
|
||||
primary: true
|
||||
imageSelector: image
|
||||
lifecycle:
|
||||
postStart:
|
||||
type: http
|
||||
port: "{{ .Values.some_port }}"
|
||||
host: "{{ .Values.some_host }}"
|
||||
scheme: "{{ .Values.some_scheme }}"
|
||||
path: "{{ .Values.some_path }}"
|
||||
httpHeaders:
|
||||
key: "{{ .Values.some_value }}"
|
||||
preStop:
|
||||
type: exec
|
||||
command: "{{ .Values.some_command }}"
|
||||
asserts:
|
||||
- documentIndex: &deploymentDoc 0
|
||||
isKind:
|
||||
of: Deployment
|
||||
- documentIndex: *deploymentDoc
|
||||
isAPIVersion:
|
||||
of: apps/v1
|
||||
- documentIndex: *deploymentDoc
|
||||
isSubset:
|
||||
path: spec.template.spec.containers[0]
|
||||
content:
|
||||
lifecycle:
|
||||
postStart:
|
||||
httpGet:
|
||||
port: 80
|
||||
path: /api/v1
|
||||
scheme: HTTPS
|
||||
host: some_host
|
||||
httpHeaders:
|
||||
- name: key
|
||||
value: some_value
|
||||
preStop:
|
||||
exec:
|
||||
command:
|
||||
- ./some_command
|
||||
|
||||
# Failures
|
||||
- it: should fail with invalid lifecycle hook
|
||||
set:
|
||||
image: *image
|
||||
workload:
|
||||
workload-name:
|
||||
enabled: true
|
||||
primary: true
|
||||
type: Deployment
|
||||
podSpec:
|
||||
containers:
|
||||
container-name1:
|
||||
enabled: true
|
||||
primary: true
|
||||
imageSelector: image
|
||||
lifecycle:
|
||||
invalid: {}
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: Container - Expected <lifecycle> <hook> to be one of [preStop, postStart], but got [invalid]
|
||||
|
||||
- it: should fail with empty lifecycle type
|
||||
set:
|
||||
image: *image
|
||||
workload:
|
||||
workload-name:
|
||||
enabled: true
|
||||
primary: true
|
||||
type: Deployment
|
||||
podSpec:
|
||||
containers:
|
||||
container-name1:
|
||||
enabled: true
|
||||
primary: true
|
||||
imageSelector: image
|
||||
lifecycle:
|
||||
preStop:
|
||||
command: []
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: Container - Expected non-empty <lifecycle> <type>
|
||||
|
||||
- it: should fail with invalid lifecycle type
|
||||
set:
|
||||
image: *image
|
||||
workload:
|
||||
workload-name:
|
||||
enabled: true
|
||||
primary: true
|
||||
type: Deployment
|
||||
podSpec:
|
||||
containers:
|
||||
container-name1:
|
||||
enabled: true
|
||||
primary: true
|
||||
imageSelector: image
|
||||
lifecycle:
|
||||
preStop:
|
||||
type: invalid
|
||||
command: []
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: Container - Expected <lifecycle> <type> to be one of [exec, http], but got [invalid]
|
||||
|
||||
- it: should fail with empty command on exec lifecycle type
|
||||
set:
|
||||
image: *image
|
||||
workload:
|
||||
workload-name:
|
||||
enabled: true
|
||||
primary: true
|
||||
type: Deployment
|
||||
podSpec:
|
||||
containers:
|
||||
container-name1:
|
||||
enabled: true
|
||||
primary: true
|
||||
imageSelector: image
|
||||
lifecycle:
|
||||
preStop:
|
||||
type: exec
|
||||
command: []
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: Container - Expected non-empty <lifecycle> <command> on [exec] type
|
||||
|
||||
- it: should fail with empty port on http lifecycle type
|
||||
set:
|
||||
image: *image
|
||||
workload:
|
||||
workload-name:
|
||||
enabled: true
|
||||
primary: true
|
||||
type: Deployment
|
||||
podSpec:
|
||||
containers:
|
||||
container-name1:
|
||||
enabled: true
|
||||
primary: true
|
||||
imageSelector: image
|
||||
lifecycle:
|
||||
preStop:
|
||||
type: http
|
||||
port: ""
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: Container - Expected non-empty <lifecycle> <port> on [http] type
|
||||
|
||||
- it: should fail with empty value on httpHeaders on http lifecycle type
|
||||
set:
|
||||
image: *image
|
||||
workload:
|
||||
workload-name:
|
||||
enabled: true
|
||||
primary: true
|
||||
type: Deployment
|
||||
podSpec:
|
||||
containers:
|
||||
container-name1:
|
||||
enabled: true
|
||||
primary: true
|
||||
imageSelector: image
|
||||
lifecycle:
|
||||
preStop:
|
||||
type: http
|
||||
port: 80
|
||||
httpHeaders:
|
||||
key: ""
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: Container - Expected non-empty <value> on <httpHeaders>
|
||||
@@ -2,19 +2,29 @@
|
||||
|
||||
Assume every key bellow has a prefix of `workload.[workload-name].podSpec`.
|
||||
|
||||
| Key | Type | Required | Helm Template | Default | Description |
|
||||
| :---------------------------------------------------- | :-----------: | :------: | :-----------: | :-----: | :--------------------------------------------------------------------------------------------- |
|
||||
| containers.[container-name] | `dict` | ✅ | ❌ | `{}` | Define the container as dict |
|
||||
| containers.[container-name].enabled | `boolean` | ✅ | ❌ | `false` | Enables or Disables the container |
|
||||
| containers.[container-name].primary | `boolean` | ✅ | ❌ | `false` | Sets the container as primary |
|
||||
| containers.[container-name].stdin | `boolean` | ❌ | ❌ | `false` | whether to enable stdin or not |
|
||||
| containers.[container-name].tty | `boolean` | ❌ | ❌ | `false` | whether to enable tty or not |
|
||||
| containers.[container-name].command | `list/string` | ❌ | ✅ | `[]` | Define command(s). If it's single, can be defined as string |
|
||||
| containers.[container-name].args | `list/string` | ❌ | ✅ | `[]` | Define arg(s). If it's single, can be defined as string |
|
||||
| containers.[container-name].extraArgs | `list/string` | ❌ | ✅ | `[]` | Define extraArg(s). Those are appended after the `args`. Useful for user defined args from GUI |
|
||||
| containers.[container-name].termination | `dict` | ❌ | ❌ | `{}` | Define termination for the container |
|
||||
| containers.[container-name].termination.messagePath | `string` | ❌ | ✅ | `""` | Define termination message path for the container |
|
||||
| containers.[container-name].termination.messagePolicy | `string` | ❌ | ✅ | `""` | Define termination message policy for the container |
|
||||
| Key | Type | Required | Helm Template | Default | Description |
|
||||
| :------------------------------------------------------- | :-----------: | :---------------: | :----------------: | :-----: | :--------------------------------------------------------------------------------------------- | --- |
|
||||
| containers.[container-name] | `dict` | ✅ | ❌ | `{}` | Define the container as dict |
|
||||
| containers.[container-name].enabled | `boolean` | ✅ | ❌ | `false` | Enables or Disables the container |
|
||||
| containers.[container-name].primary | `boolean` | ✅ | ❌ | `false` | Sets the container as primary |
|
||||
| containers.[container-name].stdin | `boolean` | ❌ | ❌ | `false` | whether to enable stdin or not |
|
||||
| containers.[container-name].tty | `boolean` | ❌ | ❌ | `false` | whether to enable tty or not |
|
||||
| containers.[container-name].command | `list/string` | ❌ | ✅ | `[]` | Define command(s). If it's single, can be defined as string |
|
||||
| containers.[container-name].args | `list/string` | ❌ | ✅ | `[]` | Define arg(s). If it's single, can be defined as string |
|
||||
| containers.[container-name].extraArgs | `list/string` | ❌ | ✅ | `[]` | Define extraArg(s). Those are appended after the `args`. Useful for user defined args from GUI |
|
||||
| containers.[container-name].termination | `dict` | ❌ | ❌ | `{}` | Define termination for the container |
|
||||
| containers.[container-name].termination.messagePath | `string` | ❌ | ✅ | `""` | Define termination message path for the container |
|
||||
| containers.[container-name].termination.messagePolicy | `string` | ❌ | ✅ | `""` | Define termination message policy for the container |
|
||||
| containers.[container-name].lifecycle | `dict` | ❌ | ❌ | `{}` | Define lifecycle for the container |
|
||||
| containers.[container-name].lifecycle.preStop | `dict` | ❌ | ❌ | `{}` | Define preStop lifecycle |
|
||||
| containers.[container-name].lifecycle.postStart | `dict` | ❌ | ❌ | `{}` | Define preStop lifecycle |
|
||||
| containers.[container-name].lifecycle.[hook].type | `string` | ❌ | ❌ | `""` | Define hook type (exec, http) |
|
||||
| containers.[container-name].lifecycle.[hook].command | `list/string` | ✅ (On exec type) | ✅ | `""` | Define command(s). If it's single, can be defined as string (Only when exec type is used) | |
|
||||
| containers.[container-name].lifecycle.[hook].port | `int` | ✅ (On http type) | ✅ | `""` | Define the port, (Only when http type is used) | |
|
||||
| containers.[container-name].lifecycle.[hook].host | `string` | ❌ | ✅ | | Define the host, k8s defaults to POD IP (Only when http type is used) | |
|
||||
| containers.[container-name].lifecycle.[hook].path | `string` | ❌ | ✅ | `/` | Define the path (Only when http type is used) | |
|
||||
| containers.[container-name].lifecycle.[hook].scheme | `string` | ❌ | ✅ | `HTTP` | Define the scheme (Only when http type is used) | |
|
||||
| containers.[container-name].lifecycle.[hook].httpHeaders | `dict` | ❌ | ✅ (On value only) | `{}` | Define the httpHeaders in key-value pairs (Only when http type is used) | |
|
||||
|
||||
---
|
||||
|
||||
@@ -57,4 +67,17 @@ workload:
|
||||
termination:
|
||||
messagePath: /dev/termination-log
|
||||
messagePolicy: File
|
||||
lifecycle:
|
||||
preStop:
|
||||
type: exec
|
||||
command:
|
||||
- command
|
||||
postStart:
|
||||
type: http
|
||||
port: 8080
|
||||
host: localhost
|
||||
path: /path
|
||||
scheme: HTTP
|
||||
httpHeaders:
|
||||
key: value
|
||||
```
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
{{/* Returns lifecycle */}}
|
||||
{{/* Call this template:
|
||||
{{ include "ix.v1.common.lib.container.lifecycle" (dict "rootCtx" $ "objectData" $objectData) }}
|
||||
rootCtx: The root context of the template. It is used to access the global context.
|
||||
objectData: The object data to be used to render the container.
|
||||
*/}}
|
||||
{{- define "ix.v1.common.lib.container.lifecycle" -}}
|
||||
{{- $rootCtx := .rootCtx -}}
|
||||
{{- $objectData := .objectData -}}
|
||||
|
||||
{{- $hooks := (list "preStop" "postStart") -}}
|
||||
{{- $types := (list "exec" "http") -}}
|
||||
{{- with $objectData.lifecycle -}}
|
||||
{{- range $hook, $hookValues := . -}}
|
||||
{{- if not (mustHas $hook $hooks) -}}
|
||||
{{- fail (printf "Container - Expected <lifecycle> <hook> to be one of [%s], but got [%s]" (join ", " $hooks) $hook) -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- if not $hookValues.type -}}
|
||||
{{- fail "Container - Expected non-empty <lifecycle> <type>" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- if not (mustHas $hookValues.type $types) -}}
|
||||
{{- fail (printf "Container - Expected <lifecycle> <type> to be one of [%s], but got [%s]" (join ", " $types) $hookValues.type) -}}
|
||||
{{- end }}
|
||||
{{ $hook }}:
|
||||
{{- if eq $hookValues.type "exec" -}}
|
||||
{{- if not $hookValues.command -}}
|
||||
{{- fail "Container - Expected non-empty <lifecycle> <command> on [exec] type" -}}
|
||||
{{- end }}
|
||||
{{- include "ix.v1.common.lib.container.actions.exec" (dict "rootCtx" $rootCtx "objectData" $hookValues) | trim | nindent 2 }}
|
||||
{{- else if eq $hookValues.type "http" }}
|
||||
{{- if not $hookValues.port -}}
|
||||
{{- fail "Container - Expected non-empty <lifecycle> <port> on [http] type" -}}
|
||||
{{- end }}
|
||||
{{- include "ix.v1.common.lib.container.actions.httpGet" (dict "rootCtx" $rootCtx "objectData" $hookValues) | trim | nindent 2 }}
|
||||
{{- end -}}
|
||||
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
|
||||
{{- end -}}
|
||||
@@ -0,0 +1,13 @@
|
||||
{{/* Returns exec action */}}
|
||||
{{/* Call this template:
|
||||
{{ include "ix.v1.common.lib.container.actions.exec" (dict "rootCtx" $ "objectData" $objectData) }}
|
||||
rootCtx: The root context of the template. It is used to access the global context.
|
||||
objectData: The object data to be used to render the container.
|
||||
*/}}
|
||||
{{- define "ix.v1.common.lib.container.actions.exec" -}}
|
||||
{{- $rootCtx := .rootCtx -}}
|
||||
{{- $objectData := .objectData }}
|
||||
exec:
|
||||
command:
|
||||
{{- include "ix.v1.common.lib.container.command" (dict "rootCtx" $rootCtx "objectData" $objectData) | trim | nindent 4}}
|
||||
{{- end -}}
|
||||
@@ -0,0 +1,42 @@
|
||||
{{/* Returns httpGet action */}}
|
||||
{{/* Call this template:
|
||||
{{ include "ix.v1.common.lib.container.actions.httpGet" (dict "rootCtx" $ "objectData" $objectData) }}
|
||||
rootCtx: The root context of the template. It is used to access the global context.
|
||||
objectData: The object data to be used to render the container.
|
||||
*/}}
|
||||
{{- define "ix.v1.common.lib.container.actions.httpGet" -}}
|
||||
{{- $rootCtx := .rootCtx -}}
|
||||
{{- $objectData := .objectData -}}
|
||||
|
||||
{{- $port := $objectData.port -}}
|
||||
{{- $path := "/" -}}
|
||||
{{- $scheme := "HTTP" -}}
|
||||
|
||||
{{- if kindIs "string" $port -}}
|
||||
{{- $port = tpl $port $rootCtx -}}
|
||||
{{- end -}}
|
||||
{{- with $objectData.path -}}
|
||||
{{- $path = tpl . $rootCtx -}}
|
||||
{{- end -}}
|
||||
{{- with $objectData.scheme -}}
|
||||
{{- $scheme = tpl . $rootCtx -}}
|
||||
{{- end }}
|
||||
httpGet:
|
||||
{{- with $objectData.host }}
|
||||
host: {{ tpl . $rootCtx }}
|
||||
{{- end }}
|
||||
port: {{ $port }}
|
||||
path: {{ $path }}
|
||||
scheme: {{ $scheme }}
|
||||
{{- with $objectData.httpHeaders }}
|
||||
httpHeaders:
|
||||
{{- range $name, $value := . }}
|
||||
{{- if not $value -}}
|
||||
{{- fail "Container - Expected non-empty <value> on <httpHeaders>" -}}
|
||||
{{- end }}
|
||||
- name: {{ $name }}
|
||||
value: {{ tpl $value $rootCtx }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- end -}}
|
||||
@@ -29,9 +29,12 @@ objectData: The object data to be used to render the Pod.
|
||||
{{- with $termination.messagePolicy }}
|
||||
terminationMessagePolicy: {{ . }}
|
||||
{{- end -}}
|
||||
{{- with (include "ix.v1.common.lib.container.lifecycle" (dict "rootCtx" $rootCtx "objectData" $objectData) | trim) }}
|
||||
lifecycle:
|
||||
{{- . | nindent 4 }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{/* TODO:
|
||||
lifecycle
|
||||
securityContext
|
||||
resources
|
||||
probes
|
||||
|
||||
@@ -476,9 +476,19 @@ workload:
|
||||
- ALL
|
||||
lifecycle:
|
||||
postStart:
|
||||
command: []
|
||||
type: http
|
||||
port: 123
|
||||
path: /asdf
|
||||
httpHeaders:
|
||||
key: value
|
||||
key2: value2
|
||||
host: asdf
|
||||
scheme: HTTPS
|
||||
preStop:
|
||||
command: []
|
||||
type: exec
|
||||
command:
|
||||
- asdf
|
||||
- asdf
|
||||
termination:
|
||||
messagePath: ""
|
||||
messagePolicy: ""
|
||||
|
||||
Reference in New Issue
Block a user