Skip to content

Commit

Permalink
Migrate CNI Metrics Helper to AWS SDK Go V2.
Browse files Browse the repository at this point in the history
  • Loading branch information
orsenthil committed Nov 22, 2024
1 parent 3c10b23 commit 40e573e
Show file tree
Hide file tree
Showing 23 changed files with 1,526 additions and 1,029 deletions.
20 changes: 10 additions & 10 deletions cmd/cni-metrics-helper/metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import (
"context"
"fmt"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/aws/aws-sdk-go-v2/aws"
cloudwatchtypes "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types"
dto "github.com/prometheus/client_model/go"
"github.com/prometheus/common/expfmt"
"k8s.io/client-go/kubernetes"
Expand Down Expand Up @@ -288,9 +288,9 @@ func produceHistogram(act metricsAction, cw publisher.Publisher) {

prevUpperBound = *bucket.UpperBound
if *bucket.CumulativeCount != 0 {
dataPoint := &cloudwatch.MetricDatum{
dataPoint := cloudwatchtypes.MetricDatum{
MetricName: aws.String(act.cwMetricName),
StatisticValues: &cloudwatch.StatisticSet{
StatisticValues: &cloudwatchtypes.StatisticSet{
Maximum: aws.Float64(mid),
Minimum: aws.Float64(mid),
SampleCount: aws.Float64(*bucket.CumulativeCount),
Expand Down Expand Up @@ -322,23 +322,23 @@ func produceCloudWatchMetrics(t metricsTarget, families map[string]*dto.MetricFa
for _, action := range convertMetrics.actions {
switch metricType {
case dto.MetricType_COUNTER:
dataPoint := &cloudwatch.MetricDatum{
dataPoint := cloudwatchtypes.MetricDatum{
MetricName: aws.String(action.cwMetricName),
Unit: aws.String(cloudwatch.StandardUnitCount),
Unit: cloudwatchtypes.StandardUnitCount,
Value: aws.Float64(action.data.curSingleDataPoint),
}
cw.Publish(dataPoint)
case dto.MetricType_GAUGE:
dataPoint := &cloudwatch.MetricDatum{
dataPoint := cloudwatchtypes.MetricDatum{
MetricName: aws.String(action.cwMetricName),
Unit: aws.String(cloudwatch.StandardUnitCount),
Unit: cloudwatchtypes.StandardUnitCount,
Value: aws.Float64(action.data.curSingleDataPoint),
}
cw.Publish(dataPoint)
case dto.MetricType_SUMMARY:
dataPoint := &cloudwatch.MetricDatum{
dataPoint := cloudwatchtypes.MetricDatum{
MetricName: aws.String(action.cwMetricName),
Unit: aws.String(cloudwatch.StandardUnitCount),
Unit: cloudwatchtypes.StandardUnitCount,
Value: aws.Float64(action.data.curSingleDataPoint),
}
cw.Publish(dataPoint)
Expand Down
109 changes: 78 additions & 31 deletions pkg/awsutils/awssession/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,24 @@
package awssession

import (
"context"
"fmt"
"net/http"
"os"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/aws/retry"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/ec2"
"github.com/aws/smithy-go"
smithymiddleware "github.com/aws/smithy-go/middleware"
smithyhttp "github.com/aws/smithy-go/transport/http"

"strconv"
"time"

"github.com/aws/amazon-vpc-cni-k8s/pkg/utils/logger"
"github.com/aws/amazon-vpc-cni-k8s/utils"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/endpoints"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2"
)

// Http client timeout env for sessions
Expand Down Expand Up @@ -59,42 +63,85 @@ func getHTTPTimeout() time.Duration {
}

// New will return an session for service clients
func New() *session.Session {
awsCfg := aws.Config{
MaxRetries: aws.Int(maxRetries),
HTTPClient: &http.Client{
Timeout: getHTTPTimeout(),
},
STSRegionalEndpoint: endpoints.RegionalSTSEndpoint,
func New(ctx context.Context) (aws.Config, error) {
customHTTPClient := &http.Client{
Timeout: getHTTPTimeout()}
optFns := []func(*config.LoadOptions) error{
config.WithHTTPClient(customHTTPClient),
config.WithRetryMaxAttempts(maxRetries),
config.WithRetryer(func() aws.Retryer {
return retry.NewStandard()
}),
injectUserAgent,
}

endpoint := os.Getenv("AWS_EC2_ENDPOINT")

//TODO (senthilx) - The endpoint resolver is using deprecated method, this should be moved to the services.
if endpoint != "" {
customResolver := func(service, region string, optFns ...func(*endpoints.Options)) (endpoints.ResolvedEndpoint, error) {
if service == ec2.EndpointsID {
return endpoints.ResolvedEndpoint{
URL: endpoint,
}, nil
}
return endpoints.DefaultResolver().EndpointFor(service, region, optFns...)
}
awsCfg.EndpointResolver = endpoints.ResolverFunc(customResolver)
optFns = append(optFns, config.WithEndpointResolver(aws.EndpointResolverFunc(
func(service, region string) (aws.Endpoint, error) {
if service == ec2.ServiceID {
return aws.Endpoint{
URL: endpoint,
}, nil
}
// Fall back to default resolution
return aws.Endpoint{}, &aws.EndpointNotFoundError{}
})))

}

sess := session.Must(session.NewSession(&awsCfg))
//injecting session handler info
injectUserAgent(&sess.Handlers)
cfg, err := config.LoadDefaultConfig(ctx, optFns...)

if err != nil {
return aws.Config{}, fmt.Errorf("failed to load AWS config: %w", err)
}

return sess
return cfg, nil
}

// injectUserAgent will inject app specific user-agent into awsSDK
func injectUserAgent(handlers *request.Handlers) {
func injectUserAgent(loadOptions *config.LoadOptions) error {
version := utils.GetEnv(envVpcCniVersion, "")
handlers.Build.PushFrontNamed(request.NamedHandler{
Name: fmt.Sprintf("%s/user-agent", "amazon-vpc-cni-k8s"),
Fn: request.MakeAddToUserAgentHandler(
"amazon-vpc-cni-k8s",
"version/"+version),
userAgent := fmt.Sprintf("amazon-vpc-cni-k8s/version/%s", version)

loadOptions.APIOptions = append(loadOptions.APIOptions, func(stack *smithymiddleware.Stack) error {
return stack.Build.Add(&addUserAgentMiddleware{
userAgent: userAgent,
}, smithymiddleware.After)
})

return nil
}

type addUserAgentMiddleware struct {
userAgent string
}

func (m *addUserAgentMiddleware) HandleBuild(ctx context.Context, in smithymiddleware.BuildInput, next smithymiddleware.BuildHandler) (out smithymiddleware.BuildOutput, metadata smithymiddleware.Metadata, err error) {
// Simply pass through to the next handler in the middleware chain
return next.HandleBuild(ctx, in)
}

func (m *addUserAgentMiddleware) ID() string {
return "AddUserAgent"
}

func (m *addUserAgentMiddleware) HandleFinalize(ctx context.Context, in smithymiddleware.FinalizeInput, next smithymiddleware.FinalizeHandler) (
out smithymiddleware.FinalizeOutput, metadata smithymiddleware.Metadata, err error) {
req, ok := in.Request.(*smithyhttp.Request)
if !ok {
return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown request type %T", in.Request)}
}

userAgent := req.Header.Get("User-Agent")
if userAgent == "" {
userAgent = m.userAgent
} else {
userAgent += " " + m.userAgent
}
req.Header.Set("User-Agent", userAgent)

return next.HandleFinalize(ctx, in)
}
9 changes: 6 additions & 3 deletions pkg/awsutils/awssession/session_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package awssession

import (
"context"
"os"
"testing"
"time"

"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go-v2/service/ec2"
"github.com/stretchr/testify/assert"
)

Expand All @@ -25,13 +26,15 @@ func TestHttpTimeoutWithValueAbove10(t *testing.T) {

func TestAwsEc2EndpointResolver(t *testing.T) {
customEndpoint := "https://ec2.us-west-2.customaws.com"
ctx := context.Background()

os.Setenv("AWS_EC2_ENDPOINT", customEndpoint)
defer os.Unsetenv("AWS_EC2_ENDPOINT")

sess := New()
cfg, err := New(ctx)
assert.NoError(t, err)

resolvedEndpoint, err := sess.Config.EndpointResolver.EndpointFor(ec2.EndpointsID, "")
resolvedEndpoint, err := cfg.EndpointResolver.ResolveEndpoint(ec2.ServiceID, "")
assert.NoError(t, err)
assert.Equal(t, customEndpoint, resolvedEndpoint.URL)
}
Loading

0 comments on commit 40e573e

Please sign in to comment.