Support Helm uninstall action

This commit is contained in:
Hidde Beydals 2020-07-03 09:24:55 +02:00
parent ff0e54db6a
commit fd715d6eb6
5 changed files with 117 additions and 2 deletions

View File

@ -62,6 +62,9 @@ const (
// RollbackCondition represents the fact that the HelmRelease has been successfully rolled back.
RollbackCondition string = "Rollback"
// UninstallCondition represents the fact that the HelmRelease has been successfully uninstalled.
UninstallCondition string = "Uninstall"
)
const (
@ -89,12 +92,18 @@ const (
// TestFailedReason represents the fact that the Helm test for the release failed.
TestFailedReason string = "TestFailed"
// RollbackSucceededReason represents the fact that the Helm test for the release failed.
// RollbackSucceededReason represents the fact that the Helm rollback for the release succeeded.
RollbackSucceededReason string = "RollbackSucceeded"
// RollbackFailedReason represents the fact that the Helm test for the release failed.
RollbackFailedReason string = "RollbackFailed"
// UninstallSucceededReason represents the fact that the Helm uninstall for the release succeeded.
UninstallSucceededReason string = "UninstallSucceeded"
// UninstallFailedReason represents the fact that the Helm uninstall for the release failed.
UninstallFailedReason string = "UninstallFailed"
// ArtifactFailedReason represents the fact that the artifact download for the release failed.
ArtifactFailedReason string = "ArtifactFailed"

View File

@ -55,6 +55,9 @@ type HelmReleaseSpec struct {
// +optional
Rollback Rollback `json:"rollback,omitempty"`
// +optional
Uninstall Uninstall `json:"uninstall,omitempty"`
// Values holds the values for this Helm release.
// +optional
Values apiextensionsv1.JSON `json:"values,omitempty"`
@ -132,6 +135,25 @@ func (in Rollback) GetTimeout(defaultTimeout metav1.Duration) metav1.Duration {
}
}
type Uninstall struct {
// +optional
OnCondition *[]Condition `json:"onCondition,omitempty"`
}
func (in Uninstall) GetOnConditions() []Condition {
switch in.OnCondition {
case nil:
return []Condition{
{
Type: InstallCondition,
Status: corev1.ConditionFalse,
},
}
default:
return *in.OnCondition
}
}
// HelmReleaseStatus defines the observed state of HelmRelease
type HelmReleaseStatus struct {
// +optional

View File

@ -117,6 +117,7 @@ func (in *HelmReleaseSpec) DeepCopyInto(out *HelmReleaseSpec) {
}
in.Test.DeepCopyInto(&out.Test)
in.Rollback.DeepCopyInto(&out.Rollback)
in.Uninstall.DeepCopyInto(&out.Uninstall)
in.Values.DeepCopyInto(&out.Values)
}
@ -213,3 +214,29 @@ func (in *Test) DeepCopy() *Test {
in.DeepCopyInto(out)
return out
}
// 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.OnCondition != nil {
in, out := &in.OnCondition, &out.OnCondition
*out = new([]Condition)
if **in != nil {
in, out := *in, *out
*out = make([]Condition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Uninstall.
func (in *Uninstall) DeepCopy() *Uninstall {
if in == nil {
return nil
}
out := new(Uninstall)
in.DeepCopyInto(out)
return out
}

View File

@ -137,6 +137,38 @@ spec:
timeout:
description: Timeout
type: string
uninstall:
properties:
onCondition:
items:
description: Condition contains condition information for a HelmRelease.
properties:
lastTransitionTime:
description: LastTransitionTime is the timestamp corresponding
to the last status change of this condition.
format: date-time
type: string
message:
description: Message is a human readable description of the
details of the last transition, complementing reason.
type: string
reason:
description: Reason is a brief machine readable explanation
for the condition's last transition.
type: string
status:
description: Status of the condition, one of ('True', 'False',
'Unknown').
type: string
type:
description: Type of the condition, currently ('Ready').
type: string
required:
- status
- type
type: object
type: array
type: object
values:
description: Values holds the values for this Helm release.
x-kubernetes-preserve-unknown-fields: true

View File

@ -187,7 +187,6 @@ func (r *HelmReleaseReconciler) release(log logr.Logger, hr v2.HelmRelease, sour
if rel, err = r.install(cfg, loadedChart, hr); err != nil {
success = false
v2.SetHelmReleaseCondition(&hr, v2.InstallCondition, corev1.ConditionFalse, v2.InstallFailedReason, err.Error())
// TODO(hidde): conditional uninstall?
} else {
v2.SetHelmReleaseCondition(&hr, v2.InstallCondition, corev1.ConditionTrue, v2.InstallSucceededReason, "Helm installation succeeded")
}
@ -219,6 +218,15 @@ func (r *HelmReleaseReconciler) release(log logr.Logger, hr v2.HelmRelease, sour
}
}
// Run uninstall
if r.shouldUninstall(&hr) {
if err = r.uninstall(cfg, hr); err != nil {
v2.SetHelmReleaseCondition(&hr, v2.UninstallCondition, corev1.ConditionFalse, v2.UninstallFailedReason, err.Error())
} else {
v2.SetHelmReleaseCondition(&hr, v2.UninstallCondition, corev1.ConditionTrue, v2.UninstallSucceededReason, "Helm uninstall succeeded")
}
}
if !success {
return v2.HelmReleaseNotReady(hr, v2.ReconciliationFailedReason, "release reconciliation failed"), err
}
@ -257,6 +265,12 @@ func (r *HelmReleaseReconciler) rollback(cfg *action.Configuration, hr v2.HelmRe
return rollback.Run(hr.Name)
}
func (r *HelmReleaseReconciler) uninstall(cfg *action.Configuration, hr v2.HelmRelease) error {
uninstall := action.NewUninstall(cfg)
_, err := uninstall.Run(hr.Name)
return err
}
func (r *HelmReleaseReconciler) shouldUpgrade(hr *v2.HelmRelease, source sourcev1.Source, rel *release.Release) bool {
switch {
case hr.Status.LatestAppliedRevision != source.GetArtifact().Revision:
@ -298,6 +312,17 @@ func (r *HelmReleaseReconciler) shouldRollback(hr *v2.HelmRelease) bool {
return false
}
func (r *HelmReleaseReconciler) shouldUninstall(hr *v2.HelmRelease) bool {
for _, c := range hr.Spec.Uninstall.GetOnConditions() {
for i := len(hr.Status.Conditions) - 1; i >= 0; i-- {
if hr.Status.Conditions[i].Type == c.Type && hr.Status.Conditions[i].Status == c.Status {
return true
}
}
}
return false
}
func (r *HelmReleaseReconciler) lock(name string) (unlock func(), err error) {
lockFile := path.Join(os.TempDir(), name+".lock")
mutex := lockedfile.MutexAt(lockFile)