add lifecycle

This commit is contained in:
Stavros kois
2023-02-10 16:04:20 +02:00
parent d81dd75764
commit 33f2fccf57
7 changed files with 392 additions and 16 deletions
@@ -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>
+36 -13
View File
@@ -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
+12 -2
View File
@@ -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: ""