@@ -17,6 +17,7 @@ import (
17
17
"context"
18
18
"fmt"
19
19
20
+ "github.com/aws/aws-sdk-go/aws/arn"
20
21
"github.com/go-logr/logr"
21
22
"github.com/pkg/errors"
22
23
corev1 "k8s.io/api/core/v1"
@@ -108,27 +109,47 @@ func (r *adoptionReconciler) reconcile(ctx context.Context, req ctrlrt.Request)
108
109
return ackerr .NotAdoptable
109
110
}
110
111
112
+ // If a user specified a namespace with role ARN annotation,
113
+ // we need to get the role and set the accout ID to that role.
114
+ teamID := r .getTeamID (res )
115
+
111
116
// If a user has specified a namespace that is annotated with the
112
117
// an owner account ID, we need an appropriate role ARN to assume
113
118
// in order to perform the reconciliation. The roles ARN are typically
114
119
// stored in a ConfigMap in the ACK system namespace.
115
120
// If the ConfigMap is not created, or not populated with an
116
121
// accountID to roleARN mapping, we need to properly requeue with a
117
122
// helpful message to the user.
118
- var roleARN ackv1alpha1.AWSResourceName
119
123
acctID , needCARMLookup := r .getOwnerAccountID (res )
120
- if needCARMLookup {
121
- // This means that the user is specifying a namespace that is
122
- // annotated with an owner account ID. We need to retrieve the
123
- // roleARN from the ConfigMap and properly requeue if the roleARN
124
- // is not available.
125
- roleARN , err = r .getOwnerAccountRoleARN (acctID )
124
+
125
+ var roleARN ackv1alpha1.AWSResourceName
126
+ if teamID != "" {
127
+ roleARN , err = r .getTeamRoleARN (teamID )
126
128
if err != nil {
127
129
ackrtlog .InfoAdoptedResource (r .log , res , fmt .Sprintf ("Unable to start adoption reconcilliation %s: %v" , acctID , err ))
128
130
// r.getRoleARN errors are not terminal, we should requeue.
129
131
return requeue .NeededAfter (err , roleARNNotAvailableRequeueDelay )
130
132
}
133
+ parsedARN , err := arn .Parse (string (roleARN ))
134
+ if err != nil {
135
+ return fmt .Errorf ("failed to parsed role ARN %q from namespace annotation: %v" , roleARN , err )
136
+ }
137
+ acctID = ackv1alpha1 .AWSAccountID (parsedARN .AccountID )
138
+ } else {
139
+ if needCARMLookup {
140
+ // This means that the user is specifying a namespace that is
141
+ // annotated with an owner account ID or team ID. We need to retrieve the
142
+ // roleARN from the ConfigMap and properly requeue if the roleARN
143
+ // is not available.
144
+ roleARN , err = r .getOwnerAccountRoleARN (acctID )
145
+ if err != nil {
146
+ ackrtlog .InfoAdoptedResource (r .log , res , fmt .Sprintf ("Unable to start adoption reconcilliation %s: %v" , acctID , err ))
147
+ // r.getRoleARN errors are not terminal, we should requeue.
148
+ return requeue .NeededAfter (err , roleARNNotAvailableRequeueDelay )
149
+ }
150
+ }
131
151
}
152
+
132
153
region := r .getRegion (res )
133
154
targetDescriptor := rmf .ResourceDescriptor ()
134
155
endpointURL := r .getEndpointURL (res )
@@ -460,6 +481,19 @@ func (r *adoptionReconciler) getOwnerAccountID(
460
481
return ackv1alpha1 .AWSAccountID (r .cfg .AccountID ), false
461
482
}
462
483
484
+ // getTeamID returns the team ID that owns the supplied resource.
485
+ func (r * adoptionReconciler ) getTeamID (
486
+ res * ackv1alpha1.AdoptedResource ,
487
+ ) ackv1alpha1.TeamID {
488
+ // look for team id in the namespace annotations
489
+ namespace := res .GetNamespace ()
490
+ teamID , ok := r .cache .Namespaces .GetTeamID (namespace )
491
+ if ok {
492
+ return ackv1alpha1 .TeamID (teamID )
493
+ }
494
+ return ""
495
+ }
496
+
463
497
// getEndpointURL returns the AWS account that owns the supplied resource.
464
498
// We look for the namespace associated endpoint url, if that is set we use it.
465
499
// Otherwise if none of these annotations are set we use the endpoint url specified
@@ -478,8 +512,8 @@ func (r *adoptionReconciler) getEndpointURL(
478
512
return r .cfg .EndpointURL
479
513
}
480
514
481
- // getOwnerAccountRoleARN return the Role ARN that should be assumed in order to manage
482
- // the resources.
515
+ // getRoleARN return the Role ARN that should be assumed for accoutn ID
516
+ // in order to manage the resources.
483
517
func (r * adoptionReconciler ) getOwnerAccountRoleARN (
484
518
acctID ackv1alpha1.AWSAccountID ,
485
519
) (ackv1alpha1.AWSResourceName , error ) {
@@ -496,6 +530,19 @@ func (r *adoptionReconciler) getOwnerAccountRoleARN(
496
530
return ackv1alpha1 .AWSResourceName (roleARN ), nil
497
531
}
498
532
533
+ // getTeamRoleARN return the Role ARN that should be assumed for a team ID
534
+ // in order to manage the resources.
535
+ func (r * adoptionReconciler ) getTeamRoleARN (
536
+ teamID ackv1alpha1.TeamID ,
537
+ ) (ackv1alpha1.AWSResourceName , error ) {
538
+ roleARN , err := r .cache .CARMMaps .GetValue (ackrtcache .TeamIDPrefix + string (teamID ))
539
+ if err == ackrtcache .ErrCARMConfigMapNotFound || err == ackrtcache .ErrKeyNotFound {
540
+ return "" , fmt .Errorf ("unable to retrieve role ARN from CARM v2 for account %s: %v" , teamID , err )
541
+ }
542
+
543
+ return ackv1alpha1 .AWSResourceName (roleARN ), nil
544
+ }
545
+
499
546
// getRegion returns the AWS region that the given resource is in or should be
500
547
// created in. If the CR have a region associated with it, it is used. Otherwise
501
548
// we look for the namespace associated region, if that is set we use it. Finally
0 commit comments