Skip to content

Commit

Permalink
Migrate to aws-sdk-go-v2
Browse files Browse the repository at this point in the history
  • Loading branch information
abicky committed Aug 11, 2024
1 parent 92d7b46 commit f04efa0
Show file tree
Hide file tree
Showing 30 changed files with 923 additions and 33,044 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/CREDITS
/bin
/dist
mocks.go
10 changes: 8 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
NAME := ecsmec
SRCS := $(shell find . -type f -name '*.go' -not -name '*_test.go')
SRCS := $(shell find . -type f -name '*.go' -not -name '*_test.go' -not -path './internal/testing/*')
MOCKS := internal/testing/capacitymock/mocks.go internal/testing/servicemock/mocks.go

all: bin/$(NAME)

Expand All @@ -15,5 +16,10 @@ install:
go install -ldflags "-s -w -X github.com/abicky/ecsmec/cmd.revision=$(shell git rev-parse --short HEAD)"

.PHONY: test
test:
test: $(MOCKS)
go test -v ./...

$(MOCKS): $(SRCS)
go generate ./...
# mockgen doesn't update timestamps if the generated code doesn't change
touch $(MOCKS)
6 changes: 3 additions & 3 deletions cmd/recreateservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"encoding/json"
"strings"

"github.com/aws/aws-sdk-go/service/ecs"
"github.com/aws/aws-sdk-go-v2/service/ecs"
"github.com/spf13/cobra"

"github.com/abicky/ecsmec/internal/service"
Expand Down Expand Up @@ -64,12 +64,12 @@ func recreateService(cmd *cobra.Command, args []string) error {
return newRuntimeError("failed to parse \"overrides\": %w", err)
}

sess, err := newSession()
cfg, err := newConfig()
if err != nil {
return newRuntimeError("failed to initialize a session: %w", err)
}

if err := service.NewService(ecs.New(sess)).Recreate(cluster, serviceName, overrideDef); err != nil {
if err := service.NewService(ecs.NewFromConfig(cfg)).Recreate(cluster, serviceName, overrideDef); err != nil {
return newRuntimeError("failed to recreate the service: %w", err)
}
return nil
Expand Down
77 changes: 42 additions & 35 deletions cmd/reduceclustercapacity.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package cmd

import (
"context"
"errors"
"fmt"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/autoscaling"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/ecs"
"github.com/aws/aws-sdk-go/service/eventbridge"
"github.com/aws/aws-sdk-go/service/sqs"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/autoscaling"
"github.com/aws/aws-sdk-go-v2/service/ec2"
"github.com/aws/aws-sdk-go-v2/service/ecs"
"github.com/aws/aws-sdk-go-v2/service/eventbridge"
eventbridgetypes "github.com/aws/aws-sdk-go-v2/service/eventbridge/types"
"github.com/aws/aws-sdk-go-v2/service/sqs"
sqstypes "github.com/aws/aws-sdk-go-v2/service/sqs/types"
"github.com/spf13/cobra"
"golang.org/x/xerrors"

Expand Down Expand Up @@ -39,7 +42,7 @@ that belong to the auto scaling group or spot fleet request.`,

cmd.Flags().String("cluster", "default", "The name of the target `CLUSTER`")

cmd.Flags().Int64("amount", 0, "The amount of the capacity to reduce (required)")
cmd.Flags().Int32("amount", 0, "The amount of the capacity to reduce (required)")
cmd.MarkFlagRequired("amount")

reduceClusterCapacityCmd = cmd
Expand All @@ -49,7 +52,7 @@ func reduceClusterCapacity(cmd *cobra.Command, args []string) error {
id, _ := reduceClusterCapacityCmd.Flags().GetString("spot-fleet-request-id")
name, _ := reduceClusterCapacityCmd.Flags().GetString("auto-scaling-group-name")
cluster, _ := reduceClusterCapacityCmd.Flags().GetString("cluster")
amount, _ := reduceClusterCapacityCmd.Flags().GetInt64("amount")
amount, _ := reduceClusterCapacityCmd.Flags().GetInt32("amount")

if len(id) == 0 && len(name) == 0 {
return errors.New("\"spot-fleet-request-id\" or \"auto-scaling-group-name\" is required")
Expand All @@ -58,18 +61,18 @@ func reduceClusterCapacity(cmd *cobra.Command, args []string) error {
return errors.New("\"amount\" must be greater than 0")
}

sess, err := newSession()
cfg, err := newConfig()
if err != nil {
return newRuntimeError("failed to initialize a session: %w", err)
}

drainer, err := capacity.NewDrainer(cluster, ecsconst.MaxListableContainerInstances, ecs.New(sess))
drainer, err := capacity.NewDrainer(cluster, ecsconst.MaxListableContainerInstances, ecs.NewFromConfig(cfg))
if err != nil {
return newRuntimeError("failed to initialize a Drainer: %w", err)
}

if len(id) == 0 {
asg, err := capacity.NewAutoScalingGroup(name, autoscaling.New(sess), ec2.New(sess))
asg, err := capacity.NewAutoScalingGroup(name, autoscaling.NewFromConfig(cfg), ec2.NewFromConfig(cfg))
if err != nil {
return newRuntimeError("failed to initialize a AutoScalingGroup: %w", err)
}
Expand All @@ -78,18 +81,18 @@ func reduceClusterCapacity(cmd *cobra.Command, args []string) error {
return newRuntimeError("failed to reduce the cluster capacity: %w", err)
}
} else {
sfr, err := capacity.NewSpotFleetRequest(id, ec2.New(sess))
sfr, err := capacity.NewSpotFleetRequest(id, ec2.NewFromConfig(cfg))
if err != nil {
return newRuntimeError("failed to initialize a SpotFleetRequest: %w", err)
}

sqsSvc := sqs.New(sess)
sqsSvc := sqs.NewFromConfig(cfg)
queueURL, queueArn, err := putSQSQueue(sqsSvc, queueNameForInterruptionWarnings)
if err != nil {
return newRuntimeError("failed to create a queue for interruption warnings: %w", err)
}

eventsSvc := eventbridge.New(sess)
eventsSvc := eventbridge.NewFromConfig(cfg)
targetID := "sqs"
if err := putEventRule(eventsSvc, sqsSvc, ruleNameForInterruptionWarnings, targetID, queueURL, queueArn); err != nil {
return newRuntimeError("failed to create an event rule for interruption warnings: %w", err)
Expand All @@ -110,46 +113,49 @@ func reduceClusterCapacity(cmd *cobra.Command, args []string) error {
return nil
}

func putSQSQueue(svc *sqs.SQS, name string) (string, string, error) {
queue, err := svc.CreateQueue(&sqs.CreateQueueInput{
func putSQSQueue(svc *sqs.Client, name string) (string, string, error) {
ctx := context.TODO()

queue, err := svc.CreateQueue(ctx, &sqs.CreateQueueInput{
QueueName: aws.String(name),
})
if err != nil {
return "", "", xerrors.Errorf("failed to create the SQS queue \"%s\": %w", name, err)
}

attrs, err := svc.GetQueueAttributes(&sqs.GetQueueAttributesInput{
AttributeNames: []*string{
aws.String("QueueArn"),
attrs, err := svc.GetQueueAttributes(ctx, &sqs.GetQueueAttributesInput{
AttributeNames: []sqstypes.QueueAttributeName{
"QueueArn",
},
QueueUrl: queue.QueueUrl,
})
if err != nil {
return "", "", xerrors.Errorf("failed to get queue attributes of the queue \"%s\": %w", name, err)
}

return *queue.QueueUrl, *attrs.Attributes["QueueArn"], nil
return *queue.QueueUrl, attrs.Attributes["QueueArn"], nil
}

func deleteSQSQueue(svc *sqs.SQS, queueURL string) error {
_, err := svc.DeleteQueue(&sqs.DeleteQueueInput{
func deleteSQSQueue(svc *sqs.Client, queueURL string) error {
_, err := svc.DeleteQueue(context.TODO(), &sqs.DeleteQueueInput{
QueueUrl: aws.String(queueURL),
})
return err
}

func putEventRule(eventsSvc *eventbridge.EventBridge, sqsSvc *sqs.SQS, ruleName, targetID, queueURL, queueArn string) error {
rule, err := eventsSvc.PutRule(&eventbridge.PutRuleInput{
func putEventRule(eventsSvc *eventbridge.Client, sqsSvc *sqs.Client, ruleName, targetID, queueURL, queueArn string) error {
ctx := context.TODO()
rule, err := eventsSvc.PutRule(ctx, &eventbridge.PutRuleInput{
EventPattern: aws.String("{\"detail-type\":[\"EC2 Spot Instance Interruption Warning\"],\"source\":[\"aws.ec2\"]}"),
Name: aws.String(ruleName),
})
if err != nil {
return xerrors.Errorf("failed to create a rule for interruption warnings: %w", err)
}

_, err = sqsSvc.SetQueueAttributes(&sqs.SetQueueAttributesInput{
Attributes: map[string]*string{
"Policy": aws.String(fmt.Sprintf(`{
_, err = sqsSvc.SetQueueAttributes(ctx, &sqs.SetQueueAttributesInput{
Attributes: map[string]string{
"Policy": fmt.Sprintf(`{
"Version": "2012-10-17",
"Statement": [
{
Expand All @@ -166,17 +172,17 @@ func putEventRule(eventsSvc *eventbridge.EventBridge, sqsSvc *sqs.SQS, ruleName,
}
}
]
}`, queueArn, *rule.RuleArn)),
}`, queueArn, *rule.RuleArn),
},
QueueUrl: aws.String(queueURL),
})
if err != nil {
return xerrors.Errorf("failed to update the queue access policy for interruption warnings: %w", err)
}

_, err = eventsSvc.PutTargets(&eventbridge.PutTargetsInput{
_, err = eventsSvc.PutTargets(ctx, &eventbridge.PutTargetsInput{
Rule: aws.String(ruleName),
Targets: []*eventbridge.Target{
Targets: []eventbridgetypes.Target{
{
Id: aws.String(targetID),
Arn: aws.String(queueArn),
Expand All @@ -190,17 +196,18 @@ func putEventRule(eventsSvc *eventbridge.EventBridge, sqsSvc *sqs.SQS, ruleName,
return nil
}

func deleteEventRule(svc *eventbridge.EventBridge, ruleName, targetID string) error {
_, err := svc.RemoveTargets(&eventbridge.RemoveTargetsInput{
Ids: []*string{aws.String(targetID)},
func deleteEventRule(svc *eventbridge.Client, ruleName, targetID string) error {
ctx := context.TODO()
_, err := svc.RemoveTargets(ctx, &eventbridge.RemoveTargetsInput{
Ids: []string{targetID},
Rule: aws.String(ruleName),
})
if err != nil {
return xerrors.Errorf("failed to remove targets of the rule \"%s\": %w", ruleName, err)
}

_, err = svc.DeleteRule(&eventbridge.DeleteRuleInput{
Force: aws.Bool(true),
_, err = svc.DeleteRule(ctx, &eventbridge.DeleteRuleInput{
Force: true,
Name: aws.String(ruleName),
})
return err
Expand Down
16 changes: 8 additions & 8 deletions cmd/replaceautoscalinggroupinstances.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package cmd

import (
"github.com/aws/aws-sdk-go/service/autoscaling"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/ecs"
"github.com/aws/aws-sdk-go-v2/service/autoscaling"
"github.com/aws/aws-sdk-go-v2/service/ec2"
"github.com/aws/aws-sdk-go-v2/service/ecs"
"github.com/spf13/cobra"

"github.com/abicky/ecsmec/internal/capacity"
Expand All @@ -28,27 +28,27 @@ launches new ones.`,

cmd.Flags().String("cluster", "default", "The name of the target `CLUSTER`")

cmd.Flags().Int64("batch-size", ecsconst.MaxListableContainerInstances, "The number of instances drained at a once")
cmd.Flags().Int32("batch-size", ecsconst.MaxListableContainerInstances, "The number of instances drained at a once")

replaceAutoScalingGroupInstancesCmd = cmd
}

func replaceAutoScalingGroupInstances(cmd *cobra.Command, args []string) error {
name, _ := replaceAutoScalingGroupInstancesCmd.Flags().GetString("auto-scaling-group-name")
cluster, _ := replaceAutoScalingGroupInstancesCmd.Flags().GetString("cluster")
batchSize, _ := replaceAutoScalingGroupInstancesCmd.Flags().GetInt64("batch-size")
batchSize, _ := replaceAutoScalingGroupInstancesCmd.Flags().GetInt32("batch-size")

sess, err := newSession()
cfg, err := newConfig()
if err != nil {
return newRuntimeError("failed to initialize a session: %w", err)
}

asg, err := capacity.NewAutoScalingGroup(name, autoscaling.New(sess), ec2.New(sess))
asg, err := capacity.NewAutoScalingGroup(name, autoscaling.NewFromConfig(cfg), ec2.NewFromConfig(cfg))
if err != nil {
return newRuntimeError("failed to initialize a AutoScalingGroup: %w", err)
}

drainer, err := capacity.NewDrainer(cluster, batchSize, ecs.New(sess))
drainer, err := capacity.NewDrainer(cluster, batchSize, ecs.NewFromConfig(cfg))
if err != nil {
return newRuntimeError("failed to initialize a Drainer: %w", err)
}
Expand Down
14 changes: 5 additions & 9 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package cmd

import (
"context"
"fmt"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/spf13/cobra"
"golang.org/x/xerrors"
)
Expand Down Expand Up @@ -62,13 +63,8 @@ func init() {
rootCmd.PersistentFlags().String("region", "", "The AWS region")
}

func newSession() (*session.Session, error) {
func newConfig() (aws.Config, error) {
region, _ := rootCmd.Flags().GetString("region")
profile, _ := rootCmd.Flags().GetString("profile")
return session.NewSessionWithOptions(session.Options{
Config: aws.Config{
Region: aws.String(region),
},
Profile: profile,
})
return config.LoadDefaultConfig(context.Background(), config.WithRegion(region), config.WithSharedConfigProfile(profile))
}
14 changes: 7 additions & 7 deletions cmd/terminatespotfleetinstances.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package cmd

import (
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/ecs"
"github.com/aws/aws-sdk-go-v2/service/ec2"
"github.com/aws/aws-sdk-go-v2/service/ecs"
"github.com/spf13/cobra"

"github.com/abicky/ecsmec/internal/capacity"
Expand All @@ -26,27 +26,27 @@ to the specified spot fleet request.`,

cmd.Flags().String("cluster", "default", "The name of the target `CLUSTER`")

cmd.Flags().Int64("batch-size", ecsconst.MaxListableContainerInstances, "The number of instances drained at a once")
cmd.Flags().Int32("batch-size", ecsconst.MaxListableContainerInstances, "The number of instances drained at a once")

terminateSpotFleetInstancesCmd = cmd
}

func terminateSpotFleetInstances(cmd *cobra.Command, args []string) error {
id, _ := terminateSpotFleetInstancesCmd.Flags().GetString("spot-fleet-request-id")
cluster, _ := terminateSpotFleetInstancesCmd.Flags().GetString("cluster")
batchSize, _ := terminateSpotFleetInstancesCmd.Flags().GetInt64("batch-size")
batchSize, _ := terminateSpotFleetInstancesCmd.Flags().GetInt32("batch-size")

sess, err := newSession()
cfg, err := newConfig()
if err != nil {
return newRuntimeError("failed to initialize a session: %w", err)
}

sfr, err := capacity.NewSpotFleetRequest(id, ec2.New(sess))
sfr, err := capacity.NewSpotFleetRequest(id, ec2.NewFromConfig(cfg))
if err != nil {
return newRuntimeError("failed to initialize a SpotFleetRequest: %w", err)
}

drainer, err := capacity.NewDrainer(cluster, batchSize, ecs.New(sess))
drainer, err := capacity.NewDrainer(cluster, batchSize, ecs.NewFromConfig(cfg))
if err != nil {
return newRuntimeError("failed to initialize a Drainer: %w", err)
}
Expand Down
20 changes: 19 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,31 @@ go 1.22.5

require (
dario.cat/mergo v1.0.0
github.com/aws/aws-sdk-go v1.36.28
github.com/aws/aws-sdk-go-v2 v1.30.3
github.com/aws/aws-sdk-go-v2/config v1.27.27
github.com/aws/aws-sdk-go-v2/service/autoscaling v1.43.3
github.com/aws/aws-sdk-go-v2/service/ec2 v1.174.0
github.com/aws/aws-sdk-go-v2/service/ecs v1.44.3
github.com/aws/aws-sdk-go-v2/service/eventbridge v1.33.3
github.com/aws/aws-sdk-go-v2/service/sqs v1.34.3
github.com/spf13/cobra v1.1.1
go.uber.org/mock v0.4.0
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
)

require (
github.com/aws/aws-sdk-go-v2/credentials v1.17.27 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.15 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect
github.com/aws/smithy-go v1.20.3 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
Expand Down
Loading

0 comments on commit f04efa0

Please sign in to comment.