Skip to content

Commit

Permalink
feat: introduce readiness and liveness probe feature
Browse files Browse the repository at this point in the history
Signed-off-by: RealAnna <[email protected]>

feat: added fix

Signed-off-by: RealAnna <[email protected]>

feat: added fix

Signed-off-by: RealAnna <[email protected]>

feat: added fix

Signed-off-by: RealAnna <[email protected]>

feat: added fix

Signed-off-by: RealAnna <[email protected]>

feat: introduce readiness and liveness probe feature (#3)

* feat: introduce readiness and liveness probe feature

feat: introduce readiness and liveness probe feature
Signed-off-by: realanna <[email protected]>

* Update pkg/processor/probes/probes.go

Co-authored-by: Florian Bacher <[email protected]>
Signed-off-by: realanna <[email protected]>

---------

Signed-off-by: realanna <[email protected]>
Co-authored-by: Florian Bacher <[email protected]>
  • Loading branch information
RealAnna and bacherfl committed Feb 16, 2023
1 parent 5b663ea commit 5998d13
Show file tree
Hide file tree
Showing 10 changed files with 217 additions and 31 deletions.
1 change: 1 addition & 0 deletions cmd/helmify/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ func ReadFlags() config.Config {
flag.BoolVar(&result.VeryVerbose, "vv", false, "Enable very verbose output. Same as verbose but with DEBUG. Example: helmify -vv")
flag.BoolVar(&crd, "crd-dir", false, "Enable crd install into 'crds' directory.\nWarning: CRDs placed in 'crds' directory will not be templated by Helm.\nSee https://helm.sh/docs/chart_best_practices/custom_resource_definitions/#some-caveats-and-explanations\nExample: helmify -crd-dir")
flag.BoolVar(&result.ImagePullSecrets, "image-pull-secrets", false, "Allows the user to use existing secrets as imagePullSecrets in values.yaml")
flag.BoolVar(&result.Probes, "probes", true, "Allows the user to customize liveness and readiness probes")

flag.Parse()
if h || help {
Expand Down
14 changes: 14 additions & 0 deletions examples/operator/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,17 @@ Create the name of the service account to use
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}

{{/*
Renders a value that contains template.
Usage:
{{ include "tplvalues.render" ( dict "value" .Values.path.to.the.Value "context" $) }}
*/}}
{{- define "tplvalues.render" -}}
{{- if typeIs "string" .value }}
{{- tpl .value .context }}
{{- else }}
{{- tpl (.value | toYaml) .context }}
{{- end }}
{{- end -}}

39 changes: 23 additions & 16 deletions examples/operator/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,28 +53,15 @@ spec:
key: VAR1
name: {{ include "operator.fullname" . }}-secret-vars
- name: VAR2
value: {{ .Values.controllerManager.manager.var2 }}
value: {{ .Values.controllerManager.manager.env.var2 }}
- name: VAR3_MY_ENV
value: {{ .Values.controllerManager.manager.var3MyEnv }}
value: {{ .Values.controllerManager.manager.env.var3MyEnv }}
- name: KUBERNETES_CLUSTER_DOMAIN
value: {{ .Values.kubernetesClusterDomain }}
image: {{ .Values.controllerManager.manager.image.repository }}:{{ .Values.controllerManager.manager.image.tag
| default .Chart.AppVersion }}
livenessProbe:
httpGet:
path: /healthz
port: 8081
initialDelaySeconds: 15
periodSeconds: 20
name: manager
readinessProbe:
httpGet:
path: /readyz
port: 8081
initialDelaySeconds: 5
periodSeconds: 10
resources: {{- toYaml .Values.controllerManager.manager.resources | nindent 10
}}
resources: {{- toYaml .Values.controllerManager.manager.resources | nindent 10 }}
securityContext:
allowPrivilegeEscalation: false
volumeMounts:
Expand All @@ -83,6 +70,26 @@ spec:
subPath: controller_manager_config.yaml
- mountPath: /my.ca
name: secret-volume
{{- if .Values.controllerManager.manager.livenessProbe }}
livenessProbe: {{- include "tplvalues.render" (dict "value" .Values.controllerManager.manager.livenessProbe "context" $) | nindent 12 }}
{{- else }}
livenessProbe:
httpGet:
path: /healthz
port: 8081
initialDelaySeconds: 15
periodSeconds: 20
{{- end }}
{{- if .Values.controllerManager.manager.readinessProbe }}
readinessProbe: {{- include "tplvalues.render" (dict "value" .Values.controllerManager.manager.readinessProbe "context" $) | nindent 12 }}
{{- else }}
readinessProbe:
httpGet:
path: /readyz
port: 8081
initialDelaySeconds: 5
periodSeconds: 10
{{- end }}
imagePullSecrets:
- name: {{ include "operator.fullname" . }}-secret-registry-credentials
securityContext:
Expand Down
12 changes: 12 additions & 0 deletions examples/operator/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@ controllerManager:
image:
repository: controller
tag: latest
livenessProbe:
httpGet:
path: /healthz
port: 8081
initialDelaySeconds: 15
periodSeconds: 20
readinessProbe:
httpGet:
path: /readyz
port: 8081
initialDelaySeconds: 5
periodSeconds: 10
resources:
limits:
cpu: 100m
Expand Down
2 changes: 2 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ type Config struct {
Crd bool
// ImagePullSecrets flag
ImagePullSecrets bool
// Probes flag if true the probes will be parametrised
Probes bool
}

func (c *Config) Validate() error {
Expand Down
14 changes: 14 additions & 0 deletions pkg/helm/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,20 @@ Create the name of the service account to use
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
{{/*
Renders a value that contains template.
Usage:
{{ include "tplvalues.render" ( dict "value" .Values.path.to.the.Value "context" $) }}
*/}}
{{- define "tplvalues.render" -}}
{{- if typeIs "string" .value }}
{{- tpl .value .context }}
{{- else }}
{{- tpl (.value | toYaml) .context }}
{{- end }}
{{- end -}}
`

const defaultChartfile = `apiVersion: v2
Expand Down
4 changes: 3 additions & 1 deletion pkg/helmify/model.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package helmify

import (
"github.com/arttor/helmify/pkg/config"
"io"

"github.com/arttor/helmify/pkg/config"

"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

Expand Down Expand Up @@ -43,6 +44,7 @@ type AppMetadata interface {
TemplatedName(objName string) string
// TemplatedString converts a string to templated string with chart name.
TemplatedString(str string) string
TemplatedValue(container string, str string) string
// TrimName trims common prefix from object name if exists.
// We trim common prefix because helm already using release for this purpose.
TrimName(objName string) string
Expand Down
10 changes: 9 additions & 1 deletion pkg/metadata/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ package metadata

import (
"fmt"
"github.com/arttor/helmify/pkg/config"
"strings"

"github.com/arttor/helmify/pkg/config"

"github.com/arttor/helmify/pkg/helmify"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
)

const valuesTempl = `{{- include "tplvalues.render" (dict "value" .Values.%s.%s.%s "context" $)}}`

const nameTeml = `{{ include "%s.fullname" . }}-%s`

var nsGVK = schema.GroupVersionKind{
Expand Down Expand Up @@ -96,6 +99,11 @@ func (a *Service) TemplatedString(str string) string {
return fmt.Sprintf(nameTeml, a.conf.ChartName, name)
}

func (a *Service) TemplatedValue(container string, str string) string {
name := a.TrimName(str)
return fmt.Sprintf(valuesTempl, a.conf.ChartName, container, name)
}

func extractAppNamespace(obj *unstructured.Unstructured) string {
if obj.GroupVersionKind() == nsGVK {
return obj.GetName()
Expand Down
53 changes: 40 additions & 13 deletions pkg/processor/deployment/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import (
"text/template"

"github.com/arttor/helmify/pkg/cluster"
"github.com/arttor/helmify/pkg/helmify"
"github.com/arttor/helmify/pkg/processor"
"github.com/arttor/helmify/pkg/processor/imagePullSecrets"

"github.com/arttor/helmify/pkg/helmify"
"github.com/arttor/helmify/pkg/processor/probes"
yamlformat "github.com/arttor/helmify/pkg/yaml"
"github.com/iancoleman/strcase"
"github.com/pkg/errors"
Expand Down Expand Up @@ -47,7 +47,7 @@ const selectorTempl = `%[1]s
{{- include "%[2]s.selectorLabels" . | nindent 6 }}
%[3]s`

const envValue = "{{ .Values.%[1]s.%[2]s.%[3]s }}"
const envValue = "{{ .Values.%[1]s.%[2]s.%[3]s.%[4]s }}"

// New creates processor for k8s Deployment resource.
func New() helmify.Processor {
Expand Down Expand Up @@ -130,28 +130,32 @@ func (d deployment) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstr
depl.Spec.Template.Spec.Volumes[i].PersistentVolumeClaim.ClaimName = tempPVCName
}

// remove from spec things that will be processed separately
cleanSpec := cleanSpec(*depl.Spec.Template.Spec.DeepCopy())

// replace container resources with template to values.
specMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&depl.Spec.Template.Spec)
specMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&cleanSpec)
if err != nil {
return true, nil, err
}
containers, _, err := unstructured.NestedSlice(specMap, "containers")
if err != nil {
return true, nil, err
}

for i := range containers {
containerName := strcase.ToLowerCamel((containers[i].(map[string]interface{})["name"]).(string))
res, exists, err := unstructured.NestedMap(values, nameCamel, containerName, "resources")
if err != nil {
return true, nil, err
}
if !exists || len(res) == 0 {
continue
}
err = unstructured.SetNestedField(containers[i].(map[string]interface{}), fmt.Sprintf(`{{- toYaml .Values.%s.%s.resources | nindent 10 }}`, nameCamel, containerName), "resources")
if err != nil {
return true, nil, err
if exists && len(res) > 0 {
err = unstructured.SetNestedField(containers[i].(map[string]interface{}), fmt.Sprintf(`{{- toYaml .Values.%s.%s.resources | nindent 10 }}`, nameCamel, containerName), "resources")
if err != nil {
return true, nil, err
}
}

}
err = unstructured.SetNestedSlice(specMap, containers, "containers")
if err != nil {
Expand All @@ -162,12 +166,21 @@ func (d deployment) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstr
imagePullSecrets.ProcessSpecMap(specMap, &values)
}

if appMeta.Config().Probes {
err = probes.ProcessSpecMap(nameCamel, specMap, &values, depl.Spec.Template.Spec)
if err != nil {
return true, nil, err
}
}

spec, err := yamlformat.Marshal(specMap, 6)
if err != nil {
return true, nil, err
}
spec = strings.ReplaceAll(spec, "'", "")

spec = strings.ReplaceAll(spec, "'", "")
spec = strings.ReplaceAll(spec, "|\n ", "")
spec = strings.ReplaceAll(spec, "|-\n ", "")
return true, &result{
values: values,
data: struct {
Expand All @@ -188,6 +201,15 @@ func (d deployment) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstr
}, nil
}

func cleanSpec(spec corev1.PodSpec) corev1.PodSpec {

for i := 0; i < len(spec.Containers); i++ {
spec.Containers[i].LivenessProbe = nil
spec.Containers[i].ReadinessProbe = nil
}
return spec
}

func processReplicas(name string, deployment *appsv1.Deployment, values *helmify.Values) (string, error) {
if deployment.Spec.Replicas == nil {
return "", nil
Expand All @@ -208,6 +230,7 @@ func processPodSpec(name string, appMeta helmify.AppMetadata, pod *corev1.PodSpe
values := helmify.Values{}
for i, c := range pod.Containers {
processed, err := processPodContainer(name, appMeta, c, &values)

if err != nil {
return nil, err
}
Expand Down Expand Up @@ -260,13 +283,16 @@ func processPodContainer(name string, appMeta helmify.AppMetadata, c corev1.Cont
if e.ConfigMapRef != nil {
e.ConfigMapRef.Name = appMeta.TemplatedName(e.ConfigMapRef.Name)
}

}

c.Env = append(c.Env, corev1.EnvVar{
Name: cluster.DomainEnv,
Value: fmt.Sprintf("{{ .Values.%s }}", cluster.DomainKey),
})
for k, v := range c.Resources.Requests {
err = unstructured.SetNestedField(*values, v.ToUnstructured(), name, containerName, "resources", "requests", k.String())

if err != nil {
return c, errors.Wrap(err, "unable to set container resources value")
}
Expand All @@ -277,7 +303,8 @@ func processPodContainer(name string, appMeta helmify.AppMetadata, c corev1.Cont
return c, errors.Wrap(err, "unable to set container resources value")
}
}
return c, nil

return c, err
}

func processEnv(name string, appMeta helmify.AppMetadata, c corev1.Container, values *helmify.Values) (corev1.Container, error) {
Expand All @@ -293,7 +320,7 @@ func processEnv(name string, appMeta helmify.AppMetadata, c corev1.Container, va
if err != nil {
return c, errors.Wrap(err, "unable to set deployment value field")
}
c.Env[i].Value = fmt.Sprintf(envValue, name, containerName, strcase.ToLowerCamel(strings.ToLower(c.Env[i].Name)))
c.Env[i].Value = fmt.Sprintf(envValue, name, containerName, "env", strcase.ToLowerCamel(strings.ToLower(c.Env[i].Name)))
}
}
return c, nil
Expand Down
Loading

0 comments on commit 5998d13

Please sign in to comment.