Implement pruning based on snapshots
This commit is contained in:
parent
dbe3e69508
commit
f96f3e326f
|
@ -60,6 +60,9 @@ const (
|
|||
// ApplyFailedReason represents the fact that the kustomization apply failed.
|
||||
ApplyFailedReason string = "ApplyFailed"
|
||||
|
||||
// PruneFailedReason represents the fact that the kustomization pruning failed.
|
||||
PruneFailedReason string = "PruneFailed"
|
||||
|
||||
// ArtifactFailedReason represents the fact that the artifact download failed.
|
||||
ArtifactFailedReason string = "ArtifactFailed"
|
||||
|
||||
|
|
|
@ -163,6 +163,20 @@ func KustomizationNotReady(kustomization Kustomization, reason, message string)
|
|||
return kustomization
|
||||
}
|
||||
|
||||
func KustomizationNotReadySnapshot(kustomization Kustomization, snapshot *Snapshot, reason, message string) Kustomization {
|
||||
kustomization.Status.Conditions = []Condition{
|
||||
{
|
||||
Type: ReadyCondition,
|
||||
Status: corev1.ConditionFalse,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: reason,
|
||||
Message: message,
|
||||
},
|
||||
}
|
||||
kustomization.Status.Snapshot = snapshot
|
||||
return kustomization
|
||||
}
|
||||
|
||||
// GetTimeout returns the timeout with default
|
||||
func (in *Kustomization) GetTimeout() time.Duration {
|
||||
duration := in.Spec.Interval.Duration
|
||||
|
|
|
@ -248,11 +248,22 @@ func (r *KustomizationReconciler) sync(
|
|||
), err
|
||||
}
|
||||
|
||||
// health assessment
|
||||
err = r.checkHealth(kustomization)
|
||||
// prune
|
||||
err = r.prune(kustomization, snapshot)
|
||||
if err != nil {
|
||||
return kustomizev1.KustomizationNotReady(
|
||||
kustomization,
|
||||
kustomizev1.PruneFailedReason,
|
||||
err.Error(),
|
||||
), err
|
||||
}
|
||||
|
||||
// health assessment
|
||||
err = r.checkHealth(kustomization)
|
||||
if err != nil {
|
||||
return kustomizev1.KustomizationNotReadySnapshot(
|
||||
kustomization,
|
||||
snapshot,
|
||||
kustomizev1.HealthCheckFailedReason,
|
||||
"health check failed",
|
||||
), err
|
||||
|
@ -364,7 +375,7 @@ func (r *KustomizationReconciler) generateLabelTransformer(kustomization kustomi
|
|||
}{
|
||||
Name: kustomization.GetName(),
|
||||
},
|
||||
Labels: gcLabels(kustomization.GetName(), revision),
|
||||
Labels: gcLabels(kustomization.GetName(), kustomization.GetNamespace(), revision),
|
||||
FieldSpecs: []kustypes.FieldSpec{
|
||||
{Path: "metadata/labels", CreateIfNotPresent: true},
|
||||
},
|
||||
|
@ -476,6 +487,25 @@ func (r *KustomizationReconciler) apply(kustomization kustomizev1.Kustomization,
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *KustomizationReconciler) prune(kustomization kustomizev1.Kustomization, snapshot *kustomizev1.Snapshot) error {
|
||||
if kustomization.Status.Snapshot == nil || snapshot == nil {
|
||||
return nil
|
||||
}
|
||||
if kustomization.Status.Snapshot.Revision == snapshot.Revision {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !prune(kustomization.GetTimeout(),
|
||||
kustomization.GetName(),
|
||||
kustomization.GetNamespace(),
|
||||
kustomization.Status.Snapshot,
|
||||
r.Log,
|
||||
) {
|
||||
return fmt.Errorf("pruning failed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *KustomizationReconciler) checkHealth(kustomization kustomizev1.Kustomization) error {
|
||||
timeout := kustomization.GetTimeout() + (time.Second * 1)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
|
|
|
@ -68,41 +68,62 @@ type KustomizationGarbageCollectPredicate struct {
|
|||
func (gc KustomizationGarbageCollectPredicate) Delete(e event.DeleteEvent) bool {
|
||||
if k, ok := e.Object.(*kustomizev1.Kustomization); ok {
|
||||
if k.Spec.Prune != "" && !k.Spec.Suspend && k.Status.Snapshot != nil {
|
||||
timeout := k.GetTimeout()
|
||||
selector := gcSelectors(k.GetName(), k.Status.Snapshot.Revision)
|
||||
gc.Log.Info("Garbage collection started",
|
||||
"kustomization", fmt.Sprintf("%s/%s", k.GetNamespace(), k.GetName()))
|
||||
|
||||
for ns, kinds := range k.Status.Snapshot.NamespacedKinds() {
|
||||
for _, kind := range kinds {
|
||||
if output, err := deleteByKind(timeout, kind, ns, selector); err != nil {
|
||||
gc.Log.Error(err, "Garbage collection failed for namespaced objects",
|
||||
"kustomization", fmt.Sprintf("%s/%s", k.GetNamespace(), k.GetName()))
|
||||
} else {
|
||||
gc.Log.Info("Garbage collection for namespaced objects completed",
|
||||
"kustomization", fmt.Sprintf("%s/%s", k.GetNamespace(), k.GetName()),
|
||||
"output", output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, kind := range k.Status.Snapshot.NonNamespacedKinds() {
|
||||
if output, err := deleteByKind(timeout, kind, "", selector); err != nil {
|
||||
gc.Log.Error(err, "Garbage collection failed for non-namespaced objects",
|
||||
"kustomization", fmt.Sprintf("%s/%s", k.GetNamespace(), k.GetName()))
|
||||
} else {
|
||||
gc.Log.Info("Garbage collection for non-namespaced objects completed",
|
||||
"kustomization", fmt.Sprintf("%s/%s", k.GetNamespace(), k.GetName()),
|
||||
"output", output)
|
||||
}
|
||||
|
||||
}
|
||||
prune(k.GetTimeout(), k.GetName(), k.GetNamespace(), k.Status.Snapshot, gc.Log)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func prune(timeout time.Duration, name string, namespace string, snapshot *kustomizev1.Snapshot, log logr.Logger) bool {
|
||||
selector := gcSelectors(name, namespace, snapshot.Revision)
|
||||
ok := true
|
||||
outInfo := ""
|
||||
outErr := ""
|
||||
for ns, kinds := range snapshot.NamespacedKinds() {
|
||||
for _, kind := range kinds {
|
||||
if output, err := deleteByKind(timeout, kind, ns, selector); err != nil {
|
||||
outErr += " " + err.Error()
|
||||
ok = false
|
||||
} else {
|
||||
outInfo += " " + output
|
||||
}
|
||||
}
|
||||
}
|
||||
if outErr == "" {
|
||||
log.Info("Garbage collection for namespaced objects completed",
|
||||
"kustomization", fmt.Sprintf("%s/%s", namespace, name),
|
||||
"output", outInfo)
|
||||
} else {
|
||||
log.Error(fmt.Errorf(outErr), "Garbage collection for namespaced objects failed",
|
||||
"kustomization", fmt.Sprintf("%s/%s", namespace, name))
|
||||
}
|
||||
|
||||
outInfo = ""
|
||||
outErr = ""
|
||||
for _, kind := range snapshot.NonNamespacedKinds() {
|
||||
if output, err := deleteByKind(timeout, kind, "", selector); err != nil {
|
||||
outErr += " " + err.Error()
|
||||
ok = false
|
||||
} else {
|
||||
outInfo += " " + output
|
||||
}
|
||||
}
|
||||
if outErr == "" {
|
||||
log.Info("Garbage collection for non-namespaced objects completed",
|
||||
"kustomization", fmt.Sprintf("%s/%s", namespace, name),
|
||||
"output", outInfo)
|
||||
} else {
|
||||
log.Error(fmt.Errorf(outErr), "Garbage collection for non-namespaced objects failed",
|
||||
"kustomization", fmt.Sprintf("%s/%s", namespace, name))
|
||||
}
|
||||
|
||||
return ok
|
||||
}
|
||||
|
||||
func deleteByKind(timeout time.Duration, kind, namespace, selector string) (string, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout+time.Second)
|
||||
defer cancel()
|
||||
|
@ -120,15 +141,15 @@ func deleteByKind(timeout time.Duration, kind, namespace, selector string) (stri
|
|||
}
|
||||
}
|
||||
|
||||
func gcLabels(name, revision string) map[string]string {
|
||||
func gcLabels(name, namespace, revision string) map[string]string {
|
||||
return map[string]string{
|
||||
"kustomization/name": name,
|
||||
"kustomization/name": fmt.Sprintf("%s-%s", name, namespace),
|
||||
"kustomization/revision": checksum(revision),
|
||||
}
|
||||
}
|
||||
|
||||
func gcSelectors(name, revision string) string {
|
||||
return fmt.Sprintf("kustomization/name=%s,kustomization/revision=%s", name, checksum(revision))
|
||||
func gcSelectors(name, namespace, revision string) string {
|
||||
return fmt.Sprintf("kustomization/name=%s-%s,kustomization/revision=%s", name, namespace, checksum(revision))
|
||||
}
|
||||
|
||||
func checksum(in string) string {
|
||||
|
|
Loading…
Reference in New Issue