diff --git a/.github/workflows/build_test_ci.yml b/.github/workflows/build_test_ci.yml index d8ec43936..23b2719da 100644 --- a/.github/workflows/build_test_ci.yml +++ b/.github/workflows/build_test_ci.yml @@ -35,10 +35,13 @@ jobs: allowed-endpoints: > api.github.com:443 github.com:443 + golang.org:443 proxy.golang.org:443 sum.golang.org:443 objects.githubusercontent.com:443 storage.googleapis.com:443 + cli.codecov.io:443 + api.codecov.io:443 - uses: actions/checkout@v4 @@ -54,6 +57,16 @@ jobs: - name: Test run: make test + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v4 + with: + files: ./coverage.out + fail_ci_if_error: true + verbose: true + token: ${{ secrets.CODECOV_TOKEN }} + slug: linode/cluster-api-provider-linode + + go-analyse: needs: go-build-test runs-on: ubuntu-latest @@ -103,6 +116,7 @@ jobs: e2e-test: needs: [go-build-test, docker-build] runs-on: ubuntu-latest + if: github.event.pull_request.draft == false steps: - name: Harden Runner uses: step-security/harden-runner@v2 diff --git a/Makefile b/Makefile index 0e981e066..cd5ac59ec 100644 --- a/Makefile +++ b/Makefile @@ -6,13 +6,13 @@ IMAGE_NAME ?= cluster-api-provider-linode CONTROLLER_IMAGE ?= $(REGISTRY)/$(IMAGE_NAME) TAG ?= dev ENVTEST_K8S_VERSION := 1.28.0 +VERSION ?= $(shell git describe --always --tag --dirty=-dev) BUILD_ARGS := --build-arg VERSION=$(VERSION) SHELL = /usr/bin/env bash -o pipefail .SHELLFLAGS = -ec CONTAINER_TOOL ?= docker MDBOOK_DEV_HOST = 0.0.0.0 MDBOOK_DEV_PORT = 3000 -VERSION ?= $(shell git describe --always --tag --dirty=-dev) # ENVTEST_K8S_VERSION # - refers to the version of kubebuilder assets to be downloaded by envtest binary. diff --git a/README.md b/README.md index d1165d7fd..7d8fb1c82 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,10 @@ + + + + diff --git a/cloud/scope/client.go b/cloud/scope/client.go index a215b4836..4ac98c377 100644 --- a/cloud/scope/client.go +++ b/cloud/scope/client.go @@ -3,10 +3,27 @@ package scope import ( "context" + "github.com/linode/linodego" "sigs.k8s.io/cluster-api/util/patch" "sigs.k8s.io/controller-runtime/pkg/client" ) +// LinodeObjectStorageClient defines functions suitable for provisioning object storage buckets and keys. +type LinodeObjectStorageClient interface { + GetObjectStorageBucket(ctx context.Context, cluster, label string) (*linodego.ObjectStorageBucket, error) + CreateObjectStorageBucket(ctx context.Context, opts linodego.ObjectStorageBucketCreateOptions) (*linodego.ObjectStorageBucket, error) + CreateObjectStorageKey(ctx context.Context, opts linodego.ObjectStorageKeyCreateOptions) (*linodego.ObjectStorageKey, error) + DeleteObjectStorageKey(ctx context.Context, keyID int) error +} + +// LinodeObjectStorageClientBuilder is a function that returns a LinodeObjectStorageClient. +type LinodeObjectStorageClientBuilder func(apiKey string) (LinodeObjectStorageClient, error) + +// CreateLinodeObjectStorageClient is the main implementation of LinodeObjectStorageClientBuilder. +func CreateLinodeObjectStorageClient(apiKey string) (LinodeObjectStorageClient, error) { + return CreateLinodeClient(apiKey) +} + type k8sClient interface { client.Client } diff --git a/cloud/scope/cluster.go b/cloud/scope/cluster.go index b550ecd12..6947588e1 100644 --- a/cloud/scope/cluster.go +++ b/cloud/scope/cluster.go @@ -61,7 +61,7 @@ func NewClusterScope(ctx context.Context, apiKey string, params ClusterScopePara } apiKey = string(data) } - linodeClient, err := createLinodeClient(apiKey) + linodeClient, err := CreateLinodeClient(apiKey) if err != nil { return nil, fmt.Errorf("failed to create linode client: %w", err) } diff --git a/cloud/scope/cluster_test.go b/cloud/scope/cluster_test.go index 40806e634..51bbc23de 100644 --- a/cloud/scope/cluster_test.go +++ b/cloud/scope/cluster_test.go @@ -141,7 +141,7 @@ func TestClusterScopeMethods(t *testing.T) { mockPatchHelper := mock.NewMockPatchHelper(ctrl) mockK8sClient := mock.NewMockk8sClient(ctrl) - lClient, err := createLinodeClient("test-key") + lClient, err := CreateLinodeClient("test-key") if err != nil { t.Errorf("createLinodeClient() error = %v", err) } diff --git a/cloud/scope/common.go b/cloud/scope/common.go index f75cd58b9..b14de5f32 100644 --- a/cloud/scope/common.go +++ b/cloud/scope/common.go @@ -17,7 +17,7 @@ import ( type patchNewHelper func(obj client.Object, crClient client.Client) (*patch.Helper, error) -func createLinodeClient(apiKey string) (*linodego.Client, error) { +func CreateLinodeClient(apiKey string) (*linodego.Client, error) { if apiKey == "" { return nil, errors.New("missing Linode API key") } diff --git a/cloud/scope/common_test.go b/cloud/scope/common_test.go index b3671a6d3..7eec6e8aa 100644 --- a/cloud/scope/common_test.go +++ b/cloud/scope/common_test.go @@ -40,7 +40,7 @@ func TestCreateLinodeClient(t *testing.T) { t.Run(testCase.name, func(t *testing.T) { t.Parallel() - got, err := createLinodeClient(testCase.apiKey) + got, err := CreateLinodeClient(testCase.apiKey) if testCase.expectedErr != nil { assert.EqualError(t, err, testCase.expectedErr.Error()) diff --git a/cloud/scope/machine.go b/cloud/scope/machine.go index 5ff257c62..cbfc04a08 100644 --- a/cloud/scope/machine.go +++ b/cloud/scope/machine.go @@ -83,7 +83,7 @@ func NewMachineScope(ctx context.Context, apiKey string, params MachineScopePara } apiKey = string(data) } - linodeClient, err := createLinodeClient(apiKey) + linodeClient, err := CreateLinodeClient(apiKey) if err != nil { return nil, fmt.Errorf("failed to create linode client: %w", err) } diff --git a/cloud/scope/object_storage_bucket.go b/cloud/scope/object_storage_bucket.go index 68e6697fd..4202b8249 100644 --- a/cloud/scope/object_storage_bucket.go +++ b/cloud/scope/object_storage_bucket.go @@ -18,16 +18,17 @@ import ( ) type ObjectStorageBucketScopeParams struct { - Client client.Client - Bucket *infrav1alpha1.LinodeObjectStorageBucket - Logger *logr.Logger + Client client.Client + LinodeClientBuilder LinodeObjectStorageClientBuilder + Bucket *infrav1alpha1.LinodeObjectStorageBucket + Logger *logr.Logger } type ObjectStorageBucketScope struct { client client.Client Bucket *infrav1alpha1.LinodeObjectStorageBucket Logger logr.Logger - LinodeClient *linodego.Client + LinodeClient LinodeObjectStorageClient BucketPatchHelper *patch.Helper } @@ -41,6 +42,9 @@ func validateObjectStorageBucketScopeParams(params ObjectStorageBucketScopeParam if params.Logger == nil { return errors.New("logger is required when creating an ObjectStorageBucketScope") } + if params.LinodeClientBuilder == nil { + return errors.New("LinodeClientBuilder is required when creating an ObjectStorageBucketScope") + } return nil } @@ -58,7 +62,7 @@ func NewObjectStorageBucketScope(ctx context.Context, apiKey string, params Obje } apiKey = string(data) } - linodeClient, err := createLinodeClient(apiKey) + linodeClient, err := params.LinodeClientBuilder(apiKey) if err != nil { return nil, fmt.Errorf("failed to create linode client: %w", err) } diff --git a/cloud/scope/vpc.go b/cloud/scope/vpc.go index 2b8f3deda..10b092b44 100644 --- a/cloud/scope/vpc.go +++ b/cloud/scope/vpc.go @@ -67,7 +67,7 @@ func NewVPCScope(ctx context.Context, apiKey string, params VPCScopeParams) (*VP } apiKey = string(data) } - linodeClient, err := createLinodeClient(apiKey) + linodeClient, err := CreateLinodeClient(apiKey) if err != nil { return nil, fmt.Errorf("failed to create linode client: %w", err) } diff --git a/cmd/main.go b/cmd/main.go index ff661f4db..0c2fd063f 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -32,6 +32,7 @@ import ( metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" infrastructurev1alpha1 "github.com/linode/cluster-api-provider-linode/api/v1alpha1" + "github.com/linode/cluster-api-provider-linode/cloud/scope" controller2 "github.com/linode/cluster-api-provider-linode/controller" "github.com/linode/cluster-api-provider-linode/version" @@ -140,12 +141,13 @@ func main() { os.Exit(1) } if err = (&controller2.LinodeObjectStorageBucketReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - Logger: ctrl.Log.WithName("LinodeObjectStorageBucketReconciler"), - Recorder: mgr.GetEventRecorderFor("LinodeObjectStorageBucketReconciler"), - WatchFilterValue: objectStorageBucketWatchFilter, - LinodeApiKey: linodeToken, + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + Logger: ctrl.Log.WithName("LinodeObjectStorageBucketReconciler"), + Recorder: mgr.GetEventRecorderFor("LinodeObjectStorageBucketReconciler"), + WatchFilterValue: objectStorageBucketWatchFilter, + LinodeApiKey: linodeToken, + LinodeClientBuilder: scope.CreateLinodeObjectStorageClient, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "LinodeObjectStorageBucket") os.Exit(1) diff --git a/controller/linodeobjectstoragebucket_controller.go b/controller/linodeobjectstoragebucket_controller.go index 0a059b443..480991fe2 100644 --- a/controller/linodeobjectstoragebucket_controller.go +++ b/controller/linodeobjectstoragebucket_controller.go @@ -46,12 +46,13 @@ import ( // LinodeObjectStorageBucketReconciler reconciles a LinodeObjectStorageBucket object type LinodeObjectStorageBucketReconciler struct { client.Client - Scheme *runtime.Scheme - Logger logr.Logger - Recorder record.EventRecorder - LinodeApiKey string - WatchFilterValue string - ReconcileTimeout time.Duration + Scheme *runtime.Scheme + Logger logr.Logger + Recorder record.EventRecorder + LinodeApiKey string + LinodeClientBuilder scope.LinodeObjectStorageClientBuilder + WatchFilterValue string + ReconcileTimeout time.Duration } // +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=linodeobjectstoragebuckets,verbs=get;list;watch;create;update;patch;delete @@ -89,9 +90,10 @@ func (r *LinodeObjectStorageBucketReconciler) Reconcile(ctx context.Context, req ctx, r.LinodeApiKey, scope.ObjectStorageBucketScopeParams{ - Client: r.Client, - Bucket: objectStorageBucket, - Logger: &logger, + Client: r.Client, + LinodeClientBuilder: r.LinodeClientBuilder, + Bucket: objectStorageBucket, + Logger: &logger, }, ) if err != nil { @@ -175,7 +177,7 @@ func (r *LinodeObjectStorageBucketReconciler) reconcileApply(ctx context.Context bScope.Bucket.Status.LastKeyGeneration = bScope.Bucket.Spec.KeyGeneration } - r.Recorder.Event(bScope.Bucket, corev1.EventTypeNormal, "Ready", "Object storage bucket configuration applied") + r.Recorder.Event(bScope.Bucket, corev1.EventTypeNormal, "Ready", "Object storage bucket applied") bScope.Bucket.Status.Ready = true conditions.MarkTrue(bScope.Bucket, clusterv1.ReadyCondition) @@ -195,7 +197,7 @@ func (r *LinodeObjectStorageBucketReconciler) reconcileDelete(ctx context.Contex } if err := services.RevokeObjectStorageKeys(ctx, bScope, secret); err != nil { - bScope.Logger.Error(err, "failed to revoke access keys; keys must be manually revoked") + bScope.Logger.Error(err, "Failed to revoke access keys; keys must be manually revoked") r.setFailure(bScope, err) return err @@ -223,6 +225,8 @@ func (r *LinodeObjectStorageBucketReconciler) reconcileDelete(ctx context.Contex return err } + r.Recorder.Event(bScope.Bucket, clusterv1.DeletedReason, "Ready", "Object storage bucket deleted") + return nil } diff --git a/controller/linodeobjectstoragebucket_controller_test.go b/controller/linodeobjectstoragebucket_controller_test.go new file mode 100644 index 000000000..2633a5591 --- /dev/null +++ b/controller/linodeobjectstoragebucket_controller_test.go @@ -0,0 +1,184 @@ +// /* +// Copyright 2023 Akamai Technologies, Inc. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// */ + +package controller + +import ( + "context" + "fmt" + "time" + + "github.com/linode/linodego" + "go.uber.org/mock/gomock" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + infrav1 "github.com/linode/cluster-api-provider-linode/api/v1alpha1" + "github.com/linode/cluster-api-provider-linode/cloud/scope" + "github.com/linode/cluster-api-provider-linode/mock" + "github.com/linode/cluster-api-provider-linode/util" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func mockClientBuilder(m *mock.MockLinodeObjectStorageClient) scope.LinodeObjectStorageClientBuilder { + return func(_ string) (scope.LinodeObjectStorageClient, error) { + return m, nil + } +} + +var _ = Describe("LinodeObjectStorageBucket controller", func() { + ctx := context.Background() + + obj := &infrav1.LinodeObjectStorageBucket{ + ObjectMeta: metav1.ObjectMeta{ + Name: "sample-bucket", + Namespace: "default", + }, + Spec: infrav1.LinodeObjectStorageBucketSpec{ + Cluster: "cluster", + Label: util.Pointer("sample"), + }, + } + + recorder := record.NewFakeRecorder(3) + + secretName := fmt.Sprintf(scope.AccessKeyNameTemplate, *obj.Spec.Label) + + var secret corev1.Secret + var mockCtrl *gomock.Controller + + BeforeEach(func() { + // Create a new gomock controller for each test run + mockCtrl = gomock.NewController(GinkgoT()) + }) + + AfterEach(func() { + // At the end of each test run, tell the gomock controller it's done + // so it can check configured expectations and validate the methods called + mockCtrl.Finish() + }) + + It("should reconcile an object apply", func() { + mockClient := mock.NewMockLinodeObjectStorageClient(mockCtrl) + + getCall := mockClient.EXPECT(). + GetObjectStorageBucket(gomock.Any(), obj.Spec.Cluster, gomock.Any()). + Return(nil, nil). + Times(1) + + createBucketCall := mockClient.EXPECT(). + CreateObjectStorageBucket(gomock.Any(), gomock.Any()). + Return(&linodego.ObjectStorageBucket{ + Label: *obj.Spec.Label, + Cluster: obj.Spec.Cluster, + Created: util.Pointer(time.Now()), + Hostname: "hostname", + }, nil). + Times(1). + After(getCall) + + for idx, permission := range []string{"rw", "ro"} { + mockClient.EXPECT(). + CreateObjectStorageKey( + gomock.Any(), + gomock.Cond(func(opt any) bool { + createOpt, ok := opt.(linodego.ObjectStorageKeyCreateOptions) + if !ok { + return false + } + + return createOpt.Label == fmt.Sprintf("%s-%s", *obj.Spec.Label, permission) + }), + ). + Return(&linodego.ObjectStorageKey{ID: idx}, nil). + Times(1). + After(createBucketCall) + } + + reconciler := &LinodeObjectStorageBucketReconciler{ + Client: k8sClient, + Scheme: k8sClient.Scheme(), + Logger: ctrl.Log.WithName("LinodeObjectStorageBucketReconciler"), + Recorder: recorder, + LinodeClientBuilder: mockClientBuilder(mockClient), + } + + objectKey := client.ObjectKeyFromObject(obj) + Expect(k8sClient.Create(ctx, obj)).To(Succeed()) + _, err := reconciler.Reconcile(ctx, reconcile.Request{ + NamespacedName: objectKey, + }) + Expect(err).NotTo(HaveOccurred()) + + By("updating its status fields") + Expect(k8sClient.Get(ctx, objectKey, obj)).To(Succeed()) + Expect(*obj.Status.Hostname).To(Equal("hostname")) + Expect(*obj.Status.KeySecretName).To(Equal(secretName)) + Expect(*obj.Status.LastKeyGeneration).To(Equal(*obj.Spec.KeyGeneration)) + Expect(*obj.Status.LastKeyGeneration).To(Equal(0)) + Expect(obj.Status.Ready).To(BeTrue()) + + By("creating a Secret with access keys") + Expect(k8sClient.Get(ctx, client.ObjectKey{ + Name: secretName, + Namespace: obj.Namespace, + }, &secret)).To(Succeed()) + Expect(secret.Data["read_write"]).To(Not(BeNil())) + Expect(secret.Data["read_only"]).To(Not(BeNil())) + + By("recording the expected event") + Expect(<-recorder.Events).To(ContainSubstring("Object storage bucket applied")) + }) + + It("should reconcile an object delete", func() { + mockClient := mock.NewMockLinodeObjectStorageClient(mockCtrl) + + for i := range 2 { + mockClient.EXPECT(). + DeleteObjectStorageKey(gomock.Any(), i). + Return(nil). + Times(1) + } + + reconciler := &LinodeObjectStorageBucketReconciler{ + Client: k8sClient, + Scheme: k8sClient.Scheme(), + Logger: ctrl.Log.WithName("LinodeObjectStorageBucketReconciler"), + Recorder: recorder, + LinodeClientBuilder: mockClientBuilder(mockClient), + } + + objectKey := client.ObjectKeyFromObject(obj) + Expect(k8sClient.Delete(ctx, obj)).To(Succeed()) + _, err := reconciler.Reconcile(ctx, reconcile.Request{ + NamespacedName: objectKey, + }) + Expect(err).NotTo(HaveOccurred()) + + By("removing the finalizer so it is deleted") + Expect(apierrors.IsNotFound(k8sClient.Get(ctx, objectKey, obj))).To(BeTrue()) + + By("recording the expected event") + Expect(<-recorder.Events).To(ContainSubstring("Object storage bucket deleted")) + }) +}) diff --git a/controller/suite_test.go b/controller/suite_test.go index 4fe9135e1..cb9aab151 100644 --- a/controller/suite_test.go +++ b/controller/suite_test.go @@ -29,7 +29,8 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" - infrastructurev1alpha1 "github.com/linode/cluster-api-provider-linode/api/v1alpha1" + infrav1 "github.com/linode/cluster-api-provider-linode/api/v1alpha1" + //+kubebuilder:scaffold:imports . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -64,7 +65,7 @@ var _ = BeforeSuite(func() { // default path defined in controller-runtime which is /usr/local/kubebuilder/. // Note that you must have the required binaries setup under the bin directory to perform // the tests directly. When we run make test it will be setup and used automatically. - BinaryAssetsDirectory: filepath.Join("..", "..", "bin", "k8s", + BinaryAssetsDirectory: filepath.Join("..", "bin", "k8s", fmt.Sprintf("1.28.0-%s-%s", runtime.GOOS, runtime.GOARCH)), } @@ -74,15 +75,13 @@ var _ = BeforeSuite(func() { Expect(err).NotTo(HaveOccurred()) Expect(cfg).NotTo(BeNil()) - err = infrastructurev1alpha1.AddToScheme(scheme.Scheme) - Expect(err).NotTo(HaveOccurred()) + Expect(infrav1.AddToScheme(scheme.Scheme)).To(Succeed()) //+kubebuilder:scaffold:scheme k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) Expect(err).NotTo(HaveOccurred()) Expect(k8sClient).NotTo(BeNil()) - }) var _ = AfterSuite(func() { diff --git a/mock/client.go b/mock/client.go index f044b30f0..6895442fe 100644 --- a/mock/client.go +++ b/mock/client.go @@ -13,6 +13,7 @@ import ( context "context" reflect "reflect" + linodego "github.com/linode/linodego" gomock "go.uber.org/mock/gomock" meta "k8s.io/apimachinery/pkg/api/meta" runtime "k8s.io/apimachinery/pkg/runtime" @@ -21,6 +22,88 @@ import ( client "sigs.k8s.io/controller-runtime/pkg/client" ) +// MockLinodeObjectStorageClient is a mock of LinodeObjectStorageClient interface. +type MockLinodeObjectStorageClient struct { + ctrl *gomock.Controller + recorder *MockLinodeObjectStorageClientMockRecorder +} + +// MockLinodeObjectStorageClientMockRecorder is the mock recorder for MockLinodeObjectStorageClient. +type MockLinodeObjectStorageClientMockRecorder struct { + mock *MockLinodeObjectStorageClient +} + +// NewMockLinodeObjectStorageClient creates a new mock instance. +func NewMockLinodeObjectStorageClient(ctrl *gomock.Controller) *MockLinodeObjectStorageClient { + mock := &MockLinodeObjectStorageClient{ctrl: ctrl} + mock.recorder = &MockLinodeObjectStorageClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockLinodeObjectStorageClient) EXPECT() *MockLinodeObjectStorageClientMockRecorder { + return m.recorder +} + +// CreateObjectStorageBucket mocks base method. +func (m *MockLinodeObjectStorageClient) CreateObjectStorageBucket(ctx context.Context, opts linodego.ObjectStorageBucketCreateOptions) (*linodego.ObjectStorageBucket, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateObjectStorageBucket", ctx, opts) + ret0, _ := ret[0].(*linodego.ObjectStorageBucket) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateObjectStorageBucket indicates an expected call of CreateObjectStorageBucket. +func (mr *MockLinodeObjectStorageClientMockRecorder) CreateObjectStorageBucket(ctx, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateObjectStorageBucket", reflect.TypeOf((*MockLinodeObjectStorageClient)(nil).CreateObjectStorageBucket), ctx, opts) +} + +// CreateObjectStorageKey mocks base method. +func (m *MockLinodeObjectStorageClient) CreateObjectStorageKey(ctx context.Context, opts linodego.ObjectStorageKeyCreateOptions) (*linodego.ObjectStorageKey, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateObjectStorageKey", ctx, opts) + ret0, _ := ret[0].(*linodego.ObjectStorageKey) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateObjectStorageKey indicates an expected call of CreateObjectStorageKey. +func (mr *MockLinodeObjectStorageClientMockRecorder) CreateObjectStorageKey(ctx, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateObjectStorageKey", reflect.TypeOf((*MockLinodeObjectStorageClient)(nil).CreateObjectStorageKey), ctx, opts) +} + +// DeleteObjectStorageKey mocks base method. +func (m *MockLinodeObjectStorageClient) DeleteObjectStorageKey(ctx context.Context, keyID int) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteObjectStorageKey", ctx, keyID) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteObjectStorageKey indicates an expected call of DeleteObjectStorageKey. +func (mr *MockLinodeObjectStorageClientMockRecorder) DeleteObjectStorageKey(ctx, keyID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteObjectStorageKey", reflect.TypeOf((*MockLinodeObjectStorageClient)(nil).DeleteObjectStorageKey), ctx, keyID) +} + +// GetObjectStorageBucket mocks base method. +func (m *MockLinodeObjectStorageClient) GetObjectStorageBucket(ctx context.Context, cluster, label string) (*linodego.ObjectStorageBucket, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetObjectStorageBucket", ctx, cluster, label) + ret0, _ := ret[0].(*linodego.ObjectStorageBucket) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetObjectStorageBucket indicates an expected call of GetObjectStorageBucket. +func (mr *MockLinodeObjectStorageClientMockRecorder) GetObjectStorageBucket(ctx, cluster, label any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetObjectStorageBucket", reflect.TypeOf((*MockLinodeObjectStorageClient)(nil).GetObjectStorageBucket), ctx, cluster, label) +} + // Mockk8sClient is a mock of k8sClient interface. type Mockk8sClient struct { ctrl *gomock.Controller