-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add annotation to trigger directed resource reconciliation. (#53)
- Loading branch information
Showing
15 changed files
with
777 additions
and
189 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
package v2 | ||
|
||
import ( | ||
"context" | ||
"strconv" | ||
|
||
"github.com/google/go-cmp/cmp" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"sigs.k8s.io/controller-runtime/pkg/event" | ||
"sigs.k8s.io/controller-runtime/pkg/predicate" | ||
) | ||
|
||
const ( | ||
// ReconcileAnnotation can be used to trigger a reconciliation of a resource managed by a controller. | ||
// The value of the annotation does not matter, the controller will cleanup the annotation automatically and trigger a reconciliation of the resource. | ||
ReconcileAnnotation = "firewall.metal-stack.io/reconcile" | ||
// MaintenanceAnnotation can be used to trigger a maintenance reconciliation for which a controller might have special behavior. | ||
// The value of the annotation does not matter, the controller will cleanup the annotation automatically. | ||
MaintenanceAnnotation = "firewall.metal-stack.io/maintain" | ||
// RollSetAnnotation can be used to trigger a rolling update of a firewall deployment. | ||
// The value of the annotation needs to be true otherwise the controller will ignore it. | ||
RollSetAnnotation = "firewall.metal-stack.io/roll-set" | ||
// RevisionAnnotation stores the revision number of a resource. | ||
RevisionAnnotation = "firewall.metal-stack.io/revision" | ||
|
||
// FirewallNoControllerConnectionAnnotation can be used as an annotation to the firewall resource in order | ||
// to indicate that the firewall-controller does not connect to the firewall monitor. this way, the replica | ||
// set will become healthy without a controller connection. | ||
// | ||
// this can be useful to silence a problem temporarily and was used in the past for migration of firewall-controller v1. | ||
FirewallNoControllerConnectionAnnotation = "firewall.metal-stack.io/no-controller-connection" | ||
// FirewallControllerManagedByAnnotation is used as tag for creating a firewall to indicate who is managing the firewall. | ||
FirewallControllerManagedByAnnotation = "firewall.metal-stack.io/managed-by" | ||
// FirewallWeightAnnotation is considered when deciding which firewall is thrown away on scale down. | ||
// Value must be parsable as an integer. Firewalls with higher weight are kept longer. | ||
// Defaults to 0 if no annotation is present. Negative values are allowed. | ||
FirewallWeightAnnotation = "firewall.metal-stack.io/weight" | ||
|
||
// FirewallControllerSetAnnotation is a tag added to the firewall entity indicating to which set a firewall belongs to. | ||
FirewallControllerSetAnnotation = "firewall.metal.stack.io/set" | ||
) | ||
|
||
// IsAnnotationPresent returns true if the given object has an annotation with a given | ||
// key, the value of this annotation does not matter. | ||
func IsAnnotationPresent(o client.Object, key string) bool { | ||
_, ok := o.GetAnnotations()[key] | ||
return ok | ||
} | ||
|
||
// IsAnnotationTrue returns true if the given object has an annotation with a given | ||
// key and the value of this annotation is a true boolean. | ||
func IsAnnotationTrue(o client.Object, key string) bool { | ||
enabled, err := strconv.ParseBool(o.GetAnnotations()[key]) | ||
return err == nil && enabled | ||
} | ||
|
||
// IsAnnotationFalse returns true if the given object has an annotation with a given | ||
// key and the value of this annotation is a false boolean. | ||
func IsAnnotationFalse(o client.Object, key string) bool { | ||
enabled, err := strconv.ParseBool(o.GetAnnotations()[key]) | ||
return err == nil && !enabled | ||
} | ||
|
||
// AddAnnotation adds an annotation by a given key to an object if not present by updating it with the given client. | ||
func AddAnnotation(ctx context.Context, c client.Client, o client.Object, key, value string) error { | ||
annotations := o.GetAnnotations() | ||
|
||
if annotations == nil { | ||
annotations = map[string]string{} | ||
} | ||
|
||
if existingValue, ok := annotations[key]; ok && existingValue == value { | ||
return nil | ||
} | ||
|
||
annotations[key] = value | ||
|
||
o.SetAnnotations(annotations) | ||
|
||
err := c.Update(ctx, o) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// RemoveAnnotation removes an annotation by a given key from an object if present by updating it with the given client. | ||
func RemoveAnnotation(ctx context.Context, c client.Client, o client.Object, key string) error { | ||
annotations := o.GetAnnotations() | ||
|
||
if annotations == nil { | ||
return nil | ||
} | ||
|
||
_, ok := annotations[key] | ||
if !ok { | ||
return nil | ||
} | ||
|
||
delete(annotations, key) | ||
|
||
o.SetAnnotations(annotations) | ||
|
||
err := c.Update(ctx, o) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// AnnotationAddedPredicate returns a predicate when the given annotation key was added. | ||
func AnnotationAddedPredicate(annotation string) predicate.Funcs { | ||
return predicate.Funcs{ | ||
CreateFunc: func(ce event.CreateEvent) bool { | ||
return false | ||
}, | ||
UpdateFunc: func(update event.UpdateEvent) bool { | ||
return annotationWasAdded(update, annotation) | ||
}, | ||
DeleteFunc: func(de event.DeleteEvent) bool { | ||
return false | ||
}, | ||
} | ||
} | ||
|
||
// AnnotationRemovedPredicate returns a predicate when the given annotation key was removed. | ||
func AnnotationRemovedPredicate(annotation string) predicate.Funcs { | ||
return predicate.Funcs{ | ||
CreateFunc: func(ce event.CreateEvent) bool { | ||
return false | ||
}, | ||
UpdateFunc: func(update event.UpdateEvent) bool { | ||
return annotationWasRemoved(update, annotation) | ||
}, | ||
DeleteFunc: func(de event.DeleteEvent) bool { | ||
return false | ||
}, | ||
} | ||
} | ||
|
||
func annotationWasRemoved(update event.UpdateEvent, annotation string) bool { | ||
if cmp.Equal(update.ObjectOld.GetAnnotations(), update.ObjectNew.GetAnnotations()) { | ||
return false | ||
} | ||
|
||
var ( | ||
_, o = update.ObjectOld.GetAnnotations()[annotation] | ||
_, n = update.ObjectNew.GetAnnotations()[annotation] | ||
) | ||
|
||
if n { | ||
return false | ||
} | ||
|
||
if !o { | ||
return false | ||
} | ||
|
||
return o && !n | ||
} | ||
|
||
func annotationWasAdded(update event.UpdateEvent, annotation string) bool { | ||
if cmp.Equal(update.ObjectOld.GetAnnotations(), update.ObjectNew.GetAnnotations()) { | ||
return false | ||
} | ||
|
||
var ( | ||
_, o = update.ObjectOld.GetAnnotations()[annotation] | ||
_, n = update.ObjectNew.GetAnnotations()[annotation] | ||
) | ||
|
||
if o { | ||
return false | ||
} | ||
|
||
if !n { | ||
return false | ||
} | ||
|
||
return !o && n | ||
} |
Oops, something went wrong.