diff --git a/servicequotas/lambda_limits.go b/servicequotas/lambda_limits.go new file mode 100644 index 0000000..69b83ad --- /dev/null +++ b/servicequotas/lambda_limits.go @@ -0,0 +1,49 @@ +package servicequotas + +import ( + "github.com/aws/aws-sdk-go/service/lambda" + "github.com/aws/aws-sdk-go/service/lambda/lambdaiface" +) + +var ( + lambdaConcurrentExecutionsLimitName = "lambda_concurrent_executions_limit" + lambdaConcurrentExecutionsLimitDesc = "Measures the maximum number of concurrent executions allowed for an AWS Lambda function." + + lambdaCodeSizeUnzippedLimitBytesName = "lambda_code_size_unzipped_limit_bytes" + lambdaCodeSizeUnzippedLimitBytesDesc = "Measures the maximum size limit (in bytes) for the unzipped AWS Lambda function code." +) + +// LambdaConcurrentExecutionsLimitCheck implements the UsageCheck interface +// for limits for lambda functions +type LambdaConcurrentExecutionsLimitCheck struct { + client lambdaiface.LambdaAPI +} + +// Usage returns the usage and quouta for the lambda concurrent executions and +// lambda code size unzipped limits +func (c *LambdaConcurrentExecutionsLimitCheck) Usage() ([]QuotaUsage, error) { + param := &lambda.GetAccountSettingsInput{} + var usages []QuotaUsage + + output, err := c.client.GetAccountSettings(param) + if err != nil { + return usages, err + } + + usages = []QuotaUsage{ + { + Name: lambdaConcurrentExecutionsLimitName, + Description: lambdaConcurrentExecutionsLimitDesc, + Quota: float64(*output.AccountLimit.ConcurrentExecutions), + Usage: float64(*output.AccountUsage.FunctionCount), + }, + { + Name: lambdaCodeSizeUnzippedLimitBytesName, + Description: lambdaCodeSizeUnzippedLimitBytesDesc, + Quota: float64(*output.AccountLimit.CodeSizeUnzipped), + Usage: float64(*output.AccountUsage.TotalCodeSize), + }, + } + + return usages, err +} diff --git a/servicequotas/lambda_limits_test.go b/servicequotas/lambda_limits_test.go new file mode 100644 index 0000000..5d25598 --- /dev/null +++ b/servicequotas/lambda_limits_test.go @@ -0,0 +1,95 @@ +package servicequotas + +import ( + "errors" + "testing" + + "github.com/aws/aws-sdk-go/service/lambda" + "github.com/aws/aws-sdk-go/service/lambda/lambdaiface" + "github.com/stretchr/testify/assert" +) + +type mockedLambdaClient struct { + lambdaiface.LambdaAPI + Output *lambda.GetAccountSettingsOutput + Err error +} + +func (m *mockedLambdaClient) GetAccountSettings(input *lambda.GetAccountSettingsInput) (*lambda.GetAccountSettingsOutput, error) { + return m.Output, m.Err +} + +func TestLambdaConcurrentExecutionsLimitCheck_Usage(t *testing.T) { + tests := []struct { + name string + client lambdaiface.LambdaAPI + output *lambda.GetAccountSettingsOutput + err error + expectedUsage []QuotaUsage + expectedErr error + }{ + { + name: "success", + client: &mockedLambdaClient{ + Output: &lambda.GetAccountSettingsOutput{ + AccountLimit: &lambda.AccountLimit{ + ConcurrentExecutions: int64p(100), + CodeSizeUnzipped: int64p(1000000), + CodeSizeZipped: int64p(500000), + }, + AccountUsage: &lambda.AccountUsage{ + FunctionCount: int64p(50), + TotalCodeSize: int64p(500000), + }, + }, + Err: nil, + }, + expectedUsage: []QuotaUsage{ + { + Name: "lambda_concurrent_executions_limit", + Description: "Measures the maximum number of concurrent executions allowed for an AWS Lambda function.", + Quota: 100, + Usage: 50, + }, + { + Name: "lambda_code_size_unzipped_limit_bytes", + Description: "Measures the maximum size limit (in bytes) for the unzipped AWS Lambda function code.", + Quota: 1000000, + Usage: 500000, + }, + { + Name: "lambda_code_size_zipped_limit_bytes", + Description: "Measures the maximum size limit (in bytes) for the zipped AWS Lambda function code.", + Quota: 500000, + }, + }, + expectedErr: nil, + }, + { + name: "error", + client: &mockedLambdaClient{ + Output: nil, + Err: errors.New("some error occurred"), + }, + expectedUsage: nil, + expectedErr: errors.New("some error occurred"), + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + c := &LambdaConcurrentExecutionsLimitCheck{ + client: test.client, + } + + usages, err := c.Usage() + + assert.Equal(t, test.expectedErr, err) + assert.Equal(t, test.expectedUsage, usages) + }) + } +} + +func int64p(i int64) *int64 { + return &i +} diff --git a/servicequotas/service_quotas.go b/servicequotas/service_quotas.go index 98fc97f..725a7fd 100644 --- a/servicequotas/service_quotas.go +++ b/servicequotas/service_quotas.go @@ -12,6 +12,7 @@ import ( "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/autoscaling" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/lambda" awsservicequotas "github.com/aws/aws-sdk-go/service/servicequotas" "github.com/aws/aws-sdk-go/service/servicequotas/servicequotasiface" logging "github.com/sirupsen/logrus" @@ -39,6 +40,7 @@ func newUsageChecks(c client.ConfigProvider, cfgs ...*aws.Config) (map[string]Us // all clients that will be used by the usage checks ec2Client := ec2.New(c, cfgs...) autoscalingClient := autoscaling.New(c, cfgs...) + lambdaClient := lambda.New(c, cfgs...) serviceQuotasUsageChecks := map[string]UsageCheck{ "L-0EA8095F": &RulesPerSecurityGroupUsageCheck{ec2Client}, @@ -51,6 +53,7 @@ func newUsageChecks(c client.ConfigProvider, cfgs ...*aws.Config) (map[string]Us otherUsageChecks := []UsageCheck{ &AvailableIpsPerSubnetUsageCheck{ec2Client}, &ASGUsageCheck{autoscalingClient}, + &LambdaConcurrentExecutionsLimitCheck{lambdaClient}, } return serviceQuotasUsageChecks, otherUsageChecks