97 lines
3.2 KiB
Go
97 lines
3.2 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"slices"
|
|
|
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
"k8s.io/apimachinery/pkg/types"
|
|
)
|
|
|
|
const recordKey = "delivery.quorate.dev/record"
|
|
|
|
func (c *controller) releaseRecords(ctx context.Context, delivery *projectDelivery) error {
|
|
known := make(map[string]bool)
|
|
for _, attempt := range delivery.Status.Points {
|
|
known[attempt.WorkflowName] = true
|
|
}
|
|
if status := delivery.Status.Continuous; status != nil && status.Attempt != nil {
|
|
known[status.Attempt.WorkflowName] = true
|
|
if status.Attempt.History != nil {
|
|
for _, name := range status.Attempt.History.Workflows {
|
|
known[name] = true
|
|
}
|
|
}
|
|
}
|
|
if status := delivery.Status.Qualification; status != nil {
|
|
for _, attempt := range status.Attempts {
|
|
if attempt.Phase != "Pending" && attempt.Phase != "Reserved" {
|
|
known[attempt.WorkflowName] = true
|
|
}
|
|
}
|
|
}
|
|
items, err := c.client.Resource(workflowGVR).Namespace(delivery.Metadata.Namespace).List(ctx, metav1.ListOptions{LabelSelector: recordKey + "=pending"})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, item := range items.Items {
|
|
if known[item.GetName()] && ownedBy(&item, delivery.Metadata.UID) {
|
|
if err := c.clearRecord(ctx, &item); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *controller) releaseOrphans(ctx context.Context) error {
|
|
items, err := c.client.Resource(workflowGVR).Namespace(metav1.NamespaceAll).List(ctx, metav1.ListOptions{LabelSelector: recordKey + "=pending"})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, item := range items.Items {
|
|
for _, owner := range item.GetOwnerReferences() {
|
|
if owner.Kind != "ProjectDelivery" || owner.APIVersion != "delivery.quorate.dev/v1alpha1" {
|
|
continue
|
|
}
|
|
parent, err := c.client.Resource(projectDeliveryGVR).Namespace(item.GetNamespace()).Get(ctx, owner.Name, metav1.GetOptions{})
|
|
if apierrors.IsNotFound(err) || err == nil && (parent.GetUID() != owner.UID || parent.GetDeletionTimestamp() != nil) {
|
|
if err := c.clearRecord(ctx, &item); err != nil {
|
|
return err
|
|
}
|
|
} else if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func ownedBy(workflow *unstructured.Unstructured, uid string) bool {
|
|
return slices.ContainsFunc(workflow.GetOwnerReferences(), func(owner metav1.OwnerReference) bool {
|
|
return owner.Kind == "ProjectDelivery" && owner.APIVersion == "delivery.quorate.dev/v1alpha1" && string(owner.UID) == uid
|
|
})
|
|
}
|
|
|
|
func (c *controller) clearRecord(ctx context.Context, workflow *unstructured.Unstructured) error {
|
|
finalizers := slices.DeleteFunc(slices.Clone(workflow.GetFinalizers()), func(name string) bool { return name == recordKey })
|
|
if finalizers == nil {
|
|
finalizers = []string{}
|
|
}
|
|
patch, err := json.Marshal(map[string]any{"metadata": map[string]any{
|
|
"resourceVersion": workflow.GetResourceVersion(),
|
|
"finalizers": finalizers,
|
|
"labels": map[string]any{recordKey: nil},
|
|
}})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = c.client.Resource(workflowGVR).Namespace(workflow.GetNamespace()).Patch(ctx, workflow.GetName(), types.MergePatchType, patch, metav1.PatchOptions{})
|
|
if apierrors.IsNotFound(err) {
|
|
return nil
|
|
}
|
|
return err
|
|
}
|