diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..0c7c8d6 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,14 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + commit-message: + prefix: ":seedling:" + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "daily" + commit-message: + prefix: ":seedling:" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aae6ed9..3bfc080 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,12 +12,12 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 with: go-version-file: "go.mod" - run: make test - - uses: codecov/codecov-action@v3 + - uses: codecov/codecov-action@v4 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: @@ -27,23 +27,23 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 with: go-version-file: "go.mod" - - uses: golangci/golangci-lint-action@v3 + - uses: golangci/golangci-lint-action@v4 with: - version: v1.51 + version: v1.57 args: --timeout 5m go-apidiff: if: github.event_name == 'pull_request' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: actions/setup-go@v4 + - uses: actions/setup-go@v5 with: go-version-file: "go.mod" - uses: joelanford/go-apidiff@main @@ -51,5 +51,5 @@ jobs: license-check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: make check-license diff --git a/.golangci.yml b/.golangci.yml index 54d05e5..749e483 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,36 +1,78 @@ -issues: - # don't skip warning about doc comments - # don't exclude the default set of lint - exclude-use-default: false - # restore some of the defaults - # (fill in the rest as needed) - exclude-rules: - - linters: [errcheck] - text: "Error return value of .((os\\.)?std(out|err)\\..*|.*Close|.*Flush|os\\.Remove(All)?|.*printf?|os\\.(Un)?Setenv). is not checked" +run: + # Default timeout is 1m, up to give more room + timeout: 4m + linters: - disable-all: true enable: - - nakedret - - interfacer - - varcheck - - deadcode - - structcheck - - misspell - - maligned - - ineffassign - - goconst - - goimports - - errcheck - - unparam - - golint - - staticcheck - - gosimple - - unused - - govet - - typecheck - - gocyclo - - gofmt - - dupl + - asciicheck + - bodyclose + - errorlint + - ginkgolinter + - gofmt + - goimports + - gosec + - importas + - misspell + - nestif + - nonamedreturns + - prealloc + - revive + - stylecheck + - tparallel + - unconvert + - unparam + - unused + - whitespace -run: - deadline: 5m +linters-settings: + errorlint: + errorf: false + + importas: + alias: + - pkg: k8s.io/apimachinery/pkg/apis/meta/v1 + alias: metav1 + - pkg: k8s.io/apimachinery/pkg/api/errors + alias: apierrors + - pkg: k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1 + alias: apiextensionsv1 + - pkg: k8s.io/apimachinery/pkg/util/runtime + alias: utilruntime + - pkg: "^k8s\\.io/api/([^/]+)/(v[^/]+)$" + alias: $1$2 + - pkg: sigs.k8s.io/controller-runtime + alias: ctrl + + goimports: + local-prefixes: github.com/operator-framework/operator-lib + + revive: + ignore-generated-header: false + severity: warning + confidence: 0.8 + rules: + - name: blank-imports + - name: context-as-argument + - name: context-keys-type + - name: error-return + - name: error-strings + - name: error-naming + - name: exported + - name: increment-decrement + - name: var-naming + - name: var-declaration + - name: package-comments + - name: range + - name: receiver-naming + - name: time-naming + - name: unexported-return + - name: indent-error-flow + - name: errorf + - name: empty-block + - name: superfluous-else + - name: unused-parameter + - name: unreachable-code + - name: redefines-builtin-id + +output: + format: tab diff --git a/OWNERS b/OWNERS index 438c4d9..002a606 100644 --- a/OWNERS +++ b/OWNERS @@ -1,5 +1,4 @@ approvers: - - asmacdo - camilamacedo86 - everettraven - jmrodri @@ -9,7 +8,6 @@ approvers: - varshaprasad96 - rashmigottipati reviewers: - - asmacdo - camilamacedo86 - everettraven - jmrodri diff --git a/conditions/conditions_test.go b/conditions/conditions_test.go index a9001f9..581b626 100644 --- a/conditions/conditions_test.go +++ b/conditions/conditions_test.go @@ -64,25 +64,21 @@ var _ = Describe("Condition", func() { } // Create Operator Condition - err := os.Setenv(operatorCondEnvVar, "operator-condition-test") - Expect(err).NotTo(HaveOccurred()) + Expect(os.Setenv(operatorCondEnvVar, "operator-condition-test")).To(Succeed()) readNamespace = func() (string, error) { return ns, nil } // create a new client sch := runtime.NewScheme() - err = apiv2.AddToScheme(sch) - Expect(err).NotTo(HaveOccurred()) + Expect(apiv2.AddToScheme(sch)).To(Succeed()) cl = fake.NewClientBuilder().WithScheme(sch).WithStatusSubresource(operatorCond).Build() // create an operator Condition resource - err = cl.Create(ctx, operatorCond) - Expect(err).NotTo(HaveOccurred()) + Expect(cl.Create(ctx, operatorCond)).To(Succeed()) // Update its status - err = cl.Status().Update(ctx, operatorCond) - Expect(err).NotTo(HaveOccurred()) + Expect(cl.Status().Update(ctx, operatorCond)).To(Succeed()) }) AfterEach(func() { @@ -107,14 +103,12 @@ var _ = Describe("Condition", func() { Expect(err).NotTo(HaveOccurred()) con, err := c.Get(ctx) - Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(ContainSubstring(fmt.Sprintf("conditionType %v not found", conditionBar)))) Expect(con).To(BeNil()) - Expect(err.Error()).To(ContainSubstring(fmt.Sprintf("conditionType %v not found", conditionBar))) }) It("should error when operator Condition is not present in cluster", func() { - err := os.Setenv(operatorCondEnvVar, "NON_EXISTING_COND") - Expect(err).NotTo(HaveOccurred()) + Expect(os.Setenv(operatorCondEnvVar, "NON_EXISTING_COND")).To(Succeed()) By("setting the status of a new condition") c, err := NewCondition(cl, conditionFoo) @@ -131,13 +125,11 @@ var _ = Describe("Condition", func() { By("setting the status of an existing condition") c, err := NewCondition(cl, conditionFoo) Expect(err).NotTo(HaveOccurred()) - err = c.Set(ctx, metav1.ConditionFalse, WithReason("not_in_foo_state"), WithMessage("test")) - Expect(err).NotTo(HaveOccurred()) + Expect(c.Set(ctx, metav1.ConditionFalse, WithReason("not_in_foo_state"), WithMessage("test"))).To(Succeed()) By("fetching the condition from cluster") op := &apiv2.OperatorCondition{} - err = cl.Get(ctx, objKey, op) - Expect(err).NotTo(HaveOccurred()) + Expect(cl.Get(ctx, objKey, op)).To(Succeed()) By("checking if the condition has been updated") res := op.Spec.Conditions[0] @@ -150,22 +142,19 @@ var _ = Describe("Condition", func() { By("setting the status of a new condition") c, err := NewCondition(cl, conditionBar) Expect(err).NotTo(HaveOccurred()) - err = c.Set(ctx, metav1.ConditionTrue, WithReason("in_bar_state"), WithMessage("test")) - Expect(err).NotTo(HaveOccurred()) + Expect(c.Set(ctx, metav1.ConditionTrue, WithReason("in_bar_state"), WithMessage("test"))).To(Succeed()) By("fetching the condition from cluster") op := &apiv2.OperatorCondition{} - err = cl.Get(ctx, objKey, op) - Expect(err).NotTo(HaveOccurred()) + Expect(cl.Get(ctx, objKey, op)).To(Succeed()) By("checking if the condition has been updated") res := op.Spec.Conditions - Expect(len(res)).To(BeEquivalentTo(2)) + Expect(res).To(HaveLen(2)) Expect(meta.IsStatusConditionTrue(res, string(conditionBar))).To(BeTrue()) }) It("should error when operator Condition is not present in cluster", func() { - err := os.Setenv(operatorCondEnvVar, "NON_EXISTING_COND") - Expect(err).NotTo(HaveOccurred()) + Expect(os.Setenv(operatorCondEnvVar, "NON_EXISTING_COND")).To(Succeed()) By("setting the status of a new condition") c, err := NewCondition(cl, conditionBar) diff --git a/conditions/factory_test.go b/conditions/factory_test.go index fdb339f..5973a3a 100644 --- a/conditions/factory_test.go +++ b/conditions/factory_test.go @@ -36,8 +36,7 @@ var _ = Describe("NewCondition", func() { var cl client.Client BeforeEach(func() { sch := runtime.NewScheme() - err := apiv2.AddToScheme(sch) - Expect(err).NotTo(HaveOccurred()) + Expect(apiv2.AddToScheme(sch)).To(Succeed()) cl = fake.NewClientBuilder().WithScheme(sch).Build() }) @@ -56,8 +55,7 @@ var _ = Describe("InClusterFactory", func() { BeforeEach(func() { sch := runtime.NewScheme() - err := apiv2.AddToScheme(sch) - Expect(err).NotTo(HaveOccurred()) + Expect(apiv2.AddToScheme(sch)).To(Succeed()) cl = fake.NewClientBuilder().WithScheme(sch).Build() f = InClusterFactory{cl} }) @@ -73,8 +71,7 @@ var _ = Describe("InClusterFactory", func() { func testNewCondition(fn func(apiv2.ConditionType) (Condition, error)) { It("should create a new condition", func() { - err := os.Setenv(operatorCondEnvVar, "test-operator-condition") - Expect(err).NotTo(HaveOccurred()) + Expect(os.Setenv(operatorCondEnvVar, "test-operator-condition")).To(Succeed()) readNamespace = func() (string, error) { return "default", nil } @@ -85,8 +82,7 @@ func testNewCondition(fn func(apiv2.ConditionType) (Condition, error)) { }) It("should error when namespacedName cannot be found", func() { - err := os.Unsetenv(operatorCondEnvVar) - Expect(err).NotTo(HaveOccurred()) + Expect(os.Unsetenv(operatorCondEnvVar)).To(Succeed()) c, err := fn(conditionFoo) Expect(err).To(HaveOccurred()) @@ -96,32 +92,27 @@ func testNewCondition(fn func(apiv2.ConditionType) (Condition, error)) { func testGetNamespacedName(fn func() (*types.NamespacedName, error)) { It("should error when name of the operator condition cannot be found", func() { - err := os.Unsetenv(operatorCondEnvVar) - Expect(err).NotTo(HaveOccurred()) + Expect(os.Unsetenv(operatorCondEnvVar)).To(Succeed()) objKey, err := fn() - Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(ContainSubstring("could not determine operator condition name"))) Expect(objKey).To(BeNil()) - Expect(err.Error()).To(ContainSubstring("could not determine operator condition name")) }) It("should error when object namespace cannot be found", func() { - err := os.Setenv(operatorCondEnvVar, "test") - Expect(err).NotTo(HaveOccurred()) + Expect(os.Setenv(operatorCondEnvVar, "test")).To(Succeed()) readNamespace = func() (string, error) { return "", os.ErrNotExist } objKey, err := fn() - Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(ContainSubstring("get operator condition namespace: file does not exist"))) Expect(objKey).To(BeNil()) - Expect(err.Error()).To(ContainSubstring("get operator condition namespace: file does not exist")) }) It("should return the right namespaced name from SA namespace file", func() { - err := os.Setenv(operatorCondEnvVar, "test") - Expect(err).NotTo(HaveOccurred()) + Expect(os.Setenv(operatorCondEnvVar, "test")).To(Succeed()) readNamespace = func() (string, error) { return "testns", nil @@ -135,6 +126,5 @@ func testGetNamespacedName(fn func() (*types.NamespacedName, error)) { } func deleteCondition(ctx context.Context, client client.Client, obj client.Object) { - err := client.Delete(ctx, obj) - Expect(err).NotTo(HaveOccurred()) + Expect(client.Delete(ctx, obj)).To(Succeed()) } diff --git a/go.mod b/go.mod index 3653fef..506c50e 100644 --- a/go.mod +++ b/go.mod @@ -1,72 +1,71 @@ module github.com/operator-framework/operator-lib -go 1.20 +go 1.21 require ( - github.com/go-logr/logr v1.2.4 - github.com/onsi/ginkgo/v2 v2.11.0 - github.com/onsi/gomega v1.27.10 - github.com/operator-framework/api v0.20.1-0.20240109180431-9ffba44ad7ed - github.com/prometheus/client_golang v1.16.0 - github.com/prometheus/client_model v0.4.0 - k8s.io/api v0.28.5 - k8s.io/apimachinery v0.28.5 - k8s.io/client-go v0.28.5 - k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 - sigs.k8s.io/controller-runtime v0.16.3 + github.com/go-logr/logr v1.4.1 + github.com/onsi/ginkgo/v2 v2.17.1 + github.com/onsi/gomega v1.32.0 + github.com/operator-framework/api v0.23.0 + github.com/prometheus/client_golang v1.19.0 + github.com/prometheus/client_model v0.6.1 + k8s.io/api v0.29.2 + k8s.io/apimachinery v0.29.2 + k8s.io/client-go v0.29.2 + k8s.io/utils v0.0.0-20240102154912-e7106e64919e + sigs.k8s.io/controller-runtime v0.17.2 ) require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/emicklei/go-restful/v3 v3.11.2 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect - github.com/evanphx/json-patch/v5 v5.6.0 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.22.3 // indirect + github.com/evanphx/json-patch/v5 v5.8.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/go-openapi/jsonpointer v0.20.2 // indirect + github.com/go-openapi/jsonreference v0.20.4 // indirect + github.com/go-openapi/swag v0.22.9 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20230510103437-eeec1cb781c3 // indirect - github.com/google/uuid v1.3.1 // indirect - github.com/imdario/mergo v0.3.12 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/imdario/mergo v0.3.16 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.10.1 // indirect + github.com/prometheus/common v0.48.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.11.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/term v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect - golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.9.3 // indirect + golang.org/x/exp v0.0.0-20240213143201-ec583247a57a // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/oauth2 v0.17.0 // indirect + golang.org/x/sys v0.17.0 // indirect + golang.org/x/term v0.17.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.18.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.31.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.28.5 // indirect - k8s.io/component-base v0.28.5 // indirect - k8s.io/klog/v2 v2.100.1 // indirect - k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect + k8s.io/apiextensions-apiserver v0.29.2 // indirect + k8s.io/component-base v0.29.2 // indirect + k8s.io/klog/v2 v2.120.1 // indirect + k8s.io/kube-openapi v0.0.0-20240221221325-2ac9dc51f3f1 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index f0edac1..2191f29 100644 --- a/go.sum +++ b/go.sum @@ -2,70 +2,64 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.11.2 h1:1onLa9DcsMYO9P+CXaL0dStDqQ2EHHXLiz+BtnqkLAU= +github.com/emicklei/go-restful/v3 v3.11.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= -github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= -github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/evanphx/json-patch/v5 v5.8.0 h1:lRj6N9Nci7MvzrXuX6HFzU8XjmhPiXPlsKEy1u0KQro= +github.com/evanphx/json-patch/v5 v5.8.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= +github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= +github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= +github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= +github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4= +github.com/go-openapi/swag v0.22.9 h1:XX2DssF+mQKM2DHsbgZK74y/zj4mo9I99+89xUmuZCE= +github.com/go-openapi/swag v0.22.9/go.mod h1:3/OXnFfnMAwBD099SwYRk7GD3xOrr1iL7d/XNLXVVwE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20230510103437-eeec1cb781c3 h1:2XF1Vzq06X+inNqgJ9tRnGuw+ZVCB3FazXODD6JE1R8= github.com/google/pprof v0.0.0-20230510103437-eeec1cb781c3/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= -github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -73,129 +67,137 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= -github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= -github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= -github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= -github.com/operator-framework/api v0.20.1-0.20240109180431-9ffba44ad7ed h1:9EQ9DB4r4fqK4kJ1Qs3+YogEt70fhJ9k7PSp/ps0m7k= -github.com/operator-framework/api v0.20.1-0.20240109180431-9ffba44ad7ed/go.mod h1:vt/GSfAnjulnMva2kreNsUBYA3ftJRKwrxJLqTY/yc4= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8= +github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= +github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk= +github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg= +github.com/operator-framework/api v0.23.0 h1:kHymOwcHBpBVujT49SKOCd4EVG7Odwj4wl3NbOR2LLA= +github.com/operator-framework/api v0.23.0/go.mod h1:oKcFOz+Xc1UhMi2Pzcp6qsO7wjS4r+yP7EQprQBXrfM= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= -github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= -github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= +github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE= +golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= -golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= +golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM= -golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= +golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.28.5 h1:XIPNr3nBgTEaCdEiwZ+dXaO9SB4NeTOZ2pNDRrFgfb4= -k8s.io/api v0.28.5/go.mod h1:98zkTCc60iSnqqCIyCB1GI7PYDiRDYTSfL0PRIxpM4c= -k8s.io/apiextensions-apiserver v0.28.5 h1:YKW9O9T/0Gkyl6LTFDLIhCbouSRh+pHt2vMLB38Snfc= -k8s.io/apiextensions-apiserver v0.28.5/go.mod h1:7p7TQ0X9zCJLNFlOTi5dncAi2dkPsdsrcvu5ILa7PEk= -k8s.io/apimachinery v0.28.5 h1:EEj2q1qdTcv2p5wl88KavAn3VlFRjREgRu8Sm/EuMPY= -k8s.io/apimachinery v0.28.5/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg= -k8s.io/client-go v0.28.5 h1:6UNmc33vuJhh3+SAOEKku3QnKa+DtPKGnhO2MR0IEbk= -k8s.io/client-go v0.28.5/go.mod h1:+pt086yx1i0HAlHzM9S+RZQDqdlzuXFl4hY01uhpcpA= -k8s.io/component-base v0.28.5 h1:uFCW7USa8Fpme8dVtn2ZrdVaUPBRDwYJ+kNrV9OO1Cc= -k8s.io/component-base v0.28.5/go.mod h1:gw2d8O28okS9RrsPuJnD2mFl2It0HH9neHiGi2xoXcY= -k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= -k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= -k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= -k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/controller-runtime v0.16.3 h1:2TuvuokmfXvDUamSx1SuAOO3eTyye+47mJCigwG62c4= -sigs.k8s.io/controller-runtime v0.16.3/go.mod h1:j7bialYoSn142nv9sCOJmQgDXQXxnroFU4VnX/brVJ0= +k8s.io/api v0.29.2 h1:hBC7B9+MU+ptchxEqTNW2DkUosJpp1P+Wn6YncZ474A= +k8s.io/api v0.29.2/go.mod h1:sdIaaKuU7P44aoyyLlikSLayT6Vb7bvJNCX105xZXY0= +k8s.io/apiextensions-apiserver v0.29.2 h1:UK3xB5lOWSnhaCk0RFZ0LUacPZz9RY4wi/yt2Iu+btg= +k8s.io/apiextensions-apiserver v0.29.2/go.mod h1:aLfYjpA5p3OwtqNXQFkhJ56TB+spV8Gc4wfMhUA3/b8= +k8s.io/apimachinery v0.29.2 h1:EWGpfJ856oj11C52NRCHuU7rFDwxev48z+6DSlGNsV8= +k8s.io/apimachinery v0.29.2/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU= +k8s.io/client-go v0.29.2 h1:FEg85el1TeZp+/vYJM7hkDlSTFZ+c5nnK44DJ4FyoRg= +k8s.io/client-go v0.29.2/go.mod h1:knlvFZE58VpqbQpJNbCbctTVXcd35mMyAAwBdpt4jrA= +k8s.io/component-base v0.29.2 h1:lpiLyuvPA9yV1aQwGLENYyK7n/8t6l3nn3zAtFTJYe8= +k8s.io/component-base v0.29.2/go.mod h1:BfB3SLrefbZXiBfbM+2H1dlat21Uewg/5qtKOl8degM= +k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= +k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20240221221325-2ac9dc51f3f1 h1:rtdnaWfP40MTKv7izH81gkWpZB45pZrwIxyZdPSn1mI= +k8s.io/kube-openapi v0.0.0-20240221221325-2ac9dc51f3f1/go.mod h1:Pa1PvrP7ACSkuX6I7KYomY6cmMA0Tx86waBhDUgoKPw= +k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ= +k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/controller-runtime v0.17.2 h1:FwHwD1CTUemg0pW2otk7/U5/i5m2ymzvOXdbeGOUvw0= +sigs.k8s.io/controller-runtime v0.17.2/go.mod h1:+MngTvIQQQhfXtwfdGw/UOQ/aIaqsYywfCINOtwMO/s= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/handler/enqueue_annotation.go b/handler/enqueue_annotation.go index b5798c3..fe882d5 100644 --- a/handler/enqueue_annotation.go +++ b/handler/enqueue_annotation.go @@ -164,7 +164,7 @@ func SetOwnerAnnotations(owner, object client.Object) error { ownerGK := owner.GetObjectKind().GroupVersionKind().GroupKind() if ownerGK.Kind == "" { - return fmt.Errorf("Owner %s Kind not found, cannot call SetOwnerAnnotations", owner.GetName()) + return fmt.Errorf("owner %s Kind not found, cannot call SetOwnerAnnotations", owner.GetName()) } annotations := object.GetAnnotations() diff --git a/handler/enqueue_annotation_test.go b/handler/enqueue_annotation_test.go index ba32bda..8835aa9 100644 --- a/handler/enqueue_annotation_test.go +++ b/handler/enqueue_annotation_test.go @@ -56,8 +56,7 @@ var _ = Describe("EnqueueRequestForAnnotation", func() { podOwner.SetGroupVersionKind(schema.GroupVersionKind{Group: "", Kind: "Pod"}) - err := SetOwnerAnnotations(podOwner, pod) - Expect(err).To(BeNil()) + Expect(SetOwnerAnnotations(podOwner, pod)).To(Succeed()) instance = EnqueueRequestForAnnotation{ Type: schema.GroupKind{ Group: "", @@ -92,8 +91,7 @@ var _ = Describe("EnqueueRequestForAnnotation", func() { }, } - err := SetOwnerAnnotations(podOwner, repl) - Expect(err).To(BeNil()) + Expect(SetOwnerAnnotations(podOwner, repl)).To(Succeed()) evt := event.CreateEvent{ Object: repl, @@ -248,8 +246,7 @@ var _ = Describe("EnqueueRequestForAnnotation", func() { newPod.Name = pod.Name + "2" newPod.Namespace = pod.Namespace + "2" - err := SetOwnerAnnotations(podOwner, pod) - Expect(err).To(BeNil()) + Expect(SetOwnerAnnotations(podOwner, pod)).To(Succeed()) evt := event.UpdateEvent{ ObjectOld: pod, @@ -337,8 +334,7 @@ var _ = Describe("EnqueueRequestForAnnotation", func() { newPod.Name = pod.Name + "2" newPod.Namespace = pod.Namespace + "2" - err := SetOwnerAnnotations(podOwner, pod) - Expect(err).To(BeNil()) + Expect(SetOwnerAnnotations(podOwner, pod)).To(Succeed()) var podOwner2 = &corev1.Pod{ ObjectMeta: metav1.ObjectMeta{ @@ -348,8 +344,7 @@ var _ = Describe("EnqueueRequestForAnnotation", func() { } podOwner2.SetGroupVersionKind(schema.GroupVersionKind{Group: "", Kind: "Pod"}) - err = SetOwnerAnnotations(podOwner2, newPod) - Expect(err).To(BeNil()) + Expect(SetOwnerAnnotations(podOwner2, newPod)).To(Succeed()) evt := event.UpdateEvent{ ObjectOld: pod, @@ -389,8 +384,7 @@ var _ = Describe("EnqueueRequestForAnnotation", func() { }, } - err := SetOwnerAnnotations(podOwner, nd) - Expect(err).To(BeNil()) + Expect(SetOwnerAnnotations(podOwner, nd)).To(Succeed()) expected := map[string]string{ "my-test-annotation": "should-keep", @@ -398,7 +392,7 @@ var _ = Describe("EnqueueRequestForAnnotation", func() { TypeAnnotation: schema.GroupKind{Group: "", Kind: "Pod"}.String(), } - Expect(len(nd.GetAnnotations())).To(Equal(3)) + Expect(nd.GetAnnotations()).To(HaveLen(3)) Expect(nd.GetAnnotations()).To(Equal(expected)) }) It("should return error when the owner Kind is not present", func() { @@ -409,8 +403,7 @@ var _ = Describe("EnqueueRequestForAnnotation", func() { } podOwner.SetGroupVersionKind(schema.GroupVersionKind{Group: "Pod", Kind: ""}) - err := SetOwnerAnnotations(podOwner, nd) - Expect(err).NotTo(BeNil()) + Expect(SetOwnerAnnotations(podOwner, nd)).ToNot(Succeed()) }) It("should return an error when the owner Name is not set", func() { nd := &corev1.Node{ @@ -426,8 +419,7 @@ var _ = Describe("EnqueueRequestForAnnotation", func() { } ownerNew.SetGroupVersionKind(schema.GroupVersionKind{Group: "Pod", Kind: ""}) - err := SetOwnerAnnotations(ownerNew, nd) - Expect(err).NotTo(BeNil()) + Expect(SetOwnerAnnotations(ownerNew, nd)).ToNot(Succeed()) }) }) }) diff --git a/handler/example_test.go b/handler/example_test.go index b888c46..a0ff195 100644 --- a/handler/example_test.go +++ b/handler/example_test.go @@ -18,14 +18,15 @@ import ( "context" "os" - "github.com/operator-framework/operator-lib/handler" - v1 "k8s.io/api/core/v1" + corev1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/client/config" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/manager/signals" "sigs.k8s.io/controller-runtime/pkg/reconcile" "sigs.k8s.io/controller-runtime/pkg/source" + + "github.com/operator-framework/operator-lib/handler" ) // This example applies the Pause handler to all incoming Pod events on a Pod controller. @@ -54,7 +55,7 @@ func ExampleNewPause() { if err != nil { os.Exit(1) } - if err := c.Watch(source.Kind(mgr.GetCache(), &v1.Pod{}), pause); err != nil { + if err := c.Watch(source.Kind(mgr.GetCache(), &corev1.Pod{}), pause); err != nil { os.Exit(1) } diff --git a/handler/instrumented_enqueue_object_test.go b/handler/instrumented_enqueue_object_test.go index 13a6653..946854b 100644 --- a/handler/instrumented_enqueue_object_test.go +++ b/handler/instrumented_enqueue_object_test.go @@ -17,8 +17,6 @@ package handler import ( "context" - "github.com/operator-framework/operator-lib/handler/internal/metrics" - . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/prometheus/client_golang/prometheus" @@ -30,6 +28,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller/controllertest" "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "github.com/operator-framework/operator-lib/handler/internal/metrics" ) var _ = Describe("InstrumentedEnqueueRequestForObject", func() { @@ -79,7 +79,7 @@ var _ = Describe("InstrumentedEnqueueRequestForObject", func() { // verify metrics gauges, err := registry.Gather() Expect(err).NotTo(HaveOccurred()) - Expect(len(gauges)).To(Equal(1)) + Expect(gauges).To(HaveLen(1)) assertMetrics(gauges[0], 1, []*corev1.Pod{pod}) }) }) @@ -114,7 +114,7 @@ var _ = Describe("InstrumentedEnqueueRequestForObject", func() { // verify metrics gauges, err := registry.Gather() Expect(err).NotTo(HaveOccurred()) - Expect(len(gauges)).To(Equal(0)) + Expect(gauges).To(BeEmpty()) }) }) Context("when a gauge does not exist", func() { @@ -139,7 +139,7 @@ var _ = Describe("InstrumentedEnqueueRequestForObject", func() { // verify metrics gauges, err := registry.Gather() Expect(err).NotTo(HaveOccurred()) - Expect(len(gauges)).To(Equal(0)) + Expect(gauges).To(BeEmpty()) }) }) @@ -174,7 +174,7 @@ var _ = Describe("InstrumentedEnqueueRequestForObject", func() { // verify metrics gauges, err := registry.Gather() Expect(err).NotTo(HaveOccurred()) - Expect(len(gauges)).To(Equal(1)) + Expect(gauges).To(HaveLen(1)) assertMetrics(gauges[0], 2, []*corev1.Pod{newpod, pod}) }) }) @@ -183,7 +183,7 @@ var _ = Describe("InstrumentedEnqueueRequestForObject", func() { It("should fill out map with values from given objects", func() { labelMap := getResourceLabels(pod) Expect(labelMap).ShouldNot(BeEmpty()) - Expect(len(labelMap)).To(Equal(5)) + Expect(labelMap).To(HaveLen(5)) Expect(labelMap["name"]).To(Equal(pod.GetObjectMeta().GetName())) Expect(labelMap["namespace"]).To(Equal(pod.GetObjectMeta().GetNamespace())) Expect(labelMap["group"]).To(Equal(pod.GetObjectKind().GroupVersionKind().Group)) @@ -195,28 +195,30 @@ var _ = Describe("InstrumentedEnqueueRequestForObject", func() { func assertMetrics(gauge *dto.MetricFamily, count int, pods []*corev1.Pod) { // need variables to compare the pointers - name := "name" - namespace := "namespace" - g := "group" - v := "version" - k := "kind" - - Expect(len(gauge.Metric)).To(Equal(count)) + const ( + name = "name" + namespace = "namespace" + g = "group" + v = "version" + k = "kind" + ) + + Expect(gauge.Metric).To(HaveLen(count)) for i := 0; i < count; i++ { Expect(*gauge.Metric[i].Gauge.Value).To(Equal(float64(pods[i].GetObjectMeta().GetCreationTimestamp().UTC().Unix()))) for _, l := range gauge.Metric[i].Label { - switch l.Name { - case &name: - Expect(l.Value).To(Equal(pods[i].GetObjectMeta().GetName())) - case &namespace: - Expect(l.Value).To(Equal(pods[i].GetObjectMeta().GetNamespace())) - case &g: - Expect(l.Value).To(Equal(pods[i].GetObjectKind().GroupVersionKind().Group)) - case &v: - Expect(l.Value).To(Equal(pods[i].GetObjectKind().GroupVersionKind().Version)) - case &k: - Expect(l.Value).To(Equal(pods[i].GetObjectKind().GroupVersionKind().Kind)) + switch *l.Name { + case name: + Expect(l.Value).To(HaveValue(Equal(pods[i].GetObjectMeta().GetName()))) + case namespace: + Expect(l.Value).To(HaveValue(Equal(pods[i].GetObjectMeta().GetNamespace()))) + case g: + Expect(l.Value).To(HaveValue(Equal(pods[i].GetObjectKind().GroupVersionKind().Group))) + case v: + Expect(l.Value).To(HaveValue(Equal(pods[i].GetObjectKind().GroupVersionKind().Version))) + case k: + Expect(l.Value).To(HaveValue(Equal(pods[i].GetObjectKind().GroupVersionKind().Kind))) } } } diff --git a/handler/pause.go b/handler/pause.go index 648aaa0..9ce2b4a 100644 --- a/handler/pause.go +++ b/handler/pause.go @@ -15,9 +15,9 @@ package handler import ( - "github.com/operator-framework/operator-lib/internal/annotation" - "sigs.k8s.io/controller-runtime/pkg/handler" + + "github.com/operator-framework/operator-lib/internal/annotation" ) // NewPause returns an event handler that filters out objects with a truthy "paused" annotation. diff --git a/internal/annotation/filter_test.go b/internal/annotation/filter_test.go index 03d309c..4e470b7 100644 --- a/internal/annotation/filter_test.go +++ b/internal/annotation/filter_test.go @@ -212,60 +212,60 @@ var _ = Describe("filter", func() { Expect(pred.Update(e)).To(BeTrue()) }) It("receives neither objects having any annotations", func() { - old, new := pod.DeepCopy(), pod.DeepCopy() + old, updated := pod.DeepCopy(), pod.DeepCopy() old.SetLabels(map[string]string{"id": "old"}) - new.SetLabels(map[string]string{"id": "new"}) - e = makeUpdateEventFor(old, new) + updated.SetLabels(map[string]string{"id": "updated"}) + e = makeUpdateEventFor(old, updated) Expect(pred.Update(e)).To(BeTrue()) hdlr.Update(ctx, e, q) - verifyQueueHasPod(q, new) + verifyQueueHasPod(q, updated) }) It("receives the new object with a registered key and false value", func() { - old, new := pod.DeepCopy(), pod.DeepCopy() + old, updated := pod.DeepCopy(), pod.DeepCopy() old.SetLabels(map[string]string{"id": "old"}) - new.SetLabels(map[string]string{"id": "new"}) - new.SetAnnotations(map[string]string{annotationKey: "false"}) - e = makeUpdateEventFor(old, new) + updated.SetLabels(map[string]string{"id": "updated"}) + updated.SetAnnotations(map[string]string{annotationKey: "false"}) + e = makeUpdateEventFor(old, updated) Expect(pred.Update(e)).To(BeTrue()) hdlr.Update(ctx, e, q) - verifyQueueHasPod(q, new) + verifyQueueHasPod(q, updated) }) It("receives the old object with a registered key and false value", func() { - old, new := pod.DeepCopy(), pod.DeepCopy() + old, updated := pod.DeepCopy(), pod.DeepCopy() old.SetLabels(map[string]string{"id": "old"}) - new.SetLabels(map[string]string{"id": "new"}) + updated.SetLabels(map[string]string{"id": "updated"}) old.SetAnnotations(map[string]string{annotationKey: "false"}) - e = makeUpdateEventFor(old, new) + e = makeUpdateEventFor(old, updated) Expect(pred.Update(e)).To(BeTrue()) hdlr.Update(ctx, e, q) - verifyQueueHasPod(q, new) + verifyQueueHasPod(q, updated) }) It("receives the new object with a non-registered key and true value", func() { - old, new := pod.DeepCopy(), pod.DeepCopy() + old, updated := pod.DeepCopy(), pod.DeepCopy() old.SetLabels(map[string]string{"id": "old"}) - new.SetLabels(map[string]string{"id": "new"}) - new.SetAnnotations(map[string]string{"my.app/foo": "true"}) - e = makeUpdateEventFor(old, new) + updated.SetLabels(map[string]string{"id": "updated"}) + updated.SetAnnotations(map[string]string{"my.app/foo": "true"}) + e = makeUpdateEventFor(old, updated) Expect(pred.Update(e)).To(BeTrue()) hdlr.Update(ctx, e, q) - verifyQueueHasPod(q, new) + verifyQueueHasPod(q, updated) }) It("receives the new object with a non-registered key and false value", func() { - old, new := pod.DeepCopy(), pod.DeepCopy() + old, updated := pod.DeepCopy(), pod.DeepCopy() old.SetLabels(map[string]string{"id": "old"}) - new.SetLabels(map[string]string{"id": "new"}) - new.SetAnnotations(map[string]string{"my.app/foo": "false"}) - e = makeUpdateEventFor(old, new) + updated.SetLabels(map[string]string{"id": "updated"}) + updated.SetAnnotations(map[string]string{"my.app/foo": "false"}) + e = makeUpdateEventFor(old, updated) Expect(pred.Update(e)).To(BeTrue()) hdlr.Update(ctx, e, q) - verifyQueueHasPod(q, new) + verifyQueueHasPod(q, updated) }) }) Context("returns false", func() { It("receives the new object with a registered key", func() { - old, new := pod.DeepCopy(), pod.DeepCopy() - new.SetAnnotations(map[string]string{annotationKey: "true"}) - e = makeUpdateEventFor(old, new) + old, updated := pod.DeepCopy(), pod.DeepCopy() + updated.SetAnnotations(map[string]string{annotationKey: "true"}) + e = makeUpdateEventFor(old, updated) Expect(pred.Update(e)).To(BeFalse()) hdlr.Update(ctx, e, q) verifyQueueEmpty(q) @@ -279,31 +279,31 @@ var _ = Describe("filter", func() { verifyQueueEmpty(q) }) It("receives both objects with a registered key", func() { - old, new := pod.DeepCopy(), pod.DeepCopy() - new.SetAnnotations(map[string]string{annotationKey: "true"}) + old, updated := pod.DeepCopy(), pod.DeepCopy() + updated.SetAnnotations(map[string]string{annotationKey: "true"}) old.SetAnnotations(map[string]string{annotationKey: "true"}) - e = makeUpdateEventFor(old, new) + e = makeUpdateEventFor(old, updated) Expect(pred.Update(e)).To(BeFalse()) hdlr.Update(ctx, e, q) verifyQueueEmpty(q) }) It("receives the old object with a registered key and false value, and new with true", func() { - old, new := pod.DeepCopy(), pod.DeepCopy() + old, updated := pod.DeepCopy(), pod.DeepCopy() old.SetLabels(map[string]string{"id": "old"}) - new.SetLabels(map[string]string{"id": "new"}) + updated.SetLabels(map[string]string{"id": "updated"}) old.SetAnnotations(map[string]string{annotationKey: "false"}) - new.SetAnnotations(map[string]string{annotationKey: "true"}) - e = makeUpdateEventFor(old, new) + updated.SetAnnotations(map[string]string{annotationKey: "true"}) + e = makeUpdateEventFor(old, updated) Expect(pred.Update(e)).To(BeFalse()) hdlr.Update(ctx, e, q) verifyQueueEmpty(q) }) It("receives the old object having no annotations, and new with a registered key and true value", func() { - old, new := pod.DeepCopy(), pod.DeepCopy() + old, updated := pod.DeepCopy(), pod.DeepCopy() old.SetLabels(map[string]string{"id": "old"}) - new.SetLabels(map[string]string{"id": "new"}) - new.SetAnnotations(map[string]string{annotationKey: "true"}) - e = makeUpdateEventFor(old, new) + updated.SetLabels(map[string]string{"id": "updated"}) + updated.SetAnnotations(map[string]string{annotationKey: "true"}) + e = makeUpdateEventFor(old, updated) Expect(pred.Update(e)).To(BeFalse()) hdlr.Update(ctx, e, q) verifyQueueEmpty(q) @@ -475,50 +475,50 @@ var _ = Describe("filter", func() { Expect(pred.Update(e)).To(BeFalse()) }) It("receives neither objects having any annotations", func() { - old, new := pod.DeepCopy(), pod.DeepCopy() + old, updated := pod.DeepCopy(), pod.DeepCopy() old.SetLabels(map[string]string{"id": "old"}) - new.SetLabels(map[string]string{"id": "new"}) - e = makeUpdateEventFor(old, new) + updated.SetLabels(map[string]string{"id": "updated"}) + e = makeUpdateEventFor(old, updated) Expect(pred.Update(e)).To(BeFalse()) hdlr.Update(ctx, e, q) verifyQueueEmpty(q) }) It("receives the new object with a registered key and false value", func() { - old, new := pod.DeepCopy(), pod.DeepCopy() + old, updated := pod.DeepCopy(), pod.DeepCopy() old.SetLabels(map[string]string{"id": "old"}) - new.SetLabels(map[string]string{"id": "new"}) - new.SetAnnotations(map[string]string{annotationKey: "false"}) - e = makeUpdateEventFor(old, new) + updated.SetLabels(map[string]string{"id": "updated"}) + updated.SetAnnotations(map[string]string{annotationKey: "false"}) + e = makeUpdateEventFor(old, updated) Expect(pred.Update(e)).To(BeFalse()) hdlr.Update(ctx, e, q) verifyQueueEmpty(q) }) It("receives the old object with a registered key and false value", func() { - old, new := pod.DeepCopy(), pod.DeepCopy() + old, updated := pod.DeepCopy(), pod.DeepCopy() old.SetLabels(map[string]string{"id": "old"}) - new.SetLabels(map[string]string{"id": "new"}) + updated.SetLabels(map[string]string{"id": "updated"}) old.SetAnnotations(map[string]string{annotationKey: "false"}) - e = makeUpdateEventFor(old, new) + e = makeUpdateEventFor(old, updated) Expect(pred.Update(e)).To(BeFalse()) hdlr.Update(ctx, e, q) verifyQueueEmpty(q) }) It("receives the new object with a non-registered key and true value", func() { - old, new := pod.DeepCopy(), pod.DeepCopy() + old, updated := pod.DeepCopy(), pod.DeepCopy() old.SetLabels(map[string]string{"id": "old"}) - new.SetLabels(map[string]string{"id": "new"}) - new.SetAnnotations(map[string]string{"my.app/foo": "true"}) - e = makeUpdateEventFor(old, new) + updated.SetLabels(map[string]string{"id": "updated"}) + updated.SetAnnotations(map[string]string{"my.app/foo": "true"}) + e = makeUpdateEventFor(old, updated) Expect(pred.Update(e)).To(BeFalse()) hdlr.Update(ctx, e, q) verifyQueueEmpty(q) }) It("receives the new object with a non-registered key and false value", func() { - old, new := pod.DeepCopy(), pod.DeepCopy() + old, updated := pod.DeepCopy(), pod.DeepCopy() old.SetLabels(map[string]string{"id": "old"}) - new.SetLabels(map[string]string{"id": "new"}) - new.SetAnnotations(map[string]string{"my.app/foo": "false"}) - e = makeUpdateEventFor(old, new) + updated.SetLabels(map[string]string{"id": "updated"}) + updated.SetAnnotations(map[string]string{"my.app/foo": "false"}) + e = makeUpdateEventFor(old, updated) Expect(pred.Update(e)).To(BeFalse()) hdlr.Update(ctx, e, q) verifyQueueEmpty(q) @@ -526,12 +526,12 @@ var _ = Describe("filter", func() { }) Context("returns true", func() { It("receives the new object with a registered key", func() { - old, new := pod.DeepCopy(), pod.DeepCopy() - new.SetAnnotations(map[string]string{annotationKey: "true"}) - e = makeUpdateEventFor(old, new) + old, updated := pod.DeepCopy(), pod.DeepCopy() + updated.SetAnnotations(map[string]string{annotationKey: "true"}) + e = makeUpdateEventFor(old, updated) Expect(pred.Update(e)).To(BeTrue()) hdlr.Update(ctx, e, q) - verifyQueueHasPod(q, new) + verifyQueueHasPod(q, updated) }) It("receives the old object with a registered key", func() { old := pod.DeepCopy() @@ -542,34 +542,34 @@ var _ = Describe("filter", func() { verifyQueueHasPod(q, old) }) It("receives both objects with a registered key", func() { - old, new := pod.DeepCopy(), pod.DeepCopy() - new.SetAnnotations(map[string]string{annotationKey: "true"}) + old, updated := pod.DeepCopy(), pod.DeepCopy() + updated.SetAnnotations(map[string]string{annotationKey: "true"}) old.SetAnnotations(map[string]string{annotationKey: "true"}) - e = makeUpdateEventFor(old, new) + e = makeUpdateEventFor(old, updated) Expect(pred.Update(e)).To(BeTrue()) hdlr.Update(ctx, e, q) - verifyQueueHasPod(q, new) + verifyQueueHasPod(q, updated) }) It("receives the old object with a registered key and false value, and new with true", func() { - old, new := pod.DeepCopy(), pod.DeepCopy() + old, updated := pod.DeepCopy(), pod.DeepCopy() old.SetLabels(map[string]string{"id": "old"}) - new.SetLabels(map[string]string{"id": "new"}) + updated.SetLabels(map[string]string{"id": "updated"}) old.SetAnnotations(map[string]string{annotationKey: "false"}) - new.SetAnnotations(map[string]string{annotationKey: "true"}) - e = makeUpdateEventFor(old, new) + updated.SetAnnotations(map[string]string{annotationKey: "true"}) + e = makeUpdateEventFor(old, updated) Expect(pred.Update(e)).To(BeTrue()) hdlr.Update(ctx, e, q) - verifyQueueHasPod(q, new) + verifyQueueHasPod(q, updated) }) It("receives the old object having no annotations, and new with a registered key and true value", func() { - old, new := pod.DeepCopy(), pod.DeepCopy() + old, updated := pod.DeepCopy(), pod.DeepCopy() old.SetLabels(map[string]string{"id": "old"}) - new.SetLabels(map[string]string{"id": "new"}) - new.SetAnnotations(map[string]string{annotationKey: "true"}) - e = makeUpdateEventFor(old, new) + updated.SetLabels(map[string]string{"id": "updated"}) + updated.SetAnnotations(map[string]string{annotationKey: "true"}) + e = makeUpdateEventFor(old, updated) Expect(pred.Update(e)).To(BeTrue()) hdlr.Update(ctx, e, q) - verifyQueueHasPod(q, new) + verifyQueueHasPod(q, updated) }) }) }) diff --git a/internal/annotation/suite_test.go b/internal/annotation/suite_test.go index 0c84711..5d7877c 100644 --- a/internal/annotation/suite_test.go +++ b/internal/annotation/suite_test.go @@ -28,23 +28,27 @@ func TestAnnotation(t *testing.T) { RunSpecs(t, "Annotation Suite") } -func makeCreateEventFor(obj client.Object) (e event.CreateEvent) { +func makeCreateEventFor(obj client.Object) event.CreateEvent { + var e event.CreateEvent e.Object = obj return e } -func makeUpdateEventFor(old, new client.Object) (e event.UpdateEvent) { +func makeUpdateEventFor(old, new client.Object) event.UpdateEvent { + var e event.UpdateEvent e.ObjectOld = old e.ObjectNew = new return e } -func makeDeleteEventFor(obj client.Object) (e event.DeleteEvent) { +func makeDeleteEventFor(obj client.Object) event.DeleteEvent { + var e event.DeleteEvent e.Object = obj return e } -func makeGenericEventFor(obj client.Object) (e event.GenericEvent) { +func makeGenericEventFor(obj client.Object) event.GenericEvent { + var e event.GenericEvent e.Object = obj return e } diff --git a/internal/utils/utils_test.go b/internal/utils/utils_test.go index 1c7e11c..b3bb7a1 100644 --- a/internal/utils/utils_test.go +++ b/internal/utils/utils_test.go @@ -38,7 +38,7 @@ var _ = Describe("Helpers test", func() { // test namespace, err := GetOperatorNamespace() - Expect(err).Should(BeNil()) + Expect(err).ShouldNot(HaveOccurred()) Expect(namespace).To(Equal("testnamespace")) }) It("should trim whitespace from namespace", func() { @@ -48,7 +48,7 @@ var _ = Describe("Helpers test", func() { // test namespace, err := GetOperatorNamespace() - Expect(err).Should(BeNil()) + Expect(err).ShouldNot(HaveOccurred()) Expect(namespace).To(Equal("testnamespace")) }) }) diff --git a/leader/leader.go b/leader/leader.go index 6b9c5c7..71a80b4 100644 --- a/leader/leader.go +++ b/leader/leader.go @@ -20,7 +20,6 @@ import ( "os" "time" - "github.com/operator-framework/operator-lib/internal/utils" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -28,6 +27,8 @@ import ( crclient "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/config" logf "sigs.k8s.io/controller-runtime/pkg/log" + + "github.com/operator-framework/operator-lib/internal/utils" ) // ErrNoNamespace indicates that a namespace could not be found for the current @@ -186,11 +187,19 @@ func Become(ctx context.Context, lockName string, opts ...Option) error { if err != nil { log.Error(err, "Leader pod could not be deleted.") } + case isPodPreempted(*leaderPod) && leaderPod.GetDeletionTimestamp() == nil: + log.Info("Operator pod with leader lock has been preempted.", "leader", leaderPod.Name) + log.Info("Deleting preempted leader.") + // Pod may not delete immediately, continue with backoff + err := config.Client.Delete(ctx, leaderPod) + if err != nil { + log.Error(err, "Leader pod could not be deleted.") + } case isNotReadyNode(ctx, config.Client, leaderPod.Spec.NodeName): log.Info("the status of the node where operator pod with leader lock was running has been 'notReady'") log.Info("Deleting the leader.") - //Mark the termainating status to the leaderPod and Delete the configmap lock + // Mark the termainating status to the leaderPod and Delete the configmap lock if err := deleteLeader(ctx, config.Client, leaderPod, existing); err != nil { return err } @@ -240,6 +249,12 @@ func isPodEvicted(pod corev1.Pod) bool { return podFailed && podEvicted } +func isPodPreempted(pod corev1.Pod) bool { + podFailed := pod.Status.Phase == corev1.PodFailed + podPreempted := pod.Status.Reason == "Preempting" + return podFailed && podPreempted +} + // getPod returns a Pod object that corresponds to the pod in which the code // is currently running. // It expects the environment variable POD_NAME to be set by the downwards API. @@ -259,11 +274,6 @@ func getPod(ctx context.Context, client crclient.Client, ns string) (*corev1.Pod return nil, err } - // .Get() clears the APIVersion and Kind, - // so we need to set them before returning the object. - pod.TypeMeta.APIVersion = "v1" - pod.TypeMeta.Kind = "Pod" - log.V(1).Info("Found Pod", "Pod.Namespace", ns, "Pod.Name", pod.Name) return pod, nil @@ -290,7 +300,6 @@ func isNotReadyNode(ctx context.Context, client crclient.Client, nodeName string } } return false - } func deleteLeader(ctx context.Context, client crclient.Client, leaderPod *corev1.Pod, existing *corev1.ConfigMap) error { diff --git a/leader/leader_test.go b/leader/leader_test.go index b1a1c2e..879b183 100644 --- a/leader/leader_test.go +++ b/leader/leader_test.go @@ -16,26 +16,31 @@ package leader import ( "context" - "errors" "os" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" crclient "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/client/interceptor" ) var _ = Describe("Leader election", func() { - Describe("Become", func() { - var ( - client crclient.Client - ) + var client crclient.Client BeforeEach(func() { client = fake.NewClientBuilder().WithObjects( &corev1.Pod{ + TypeMeta: metav1.TypeMeta{ + APIVersion: schema.GroupVersion{ + Group: corev1.SchemeGroupVersion.Group, + Version: corev1.SchemeGroupVersion.Version, + }.String(), + Kind: "Pod", + }, ObjectMeta: metav1.ObjectMeta{ Name: "leader-test", Namespace: "testns", @@ -49,6 +54,13 @@ var _ = Describe("Leader election", func() { }, }, &corev1.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + APIVersion: schema.GroupVersion{ + Group: corev1.SchemeGroupVersion.Group, + Version: corev1.SchemeGroupVersion.Version, + }.String(), + Kind: "ConfigMap", + }, ObjectMeta: metav1.ObjectMeta{ Name: "leader-test", Namespace: "testns", @@ -65,8 +77,7 @@ var _ = Describe("Leader election", func() { }) It("should return an error when POD_NAME is not set", func() { os.Unsetenv("POD_NAME") - err := Become(context.TODO(), "leader-test") - Expect(err).ShouldNot(BeNil()) + Expect(Become(context.TODO(), "leader-test")).ShouldNot(Succeed()) }) It("should return an ErrNoNamespace", func() { os.Setenv("POD_NAME", "leader-test") @@ -74,9 +85,7 @@ var _ = Describe("Leader election", func() { return "", ErrNoNamespace } err := Become(context.TODO(), "leader-test", WithClient(client)) - Expect(err).ShouldNot(BeNil()) - Expect(err).To(Equal(ErrNoNamespace)) - Expect(errors.Is(err, ErrNoNamespace)).To(Equal(true)) + Expect(err).Should(MatchError(ErrNoNamespace)) }) It("should not return an error", func() { os.Setenv("POD_NAME", "leader-test") @@ -84,42 +93,257 @@ var _ = Describe("Leader election", func() { return "testns", nil } - err := Become(context.TODO(), "leader-test", WithClient(client)) - Expect(err).Should(BeNil()) + Expect(Become(context.TODO(), "leader-test", WithClient(client))).To(Succeed()) + }) + It("should become leader when pod is evicted and rescheduled", func() { + evictedPodStatusClient := fake.NewClientBuilder().WithObjects( + &corev1.Pod{ + TypeMeta: metav1.TypeMeta{ + APIVersion: schema.GroupVersion{ + Group: corev1.SchemeGroupVersion.Group, + Version: corev1.SchemeGroupVersion.Version, + }.String(), + Kind: "Pod", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "leader-test-new", + Namespace: "testns", + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: "v1", + Kind: "Pod", + Name: "leader-test-new", + }, + }, + }, + }, + &corev1.Pod{ + TypeMeta: metav1.TypeMeta{ + APIVersion: schema.GroupVersion{ + Group: corev1.SchemeGroupVersion.Group, + Version: corev1.SchemeGroupVersion.Version, + }.String(), + Kind: "Pod", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "leader-test", + Namespace: "testns", + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: "v1", + Kind: "Pod", + Name: "leader-test", + }, + }, + }, + Status: corev1.PodStatus{ + Phase: corev1.PodFailed, + Reason: "Evicted", + }, + }, + &corev1.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + APIVersion: schema.GroupVersion{ + Group: corev1.SchemeGroupVersion.Group, + Version: corev1.SchemeGroupVersion.Version, + }.String(), + Kind: "ConfigMap", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "leader-test", + Namespace: "testns", + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: "v1", + Kind: "Pod", + Name: "leader-test", + }, + }, + }, + }, + ).WithInterceptorFuncs( + interceptor.Funcs{ + // Mock garbage collection of the ConfigMap when the Pod is deleted. + Delete: func(ctx context.Context, client crclient.WithWatch, obj crclient.Object, _ ...crclient.DeleteOption) error { + if obj.GetObjectKind() != nil && obj.GetObjectKind().GroupVersionKind().Kind == "Pod" && obj.GetName() == "leader-test" { + cm := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "leader-test", + Namespace: "testns", + }, + } + + err := client.Delete(ctx, cm) + if err != nil { + return err + } + } + return nil + }, + }, + ).Build() + + os.Setenv("POD_NAME", "leader-test-new") + readNamespace = func() (string, error) { + return "testns", nil + } + + Expect(Become(context.TODO(), "leader-test", WithClient(evictedPodStatusClient))).To(Succeed()) + }) + It("should become leader when pod is preempted and rescheduled", func() { + preemptedPodStatusClient := fake.NewClientBuilder().WithObjects( + &corev1.Pod{ + TypeMeta: metav1.TypeMeta{ + APIVersion: schema.GroupVersion{ + Group: corev1.SchemeGroupVersion.Group, + Version: corev1.SchemeGroupVersion.Version, + }.String(), + Kind: "Pod", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "leader-test-new", + Namespace: "testns", + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: "v1", + Kind: "Pod", + Name: "leader-test-new", + }, + }, + }, + }, + &corev1.Pod{ + TypeMeta: metav1.TypeMeta{ + APIVersion: schema.GroupVersion{ + Group: corev1.SchemeGroupVersion.Group, + Version: corev1.SchemeGroupVersion.Version, + }.String(), + Kind: "Pod", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "leader-test", + Namespace: "testns", + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: "v1", + Kind: "Pod", + Name: "leader-test", + }, + }, + }, + Status: corev1.PodStatus{ + Phase: corev1.PodFailed, + Reason: "Preempting", + }, + }, + &corev1.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + APIVersion: schema.GroupVersion{ + Group: corev1.SchemeGroupVersion.Group, + Version: corev1.SchemeGroupVersion.Version, + }.String(), + Kind: "ConfigMap", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "leader-test", + Namespace: "testns", + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: "v1", + Kind: "Pod", + Name: "leader-test", + }, + }, + }, + }, + ).WithInterceptorFuncs( + interceptor.Funcs{ + // Mock garbage collection of the ConfigMap when the Pod is deleted. + Delete: func(ctx context.Context, client crclient.WithWatch, obj crclient.Object, _ ...crclient.DeleteOption) error { + if obj.GetObjectKind() != nil && obj.GetObjectKind().GroupVersionKind().Kind == "Pod" && obj.GetName() == "leader-test" { + cm := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "leader-test", + Namespace: "testns", + }, + } + + err := client.Delete(ctx, cm) + if err != nil { + return err + } + } + return nil + }, + }, + ).Build() + + os.Setenv("POD_NAME", "leader-test-new") + readNamespace = func() (string, error) { + return "testns", nil + } + + Expect(Become(context.TODO(), "leader-test", WithClient(preemptedPodStatusClient))).To(Succeed()) }) }) Describe("isPodEvicted", func() { - var ( - leaderPod *corev1.Pod - ) + var leaderPod *corev1.Pod BeforeEach(func() { leaderPod = &corev1.Pod{} }) It("should return false with an empty status", func() { - Expect(isPodEvicted(*leaderPod)).To(Equal(false)) + Expect(isPodEvicted(*leaderPod)).To(BeFalse()) }) It("should return false if reason is incorrect", func() { leaderPod.Status.Phase = corev1.PodFailed leaderPod.Status.Reason = "invalid" - Expect(isPodEvicted(*leaderPod)).To(Equal(false)) + Expect(isPodEvicted(*leaderPod)).To(BeFalse()) }) It("should return false if pod is in the wrong phase", func() { leaderPod.Status.Phase = corev1.PodRunning - Expect(isPodEvicted(*leaderPod)).To(Equal(false)) + Expect(isPodEvicted(*leaderPod)).To(BeFalse()) }) It("should return true when Phase and Reason are set", func() { leaderPod.Status.Phase = corev1.PodFailed leaderPod.Status.Reason = "Evicted" - Expect(isPodEvicted(*leaderPod)).To(Equal(true)) + Expect(isPodEvicted(*leaderPod)).To(BeTrue()) + }) + }) + Describe("isPodPreempted", func() { + var leaderPod *corev1.Pod + BeforeEach(func() { + leaderPod = &corev1.Pod{} + }) + It("should return false with an empty status", func() { + Expect(isPodPreempted(*leaderPod)).To(BeFalse()) + }) + It("should return false if reason is incorrect", func() { + leaderPod.Status.Phase = corev1.PodFailed + leaderPod.Status.Reason = "invalid" + Expect(isPodPreempted(*leaderPod)).To(BeFalse()) + }) + It("should return false if pod is in the wrong phase", func() { + leaderPod.Status.Phase = corev1.PodRunning + Expect(isPodPreempted(*leaderPod)).To(BeFalse()) + }) + It("should return true when Phase and Reason are set", func() { + leaderPod.Status.Phase = corev1.PodFailed + leaderPod.Status.Reason = "Preempting" + Expect(isPodPreempted(*leaderPod)).To(BeTrue()) }) }) Describe("myOwnerRef", func() { - var ( - client crclient.Client - ) + var client crclient.Client BeforeEach(func() { client = fake.NewClientBuilder().WithObjects( &corev1.Pod{ + TypeMeta: metav1.TypeMeta{ + APIVersion: schema.GroupVersion{ + Group: corev1.SchemeGroupVersion.Group, + Version: corev1.SchemeGroupVersion.Version, + }.String(), + Kind: "Pod", + }, ObjectMeta: metav1.ObjectMeta{ Name: "mypod", Namespace: "testns", @@ -130,29 +354,34 @@ var _ = Describe("Leader election", func() { It("should return an error when POD_NAME is not set", func() { os.Unsetenv("POD_NAME") _, err := myOwnerRef(context.TODO(), client, "") - Expect(err).ShouldNot(BeNil()) + Expect(err).Should(HaveOccurred()) }) It("should return an error if no pod is found", func() { os.Setenv("POD_NAME", "thisisnotthepodyourelookingfor") _, err := myOwnerRef(context.TODO(), client, "") - Expect(err).ShouldNot(BeNil()) + Expect(err).Should(HaveOccurred()) }) It("should return the owner reference without error", func() { os.Setenv("POD_NAME", "mypod") owner, err := myOwnerRef(context.TODO(), client, "testns") - Expect(err).Should(BeNil()) + Expect(err).ShouldNot(HaveOccurred()) Expect(owner.APIVersion).To(Equal("v1")) Expect(owner.Kind).To(Equal("Pod")) Expect(owner.Name).To(Equal("mypod")) }) }) Describe("getPod", func() { - var ( - client crclient.Client - ) + var client crclient.Client BeforeEach(func() { client = fake.NewClientBuilder().WithObjects( &corev1.Pod{ + TypeMeta: metav1.TypeMeta{ + APIVersion: schema.GroupVersion{ + Group: corev1.SchemeGroupVersion.Group, + Version: corev1.SchemeGroupVersion.Version, + }.String(), + Kind: "Pod", + }, ObjectMeta: metav1.ObjectMeta{ Name: "mypod", Namespace: "testns", @@ -163,17 +392,17 @@ var _ = Describe("Leader election", func() { It("should return an error when POD_NAME is not set", func() { os.Unsetenv("POD_NAME") _, err := getPod(context.TODO(), nil, "") - Expect(err).ShouldNot(BeNil()) + Expect(err).Should(HaveOccurred()) }) It("should return an error if no pod is found", func() { os.Setenv("POD_NAME", "thisisnotthepodyourelookingfor") _, err := getPod(context.TODO(), client, "") - Expect(err).ShouldNot(BeNil()) + Expect(err).Should(HaveOccurred()) }) It("should return the pod with the given name", func() { os.Setenv("POD_NAME", "mypod") pod, err := getPod(context.TODO(), client, "testns") - Expect(err).Should(BeNil()) + Expect(err).ShouldNot(HaveOccurred()) Expect(pod).ShouldNot(BeNil()) Expect(pod.TypeMeta.APIVersion).To(Equal("v1")) Expect(pod.TypeMeta.Kind).To(Equal("Pod")) @@ -181,12 +410,17 @@ var _ = Describe("Leader election", func() { }) Describe("getNode", func() { - var ( - client crclient.Client - ) + var client crclient.Client BeforeEach(func() { client = fake.NewClientBuilder().WithObjects( &corev1.Node{ + TypeMeta: metav1.TypeMeta{ + APIVersion: schema.GroupVersion{ + Group: corev1.SchemeGroupVersion.Group, + Version: corev1.SchemeGroupVersion.Version, + }.String(), + Kind: "Node", + }, ObjectMeta: metav1.ObjectMeta{ Name: "mynode", }, @@ -195,13 +429,11 @@ var _ = Describe("Leader election", func() { }) It("should return an error if no node is found", func() { node := corev1.Node{} - err := getNode(context.TODO(), client, "", &node) - Expect(err).ShouldNot(BeNil()) + Expect(getNode(context.TODO(), client, "", &node)).ToNot(Succeed()) }) It("should return the node with the given name", func() { node := corev1.Node{} - err := getNode(context.TODO(), client, "mynode", &node) - Expect(err).Should(BeNil()) + Expect(getNode(context.TODO(), client, "mynode", &node)).Should(Succeed()) Expect(node.TypeMeta.APIVersion).To(Equal("v1")) Expect(node.TypeMeta.Kind).To(Equal("Node")) }) @@ -216,6 +448,13 @@ var _ = Describe("Leader election", func() { BeforeEach(func() { nodeName = "mynode" node = &corev1.Node{ + TypeMeta: metav1.TypeMeta{ + APIVersion: schema.GroupVersion{ + Group: corev1.SchemeGroupVersion.Group, + Version: corev1.SchemeGroupVersion.Version, + }.String(), + Kind: "Node", + }, ObjectMeta: metav1.ObjectMeta{ Name: nodeName, }, @@ -228,33 +467,33 @@ var _ = Describe("Leader election", func() { It("should return false if node is invalid", func() { client = fake.NewClientBuilder().WithObjects().Build() ret := isNotReadyNode(context.TODO(), client, "") - Expect(ret).To(Equal(false)) + Expect(ret).To(BeFalse()) }) It("should return false if no NodeCondition is found", func() { client = fake.NewClientBuilder().WithObjects(node).Build() ret := isNotReadyNode(context.TODO(), client, nodeName) - Expect(ret).To(Equal(false)) + Expect(ret).To(BeFalse()) }) It("should return false if type is incorrect", func() { node.Status.Conditions[0].Type = corev1.NodeMemoryPressure node.Status.Conditions[0].Status = corev1.ConditionFalse client = fake.NewClientBuilder().WithObjects(node).Build() ret := isNotReadyNode(context.TODO(), client, nodeName) - Expect(ret).To(Equal(false)) + Expect(ret).To(BeFalse()) }) It("should return false if NodeReady's type is true", func() { node.Status.Conditions[0].Type = corev1.NodeReady node.Status.Conditions[0].Status = corev1.ConditionTrue client = fake.NewClientBuilder().WithObjects(node).Build() ret := isNotReadyNode(context.TODO(), client, nodeName) - Expect(ret).To(Equal(false)) + Expect(ret).To(BeFalse()) }) It("should return true when Type is set and Status is set to false", func() { node.Status.Conditions[0].Type = corev1.NodeReady node.Status.Conditions[0].Status = corev1.ConditionFalse client = fake.NewClientBuilder().WithObjects(node).Build() ret := isNotReadyNode(context.TODO(), client, nodeName) - Expect(ret).To(Equal(true)) + Expect(ret).To(BeTrue()) }) }) Describe("deleteLeader", func() { @@ -265,6 +504,13 @@ var _ = Describe("Leader election", func() { ) BeforeEach(func() { pod = &corev1.Pod{ + TypeMeta: metav1.TypeMeta{ + APIVersion: schema.GroupVersion{ + Group: corev1.SchemeGroupVersion.Group, + Version: corev1.SchemeGroupVersion.Version, + }.String(), + Kind: "Pod", + }, ObjectMeta: metav1.ObjectMeta{ Name: "leader-test", Namespace: "testns", @@ -278,6 +524,13 @@ var _ = Describe("Leader election", func() { }, } configmap = &corev1.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + APIVersion: schema.GroupVersion{ + Group: corev1.SchemeGroupVersion.Group, + Version: corev1.SchemeGroupVersion.Version, + }.String(), + Kind: "ConfigMap", + }, ObjectMeta: metav1.ObjectMeta{ Name: "leader-test", Namespace: "testns", @@ -293,29 +546,23 @@ var _ = Describe("Leader election", func() { }) It("should return an error if existing is not found", func() { client = fake.NewClientBuilder().WithObjects(pod).Build() - err := deleteLeader(context.TODO(), client, pod, configmap) - Expect(err).ShouldNot(BeNil()) + Expect(deleteLeader(context.TODO(), client, pod, configmap)).ToNot(Succeed()) }) It("should return an error if pod is not found", func() { client = fake.NewClientBuilder().WithObjects(configmap).Build() - err := deleteLeader(context.TODO(), client, pod, configmap) - Expect(err).ShouldNot(BeNil()) + Expect(deleteLeader(context.TODO(), client, pod, configmap)).ToNot(Succeed()) }) It("should return an error if pod is nil", func() { client = fake.NewClientBuilder().WithObjects(pod, configmap).Build() - err := deleteLeader(context.TODO(), client, nil, configmap) - Expect(err).ShouldNot(BeNil()) + Expect(deleteLeader(context.TODO(), client, nil, configmap)).ToNot(Succeed()) }) It("should return an error if configmap is nil", func() { client = fake.NewClientBuilder().WithObjects(pod, configmap).Build() - err := deleteLeader(context.TODO(), client, pod, nil) - Expect(err).ShouldNot(BeNil()) + Expect(deleteLeader(context.TODO(), client, pod, nil)).ToNot(Succeed()) }) It("should return nil if pod and configmap exists and configmap's owner is the pod", func() { client = fake.NewClientBuilder().WithObjects(pod, configmap).Build() - err := deleteLeader(context.TODO(), client, pod, configmap) - Expect(err).Should(BeNil()) + Expect(deleteLeader(context.TODO(), client, pod, configmap)).To(Succeed()) }) - }) }) diff --git a/predicate/dependent.go b/predicate/dependent.go index bb37321..608aa45 100644 --- a/predicate/dependent.go +++ b/predicate/dependent.go @@ -85,22 +85,22 @@ func (DependentPredicate) Generic(e event.GenericEvent) bool { // resource to write to the status of one its dependent resources. func (DependentPredicate) Update(e event.UpdateEvent) bool { old := e.ObjectOld.(*unstructured.Unstructured).DeepCopy() - new := e.ObjectNew.(*unstructured.Unstructured).DeepCopy() + updated := e.ObjectNew.(*unstructured.Unstructured).DeepCopy() delete(old.Object, "status") - delete(new.Object, "status") + delete(updated.Object, "status") old.SetResourceVersion("") - new.SetResourceVersion("") + updated.SetResourceVersion("") old.SetManagedFields(removeTimeFromManagedFields(old.GetManagedFields())) - new.SetManagedFields(removeTimeFromManagedFields(new.GetManagedFields())) + updated.SetManagedFields(removeTimeFromManagedFields(updated.GetManagedFields())) - if reflect.DeepEqual(old.Object, new.Object) { + if reflect.DeepEqual(old.Object, updated.Object) { return false } log.V(1).Info("Reconciling due to dependent resource update", - "name", new.GetName(), "namespace", new.GetNamespace(), "apiVersion", - new.GroupVersionKind().GroupVersion(), "kind", new.GroupVersionKind().Kind) + "name", updated.GetName(), "namespace", updated.GetNamespace(), "apiVersion", + updated.GroupVersionKind().GroupVersion(), "kind", updated.GroupVersionKind().Kind) return true } diff --git a/predicate/example_test.go b/predicate/example_test.go index e0bac33..f420112 100644 --- a/predicate/example_test.go +++ b/predicate/example_test.go @@ -18,13 +18,14 @@ import ( "context" "os" - "github.com/operator-framework/operator-lib/predicate" - v1 "k8s.io/api/core/v1" + corev1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client/config" "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/manager/signals" "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "github.com/operator-framework/operator-lib/predicate" ) // This example applies the Pause predicate to all incoming Pod events on a Pod controller. @@ -39,7 +40,7 @@ func ExampleNewPause() { os.Exit(1) } - var r reconcile.Func = func(ctx context.Context, req reconcile.Request) (reconcile.Result, error) { + var r reconcile.Func = func(_ context.Context, _ reconcile.Request) (reconcile.Result, error) { // Your reconcile logic would go here. No paused Pod events would trigger reconciliation. return reconcile.Result{}, nil } @@ -50,7 +51,7 @@ func ExampleNewPause() { os.Exit(1) } pred := builder.WithPredicates(pause) - if err := builder.ControllerManagedBy(mgr).For(&v1.Pod{}, pred).Complete(r); err != nil { + if err := builder.ControllerManagedBy(mgr).For(&corev1.Pod{}, pred).Complete(r); err != nil { os.Exit(1) } diff --git a/predicate/nogeneration_test.go b/predicate/nogeneration_test.go index b4ae3b1..355ce9a 100644 --- a/predicate/nogeneration_test.go +++ b/predicate/nogeneration_test.go @@ -38,50 +38,50 @@ var _ = Describe("NoGenerationPredicate", func() { It("returns false", func() { By("the new object having a non-zero generation", func() { - old, new := &appsv1.Deployment{}, &appsv1.Deployment{} - new.SetGeneration(1) - e = makeUpdateEventFor(old, new) + old, updated := &appsv1.Deployment{}, &appsv1.Deployment{} + updated.SetGeneration(1) + e = makeUpdateEventFor(old, updated) Expect(pred.Update(e)).To(BeFalse()) }) // The old generation will never be lower than the new, so we don't have to test that case. By("the old and new objects having equal non-zero generations", func() { - old, new := &appsv1.Deployment{}, &appsv1.Deployment{} + old, updated := &appsv1.Deployment{}, &appsv1.Deployment{} old.SetGeneration(1) - new.SetGeneration(1) - e = makeUpdateEventFor(old, new) + updated.SetGeneration(1) + e = makeUpdateEventFor(old, updated) Expect(pred.Update(e)).To(BeFalse()) }) By("the old and new objects having unequal non-zero generations", func() { - old, new := &appsv1.Deployment{}, &appsv1.Deployment{} + old, updated := &appsv1.Deployment{}, &appsv1.Deployment{} old.SetGeneration(1) - new.SetGeneration(2) - e = makeUpdateEventFor(old, new) + updated.SetGeneration(2) + e = makeUpdateEventFor(old, updated) Expect(pred.Update(e)).To(BeFalse()) }) }) It("logs a message and returns false", func() { By("the old object being nil", func() { - old, new := &appsv1.Deployment{}, &appsv1.Deployment{} - e = makeUpdateEventFor(old, new) + old, updated := &appsv1.Deployment{}, &appsv1.Deployment{} + e = makeUpdateEventFor(old, updated) e.ObjectOld = nil Expect(pred.Update(e)).To(BeFalse()) }) By("the old metadata being nil", func() { - old, new := &appsv1.Deployment{}, &appsv1.Deployment{} - e = makeUpdateEventFor(old, new) + old, updated := &appsv1.Deployment{}, &appsv1.Deployment{} + e = makeUpdateEventFor(old, updated) e.ObjectOld = nil Expect(pred.Update(e)).To(BeFalse()) }) By("the new object being nil", func() { - old, new := &appsv1.Deployment{}, &appsv1.Deployment{} - e = makeUpdateEventFor(old, new) + old, updated := &appsv1.Deployment{}, &appsv1.Deployment{} + e = makeUpdateEventFor(old, updated) e.ObjectNew = nil Expect(pred.Update(e)).To(BeFalse()) }) By("the new metadata being nil", func() { - old, new := &appsv1.Deployment{}, &appsv1.Deployment{} - e = makeUpdateEventFor(old, new) + old, updated := &appsv1.Deployment{}, &appsv1.Deployment{} + e = makeUpdateEventFor(old, updated) e.ObjectNew = nil Expect(pred.Update(e)).To(BeFalse()) }) diff --git a/predicate/pause.go b/predicate/pause.go index 9a2ea3e..b008f66 100644 --- a/predicate/pause.go +++ b/predicate/pause.go @@ -15,9 +15,9 @@ package predicate import ( - "github.com/operator-framework/operator-lib/internal/annotation" - "sigs.k8s.io/controller-runtime/pkg/predicate" + + "github.com/operator-framework/operator-lib/internal/annotation" ) // NewPause returns a predicate that filters out objects with a truthy "paused" annotation. diff --git a/predicate/predicate_suite_test.go b/predicate/predicate_suite_test.go index a96a9f5..1659c6e 100644 --- a/predicate/predicate_suite_test.go +++ b/predicate/predicate_suite_test.go @@ -28,23 +28,27 @@ func TestPredicate(t *testing.T) { RunSpecs(t, "Predicate Suite") } -func makeCreateEventFor(obj client.Object) (e event.CreateEvent) { +func makeCreateEventFor(obj client.Object) event.CreateEvent { + var e event.CreateEvent e.Object = obj return e } -func makeUpdateEventFor(old, new client.Object) (e event.UpdateEvent) { +func makeUpdateEventFor(old, new client.Object) event.UpdateEvent { + var e event.UpdateEvent e.ObjectOld = old e.ObjectNew = new return e } -func makeDeleteEventFor(obj client.Object) (e event.DeleteEvent) { +func makeDeleteEventFor(obj client.Object) event.DeleteEvent { + var e event.DeleteEvent e.Object = obj return e } -func makeGenericEventFor(obj client.Object) (e event.GenericEvent) { +func makeGenericEventFor(obj client.Object) event.GenericEvent { + var e event.GenericEvent e.Object = obj return e } diff --git a/proxy/proxy_test.go b/proxy/proxy_test.go index 25052b8..a680a11 100644 --- a/proxy/proxy_test.go +++ b/proxy/proxy_test.go @@ -31,7 +31,6 @@ func checkValueFromEnvObj(name string, envVars []corev1.EnvVar) (string, error) } } return "", errors.New("empty name") - } var _ = Describe("Retrieving", func() { @@ -41,11 +40,11 @@ var _ = Describe("Retrieving", func() { os.Setenv("HTTP_PROXY", "http_proxy_test") os.Setenv("NO_PROXY", "no_proxy_test") envVars := ReadProxyVarsFromEnv() - Expect(len(envVars)).To(Equal(6)) + Expect(envVars).To(HaveLen(6)) }) It("does not return unset variables", func() { envVars := ReadProxyVarsFromEnv() - Expect(len(envVars)).To(Equal(0)) + Expect(envVars).To(BeEmpty()) }) It("creates upper and lower case environment variables with the same value", func() { @@ -56,9 +55,9 @@ var _ = Describe("Retrieving", func() { for _, envName := range ProxyEnvNames { upperValue, err := checkValueFromEnvObj(envName, envVars) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) lowerValue, err := checkValueFromEnvObj(strings.ToLower(envName), envVars) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) Expect(upperValue).To(Equal(lowerValue)) } }) diff --git a/prune/prune.go b/prune/prune.go index 460a154..10ab5c5 100644 --- a/prune/prune.go +++ b/prune/prune.go @@ -111,7 +111,6 @@ func (p Pruner) Namespace() string { // NewPruner returns a pruner that uses the given strategy to prune objects that have the given GVK func NewPruner(prunerClient client.Client, gvk schema.GroupVersionKind, strategy StrategyFunc, opts ...PrunerOption) (*Pruner, error) { - if gvk.Empty() { return nil, fmt.Errorf("error when creating a new Pruner: gvk parameter can not be empty") } @@ -132,7 +131,6 @@ func NewPruner(prunerClient client.Client, gvk schema.GroupVersionKind, strategy // Prune runs the pruner. func (p Pruner) Prune(ctx context.Context) ([]client.Object, error) { - var objs []client.Object listOpts := client.ListOptions{ LabelSelector: labels.Set(p.labels).AsSelector(), Namespace: p.namespace, @@ -144,7 +142,10 @@ func (p Pruner) Prune(ctx context.Context) ([]client.Object, error) { return nil, fmt.Errorf("error getting a list of resources: %w", err) } - for _, unsObj := range unstructuredObjs.Items { + objs := make([]client.Object, 0, len(unstructuredObjs.Items)) + + for i := range unstructuredObjs.Items { + unsObj := unstructuredObjs.Items[i] obj, err := convert(p.client, p.gvk, &unsObj) if err != nil { return nil, err diff --git a/prune/prune_test.go b/prune/prune_test.go index e610fc1..da5ea7f 100644 --- a/prune/prune_test.go +++ b/prune/prune_test.go @@ -49,7 +49,7 @@ var _ = Describe("Prune", func() { ) BeforeEach(func() { testScheme, err := createSchemes() - Expect(err).Should(BeNil()) + Expect(err).ShouldNot(HaveOccurred()) fakeClient = crFake.NewClientBuilder().WithScheme(testScheme).Build() fakeObj = &corev1.Pod{} @@ -97,7 +97,7 @@ var _ = Describe("Prune", func() { Kind: "NotReal", }) - Expect(NewRegistry().IsPrunable(obj)).Should(BeNil()) + Expect(NewRegistry().IsPrunable(obj)).Should(Succeed()) }) }) @@ -106,7 +106,7 @@ var _ = Describe("Prune", func() { Describe("NewPruner()", func() { It("Should Return a New Pruner Object", func() { pruner, err := NewPruner(fakeClient, podGVK, myStrategy) - Expect(err).Should(BeNil()) + Expect(err).ShouldNot(HaveOccurred()) Expect(pruner).ShouldNot(BeNil()) }) @@ -118,7 +118,7 @@ var _ = Describe("Prune", func() { myStrategy, WithNamespace(namespace), WithLabels(labels)) - Expect(err).Should(BeNil()) + Expect(err).ShouldNot(HaveOccurred()) Expect(pruner).ShouldNot(BeNil()) Expect(&pruner.registry).Should(Equal(DefaultRegistry())) Expect(pruner.namespace).Should(Equal(namespace)) @@ -131,8 +131,7 @@ var _ = Describe("Prune", func() { It("Should Error if schema.GroupVersionKind Parameter is empty", func() { // empty GVK struct pruner, err := NewPruner(fakeClient, schema.GroupVersionKind{}, myStrategy) - Expect(err).ShouldNot(BeNil()) - Expect(err.Error()).Should(Equal("error when creating a new Pruner: gvk parameter can not be empty")) + Expect(err).Should(MatchError("error when creating a new Pruner: gvk parameter can not be empty")) Expect(pruner).Should(BeNil()) }) }) @@ -141,123 +140,109 @@ var _ = Describe("Prune", func() { Context("Does not return an Error", func() { testPruneWithDefaultIsPrunableFunc := func(gvk schema.GroupVersionKind) { pruner, err := NewPruner(fakeClient, gvk, myStrategy, WithLabels(appLabels), WithNamespace(namespace)) - Expect(err).Should(BeNil()) + Expect(err).ShouldNot(HaveOccurred()) Expect(pruner).ShouldNot(BeNil()) prunedObjects, err := pruner.Prune(context.Background()) - Expect(err).Should(BeNil()) - Expect(len(prunedObjects)).Should(Equal(2)) + Expect(err).ShouldNot(HaveOccurred()) + Expect(prunedObjects).Should(HaveLen(2)) } It("Should Prune Pods with Default IsPrunableFunc", func() { // Create the test resources - in this case Pods - err := createTestPods(fakeClient) - Expect(err).Should(BeNil()) + Expect(createTestPods(fakeClient)).To(Succeed()) // Make sure the pod resources are properly created pods := &unstructured.UnstructuredList{} pods.SetGroupVersionKind(podGVK) - err = fakeClient.List(context.Background(), pods) - Expect(err).Should(BeNil()) - Expect(len(pods.Items)).Should(Equal(3)) + Expect(fakeClient.List(context.Background(), pods)).To(Succeed()) + Expect(pods.Items).Should(HaveLen(3)) testPruneWithDefaultIsPrunableFunc(podGVK) // Get a list of the Pods to make sure we have pruned the ones we expected - err = fakeClient.List(context.Background(), pods) - Expect(err).Should(BeNil()) - Expect(len(pods.Items)).Should(Equal(1)) + Expect(fakeClient.List(context.Background(), pods)).To(Succeed()) + Expect(pods.Items).Should(HaveLen(1)) }) It("Should Prune Jobs with Default IsPrunableFunc", func() { // Create the test resources - in this case Jobs - err := createTestJobs(fakeClient) - Expect(err).Should(BeNil()) + Expect(createTestJobs(fakeClient)).To(Succeed()) // Make sure the job resources are properly created jobs := &unstructured.UnstructuredList{} jobs.SetGroupVersionKind(jobGVK) - err = fakeClient.List(context.Background(), jobs) - Expect(err).Should(BeNil()) - Expect(len(jobs.Items)).Should(Equal(3)) + Expect(fakeClient.List(context.Background(), jobs)).To(Succeed()) + Expect(jobs.Items).Should(HaveLen(3)) testPruneWithDefaultIsPrunableFunc(jobGVK) // Get a list of the job to make sure we have pruned the ones we expected - err = fakeClient.List(context.Background(), jobs) - Expect(err).Should(BeNil()) - Expect(len(jobs.Items)).Should(Equal(1)) + Expect(fakeClient.List(context.Background(), jobs)).To(Succeed()) + Expect(jobs.Items).Should(HaveLen(1)) }) It("Should Remove Resource When Using a Custom IsPrunableFunc", func() { // Create the test resources - in this case Jobs - err := createTestJobs(fakeClient) - Expect(err).Should(BeNil()) + Expect(createTestJobs(fakeClient)).To(Succeed()) // Make sure the job resources are properly created jobs := &unstructured.UnstructuredList{} jobs.SetGroupVersionKind(jobGVK) - err = fakeClient.List(context.Background(), jobs) - Expect(err).Should(BeNil()) - Expect(len(jobs.Items)).Should(Equal(3)) + Expect(fakeClient.List(context.Background(), jobs)).To(Succeed()) + Expect(jobs.Items).Should(HaveLen(3)) pruner, err := NewPruner(fakeClient, jobGVK, myStrategy, WithLabels(appLabels), WithNamespace(namespace)) - Expect(err).Should(BeNil()) + Expect(err).ShouldNot(HaveOccurred()) Expect(pruner).ShouldNot(BeNil()) // Register our custom IsPrunableFunc RegisterIsPrunableFunc(jobGVK, myIsPrunable) prunedObjects, err := pruner.Prune(context.Background()) - Expect(err).Should(BeNil()) - Expect(len(prunedObjects)).Should(Equal(2)) + Expect(err).ShouldNot(HaveOccurred()) + Expect(prunedObjects).Should(HaveLen(2)) // Get a list of the jobs to make sure we have pruned the ones we expected - err = fakeClient.List(context.Background(), jobs) - Expect(err).Should(BeNil()) - Expect(len(jobs.Items)).Should(Equal(1)) + Expect(fakeClient.List(context.Background(), jobs)).To(Succeed()) + Expect(jobs.Items).Should(HaveLen(1)) }) It("Should Not Prune Resources when using a DryRunClient", func() { // Create the test resources - in this case Pods - err := createTestPods(fakeClient) - Expect(err).Should(BeNil()) + Expect(createTestPods(fakeClient)).To(Succeed()) // Make sure the pod resources are properly created pods := &unstructured.UnstructuredList{} pods.SetGroupVersionKind(podGVK) - err = fakeClient.List(context.Background(), pods) - Expect(err).Should(BeNil()) - Expect(len(pods.Items)).Should(Equal(3)) + Expect(fakeClient.List(context.Background(), pods)).To(Succeed()) + Expect(pods.Items).Should(HaveLen(3)) dryRunClient := client.NewDryRunClient(fakeClient) pruner, err := NewPruner(dryRunClient, podGVK, myStrategy, WithLabels(appLabels), WithNamespace(namespace)) - Expect(err).Should(BeNil()) + Expect(err).ShouldNot(HaveOccurred()) Expect(pruner).ShouldNot(BeNil()) prunedObjects, err := pruner.Prune(context.Background()) - Expect(err).Should(BeNil()) - Expect(len(prunedObjects)).Should(Equal(2)) + Expect(err).ShouldNot(HaveOccurred()) + Expect(prunedObjects).Should(HaveLen(2)) // Get a list of the Pods to make sure we haven't pruned any - err = fakeClient.List(context.Background(), pods) - Expect(err).Should(BeNil()) - Expect(len(pods.Items)).Should(Equal(3)) + Expect(fakeClient.List(context.Background(), pods)).To(Succeed()) + Expect(pods.Items).Should(HaveLen(3)) }) It("Should Skip Pruning a Resource If IsPrunable Returns an Error of Type Unprunable", func() { // Create the test resources - in this case Jobs - err := createTestJobs(fakeClient) - Expect(err).Should(BeNil()) + Expect(createTestJobs(fakeClient)).To(Succeed()) // Make sure the job resources are properly created jobs := &unstructured.UnstructuredList{} jobs.SetGroupVersionKind(jobGVK) - err = fakeClient.List(context.Background(), jobs) - Expect(err).Should(BeNil()) - Expect(len(jobs.Items)).Should(Equal(3)) + Expect(fakeClient.List(context.Background(), jobs)).To(Succeed()) + Expect(jobs.Items).Should(HaveLen(3)) pruner, err := NewPruner(fakeClient, jobGVK, myStrategy, WithLabels(appLabels), WithNamespace(namespace)) - Expect(err).Should(BeNil()) + Expect(err).ShouldNot(HaveOccurred()) Expect(pruner).ShouldNot(BeNil()) // IsPrunableFunc that throws Unprunable error @@ -272,35 +257,32 @@ var _ = Describe("Prune", func() { RegisterIsPrunableFunc(jobGVK, errorPrunableFunc) prunedObjects, err := pruner.Prune(context.Background()) - Expect(err).Should(BeNil()) - Expect(len(prunedObjects)).Should(Equal(0)) + Expect(err).ShouldNot(HaveOccurred()) + Expect(prunedObjects).Should(BeEmpty()) // Get a list of the jobs to make sure we have pruned the ones we expected - err = fakeClient.List(context.Background(), jobs) - Expect(err).Should(BeNil()) - Expect(len(jobs.Items)).Should(Equal(3)) + Expect(fakeClient.List(context.Background(), jobs)).To(Succeed()) + Expect(jobs.Items).Should(HaveLen(3)) }) }) Context("Returns an Error", func() { It("Should Return an Error if IsPrunableFunc Returns an Error That is not of Type Unprunable", func() { // Create the test resources - in this case Jobs - err := createTestJobs(fakeClient) - Expect(err).Should(BeNil()) + Expect(createTestJobs(fakeClient)).To(Succeed()) // Make sure the job resources are properly created jobs := &unstructured.UnstructuredList{} jobs.SetGroupVersionKind(jobGVK) - err = fakeClient.List(context.Background(), jobs) - Expect(err).Should(BeNil()) - Expect(len(jobs.Items)).Should(Equal(3)) + Expect(fakeClient.List(context.Background(), jobs)).To(Succeed()) + Expect(jobs.Items).Should(HaveLen(3)) pruner, err := NewPruner(fakeClient, jobGVK, myStrategy, WithLabels(appLabels), WithNamespace(namespace)) - Expect(err).Should(BeNil()) + Expect(err).ShouldNot(HaveOccurred()) Expect(pruner).ShouldNot(BeNil()) // IsPrunableFunc that throws non Unprunable error - errorPrunableFunc := func(obj client.Object) error { + errorPrunableFunc := func(_ client.Object) error { return fmt.Errorf("TEST") } @@ -308,65 +290,57 @@ var _ = Describe("Prune", func() { RegisterIsPrunableFunc(jobGVK, errorPrunableFunc) prunedObjects, err := pruner.Prune(context.Background()) - Expect(err).ShouldNot(BeNil()) - Expect(err.Error()).Should(Equal("TEST")) - Expect(len(prunedObjects)).Should(Equal(0)) + Expect(err).Should(MatchError("TEST")) + Expect(prunedObjects).Should(BeEmpty()) // Get a list of the jobs to make sure we have pruned the ones we expected - err = fakeClient.List(context.Background(), jobs) - Expect(err).Should(BeNil()) - Expect(len(jobs.Items)).Should(Equal(3)) + Expect(fakeClient.List(context.Background(), jobs)).To(Succeed()) + Expect(jobs.Items).Should(HaveLen(3)) }) It("Should Return An Error If Strategy Function Returns An Error", func() { // Create the test resources - in this case Jobs - err := createTestJobs(fakeClient) - Expect(err).Should(BeNil()) + Expect(createTestJobs(fakeClient)).To(Succeed()) // Make sure the job resources are properly created jobs := &unstructured.UnstructuredList{} jobs.SetGroupVersionKind(jobGVK) - err = fakeClient.List(context.Background(), jobs) - Expect(err).Should(BeNil()) - Expect(len(jobs.Items)).Should(Equal(3)) + Expect(fakeClient.List(context.Background(), jobs)).To(Succeed()) + Expect(jobs.Items).Should(HaveLen(3)) // strategy that will return an error - prunerStrategy := func(ctx context.Context, objs []client.Object) ([]client.Object, error) { + prunerStrategy := func(_ context.Context, _ []client.Object) ([]client.Object, error) { return nil, fmt.Errorf("TESTERROR") } pruner, err := NewPruner(fakeClient, jobGVK, prunerStrategy, WithLabels(appLabels), WithNamespace(namespace)) - Expect(err).Should(BeNil()) + Expect(err).ShouldNot(HaveOccurred()) Expect(pruner).ShouldNot(BeNil()) // Register our custom IsPrunableFunc RegisterIsPrunableFunc(jobGVK, myIsPrunable) prunedObjects, err := pruner.Prune(context.Background()) - Expect(err).ShouldNot(BeNil()) - Expect(err.Error()).Should(Equal("error determining prunable objects: TESTERROR")) + Expect(err).Should(MatchError("error determining prunable objects: TESTERROR")) Expect(prunedObjects).Should(BeNil()) // Get a list of the jobs to make sure we have pruned the ones we expected - err = fakeClient.List(context.Background(), jobs) - Expect(err).Should(BeNil()) - Expect(len(jobs.Items)).Should(Equal(3)) + Expect(fakeClient.List(context.Background(), jobs)).To(Succeed()) + Expect(jobs.Items).Should(HaveLen(3)) }) It("Should Return an Error if it can not Prune a Resource", func() { // Create the test resources - in this case Jobs - err := createTestJobs(fakeClient) - Expect(err).Should(BeNil()) + Expect(createTestJobs(fakeClient)).To(Succeed()) // Make sure the job resources are properly created jobs := &unstructured.UnstructuredList{} jobs.SetGroupVersionKind(jobGVK) - err = fakeClient.List(context.Background(), jobs) - Expect(err).Should(BeNil()) - Expect(len(jobs.Items)).Should(Equal(3)) + Expect(fakeClient.List(context.Background(), jobs)).To(Succeed()) + Expect(jobs.Items).Should(HaveLen(3)) pruner, err := NewPruner(fakeClient, jobGVK, myStrategy, WithLabels(appLabels), WithNamespace(namespace)) - Expect(err).Should(BeNil()) + Expect(err).ShouldNot(HaveOccurred()) Expect(pruner).ShouldNot(BeNil()) // IsPrunableFunc that returns nil but also deletes the object @@ -380,14 +354,12 @@ var _ = Describe("Prune", func() { RegisterIsPrunableFunc(jobGVK, prunableFunc) prunedObjects, err := pruner.Prune(context.Background()) - Expect(err).ShouldNot(BeNil()) - Expect(err.Error()).Should(ContainSubstring("error pruning object: jobs.batch \"churro1\" not found")) - Expect(len(prunedObjects)).Should(Equal(0)) + Expect(err).Should(MatchError(ContainSubstring("error pruning object: jobs.batch \"churro1\" not found"))) + Expect(prunedObjects).Should(BeEmpty()) // Get a list of the jobs to make sure we have pruned the ones we expected - err = fakeClient.List(context.Background(), jobs) - Expect(err).Should(BeNil()) - Expect(len(jobs.Items)).Should(Equal(0)) + Expect(fakeClient.List(context.Background(), jobs)).To(Succeed()) + Expect(jobs.Items).Should(BeEmpty()) }) }) @@ -396,7 +368,7 @@ var _ = Describe("Prune", func() { Describe("GVK()", func() { It("Should return the GVK field in the Pruner", func() { pruner, err := NewPruner(fakeClient, podGVK, myStrategy) - Expect(err).Should(BeNil()) + Expect(err).ShouldNot(HaveOccurred()) Expect(pruner).ShouldNot(BeNil()) Expect(pruner.GVK()).Should(Equal(podGVK)) }) @@ -405,7 +377,7 @@ var _ = Describe("Prune", func() { Describe("Labels()", func() { It("Should return the Labels field in the Pruner", func() { pruner, err := NewPruner(fakeClient, podGVK, myStrategy, WithLabels(appLabels)) - Expect(err).Should(BeNil()) + Expect(err).ShouldNot(HaveOccurred()) Expect(pruner).ShouldNot(BeNil()) Expect(pruner.Labels()).Should(Equal(appLabels)) }) @@ -414,7 +386,7 @@ var _ = Describe("Prune", func() { Describe("Namespace()", func() { It("Should return the Namespace field in the Pruner", func() { pruner, err := NewPruner(fakeClient, podGVK, myStrategy, WithNamespace(namespace)) - Expect(err).Should(BeNil()) + Expect(err).ShouldNot(HaveOccurred()) Expect(pruner).ShouldNot(BeNil()) Expect(pruner.Namespace()).Should(Equal(namespace)) }) @@ -437,8 +409,7 @@ var _ = Describe("Prune", func() { pod.SetGroupVersionKind(podGVK) // Run it through DefaultPodIsPrunable - err := DefaultPodIsPrunable(pod) - Expect(err).Should(BeNil()) + Expect(DefaultPodIsPrunable(pod)).To(Succeed()) }) It("Should Panic When client.Object is not of type 'Pod'", func() { @@ -467,12 +438,11 @@ var _ = Describe("Prune", func() { // Run it through DefaultPodIsPrunable err := DefaultPodIsPrunable(pod) - Expect(err).ShouldNot(BeNil()) + Expect(err).Should(MatchError(fmt.Sprintf("unable to prune %s: Pod has not succeeded", client.ObjectKeyFromObject(pod)))) var expectErr *Unprunable Expect(errors.As(err, &expectErr)).Should(BeTrue()) Expect(expectErr.Reason).Should(Equal("Pod has not succeeded")) Expect(expectErr.Obj).ShouldNot(BeNil()) - Expect(err.Error()).Should(Equal(fmt.Sprintf("unable to prune %s: Pod has not succeeded", client.ObjectKeyFromObject(pod)))) }) }) @@ -492,8 +462,7 @@ var _ = Describe("Prune", func() { job.SetGroupVersionKind(jobGVK) // Run it through DefaultJobIsPrunable - err := DefaultJobIsPrunable(job) - Expect(err).Should(BeNil()) + Expect(DefaultJobIsPrunable(job)).To(Succeed()) }) It("Should Return An Error When Kind Is Not 'Job'", func() { @@ -522,12 +491,11 @@ var _ = Describe("Prune", func() { // Run it through DefaultJobIsPrunable err := DefaultJobIsPrunable(job) - Expect(err).ShouldNot(BeNil()) + Expect(err).Should(MatchError(ContainSubstring(fmt.Sprintf("unable to prune %s: Job has not completed", client.ObjectKeyFromObject(job))))) var expectErr *Unprunable Expect(errors.As(err, &expectErr)).Should(BeTrue()) Expect(expectErr.Reason).Should(Equal("Job has not completed")) Expect(expectErr.Obj).ShouldNot(BeNil()) - Expect(err.Error()).Should(ContainSubstring(fmt.Sprintf("unable to prune %s: Job has not completed", client.ObjectKeyFromObject(job)))) }) }) @@ -535,13 +503,13 @@ var _ = Describe("Prune", func() { resources := createDatedResources() It("Should return the 3 oldest resources", func() { resourcesToRemove, err := NewPruneByCountStrategy(2)(context.Background(), resources) - Expect(err).Should(BeNil()) + Expect(err).ShouldNot(HaveOccurred()) Expect(resourcesToRemove).Should(Equal(resources[2:])) }) It("Should return nil", func() { resourcesToRemove, err := NewPruneByCountStrategy(5)(context.Background(), resources) - Expect(err).Should(BeNil()) + Expect(err).ShouldNot(HaveOccurred()) Expect(resourcesToRemove).Should(BeNil()) }) }) @@ -551,15 +519,15 @@ var _ = Describe("Prune", func() { It("Should return 2 resources", func() { date := time.Now().Add(time.Hour * time.Duration(2)) resourcesToRemove, err := NewPruneByDateStrategy(date)(context.Background(), resources) - Expect(err).Should(BeNil()) - Expect(len(resourcesToRemove)).Should(Equal(2)) + Expect(err).ShouldNot(HaveOccurred()) + Expect(resourcesToRemove).Should(HaveLen(2)) }) It("Should return 0 resources", func() { date := time.Now().Add(time.Hour * time.Duration(24)) resourcesToRemove, err := NewPruneByDateStrategy(date)(context.Background(), resources) - Expect(err).Should(BeNil()) - Expect(len(resourcesToRemove)).Should(Equal(0)) + Expect(err).ShouldNot(HaveOccurred()) + Expect(resourcesToRemove).Should(BeEmpty()) }) }) @@ -687,7 +655,7 @@ func createSchemes() (*runtime.Scheme, error) { // myStrategy shows how you can write your own strategy // In this example it simply removes a resource if it has // the name 'churro1' or 'churro2' -func myStrategy(ctx context.Context, objs []client.Object) ([]client.Object, error) { +func myStrategy(_ context.Context, objs []client.Object) ([]client.Object, error) { var objsToRemove []client.Object for _, obj := range objs { @@ -710,6 +678,6 @@ func expectPanic() { // myIsPrunable shows how you can write your own IsPrunableFunc // In this example it simply removes all resources -func myIsPrunable(obj client.Object) error { +func myIsPrunable(_ client.Object) error { return nil } diff --git a/prune/strategies.go b/prune/strategies.go index 79f65be..86d6345 100644 --- a/prune/strategies.go +++ b/prune/strategies.go @@ -26,8 +26,7 @@ import ( // resources to prune based on a maximum count of resources allowed. // If the max count of resources is exceeded, the oldest resources are prioritized for pruning func NewPruneByCountStrategy(count int) StrategyFunc { - return func(ctx context.Context, objs []client.Object) ([]client.Object, error) { - + return func(_ context.Context, objs []client.Object) ([]client.Object, error) { if len(objs) <= count { return nil, nil } @@ -48,7 +47,7 @@ func NewPruneByCountStrategy(count int) StrategyFunc { // NewPruneByDateStrategy returns a StrategyFunc that will return a list of // resources to prune where the resource CreationTimestamp is after the given time.Time. func NewPruneByDateStrategy(date time.Time) StrategyFunc { - return func(ctx context.Context, objs []client.Object) ([]client.Object, error) { + return func(_ context.Context, objs []client.Object) ([]client.Object, error) { var objsToPrune []client.Object for _, obj := range objs {