-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
iamserviceaccount_filter.go
179 lines (158 loc) · 6.32 KB
/
iamserviceaccount_filter.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
package filter
import (
"k8s.io/apimachinery/pkg/util/sets"
"github.com/kris-nova/logger"
api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5"
"github.com/weaveworks/eksctl/pkg/kubernetes"
)
// IAMServiceAccountFilter holds filter configuration
type IAMServiceAccountFilter struct {
*Filter
}
// A stackLister lists nodegroup stacks
type serviceAccountLister interface {
ListIAMServiceAccountStacks() ([]string, error)
}
// NewIAMServiceAccountFilter create new ServiceAccountFilter instance
func NewIAMServiceAccountFilter() *IAMServiceAccountFilter {
return &IAMServiceAccountFilter{
Filter: &Filter{
ExcludeAll: false,
includeNames: sets.NewString(),
excludeNames: sets.NewString(),
},
}
}
// AppendGlobs appends globs for inclusion and exclusion rules
func (f *IAMServiceAccountFilter) AppendGlobs(includeGlobExprs, excludeGlobExprs []string, serviceAccounts []*api.ClusterIAMServiceAccount) error {
if err := f.AppendIncludeGlobs(serviceAccounts, includeGlobExprs...); err != nil {
return err
}
return f.AppendExcludeGlobs(excludeGlobExprs...)
}
// AppendIncludeGlobs sets globs for inclusion rules
func (f *IAMServiceAccountFilter) AppendIncludeGlobs(serviceAccounts []*api.ClusterIAMServiceAccount, globExprs ...string) error {
return f.doAppendIncludeGlobs(f.collectNames(serviceAccounts), "iamserviceaccount", globExprs...)
}
// SetExcludeExistingFilter uses stackManager to list existing nodegroup stacks and configures
// the filter accordingly
func (f *IAMServiceAccountFilter) SetExcludeExistingFilter(stackManager serviceAccountLister, clientSet kubernetes.Interface, serviceAccounts []*api.ClusterIAMServiceAccount, overrideExistingServiceAccounts bool) error {
if f.ExcludeAll {
return nil
}
existing, err := stackManager.ListIAMServiceAccountStacks()
if err != nil {
return err
}
if !overrideExistingServiceAccounts {
err := f.ForEach(serviceAccounts, func(_ int, sa *api.ClusterIAMServiceAccount) error {
if api.IsEnabled(sa.RoleOnly) {
return nil
}
exists, err := kubernetes.CheckServiceAccountExists(clientSet, sa.ClusterIAMMeta.AsObjectMeta())
if err != nil {
return err
}
if exists {
existing = append(existing, sa.NameString())
}
return nil
})
if err != nil {
return err
}
}
return f.doSetExcludeExistingFilter(existing, "iamserviceaccount")
}
// SetDeleteFilter uses stackManager to list existing iamserviceaccount stacks and configures
// the filter to either explictily exluce or include iamserviceaccounts that are missing from given serviceAccounts
func (f *IAMServiceAccountFilter) SetDeleteFilter(lister serviceAccountLister, includeOnlyMissing bool, cfg *api.ClusterConfig) error {
existing, err := lister.ListIAMServiceAccountStacks()
if err != nil {
return err
}
remote := sets.NewString(existing...)
local := sets.NewString()
var explicitIncludes []string
// if we're doing onlyMissing, that means the user _probably_ doesn't want
// to delete the aws-node service account
// if they do, they can explicitly delete it by calling `delete
// iamserviceaccount` either explicitly with `--name aws-node` or by leaving
// out `--only-missing` and listing it
if includeOnlyMissing {
cfg.IAM.ServiceAccounts = api.IAMServiceAccountsWithImplicitServiceAccounts(cfg)
}
serviceAccounts := &cfg.IAM.ServiceAccounts
for _, localServiceAccount := range *serviceAccounts {
localServiceAccountName := localServiceAccount.NameString()
local.Insert(localServiceAccountName)
if !remote.Has(localServiceAccountName) {
logger.Info("iamserviceaccounts %q present in the given config, but missing in the cluster", localServiceAccountName)
f.AppendExcludeNames(localServiceAccountName)
} else if includeOnlyMissing {
logger.Info("iamserviceaccounts %q present in the given config and the cluster", localServiceAccountName)
f.AppendExcludeNames(localServiceAccountName)
}
}
for remoteServiceAccountName := range remote {
if !local.Has(remoteServiceAccountName) {
logger.Info("iamserviceaccounts %q present in the cluster, but missing from the given config", remoteServiceAccountName)
if includeOnlyMissing {
// append it to the config object, so that `saFilter.ForEach` knows about it
meta, err := api.ClusterIAMServiceAccountNameStringToClusterIAMMeta(remoteServiceAccountName)
if err != nil {
return err
}
remoteServiceAccount := &api.ClusterIAMServiceAccount{
ClusterIAMMeta: *meta,
}
*serviceAccounts = append(*serviceAccounts, remoteServiceAccount)
// make sure it passes it through the filter, so that one can use `--only-missing` along with `--exclude`
if f.Match(remoteServiceAccountName) {
explicitIncludes = append(explicitIncludes, remoteServiceAccountName)
}
}
}
}
for i := range explicitIncludes {
f.AppendIncludeNames(explicitIncludes[i])
}
return nil
}
// LogInfo prints out a user-friendly message about how filter was applied
func (f *IAMServiceAccountFilter) LogInfo(serviceAccounts []*api.ClusterIAMServiceAccount) {
included, excluded := f.MatchAll(serviceAccounts)
f.doLogInfo("iamserviceaccount", included, excluded)
}
// MatchAll all names against the filter and return two sets of names - included and excluded
func (f *IAMServiceAccountFilter) MatchAll(serviceAccounts []*api.ClusterIAMServiceAccount) (sets.String, sets.String) {
return f.doMatchAll(f.collectNames(serviceAccounts))
}
// FilterMatching matches names against the filter and returns all included service accounts
func (f *IAMServiceAccountFilter) FilterMatching(serviceAccounts []*api.ClusterIAMServiceAccount) []*api.ClusterIAMServiceAccount {
var match []*api.ClusterIAMServiceAccount
for _, sa := range serviceAccounts {
if f.Match(sa.NameString()) {
match = append(match, sa)
}
}
return match
}
// ForEach iterates over each nodegroup that is included by the filter and calls iterFn
func (f *IAMServiceAccountFilter) ForEach(serviceAccounts []*api.ClusterIAMServiceAccount, iterFn func(i int, sa *api.ClusterIAMServiceAccount) error) error {
for i, sa := range serviceAccounts {
if f.Match(sa.NameString()) {
if err := iterFn(i, sa); err != nil {
return err
}
}
}
return nil
}
func (*IAMServiceAccountFilter) collectNames(serviceAccounts []*api.ClusterIAMServiceAccount) []string {
names := []string{}
for _, sa := range serviceAccounts {
names = append(names, sa.NameString())
}
return names
}