package reconcile import ( "errors" "fmt" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" edgeunstructured "edge-infra.dev/pkg/k8s/unstructured" ) const ( // ReconcileRequestAnnotation is the annotation used for triggering a // reconciliation outside of a defined schedule. The value is interpreted as // a token, and any change in value SHOULD trigger a reconciliation. ReconcileRequestAnnotation string = "reconcile.f8n.ncr.com/requestedAt" ) var ErrLastHandledReconcileAtNotFound = errors.New("last handled reconcile at not found") // RequestStatus is a struct to embed in a status type, so that all types using the mechanism have the same // field. Use it like this: // // type FooStatus struct { // reconcile.RequestStatus `json:",inline"` // // other status fields... // } type RequestStatus struct { // LastHandledReconcileAt holds the value of the most recent // reconcile request value, so a change of the annotation value // can be detected. // +optional LastHandledReconcileAt string `json:"lastHandledReconcileAt,omitempty"` } // GetStatusLastHandledReconcileAt returns the status.lastHandledReconcileAt // value of a given runtime object, if present. func GetStatusLastHandledReconcileAt(obj runtime.Object) (string, error) { u, err := edgeunstructured.FromRuntime(obj) if err != nil { return "", err } ra, found, err := unstructured.NestedString(u.Object, "status", "lastHandledReconcileAt") if err != nil { return "", err } if !found { return "", fmt.Errorf("%w", ErrLastHandledReconcileAtNotFound) } return ra, nil } // SetStatusLastHandledReconcileAt sets the status.lastHandledReconcileAt value // of a given runtime object. func SetStatusLastHandledReconcileAt(obj runtime.Object, val string) error { u, err := edgeunstructured.FromRuntime(obj) if err != nil { return err } if err := unstructured.SetNestedField(u.Object, val, "status", "lastHandledReconcileAt"); err != nil { return err } return runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, obj) } // GetAnnotation returns a value for the reconciliation request annotation, // which can be used to detect changes; and, a boolean indicating whether the // annotation was set. func GetAnnotation(annotations map[string]string) (string, bool) { requestedAt, ok := annotations[ReconcileRequestAnnotation] return requestedAt, ok }