From 19f5db31b30bde17d31a54d9858422d15e5f2261 Mon Sep 17 00:00:00 2001 From: r3drun3 Date: Thu, 30 Nov 2023 09:19:06 +0100 Subject: [PATCH] feat: add apiserver overload gvk Signed-off-by: r3drun3 --- PROJECT | 9 ++ README.md | 20 ++- api/v1alpha1/apiserveroverload_types.go | 59 ++++++++ api/v1alpha1/zz_generated.deepcopy.go | 89 ++++++++++++ cmd/main.go | 7 + .../khaos.stackzoo.io_apiserveroverloads.yaml | 47 ++++++ config/crd/kustomization.yaml | 3 + .../rbac/apiserveroverload_editor_role.yaml | 31 ++++ .../rbac/apiserveroverload_viewer_role.yaml | 27 ++++ config/rbac/role.yaml | 38 +++++ .../khaos_v1alpha1_apiserveroverload.yaml | 12 ++ config/samples/kustomization.yaml | 1 + examples/api-server-overload.yaml | 4 + go.mod | 2 +- .../apiserveroverload_controller.go | 137 ++++++++++++++++++ 15 files changed, 478 insertions(+), 8 deletions(-) create mode 100644 api/v1alpha1/apiserveroverload_types.go create mode 100644 config/crd/bases/khaos.stackzoo.io_apiserveroverloads.yaml create mode 100644 config/rbac/apiserveroverload_editor_role.yaml create mode 100644 config/rbac/apiserveroverload_viewer_role.yaml create mode 100644 config/samples/khaos_v1alpha1_apiserveroverload.yaml create mode 100644 examples/api-server-overload.yaml create mode 100644 internal/controller/apiserveroverload_controller.go diff --git a/PROJECT b/PROJECT index 023274a..c6a8525 100644 --- a/PROJECT +++ b/PROJECT @@ -71,4 +71,13 @@ resources: kind: ConfigMapDestroyer path: stackzoo.io/khaos/api/v1alpha1 version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: stackzoo.io + group: khaos + kind: ApiServerOverload + path: stackzoo.io/khaos/api/v1alpha1 + version: v1alpha1 version: "3" diff --git a/README.md b/README.md index 0291ceb..403af7c 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,9 @@ Through the implementation of custom controllers and resources, Khaos facilitate Khaos is an **unopinionated** operator, in the sense that it provides simple and *atomic primitives* that engineers can use as building blocks in order to compose their preferred chaos strategy. Currently, Khaos does not implement *cronjobs*; any scheduling of Khaos Custom Resources is delegated to external logic outside the cluster, possibly through a GitOps approach. +> [!WARNING] +> This operator will introduce fault and unpredicatbility in you rinfrastructure, use with caution + ## Supported features - [X] Delete pods - [x] Delete cluster nodes @@ -20,9 +23,11 @@ Currently, Khaos does not implement *cronjobs*; any scheduling of Khaos Custom R - [X] Delete configmaps - [X] Inject resource constraints in pods - [X] Add o remove labels in pods +- [X] Flood api server with calls - [X] Exec commands inside pods (**experimental**). + ## Local Testing and Debugging First of all clone the repository: ```console @@ -80,13 +85,14 @@ Install and list the operator CRDs with the following command: make install && kubectl get crds NAME CREATED AT -commandinjections.khaos.stackzoo.io 2023-11-29T08:09:59Z -configmapdestroyers.khaos.stackzoo.io 2023-11-29T08:09:59Z -containerresourcechaos.khaos.stackzoo.io 2023-11-29T08:09:59Z -nodedestroyers.khaos.stackzoo.io 2023-11-29T08:09:59Z -poddestroyers.khaos.stackzoo.io 2023-11-29T08:09:59Z -podlabelchaos.khaos.stackzoo.io 2023-11-29T08:09:59Z -secretdestroyers.khaos.stackzoo.io 2023-11-29T08:09:59Z +apiserveroverloads.khaos.stackzoo.io 2023-11-30T06:25:59Z +commandinjections.khaos.stackzoo.io 2023-11-30T06:25:59Z +configmapdestroyers.khaos.stackzoo.io 2023-11-30T06:25:59Z +containerresourcechaos.khaos.stackzoo.io 2023-11-30T06:25:59Z +nodedestroyers.khaos.stackzoo.io 2023-11-30T06:25:59Z +poddestroyers.khaos.stackzoo.io 2023-11-30T06:25:59Z +podlabelchaos.khaos.stackzoo.io 2023-11-30T06:25:59Z +secretdestroyers.khaos.stackzoo.io 2023-11-30T06:25:59Z ``` In order to run the operator on your cluster (current context - i.e. whatever cluster `kubectl cluster-info` shows) run: diff --git a/api/v1alpha1/apiserveroverload_types.go b/api/v1alpha1/apiserveroverload_types.go new file mode 100644 index 0000000..0819352 --- /dev/null +++ b/api/v1alpha1/apiserveroverload_types.go @@ -0,0 +1,59 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// ApiServerOverloadSpec defines the desired state of ApiServerOverload +type ApiServerOverloadSpec struct { + //DurationSeconds int64 `json:"durationSeconds"` +} + +// ApiServerOverloadStatus defines the observed state of ApiServerOverload +type ApiServerOverloadStatus struct { + ExecutedTimestamp string `json:"executedTimestamp,omitempty"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// ApiServerOverload is the Schema for the apiserveroverloads API +type ApiServerOverload struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ApiServerOverloadSpec `json:"spec,omitempty"` + Status ApiServerOverloadStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// ApiServerOverloadList contains a list of ApiServerOverload +type ApiServerOverloadList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ApiServerOverload `json:"items"` +} + +func init() { + SchemeBuilder.Register(&ApiServerOverload{}, &ApiServerOverloadList{}) +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index bdd023b..b99fc62 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -24,6 +24,95 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApiServerOverload) DeepCopyInto(out *ApiServerOverload) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApiServerOverload. +func (in *ApiServerOverload) DeepCopy() *ApiServerOverload { + if in == nil { + return nil + } + out := new(ApiServerOverload) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ApiServerOverload) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApiServerOverloadList) DeepCopyInto(out *ApiServerOverloadList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ApiServerOverload, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApiServerOverloadList. +func (in *ApiServerOverloadList) DeepCopy() *ApiServerOverloadList { + if in == nil { + return nil + } + out := new(ApiServerOverloadList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ApiServerOverloadList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApiServerOverloadSpec) DeepCopyInto(out *ApiServerOverloadSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApiServerOverloadSpec. +func (in *ApiServerOverloadSpec) DeepCopy() *ApiServerOverloadSpec { + if in == nil { + return nil + } + out := new(ApiServerOverloadSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApiServerOverloadStatus) DeepCopyInto(out *ApiServerOverloadStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApiServerOverloadStatus. +func (in *ApiServerOverloadStatus) DeepCopy() *ApiServerOverloadStatus { + if in == nil { + return nil + } + out := new(ApiServerOverloadStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CommandInjection) DeepCopyInto(out *CommandInjection) { *out = *in diff --git a/cmd/main.go b/cmd/main.go index d11259e..188935a 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -138,6 +138,13 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "ConfigMapDestroyer") os.Exit(1) } + if err = (&controller.ApiServerOverloadReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "ApiServerOverload") + os.Exit(1) + } //+kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { diff --git a/config/crd/bases/khaos.stackzoo.io_apiserveroverloads.yaml b/config/crd/bases/khaos.stackzoo.io_apiserveroverloads.yaml new file mode 100644 index 0000000..cc90410 --- /dev/null +++ b/config/crd/bases/khaos.stackzoo.io_apiserveroverloads.yaml @@ -0,0 +1,47 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: apiserveroverloads.khaos.stackzoo.io +spec: + group: khaos.stackzoo.io + names: + kind: ApiServerOverload + listKind: ApiServerOverloadList + plural: apiserveroverloads + singular: apiserveroverload + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ApiServerOverload is the Schema for the apiserveroverloads API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ApiServerOverloadSpec defines the desired state of ApiServerOverload + type: object + status: + description: ApiServerOverloadStatus defines the observed state of ApiServerOverload + properties: + executedTimestamp: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 1aaaddb..80bfc5a 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -9,6 +9,7 @@ resources: - bases/khaos.stackzoo.io_commandinjections.yaml - bases/khaos.stackzoo.io_podlabelchaos.yaml - bases/khaos.stackzoo.io_configmapdestroyers.yaml +- bases/khaos.stackzoo.io_apiserveroverloads.yaml #+kubebuilder:scaffold:crdkustomizeresource patches: @@ -21,6 +22,7 @@ patches: #- path: patches/webhook_in_commandinjections.yaml #- path: patches/webhook_in_podlabelchaos.yaml #- path: patches/webhook_in_configmapdestroyers.yaml +#- path: patches/webhook_in_apiserveroverloads.yaml #+kubebuilder:scaffold:crdkustomizewebhookpatch # [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. @@ -32,6 +34,7 @@ patches: #- path: patches/cainjection_in_commandinjections.yaml #- path: patches/cainjection_in_podlabelchaos.yaml #- path: patches/cainjection_in_configmapdestroyers.yaml +#- path: patches/cainjection_in_apiserveroverloads.yaml #+kubebuilder:scaffold:crdkustomizecainjectionpatch # [WEBHOOK] To enable webhook, uncomment the following section diff --git a/config/rbac/apiserveroverload_editor_role.yaml b/config/rbac/apiserveroverload_editor_role.yaml new file mode 100644 index 0000000..13c9a62 --- /dev/null +++ b/config/rbac/apiserveroverload_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit apiserveroverloads. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: apiserveroverload-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: khaos + app.kubernetes.io/part-of: khaos + app.kubernetes.io/managed-by: kustomize + name: apiserveroverload-editor-role +rules: +- apiGroups: + - khaos.stackzoo.io + resources: + - apiserveroverloads + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - khaos.stackzoo.io + resources: + - apiserveroverloads/status + verbs: + - get diff --git a/config/rbac/apiserveroverload_viewer_role.yaml b/config/rbac/apiserveroverload_viewer_role.yaml new file mode 100644 index 0000000..9b647f5 --- /dev/null +++ b/config/rbac/apiserveroverload_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view apiserveroverloads. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: apiserveroverload-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: khaos + app.kubernetes.io/part-of: khaos + app.kubernetes.io/managed-by: kustomize + name: apiserveroverload-viewer-role +rules: +- apiGroups: + - khaos.stackzoo.io + resources: + - apiserveroverloads + verbs: + - get + - list + - watch +- apiGroups: + - khaos.stackzoo.io + resources: + - apiserveroverloads/status + verbs: + - get diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 45d435c..4b5baaf 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -13,6 +13,14 @@ rules: - get - list - watch +- apiGroups: + - "" + resources: + - namespaces + verbs: + - get + - list + - watch - apiGroups: - "" resources: @@ -41,6 +49,14 @@ rules: - get - list - watch +- apiGroups: + - "" + resources: + - services + verbs: + - get + - list + - watch - apiGroups: - apps resources: @@ -76,6 +92,28 @@ rules: - get - patch - update +- apiGroups: + - khaos.stackzoo.io + resources: + - apiserveroverloads + verbs: + - get + - list + - watch +- apiGroups: + - khaos.stackzoo.io + resources: + - apiserveroverloads/finalizers + verbs: + - update +- apiGroups: + - khaos.stackzoo.io + resources: + - apiserveroverloads/status + verbs: + - get + - patch + - update - apiGroups: - khaos.stackzoo.io resources: diff --git a/config/samples/khaos_v1alpha1_apiserveroverload.yaml b/config/samples/khaos_v1alpha1_apiserveroverload.yaml new file mode 100644 index 0000000..96ad41d --- /dev/null +++ b/config/samples/khaos_v1alpha1_apiserveroverload.yaml @@ -0,0 +1,12 @@ +apiVersion: khaos.stackzoo.io/v1alpha1 +kind: ApiServerOverload +metadata: + labels: + app.kubernetes.io/name: apiserveroverload + app.kubernetes.io/instance: apiserveroverload-sample + app.kubernetes.io/part-of: khaos + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: khaos + name: apiserveroverload-sample +spec: + # TODO(user): Add fields here diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml index d895616..f4b8a77 100644 --- a/config/samples/kustomization.yaml +++ b/config/samples/kustomization.yaml @@ -7,4 +7,5 @@ resources: - khaos_v1alpha1_commandinjection.yaml - khaos_v1alpha1_podlabelchaos.yaml - khaos_v1alpha1_configmapdestroyer.yaml +- khaos_v1alpha1_apiserveroverload.yaml #+kubebuilder:scaffold:manifestskustomizesamples diff --git a/examples/api-server-overload.yaml b/examples/api-server-overload.yaml new file mode 100644 index 0000000..b8f7de9 --- /dev/null +++ b/examples/api-server-overload.yaml @@ -0,0 +1,4 @@ +apiVersion: khaos.stackzoo.io/v1alpha1 +kind: ApiServerOverload +metadata: + name: apiserveroverload-sample diff --git a/go.mod b/go.mod index cc86b0c..c6aae7d 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.2.4 github.com/go-logr/zapr v1.2.4 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect diff --git a/internal/controller/apiserveroverload_controller.go b/internal/controller/apiserveroverload_controller.go new file mode 100644 index 0000000..3be720b --- /dev/null +++ b/internal/controller/apiserveroverload_controller.go @@ -0,0 +1,137 @@ +package controller + +import ( + "context" + "fmt" + "time" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + khaosv1alpha1 "stackzoo.io/khaos/api/v1alpha1" +) + +// ApiServerOverloadReconciler reconciles a ApiServerOverload object +type ApiServerOverloadReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=khaos.stackzoo.io,resources=apiserveroverloads,verbs=get;list;watch; +//+kubebuilder:rbac:groups=khaos.stackzoo.io,resources=apiserveroverloads/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=khaos.stackzoo.io,resources=apiserveroverloads/finalizers,verbs=update +// +kubebuilder:rbac:groups="",resources=services,verbs=get;list;watch; +// +kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch; +// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch; +// +kubebuilder:rbac:groups="",resources=pods,verbs=get;list;watch; +// +kubebuilder:rbac:groups="",resources=nodes,verbs=get;list;watch +// +kubebuilder:rbac:groups="",resources=namespaces,verbs=get;list;watch + +// Reconcile is part of the main Kubernetes reconciliation loop +func (r *ApiServerOverloadReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + + // Fetch the ApiServerOverload instance + apiServerOverload := &khaosv1alpha1.ApiServerOverload{} + if err := r.Get(ctx, req.NamespacedName, apiServerOverload); err != nil { + if errors.IsNotFound(err) { + // ApiServerOverload resource not found, may have been deleted, return without error + return ctrl.Result{}, nil + } + logger.Error(err, "unable to fetch ApiServerOverload") + return reconcile.Result{}, err + } + + // Log the ApiServerOverload's information + logger.Info(fmt.Sprintf("Reconciling ApiServerOverload: %s", req.NamespacedName)) + + // Update the status with the current datetime + apiServerOverload.Status.ExecutedTimestamp = time.Now().Format(time.RFC3339) + if err := r.Status().Update(ctx, apiServerOverload); err != nil { + logger.Error(err, "failed to update ApiServerOverload status") + return reconcile.Result{}, err + } + + // Start an infinite loop + logger.Info("Started API Server Flooding") + for { + // Do some call to the API server in an infinite loop + podList := &corev1.PodList{} + if err := r.List(ctx, podList); err != nil { + logger.Error(err, "failed to list pods") + return reconcile.Result{}, err + } + + secretList := &corev1.SecretList{} + if err := r.List(ctx, secretList); err != nil { + logger.Error(err, "failed to list secrets") + return reconcile.Result{}, err + } + + configmapList := &corev1.ConfigMapList{} + if err := r.List(ctx, configmapList); err != nil { + logger.Error(err, "failed to list configmaps") + return reconcile.Result{}, err + } + + namespaceList := &corev1.NamespaceList{} + if err := r.List(ctx, namespaceList); err != nil { + logger.Error(err, "failed to list namespaces") + return reconcile.Result{}, err + } + + endpointList := &corev1.EndpointsList{} + if err := r.List(ctx, endpointList); err != nil { + logger.Error(err, "failed to list endpoints") + return reconcile.Result{}, err + } + + eventList := &corev1.EventList{} + if err := r.List(ctx, eventList); err != nil { + logger.Error(err, "failed to list events") + return reconcile.Result{}, err + } + + saList := &corev1.ServiceAccountList{} + if err := r.List(ctx, saList); err != nil { + logger.Error(err, "failed to list service accounts") + return reconcile.Result{}, err + } + + nodeList := &corev1.NodeList{} + if err := r.List(ctx, nodeList); err != nil { + logger.Error(err, "failed to list nodes") + return reconcile.Result{}, err + } + + serviceList := &corev1.ServiceList{} + if err := r.List(ctx, serviceList); err != nil { + logger.Error(err, "failed to list services") + return reconcile.Result{}, err + } + + // Check if the ApiServerOverload resource has been deleted + err := r.Get(ctx, req.NamespacedName, apiServerOverload) + if errors.IsNotFound(err) { + // Resource has been deleted, break out of the loop + break + } else if err != nil { + logger.Error(err, "failed to fetch ApiServerOverload") + return reconcile.Result{}, err + } + } + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *ApiServerOverloadReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&khaosv1alpha1.ApiServerOverload{}). + Complete(r) +}