forked from mrbarge/aws-account-operator
/
account_types.go
325 lines (283 loc) · 11.6 KB
/
account_types.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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
package v1alpha1
import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
// AccountStateStatus defines the various status an Account CR can have
type AccountStateStatus string
const (
// AccountStatusRequested const for Requested status
AccountStatusRequested AccountStateStatus = "Requested"
// AccountStatusClaimed const for Claimed status
AccountStatusClaimed AccountStateStatus = "Claimed"
// AccountCrNamespace namespace where AWS accounts will be created
AccountCrNamespace = "aws-account-operator"
// AccountOperatorIAMRole is the name for IAM user creating resources in account
AccountOperatorIAMRole = "OrganizationAccountAccessRole"
// SREAccessRoleName for CCS Account Access
SREAccessRoleName = "RH-SRE-CCS-Access"
// AccountFinalizer is the string finalizer name
AccountFinalizer = "finalizer.aws.managed.openshift.io"
)
// AccountSpec defines the desired state of Account
// +k8s:openapi-gen=true
type AccountSpec struct {
AwsAccountID string `json:"awsAccountID"`
IAMUserSecret string `json:"iamUserSecret"`
BYOC bool `json:"byoc,omitempty"`
// +optional
ClaimLink string `json:"claimLink"`
// +optional
ClaimLinkNamespace string `json:"claimLinkNamespace,omitempty"`
LegalEntity LegalEntity `json:"legalEntity,omitempty"`
ManualSTSMode bool `json:"manualSTSMode,omitempty"`
}
// AccountStatus defines the observed state of Account
// +k8s:openapi-gen=true
type AccountStatus struct {
Claimed bool `json:"claimed,omitempty"`
SupportCaseID string `json:"supportCaseID,omitempty"`
// +optional
Conditions []AccountCondition `json:"conditions,omitempty"`
State string `json:"state,omitempty"`
RotateCredentials bool `json:"rotateCredentials,omitempty"`
RotateConsoleCredentials bool `json:"rotateConsoleCredentials,omitempty"`
Reused bool `json:"reused,omitempty"`
}
// AccountCondition contains details for the current condition of a AWS account
// +k8s:openapi-gen=true
type AccountCondition struct {
// Type is the type of the condition.
// +optional
Type AccountConditionType `json:"type,omitempty"`
// Status is the status of the condition
Status corev1.ConditionStatus `json:"status,omitempty"`
// LastProbeTime is the last time we probed the condition.
// +optional
LastProbeTime metav1.Time `json:"lastProbeTime,omitempty"`
// LastTransitionTime is the laste time the condition transitioned from one status to another.
// +optional
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
// Reason is a unique, one-word, CamelCase reason for the condition's last transition.
// +optional
Reason string `json:"reason,omitempty"`
// Message is a human-readable message indicating details about last transition.
// +optional
Message string `json:"message,omitempty"`
}
// AccountConditionType is a valid value for AccountCondition.Type
type AccountConditionType string
const (
// AccountCreating is set when an Account is being created
AccountCreating AccountConditionType = "Creating"
// AccountReady is set when an Account creation is ready
AccountReady AccountConditionType = "Ready"
// AccountFailed is set when account creation has failed
AccountFailed AccountConditionType = "Failed"
// AccountCreationFailed is set during AWS account creation
AccountCreationFailed AccountConditionType = "AccountCreationFailed"
// AccountPending is set when account creation is pending
AccountPending AccountConditionType = "Pending"
// AccountPendingVerification is set when account creation is pending
AccountPendingVerification AccountConditionType = "PendingVerification"
// FIXME: Have to call this different than "AccountClaimed", as that clashes
// with the AccountClaimConditionType
AccountIsClaimed AccountConditionType = "Claimed"
// AccountReused is set when account is reused
AccountReused AccountConditionType = "Reused"
// AccountClientError is set when there was an issue getting a client
AccountClientError AccountConditionType = "AccountClientError"
// AccountAuthorizationError indicates an authorization error occurred
AccountAuthorizationError AccountConditionType = "AuthorizationError"
// AccountAuthenticationError indicates an authentication error occurred
AccountAuthenticationError AccountConditionType = "AuthenticationError"
// AccountUnhandledError indicates a error that isn't handled, probably a go error
AccountUnhandledError AccountConditionType = "UnhandledError"
// AccountInternalError is set when a serious internal issue arrises
AccountInternalError AccountConditionType = "InternalError"
// AccountInitializingRegions indicates we've kicked off the process of creating and terminating
// instances in all supported regions
AccountInitializingRegions = "InitializingRegions"
// AccountQuotaIncreaseRequested is set when a quota increase has been requested
AccountQuotaIncreaseRequested AccountConditionType = "QuotaIncreaseRequested"
)
// +genclient
// +kubebuilder:object:root=true
// Account is the Schema for the accounts API
// +k8s:openapi-gen=true
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="State",type="string",JSONPath=".status.state",description="Status the account"
// +kubebuilder:printcolumn:name="Claimed",type="boolean",JSONPath=".status.claimed",description="True if the account has been claimed"
// +kubebuilder:printcolumn:name="Claim",type="string",JSONPath=".spec.claimLink",description="Link to the account claim CR"
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Age since the account was created"
// +kubebuilder:resource:path=accounts,scope=Namespaced
type Account struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec AccountSpec `json:"spec,omitempty"`
Status AccountStatus `json:"status,omitempty"`
}
// +kubebuilder:object:root=true
// AccountList contains a list of Account
type AccountList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []Account `json:"items"`
}
func init() {
SchemeBuilder.Register(&Account{}, &AccountList{})
}
// Helper Functions
//IsFailed returns true if an account is in a failed state
func (a *Account) IsFailed() bool {
failedStates := [7]string{
string(AccountFailed),
string(AccountCreationFailed),
string(AccountClientError),
string(AccountAuthorizationError),
string(AccountAuthenticationError),
string(AccountUnhandledError),
string(AccountInternalError),
}
for _, state := range failedStates {
if a.Status.State == state {
return true
}
}
return false
}
//HasState returns true if an account has a state set at all
func (a *Account) HasState() bool {
return a.Status.State != ""
}
//HasSupportCaseID returns true if an account has a SupportCaseID Set
func (a *Account) HasSupportCaseID() bool {
return a.Status.SupportCaseID != ""
}
//IsPendingVerification returns true if the account is in a PendingVerification state
func (a *Account) IsPendingVerification() bool {
return a.Status.State == string(AccountPendingVerification)
}
//IsReady returns true if an account is ready
func (a *Account) IsReady() bool {
return a.Status.State == string(AccountReady)
}
//IsCreating returns true if an account is creating
func (a *Account) IsCreating() bool {
return a.Status.State == string(AccountCreating)
}
//HasClaimLink returns true if an accounts claim link is not empty
func (a *Account) HasClaimLink() bool {
return a.Spec.ClaimLink != ""
}
//IsClaimed returns true if account Status.Claimed is false
func (a *Account) IsClaimed() bool {
return a.Status.Claimed
}
//IsPendingDeletion returns true if a DeletionTimestamp has been set
func (a *Account) IsPendingDeletion() bool {
return a.DeletionTimestamp != nil
}
//IsBYOC returns true if account is a BYOC account
func (a *Account) IsBYOC() bool {
return a.Spec.BYOC
}
//HasAwsAccountID returns true if awsAccountID is set
func (a *Account) HasAwsAccountID() bool {
return a.Spec.AwsAccountID != ""
}
//IsReadyUnclaimedAndHasClaimLink returns true if an account is ready, unclaimed, and has a claim link
func (a *Account) IsReadyUnclaimedAndHasClaimLink() bool {
return a.IsReady() &&
a.HasClaimLink() &&
!a.IsClaimed()
}
//HasAwsv1alpha1Finalizer returns true if the awsv1alpha1 finalizer is set on the account
func (a *Account) HasAwsv1alpha1Finalizer() bool {
for _, v := range a.GetFinalizers() {
if v == AccountFinalizer {
return true
}
}
return false
}
func (a *Account) IsSTS() bool {
return a.Spec.ManualSTSMode
}
func (a *Account) IsNonSTSPendingDeletionWithFinalizer() bool {
return a.IsPendingDeletion() &&
!a.IsSTS() &&
a.HasAwsv1alpha1Finalizer()
}
//IsBYOCPendingDeletionWithFinalizer returns true if account is a BYOC Account,
// has been marked for deletion (deletion timestamp set), and has a finalizer set.
func (a *Account) IsBYOCPendingDeletionWithFinalizer() bool {
return a.IsPendingDeletion() &&
a.IsBYOC() &&
a.HasAwsv1alpha1Finalizer()
}
//IsBYOCAndNotReady returns true if account is BYOC and the state is not AccountReady
func (a *Account) IsBYOCAndNotReady() bool {
return a.IsBYOC() && !a.IsReady()
}
//ReadyForInitialization returns true if account is a BYOC Account and the state is not ready OR
// accout state is creating, and has not been claimed
func (a *Account) ReadyForInitialization() bool {
return a.IsBYOCAndNotReady() ||
a.IsUnclaimedAndIsCreating()
}
//IsUnclaimedAndHasNoState returns true if account has not set state and has not been claimed
func (a *Account) IsUnclaimedAndHasNoState() bool {
return !a.HasState() &&
!a.IsClaimed()
}
//IsUnclaimedAndIsCreating returns true if account state is AccountCreating and has not been claimed
func (a *Account) IsUnclaimedAndIsCreating() bool {
return a.IsCreating() &&
!a.IsClaimed()
}
//IsInitializingRegions returns true if the account state is InitalizingRegions
func (a *Account) IsInitializingRegions() bool {
return a.Status.State == AccountInitializingRegions
}
//IsProgressing returns true if the account state is Creating, Pending Verification, or InitializingRegions
func (a *Account) IsProgressing() bool {
if a.Status.State == string(AccountCreating) ||
a.Status.State == string(AccountPendingVerification) ||
a.Status.State == string(AccountInitializingRegions) {
return true
}
return false
}
// HasBeenClaimed lets us know if an account has been claimed at some point and can only be reused by clusters in the same legal entity
func (a *Account) HasBeenClaimedAtLeastOnce() bool {
return a.Spec.LegalEntity.ID != "" || a.Status.Reused
}
//HasNeverBeenClaimed returns true if the account is not claimed AND has no legalEntity set, meaning it hasn't been claimed before and is not available for reuse
func (a *Account) HasNeverBeenClaimed() bool {
return !a.Status.Claimed && a.Spec.LegalEntity.ID == ""
}
//IsOwnedByAccountPool returns true if the account has an ownerreference type that is the accountpool
func (a *Account) IsOwnedByAccountPool() bool {
if a.ObjectMeta.OwnerReferences == nil {
return false
}
for _, ref := range a.ObjectMeta.OwnerReferences {
if ref.Kind == "AccountPool" {
return true
}
}
return false
}
// GetCondition finds the condition that has the
// specified condition type in the given list. If none exists, then returns nil.
func (a *Account) GetCondition(conditionType AccountConditionType) *AccountCondition {
for i, condition := range a.Status.Conditions {
if condition.Type == conditionType {
return &a.Status.Conditions[i]
}
}
return nil
}