Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cmd/cluster-node-tuning-operator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,13 +225,13 @@ func removePerformanceOLMOperator(cfg *rest.Config) error {
}

performanceOperatorCSVs, err := paocontroller.ListPerformanceOperatorCSVs(k8sclient, options, paginationLimit, performanceOperatorDeploymentName)
if err != nil {
if err != nil && !util.IsNoMatchError(err) {
return err
}

subscriptions := &olmv1alpha1.SubscriptionList{}
if err := k8sclient.List(context.TODO(), subscriptions); err != nil {
if !errors.IsNotFound(err) {
if !errors.IsNotFound(err) && !util.IsNoMatchError(err) {
return err
}
}
Expand Down
24 changes: 24 additions & 0 deletions pkg/util/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package util

import (
"errors"

"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/client-go/discovery"
)

// IsNoMatchError checks if error is for a non existant resource, there is a meaningful difference between a
// resource type not existing on the cluster as a whole versus an individual resource not being found.
//
// Example:
// OLM can be an optional operator, when the OLM resources do not exist, the returned
// error is a discovery error of meta.NoResourceMatchError.
//
// A bug is present in controller-runtime@v0.16.1 and older where the returned error type is a DiscoveryFailedError
// this was fixed in https://github.com/kubernetes-sigs/controller-runtime/pull/2472 and versions of controller-runtime@v0.16.2
// going forward will return the meta.NoResourceMatchError error. Here we check if either one is true.
func IsNoMatchError(err error) bool {
// We use errors.As instead of discovery.IsGroupDiscoveryFailedError because it Unwraps errors.
_err := &discovery.ErrGroupDiscoveryFailed{}
return meta.IsNoMatchError(err) || errors.As(err, &_err)
}
81 changes: 81 additions & 0 deletions pkg/util/errors_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package util

import (
"errors"
"fmt"
"testing"

apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/discovery"
)

func mockAPIStatusError(reason metav1.StatusReason, code int) *apierrors.StatusError {
return &apierrors.StatusError{ErrStatus: metav1.Status{
Reason: reason,
Code: int32(code),
}}
}

func TestIsNoMatchError(t *testing.T) {
defaultErr := discovery.ErrGroupDiscoveryFailed{
Groups: map[schema.GroupVersion]error{
{
Group: "apps",
Version: "v1",
}: fmt.Errorf("resource does not exist"),
},
}

testCases := []struct {
desc string
err error
expectedMatch bool
}{
{
desc: "should match discovery.ErrGroupDiscoveryFailed",
err: &defaultErr,
expectedMatch: true,
},
{
desc: "should match meta.NoResourceMatchError",
err: &meta.NoResourceMatchError{},
expectedMatch: true,
},
{
desc: "should unwrap error tree and match discovery.ErrGroupDiscoveryFailed",
err: fmt.Errorf("wrapped error %w", fmt.Errorf("inner %w", &defaultErr)),
expectedMatch: true,
},
{
desc: "should unwrap error tree and match meta.NoResourceMatchError",
err: fmt.Errorf("wrapped error %w", fmt.Errorf("inner %w", &meta.NoResourceMatchError{})),
expectedMatch: true,
},
{
desc: "should not match regular error",
err: errors.New("some other error"),
expectedMatch: false,
},
{
desc: "should not match on api error: NotFound",
err: mockAPIStatusError(metav1.StatusReasonNotFound, 404),
expectedMatch: false,
},
{
desc: "should not match on api error: Gone",
err: mockAPIStatusError(metav1.StatusReasonGone, 410),
expectedMatch: false,
},
}

for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
if IsNoMatchError(tc.err) != tc.expectedMatch {
t.Errorf("error did not match expected: %T", tc.err)
}
})
}
}