diff --git a/Makefile b/Makefile index 1058649..8fd0284 100644 --- a/Makefile +++ b/Makefile @@ -65,7 +65,7 @@ GOLANGCI_LINT_VERSION ?= v1.57.2 .PHONY: all -all: fmt vet lint generate manifests kustomize helmify generate-docs mock +all: fmt vet lint generate manifests kustomize helmify generate-docs ##@ Development @@ -223,3 +223,9 @@ OPERATOR_SDK = $(shell which operator-sdk) endif endif +.PHONY: test-deploy +test-deploy: build install + docker build . -t ghcr.io/kkb0318/irsa-manager + docker push ghcr.io/kkb0318/irsa-manager:latest + + diff --git a/api/v1alpha1/irsa_types.go b/api/v1alpha1/irsa_types.go index 00fa184..f890f42 100644 --- a/api/v1alpha1/irsa_types.go +++ b/api/v1alpha1/irsa_types.go @@ -20,9 +20,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! -// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. - // IRSASpec defines the desired state of IRSA type IRSASpec struct { // ServiceAccount represents the Kubernetes service account associated with the IRSA @@ -43,8 +40,6 @@ type IRSAServiceAccount struct { // IamRole represents the IAM role configuration type IamRole struct { - // Create specifies whether to create the IAM role or not - Create bool `json:"create,omitempty"` // Name represents the name of the IAM role Name string `json:"name,omitempty"` } diff --git a/config/crd/bases/irsa.kkb0318.github.io_irsas.yaml b/config/crd/bases/irsa.kkb0318.github.io_irsas.yaml index 98ad280..14977f2 100644 --- a/config/crd/bases/irsa.kkb0318.github.io_irsas.yaml +++ b/config/crd/bases/irsa.kkb0318.github.io_irsas.yaml @@ -49,10 +49,6 @@ spec: description: IamRole represents the IAM role details associated with the IRSA properties: - create: - description: Create specifies whether to create the IAM role or - not - type: boolean name: description: Name represents the name of the IAM role type: string diff --git a/docs/api.md b/docs/api.md index e91038a..b70f842 100644 --- a/docs/api.md +++ b/docs/api.md @@ -154,7 +154,6 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `create` _boolean_ | Create specifies whether to create the IAM role or not | | | | `name` _string_ | Name represents the name of the IAM role | | | diff --git a/internal/aws/aws.go b/internal/aws/aws.go index 0a4e267..fbc429d 100644 --- a/internal/aws/aws.go +++ b/internal/aws/aws.go @@ -25,6 +25,11 @@ type AwsClientFactory struct { type AwsIamAPI interface { CreateOpenIDConnectProvider(ctx context.Context, params *iam.CreateOpenIDConnectProviderInput, optFns ...func(*iam.Options)) (*iam.CreateOpenIDConnectProviderOutput, error) DeleteOpenIDConnectProvider(ctx context.Context, params *iam.DeleteOpenIDConnectProviderInput, optFns ...func(*iam.Options)) (*iam.DeleteOpenIDConnectProviderOutput, error) + CreateRole(ctx context.Context, params *iam.CreateRoleInput, optFns ...func(*iam.Options)) (*iam.CreateRoleOutput, error) + UpdateAssumeRolePolicy(ctx context.Context, params *iam.UpdateAssumeRolePolicyInput, optFns ...func(*iam.Options)) (*iam.UpdateAssumeRolePolicyOutput, error) + AttachRolePolicy(ctx context.Context, params *iam.AttachRolePolicyInput, optFns ...func(*iam.Options)) (*iam.AttachRolePolicyOutput, error) + DeleteRole(ctx context.Context, params *iam.DeleteRoleInput, optFns ...func(*iam.Options)) (*iam.DeleteRoleOutput, error) + DetachRolePolicy(ctx context.Context, params *iam.DetachRolePolicyInput, optFns ...func(*iam.Options)) (*iam.DetachRolePolicyOutput, error) } type AwsStsAPI interface { diff --git a/internal/aws/aws_role.go b/internal/aws/aws_role.go new file mode 100644 index 0000000..538cef8 --- /dev/null +++ b/internal/aws/aws_role.go @@ -0,0 +1,134 @@ +package aws + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "log" + "slices" + "strings" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iam" + "github.com/aws/smithy-go" +) + +// RoleManager represents the details needed to manage IAM roles +type RoleManager struct { + // RoleName represents the name of the IAM role + RoleName string + // Namespaces represents the list of namespaces associated with the role + Namespaces []string + // Policies represents the list of policies to be attached to the role + Policies []string +} + +func (r *RoleManager) PolicyArn(policy string) *string { + prefix := "arn:aws:iam::" + if strings.HasPrefix(policy, prefix) { + return aws.String(policy) + } + return aws.String(fmt.Sprintf("%saws:policy/%s", prefix, policy)) +} + +// DeleteIRSARole detaches specified policies from the IAM role and deletes the IAM role +func (a *AwsIamClient) DeleteIRSARole(ctx context.Context, r RoleManager) error { + for _, policy := range r.Policies { + detachRolePolicyInput := &iam.DetachRolePolicyInput{ + RoleName: aws.String(r.RoleName), + PolicyArn: r.PolicyArn(policy), + } + _, err := a.Client.DetachRolePolicy(ctx, detachRolePolicyInput) + // Ignore error if the policy is already detached or the role does not exist + if errorHandle(err, []string{"NoSuchEntity"}) != nil { + return err + } + log.Printf("Policy %s detached from role %s successfully", policy, r.RoleName) + + } + input := &iam.DeleteRoleInput{RoleName: aws.String(r.RoleName)} + _, err := a.Client.DeleteRole(ctx, input) + // Ignore error if the role does not exist or there are other policies that this controller does not manage + if errorHandle(err, []string{"DeleteConflict", "NoSuchEntity"}) != nil { + return err + } + log.Printf("Role %s deleted successfully", r.RoleName) + return nil +} + +// CreateIRSARole creates an IAM role with the specified trust policy and attaches specified policies to it +func (a *AwsIamClient) CreateIRSARole(ctx context.Context, accountId, issuerHostPath string, r RoleManager) error { + providerArn := fmt.Sprintf("arn:aws:iam::%s:oidc-provider/%s", accountId, issuerHostPath) + statement := make([]map[string]interface{}, len(r.Namespaces)) + for i, ns := range r.Namespaces { + statement[i] = map[string]interface{}{ + "Effect": "Allow", + "Principal": map[string]interface{}{ + "Federated": providerArn, + }, + "Action": "sts:AssumeRoleWithWebIdentity", + "Condition": map[string]interface{}{ + "StringEquals": map[string]interface{}{ + fmt.Sprintf("%s:sub", issuerHostPath): fmt.Sprintf("system:serviceaccount:%s:%s", ns, r.RoleName), + }, + }, + } + } + trustPolicy := map[string]interface{}{ + "Version": "2012-10-17", + "Statement": statement, + } + trustPolicyJSON, err := json.Marshal(trustPolicy) + if err != nil { + return fmt.Errorf("failed to marshal trust policy: %w", err) + } + createRoleInput := &iam.CreateRoleInput{ + RoleName: aws.String(r.RoleName), + AssumeRolePolicyDocument: aws.String(string(trustPolicyJSON)), + } + + _, err = a.Client.CreateRole(context.TODO(), createRoleInput) + if errorHandle(err, []string{"EntityAlreadyExists"}) != nil { + return err + } + log.Printf("Role %s created successfully", r.RoleName) + + updateRoleInput := &iam.UpdateAssumeRolePolicyInput{ + RoleName: aws.String(r.RoleName), + PolicyDocument: aws.String(string(trustPolicyJSON)), + } + + _, err = a.Client.UpdateAssumeRolePolicy(context.TODO(), updateRoleInput) + if err != nil { + return fmt.Errorf("failed to update assume role policy for role %s: %w", r.RoleName, err) + } + log.Printf("Assume role policy for %s updated successfully", r.RoleName) + + for _, policy := range r.Policies { + attachRolePolicyInput := &iam.AttachRolePolicyInput{ + RoleName: aws.String(r.RoleName), + PolicyArn: r.PolicyArn(policy), + } + + _, err = a.Client.AttachRolePolicy(context.TODO(), attachRolePolicyInput) + if err != nil { + return err + } + log.Printf("Policy %s attached to role %s successfully", policy, r.RoleName) + + } + return nil +} + +// errorHandle handles specific errors by checking the error code against a list of codes to ignore +func errorHandle(err error, errorCodes []string) error { + if err != nil { + var ae smithy.APIError + if errors.As(err, &ae) && slices.Contains(errorCodes, ae.ErrorCode()) { + fmt.Printf("Skipped error: %s \n", err.Error()) + return nil + } + } + return err +} diff --git a/internal/controller/irsasetup_controller_test.go b/internal/controller/irsasetup_controller_test.go index 23850c4..5006009 100644 --- a/internal/controller/irsasetup_controller_test.go +++ b/internal/controller/irsasetup_controller_test.go @@ -371,6 +371,26 @@ func (m *mockAwsIamAPI) DeleteOpenIDConnectProvider(ctx context.Context, params return &iam.DeleteOpenIDConnectProviderOutput{}, nil } +func (m *mockAwsIamAPI) CreateRole(ctx context.Context, params *iam.CreateRoleInput, optFns ...func(*iam.Options)) (*iam.CreateRoleOutput, error) { + return nil, nil +} + +func (m *mockAwsIamAPI) UpdateAssumeRolePolicy(ctx context.Context, params *iam.UpdateAssumeRolePolicyInput, optFns ...func(*iam.Options)) (*iam.UpdateAssumeRolePolicyOutput, error) { + return nil, nil +} + +func (m *mockAwsIamAPI) AttachRolePolicy(ctx context.Context, params *iam.AttachRolePolicyInput, optFns ...func(*iam.Options)) (*iam.AttachRolePolicyOutput, error) { + return nil, nil +} + +func (m *mockAwsIamAPI) DeleteRole(ctx context.Context, params *iam.DeleteRoleInput, optFns ...func(*iam.Options)) (*iam.DeleteRoleOutput, error) { + return nil, nil +} + +func (m *mockAwsIamAPI) DetachRolePolicy(ctx context.Context, params *iam.DetachRolePolicyInput, optFns ...func(*iam.Options)) (*iam.DetachRolePolicyOutput, error) { + return nil, nil +} + func (m *mockAwsStsAPI) GetCallerIdentity(ctx context.Context, params *sts.GetCallerIdentityInput, optFns ...func(*sts.Options)) (*sts.GetCallerIdentityOutput, error) { return &sts.GetCallerIdentityOutput{Account: aws.String("123456789012")}, nil } diff --git a/internal/mock/aws_mock.go b/internal/mock/aws_mock.go deleted file mode 100644 index 0e656e5..0000000 --- a/internal/mock/aws_mock.go +++ /dev/null @@ -1,289 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: internal/client/aws.go -// -// Generated by this command: -// -// mockgen -source internal/client/aws.go -destination internal/mock/aws_mock.go -package mock -// - -// Package mock is a generated GoMock package. -package mock - -import ( - context "context" - reflect "reflect" - - iam "github.com/aws/aws-sdk-go-v2/service/iam" - s3 "github.com/aws/aws-sdk-go-v2/service/s3" - sts "github.com/aws/aws-sdk-go-v2/service/sts" - gomock "go.uber.org/mock/gomock" -) - -// MockAwsIamAPI is a mock of AwsIamAPI interface. -type MockAwsIamAPI struct { - ctrl *gomock.Controller - recorder *MockAwsIamAPIMockRecorder -} - -// MockAwsIamAPIMockRecorder is the mock recorder for MockAwsIamAPI. -type MockAwsIamAPIMockRecorder struct { - mock *MockAwsIamAPI -} - -// NewMockAwsIamAPI creates a new mock instance. -func NewMockAwsIamAPI(ctrl *gomock.Controller) *MockAwsIamAPI { - mock := &MockAwsIamAPI{ctrl: ctrl} - mock.recorder = &MockAwsIamAPIMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockAwsIamAPI) EXPECT() *MockAwsIamAPIMockRecorder { - return m.recorder -} - -// CreateOpenIDConnectProvider mocks base method. -func (m *MockAwsIamAPI) CreateOpenIDConnectProvider(ctx context.Context, params *iam.CreateOpenIDConnectProviderInput, optFns ...func(*iam.Options)) (*iam.CreateOpenIDConnectProviderOutput, error) { - m.ctrl.T.Helper() - varargs := []any{ctx, params} - for _, a := range optFns { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "CreateOpenIDConnectProvider", varargs...) - ret0, _ := ret[0].(*iam.CreateOpenIDConnectProviderOutput) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CreateOpenIDConnectProvider indicates an expected call of CreateOpenIDConnectProvider. -func (mr *MockAwsIamAPIMockRecorder) CreateOpenIDConnectProvider(ctx, params any, optFns ...any) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]any{ctx, params}, optFns...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOpenIDConnectProvider", reflect.TypeOf((*MockAwsIamAPI)(nil).CreateOpenIDConnectProvider), varargs...) -} - -// DeleteOpenIDConnectProvider mocks base method. -func (m *MockAwsIamAPI) DeleteOpenIDConnectProvider(ctx context.Context, params *iam.DeleteOpenIDConnectProviderInput, optFns ...func(*iam.Options)) (*iam.DeleteOpenIDConnectProviderOutput, error) { - m.ctrl.T.Helper() - varargs := []any{ctx, params} - for _, a := range optFns { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DeleteOpenIDConnectProvider", varargs...) - ret0, _ := ret[0].(*iam.DeleteOpenIDConnectProviderOutput) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DeleteOpenIDConnectProvider indicates an expected call of DeleteOpenIDConnectProvider. -func (mr *MockAwsIamAPIMockRecorder) DeleteOpenIDConnectProvider(ctx, params any, optFns ...any) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]any{ctx, params}, optFns...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteOpenIDConnectProvider", reflect.TypeOf((*MockAwsIamAPI)(nil).DeleteOpenIDConnectProvider), varargs...) -} - -// MockAwsStsAPI is a mock of AwsStsAPI interface. -type MockAwsStsAPI struct { - ctrl *gomock.Controller - recorder *MockAwsStsAPIMockRecorder -} - -// MockAwsStsAPIMockRecorder is the mock recorder for MockAwsStsAPI. -type MockAwsStsAPIMockRecorder struct { - mock *MockAwsStsAPI -} - -// NewMockAwsStsAPI creates a new mock instance. -func NewMockAwsStsAPI(ctrl *gomock.Controller) *MockAwsStsAPI { - mock := &MockAwsStsAPI{ctrl: ctrl} - mock.recorder = &MockAwsStsAPIMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockAwsStsAPI) EXPECT() *MockAwsStsAPIMockRecorder { - return m.recorder -} - -// GetCallerIdentity mocks base method. -func (m *MockAwsStsAPI) GetCallerIdentity(ctx context.Context, params *sts.GetCallerIdentityInput, optFns ...func(*sts.Options)) (*sts.GetCallerIdentityOutput, error) { - m.ctrl.T.Helper() - varargs := []any{ctx, params} - for _, a := range optFns { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "GetCallerIdentity", varargs...) - ret0, _ := ret[0].(*sts.GetCallerIdentityOutput) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetCallerIdentity indicates an expected call of GetCallerIdentity. -func (mr *MockAwsStsAPIMockRecorder) GetCallerIdentity(ctx, params any, optFns ...any) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]any{ctx, params}, optFns...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCallerIdentity", reflect.TypeOf((*MockAwsStsAPI)(nil).GetCallerIdentity), varargs...) -} - -// MockAwsS3API is a mock of AwsS3API interface. -type MockAwsS3API struct { - ctrl *gomock.Controller - recorder *MockAwsS3APIMockRecorder -} - -// MockAwsS3APIMockRecorder is the mock recorder for MockAwsS3API. -type MockAwsS3APIMockRecorder struct { - mock *MockAwsS3API -} - -// NewMockAwsS3API creates a new mock instance. -func NewMockAwsS3API(ctrl *gomock.Controller) *MockAwsS3API { - mock := &MockAwsS3API{ctrl: ctrl} - mock.recorder = &MockAwsS3APIMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockAwsS3API) EXPECT() *MockAwsS3APIMockRecorder { - return m.recorder -} - -// CreateBucket mocks base method. -func (m *MockAwsS3API) CreateBucket(ctx context.Context, params *s3.CreateBucketInput, optFns ...func(*s3.Options)) (*s3.CreateBucketOutput, error) { - m.ctrl.T.Helper() - varargs := []any{ctx, params} - for _, a := range optFns { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "CreateBucket", varargs...) - ret0, _ := ret[0].(*s3.CreateBucketOutput) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CreateBucket indicates an expected call of CreateBucket. -func (mr *MockAwsS3APIMockRecorder) CreateBucket(ctx, params any, optFns ...any) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]any{ctx, params}, optFns...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateBucket", reflect.TypeOf((*MockAwsS3API)(nil).CreateBucket), varargs...) -} - -// DeleteBucket mocks base method. -func (m *MockAwsS3API) DeleteBucket(ctx context.Context, params *s3.DeleteBucketInput, optFns ...func(*s3.Options)) (*s3.DeleteBucketOutput, error) { - m.ctrl.T.Helper() - varargs := []any{ctx, params} - for _, a := range optFns { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DeleteBucket", varargs...) - ret0, _ := ret[0].(*s3.DeleteBucketOutput) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DeleteBucket indicates an expected call of DeleteBucket. -func (mr *MockAwsS3APIMockRecorder) DeleteBucket(ctx, params any, optFns ...any) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]any{ctx, params}, optFns...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteBucket", reflect.TypeOf((*MockAwsS3API)(nil).DeleteBucket), varargs...) -} - -// DeleteObjects mocks base method. -func (m *MockAwsS3API) DeleteObjects(ctx context.Context, params *s3.DeleteObjectsInput, optFns ...func(*s3.Options)) (*s3.DeleteObjectsOutput, error) { - m.ctrl.T.Helper() - varargs := []any{ctx, params} - for _, a := range optFns { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DeleteObjects", varargs...) - ret0, _ := ret[0].(*s3.DeleteObjectsOutput) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DeleteObjects indicates an expected call of DeleteObjects. -func (mr *MockAwsS3APIMockRecorder) DeleteObjects(ctx, params any, optFns ...any) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]any{ctx, params}, optFns...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteObjects", reflect.TypeOf((*MockAwsS3API)(nil).DeleteObjects), varargs...) -} - -// DeletePublicAccessBlock mocks base method. -func (m *MockAwsS3API) DeletePublicAccessBlock(ctx context.Context, params *s3.DeletePublicAccessBlockInput, optFns ...func(*s3.Options)) (*s3.DeletePublicAccessBlockOutput, error) { - m.ctrl.T.Helper() - varargs := []any{ctx, params} - for _, a := range optFns { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DeletePublicAccessBlock", varargs...) - ret0, _ := ret[0].(*s3.DeletePublicAccessBlockOutput) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DeletePublicAccessBlock indicates an expected call of DeletePublicAccessBlock. -func (mr *MockAwsS3APIMockRecorder) DeletePublicAccessBlock(ctx, params any, optFns ...any) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]any{ctx, params}, optFns...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePublicAccessBlock", reflect.TypeOf((*MockAwsS3API)(nil).DeletePublicAccessBlock), varargs...) -} - -// HeadObject mocks base method. -func (m *MockAwsS3API) HeadObject(ctx context.Context, params *s3.HeadObjectInput, optFns ...func(*s3.Options)) (*s3.HeadObjectOutput, error) { - m.ctrl.T.Helper() - varargs := []any{ctx, params} - for _, a := range optFns { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "HeadObject", varargs...) - ret0, _ := ret[0].(*s3.HeadObjectOutput) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// HeadObject indicates an expected call of HeadObject. -func (mr *MockAwsS3APIMockRecorder) HeadObject(ctx, params any, optFns ...any) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]any{ctx, params}, optFns...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeadObject", reflect.TypeOf((*MockAwsS3API)(nil).HeadObject), varargs...) -} - -// PutBucketOwnershipControls mocks base method. -func (m *MockAwsS3API) PutBucketOwnershipControls(ctx context.Context, params *s3.PutBucketOwnershipControlsInput, optFns ...func(*s3.Options)) (*s3.PutBucketOwnershipControlsOutput, error) { - m.ctrl.T.Helper() - varargs := []any{ctx, params} - for _, a := range optFns { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "PutBucketOwnershipControls", varargs...) - ret0, _ := ret[0].(*s3.PutBucketOwnershipControlsOutput) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// PutBucketOwnershipControls indicates an expected call of PutBucketOwnershipControls. -func (mr *MockAwsS3APIMockRecorder) PutBucketOwnershipControls(ctx, params any, optFns ...any) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]any{ctx, params}, optFns...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutBucketOwnershipControls", reflect.TypeOf((*MockAwsS3API)(nil).PutBucketOwnershipControls), varargs...) -} - -// PutObject mocks base method. -func (m *MockAwsS3API) PutObject(ctx context.Context, params *s3.PutObjectInput, optFns ...func(*s3.Options)) (*s3.PutObjectOutput, error) { - m.ctrl.T.Helper() - varargs := []any{ctx, params} - for _, a := range optFns { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "PutObject", varargs...) - ret0, _ := ret[0].(*s3.PutObjectOutput) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// PutObject indicates an expected call of PutObject. -func (mr *MockAwsS3APIMockRecorder) PutObject(ctx, params any, optFns ...any) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]any{ctx, params}, optFns...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutObject", reflect.TypeOf((*MockAwsS3API)(nil).PutObject), varargs...) -}