Provide configuration flags for Helm actions

This commit is contained in:
Hidde Beydals 2020-07-07 17:33:49 +02:00
parent 4d44b1f99b
commit bb7f3c68ea
4 changed files with 240 additions and 27 deletions

View File

@ -18,6 +18,8 @@ package v2alpha1
import (
"encoding/json"
"strings"
"time"
corev1 "k8s.io/api/core/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
@ -34,15 +36,20 @@ type HelmReleaseSpec struct {
// +required
Interval metav1.Duration `json:"interval"`
// Timeout
// +optional
ReleaseName string `json:"releaseName,omitempty"`
// +optional
TargetNamespace string `json:"targetNamespace,omitempty"`
// +optional
Timeout *metav1.Duration `json:"timeout,omitempty"`
// Wait tells the reconciler to wait with marking a Helm action as
// successful until all resources are in a ready state. When set, it will
// wait for as long as 'Timeout'.
// +optional
Wait bool `json:"wait,omitempty"`
MaxHistory *int `json:"maxHistory,omitempty"`
// +optional
Install Install `json:"install,omitempty"`
// +optional
Upgrade Upgrade `json:"upgrade,omitempty"`
@ -61,12 +68,68 @@ type HelmReleaseSpec struct {
Values apiextensionsv1.JSON `json:"values,omitempty"`
}
type Install struct {
// +optional
Timeout *metav1.Duration `json:"timeout,omitempty"`
// +optional
DisableWait bool `json:"disableWait,omitempty"`
// +optional
DisableHooks bool `json:"disableHooks,omitempty"`
// +optional
DisableOpenAPIValidation bool `json:"disableOpenAPIValidation,omitempty"`
// +optional
Replace bool `json:"replace,omitempty"`
// +optional
SkipCRDs bool `json:"skipCRDs,omitempty"`
}
func (in Install) GetTimeout(defaultTimeout metav1.Duration) metav1.Duration {
switch in.Timeout {
case nil:
return defaultTimeout
default:
return *in.Timeout
}
}
type Upgrade struct {
// +optional
Timeout *metav1.Duration `json:"timeout,omitempty"`
// +optional
MaxRetries int `json:"maxRetries,omitempty"`
// +optional
DisableWait bool `json:"disableWait,omitempty"`
// +optional
DisableHooks bool `json:"disableHooks,omitempty"`
// +optional
DisableOpenAPIValidation bool `json:"disableOpenAPIValidation,omitempty"`
// +optional
Force bool `json:"force,omitempty"`
// +optional
PreserveValues bool `json:"preserveValues,omitempty"`
// +optional
CleanupOnFail bool `json:"cleanupOnFail,omitempty"`
}
func (in Upgrade) GetTimeout(defaultTimeout metav1.Duration) metav1.Duration {
switch in.Timeout {
case nil:
return defaultTimeout
default:
return *in.Timeout
}
}
type Test struct {
@ -116,6 +179,21 @@ type Rollback struct {
// +optional
Timeout *metav1.Duration `json:"timeout,omitempty"`
// +optional
DisableHooks bool `json:"disableHooks,omitempty"`
// +optional
DisableWait bool `json:"disableWait,omitempty"`
// +optional
Recreate bool `json:"recreate,omitempty"`
// +optional
Force bool `json:"force,omitempty"`
// +optional
CleanupOnFail bool `json:"cleanupOnFail,omitempty"`
}
func (in Rollback) On() []Condition {
@ -142,8 +220,23 @@ func (in Rollback) GetTimeout(defaultTimeout metav1.Duration) metav1.Duration {
}
type Uninstall struct {
// +optional
Timeout *metav1.Duration `json:"timeout,omitempty"`
// +optional
OnCondition *[]Condition `json:"onCondition,omitempty"`
// +optional
DisableHooks bool `json:"disableHooks,omitempty"`
}
func (in Uninstall) GetTimeout(defaultTimeout metav1.Duration) metav1.Duration {
switch in.Timeout {
case nil:
return defaultTimeout
default:
return *in.Timeout
}
}
func (in Uninstall) On() []Condition {
@ -176,7 +269,7 @@ type HelmReleaseStatus struct {
// +optional
LastAttemptedRevision string `json:"lastAttemptedRevision,omitempty"`
// LastReleaseRevision is the revision of the last successfully Helm release.
// LastReleaseRevision is the revision of the last successful Helm release.
// +optional
LastReleaseRevision int `json:"lastReleaseRevision,omitempty"`
@ -274,21 +367,49 @@ type HelmRelease struct {
// GetValues unmarshals the raw values to a map[string]interface{}
// and returns the result.
func (in *HelmRelease) GetValues() map[string]interface{} {
func (in HelmRelease) GetValues() map[string]interface{} {
var values map[string]interface{}
_ = json.Unmarshal(in.Spec.Values.Raw, &values)
return values
}
func (in *HelmRelease) GetTimeout() metav1.Duration {
func (in HelmRelease) GetReleaseName() string {
if in.Spec.ReleaseName != "" {
return in.Spec.ReleaseName
}
if in.Spec.TargetNamespace != "" {
return strings.Join([]string{in.Spec.TargetNamespace, in.Name}, "-")
}
return in.Name
}
func (in HelmRelease) GetReleaseNamespace() string {
switch {
case in.Spec.TargetNamespace != "":
return in.Spec.TargetNamespace
default:
return in.Namespace
}
}
func (in HelmRelease) GetTimeout() metav1.Duration {
switch in.Spec.Timeout {
case nil:
return in.Spec.Interval
return metav1.Duration{Duration: 300 * time.Second}
default:
return *in.Spec.Timeout
}
}
func (in HelmRelease) GetMaxHistory() int {
switch in.Spec.MaxHistory {
case nil:
return 10
default:
return *in.Spec.MaxHistory
}
}
// +kubebuilder:object:root=true
// HelmReleaseList contains a list of HelmRelease

View File

@ -110,6 +110,12 @@ func (in *HelmReleaseSpec) DeepCopyInto(out *HelmReleaseSpec) {
*out = new(v1.Duration)
**out = **in
}
if in.MaxHistory != nil {
in, out := &in.MaxHistory, &out.MaxHistory
*out = new(int)
**out = **in
}
in.Install.DeepCopyInto(&out.Install)
in.Upgrade.DeepCopyInto(&out.Upgrade)
in.Test.DeepCopyInto(&out.Test)
in.Rollback.DeepCopyInto(&out.Rollback)
@ -149,6 +155,26 @@ func (in *HelmReleaseStatus) DeepCopy() *HelmReleaseStatus {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Install) DeepCopyInto(out *Install) {
*out = *in
if in.Timeout != nil {
in, out := &in.Timeout, &out.Timeout
*out = new(v1.Duration)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Install.
func (in *Install) DeepCopy() *Install {
if in == nil {
return nil
}
out := new(Install)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Rollback) DeepCopyInto(out *Rollback) {
*out = *in
@ -214,6 +240,11 @@ func (in *Test) DeepCopy() *Test {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Uninstall) DeepCopyInto(out *Uninstall) {
*out = *in
if in.Timeout != nil {
in, out := &in.Timeout, &out.Timeout
*out = new(v1.Duration)
**out = **in
}
if in.OnCondition != nil {
in, out := &in.OnCondition, &out.OnCondition
*out = new([]Condition)

View File

@ -36,13 +36,40 @@ spec:
spec:
description: HelmReleaseSpec defines the desired state of HelmRelease
properties:
install:
properties:
disableHooks:
type: boolean
disableOpenAPIValidation:
type: boolean
disableWait:
type: boolean
replace:
type: boolean
skipCRDs:
type: boolean
timeout:
type: string
type: object
interval:
description: Interval at which to reconcile the Helm release.
type: string
maxHistory:
type: integer
releaseName:
type: string
rollback:
properties:
cleanupOnFail:
type: boolean
disableHooks:
type: boolean
disableWait:
type: boolean
enable:
type: boolean
force:
type: boolean
onCondition:
items:
description: Condition contains condition information for a HelmRelease.
@ -72,6 +99,8 @@ spec:
- type
type: object
type: array
recreate:
type: boolean
timeout:
type: string
type: object
@ -93,6 +122,8 @@ spec:
- kind
- name
type: object
targetNamespace:
type: string
test:
properties:
enable:
@ -130,10 +161,11 @@ spec:
type: string
type: object
timeout:
description: Timeout
type: string
uninstall:
properties:
disableHooks:
type: boolean
onCondition:
items:
description: Condition contains condition information for a HelmRelease.
@ -163,22 +195,31 @@ spec:
- type
type: object
type: array
timeout:
type: string
type: object
upgrade:
properties:
cleanupOnFail:
type: boolean
disableHooks:
type: boolean
disableOpenAPIValidation:
type: boolean
disableWait:
type: boolean
force:
type: boolean
maxRetries:
type: integer
preserveValues:
type: boolean
timeout:
type: string
type: object
values:
description: Values holds the values for this Helm release.
x-kubernetes-preserve-unknown-fields: true
wait:
description: Wait tells the reconciler to wait with marking a Helm action
as successful until all resources are in a ready state. When set,
it will wait for as long as 'Timeout'.
type: boolean
required:
- interval
- sourceRef
@ -227,7 +268,7 @@ spec:
attempt.
type: string
lastReleaseRevision:
description: LastReleaseRevision is the revision of the last successfully
description: LastReleaseRevision is the revision of the last successful
Helm release.
type: integer
observedGeneration:

View File

@ -241,39 +241,59 @@ func (r *HelmReleaseReconciler) release(log logr.Logger, hr v2.HelmRelease, sour
func (r *HelmReleaseReconciler) install(cfg *action.Configuration, chart *chart.Chart, hr v2.HelmRelease) (*release.Release, error) {
install := action.NewInstall(cfg)
install.ReleaseName = hr.Name
install.Namespace = hr.Namespace
install.ReleaseName = hr.GetReleaseName()
install.Namespace = hr.GetReleaseNamespace()
install.Timeout = hr.Spec.Install.GetTimeout(hr.GetTimeout()).Duration
install.Wait = !hr.Spec.Install.DisableWait
install.DisableHooks = hr.Spec.Install.DisableHooks
install.DisableOpenAPIValidation = hr.Spec.Install.DisableOpenAPIValidation
install.Replace = hr.Spec.Install.Replace
install.SkipCRDs = hr.Spec.Install.SkipCRDs
return install.Run(chart, hr.GetValues())
}
func (r *HelmReleaseReconciler) upgrade(cfg *action.Configuration, chart *chart.Chart, hr v2.HelmRelease) (*release.Release, error) {
upgrade := action.NewUpgrade(cfg)
upgrade.Namespace = hr.Namespace
// TODO(hidde): make this configurable
upgrade.ResetValues = true
upgrade.Namespace = hr.GetReleaseNamespace()
upgrade.ResetValues = !hr.Spec.Upgrade.PreserveValues
upgrade.ReuseValues = hr.Spec.Upgrade.PreserveValues
upgrade.MaxHistory = hr.GetMaxHistory()
upgrade.Timeout = hr.Spec.Upgrade.GetTimeout(hr.GetTimeout()).Duration
upgrade.Wait = !hr.Spec.Upgrade.DisableWait
upgrade.DisableHooks = hr.Spec.Upgrade.DisableHooks
upgrade.Force = hr.Spec.Upgrade.Force
upgrade.CleanupOnFail = hr.Spec.Upgrade.CleanupOnFail
return upgrade.Run(hr.Name, chart, hr.GetValues())
}
func (r *HelmReleaseReconciler) test(cfg *action.Configuration, hr v2.HelmRelease) (*release.Release, error) {
test := action.NewReleaseTesting(cfg)
test.Namespace = hr.Namespace
test.Namespace = hr.GetReleaseNamespace()
test.Timeout = hr.Spec.Test.GetTimeout(hr.GetTimeout()).Duration
return test.Run(hr.Name)
return test.Run(hr.GetReleaseName())
}
func (r *HelmReleaseReconciler) rollback(cfg *action.Configuration, hr v2.HelmRelease) error {
rollback := action.NewRollback(cfg)
rollback.Timeout = hr.Spec.Rollback.GetTimeout(hr.GetTimeout()).Duration
rollback.Wait = !hr.Spec.Rollback.DisableWait
rollback.DisableHooks = hr.Spec.Rollback.DisableHooks
rollback.Force = hr.Spec.Rollback.Force
rollback.Recreate = hr.Spec.Rollback.Recreate
rollback.CleanupOnFail = hr.Spec.Rollback.CleanupOnFail
return rollback.Run(hr.Name)
return rollback.Run(hr.GetReleaseName())
}
func (r *HelmReleaseReconciler) uninstall(cfg *action.Configuration, hr v2.HelmRelease) error {
uninstall := action.NewUninstall(cfg)
_, err := uninstall.Run(hr.Name)
uninstall.Timeout = hr.Spec.Uninstall.GetTimeout(hr.GetTimeout()).Duration
uninstall.DisableHooks = hr.Spec.Uninstall.DisableHooks
_, err := uninstall.Run(hr.GetReleaseName())
return err
}
@ -365,9 +385,9 @@ func (r *HelmReleaseReconciler) download(url, tmpDir string) (string, error) {
func (r *HelmReleaseReconciler) newActionCfg(log logr.Logger, hr v2.HelmRelease) (*action.Configuration, error) {
cfg := new(action.Configuration)
// TODO(hidde): write our own init
ns := hr.GetReleaseNamespace()
err := cfg.Init(&genericclioptions.ConfigFlags{
Namespace: &hr.Namespace,
Namespace: &ns,
APIServer: &r.Config.Host,
CAFile: &r.Config.CAFile,
BearerToken: &r.Config.BearerToken,