diff --git a/pkg/actions/addon/tasks.go b/pkg/actions/addon/tasks.go index d81837335a..f577cb4493 100644 --- a/pkg/actions/addon/tasks.go +++ b/pkg/actions/addon/tasks.go @@ -119,8 +119,6 @@ type deleteAddonIAMTask struct { func (t *deleteAddonIAMTask) Describe() string { return t.info } func (t *deleteAddonIAMTask) Do(errorCh chan error) error { - defer close(errorCh) - errMsg := fmt.Sprintf("deleting addon IAM %q", *t.stack.StackName) if t.wait { if err := t.stackManager.DeleteStackBySpecSync(t.ctx, t.stack, errorCh); err != nil { @@ -128,6 +126,8 @@ func (t *deleteAddonIAMTask) Do(errorCh chan error) error { } return nil } + + defer close(errorCh) if _, err := t.stackManager.DeleteStackBySpec(t.ctx, t.stack); err != nil { return fmt.Errorf("%s: %w", errMsg, err) } diff --git a/pkg/actions/cluster/owned.go b/pkg/actions/cluster/owned.go index 6e996c8640..86e36364a2 100644 --- a/pkg/actions/cluster/owned.go +++ b/pkg/actions/cluster/owned.go @@ -10,6 +10,7 @@ import ( "github.com/kris-nova/logger" "github.com/weaveworks/eksctl/pkg/actions/addon" + "github.com/weaveworks/eksctl/pkg/actions/irsa" "github.com/weaveworks/eksctl/pkg/actions/nodegroup" api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" "github.com/weaveworks/eksctl/pkg/cfn/manager" @@ -27,6 +28,7 @@ type OwnedCluster struct { stackManager manager.StackManager newClientSet func() (kubernetes.Interface, error) newNodeGroupManager func(cfg *api.ClusterConfig, ctl *eks.ClusterProvider, clientSet kubernetes.Interface) NodeGroupDrainer + newIRSARemover func(clientSetGetter kubernetes.ClientSetGetter, stackManager irsa.StackManager) irsa.DeleteTasksBuilder } func NewOwnedCluster(ctx context.Context, cfg *api.ClusterConfig, ctl *eks.ClusterProvider, clusterStack *manager.Stack, stackManager manager.StackManager) (*OwnedCluster, error) { @@ -45,6 +47,9 @@ func NewOwnedCluster(ctx context.Context, cfg *api.ClusterConfig, ctl *eks.Clust newNodeGroupManager: func(cfg *api.ClusterConfig, ctl *eks.ClusterProvider, clientSet kubernetes.Interface) NodeGroupDrainer { return nodegroup.New(cfg, ctl, clientSet, instanceSelector) }, + newIRSARemover: func(clientSetGetter kubernetes.ClientSetGetter, stackManager irsa.StackManager) irsa.DeleteTasksBuilder { + return irsa.NewRemover(clientSetGetter, stackManager) + }, }, nil } @@ -121,7 +126,8 @@ func (c *OwnedCluster) Delete(ctx context.Context, _, podEvictionWaitPeriod time return c.ctl.NewOpenIDConnectManager(ctx, c.cfg) } newTasksToDeleteAddonIAM := addon.NewRemover(c.stackManager).DeleteAddonIAMTasks - tasks, err := c.stackManager.NewTasksToDeleteClusterWithNodeGroups(ctx, c.clusterStack, allStacks, clusterOperable, newOIDCManager, newTasksToDeleteAddonIAM, c.ctl.Status.ClusterInfo.Cluster, kubernetes.NewCachedClientSet(clientSet), wait, force, func(errs chan error, _ string) error { + newTasksToDeleteIAMServiceAccounts := c.newIRSARemover(kubernetes.NewCachedClientSet(clientSet), c.stackManager).DeleteIAMServiceAccountsTasks + tasks, err := c.stackManager.NewTasksToDeleteClusterWithNodeGroups(ctx, c.clusterStack, allStacks, clusterOperable, newOIDCManager, newTasksToDeleteAddonIAM, newTasksToDeleteIAMServiceAccounts, c.ctl.Status.ClusterInfo.Cluster, wait, force, func(errs chan error, _ string) error { logger.Info("trying to cleanup dangling network interfaces") stack, err := c.stackManager.DescribeClusterStack(ctx) if err != nil { diff --git a/pkg/actions/cluster/unowned.go b/pkg/actions/cluster/unowned.go index a998c4a92e..f4daeb22f4 100644 --- a/pkg/actions/cluster/unowned.go +++ b/pkg/actions/cluster/unowned.go @@ -12,6 +12,7 @@ import ( "github.com/pkg/errors" "github.com/weaveworks/eksctl/pkg/actions/addon" + "github.com/weaveworks/eksctl/pkg/actions/irsa" "github.com/weaveworks/eksctl/pkg/actions/nodegroup" api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" "github.com/weaveworks/eksctl/pkg/cfn/manager" @@ -28,6 +29,7 @@ type UnownedCluster struct { stackManager manager.StackManager newClientSet func() (kubernetes.Interface, error) newNodeGroupManager func(cfg *api.ClusterConfig, ctl *eks.ClusterProvider, clientSet kubernetes.Interface) NodeGroupDrainer + newIRSARemover func(clientSetGetter kubernetes.ClientSetGetter, stackManager irsa.StackManager) irsa.DeleteTasksBuilder } func NewUnownedCluster(ctx context.Context, cfg *api.ClusterConfig, ctl *eks.ClusterProvider, stackManager manager.StackManager) (*UnownedCluster, error) { @@ -45,6 +47,9 @@ func NewUnownedCluster(ctx context.Context, cfg *api.ClusterConfig, ctl *eks.Clu newNodeGroupManager: func(cfg *api.ClusterConfig, ctl *eks.ClusterProvider, clientSet kubernetes.Interface) NodeGroupDrainer { return nodegroup.New(cfg, ctl, clientSet, instanceSelector) }, + newIRSARemover: func(clientSetGetter kubernetes.ClientSetGetter, stackManager irsa.StackManager) irsa.DeleteTasksBuilder { + return irsa.NewRemover(clientSetGetter, stackManager) + }, }, nil } @@ -174,7 +179,8 @@ func (c *UnownedCluster) deleteIAMAndOIDC(ctx context.Context, wait bool, cluste newOIDCManager := func() (*iamoidc.OpenIDConnectManager, error) { return c.ctl.NewOpenIDConnectManager(ctx, c.cfg) } - serviceAccountAndOIDCTasks, err := c.stackManager.NewTasksToDeleteOIDCProviderWithIAMServiceAccounts(ctx, newOIDCManager, c.ctl.Status.ClusterInfo.Cluster, clientSetGetter, force) + newTasksToDeleteIAMServiceAccounts := c.newIRSARemover(clientSetGetter, c.stackManager).DeleteIAMServiceAccountsTasks + serviceAccountAndOIDCTasks, err := c.stackManager.NewTasksToDeleteOIDCProviderWithIAMServiceAccounts(ctx, newOIDCManager, newTasksToDeleteIAMServiceAccounts, c.ctl.Status.ClusterInfo.Cluster, force) if err != nil { return err } diff --git a/pkg/actions/irsa/create.go b/pkg/actions/irsa/create.go index 8658dcf9ee..f446db23da 100644 --- a/pkg/actions/irsa/create.go +++ b/pkg/actions/irsa/create.go @@ -1,17 +1,115 @@ package irsa import ( + "context" + "fmt" + + "github.com/kris-nova/logger" + "github.com/pkg/errors" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" + iamoidc "github.com/weaveworks/eksctl/pkg/iam/oidc" "github.com/weaveworks/eksctl/pkg/kubernetes" + "github.com/weaveworks/eksctl/pkg/utils/tasks" ) -func (a *Manager) CreateIAMServiceAccount(iamServiceAccounts []*api.ClusterIAMServiceAccount, plan bool) error { - taskTree := a.stackManager.NewTasksToCreateIAMServiceAccounts(iamServiceAccounts, a.oidcManager, kubernetes.NewCachedClientSet(a.clientSet)) +var ( + managedByKubernetesLabelKey = "app.kubernetes.io/managed-by" + managedByKubernetesLabelValue = "eksctl" + maybeCreateServiceAccountOrUpdateMetadata = kubernetes.MaybeCreateServiceAccountOrUpdateMetadata +) + +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -generate +//counterfeiter:generate -o fakes/fake_create_tasks_builder.go . CreateTasksBuilder +type CreateTasksBuilder interface { + CreateIAMServiceAccountsTasks(ctx context.Context, serviceAccounts []*api.ClusterIAMServiceAccount) *tasks.TaskTree +} + +type Creator struct { + clusterName string + region string + + clientSetGetter kubernetes.ClientSetGetter + oidcManager *iamoidc.OpenIDConnectManager + stackManager StackManager +} + +func NewCreator( + clusterName string, + region string, + clientSetGetter kubernetes.ClientSetGetter, + oidcManager *iamoidc.OpenIDConnectManager, + stackManager StackManager) *Creator { + return &Creator{ + clusterName: clusterName, + region: region, + clientSetGetter: clientSetGetter, + oidcManager: oidcManager, + stackManager: stackManager, + } +} + +func (c *Creator) CreateIAMServiceAccounts(ctx context.Context, serviceAccounts []*api.ClusterIAMServiceAccount, plan bool) error { + taskTree := c.CreateIAMServiceAccountsTasks(ctx, serviceAccounts) taskTree.PlanMode = plan err := doTasks(taskTree, actionCreate) - logPlanModeWarning(plan && len(iamServiceAccounts) > 0) + logPlanModeWarning(plan && len(serviceAccounts) > 0) return err } + +func (c *Creator) CreateIAMServiceAccountsTasks(ctx context.Context, serviceAccounts []*api.ClusterIAMServiceAccount) *tasks.TaskTree { + taskTree := &tasks.TaskTree{Parallel: true} + + for i := range serviceAccounts { + sa := serviceAccounts[i] + saTasks := &tasks.TaskTree{ + Parallel: false, + IsSubTask: true, + } + + if sa.AttachRoleARN == "" { + saTasks.Append(&createIAMRoleForServiceAccountTask{ + ctx: ctx, + info: fmt.Sprintf("create IAM role for serviceaccount %q", sa.NameString()), + clusterName: c.clusterName, + region: c.region, + stackManager: c.stackManager, + sa: sa, + oidc: c.oidcManager, + }) + } else { + logger.Debug("attachRoleARN was provided, skipping role creation") + sa.Status = &api.ClusterIAMServiceAccountStatus{ + RoleARN: &sa.AttachRoleARN, + } + } + + if sa.Labels == nil { + sa.Labels = make(map[string]string) + } + sa.Labels[managedByKubernetesLabelKey] = managedByKubernetesLabelValue + if !api.IsEnabled(sa.RoleOnly) { + saTasks.Append(&kubernetesTask{ + info: fmt.Sprintf("create serviceaccount %q", sa.NameString()), + kubernetes: c.clientSetGetter, + objectMeta: sa.ClusterIAMMeta.AsObjectMeta(), + call: func(clientSet kubernetes.Interface, objectMeta v1.ObjectMeta) error { + sa.SetAnnotations() + objectMeta.SetAnnotations(sa.AsObjectMeta().Annotations) + objectMeta.SetLabels(sa.AsObjectMeta().Labels) + if err := maybeCreateServiceAccountOrUpdateMetadata(clientSet, objectMeta); err != nil { + return errors.Wrapf(err, "failed to create service account %s/%s", objectMeta.GetNamespace(), objectMeta.GetName()) + } + return nil + }, + }) + } + + taskTree.Append(saTasks) + } + return taskTree +} diff --git a/pkg/actions/irsa/create_test.go b/pkg/actions/irsa/create_test.go new file mode 100644 index 0000000000..05d3566a3d --- /dev/null +++ b/pkg/actions/irsa/create_test.go @@ -0,0 +1,97 @@ +package irsa_test + +import ( + "context" + + "github.com/aws/aws-sdk-go-v2/aws" + . "github.com/onsi/ginkgo/v2" + + . "github.com/onsi/gomega" + + "github.com/weaveworks/eksctl/pkg/actions/irsa" + api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" +) + +var _ = Describe("Create", func() { + + Describe("CreateIAMServiceAccountsTasks", func() { + var ( + clusterName = "test-cluster" + roleName = "test-role-name" + roleARN = "test-role-arn" + region = "us-west-2" + creator *irsa.Creator + ) + + BeforeEach(func() { + creator = irsa.NewCreator(clusterName, region, nil, nil, nil) + }) + + When("attachRoleARN is provided and RoleOnly is true", func() { + It("returns a empty tasktree", func() { + serviceAccounts := []*api.ClusterIAMServiceAccount{ + { + RoleName: roleName, + AttachRoleARN: roleARN, + RoleOnly: aws.Bool(true), + }, + } + taskTree := creator.CreateIAMServiceAccountsTasks(context.Background(), serviceAccounts) + Expect(taskTree.Parallel).To(Equal(true)) + Expect(taskTree.IsSubTask).To(Equal(false)) + Expect(len(taskTree.Tasks)).To(Equal(1)) + Expect(taskTree.Tasks[0].Describe()).To(Equal("no tasks")) + }) + }) + + When("attachRoleARN is provided and RoleOnly is false", func() { + It("returns a tasktree with all expected tasks", func() { + serviceAccounts := []*api.ClusterIAMServiceAccount{ + { + RoleName: roleName, + AttachRoleARN: roleARN, + }, + } + taskTree := creator.CreateIAMServiceAccountsTasks(context.Background(), serviceAccounts) + Expect(taskTree.Parallel).To(Equal(true)) + Expect(taskTree.IsSubTask).To(Equal(false)) + Expect(len(taskTree.Tasks)).To(Equal(1)) + Expect(taskTree.Tasks[0].Describe()).To(ContainSubstring("create serviceaccount")) + }) + }) + + When("attachRoleARN is not provided and RoleOnly is true", func() { + It("returns a tasktree with all expected tasks", func() { + serviceAccounts := []*api.ClusterIAMServiceAccount{ + { + RoleName: roleName, + RoleOnly: aws.Bool(true), + }, + } + taskTree := creator.CreateIAMServiceAccountsTasks(context.Background(), serviceAccounts) + Expect(taskTree.Parallel).To(Equal(true)) + Expect(taskTree.IsSubTask).To(Equal(false)) + Expect(len(taskTree.Tasks)).To(Equal(1)) + Expect(taskTree.Tasks[0].Describe()).To(ContainSubstring("create IAM role for serviceaccount")) + }) + }) + + When("attachRoleARN is not provided and RoleOnly is false", func() { + It("returns a tasktree with all expected tasks", func() { + serviceAccounts := []*api.ClusterIAMServiceAccount{ + { + RoleName: roleName, + RoleOnly: aws.Bool(false), + }, + } + taskTree := creator.CreateIAMServiceAccountsTasks(context.Background(), serviceAccounts) + Expect(taskTree.Parallel).To(Equal(true)) + Expect(taskTree.IsSubTask).To(Equal(false)) + Expect(len(taskTree.Tasks)).To(Equal(1)) + Expect(taskTree.Tasks[0].Describe()).To(ContainSubstring("2 sequential sub-tasks")) + Expect(taskTree.Tasks[0].Describe()).To(ContainSubstring("create IAM role for serviceaccount")) + Expect(taskTree.Tasks[0].Describe()).To(ContainSubstring("create serviceaccount")) + }) + }) + }) +}) diff --git a/pkg/actions/irsa/delete.go b/pkg/actions/irsa/delete.go index 9c2a53bf9a..6cbf9ede78 100644 --- a/pkg/actions/irsa/delete.go +++ b/pkg/actions/irsa/delete.go @@ -2,12 +2,34 @@ package irsa import ( "context" + "fmt" + cfntypes "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" + api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" "github.com/weaveworks/eksctl/pkg/kubernetes" + "github.com/weaveworks/eksctl/pkg/utils/tasks" ) -func (m *Manager) Delete(ctx context.Context, serviceAccounts []string, plan, wait bool) error { - taskTree, err := m.stackManager.NewTasksToDeleteIAMServiceAccounts(ctx, serviceAccounts, kubernetes.NewCachedClientSet(m.clientSet), wait) +type DeleteTasksBuilder interface { + DeleteIAMServiceAccountsTasks(ctx context.Context, serviceAccounts []string, wait bool) (*tasks.TaskTree, error) +} + +type Remover struct { + clientSetGetter kubernetes.ClientSetGetter + stackManager StackManager +} + +func NewRemover( + clientSetGetter kubernetes.ClientSetGetter, + stackManager StackManager) *Remover { + return &Remover{ + clientSetGetter: clientSetGetter, + stackManager: stackManager, + } +} + +func (r *Remover) Delete(ctx context.Context, serviceAccounts []string, plan, wait bool) error { + taskTree, err := r.DeleteIAMServiceAccountsTasks(ctx, serviceAccounts, wait) if err != nil { return err } @@ -18,3 +40,63 @@ func (m *Manager) Delete(ctx context.Context, serviceAccounts []string, plan, wa logPlanModeWarning(plan && taskTree.Len() > 0) return err } + +func (r *Remover) DeleteIAMServiceAccountsTasks(ctx context.Context, serviceAccounts []string, wait bool) (*tasks.TaskTree, error) { + serviceAccountStacks, err := r.stackManager.DescribeIAMServiceAccountStacks(ctx) + if err != nil { + return nil, fmt.Errorf("failed to describe IAM Service Account CFN Stacks: %v", err) + } + + stacksMap := stacksToServiceAccountMap(serviceAccountStacks) + taskTree := &tasks.TaskTree{Parallel: true} + + for _, serviceAccount := range serviceAccounts { + saTasks := &tasks.TaskTree{ + Parallel: false, + IsSubTask: true, + } + + if s, ok := stacksMap[serviceAccount]; ok { + info := fmt.Sprintf("delete IAM role for serviceaccount %q", serviceAccount) + saTasks.Append(&deleteIAMRoleForServiceAccountTask{ + ctx: ctx, + info: info, + stack: s, + stackManager: r.stackManager, + wait: wait, + }) + } + + meta, err := api.ClusterIAMServiceAccountNameStringToClusterIAMMeta(serviceAccount) + if err != nil { + return nil, err + } + saTasks.Append(&kubernetesTask{ + info: fmt.Sprintf("delete serviceaccount %q", serviceAccount), + kubernetes: r.clientSetGetter, + objectMeta: meta.AsObjectMeta(), + call: kubernetes.MaybeDeleteServiceAccount, + }) + taskTree.Append(saTasks) + } + + return taskTree, nil +} + +func stacksToServiceAccountMap(stacks []*cfntypes.Stack) map[string]*cfntypes.Stack { + stackMap := make(map[string]*cfntypes.Stack) + for _, stack := range stacks { + stackMap[getIAMServiceAccountName(stack)] = stack + } + + return stackMap +} + +func getIAMServiceAccountName(s *cfntypes.Stack) string { + for _, tag := range s.Tags { + if *tag.Key == api.IAMServiceAccountNameTag { + return *tag.Value + } + } + return "" +} diff --git a/pkg/actions/irsa/delete_test.go b/pkg/actions/irsa/delete_test.go new file mode 100644 index 0000000000..dd677702d7 --- /dev/null +++ b/pkg/actions/irsa/delete_test.go @@ -0,0 +1,102 @@ +package irsa_test + +import ( + "context" + "fmt" + + "github.com/aws/aws-sdk-go-v2/aws" + cfntypes "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "github.com/weaveworks/eksctl/pkg/actions/irsa" + "github.com/weaveworks/eksctl/pkg/actions/irsa/fakes" + api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" + "github.com/weaveworks/eksctl/pkg/kubernetes" +) + +var _ = Describe("Delete", func() { + + Describe("DeleteIAMServiceAccountsTasks", func() { + var ( + remover *irsa.Remover + fakeStackManager *fakes.FakeStackManager + stackName1 = "eksctl-test-cluster-addon-iamserviceaccount-default-sa" + stackName2 = "eksctl-test-cluster-addon-iamserviceaccount-kube-system-sa" + ) + + BeforeEach(func() { + fakeStackManager = &fakes.FakeStackManager{} + remover = irsa.NewRemover(&kubernetes.CachedClientSet{}, fakeStackManager) + }) + + When("DescribeIAMServiceAccountStacks fails", func() { + It("returns an error", func() { + fakeStackManager.DescribeIAMServiceAccountStacksReturns(nil, fmt.Errorf("foo")) + _, err := remover.DeleteIAMServiceAccountsTasks(context.Background(), []string{}, false) + Expect(err).To(MatchError(ContainSubstring("failed to describe IAM Service Account CFN Stacks"))) + }) + }) + + When("there is no IAM Service Account stack", func() { + It("returns an empty tasktree", func() { + fakeStackManager.DescribeIAMServiceAccountStacksReturns([]*cfntypes.Stack{}, nil) + taskTree, err := remover.DeleteIAMServiceAccountsTasks(context.Background(), []string{}, false) + Expect(err).NotTo(HaveOccurred()) + Expect(len(taskTree.Tasks)).To(Equal(0)) + }) + }) + + When("there are multiple IAM Service Account stacks", func() { + When("there is a stack with invalid name string", func() { + It("returns an error", func() { + fakeStackManager.DescribeIAMServiceAccountStacksReturns([]*cfntypes.Stack{ + { + StackName: &stackName1, + }, + }, nil) + _, err := remover.DeleteIAMServiceAccountsTasks(context.Background(), []string{"invalid-name"}, false) + Expect(err).To(MatchError(ContainSubstring("unexpected serviceaccount name format"))) + }) + }) + + When("all stacks have valid names", func() { + It("returns a tasktree with all expected tasks", func() { + fakeStackManager.DescribeIAMServiceAccountStacksReturns([]*cfntypes.Stack{ + { + StackName: &stackName1, + Tags: []cfntypes.Tag{ + { + Key: aws.String(api.IAMServiceAccountNameTag), + Value: aws.String("default/sa"), + }, + }, + }, + { + StackName: &stackName2, + Tags: []cfntypes.Tag{ + { + Key: aws.String(api.IAMServiceAccountNameTag), + Value: aws.String("kube-system/sa"), + }, + }, + }, + }, nil) + taskTree, err := remover.DeleteIAMServiceAccountsTasks(context.Background(), []string{ + "default/sa", + "kube-system/sa", + }, false) + Expect(err).ToNot(HaveOccurred()) + Expect(taskTree.Parallel).To(Equal(true)) + Expect(len(taskTree.Tasks)).To(Equal(2)) + Expect(taskTree.Tasks[0].Describe()).To(ContainSubstring("2 sequential sub-tasks")) + Expect(taskTree.Tasks[0].Describe()).To(ContainSubstring("delete IAM role for serviceaccount")) + Expect(taskTree.Tasks[0].Describe()).To(ContainSubstring("delete serviceaccount")) + Expect(taskTree.Tasks[1].Describe()).To(ContainSubstring("2 sequential sub-tasks")) + Expect(taskTree.Tasks[1].Describe()).To(ContainSubstring("delete IAM role for serviceaccount")) + Expect(taskTree.Tasks[1].Describe()).To(ContainSubstring("delete serviceaccount")) + }) + }) + }) + }) +}) diff --git a/pkg/actions/irsa/fakes/fake_create_tasks_builder.go b/pkg/actions/irsa/fakes/fake_create_tasks_builder.go new file mode 100644 index 0000000000..402373aef9 --- /dev/null +++ b/pkg/actions/irsa/fakes/fake_create_tasks_builder.go @@ -0,0 +1,121 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package fakes + +import ( + "context" + "sync" + + "github.com/weaveworks/eksctl/pkg/actions/irsa" + "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" + "github.com/weaveworks/eksctl/pkg/utils/tasks" +) + +type FakeCreateTasksBuilder struct { + CreateIAMServiceAccountsTasksStub func(context.Context, []*v1alpha5.ClusterIAMServiceAccount) *tasks.TaskTree + createIAMServiceAccountsTasksMutex sync.RWMutex + createIAMServiceAccountsTasksArgsForCall []struct { + arg1 context.Context + arg2 []*v1alpha5.ClusterIAMServiceAccount + } + createIAMServiceAccountsTasksReturns struct { + result1 *tasks.TaskTree + } + createIAMServiceAccountsTasksReturnsOnCall map[int]struct { + result1 *tasks.TaskTree + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeCreateTasksBuilder) CreateIAMServiceAccountsTasks(arg1 context.Context, arg2 []*v1alpha5.ClusterIAMServiceAccount) *tasks.TaskTree { + var arg2Copy []*v1alpha5.ClusterIAMServiceAccount + if arg2 != nil { + arg2Copy = make([]*v1alpha5.ClusterIAMServiceAccount, len(arg2)) + copy(arg2Copy, arg2) + } + fake.createIAMServiceAccountsTasksMutex.Lock() + ret, specificReturn := fake.createIAMServiceAccountsTasksReturnsOnCall[len(fake.createIAMServiceAccountsTasksArgsForCall)] + fake.createIAMServiceAccountsTasksArgsForCall = append(fake.createIAMServiceAccountsTasksArgsForCall, struct { + arg1 context.Context + arg2 []*v1alpha5.ClusterIAMServiceAccount + }{arg1, arg2Copy}) + stub := fake.CreateIAMServiceAccountsTasksStub + fakeReturns := fake.createIAMServiceAccountsTasksReturns + fake.recordInvocation("CreateIAMServiceAccountsTasks", []interface{}{arg1, arg2Copy}) + fake.createIAMServiceAccountsTasksMutex.Unlock() + if stub != nil { + return stub(arg1, arg2) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeCreateTasksBuilder) CreateIAMServiceAccountsTasksCallCount() int { + fake.createIAMServiceAccountsTasksMutex.RLock() + defer fake.createIAMServiceAccountsTasksMutex.RUnlock() + return len(fake.createIAMServiceAccountsTasksArgsForCall) +} + +func (fake *FakeCreateTasksBuilder) CreateIAMServiceAccountsTasksCalls(stub func(context.Context, []*v1alpha5.ClusterIAMServiceAccount) *tasks.TaskTree) { + fake.createIAMServiceAccountsTasksMutex.Lock() + defer fake.createIAMServiceAccountsTasksMutex.Unlock() + fake.CreateIAMServiceAccountsTasksStub = stub +} + +func (fake *FakeCreateTasksBuilder) CreateIAMServiceAccountsTasksArgsForCall(i int) (context.Context, []*v1alpha5.ClusterIAMServiceAccount) { + fake.createIAMServiceAccountsTasksMutex.RLock() + defer fake.createIAMServiceAccountsTasksMutex.RUnlock() + argsForCall := fake.createIAMServiceAccountsTasksArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeCreateTasksBuilder) CreateIAMServiceAccountsTasksReturns(result1 *tasks.TaskTree) { + fake.createIAMServiceAccountsTasksMutex.Lock() + defer fake.createIAMServiceAccountsTasksMutex.Unlock() + fake.CreateIAMServiceAccountsTasksStub = nil + fake.createIAMServiceAccountsTasksReturns = struct { + result1 *tasks.TaskTree + }{result1} +} + +func (fake *FakeCreateTasksBuilder) CreateIAMServiceAccountsTasksReturnsOnCall(i int, result1 *tasks.TaskTree) { + fake.createIAMServiceAccountsTasksMutex.Lock() + defer fake.createIAMServiceAccountsTasksMutex.Unlock() + fake.CreateIAMServiceAccountsTasksStub = nil + if fake.createIAMServiceAccountsTasksReturnsOnCall == nil { + fake.createIAMServiceAccountsTasksReturnsOnCall = make(map[int]struct { + result1 *tasks.TaskTree + }) + } + fake.createIAMServiceAccountsTasksReturnsOnCall[i] = struct { + result1 *tasks.TaskTree + }{result1} +} + +func (fake *FakeCreateTasksBuilder) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.createIAMServiceAccountsTasksMutex.RLock() + defer fake.createIAMServiceAccountsTasksMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeCreateTasksBuilder) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} + +var _ irsa.CreateTasksBuilder = new(FakeCreateTasksBuilder) diff --git a/pkg/actions/irsa/fakes/fake_stack_manager.go b/pkg/actions/irsa/fakes/fake_stack_manager.go new file mode 100644 index 0000000000..90ee61067b --- /dev/null +++ b/pkg/actions/irsa/fakes/fake_stack_manager.go @@ -0,0 +1,600 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package fakes + +import ( + "context" + "sync" + + "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" + "github.com/weaveworks/eksctl/pkg/actions/irsa" + "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" + "github.com/weaveworks/eksctl/pkg/cfn/builder" + "github.com/weaveworks/eksctl/pkg/cfn/manager" +) + +type FakeStackManager struct { + CreateStackStub func(context.Context, string, builder.ResourceSetReader, map[string]string, map[string]string, chan error) error + createStackMutex sync.RWMutex + createStackArgsForCall []struct { + arg1 context.Context + arg2 string + arg3 builder.ResourceSetReader + arg4 map[string]string + arg5 map[string]string + arg6 chan error + } + createStackReturns struct { + result1 error + } + createStackReturnsOnCall map[int]struct { + result1 error + } + DeleteStackBySpecStub func(context.Context, *types.Stack) (*types.Stack, error) + deleteStackBySpecMutex sync.RWMutex + deleteStackBySpecArgsForCall []struct { + arg1 context.Context + arg2 *types.Stack + } + deleteStackBySpecReturns struct { + result1 *types.Stack + result2 error + } + deleteStackBySpecReturnsOnCall map[int]struct { + result1 *types.Stack + result2 error + } + DeleteStackBySpecSyncStub func(context.Context, *types.Stack, chan error) error + deleteStackBySpecSyncMutex sync.RWMutex + deleteStackBySpecSyncArgsForCall []struct { + arg1 context.Context + arg2 *types.Stack + arg3 chan error + } + deleteStackBySpecSyncReturns struct { + result1 error + } + deleteStackBySpecSyncReturnsOnCall map[int]struct { + result1 error + } + DescribeIAMServiceAccountStacksStub func(context.Context) ([]*types.Stack, error) + describeIAMServiceAccountStacksMutex sync.RWMutex + describeIAMServiceAccountStacksArgsForCall []struct { + arg1 context.Context + } + describeIAMServiceAccountStacksReturns struct { + result1 []*types.Stack + result2 error + } + describeIAMServiceAccountStacksReturnsOnCall map[int]struct { + result1 []*types.Stack + result2 error + } + GetIAMServiceAccountsStub func(context.Context) ([]*v1alpha5.ClusterIAMServiceAccount, error) + getIAMServiceAccountsMutex sync.RWMutex + getIAMServiceAccountsArgsForCall []struct { + arg1 context.Context + } + getIAMServiceAccountsReturns struct { + result1 []*v1alpha5.ClusterIAMServiceAccount + result2 error + } + getIAMServiceAccountsReturnsOnCall map[int]struct { + result1 []*v1alpha5.ClusterIAMServiceAccount + result2 error + } + GetStackTemplateStub func(context.Context, string) (string, error) + getStackTemplateMutex sync.RWMutex + getStackTemplateArgsForCall []struct { + arg1 context.Context + arg2 string + } + getStackTemplateReturns struct { + result1 string + result2 error + } + getStackTemplateReturnsOnCall map[int]struct { + result1 string + result2 error + } + UpdateStackStub func(context.Context, manager.UpdateStackOptions) error + updateStackMutex sync.RWMutex + updateStackArgsForCall []struct { + arg1 context.Context + arg2 manager.UpdateStackOptions + } + updateStackReturns struct { + result1 error + } + updateStackReturnsOnCall map[int]struct { + result1 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeStackManager) CreateStack(arg1 context.Context, arg2 string, arg3 builder.ResourceSetReader, arg4 map[string]string, arg5 map[string]string, arg6 chan error) error { + fake.createStackMutex.Lock() + ret, specificReturn := fake.createStackReturnsOnCall[len(fake.createStackArgsForCall)] + fake.createStackArgsForCall = append(fake.createStackArgsForCall, struct { + arg1 context.Context + arg2 string + arg3 builder.ResourceSetReader + arg4 map[string]string + arg5 map[string]string + arg6 chan error + }{arg1, arg2, arg3, arg4, arg5, arg6}) + stub := fake.CreateStackStub + fakeReturns := fake.createStackReturns + fake.recordInvocation("CreateStack", []interface{}{arg1, arg2, arg3, arg4, arg5, arg6}) + fake.createStackMutex.Unlock() + if stub != nil { + return stub(arg1, arg2, arg3, arg4, arg5, arg6) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeStackManager) CreateStackCallCount() int { + fake.createStackMutex.RLock() + defer fake.createStackMutex.RUnlock() + return len(fake.createStackArgsForCall) +} + +func (fake *FakeStackManager) CreateStackCalls(stub func(context.Context, string, builder.ResourceSetReader, map[string]string, map[string]string, chan error) error) { + fake.createStackMutex.Lock() + defer fake.createStackMutex.Unlock() + fake.CreateStackStub = stub +} + +func (fake *FakeStackManager) CreateStackArgsForCall(i int) (context.Context, string, builder.ResourceSetReader, map[string]string, map[string]string, chan error) { + fake.createStackMutex.RLock() + defer fake.createStackMutex.RUnlock() + argsForCall := fake.createStackArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4, argsForCall.arg5, argsForCall.arg6 +} + +func (fake *FakeStackManager) CreateStackReturns(result1 error) { + fake.createStackMutex.Lock() + defer fake.createStackMutex.Unlock() + fake.CreateStackStub = nil + fake.createStackReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeStackManager) CreateStackReturnsOnCall(i int, result1 error) { + fake.createStackMutex.Lock() + defer fake.createStackMutex.Unlock() + fake.CreateStackStub = nil + if fake.createStackReturnsOnCall == nil { + fake.createStackReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.createStackReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeStackManager) DeleteStackBySpec(arg1 context.Context, arg2 *types.Stack) (*types.Stack, error) { + fake.deleteStackBySpecMutex.Lock() + ret, specificReturn := fake.deleteStackBySpecReturnsOnCall[len(fake.deleteStackBySpecArgsForCall)] + fake.deleteStackBySpecArgsForCall = append(fake.deleteStackBySpecArgsForCall, struct { + arg1 context.Context + arg2 *types.Stack + }{arg1, arg2}) + stub := fake.DeleteStackBySpecStub + fakeReturns := fake.deleteStackBySpecReturns + fake.recordInvocation("DeleteStackBySpec", []interface{}{arg1, arg2}) + fake.deleteStackBySpecMutex.Unlock() + if stub != nil { + return stub(arg1, arg2) + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeStackManager) DeleteStackBySpecCallCount() int { + fake.deleteStackBySpecMutex.RLock() + defer fake.deleteStackBySpecMutex.RUnlock() + return len(fake.deleteStackBySpecArgsForCall) +} + +func (fake *FakeStackManager) DeleteStackBySpecCalls(stub func(context.Context, *types.Stack) (*types.Stack, error)) { + fake.deleteStackBySpecMutex.Lock() + defer fake.deleteStackBySpecMutex.Unlock() + fake.DeleteStackBySpecStub = stub +} + +func (fake *FakeStackManager) DeleteStackBySpecArgsForCall(i int) (context.Context, *types.Stack) { + fake.deleteStackBySpecMutex.RLock() + defer fake.deleteStackBySpecMutex.RUnlock() + argsForCall := fake.deleteStackBySpecArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeStackManager) DeleteStackBySpecReturns(result1 *types.Stack, result2 error) { + fake.deleteStackBySpecMutex.Lock() + defer fake.deleteStackBySpecMutex.Unlock() + fake.DeleteStackBySpecStub = nil + fake.deleteStackBySpecReturns = struct { + result1 *types.Stack + result2 error + }{result1, result2} +} + +func (fake *FakeStackManager) DeleteStackBySpecReturnsOnCall(i int, result1 *types.Stack, result2 error) { + fake.deleteStackBySpecMutex.Lock() + defer fake.deleteStackBySpecMutex.Unlock() + fake.DeleteStackBySpecStub = nil + if fake.deleteStackBySpecReturnsOnCall == nil { + fake.deleteStackBySpecReturnsOnCall = make(map[int]struct { + result1 *types.Stack + result2 error + }) + } + fake.deleteStackBySpecReturnsOnCall[i] = struct { + result1 *types.Stack + result2 error + }{result1, result2} +} + +func (fake *FakeStackManager) DeleteStackBySpecSync(arg1 context.Context, arg2 *types.Stack, arg3 chan error) error { + fake.deleteStackBySpecSyncMutex.Lock() + ret, specificReturn := fake.deleteStackBySpecSyncReturnsOnCall[len(fake.deleteStackBySpecSyncArgsForCall)] + fake.deleteStackBySpecSyncArgsForCall = append(fake.deleteStackBySpecSyncArgsForCall, struct { + arg1 context.Context + arg2 *types.Stack + arg3 chan error + }{arg1, arg2, arg3}) + stub := fake.DeleteStackBySpecSyncStub + fakeReturns := fake.deleteStackBySpecSyncReturns + fake.recordInvocation("DeleteStackBySpecSync", []interface{}{arg1, arg2, arg3}) + fake.deleteStackBySpecSyncMutex.Unlock() + if stub != nil { + return stub(arg1, arg2, arg3) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeStackManager) DeleteStackBySpecSyncCallCount() int { + fake.deleteStackBySpecSyncMutex.RLock() + defer fake.deleteStackBySpecSyncMutex.RUnlock() + return len(fake.deleteStackBySpecSyncArgsForCall) +} + +func (fake *FakeStackManager) DeleteStackBySpecSyncCalls(stub func(context.Context, *types.Stack, chan error) error) { + fake.deleteStackBySpecSyncMutex.Lock() + defer fake.deleteStackBySpecSyncMutex.Unlock() + fake.DeleteStackBySpecSyncStub = stub +} + +func (fake *FakeStackManager) DeleteStackBySpecSyncArgsForCall(i int) (context.Context, *types.Stack, chan error) { + fake.deleteStackBySpecSyncMutex.RLock() + defer fake.deleteStackBySpecSyncMutex.RUnlock() + argsForCall := fake.deleteStackBySpecSyncArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 +} + +func (fake *FakeStackManager) DeleteStackBySpecSyncReturns(result1 error) { + fake.deleteStackBySpecSyncMutex.Lock() + defer fake.deleteStackBySpecSyncMutex.Unlock() + fake.DeleteStackBySpecSyncStub = nil + fake.deleteStackBySpecSyncReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeStackManager) DeleteStackBySpecSyncReturnsOnCall(i int, result1 error) { + fake.deleteStackBySpecSyncMutex.Lock() + defer fake.deleteStackBySpecSyncMutex.Unlock() + fake.DeleteStackBySpecSyncStub = nil + if fake.deleteStackBySpecSyncReturnsOnCall == nil { + fake.deleteStackBySpecSyncReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.deleteStackBySpecSyncReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeStackManager) DescribeIAMServiceAccountStacks(arg1 context.Context) ([]*types.Stack, error) { + fake.describeIAMServiceAccountStacksMutex.Lock() + ret, specificReturn := fake.describeIAMServiceAccountStacksReturnsOnCall[len(fake.describeIAMServiceAccountStacksArgsForCall)] + fake.describeIAMServiceAccountStacksArgsForCall = append(fake.describeIAMServiceAccountStacksArgsForCall, struct { + arg1 context.Context + }{arg1}) + stub := fake.DescribeIAMServiceAccountStacksStub + fakeReturns := fake.describeIAMServiceAccountStacksReturns + fake.recordInvocation("DescribeIAMServiceAccountStacks", []interface{}{arg1}) + fake.describeIAMServiceAccountStacksMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeStackManager) DescribeIAMServiceAccountStacksCallCount() int { + fake.describeIAMServiceAccountStacksMutex.RLock() + defer fake.describeIAMServiceAccountStacksMutex.RUnlock() + return len(fake.describeIAMServiceAccountStacksArgsForCall) +} + +func (fake *FakeStackManager) DescribeIAMServiceAccountStacksCalls(stub func(context.Context) ([]*types.Stack, error)) { + fake.describeIAMServiceAccountStacksMutex.Lock() + defer fake.describeIAMServiceAccountStacksMutex.Unlock() + fake.DescribeIAMServiceAccountStacksStub = stub +} + +func (fake *FakeStackManager) DescribeIAMServiceAccountStacksArgsForCall(i int) context.Context { + fake.describeIAMServiceAccountStacksMutex.RLock() + defer fake.describeIAMServiceAccountStacksMutex.RUnlock() + argsForCall := fake.describeIAMServiceAccountStacksArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeStackManager) DescribeIAMServiceAccountStacksReturns(result1 []*types.Stack, result2 error) { + fake.describeIAMServiceAccountStacksMutex.Lock() + defer fake.describeIAMServiceAccountStacksMutex.Unlock() + fake.DescribeIAMServiceAccountStacksStub = nil + fake.describeIAMServiceAccountStacksReturns = struct { + result1 []*types.Stack + result2 error + }{result1, result2} +} + +func (fake *FakeStackManager) DescribeIAMServiceAccountStacksReturnsOnCall(i int, result1 []*types.Stack, result2 error) { + fake.describeIAMServiceAccountStacksMutex.Lock() + defer fake.describeIAMServiceAccountStacksMutex.Unlock() + fake.DescribeIAMServiceAccountStacksStub = nil + if fake.describeIAMServiceAccountStacksReturnsOnCall == nil { + fake.describeIAMServiceAccountStacksReturnsOnCall = make(map[int]struct { + result1 []*types.Stack + result2 error + }) + } + fake.describeIAMServiceAccountStacksReturnsOnCall[i] = struct { + result1 []*types.Stack + result2 error + }{result1, result2} +} + +func (fake *FakeStackManager) GetIAMServiceAccounts(arg1 context.Context) ([]*v1alpha5.ClusterIAMServiceAccount, error) { + fake.getIAMServiceAccountsMutex.Lock() + ret, specificReturn := fake.getIAMServiceAccountsReturnsOnCall[len(fake.getIAMServiceAccountsArgsForCall)] + fake.getIAMServiceAccountsArgsForCall = append(fake.getIAMServiceAccountsArgsForCall, struct { + arg1 context.Context + }{arg1}) + stub := fake.GetIAMServiceAccountsStub + fakeReturns := fake.getIAMServiceAccountsReturns + fake.recordInvocation("GetIAMServiceAccounts", []interface{}{arg1}) + fake.getIAMServiceAccountsMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeStackManager) GetIAMServiceAccountsCallCount() int { + fake.getIAMServiceAccountsMutex.RLock() + defer fake.getIAMServiceAccountsMutex.RUnlock() + return len(fake.getIAMServiceAccountsArgsForCall) +} + +func (fake *FakeStackManager) GetIAMServiceAccountsCalls(stub func(context.Context) ([]*v1alpha5.ClusterIAMServiceAccount, error)) { + fake.getIAMServiceAccountsMutex.Lock() + defer fake.getIAMServiceAccountsMutex.Unlock() + fake.GetIAMServiceAccountsStub = stub +} + +func (fake *FakeStackManager) GetIAMServiceAccountsArgsForCall(i int) context.Context { + fake.getIAMServiceAccountsMutex.RLock() + defer fake.getIAMServiceAccountsMutex.RUnlock() + argsForCall := fake.getIAMServiceAccountsArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeStackManager) GetIAMServiceAccountsReturns(result1 []*v1alpha5.ClusterIAMServiceAccount, result2 error) { + fake.getIAMServiceAccountsMutex.Lock() + defer fake.getIAMServiceAccountsMutex.Unlock() + fake.GetIAMServiceAccountsStub = nil + fake.getIAMServiceAccountsReturns = struct { + result1 []*v1alpha5.ClusterIAMServiceAccount + result2 error + }{result1, result2} +} + +func (fake *FakeStackManager) GetIAMServiceAccountsReturnsOnCall(i int, result1 []*v1alpha5.ClusterIAMServiceAccount, result2 error) { + fake.getIAMServiceAccountsMutex.Lock() + defer fake.getIAMServiceAccountsMutex.Unlock() + fake.GetIAMServiceAccountsStub = nil + if fake.getIAMServiceAccountsReturnsOnCall == nil { + fake.getIAMServiceAccountsReturnsOnCall = make(map[int]struct { + result1 []*v1alpha5.ClusterIAMServiceAccount + result2 error + }) + } + fake.getIAMServiceAccountsReturnsOnCall[i] = struct { + result1 []*v1alpha5.ClusterIAMServiceAccount + result2 error + }{result1, result2} +} + +func (fake *FakeStackManager) GetStackTemplate(arg1 context.Context, arg2 string) (string, error) { + fake.getStackTemplateMutex.Lock() + ret, specificReturn := fake.getStackTemplateReturnsOnCall[len(fake.getStackTemplateArgsForCall)] + fake.getStackTemplateArgsForCall = append(fake.getStackTemplateArgsForCall, struct { + arg1 context.Context + arg2 string + }{arg1, arg2}) + stub := fake.GetStackTemplateStub + fakeReturns := fake.getStackTemplateReturns + fake.recordInvocation("GetStackTemplate", []interface{}{arg1, arg2}) + fake.getStackTemplateMutex.Unlock() + if stub != nil { + return stub(arg1, arg2) + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeStackManager) GetStackTemplateCallCount() int { + fake.getStackTemplateMutex.RLock() + defer fake.getStackTemplateMutex.RUnlock() + return len(fake.getStackTemplateArgsForCall) +} + +func (fake *FakeStackManager) GetStackTemplateCalls(stub func(context.Context, string) (string, error)) { + fake.getStackTemplateMutex.Lock() + defer fake.getStackTemplateMutex.Unlock() + fake.GetStackTemplateStub = stub +} + +func (fake *FakeStackManager) GetStackTemplateArgsForCall(i int) (context.Context, string) { + fake.getStackTemplateMutex.RLock() + defer fake.getStackTemplateMutex.RUnlock() + argsForCall := fake.getStackTemplateArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeStackManager) GetStackTemplateReturns(result1 string, result2 error) { + fake.getStackTemplateMutex.Lock() + defer fake.getStackTemplateMutex.Unlock() + fake.GetStackTemplateStub = nil + fake.getStackTemplateReturns = struct { + result1 string + result2 error + }{result1, result2} +} + +func (fake *FakeStackManager) GetStackTemplateReturnsOnCall(i int, result1 string, result2 error) { + fake.getStackTemplateMutex.Lock() + defer fake.getStackTemplateMutex.Unlock() + fake.GetStackTemplateStub = nil + if fake.getStackTemplateReturnsOnCall == nil { + fake.getStackTemplateReturnsOnCall = make(map[int]struct { + result1 string + result2 error + }) + } + fake.getStackTemplateReturnsOnCall[i] = struct { + result1 string + result2 error + }{result1, result2} +} + +func (fake *FakeStackManager) UpdateStack(arg1 context.Context, arg2 manager.UpdateStackOptions) error { + fake.updateStackMutex.Lock() + ret, specificReturn := fake.updateStackReturnsOnCall[len(fake.updateStackArgsForCall)] + fake.updateStackArgsForCall = append(fake.updateStackArgsForCall, struct { + arg1 context.Context + arg2 manager.UpdateStackOptions + }{arg1, arg2}) + stub := fake.UpdateStackStub + fakeReturns := fake.updateStackReturns + fake.recordInvocation("UpdateStack", []interface{}{arg1, arg2}) + fake.updateStackMutex.Unlock() + if stub != nil { + return stub(arg1, arg2) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeStackManager) UpdateStackCallCount() int { + fake.updateStackMutex.RLock() + defer fake.updateStackMutex.RUnlock() + return len(fake.updateStackArgsForCall) +} + +func (fake *FakeStackManager) UpdateStackCalls(stub func(context.Context, manager.UpdateStackOptions) error) { + fake.updateStackMutex.Lock() + defer fake.updateStackMutex.Unlock() + fake.UpdateStackStub = stub +} + +func (fake *FakeStackManager) UpdateStackArgsForCall(i int) (context.Context, manager.UpdateStackOptions) { + fake.updateStackMutex.RLock() + defer fake.updateStackMutex.RUnlock() + argsForCall := fake.updateStackArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeStackManager) UpdateStackReturns(result1 error) { + fake.updateStackMutex.Lock() + defer fake.updateStackMutex.Unlock() + fake.UpdateStackStub = nil + fake.updateStackReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeStackManager) UpdateStackReturnsOnCall(i int, result1 error) { + fake.updateStackMutex.Lock() + defer fake.updateStackMutex.Unlock() + fake.UpdateStackStub = nil + if fake.updateStackReturnsOnCall == nil { + fake.updateStackReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.updateStackReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeStackManager) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.createStackMutex.RLock() + defer fake.createStackMutex.RUnlock() + fake.deleteStackBySpecMutex.RLock() + defer fake.deleteStackBySpecMutex.RUnlock() + fake.deleteStackBySpecSyncMutex.RLock() + defer fake.deleteStackBySpecSyncMutex.RUnlock() + fake.describeIAMServiceAccountStacksMutex.RLock() + defer fake.describeIAMServiceAccountStacksMutex.RUnlock() + fake.getIAMServiceAccountsMutex.RLock() + defer fake.getIAMServiceAccountsMutex.RUnlock() + fake.getStackTemplateMutex.RLock() + defer fake.getStackTemplateMutex.RUnlock() + fake.updateStackMutex.RLock() + defer fake.updateStackMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeStackManager) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} + +var _ irsa.StackManager = new(FakeStackManager) diff --git a/pkg/actions/irsa/get_test.go b/pkg/actions/irsa/get_test.go index 816bf8549b..525d716a68 100644 --- a/pkg/actions/irsa/get_test.go +++ b/pkg/actions/irsa/get_test.go @@ -7,8 +7,8 @@ import ( . "github.com/onsi/gomega" "github.com/weaveworks/eksctl/pkg/actions/irsa" + "github.com/weaveworks/eksctl/pkg/actions/irsa/fakes" api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" - "github.com/weaveworks/eksctl/pkg/cfn/manager/fakes" ) var _ = Describe("Get", func() { diff --git a/pkg/actions/irsa/irsa.go b/pkg/actions/irsa/irsa.go index b511496147..fb0e0213e6 100644 --- a/pkg/actions/irsa/irsa.go +++ b/pkg/actions/irsa/irsa.go @@ -1,19 +1,38 @@ package irsa import ( + "context" "fmt" + cfntypes "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/kris-nova/logger" + kubeclient "k8s.io/client-go/kubernetes" + + api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" + "github.com/weaveworks/eksctl/pkg/cfn/builder" "github.com/weaveworks/eksctl/pkg/cfn/manager" iamoidc "github.com/weaveworks/eksctl/pkg/iam/oidc" "github.com/weaveworks/eksctl/pkg/utils/tasks" - kubeclient "k8s.io/client-go/kubernetes" ) +// StackManager manages CloudFormation stacks for IAM Service Accounts. +// +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -generate +//counterfeiter:generate -o fakes/fake_stack_manager.go . StackManager +type StackManager interface { + CreateStack(ctx context.Context, name string, stack builder.ResourceSetReader, tags, parameters map[string]string, errs chan error) error + DeleteStackBySpec(ctx context.Context, s *cfntypes.Stack) (*cfntypes.Stack, error) + DeleteStackBySpecSync(ctx context.Context, s *cfntypes.Stack, errs chan error) error + DescribeIAMServiceAccountStacks(ctx context.Context) ([]*cfntypes.Stack, error) + GetIAMServiceAccounts(ctx context.Context) ([]*api.ClusterIAMServiceAccount, error) + GetStackTemplate(ctx context.Context, stackName string) (string, error) + UpdateStack(ctx context.Context, options manager.UpdateStackOptions) error +} + type Manager struct { clusterName string oidcManager *iamoidc.OpenIDConnectManager - stackManager manager.StackManager + stackManager StackManager clientSet kubeclient.Interface } @@ -25,7 +44,7 @@ const ( actionUpdate action = "update" ) -func New(clusterName string, stackManager manager.StackManager, oidcManager *iamoidc.OpenIDConnectManager, clientSet kubeclient.Interface) *Manager { +func New(clusterName string, stackManager StackManager, oidcManager *iamoidc.OpenIDConnectManager, clientSet kubeclient.Interface) *Manager { return &Manager{ clusterName: clusterName, oidcManager: oidcManager, diff --git a/pkg/actions/irsa/tasks.go b/pkg/actions/irsa/tasks.go index b62d612d45..3013b660c8 100644 --- a/pkg/actions/irsa/tasks.go +++ b/pkg/actions/irsa/tasks.go @@ -4,16 +4,20 @@ import ( "context" "fmt" + cfntypes "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/google/uuid" + "github.com/kris-nova/logger" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" "github.com/weaveworks/eksctl/pkg/cfn/builder" "github.com/weaveworks/eksctl/pkg/cfn/manager" iamoidc "github.com/weaveworks/eksctl/pkg/iam/oidc" + "github.com/weaveworks/eksctl/pkg/kubernetes" "github.com/weaveworks/eksctl/pkg/utils/tasks" ) -func NewUpdateIAMServiceAccountTask(clusterName string, sa *api.ClusterIAMServiceAccount, stackManager manager.StackManager, oidcManager *iamoidc.OpenIDConnectManager) (*tasks.TaskTree, error) { +func NewUpdateIAMServiceAccountTask(clusterName string, sa *api.ClusterIAMServiceAccount, stackManager StackManager, oidcManager *iamoidc.OpenIDConnectManager) (*tasks.TaskTree, error) { rs := builder.NewIAMRoleResourceSetForServiceAccount(sa, oidcManager) err := rs.AddAllResources() if err != nil { @@ -41,9 +45,40 @@ func NewUpdateIAMServiceAccountTask(clusterName string, sa *api.ClusterIAMServic return taskTree, nil } +type createIAMRoleForServiceAccountTask struct { + ctx context.Context + info string + clusterName string + region string + stackManager StackManager + sa *api.ClusterIAMServiceAccount + oidc *iamoidc.OpenIDConnectManager +} + +func (t *createIAMRoleForServiceAccountTask) Describe() string { return t.info } +func (t *createIAMRoleForServiceAccountTask) Do(errs chan error) error { + name := makeIAMServiceAccountStackName(t.clusterName, t.sa.Namespace, t.sa.Name) + logger.Info("building iamserviceaccount stack %q", name) + stack := builder.NewIAMRoleResourceSetForServiceAccount(t.sa, t.oidc) + if err := stack.AddAllResources(); err != nil { + return err + } + + if t.sa.Tags == nil { + t.sa.Tags = make(map[string]string) + } + t.sa.Tags[api.IAMServiceAccountNameTag] = t.sa.NameString() + + if err := t.stackManager.CreateStack(t.ctx, name, stack, t.sa.Tags, nil, errs); err != nil { + logger.Info("an error occurred creating the stack, to cleanup resources, run 'eksctl delete iamserviceaccount --region=%s --name=%s --namespace=%s'", t.region, t.sa.Name, t.sa.Namespace) + return err + } + return nil +} + type updateIAMServiceAccountTask struct { sa *api.ClusterIAMServiceAccount - stackManager manager.StackManager + stackManager StackManager templateData manager.TemplateData clusterName string info string @@ -66,3 +101,51 @@ func (t *updateIAMServiceAccountTask) Do(errorCh chan error) error { Wait: true, }) } + +type deleteIAMRoleForServiceAccountTask struct { + ctx context.Context + info string + stack *cfntypes.Stack + stackManager StackManager + wait bool +} + +func (t *deleteIAMRoleForServiceAccountTask) Describe() string { return t.info } + +func (t *deleteIAMRoleForServiceAccountTask) Do(errorCh chan error) error { + errMsg := fmt.Sprintf("deleting IAM role for serviceaccount %q", *t.stack.StackName) + if t.wait { + if err := t.stackManager.DeleteStackBySpecSync(t.ctx, t.stack, errorCh); err != nil { + return fmt.Errorf("%s: %w", errMsg, err) + } + return nil + } + + defer close(errorCh) + if _, err := t.stackManager.DeleteStackBySpec(t.ctx, t.stack); err != nil { + return fmt.Errorf("%s: %w", errMsg, err) + } + return nil +} + +type kubernetesTask struct { + info string + kubernetes kubernetes.ClientSetGetter + objectMeta v1.ObjectMeta + call func(kubernetes.Interface, v1.ObjectMeta) error +} + +func (t *kubernetesTask) Describe() string { return t.info } +func (t *kubernetesTask) Do(errs chan error) error { + defer close(errs) + + if t.kubernetes == nil { + return fmt.Errorf("cannot start task %q as Kubernetes client configurtaion wasn't provided", t.Describe()) + } + clientSet, err := t.kubernetes.ClientSet() + if err != nil { + return err + } + err = t.call(clientSet, t.objectMeta) + return err +} diff --git a/pkg/actions/irsa/update_test.go b/pkg/actions/irsa/update_test.go index 55e4899775..9751148455 100644 --- a/pkg/actions/irsa/update_test.go +++ b/pkg/actions/irsa/update_test.go @@ -11,9 +11,9 @@ import ( . "github.com/onsi/gomega" "github.com/weaveworks/eksctl/pkg/actions/irsa" + "github.com/weaveworks/eksctl/pkg/actions/irsa/fakes" api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" "github.com/weaveworks/eksctl/pkg/cfn/manager" - "github.com/weaveworks/eksctl/pkg/cfn/manager/fakes" iamoidc "github.com/weaveworks/eksctl/pkg/iam/oidc" ) diff --git a/pkg/actions/karpenter/create.go b/pkg/actions/karpenter/create.go index b762b2c7ab..44b4f25983 100644 --- a/pkg/actions/karpenter/create.go +++ b/pkg/actions/karpenter/create.go @@ -14,7 +14,6 @@ import ( "github.com/weaveworks/eksctl/pkg/cfn/builder" "github.com/weaveworks/eksctl/pkg/iam" "github.com/weaveworks/eksctl/pkg/karpenter" - "github.com/weaveworks/eksctl/pkg/kubernetes" ) // Create creates a Karpenter installer task and waits for it to finish. @@ -24,11 +23,6 @@ func (i *Installer) Create(ctx context.Context) error { if err != nil { return fmt.Errorf("unexpected or invalid ARN: %q, %w", i.Config.Status.ARN, err) } - clientSetGetter := &kubernetes.CallbackClientSet{ - Callback: func() (kubernetes.Interface, error) { - return i.ClientSet, nil - }, - } instanceProfileName := fmt.Sprintf("eksctl-%s-%s", builder.KarpenterNodeInstanceProfile, i.Config.Metadata.Name) if i.Config.Karpenter.DefaultInstanceProfile != nil { instanceProfileName = aws.ToString(i.Config.Karpenter.DefaultInstanceProfile) @@ -58,7 +52,7 @@ func (i *Installer) Create(ctx context.Context) error { // Create the service account role only. iamServiceAccount.RoleOnly = api.Enabled() } - karpenterServiceAccountTaskTree := i.StackManager.NewTasksToCreateIAMServiceAccounts([]*api.ClusterIAMServiceAccount{iamServiceAccount}, i.OIDC, clientSetGetter) + karpenterServiceAccountTaskTree := i.IRSACreator.CreateIAMServiceAccountsTasks(ctx, []*api.ClusterIAMServiceAccount{iamServiceAccount}) logger.Info(karpenterServiceAccountTaskTree.Describe()) if err := doTasks(karpenterServiceAccountTaskTree); err != nil { return fmt.Errorf("failed to create/attach service account: %w", err) diff --git a/pkg/actions/karpenter/create_test.go b/pkg/actions/karpenter/create_test.go index ec591afced..2d53a505b8 100644 --- a/pkg/actions/karpenter/create_test.go +++ b/pkg/actions/karpenter/create_test.go @@ -24,6 +24,7 @@ import ( "k8s.io/client-go/kubernetes/fake" core "k8s.io/client-go/testing" + irsafakes "github.com/weaveworks/eksctl/pkg/actions/irsa/fakes" karpenteractions "github.com/weaveworks/eksctl/pkg/actions/karpenter" api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" "github.com/weaveworks/eksctl/pkg/cfn/builder" @@ -54,6 +55,7 @@ var _ = Describe("Create", func() { p *mockprovider.MockProvider cfg *api.ClusterConfig fakeStackManager *managerfakes.FakeStackManager + fakeIRSACreator *irsafakes.FakeCreateTasksBuilder ctl *eks.ClusterProvider fakeKarpenterInstaller *karpenterfakes.FakeChartInstaller fakeClientSet *fake.Clientset @@ -72,6 +74,7 @@ var _ = Describe("Create", func() { cfg.Karpenter = &api.Karpenter{ Version: "0.4.3", } + fakeIRSACreator = &irsafakes.FakeCreateTasksBuilder{} fakeStackManager = &fakes.FakeStackManager{} fakeKarpenterInstaller = &karpenterfakes.FakeChartInstaller{} ctl = &eks.ClusterProvider{ @@ -113,6 +116,7 @@ var _ = Describe("Create", func() { Config: cfg, KarpenterInstaller: fakeKarpenterInstaller, ClientSet: fakeClientSet, + IRSACreator: fakeIRSACreator, } Expect(install.Create(context.Background())).To(Succeed()) Expect(fakeKarpenterInstaller.InstallCallCount()).To(Equal(1)) @@ -142,6 +146,7 @@ var _ = Describe("Create", func() { Config: cfg, KarpenterInstaller: fakeKarpenterInstaller, ClientSet: fakeClientSet, + IRSACreator: fakeIRSACreator, } err := install.Create(context.Background()) Expect(err).To(MatchError(ContainSubstring("failed to install Karpenter on cluster"))) @@ -157,6 +162,7 @@ var _ = Describe("Create", func() { Config: cfg, KarpenterInstaller: fakeKarpenterInstaller, ClientSet: fakeClientSet, + IRSACreator: fakeIRSACreator, } err := install.Create(context.Background()) Expect(err).To(MatchError(ContainSubstring("nope"))) @@ -183,6 +189,7 @@ var _ = Describe("Create", func() { Config: cfg, KarpenterInstaller: fakeKarpenterInstaller, ClientSet: fakeClientSet, + IRSACreator: fakeIRSACreator, } err := install.Create(context.Background()) Expect(err).To(MatchError(ContainSubstring("failed to install Karpenter on cluster"))) @@ -200,6 +207,7 @@ var _ = Describe("Create", func() { Config: cfg, KarpenterInstaller: fakeKarpenterInstaller, ClientSet: fakeClientSet, + IRSACreator: fakeIRSACreator, } err := install.Create(context.Background()) Expect(err).To(MatchError(ContainSubstring("unexpected or invalid ARN"))) @@ -211,7 +219,7 @@ var _ = Describe("Create", func() { ft := &fakeTask{ err: errors.New("nope"), } - fakeStackManager.NewTasksToCreateIAMServiceAccountsReturns(&tasks.TaskTree{ + fakeIRSACreator.CreateIAMServiceAccountsTasksReturns(&tasks.TaskTree{ Tasks: []tasks.Task{ft}, }) }) @@ -222,6 +230,7 @@ var _ = Describe("Create", func() { Config: cfg, KarpenterInstaller: fakeKarpenterInstaller, ClientSet: fakeClientSet, + IRSACreator: fakeIRSACreator, } err := install.Create(context.Background()) Expect(err).To(MatchError(ContainSubstring("failed to create/attach service account: failed to install Karpenter on cluster"))) @@ -241,6 +250,7 @@ var _ = Describe("Create", func() { Config: cfg, KarpenterInstaller: fakeKarpenterInstaller, ClientSet: fakeClientSet, + IRSACreator: fakeIRSACreator, } err := install.Create(context.Background()) Expect(err).To(MatchError(ContainSubstring("failed to create client for auth config: getting auth ConfigMap: nope"))) @@ -260,6 +270,7 @@ var _ = Describe("Create", func() { Config: cfg, KarpenterInstaller: fakeKarpenterInstaller, ClientSet: fakeClientSet, + IRSACreator: fakeIRSACreator, } err := install.Create(context.Background()) Expect(err).To(MatchError(ContainSubstring("failed to save the identity config: nope"))) @@ -291,6 +302,7 @@ var _ = Describe("Create", func() { Config: cfg, KarpenterInstaller: fakeKarpenterInstaller, ClientSet: fakeClientSet, + IRSACreator: fakeIRSACreator, } err := install.Create(context.Background()) Expect(err).To(MatchError(ContainSubstring("failed to save the identity config: nope"))) @@ -308,10 +320,11 @@ var _ = Describe("Create", func() { Config: cfg, KarpenterInstaller: fakeKarpenterInstaller, ClientSet: fakeClientSet, + IRSACreator: fakeIRSACreator, } Expect(install.Create(context.Background())).To(Succeed()) Expect(fakeKarpenterInstaller.InstallCallCount()).To(Equal(1)) - accounts, _, _ := fakeStackManager.NewTasksToCreateIAMServiceAccountsArgsForCall(0) + _, accounts := fakeIRSACreator.CreateIAMServiceAccountsTasksArgsForCall(0) Expect(accounts).NotTo(BeEmpty()) Expect(api.IsEnabled(accounts[0].RoleOnly)).To(BeTrue()) }) @@ -328,10 +341,11 @@ var _ = Describe("Create", func() { Config: cfg, KarpenterInstaller: fakeKarpenterInstaller, ClientSet: fakeClientSet, + IRSACreator: fakeIRSACreator, } Expect(install.Create(context.Background())).To(Succeed()) Expect(fakeKarpenterInstaller.InstallCallCount()).To(Equal(1)) - accounts, _, _ := fakeStackManager.NewTasksToCreateIAMServiceAccountsArgsForCall(0) + _, accounts := fakeIRSACreator.CreateIAMServiceAccountsTasksArgsForCall(0) Expect(accounts).NotTo(BeEmpty()) Expect(accounts[0].RoleOnly).To(BeNil()) policyARN := fmt.Sprintf("arn:aws:iam::123456789012:policy/eksctl-%s-%s", builder.KarpenterManagedPolicy, cfg.Metadata.Name) @@ -350,6 +364,7 @@ var _ = Describe("Create", func() { Config: cfg, KarpenterInstaller: fakeKarpenterInstaller, ClientSet: fakeClientSet, + IRSACreator: fakeIRSACreator, } Expect(install.Create(context.Background())).To(Succeed()) Expect(fakeKarpenterInstaller.InstallCallCount()).To(Equal(1)) @@ -370,6 +385,7 @@ var _ = Describe("Create", func() { Config: cfg, KarpenterInstaller: fakeKarpenterInstaller, ClientSet: fakeClientSet, + IRSACreator: fakeIRSACreator, } Expect(install.Create(context.Background())).To(Succeed()) Expect(fakeKarpenterInstaller.InstallCallCount()).To(Equal(1)) diff --git a/pkg/actions/karpenter/karpenter.go b/pkg/actions/karpenter/karpenter.go index 25afac82e8..c912f0f5e2 100644 --- a/pkg/actions/karpenter/karpenter.go +++ b/pkg/actions/karpenter/karpenter.go @@ -9,6 +9,7 @@ import ( "github.com/kris-nova/logger" kubeclient "k8s.io/client-go/kubernetes" + "github.com/weaveworks/eksctl/pkg/actions/irsa" api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" "github.com/weaveworks/eksctl/pkg/cfn/manager" "github.com/weaveworks/eksctl/pkg/eks" @@ -36,6 +37,7 @@ type Installer struct { Wait WaitFunc KarpenterInstaller karpenter.ChartInstaller ClientSet kubernetes.Interface + IRSACreator irsa.CreateTasksBuilder OIDC *iamoidc.OpenIDConnectManager } @@ -69,6 +71,17 @@ func NewInstaller(ctx context.Context, cfg *api.ClusterConfig, ctl *eks.ClusterP logger.Warning("no IAM OIDC provider associated with cluster, try 'eksctl utils associate-iam-oidc-provider --region=%s --cluster=%s'", cfg.Metadata.Region, cfg.Metadata.Name) } + irsaCreator := irsa.NewCreator( + cfg.Metadata.Name, + cfg.Metadata.Region, + &kubernetes.CallbackClientSet{ + Callback: func() (kubernetes.Interface, error) { + return clientSet, nil + }, + }, + oidc, + stackManager) + return &Installer{ StackManager: stackManager, CTL: ctl, @@ -76,6 +89,7 @@ func NewInstaller(ctx context.Context, cfg *api.ClusterConfig, ctl *eks.ClusterP Wait: waiters.Wait, KarpenterInstaller: karpenterInstaller, ClientSet: clientSet, + IRSACreator: irsaCreator, OIDC: oidc, }, nil } diff --git a/pkg/addons/irsa_helper.go b/pkg/addons/irsa_helper.go index e9f887fb89..dd8a9e9da3 100644 --- a/pkg/addons/irsa_helper.go +++ b/pkg/addons/irsa_helper.go @@ -22,16 +22,18 @@ type IRSAHelper interface { type irsaHelper struct { oidc *iamoidc.OpenIDConnectManager irsaManager *irsa.Manager + irsaCreator *irsa.Creator stackManager manager.StackManager clusterName string } // NewIRSAHelper creates a new IRSAHelper -func NewIRSAHelper(oidc *iamoidc.OpenIDConnectManager, stackManager manager.StackManager, irsaManager *irsa.Manager, clusterName string) IRSAHelper { +func NewIRSAHelper(oidc *iamoidc.OpenIDConnectManager, stackManager manager.StackManager, irsaManager *irsa.Manager, irsaCreator *irsa.Creator, clusterName string) IRSAHelper { return &irsaHelper{ oidc: oidc, stackManager: stackManager, irsaManager: irsaManager, + irsaCreator: irsaCreator, clusterName: clusterName, } } @@ -56,7 +58,7 @@ func (h *irsaHelper) CreateOrUpdate(ctx context.Context, sa *api.ClusterIAMServi } } if stack == nil { - err = h.irsaManager.CreateIAMServiceAccount(serviceAccounts, false) + err = h.irsaCreator.CreateIAMServiceAccounts(ctx, serviceAccounts, false) } else { err = h.irsaManager.UpdateIAMServiceAccounts(ctx, serviceAccounts, []*manager.Stack{stack}, false) } diff --git a/pkg/cfn/manager/create_tasks.go b/pkg/cfn/manager/create_tasks.go index 817c9feb30..2c5f9dbeb2 100644 --- a/pkg/cfn/manager/create_tasks.go +++ b/pkg/cfn/manager/create_tasks.go @@ -4,22 +4,11 @@ import ( "context" "fmt" - "github.com/kris-nova/logger" - "github.com/pkg/errors" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" - iamoidc "github.com/weaveworks/eksctl/pkg/iam/oidc" - "github.com/weaveworks/eksctl/pkg/kubernetes" "github.com/weaveworks/eksctl/pkg/utils/tasks" "github.com/weaveworks/eksctl/pkg/vpc" ) -const ( - managedByKubernetesLabelKey = "app.kubernetes.io/managed-by" - managedByKubernetesLabelValue = "eksctl" -) - // NewTasksToCreateClusterWithNodeGroups defines all tasks required to create a cluster along // with some nodegroups; see CreateAllNodeGroups for how onlyNodeGroupSubset works. func (c *StackCollection) NewTasksToCreateClusterWithNodeGroups(ctx context.Context, nodeGroups []*api.NodeGroup, @@ -121,54 +110,3 @@ func (c *StackCollection) NewManagedNodeGroupTask(ctx context.Context, nodeGroup } return taskTree } - -// NewTasksToCreateIAMServiceAccounts defines tasks required to create all of the IAM ServiceAccounts -func (c *StackCollection) NewTasksToCreateIAMServiceAccounts(serviceAccounts []*api.ClusterIAMServiceAccount, oidc *iamoidc.OpenIDConnectManager, clientSetGetter kubernetes.ClientSetGetter) *tasks.TaskTree { - taskTree := &tasks.TaskTree{Parallel: true} - - for i := range serviceAccounts { - sa := serviceAccounts[i] - saTasks := &tasks.TaskTree{ - Parallel: false, - IsSubTask: true, - } - - if sa.AttachRoleARN == "" { - saTasks.Append(&taskWithClusterIAMServiceAccountSpec{ - info: fmt.Sprintf("create IAM role for serviceaccount %q", sa.NameString()), - stackCollection: c, - serviceAccount: sa, - oidc: oidc, - }) - } else { - logger.Debug("attachRoleARN was provided, skipping role creation") - sa.Status = &api.ClusterIAMServiceAccountStatus{ - RoleARN: &sa.AttachRoleARN, - } - } - - if sa.Labels == nil { - sa.Labels = make(map[string]string) - } - sa.Labels[managedByKubernetesLabelKey] = managedByKubernetesLabelValue - if !api.IsEnabled(sa.RoleOnly) { - saTasks.Append(&kubernetesTask{ - info: fmt.Sprintf("create serviceaccount %q", sa.NameString()), - kubernetes: clientSetGetter, - objectMeta: sa.ClusterIAMMeta.AsObjectMeta(), - call: func(clientSet kubernetes.Interface, objectMeta v1.ObjectMeta) error { - sa.SetAnnotations() - objectMeta.SetAnnotations(sa.AsObjectMeta().Annotations) - objectMeta.SetLabels(sa.AsObjectMeta().Labels) - if err := kubernetes.MaybeCreateServiceAccountOrUpdateMetadata(clientSet, objectMeta); err != nil { - return errors.Wrapf(err, "failed to create service account %s/%s", objectMeta.GetNamespace(), objectMeta.GetName()) - } - return nil - }, - }) - } - - taskTree.Append(saTasks) - } - return taskTree -} diff --git a/pkg/cfn/manager/delete_tasks.go b/pkg/cfn/manager/delete_tasks.go index 303e53f86a..55afda9905 100644 --- a/pkg/cfn/manager/delete_tasks.go +++ b/pkg/cfn/manager/delete_tasks.go @@ -16,7 +16,6 @@ import ( "github.com/weaveworks/eksctl/pkg/awsapi" "github.com/weaveworks/eksctl/pkg/cfn/waiter" iamoidc "github.com/weaveworks/eksctl/pkg/iam/oidc" - "github.com/weaveworks/eksctl/pkg/kubernetes" "github.com/weaveworks/eksctl/pkg/utils/apierrors" "github.com/weaveworks/eksctl/pkg/utils/tasks" ) @@ -29,6 +28,9 @@ type NewOIDCManager func() (*iamoidc.OpenIDConnectManager, error) // NewTasksToDeleteAddonIAM temporary type, to be removed after moving NewTasksToDeleteClusterWithNodeGroups to actions package type NewTasksToDeleteAddonIAM func(ctx context.Context, wait bool) (*tasks.TaskTree, error) +// NewTasksToDeleteIAMServiceAccounts temporary type, to be removed after moving NewTasksToDeleteOIDCProviderWithIAMServiceAccounts to actions package +type NewTasksToDeleteIAMServiceAccounts func(ctx context.Context, serviceAccounts []string, wait bool) (*tasks.TaskTree, error) + // NewTasksToDeleteClusterWithNodeGroups defines tasks required to delete the given cluster along with all of its resources func (c *StackCollection) NewTasksToDeleteClusterWithNodeGroups( ctx context.Context, @@ -37,8 +39,8 @@ func (c *StackCollection) NewTasksToDeleteClusterWithNodeGroups( clusterOperable bool, newOIDCManager NewOIDCManager, newTasksToDeleteAddonIAM NewTasksToDeleteAddonIAM, + newTasksToDeleteIAMServiceAccounts NewTasksToDeleteIAMServiceAccounts, cluster *ekstypes.Cluster, - clientSetGetter kubernetes.ClientSetGetter, wait, force bool, cleanup func(chan error, string) error) (*tasks.TaskTree, error) { taskTree := &tasks.TaskTree{Parallel: false} @@ -54,7 +56,7 @@ func (c *StackCollection) NewTasksToDeleteClusterWithNodeGroups( } if clusterOperable { - serviceAccountAndOIDCTasks, err := c.NewTasksToDeleteOIDCProviderWithIAMServiceAccounts(ctx, newOIDCManager, cluster, clientSetGetter, force) + serviceAccountAndOIDCTasks, err := c.NewTasksToDeleteOIDCProviderWithIAMServiceAccounts(ctx, newOIDCManager, newTasksToDeleteIAMServiceAccounts, cluster, force) if err != nil { return nil, err } @@ -196,7 +198,12 @@ func (c *StackCollection) NewTaskToDeleteUnownedNodeGroup(ctx context.Context, c // NewTasksToDeleteOIDCProviderWithIAMServiceAccounts defines tasks required to delete all of the iamserviceaccounts // along with associated IAM OIDC provider -func (c *StackCollection) NewTasksToDeleteOIDCProviderWithIAMServiceAccounts(ctx context.Context, newOIDCManager NewOIDCManager, cluster *ekstypes.Cluster, clientSetGetter kubernetes.ClientSetGetter, force bool) (*tasks.TaskTree, error) { +func (c *StackCollection) NewTasksToDeleteOIDCProviderWithIAMServiceAccounts( + ctx context.Context, + newOIDCManager NewOIDCManager, + newTasksToDeleteIAMServiceAccounts NewTasksToDeleteIAMServiceAccounts, + cluster *ekstypes.Cluster, + force bool) (*tasks.TaskTree, error) { taskTree := &tasks.TaskTree{Parallel: false} oidc, err := newOIDCManager() @@ -214,7 +221,7 @@ func (c *StackCollection) NewTasksToDeleteOIDCProviderWithIAMServiceAccounts(ctx } if len(allServiceAccountsWithStacks) > 0 { - saTasks, err := c.NewTasksToDeleteIAMServiceAccounts(ctx, allServiceAccountsWithStacks, clientSetGetter, true) + saTasks, err := newTasksToDeleteIAMServiceAccounts(ctx, allServiceAccountsWithStacks, true) if err != nil { return nil, err } @@ -278,64 +285,6 @@ func (c *StackCollection) getAllServiceAccounts(ctx context.Context) ([]string, return serviceAccounts, nil } -// NewTasksToDeleteIAMServiceAccounts defines tasks required to delete all of the iamserviceaccounts -func (c *StackCollection) NewTasksToDeleteIAMServiceAccounts(ctx context.Context, serviceAccounts []string, clientSetGetter kubernetes.ClientSetGetter, wait bool) (*tasks.TaskTree, error) { - serviceAccountStacks, err := c.DescribeIAMServiceAccountStacks(ctx) - if err != nil { - return nil, err - } - - stacksMap := stacksToServiceAccountMap(serviceAccountStacks) - taskTree := &tasks.TaskTree{Parallel: true} - - for _, serviceAccount := range serviceAccounts { - saTasks := &tasks.TaskTree{ - Parallel: false, - IsSubTask: true, - } - - if s, ok := stacksMap[serviceAccount]; ok { - info := fmt.Sprintf("delete IAM role for serviceaccount %q", serviceAccount) - if wait { - saTasks.Append(&taskWithStackSpec{ - info: info, - stack: s, - call: c.DeleteStackBySpecSync, - }) - } else { - saTasks.Append(&asyncTaskWithStackSpec{ - info: info, - stack: s, - call: c.DeleteStackBySpec, - }) - } - } - - meta, err := api.ClusterIAMServiceAccountNameStringToClusterIAMMeta(serviceAccount) - if err != nil { - return nil, err - } - saTasks.Append(&kubernetesTask{ - info: fmt.Sprintf("delete serviceaccount %q", serviceAccount), - kubernetes: clientSetGetter, - objectMeta: meta.AsObjectMeta(), - call: kubernetes.MaybeDeleteServiceAccount, - }) - taskTree.Append(saTasks) - } - - return taskTree, nil -} - -func stacksToServiceAccountMap(stacks []*types.Stack) map[string]*types.Stack { - stackMap := make(map[string]*types.Stack) - for _, stack := range stacks { - stackMap[GetIAMServiceAccountName(stack)] = stack - } - - return stackMap -} - func clusterHasOIDCProvider(cluster *ekstypes.Cluster) (hasOIDC bool, found bool) { for k, v := range cluster.Tags { if k == api.ClusterOIDCEnabledTag { diff --git a/pkg/cfn/manager/fakes/fake_stack_manager.go b/pkg/cfn/manager/fakes/fake_stack_manager.go index 4c95b38e23..15ab9d3cae 100644 --- a/pkg/cfn/manager/fakes/fake_stack_manager.go +++ b/pkg/cfn/manager/fakes/fake_stack_manager.go @@ -14,8 +14,6 @@ import ( "github.com/weaveworks/eksctl/pkg/awsapi" "github.com/weaveworks/eksctl/pkg/cfn/builder" "github.com/weaveworks/eksctl/pkg/cfn/manager" - iamoidc "github.com/weaveworks/eksctl/pkg/iam/oidc" - "github.com/weaveworks/eksctl/pkg/kubernetes" "github.com/weaveworks/eksctl/pkg/utils/tasks" "github.com/weaveworks/eksctl/pkg/vpc" ) @@ -635,20 +633,7 @@ type FakeStackManager struct { newTasksToCreateClusterWithNodeGroupsReturnsOnCall map[int]struct { result1 *tasks.TaskTree } - NewTasksToCreateIAMServiceAccountsStub func([]*v1alpha5.ClusterIAMServiceAccount, *iamoidc.OpenIDConnectManager, kubernetes.ClientSetGetter) *tasks.TaskTree - newTasksToCreateIAMServiceAccountsMutex sync.RWMutex - newTasksToCreateIAMServiceAccountsArgsForCall []struct { - arg1 []*v1alpha5.ClusterIAMServiceAccount - arg2 *iamoidc.OpenIDConnectManager - arg3 kubernetes.ClientSetGetter - } - newTasksToCreateIAMServiceAccountsReturns struct { - result1 *tasks.TaskTree - } - newTasksToCreateIAMServiceAccountsReturnsOnCall map[int]struct { - result1 *tasks.TaskTree - } - NewTasksToDeleteClusterWithNodeGroupsStub func(context.Context, *types.Stack, []manager.NodeGroupStack, bool, manager.NewOIDCManager, manager.NewTasksToDeleteAddonIAM, *typesc.Cluster, kubernetes.ClientSetGetter, bool, bool, func(chan error, string) error) (*tasks.TaskTree, error) + NewTasksToDeleteClusterWithNodeGroupsStub func(context.Context, *types.Stack, []manager.NodeGroupStack, bool, manager.NewOIDCManager, manager.NewTasksToDeleteAddonIAM, manager.NewTasksToDeleteIAMServiceAccounts, *typesc.Cluster, bool, bool, func(chan error, string) error) (*tasks.TaskTree, error) newTasksToDeleteClusterWithNodeGroupsMutex sync.RWMutex newTasksToDeleteClusterWithNodeGroupsArgsForCall []struct { arg1 context.Context @@ -657,8 +642,8 @@ type FakeStackManager struct { arg4 bool arg5 manager.NewOIDCManager arg6 manager.NewTasksToDeleteAddonIAM - arg7 *typesc.Cluster - arg8 kubernetes.ClientSetGetter + arg7 manager.NewTasksToDeleteIAMServiceAccounts + arg8 *typesc.Cluster arg9 bool arg10 bool arg11 func(chan error, string) error @@ -671,22 +656,6 @@ type FakeStackManager struct { result1 *tasks.TaskTree result2 error } - NewTasksToDeleteIAMServiceAccountsStub func(context.Context, []string, kubernetes.ClientSetGetter, bool) (*tasks.TaskTree, error) - newTasksToDeleteIAMServiceAccountsMutex sync.RWMutex - newTasksToDeleteIAMServiceAccountsArgsForCall []struct { - arg1 context.Context - arg2 []string - arg3 kubernetes.ClientSetGetter - arg4 bool - } - newTasksToDeleteIAMServiceAccountsReturns struct { - result1 *tasks.TaskTree - result2 error - } - newTasksToDeleteIAMServiceAccountsReturnsOnCall map[int]struct { - result1 *tasks.TaskTree - result2 error - } NewTasksToDeleteNodeGroupsStub func([]manager.NodeGroupStack, func(_ string) bool, bool, func(chan error, string) error) (*tasks.TaskTree, error) newTasksToDeleteNodeGroupsMutex sync.RWMutex newTasksToDeleteNodeGroupsArgsForCall []struct { @@ -703,13 +672,13 @@ type FakeStackManager struct { result1 *tasks.TaskTree result2 error } - NewTasksToDeleteOIDCProviderWithIAMServiceAccountsStub func(context.Context, manager.NewOIDCManager, *typesc.Cluster, kubernetes.ClientSetGetter, bool) (*tasks.TaskTree, error) + NewTasksToDeleteOIDCProviderWithIAMServiceAccountsStub func(context.Context, manager.NewOIDCManager, manager.NewTasksToDeleteIAMServiceAccounts, *typesc.Cluster, bool) (*tasks.TaskTree, error) newTasksToDeleteOIDCProviderWithIAMServiceAccountsMutex sync.RWMutex newTasksToDeleteOIDCProviderWithIAMServiceAccountsArgsForCall []struct { arg1 context.Context arg2 manager.NewOIDCManager - arg3 *typesc.Cluster - arg4 kubernetes.ClientSetGetter + arg3 manager.NewTasksToDeleteIAMServiceAccounts + arg4 *typesc.Cluster arg5 bool } newTasksToDeleteOIDCProviderWithIAMServiceAccountsReturns struct { @@ -3760,75 +3729,7 @@ func (fake *FakeStackManager) NewTasksToCreateClusterWithNodeGroupsReturnsOnCall }{result1} } -func (fake *FakeStackManager) NewTasksToCreateIAMServiceAccounts(arg1 []*v1alpha5.ClusterIAMServiceAccount, arg2 *iamoidc.OpenIDConnectManager, arg3 kubernetes.ClientSetGetter) *tasks.TaskTree { - var arg1Copy []*v1alpha5.ClusterIAMServiceAccount - if arg1 != nil { - arg1Copy = make([]*v1alpha5.ClusterIAMServiceAccount, len(arg1)) - copy(arg1Copy, arg1) - } - fake.newTasksToCreateIAMServiceAccountsMutex.Lock() - ret, specificReturn := fake.newTasksToCreateIAMServiceAccountsReturnsOnCall[len(fake.newTasksToCreateIAMServiceAccountsArgsForCall)] - fake.newTasksToCreateIAMServiceAccountsArgsForCall = append(fake.newTasksToCreateIAMServiceAccountsArgsForCall, struct { - arg1 []*v1alpha5.ClusterIAMServiceAccount - arg2 *iamoidc.OpenIDConnectManager - arg3 kubernetes.ClientSetGetter - }{arg1Copy, arg2, arg3}) - stub := fake.NewTasksToCreateIAMServiceAccountsStub - fakeReturns := fake.newTasksToCreateIAMServiceAccountsReturns - fake.recordInvocation("NewTasksToCreateIAMServiceAccounts", []interface{}{arg1Copy, arg2, arg3}) - fake.newTasksToCreateIAMServiceAccountsMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3) - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *FakeStackManager) NewTasksToCreateIAMServiceAccountsCallCount() int { - fake.newTasksToCreateIAMServiceAccountsMutex.RLock() - defer fake.newTasksToCreateIAMServiceAccountsMutex.RUnlock() - return len(fake.newTasksToCreateIAMServiceAccountsArgsForCall) -} - -func (fake *FakeStackManager) NewTasksToCreateIAMServiceAccountsCalls(stub func([]*v1alpha5.ClusterIAMServiceAccount, *iamoidc.OpenIDConnectManager, kubernetes.ClientSetGetter) *tasks.TaskTree) { - fake.newTasksToCreateIAMServiceAccountsMutex.Lock() - defer fake.newTasksToCreateIAMServiceAccountsMutex.Unlock() - fake.NewTasksToCreateIAMServiceAccountsStub = stub -} - -func (fake *FakeStackManager) NewTasksToCreateIAMServiceAccountsArgsForCall(i int) ([]*v1alpha5.ClusterIAMServiceAccount, *iamoidc.OpenIDConnectManager, kubernetes.ClientSetGetter) { - fake.newTasksToCreateIAMServiceAccountsMutex.RLock() - defer fake.newTasksToCreateIAMServiceAccountsMutex.RUnlock() - argsForCall := fake.newTasksToCreateIAMServiceAccountsArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 -} - -func (fake *FakeStackManager) NewTasksToCreateIAMServiceAccountsReturns(result1 *tasks.TaskTree) { - fake.newTasksToCreateIAMServiceAccountsMutex.Lock() - defer fake.newTasksToCreateIAMServiceAccountsMutex.Unlock() - fake.NewTasksToCreateIAMServiceAccountsStub = nil - fake.newTasksToCreateIAMServiceAccountsReturns = struct { - result1 *tasks.TaskTree - }{result1} -} - -func (fake *FakeStackManager) NewTasksToCreateIAMServiceAccountsReturnsOnCall(i int, result1 *tasks.TaskTree) { - fake.newTasksToCreateIAMServiceAccountsMutex.Lock() - defer fake.newTasksToCreateIAMServiceAccountsMutex.Unlock() - fake.NewTasksToCreateIAMServiceAccountsStub = nil - if fake.newTasksToCreateIAMServiceAccountsReturnsOnCall == nil { - fake.newTasksToCreateIAMServiceAccountsReturnsOnCall = make(map[int]struct { - result1 *tasks.TaskTree - }) - } - fake.newTasksToCreateIAMServiceAccountsReturnsOnCall[i] = struct { - result1 *tasks.TaskTree - }{result1} -} - -func (fake *FakeStackManager) NewTasksToDeleteClusterWithNodeGroups(arg1 context.Context, arg2 *types.Stack, arg3 []manager.NodeGroupStack, arg4 bool, arg5 manager.NewOIDCManager, arg6 manager.NewTasksToDeleteAddonIAM, arg7 *typesc.Cluster, arg8 kubernetes.ClientSetGetter, arg9 bool, arg10 bool, arg11 func(chan error, string) error) (*tasks.TaskTree, error) { +func (fake *FakeStackManager) NewTasksToDeleteClusterWithNodeGroups(arg1 context.Context, arg2 *types.Stack, arg3 []manager.NodeGroupStack, arg4 bool, arg5 manager.NewOIDCManager, arg6 manager.NewTasksToDeleteAddonIAM, arg7 manager.NewTasksToDeleteIAMServiceAccounts, arg8 *typesc.Cluster, arg9 bool, arg10 bool, arg11 func(chan error, string) error) (*tasks.TaskTree, error) { var arg3Copy []manager.NodeGroupStack if arg3 != nil { arg3Copy = make([]manager.NodeGroupStack, len(arg3)) @@ -3843,8 +3744,8 @@ func (fake *FakeStackManager) NewTasksToDeleteClusterWithNodeGroups(arg1 context arg4 bool arg5 manager.NewOIDCManager arg6 manager.NewTasksToDeleteAddonIAM - arg7 *typesc.Cluster - arg8 kubernetes.ClientSetGetter + arg7 manager.NewTasksToDeleteIAMServiceAccounts + arg8 *typesc.Cluster arg9 bool arg10 bool arg11 func(chan error, string) error @@ -3868,13 +3769,13 @@ func (fake *FakeStackManager) NewTasksToDeleteClusterWithNodeGroupsCallCount() i return len(fake.newTasksToDeleteClusterWithNodeGroupsArgsForCall) } -func (fake *FakeStackManager) NewTasksToDeleteClusterWithNodeGroupsCalls(stub func(context.Context, *types.Stack, []manager.NodeGroupStack, bool, manager.NewOIDCManager, manager.NewTasksToDeleteAddonIAM, *typesc.Cluster, kubernetes.ClientSetGetter, bool, bool, func(chan error, string) error) (*tasks.TaskTree, error)) { +func (fake *FakeStackManager) NewTasksToDeleteClusterWithNodeGroupsCalls(stub func(context.Context, *types.Stack, []manager.NodeGroupStack, bool, manager.NewOIDCManager, manager.NewTasksToDeleteAddonIAM, manager.NewTasksToDeleteIAMServiceAccounts, *typesc.Cluster, bool, bool, func(chan error, string) error) (*tasks.TaskTree, error)) { fake.newTasksToDeleteClusterWithNodeGroupsMutex.Lock() defer fake.newTasksToDeleteClusterWithNodeGroupsMutex.Unlock() fake.NewTasksToDeleteClusterWithNodeGroupsStub = stub } -func (fake *FakeStackManager) NewTasksToDeleteClusterWithNodeGroupsArgsForCall(i int) (context.Context, *types.Stack, []manager.NodeGroupStack, bool, manager.NewOIDCManager, manager.NewTasksToDeleteAddonIAM, *typesc.Cluster, kubernetes.ClientSetGetter, bool, bool, func(chan error, string) error) { +func (fake *FakeStackManager) NewTasksToDeleteClusterWithNodeGroupsArgsForCall(i int) (context.Context, *types.Stack, []manager.NodeGroupStack, bool, manager.NewOIDCManager, manager.NewTasksToDeleteAddonIAM, manager.NewTasksToDeleteIAMServiceAccounts, *typesc.Cluster, bool, bool, func(chan error, string) error) { fake.newTasksToDeleteClusterWithNodeGroupsMutex.RLock() defer fake.newTasksToDeleteClusterWithNodeGroupsMutex.RUnlock() argsForCall := fake.newTasksToDeleteClusterWithNodeGroupsArgsForCall[i] @@ -3907,78 +3808,6 @@ func (fake *FakeStackManager) NewTasksToDeleteClusterWithNodeGroupsReturnsOnCall }{result1, result2} } -func (fake *FakeStackManager) NewTasksToDeleteIAMServiceAccounts(arg1 context.Context, arg2 []string, arg3 kubernetes.ClientSetGetter, arg4 bool) (*tasks.TaskTree, error) { - var arg2Copy []string - if arg2 != nil { - arg2Copy = make([]string, len(arg2)) - copy(arg2Copy, arg2) - } - fake.newTasksToDeleteIAMServiceAccountsMutex.Lock() - ret, specificReturn := fake.newTasksToDeleteIAMServiceAccountsReturnsOnCall[len(fake.newTasksToDeleteIAMServiceAccountsArgsForCall)] - fake.newTasksToDeleteIAMServiceAccountsArgsForCall = append(fake.newTasksToDeleteIAMServiceAccountsArgsForCall, struct { - arg1 context.Context - arg2 []string - arg3 kubernetes.ClientSetGetter - arg4 bool - }{arg1, arg2Copy, arg3, arg4}) - stub := fake.NewTasksToDeleteIAMServiceAccountsStub - fakeReturns := fake.newTasksToDeleteIAMServiceAccountsReturns - fake.recordInvocation("NewTasksToDeleteIAMServiceAccounts", []interface{}{arg1, arg2Copy, arg3, arg4}) - fake.newTasksToDeleteIAMServiceAccountsMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3, arg4) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *FakeStackManager) NewTasksToDeleteIAMServiceAccountsCallCount() int { - fake.newTasksToDeleteIAMServiceAccountsMutex.RLock() - defer fake.newTasksToDeleteIAMServiceAccountsMutex.RUnlock() - return len(fake.newTasksToDeleteIAMServiceAccountsArgsForCall) -} - -func (fake *FakeStackManager) NewTasksToDeleteIAMServiceAccountsCalls(stub func(context.Context, []string, kubernetes.ClientSetGetter, bool) (*tasks.TaskTree, error)) { - fake.newTasksToDeleteIAMServiceAccountsMutex.Lock() - defer fake.newTasksToDeleteIAMServiceAccountsMutex.Unlock() - fake.NewTasksToDeleteIAMServiceAccountsStub = stub -} - -func (fake *FakeStackManager) NewTasksToDeleteIAMServiceAccountsArgsForCall(i int) (context.Context, []string, kubernetes.ClientSetGetter, bool) { - fake.newTasksToDeleteIAMServiceAccountsMutex.RLock() - defer fake.newTasksToDeleteIAMServiceAccountsMutex.RUnlock() - argsForCall := fake.newTasksToDeleteIAMServiceAccountsArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 -} - -func (fake *FakeStackManager) NewTasksToDeleteIAMServiceAccountsReturns(result1 *tasks.TaskTree, result2 error) { - fake.newTasksToDeleteIAMServiceAccountsMutex.Lock() - defer fake.newTasksToDeleteIAMServiceAccountsMutex.Unlock() - fake.NewTasksToDeleteIAMServiceAccountsStub = nil - fake.newTasksToDeleteIAMServiceAccountsReturns = struct { - result1 *tasks.TaskTree - result2 error - }{result1, result2} -} - -func (fake *FakeStackManager) NewTasksToDeleteIAMServiceAccountsReturnsOnCall(i int, result1 *tasks.TaskTree, result2 error) { - fake.newTasksToDeleteIAMServiceAccountsMutex.Lock() - defer fake.newTasksToDeleteIAMServiceAccountsMutex.Unlock() - fake.NewTasksToDeleteIAMServiceAccountsStub = nil - if fake.newTasksToDeleteIAMServiceAccountsReturnsOnCall == nil { - fake.newTasksToDeleteIAMServiceAccountsReturnsOnCall = make(map[int]struct { - result1 *tasks.TaskTree - result2 error - }) - } - fake.newTasksToDeleteIAMServiceAccountsReturnsOnCall[i] = struct { - result1 *tasks.TaskTree - result2 error - }{result1, result2} -} - func (fake *FakeStackManager) NewTasksToDeleteNodeGroups(arg1 []manager.NodeGroupStack, arg2 func(_ string) bool, arg3 bool, arg4 func(chan error, string) error) (*tasks.TaskTree, error) { var arg1Copy []manager.NodeGroupStack if arg1 != nil { @@ -4051,14 +3880,14 @@ func (fake *FakeStackManager) NewTasksToDeleteNodeGroupsReturnsOnCall(i int, res }{result1, result2} } -func (fake *FakeStackManager) NewTasksToDeleteOIDCProviderWithIAMServiceAccounts(arg1 context.Context, arg2 manager.NewOIDCManager, arg3 *typesc.Cluster, arg4 kubernetes.ClientSetGetter, arg5 bool) (*tasks.TaskTree, error) { +func (fake *FakeStackManager) NewTasksToDeleteOIDCProviderWithIAMServiceAccounts(arg1 context.Context, arg2 manager.NewOIDCManager, arg3 manager.NewTasksToDeleteIAMServiceAccounts, arg4 *typesc.Cluster, arg5 bool) (*tasks.TaskTree, error) { fake.newTasksToDeleteOIDCProviderWithIAMServiceAccountsMutex.Lock() ret, specificReturn := fake.newTasksToDeleteOIDCProviderWithIAMServiceAccountsReturnsOnCall[len(fake.newTasksToDeleteOIDCProviderWithIAMServiceAccountsArgsForCall)] fake.newTasksToDeleteOIDCProviderWithIAMServiceAccountsArgsForCall = append(fake.newTasksToDeleteOIDCProviderWithIAMServiceAccountsArgsForCall, struct { arg1 context.Context arg2 manager.NewOIDCManager - arg3 *typesc.Cluster - arg4 kubernetes.ClientSetGetter + arg3 manager.NewTasksToDeleteIAMServiceAccounts + arg4 *typesc.Cluster arg5 bool }{arg1, arg2, arg3, arg4, arg5}) stub := fake.NewTasksToDeleteOIDCProviderWithIAMServiceAccountsStub @@ -4080,13 +3909,13 @@ func (fake *FakeStackManager) NewTasksToDeleteOIDCProviderWithIAMServiceAccounts return len(fake.newTasksToDeleteOIDCProviderWithIAMServiceAccountsArgsForCall) } -func (fake *FakeStackManager) NewTasksToDeleteOIDCProviderWithIAMServiceAccountsCalls(stub func(context.Context, manager.NewOIDCManager, *typesc.Cluster, kubernetes.ClientSetGetter, bool) (*tasks.TaskTree, error)) { +func (fake *FakeStackManager) NewTasksToDeleteOIDCProviderWithIAMServiceAccountsCalls(stub func(context.Context, manager.NewOIDCManager, manager.NewTasksToDeleteIAMServiceAccounts, *typesc.Cluster, bool) (*tasks.TaskTree, error)) { fake.newTasksToDeleteOIDCProviderWithIAMServiceAccountsMutex.Lock() defer fake.newTasksToDeleteOIDCProviderWithIAMServiceAccountsMutex.Unlock() fake.NewTasksToDeleteOIDCProviderWithIAMServiceAccountsStub = stub } -func (fake *FakeStackManager) NewTasksToDeleteOIDCProviderWithIAMServiceAccountsArgsForCall(i int) (context.Context, manager.NewOIDCManager, *typesc.Cluster, kubernetes.ClientSetGetter, bool) { +func (fake *FakeStackManager) NewTasksToDeleteOIDCProviderWithIAMServiceAccountsArgsForCall(i int) (context.Context, manager.NewOIDCManager, manager.NewTasksToDeleteIAMServiceAccounts, *typesc.Cluster, bool) { fake.newTasksToDeleteOIDCProviderWithIAMServiceAccountsMutex.RLock() defer fake.newTasksToDeleteOIDCProviderWithIAMServiceAccountsMutex.RUnlock() argsForCall := fake.newTasksToDeleteOIDCProviderWithIAMServiceAccountsArgsForCall[i] @@ -4601,12 +4430,8 @@ func (fake *FakeStackManager) Invocations() map[string][][]interface{} { defer fake.newTaskToDeleteUnownedNodeGroupMutex.RUnlock() fake.newTasksToCreateClusterWithNodeGroupsMutex.RLock() defer fake.newTasksToCreateClusterWithNodeGroupsMutex.RUnlock() - fake.newTasksToCreateIAMServiceAccountsMutex.RLock() - defer fake.newTasksToCreateIAMServiceAccountsMutex.RUnlock() fake.newTasksToDeleteClusterWithNodeGroupsMutex.RLock() defer fake.newTasksToDeleteClusterWithNodeGroupsMutex.RUnlock() - fake.newTasksToDeleteIAMServiceAccountsMutex.RLock() - defer fake.newTasksToDeleteIAMServiceAccountsMutex.RUnlock() fake.newTasksToDeleteNodeGroupsMutex.RLock() defer fake.newTasksToDeleteNodeGroupsMutex.RUnlock() fake.newTasksToDeleteOIDCProviderWithIAMServiceAccountsMutex.RLock() diff --git a/pkg/cfn/manager/iam.go b/pkg/cfn/manager/iam.go index 85574b70ea..7db712eafe 100644 --- a/pkg/cfn/manager/iam.go +++ b/pkg/cfn/manager/iam.go @@ -2,43 +2,14 @@ package manager import ( "context" - "fmt" "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/kris-nova/logger" api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" - "github.com/weaveworks/eksctl/pkg/cfn/builder" "github.com/weaveworks/eksctl/pkg/cfn/outputs" - iamoidc "github.com/weaveworks/eksctl/pkg/iam/oidc" ) -// makeIAMServiceAccountStackName generates the name of the iamserviceaccount stack identified by its name, isolated by the cluster this StackCollection operates on and 'addon' suffix -func (c *StackCollection) makeIAMServiceAccountStackName(namespace, name string) string { - return fmt.Sprintf("eksctl-%s-addon-iamserviceaccount-%s-%s", c.spec.Metadata.Name, namespace, name) -} - -// createIAMServiceAccountTask creates the iamserviceaccount in CloudFormation -func (c *StackCollection) createIAMServiceAccountTask(ctx context.Context, errs chan error, spec *api.ClusterIAMServiceAccount, oidc *iamoidc.OpenIDConnectManager) error { - name := c.makeIAMServiceAccountStackName(spec.Namespace, spec.Name) - logger.Info("building iamserviceaccount stack %q", name) - stack := builder.NewIAMRoleResourceSetForServiceAccount(spec, oidc) - if err := stack.AddAllResources(); err != nil { - return err - } - - if spec.Tags == nil { - spec.Tags = make(map[string]string) - } - spec.Tags[api.IAMServiceAccountNameTag] = spec.NameString() - - if err := c.CreateStack(ctx, name, stack, spec.Tags, nil, errs); err != nil { - logger.Info("an error occurred creating the stack, to cleanup resources, run 'eksctl delete iamserviceaccount --region=%s --name=%s --namespace=%s'", c.spec.Metadata.Region, spec.Name, spec.Namespace) - return err - } - return nil -} - // DescribeIAMServiceAccountStacks calls ListStacks and filters out iamserviceaccounts func (c *StackCollection) DescribeIAMServiceAccountStacks(ctx context.Context) ([]*Stack, error) { stacks, err := c.ListStacks(ctx) diff --git a/pkg/cfn/manager/interface.go b/pkg/cfn/manager/interface.go index 3dc4ca91b5..50c4c2f486 100644 --- a/pkg/cfn/manager/interface.go +++ b/pkg/cfn/manager/interface.go @@ -11,8 +11,6 @@ import ( "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" "github.com/weaveworks/eksctl/pkg/awsapi" "github.com/weaveworks/eksctl/pkg/cfn/builder" - iamoidc "github.com/weaveworks/eksctl/pkg/iam/oidc" - "github.com/weaveworks/eksctl/pkg/kubernetes" "github.com/weaveworks/eksctl/pkg/utils/tasks" "github.com/weaveworks/eksctl/pkg/vpc" ) @@ -85,11 +83,9 @@ type StackManager interface { NewManagedNodeGroupTask(ctx context.Context, nodeGroups []*v1alpha5.ManagedNodeGroup, forceAddCNIPolicy bool, importer vpc.Importer) *tasks.TaskTree NewTaskToDeleteUnownedNodeGroup(ctx context.Context, clusterName, nodegroup string, eksAPI awsapi.EKS, waitCondition *DeleteWaitCondition) tasks.Task NewTasksToCreateClusterWithNodeGroups(ctx context.Context, nodeGroups []*v1alpha5.NodeGroup, managedNodeGroups []*v1alpha5.ManagedNodeGroup, postClusterCreationTasks ...tasks.Task) *tasks.TaskTree - NewTasksToCreateIAMServiceAccounts(serviceAccounts []*v1alpha5.ClusterIAMServiceAccount, oidc *iamoidc.OpenIDConnectManager, clientSetGetter kubernetes.ClientSetGetter) *tasks.TaskTree - NewTasksToDeleteClusterWithNodeGroups(ctx context.Context, clusterStack *Stack, nodeGroupStacks []NodeGroupStack, clusterOperable bool, newOIDCManager NewOIDCManager, newTasksToDeleteAddonIAM NewTasksToDeleteAddonIAM, cluster *ekstypes.Cluster, clientSetGetter kubernetes.ClientSetGetter, wait, force bool, cleanup func(chan error, string) error) (*tasks.TaskTree, error) - NewTasksToDeleteIAMServiceAccounts(ctx context.Context, serviceAccounts []string, clientSetGetter kubernetes.ClientSetGetter, wait bool) (*tasks.TaskTree, error) + NewTasksToDeleteClusterWithNodeGroups(ctx context.Context, clusterStack *Stack, nodeGroupStacks []NodeGroupStack, clusterOperable bool, newOIDCManager NewOIDCManager, newTasksToDeleteAddonIAM NewTasksToDeleteAddonIAM, newTasksToDeleteIAMServiceAccounts NewTasksToDeleteIAMServiceAccounts, cluster *ekstypes.Cluster, wait, force bool, cleanup func(chan error, string) error) (*tasks.TaskTree, error) NewTasksToDeleteNodeGroups(stacks []NodeGroupStack, shouldDelete func(_ string) bool, wait bool, cleanup func(chan error, string) error) (*tasks.TaskTree, error) - NewTasksToDeleteOIDCProviderWithIAMServiceAccounts(ctx context.Context, newOIDCManager NewOIDCManager, cluster *ekstypes.Cluster, clientSetGetter kubernetes.ClientSetGetter, force bool) (*tasks.TaskTree, error) + NewTasksToDeleteOIDCProviderWithIAMServiceAccounts(ctx context.Context, newOIDCManager NewOIDCManager, newTasksToDeleteIAMServiceAccounts NewTasksToDeleteIAMServiceAccounts, cluster *ekstypes.Cluster, force bool) (*tasks.TaskTree, error) NewUnmanagedNodeGroupTask(ctx context.Context, nodeGroups []*v1alpha5.NodeGroup, forceAddCNIPolicy, skipEgressRules bool, importer vpc.Importer) *tasks.TaskTree PropagateManagedNodeGroupTagsToASG(ngName string, ngTags map[string]string, asgNames []string, errCh chan error) error RefreshFargatePodExecutionRoleARN(ctx context.Context) error diff --git a/pkg/cfn/manager/tasks.go b/pkg/cfn/manager/tasks.go index 2569c31140..b5d34fedfb 100644 --- a/pkg/cfn/manager/tasks.go +++ b/pkg/cfn/manager/tasks.go @@ -2,14 +2,8 @@ package manager import ( "context" - "fmt" - - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" - iamoidc "github.com/weaveworks/eksctl/pkg/iam/oidc" - kubewrapper "github.com/weaveworks/eksctl/pkg/kubernetes" "github.com/weaveworks/eksctl/pkg/vpc" ) @@ -69,18 +63,6 @@ func (t *managedNodeGroupTagsToASGPropagationTask) Do(errorCh chan error) error return t.stackCollection.propagateManagedNodeGroupTagsToASGTask(t.ctx, errorCh, t.nodeGroup, t.stackCollection.PropagateManagedNodeGroupTagsToASG) } -type taskWithClusterIAMServiceAccountSpec struct { - info string - stackCollection *StackCollection - serviceAccount *api.ClusterIAMServiceAccount - oidc *iamoidc.OpenIDConnectManager -} - -func (t *taskWithClusterIAMServiceAccountSpec) Describe() string { return t.info } -func (t *taskWithClusterIAMServiceAccountSpec) Do(errs chan error) error { - return t.stackCollection.createIAMServiceAccountTask(context.TODO(), errs, t.serviceAccount, t.oidc) -} - type taskWithStackSpec struct { info string stack *Stack @@ -116,24 +98,3 @@ func (t *asyncTaskWithoutParams) Do(errs chan error) error { close(errs) return err } - -type kubernetesTask struct { - info string - kubernetes kubewrapper.ClientSetGetter - objectMeta v1.ObjectMeta - call func(kubernetes.Interface, v1.ObjectMeta) error -} - -func (t *kubernetesTask) Describe() string { return t.info } -func (t *kubernetesTask) Do(errs chan error) error { - if t.kubernetes == nil { - return fmt.Errorf("cannot start task %q as Kubernetes client configurtaion wasn't provided", t.Describe()) - } - clientSet, err := t.kubernetes.ClientSet() - if err != nil { - return err - } - err = t.call(clientSet, t.objectMeta) - close(errs) - return err -} diff --git a/pkg/cfn/manager/tasks_test.go b/pkg/cfn/manager/tasks_test.go index a4f2d051ac..1165b30be5 100644 --- a/pkg/cfn/manager/tasks_test.go +++ b/pkg/cfn/manager/tasks_test.go @@ -19,6 +19,7 @@ import ( api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" iamoidc "github.com/weaveworks/eksctl/pkg/iam/oidc" "github.com/weaveworks/eksctl/pkg/testutils/mockprovider" + "github.com/weaveworks/eksctl/pkg/utils/tasks" vpcfakes "github.com/weaveworks/eksctl/pkg/vpc/fakes" ) @@ -240,7 +241,14 @@ var _ = Describe("StackCollection Tasks", func() { }) stackManager = NewStackCollection(p, cfg) - _, err := stackManager.NewTasksToDeleteOIDCProviderWithIAMServiceAccounts(context.Background(), newOIDCManager, e.cluster, nil, false) + _, err := stackManager.NewTasksToDeleteOIDCProviderWithIAMServiceAccounts( + context.Background(), + newOIDCManager, + func(ctx context.Context, serviceAccounts []string, wait bool) (*tasks.TaskTree, error) { + return &tasks.TaskTree{}, nil + }, + e.cluster, + false) if e.expectedErr != "" { Expect(err).To(MatchError(ContainSubstring(e.expectedErr))) } else { diff --git a/pkg/ctl/create/iamserviceaccount.go b/pkg/ctl/create/iamserviceaccount.go index dbec84ccbd..d417855d43 100644 --- a/pkg/ctl/create/iamserviceaccount.go +++ b/pkg/ctl/create/iamserviceaccount.go @@ -5,6 +5,7 @@ import ( "errors" "github.com/weaveworks/eksctl/pkg/actions/irsa" + "github.com/weaveworks/eksctl/pkg/kubernetes" "github.com/kris-nova/logger" "github.com/spf13/cobra" @@ -132,5 +133,6 @@ func doCreateIAMServiceAccount(cmd *cmdutils.Cmd, overrideExistingServiceAccount return err } - return irsa.New(cfg.Metadata.Name, stackManager, oidc, clientSet).CreateIAMServiceAccount(filteredServiceAccounts, cmd.Plan) + irsaCreator := irsa.NewCreator(cfg.Metadata.Name, cfg.Metadata.Region, kubernetes.NewCachedClientSet(clientSet), oidc, stackManager) + return irsaCreator.CreateIAMServiceAccounts(ctx, filteredServiceAccounts, cmd.Plan) } diff --git a/pkg/ctl/delete/iamserviceaccount.go b/pkg/ctl/delete/iamserviceaccount.go index 91e1db3abc..1ad5d503fb 100644 --- a/pkg/ctl/delete/iamserviceaccount.go +++ b/pkg/ctl/delete/iamserviceaccount.go @@ -12,6 +12,7 @@ import ( api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" "github.com/weaveworks/eksctl/pkg/ctl/cmdutils" "github.com/weaveworks/eksctl/pkg/ctl/cmdutils/filter" + "github.com/weaveworks/eksctl/pkg/kubernetes" "github.com/weaveworks/eksctl/pkg/printers" ) @@ -111,10 +112,8 @@ func doDeleteIAMServiceAccount(cmd *cmdutils.Cmd, serviceAccount *api.ClusterIAM saSubset, _ := saFilter.MatchAll(cfg.IAM.ServiceAccounts) - irsaManager := irsa.New(cfg.Metadata.Name, stackManager, oidc, clientSet) - if err := printer.LogObj(logger.Debug, "cfg.json = \\\n%s\n", cfg); err != nil { return err } - return irsaManager.Delete(ctx, saSubset.List(), cmd.Plan, cmd.Wait) + return irsa.NewRemover(kubernetes.NewCachedClientSet(clientSet), stackManager).Delete(ctx, saSubset.List(), cmd.Plan, cmd.Wait) } diff --git a/pkg/eks/tasks.go b/pkg/eks/tasks.go index f10b57dc06..00bc25141e 100644 --- a/pkg/eks/tasks.go +++ b/pkg/eks/tasks.go @@ -104,7 +104,8 @@ func (v *VPCControllerTask) Do(errCh chan error) error { return err } irsaManager := irsa.New(v.ClusterConfig.Metadata.Name, stackCollection, oidc, clientSet) - irsa := addons.NewIRSAHelper(oidc, stackCollection, irsaManager, v.ClusterConfig.Metadata.Name) + irsaCreator := irsa.NewCreator(v.ClusterConfig.Metadata.Name, v.ClusterConfig.Metadata.Region, kubernetes.NewCachedClientSet(clientSet), oidc, stackCollection) + irsa := addons.NewIRSAHelper(oidc, stackCollection, irsaManager, irsaCreator, v.ClusterConfig.Metadata.Name) // TODO PlanMode doesn't work as intended vpcController := addons.NewVPCController(rawClient, irsa, v.ClusterConfig.Status, v.ClusterProvider.AWSProvider.Region(), v.PlanMode) @@ -457,11 +458,8 @@ func (c *ClusterProvider) appendCreateTasksForIAMServiceAccounts(ctx context.Con // as this is non-CloudFormation context, we need to construct a new stackManager, // given a clientSet getter and OpenIDConnectManager reference we can build out // the list of tasks for each of the service accounts that need to be created - newTasks := c.NewStackManager(cfg).NewTasksToCreateIAMServiceAccounts( - api.IAMServiceAccountsWithImplicitServiceAccounts(cfg), - oidcPlaceholder, - clientSet, - ) + irsaCreator := irsa.NewCreator(cfg.Metadata.Name, cfg.Metadata.Region, clientSet, oidcPlaceholder, c.NewStackManager(cfg)) + newTasks := irsaCreator.CreateIAMServiceAccountsTasks(ctx, api.IAMServiceAccountsWithImplicitServiceAccounts(cfg)) newTasks.IsSubTask = true tasks.Append(newTasks) tasks.Append(&restartDaemonsetTask{