Skip to content

Commit 6e6dd5d

Browse files
CloudWatch infra support for eksapi deployer (#648)
* CW Infra changes and supporting files * cw infra changes as suggested * Pod Agent Identity * fixing for nodeam update * Fixing nits * infra.go uuid * moree edits * fixing nit.
1 parent 01c363f commit 6e6dd5d

File tree

5 files changed

+209
-0
lines changed

5 files changed

+209
-0
lines changed

internal/deployers/eksapi/deployer.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import (
88

99
"github.com/aws/aws-k8s-tester/internal"
1010
"github.com/aws/aws-k8s-tester/internal/awssdk"
11+
"github.com/aws/aws-k8s-tester/internal/deployers/eksapi/templates"
12+
fwext "github.com/aws/aws-k8s-tester/internal/e2e"
1113
"github.com/aws/aws-k8s-tester/internal/metrics"
1214
"github.com/aws/aws-k8s-tester/internal/util"
1315

@@ -232,6 +234,22 @@ func (d *deployer) Up() error {
232234
// don't return err, this isn't critical
233235
}
234236
}
237+
238+
klog.Infof("Setting up CloudWatch infrastructure...")
239+
if roleArn, err := d.infraManager.createCloudWatchInfrastructureStack(d.cluster.name); err != nil {
240+
klog.Errorf("CloudWatch infrastructure setup failed: %v", err)
241+
return err
242+
} else {
243+
d.infra.cloudwatchRoleArn = roleArn
244+
klog.Infof("CloudWatch infrastructure setup completed")
245+
}
246+
// Apply CloudWatch infrastructure manifest
247+
manifest := templates.CloudWatchAgentRbac
248+
if err := fwext.ApplyManifests(d.k8sClient.config, manifest); err != nil {
249+
klog.Errorf("CloudWatch infrastructure manifest failed: %v", err)
250+
return err
251+
}
252+
klog.Infof("CloudWatch infrastructure manifest applied successfully")
235253
return nil
236254
}
237255

@@ -338,6 +356,9 @@ func (d *deployer) Down() error {
338356
}
339357

340358
func deleteResources(im *InfrastructureManager, cm *ClusterManager, nm *nodeManager, k8sClient *k8sClient /* nillable */, opts *deployerOptions /* nillable */) error {
359+
if err := im.deleteCloudWatchInfrastructureStack(); err != nil {
360+
return err
361+
}
341362
if err := nm.deleteNodes(k8sClient, opts); err != nil {
342363
return err
343364
}

internal/deployers/eksapi/infra.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ type Infrastructure struct {
8585
clusterRoleARN string
8686
nodeRoleARN string
8787
nodeRoleName string
88+
cloudwatchRoleArn string
8889
}
8990

9091
func (i *Infrastructure) subnets() []string {
@@ -475,3 +476,77 @@ func (m *InfrastructureManager) getAZsWithCapacity(opts *deployerOptions) ([]str
475476
}
476477
return subnetAzs, nil
477478
}
479+
480+
func getCloudWatchStackName(resourceID string) (string, string) {
481+
clusterUUID := strings.TrimPrefix(resourceID, ResourcePrefix+"-")
482+
return fmt.Sprintf("cloudwatch-%s", clusterUUID), clusterUUID
483+
}
484+
485+
func (m *InfrastructureManager) createCloudWatchInfrastructureStack(clusterName string) (string, error) {
486+
stackName, clusterUUID := getCloudWatchStackName(clusterName)
487+
klog.Infof("creating CloudWatch infrastructure stack: %s", stackName)
488+
out, err := m.clients.CFN().CreateStack(context.TODO(), &cloudformation.CreateStackInput{
489+
StackName: aws.String(stackName),
490+
TemplateBody: aws.String(templates.CloudWatchInfra),
491+
Capabilities: []cloudformationtypes.Capability{cloudformationtypes.CapabilityCapabilityNamedIam},
492+
Parameters: []cloudformationtypes.Parameter{
493+
{
494+
ParameterKey: aws.String("ClusterName"),
495+
ParameterValue: aws.String(clusterName),
496+
},
497+
{
498+
ParameterKey: aws.String("ClusterUUID"),
499+
ParameterValue: aws.String(clusterUUID),
500+
},
501+
},
502+
})
503+
if err != nil {
504+
return "", fmt.Errorf("failed to create CloudWatch infrastructure stack: %w", err)
505+
}
506+
507+
klog.Infof("waiting for CloudWatch infrastructure stack to be created: %s", *out.StackId)
508+
if err := cloudformation.NewStackCreateCompleteWaiter(m.clients.CFN()).
509+
Wait(context.TODO(),
510+
&cloudformation.DescribeStacksInput{
511+
StackName: out.StackId,
512+
},
513+
infraStackCreationTimeout); err != nil {
514+
return "", fmt.Errorf("failed to wait for CloudWatch infrastructure stack creation: %w", err)
515+
}
516+
517+
// Get the CloudWatch role ARN from stack outputs
518+
stack, err := m.clients.CFN().DescribeStacks(context.TODO(), &cloudformation.DescribeStacksInput{
519+
StackName: out.StackId,
520+
})
521+
if err != nil {
522+
return "", fmt.Errorf("failed to describe CloudWatch infrastructure stack: %w", err)
523+
}
524+
525+
for _, output := range stack.Stacks[0].Outputs {
526+
if aws.ToString(output.OutputKey) == "CloudWatchRoleArn" {
527+
klog.Infof("CloudWatch infrastructure stack created successfully with role ARN: %s", aws.ToString(output.OutputValue))
528+
return aws.ToString(output.OutputValue), nil
529+
}
530+
}
531+
532+
return "", fmt.Errorf("CloudWatch role ARN not found in stack outputs")
533+
}
534+
535+
func (m *InfrastructureManager) deleteCloudWatchInfrastructureStack() error {
536+
stackName, _ := getCloudWatchStackName(m.resourceID)
537+
538+
klog.Infof("deleting CloudWatch infrastructure stack: %s", stackName)
539+
if _, err := m.clients.CFN().DeleteStack(context.TODO(), &cloudformation.DeleteStackInput{
540+
StackName: aws.String(stackName),
541+
}); err != nil {
542+
var notFound *cloudformationtypes.StackNotFoundException
543+
if errors.As(err, &notFound) {
544+
klog.Infof("CloudWatch infrastructure stack does not exist: %s", stackName)
545+
return nil
546+
}
547+
return fmt.Errorf("failed to delete CloudWatch infrastructure stack: %w", err)
548+
}
549+
550+
klog.Infof("initiated deletion of CloudWatch infrastructure stack: %s", stackName)
551+
return nil
552+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
AWSTemplateFormatVersion: '2010-09-09'
2+
Description: kubetest2-eksapi CloudWatch using Pod Identity
3+
4+
Parameters:
5+
ClusterName:
6+
Description: Name of the EKS cluster
7+
Type: String
8+
9+
ClusterUUID:
10+
Description: UUID portion of the cluster name
11+
Type: String
12+
13+
Resources:
14+
CloudWatchRole:
15+
Type: AWS::IAM::Role
16+
Properties:
17+
RoleName: !Sub "cloudwatch-role-${ClusterUUID}"
18+
AssumeRolePolicyDocument:
19+
Version: '2012-10-17'
20+
Statement:
21+
- Sid: AllowEksAuthToAssumeRoleForPodIdentity
22+
Effect: Allow
23+
Principal:
24+
Service: pods.eks.amazonaws.com
25+
Action:
26+
- sts:AssumeRole
27+
- sts:TagSession
28+
ManagedPolicyArns:
29+
- arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy
30+
Description: Role for CloudWatch Agent in EKS cluster
31+
32+
PodIdentityAssociation:
33+
Type: AWS::EKS::PodIdentityAssociation
34+
Properties:
35+
ClusterName: !Ref ClusterName
36+
Namespace: amazon-cloudwatch
37+
ServiceAccount: cwagent
38+
RoleArn: !GetAtt CloudWatchRole.Arn
39+
40+
EksPodIdentityAgentAddon:
41+
Type: AWS::EKS::Addon
42+
Properties:
43+
AddonName: eks-pod-identity-agent
44+
ClusterName: !Ref ClusterName
45+
46+
Outputs:
47+
CloudWatchRoleArn:
48+
Description: ARN of the CloudWatch IAM role
49+
Value: !GetAtt CloudWatchRole.Arn
50+
Export:
51+
Name: !Sub "${AWS::StackName}::CloudWatchRoleArn"
52+
53+
PodIdentityAssociationArn:
54+
Description: ARN of the Pod Identity Association
55+
Value: !Ref PodIdentityAssociation
56+
Export:
57+
Name: !Sub '${AWS::StackName}-PodIdentityAssociationArn'
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
apiVersion: v1
2+
kind: Namespace
3+
metadata:
4+
name: amazon-cloudwatch
5+
labels:
6+
name: amazon-cloudwatch
7+
8+
---
9+
apiVersion: v1
10+
kind: ServiceAccount
11+
metadata:
12+
name: cwagent
13+
namespace: amazon-cloudwatch
14+
15+
---
16+
# ClusterRole for cwagent
17+
apiVersion: rbac.authorization.k8s.io/v1
18+
kind: ClusterRole
19+
metadata:
20+
name: cwagent-role
21+
rules:
22+
- apiGroups: [""]
23+
resources:
24+
- nodes
25+
- nodes/proxy
26+
- services
27+
- endpoints
28+
- pods
29+
verbs: ["get", "list", "watch"]
30+
- apiGroups: ["extensions"]
31+
resources:
32+
- ingresses
33+
verbs: ["get", "list", "watch"]
34+
- nonResourceURLs: ["/metrics"]
35+
verbs: ["get"]
36+
37+
---
38+
# ClusterRoleBinding
39+
apiVersion: rbac.authorization.k8s.io/v1
40+
kind: ClusterRoleBinding
41+
metadata:
42+
name: cwagent-role-binding
43+
subjects:
44+
- kind: ServiceAccount
45+
name: cwagent
46+
namespace: amazon-cloudwatch
47+
roleRef:
48+
kind: ClusterRole
49+
name: cwagent-role
50+
apiGroup: rbac.authorization.k8s.io

internal/deployers/eksapi/templates/templates.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,18 @@ import (
88
//go:embed infra.yaml
99
var Infrastructure string
1010

11+
//go:embed cloudwatch_agent_infra.yaml
12+
var CloudWatchAgentRbac []byte
13+
1114
var (
1215
//go:embed unmanaged-nodegroup.yaml.template
1316
unmanagedNodegroupTemplate string
1417
UnmanagedNodegroup = template.Must(template.New("unmanagedNodegroup").Parse(unmanagedNodegroupTemplate))
1518
)
1619

20+
//go:embed cloudwatch-infra.yaml.template
21+
var CloudWatchInfra string
22+
1723
type NetworkInterface struct {
1824
Description *string
1925
NetworkCardIndex *int

0 commit comments

Comments
 (0)