fix(lint): enable cyclop

Signed-off-by: Luca Burgazzoli <lburgazzoli@gmail.com>
This commit is contained in:
Luca Burgazzoli 2024-09-11 13:42:10 +02:00 committed by Luca Burgazzoli
parent c545400093
commit 3e366c0714
8 changed files with 363 additions and 280 deletions

View File

@ -68,5 +68,4 @@ linters:
- gochecknoinits - gochecknoinits
- depguard - depguard
# validate # validate
- cyclop
- gocognit - gocognit

View File

@ -5,6 +5,8 @@ import (
"fmt" "fmt"
"strconv" "strconv"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
k8serrors "k8s.io/apimachinery/pkg/api/errors" k8serrors "k8s.io/apimachinery/pkg/api/errors"
"github.com/dapr/kubernetes-operator/pkg/controller" "github.com/dapr/kubernetes-operator/pkg/controller"
@ -50,11 +52,6 @@ func (a *ApplyCRDsAction) Run(ctx context.Context, rc *ReconciliationRequest) er
} }
for _, crd := range crds { for _, crd := range crds {
dc, err := rc.Client.Dynamic(rc.Resource.Namespace, &crd)
if err != nil {
return fmt.Errorf("cannot create dynamic client: %w", err)
}
resources.Labels(&crd, map[string]string{ resources.Labels(&crd, map[string]string{
helm.ReleaseGeneration: strconv.FormatInt(rc.Resource.Generation, 10), helm.ReleaseGeneration: strconv.FormatInt(rc.Resource.Generation, 10),
helm.ReleaseName: rc.Resource.Name, helm.ReleaseName: rc.Resource.Name,
@ -62,41 +59,10 @@ func (a *ApplyCRDsAction) Run(ctx context.Context, rc *ReconciliationRequest) er
helm.ReleaseVersion: c.Version(), helm.ReleaseVersion: c.Version(),
}) })
apply := rc.Resource.Generation != rc.Resource.Status.ObservedGeneration err = a.apply(ctx, rc, &crd)
_, err = dc.Get(ctx, crd.GetName(), metav1.GetOptions{})
if err != nil && !k8serrors.IsNotFound(err) {
return fmt.Errorf("cannot determine if CRD %s exists: %w", resources.Ref(&crd), err)
}
if err != nil && k8serrors.IsNotFound(err) {
apply = true
}
if !apply {
a.l.Info("run",
"apply", "false",
"gen", rc.Resource.Generation,
"ref", resources.Ref(&crd),
"generation-changed", rc.Resource.Generation != rc.Resource.Status.ObservedGeneration,
"not-found", k8serrors.IsNotFound(err))
continue
}
_, err = dc.Apply(ctx, crd.GetName(), &crd, metav1.ApplyOptions{
FieldManager: controller.FieldManager,
Force: true,
})
if err != nil { if err != nil {
return fmt.Errorf("cannot apply CRD %s: %w", resources.Ref(&crd), err) return err
} }
a.l.Info("run",
"apply", "true",
"gen", rc.Resource.Generation,
"ref", resources.Ref(&crd))
} }
// invalidate the client so it gets aware of the new CRDs // invalidate the client so it gets aware of the new CRDs
@ -108,3 +74,48 @@ func (a *ApplyCRDsAction) Run(ctx context.Context, rc *ReconciliationRequest) er
func (a *ApplyCRDsAction) Cleanup(_ context.Context, _ *ReconciliationRequest) error { func (a *ApplyCRDsAction) Cleanup(_ context.Context, _ *ReconciliationRequest) error {
return nil return nil
} }
func (a *ApplyCRDsAction) apply(ctx context.Context, rc *ReconciliationRequest, crd *unstructured.Unstructured) error {
dc, err := rc.Client.Dynamic(rc.Resource.Namespace, crd)
if err != nil {
return fmt.Errorf("cannot create dynamic client: %w", err)
}
apply := rc.Resource.Generation != rc.Resource.Status.ObservedGeneration
_, err = dc.Get(ctx, crd.GetName(), metav1.GetOptions{})
if err != nil && !k8serrors.IsNotFound(err) {
return fmt.Errorf("cannot determine if CRD %s exists: %w", resources.Ref(crd), err)
}
if err != nil && k8serrors.IsNotFound(err) {
apply = true
}
if !apply {
a.l.Info("run",
"apply", "false",
"gen", rc.Resource.Generation,
"ref", resources.Ref(crd),
"generation-changed", rc.Resource.Generation != rc.Resource.Status.ObservedGeneration,
"not-found", k8serrors.IsNotFound(err))
return nil
}
_, err = dc.Apply(ctx, crd.GetName(), crd, metav1.ApplyOptions{
FieldManager: controller.FieldManager,
Force: true,
})
if err != nil {
return fmt.Errorf("cannot apply CRD %s: %w", resources.Ref(crd), err)
}
a.l.Info("run",
"apply", "true",
"gen", rc.Resource.Generation,
"ref", resources.Ref(crd))
return nil
}

View File

@ -6,6 +6,8 @@ import (
"sort" "sort"
"strconv" "strconv"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"github.com/dapr/kubernetes-operator/pkg/controller/predicates" "github.com/dapr/kubernetes-operator/pkg/controller/predicates"
"github.com/dapr/kubernetes-operator/pkg/controller" "github.com/dapr/kubernetes-operator/pkg/controller"
@ -66,9 +68,9 @@ func (a *ApplyResourcesAction) Run(ctx context.Context, rc *ReconciliationReques
installedVersion = rc.Resource.Status.Chart.Version installedVersion = rc.Resource.Status.Chart.Version
} }
reinstall := rc.Resource.Generation != rc.Resource.Status.ObservedGeneration || c.Version() != installedVersion force := rc.Resource.Generation != rc.Resource.Status.ObservedGeneration || c.Version() != installedVersion
if reinstall { if force {
rc.Reconciler.Event( rc.Reconciler.Event(
rc.Resource, rc.Resource,
corev1.EventTypeNormal, corev1.EventTypeNormal,
@ -81,20 +83,7 @@ func (a *ApplyResourcesAction) Run(ctx context.Context, rc *ReconciliationReques
) )
} }
for i := range items { for _, obj := range items {
obj := items[i]
gvk := obj.GroupVersionKind()
installOnly := a.installOnly(gvk)
if reinstall {
installOnly = false
}
dc, err := rc.Client.Dynamic(rc.Resource.Namespace, &obj)
if err != nil {
return fmt.Errorf("cannot create dynamic client: %w", err)
}
resources.Labels(&obj, map[string]string{ resources.Labels(&obj, map[string]string{
helm.ReleaseGeneration: strconv.FormatInt(rc.Resource.Generation, 10), helm.ReleaseGeneration: strconv.FormatInt(rc.Resource.Generation, 10),
helm.ReleaseName: rc.Resource.Name, helm.ReleaseName: rc.Resource.Name,
@ -102,117 +91,16 @@ func (a *ApplyResourcesAction) Run(ctx context.Context, rc *ReconciliationReques
helm.ReleaseVersion: c.Version(), helm.ReleaseVersion: c.Version(),
}) })
switch dc.(type) { gvk := obj.GroupVersionKind()
//
// NamespacedResource: in this case, filtering with ownership can be implemented
// as all the namespaced resources created by this controller have the Dapr CR as
// an owner
//
case *client.NamespacedResource:
obj.SetOwnerReferences(resources.OwnerReferences(rc.Resource))
obj.SetNamespace(rc.Resource.Namespace)
r := gvk.GroupVersion().String() + ":" + gvk.Kind if !force {
force = !a.installOnly(gvk)
if _, ok := a.subscriptions[r]; !ok { }
a.l.Info("watch", "ref", r)
err = rc.Reconciler.Watch(
&obj,
rc.Reconciler.EnqueueRequestForOwner(&daprApi.DaprInstance{}, handler.OnlyControllerOwner()),
dependantWithLabels(
predicates.WithWatchUpdate(a.watchForUpdates(gvk)),
predicates.WithWatchDeleted(true),
predicates.WithWatchStatus(a.watchStatus(gvk)),
),
)
err = a.apply(ctx, rc, &obj, force)
if err != nil { if err != nil {
return err return err
} }
a.subscriptions[r] = struct{}{}
}
//
// ClusteredResource: in this case, ownership based filtering is not supported
// as you cannot have a non namespaced owner. For such reason, the resource for
// which a reconcile should be triggered can be identified by using the labels
// added by the controller to all the generated resources
//
// helm.operator.dapr.io/resource.namespace = ${namespace}
// helm.operator.dapr.io/resource.name = ${name}
//
case *client.ClusteredResource:
r := gvk.GroupVersion().String() + ":" + gvk.Kind
if _, ok := a.subscriptions[r]; !ok {
a.l.Info("watch", "ref", r)
err = rc.Reconciler.Watch(
&obj,
rc.Reconciler.EnqueueRequestsFromMapFunc(labelsToRequest),
dependantWithLabels(
predicates.WithWatchUpdate(a.watchForUpdates(gvk)),
predicates.WithWatchDeleted(true),
predicates.WithWatchStatus(a.watchStatus(gvk)),
),
)
if err != nil {
return err
}
a.subscriptions[r] = struct{}{}
}
}
if installOnly {
old, err := dc.Get(ctx, obj.GetName(), metav1.GetOptions{})
if err != nil {
if !k8serrors.IsNotFound(err) {
return fmt.Errorf("cannot get object %s: %w", resources.Ref(&obj), err)
}
}
if old != nil {
//
// Every time the template is rendered, the helm function genSignedCert kicks in and
// re-generated certs which causes a number os side effects and makes the set-up quite
// unstable. As consequence some resources are not meant to be watched and re-created
// unless the Dapr CR generation changes (which means the Spec has changed) or the
// resource impacted by the genSignedCert hook is deleted.
//
// Ideally on OpenShift it would be good to leverage the service serving certificates
// capability.
//
// Related info:
// - https://docs.openshift.com/container-platform/4.13/security/certificates/service-serving-certificate.html
// - https://github.com/dapr/dapr/issues/3968
// - https://github.com/dapr/dapr/issues/6500
//
a.l.Info("run",
"apply", "false",
"ref", resources.Ref(&obj),
"reason", "resource marked as install-only")
continue
}
}
_, err = dc.Apply(ctx, obj.GetName(), &obj, metav1.ApplyOptions{
FieldManager: controller.FieldManager,
Force: true,
})
if err != nil {
return fmt.Errorf("cannot patch object %s: %w", resources.Ref(&obj), err)
}
a.l.Info("run",
"apply", "true",
"gen", rc.Resource.Generation,
"ref", resources.Ref(&obj))
} }
return nil return nil
@ -293,3 +181,152 @@ func (a *ApplyResourcesAction) installOnly(gvk schema.GroupVersionKind) bool {
return false return false
} }
//nolint:cyclop
func (a *ApplyResourcesAction) apply(ctx context.Context, rc *ReconciliationRequest, obj *unstructured.Unstructured, force bool) error {
dc, err := rc.Client.Dynamic(rc.Resource.Namespace, obj)
if err != nil {
return fmt.Errorf("cannot create dynamic client: %w", err)
}
switch dc.(type) {
//
// NamespacedResource: in this case, filtering with ownership can be implemented
// as all the namespaced resources created by this controller have the Dapr CR as
// an owner
//
case *client.NamespacedResource:
if err := a.watchNamespaceScopeResource(rc, obj); err != nil {
return err
}
//
// ClusteredResource: in this case, ownership based filtering is not supported
// as you cannot have a non namespaced owner. For such reason, the resource for
// which a reconcile should be triggered can be identified by using the labels
// added by the controller to all the generated resources
//
// helm.operator.dapr.io/resource.namespace = ${namespace}
// helm.operator.dapr.io/resource.name = ${name}
//
case *client.ClusteredResource:
if err := a.watchClusterScopeResource(rc, obj); err != nil {
return err
}
}
if !force {
old, err := dc.Get(ctx, obj.GetName(), metav1.GetOptions{})
if err != nil && !k8serrors.IsNotFound(err) {
return fmt.Errorf("cannot get object %s: %w", resources.Ref(obj), err)
}
if old != nil {
//
// Every time the template is rendered, the helm function genSignedCert kicks in and
// re-generated certs which causes a number os side effects and makes the set-up quite
// unstable. As consequence some resources are not meant to be watched and re-created
// unless the Dapr CR generation changes (which means the Spec has changed) or the
// resource impacted by the genSignedCert hook is deleted.
//
// Ideally on OpenShift it would be good to leverage the service serving certificates
// capability.
//
// Related info:
// - https://docs.openshift.com/container-platform/4.13/security/certificates/service-serving-certificate.html
// - https://github.com/dapr/dapr/issues/3968
// - https://github.com/dapr/dapr/issues/6500
//
a.l.Info("run",
"apply", "false",
"gen", rc.Resource.Generation,
"ref", resources.Ref(obj),
"reason", "resource marked as install-only")
return nil
}
}
_, err = dc.Apply(ctx, obj.GetName(), obj, metav1.ApplyOptions{
FieldManager: controller.FieldManager,
Force: true,
})
if err != nil {
return fmt.Errorf("cannot patch object %s: %w", resources.Ref(obj), err)
}
a.l.Info("run",
"apply", "true",
"gen", rc.Resource.Generation,
"ref", resources.Ref(obj))
return nil
}
func (a *ApplyResourcesAction) watchNamespaceScopeResource(rc *ReconciliationRequest, obj *unstructured.Unstructured) error {
gvk := obj.GroupVersionKind()
obj.SetOwnerReferences(resources.OwnerReferences(rc.Resource))
obj.SetNamespace(rc.Resource.Namespace)
r := gvk.GroupVersion().String() + ":" + gvk.Kind
if _, ok := a.subscriptions[r]; ok {
return nil
}
if _, ok := a.subscriptions[r]; !ok {
a.l.Info("watch", "scope", "namespace", "ref", r)
err := rc.Reconciler.Watch(
obj,
rc.Reconciler.EnqueueRequestForOwner(&daprApi.DaprInstance{}, handler.OnlyControllerOwner()),
dependantWithLabels(
predicates.WithWatchUpdate(a.watchForUpdates(gvk)),
predicates.WithWatchDeleted(true),
predicates.WithWatchStatus(a.watchStatus(gvk)),
),
)
if err != nil {
return err
}
a.subscriptions[r] = struct{}{}
}
return nil
}
func (a *ApplyResourcesAction) watchClusterScopeResource(rc *ReconciliationRequest, obj *unstructured.Unstructured) error {
gvk := obj.GroupVersionKind()
r := gvk.GroupVersion().String() + ":" + gvk.Kind
if _, ok := a.subscriptions[r]; ok {
return nil
}
if _, ok := a.subscriptions[r]; !ok {
a.l.Info("watch", "scope", "cluster", "ref", r)
err := rc.Reconciler.Watch(
obj,
rc.Reconciler.EnqueueRequestsFromMapFunc(labelsToRequest),
dependantWithLabels(
predicates.WithWatchUpdate(a.watchForUpdates(gvk)),
predicates.WithWatchDeleted(true),
predicates.WithWatchStatus(a.watchStatus(gvk)),
),
)
if err != nil {
return err
}
a.subscriptions[r] = struct{}{}
}
return nil
}

View File

@ -4,6 +4,8 @@ import (
"context" "context"
"fmt" "fmt"
"k8s.io/apimachinery/pkg/labels"
"github.com/dapr/kubernetes-operator/pkg/conditions" "github.com/dapr/kubernetes-operator/pkg/conditions"
appsv1 "k8s.io/api/apps/v1" appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
@ -35,69 +37,35 @@ func (a *ConditionsAction) Run(ctx context.Context, rc *ReconciliationRequest) e
return fmt.Errorf("cannot compute current release selector: %w", err) return fmt.Errorf("cannot compute current release selector: %w", err)
} }
// Deployments deployments, readyDeployments, err := a.deployments(ctx, rc, crs)
deployments, err := rc.Client.AppsV1().Deployments(rc.Resource.Namespace).List(ctx, metav1.ListOptions{
LabelSelector: crs.String(),
})
if err != nil { if err != nil {
return fmt.Errorf("cannot list deployments: %w", err) return fmt.Errorf("cannot count deployments: %w", err)
} }
readyDeployments := 0 statefulSets, readyReplicaSets, err := a.statefulSets(ctx, rc, crs)
for i := range deployments.Items {
if conditions.ConditionStatus(deployments.Items[i], appsv1.DeploymentAvailable) == corev1.ConditionTrue {
readyDeployments++
}
}
// StatefulSets
statefulSets, err := rc.Client.AppsV1().StatefulSets(rc.Resource.Namespace).List(ctx, metav1.ListOptions{
LabelSelector: crs.String(),
})
if err != nil { if err != nil {
return fmt.Errorf("cannot list stateful sets: %w", err) return fmt.Errorf("cannot count stateful sets: %w", err)
}
readyReplicaSets := 0
for i := range statefulSets.Items {
if statefulSets.Items[i].Status.Replicas == 0 {
continue
}
if statefulSets.Items[i].Status.Replicas == statefulSets.Items[i].Status.ReadyReplicas {
readyReplicaSets++
}
} }
var readyCondition metav1.Condition var readyCondition metav1.Condition
if len(deployments.Items)+len(statefulSets.Items) > 0 { if deployments+statefulSets > 0 {
if readyDeployments+readyReplicaSets == len(deployments.Items)+len(statefulSets.Items) { reason := "Ready"
status := metav1.ConditionTrue
if readyDeployments+readyReplicaSets != deployments+statefulSets {
reason = "InProgress"
status = metav1.ConditionFalse
}
readyCondition = metav1.Condition{ readyCondition = metav1.Condition{
Type: conditions.TypeReady, Type: conditions.TypeReady,
Status: metav1.ConditionTrue, Status: status,
Reason: "Ready", Reason: reason,
ObservedGeneration: rc.Resource.Generation, ObservedGeneration: rc.Resource.Generation,
Message: fmt.Sprintf("%d/%d deployments ready, statefulSets ready %d/%d", Message: fmt.Sprintf("%d/%d deployments ready, statefulSets ready %d/%d",
readyDeployments, len(deployments.Items), readyDeployments, deployments,
readyReplicaSets, len(statefulSets.Items)), readyReplicaSets, statefulSets),
}
} else {
readyCondition = metav1.Condition{
Type: conditions.TypeReady,
Status: metav1.ConditionFalse,
Reason: "InProgress",
ObservedGeneration: rc.Resource.Generation,
Message: fmt.Sprintf("%d/%d deployments ready, statefulSets ready %d/%d",
readyDeployments, len(deployments.Items),
readyReplicaSets, len(statefulSets.Items)),
}
} }
} else { } else {
readyCondition = metav1.Condition{ readyCondition = metav1.Condition{
@ -117,3 +85,47 @@ func (a *ConditionsAction) Run(ctx context.Context, rc *ReconciliationRequest) e
func (a *ConditionsAction) Cleanup(_ context.Context, _ *ReconciliationRequest) error { func (a *ConditionsAction) Cleanup(_ context.Context, _ *ReconciliationRequest) error {
return nil return nil
} }
func (a *ConditionsAction) deployments(ctx context.Context, rc *ReconciliationRequest, selector labels.Selector) (int, int, error) {
objects, err := rc.Client.AppsV1().Deployments(rc.Resource.Namespace).List(ctx, metav1.ListOptions{
LabelSelector: selector.String(),
})
if err != nil {
return 0, 0, fmt.Errorf("cannot list deployments: %w", err)
}
ready := 0
for i := range objects.Items {
if conditions.ConditionStatus(objects.Items[i], appsv1.DeploymentAvailable) == corev1.ConditionTrue {
ready++
}
}
return len(objects.Items), ready, nil
}
func (a *ConditionsAction) statefulSets(ctx context.Context, rc *ReconciliationRequest, selector labels.Selector) (int, int, error) {
objects, err := rc.Client.AppsV1().StatefulSets(rc.Resource.Namespace).List(ctx, metav1.ListOptions{
LabelSelector: selector.String(),
})
if err != nil {
return 0, 0, fmt.Errorf("cannot list stateful sets: %w", err)
}
ready := 0
for i := range objects.Items {
if objects.Items[i].Status.Replicas == 0 {
continue
}
if objects.Items[i].Status.Replicas == objects.Items[i].Status.ReadyReplicas {
ready++
}
}
return len(objects.Items), ready, nil
}

View File

@ -50,26 +50,16 @@ func ConditionStatus[T GenericConditionType](object any, conditionType T) corev1
return corev1.ConditionStatus(c.Status) return corev1.ConditionStatus(c.Status)
} }
case *appsv1.Deployment: case *appsv1.Deployment:
if o != nil { if c, ok := FindDeploymentStatusCondition(o, string(conditionType)); ok {
for i := range o.Status.Conditions { return c.Status
if string(o.Status.Conditions[i].Type) == string(conditionType) {
return o.Status.Conditions[i].Status
}
}
} }
case appsv1.Deployment: case appsv1.Deployment:
for i := range o.Status.Conditions { if c, ok := FindDeploymentStatusCondition(&o, string(conditionType)); ok {
if string(o.Status.Conditions[i].Type) == string(conditionType) { return c.Status
return o.Status.Conditions[i].Status
}
} }
case *corev1.Pod: case *corev1.Pod:
if o != nil { if c, ok := FindPodStatusCondition(o, string(conditionType)); ok {
for i := range o.Status.Conditions { return c.Status
if string(o.Status.Conditions[i].Type) == string(conditionType) {
return o.Status.Conditions[i].Status
}
}
} }
} }
@ -83,28 +73,46 @@ func ConditionReason[T GenericConditionType](object any, conditionType T) string
return c.Reason return c.Reason
} }
case *appsv1.Deployment: case *appsv1.Deployment:
if o != nil { if c, ok := FindDeploymentStatusCondition(o, string(conditionType)); ok {
for i := range o.Status.Conditions { return c.Reason
if string(o.Status.Conditions[i].Type) == string(conditionType) {
return o.Status.Conditions[i].Reason
}
}
} }
case appsv1.Deployment: case appsv1.Deployment:
for i := range o.Status.Conditions { if c, ok := FindDeploymentStatusCondition(&o, string(conditionType)); ok {
if string(o.Status.Conditions[i].Type) == string(conditionType) { return c.Reason
return o.Status.Conditions[i].Reason
}
} }
case *corev1.Pod: case *corev1.Pod:
if o != nil { if c, ok := FindPodStatusCondition(o, string(conditionType)); ok {
for i := range o.Status.Conditions { return c.Reason
if string(o.Status.Conditions[i].Type) == string(conditionType) {
return o.Status.Conditions[i].Reason
}
}
} }
} }
return "" return ""
} }
func FindDeploymentStatusCondition(in *appsv1.Deployment, conditionType string) (appsv1.DeploymentCondition, bool) {
if in == nil {
return appsv1.DeploymentCondition{}, false
}
for i := range in.Status.Conditions {
if string(in.Status.Conditions[i].Type) == conditionType {
return in.Status.Conditions[i], true
}
}
return appsv1.DeploymentCondition{}, false
}
func FindPodStatusCondition(in *corev1.Pod, conditionType string) (corev1.PodCondition, bool) {
if in == nil {
return corev1.PodCondition{}, false
}
for i := range in.Status.Conditions {
if string(in.Status.Conditions[i].Type) == conditionType {
return in.Status.Conditions[i], true
}
}
return corev1.PodCondition{}, false
}

View File

@ -93,19 +93,37 @@ func (gc *GC) deleteEachOf(
} }
for i := range items.Items { for i := range items.Items {
resource := items.Items[i] ok, err := gc.delete(ctx, c, items.Items[i], predicate)
if !gc.canBeDeleted(ctx, resource.GroupVersionKind()) {
continue
}
canBeDeleted, err := predicate(ctx, resource)
if err != nil { if err != nil {
return 0, err return 0, err
} }
if ok {
deleted++
}
}
}
return deleted, nil
}
func (gc *GC) delete(
ctx context.Context,
c *client.Client,
resource unstructured.Unstructured,
predicate func(context.Context, unstructured.Unstructured) (bool, error),
) (bool, error) {
if !gc.canBeDeleted(ctx, resource.GroupVersionKind()) {
return false, nil
}
canBeDeleted, err := predicate(ctx, resource)
if err != nil {
return false, err
}
if !canBeDeleted { if !canBeDeleted {
continue return false, err
} }
gc.l.Info("deleting", "ref", resources.Ref(&resource)) gc.l.Info("deleting", "ref", resources.Ref(&resource))
@ -113,11 +131,11 @@ func (gc *GC) deleteEachOf(
err = c.Delete(ctx, &resource, ctrlCli.PropagationPolicy(metav1.DeletePropagationForeground)) err = c.Delete(ctx, &resource, ctrlCli.PropagationPolicy(metav1.DeletePropagationForeground))
if err != nil { if err != nil {
// The resource may have already been deleted // The resource may have already been deleted
if !k8serrors.IsNotFound(err) { if k8serrors.IsNotFound(err) {
continue return true, nil
} }
return 0, fmt.Errorf( return false, fmt.Errorf(
"cannot delete resources gvk:%s, namespace: %s, name: %s, err: %w", "cannot delete resources gvk:%s, namespace: %s, name: %s, err: %w",
resource.GroupVersionKind().String(), resource.GroupVersionKind().String(),
resource.GetNamespace(), resource.GetNamespace(),
@ -128,11 +146,7 @@ func (gc *GC) deleteEachOf(
gc.l.Info("deleted", "ref", resources.Ref(&resource)) gc.l.Info("deleted", "ref", resources.Ref(&resource))
deleted++ return true, nil
}
}
return deleted, nil
} }
func (gc *GC) canBeDeleted(_ context.Context, gvk schema.GroupVersionKind) bool { func (gc *GC) canBeDeleted(_ context.Context, gvk schema.GroupVersionKind) bool {
@ -143,6 +157,7 @@ func (gc *GC) canBeDeleted(_ context.Context, gvk schema.GroupVersionKind) bool
return true return true
} }
//nolint:cyclop
func (gc *GC) computeDeletableTypes(ctx context.Context, c *client.Client, ns string) error { func (gc *GC) computeDeletableTypes(ctx context.Context, c *client.Client, ns string) error {
// Rate limit to avoid Discovery and SelfSubjectRulesReview requests at every reconciliation. // Rate limit to avoid Discovery and SelfSubjectRulesReview requests at every reconciliation.
if !gc.limiter.Allow() { if !gc.limiter.Allow() {

View File

@ -76,7 +76,7 @@ type BaseReconciler[T controller.ResourceObject] struct {
Client ctrlClient.Client Client ctrlClient.Client
} }
//nolint:forcetypeassert,wrapcheck,nestif //nolint:forcetypeassert,wrapcheck,nestif,cyclop
func (s *BaseReconciler[T]) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { func (s *BaseReconciler[T]) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
res := reflect.New(reflect.TypeOf(*new(T)).Elem()).Interface().(T) res := reflect.New(reflect.TypeOf(*new(T)).Elem()).Interface().(T)
if err := s.Client.Get(ctx, req.NamespacedName, res); err != nil { if err := s.Client.Get(ctx, req.NamespacedName, res); err != nil {

View File

@ -13,6 +13,7 @@ import (
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
) )
//nolint:cyclop
func runCleanup(t Test, in runtime.Object) error { func runCleanup(t Test, in runtime.Object) error {
un, err := resources.ToUnstructured(t.Client().Scheme(), in) un, err := resources.ToUnstructured(t.Client().Scheme(), in)
if err != nil { if err != nil {