Skip to content

Commit ad5bd7f

Browse files
committed
refactor: aws resource discovery by tags
1 parent 1579493 commit ad5bd7f

3 files changed

Lines changed: 90 additions & 54 deletions

File tree

main.go

Lines changed: 74 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,34 @@ func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyRespo
6262
return events.APIGatewayProxyResponse{StatusCode: http.StatusOK}, nil
6363
}
6464

65-
cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion("us-east-2"))
65+
// parse valid regions from env var
66+
validRegions := strings.Split(os.Getenv("VALID_REGIONS"), ",")
67+
region := "us-east-2"
68+
imageID := ""
69+
instanceType := types.InstanceTypeC7aLarge
70+
instanceTypes := instanceType.Values()
71+
72+
for _, label := range event.GetWorkflowJob().Labels {
73+
// check AMI
74+
if strings.HasPrefix(label, "ami-") {
75+
imageID = label
76+
}
77+
// check region
78+
for _, r := range validRegions {
79+
if label == r {
80+
region = label
81+
break
82+
}
83+
}
84+
// check instance type
85+
for i := range instanceTypes {
86+
if label == string(instanceTypes[i]) {
87+
instanceType = instanceTypes[i]
88+
}
89+
}
90+
}
91+
92+
cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion(region))
6693
if err != nil {
6794
return events.APIGatewayProxyResponse{StatusCode: http.StatusInternalServerError}, err
6895
}
@@ -91,21 +118,58 @@ func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyRespo
91118
extraLabels = "," + extraLabels
92119
}
93120

94-
subnetID := os.Getenv("SUBNET_ID")
95-
if subnetID == "" {
96-
slog.Error("SUBNET_ID env var not set")
121+
// discover subnets by tag
122+
subnetTags := strings.Split(os.Getenv("SUBNET_TAGS"), ",")
123+
124+
filters := []types.Filter{}
125+
for _, tag := range subnetTags {
126+
parts := strings.SplitN(tag, "=", 2)
127+
if len(parts) != 2 {
128+
continue
129+
}
130+
filters = append(filters, types.Filter{
131+
Name: aws.String("tag:" + parts[0]),
132+
Values: []string{parts[1]},
133+
})
134+
}
135+
136+
subnetResult, err := svc.DescribeSubnets(context.TODO(), &ec2.DescribeSubnetsInput{
137+
Filters: filters,
138+
})
139+
if err != nil {
140+
return events.APIGatewayProxyResponse{StatusCode: http.StatusInternalServerError}, err
141+
}
97142

98-
return events.APIGatewayProxyResponse{StatusCode: http.StatusInternalServerError}, errors.New("subnet id missing")
143+
if len(subnetResult.Subnets) == 0 {
144+
return events.APIGatewayProxyResponse{StatusCode: http.StatusInternalServerError},
145+
fmt.Errorf("no subnets found with tags %s in region %s", os.Getenv("SUBNET_TAGS"), region)
99146
}
100147

101-
sgIDs := os.Getenv("SECURITY_GROUP_IDS")
102-
if sgIDs == "" {
103-
slog.Error("SECURITY_GROUP_IDS env var not set")
148+
subnetID := *subnetResult.Subnets[0].SubnetId
149+
150+
// discover security groups by tag
151+
sgTags := strings.Split(os.Getenv("SECURITY_GROUP_TAGS"), ",")
104152

105-
return events.APIGatewayProxyResponse{StatusCode: http.StatusInternalServerError}, errors.New("security groups missing")
153+
filters = []types.Filter{}
154+
for _, tag := range sgTags {
155+
parts := strings.SplitN(tag, "=", 2)
156+
if len(parts) != 2 {
157+
continue
158+
}
159+
filters = append(filters, types.Filter{
160+
Name: aws.String("tag:" + parts[0]),
161+
Values: []string{parts[1]},
162+
})
106163
}
107164

108-
securityGroups := strings.Split(sgIDs, ",")
165+
sgResult, err := svc.DescribeSecurityGroups(context.TODO(), &ec2.DescribeSecurityGroupsInput{
166+
Filters: filters,
167+
})
168+
169+
securityGroups := []string{}
170+
for _, sg := range sgResult.SecurityGroups {
171+
securityGroups = append(securityGroups, *sg.GroupId)
172+
}
109173

110174
keyName := os.Getenv("KEY_NAME")
111175
if keyName == "" {
@@ -121,13 +185,6 @@ func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyRespo
121185
return events.APIGatewayProxyResponse{StatusCode: http.StatusInternalServerError}, errors.New("instance profile arn missing")
122186
}
123187

124-
imageID := os.Getenv("IMAGE_ID")
125-
if imageID == "" {
126-
slog.Error("IMAGE_ID env var not set")
127-
128-
return events.APIGatewayProxyResponse{StatusCode: http.StatusInternalServerError}, errors.New("image id missing")
129-
}
130-
131188
tags := []types.Tag{
132189
{
133190
Key: aws.String("GitHub Workflow Job Event ID"),
@@ -146,19 +203,6 @@ func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyRespo
146203
return events.APIGatewayProxyResponse{StatusCode: http.StatusOK}, nil
147204
}
148205

149-
instanceType := types.InstanceTypeC7aLarge
150-
151-
instanceTypes := instanceType.Values()
152-
for _, label := range event.GetWorkflowJob().Labels {
153-
for i := range instanceTypes {
154-
if label == string(instanceTypes[i]) {
155-
instanceType = instanceTypes[i]
156-
157-
break
158-
}
159-
}
160-
}
161-
162206
slog.Info("creating instance", "instanceType", instanceType)
163207

164208
tpl, err := template.New("userdata").Parse(userData)

samconfig.example.yaml

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,8 @@ dev:
1010
parameter_overrides:
1111
- GitHubPATSecretName=github-runner-autoscaler-pat
1212
- ExtraRunnerLabels=dev
13-
- ImageId=ami-0c0c88099397fccb4
14-
- SubnetId=subnet-0123456789def
15-
- SecurityGroupIds=sg-0123456789def
16-
- KeyName=terraform-2025051802
13+
- SubnetTag=github-runner=true
14+
- SecurityGroupTags=github-runner=true
1715
prod:
1816
deploy:
1917
parameters:
@@ -25,7 +23,5 @@ prod:
2523
parameter_overrides:
2624
- GitHubPATSecretName=github-runner-autoscaler-pat
2725
- ExtraRunnerLabels=prod
28-
- ImageId=ami-0c0c88099397fccb4
29-
- SubnetId=subnet-0123456789def
30-
- SecurityGroupIds=sg-0123456789def
31-
- KeyName=terraform-2025051801
26+
- SubnetTag=github-runner=true
27+
- SecurityGroupTags=github-runner=true

template.yaml

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,15 @@ Parameters:
99
Type: String
1010
Default: ""
1111
Description: Additional comma separated labels for the runner
12-
ImageId:
13-
Type: String
14-
Description: AMI ID for the runner instances
15-
SubnetId:
16-
Type: String
17-
Description: Subnet ID for the runner instances
18-
SecurityGroupIds:
19-
Type: String
20-
Description: Comma separated security group IDs for the runner
21-
KeyName:
22-
Type: String
23-
Description: EC2 key pair name for the runner
12+
ValidRegions:
13+
Type: CommaDelimitedList
14+
Description: List of valid AWS regions for runner deployment.
15+
SubnetTags:
16+
Type: CommaDelimitedList
17+
Description: Comma separated list of tag key-value pairs to discover subnets
18+
SecurityGroupTags:
19+
Type: CommaDelimitedList
20+
Description: Comma separated list of tag key-value pairs to discover security groups
2421

2522
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
2623
Globals:
@@ -81,10 +78,9 @@ Resources:
8178
Variables:
8279
GITHUB_PAT_SECRET_NAME: !Ref GitHubPATSecretName
8380
EXTRA_RUNNER_LABELS: !Ref ExtraRunnerLabels
84-
IMAGE_ID: !Ref ImageId
85-
SUBNET_ID: !Ref SubnetId
86-
SECURITY_GROUP_IDS: !Ref SecurityGroupIds
87-
KEY_NAME: !Ref KeyName
81+
SUBNET_TAGS: !Join [",", !Ref SubnetTags]
82+
SECURITY_GROUP_TAGS: !Join [",", !Ref SecurityGroupTags]
83+
VALID_REGIONS: !Join [",", !Ref ValidRegions]
8884
INSTANCE_PROFILE_ARN: !GetAtt RunnerInstanceProfile.Arn
8985
Policies:
9086
- Statement:

0 commit comments

Comments
 (0)