// Package objectrestarter provides a utility for restarting workloads using the // kubectl annotation used by K8s for graceful restarting. // Inspired by https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/kubectl/pkg/polymorphichelpers/objectrestarter.go. package objectrestarter import ( "context" "errors" "fmt" "time" appsv1 "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" ) var ErrWorkloadIsNotRestartable = errors.New("workload kind is not restartable") // restartAnnotation is the annotation added by kubectl when you run // `kubectl rollout restart` const restartAnnotation = "kubectl.kubernetes.io/restartedAt" // Restart performs a graceful restart of the provided workload object, if it // is a restartable workload. func Restart(ctx context.Context, c client.Client, workload client.Object) error { patch := []byte(fmt.Sprintf( `{"spec": { "template": {"metadata":{"annotations":{"%s": "%s"}}}}}`, restartAnnotation, time.Now().Format(time.RFC3339)), ) return c.Patch(ctx, workload, client.RawPatch(types.MergePatchType, patch)) } // IsKindRestartable returns true if the provided Kind string refers to a workload // object that can be restarted. func IsKindRestartable(kind string) bool { return kind == "StatefulSet" || kind == "DaemonSet" || kind == "Deployment" } // IsObjectRestartable determines if the provided Object interface represents // a workload object that can be restarted. If an Unstructured object is provided, // it must have had its Kind information set explicitly. func IsObjectRestartable(obj client.Object) bool { switch obj.(type) { case *appsv1.Deployment: return true case *appsv1.DaemonSet: return true case *appsv1.StatefulSet: return true case *unstructured.Unstructured: return IsKindRestartable(obj.GetObjectKind().GroupVersionKind().Kind) default: return false } }