Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

aws_lambda_end_of_life #154

Merged
merged 5 commits into from
Aug 12, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions docs/rules/aws_lambda_function_deprecated_runtime.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# aws_lambda_function_deprecated_runtime

Checks to see if a lambda function has been set with a runtime that is deprecated. This can show up as either "end of support" or "end of life" depending on the phase of deprecation it is currently in.

## Example

```hcl
resource "aws_lambda_function" "function" {
function_name = "test_function"
role = "test_role"
runtime = "python2.7"
}
```


```
$ tflint
1 issue(s) found:

Error: The "python2.7" runtime has reached the end of support. (aws_lambda_function_deprecated_runtime)

on template.tf line 4:
4: runtime = "python2.7" // end of support reached!

```

## Why

AWS no longer supports these runtimes.

## How To Fix

Update to a newer runtime. Supported runtimes can be found [here](https://docs.aws.amazon.com/lambda/latest/dg/runtime-support-policy.html)
91 changes: 91 additions & 0 deletions rules/aws_lambda_function_deprecated_runtime.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package rules

import (
"fmt"
hcl "github.com/hashicorp/hcl/v2"
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
"github.com/terraform-linters/tflint-ruleset-aws/project"
"time"
)

// AwsLambdaFunctionDeprecatedRuntimeRule checks to see if the lambda runtime has reached End Of Support
type AwsLambdaFunctionDeprecatedRuntimeRule struct {
resourceType string
attributeName string
eosRuntimes map[string]time.Time
eolRuntimes map[string]time.Time
}

// NewAwsLambdaFunctionDeprecatedRuntimeRule returns new rule with default attributes
func NewAwsLambdaFunctionDeprecatedRuntimeRule() *AwsLambdaFunctionDeprecatedRuntimeRule {
return &AwsLambdaFunctionDeprecatedRuntimeRule{
resourceType: "aws_lambda_function",
attributeName: "runtime",
eosRuntimes: map[string]time.Time{
"nodejs10.x": time.Date(2021, time.July, 30, 0, 0, 0, 0, time.UTC),
"ruby2.5": time.Date(2021, time.July, 30, 0, 0, 0, 0, time.UTC),
"python2.7": time.Date(2021, time.July, 15, 0, 0, 0, 0, time.UTC),
"dotnetcore2.1": time.Date(2021, time.September, 20, 0, 0, 0, 0, time.UTC),
},
eolRuntimes: map[string]time.Time{
"dotnetcore1.0": time.Date(2019, time.July, 30, 0, 0, 0, 0, time.UTC),
"dotnetcore2.0": time.Date(2019, time.May, 30, 0, 0, 0, 0, time.UTC),
"nodejs": time.Date(2016, time.October, 31, 0, 0, 0, 0, time.UTC),
"nodejs4.3": time.Date(2020, time.March, 06, 0, 0, 0, 0, time.UTC),
"nodejs4.3-edge": time.Date(2019, time.April, 30, 0, 0, 0, 0, time.UTC),
"nodejs6.10": time.Date(2019, time.August, 12, 0, 0, 0, 0, time.UTC),
"nodejs8.10": time.Date(2020, time.March, 06, 0, 0, 0, 0, time.UTC),
"nodejs10.x": time.Date(2021, time.August, 30, 0, 0, 0, 0, time.UTC),
"ruby2.5": time.Date(2021, time.August, 30, 0, 0, 0, 0, time.UTC),
"python2.7": time.Date(2021, time.September, 30, 0, 0, 0, 0, time.UTC),
"dotnetcore2.1": time.Date(2021, time.October, 30, 0, 0, 0, 0, time.UTC),
},
}
}

// Name returns the rule name
func (r *AwsLambdaFunctionDeprecatedRuntimeRule) Name() string {
return "aws_lambda_function_deprecated_runtime"
}

// Enabled returns whether the rule is enabled by default
func (r *AwsLambdaFunctionDeprecatedRuntimeRule) Enabled() bool {
return true
}

// Severity returns the rule severity
func (r *AwsLambdaFunctionDeprecatedRuntimeRule) Severity() string {
return tflint.WARNING
}

// Link returns the rule reference link
func (r *AwsLambdaFunctionDeprecatedRuntimeRule) Link() string {
return project.ReferenceLink(r.Name())
}

// Check checks if the chosen runtime has reached EOS. Date check allows future values to be created as well.
func (r *AwsLambdaFunctionDeprecatedRuntimeRule) Check(runner tflint.Runner) error {

return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error {
var val string
err := runner.EvaluateExpr(attribute.Expr, &val, nil)
now := time.Now().UTC()

return runner.EnsureNoError(err, func() error {
if _, ok := r.eolRuntimes[val]; ok && now.After(r.eolRuntimes[val]) {
runner.EmitIssueOnExpr(
r,
fmt.Sprintf("The \"%s\" runtime has reached the end of life", val),
attribute.Expr,
)
} else if _, ok := r.eosRuntimes[val]; ok && now.After(r.eosRuntimes[val]) {
runner.EmitIssueOnExpr(
r,
fmt.Sprintf("The \"%s\" runtime has reached the end of support", val),
attribute.Expr,
)
}
return nil
})
})
}
103 changes: 103 additions & 0 deletions rules/aws_lambda_function_deprecated_runtime_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package rules

import (
hcl "github.com/hashicorp/hcl/v2"
"github.com/terraform-linters/tflint-plugin-sdk/helper"
"testing"
"time"
)

func Test_AwsLambdaFunctionEndOfSupport(t *testing.T) {
type caseStudy struct {
Name string
Content string
Expected helper.Issues
}
eosRuntimes := map[string]time.Time{
"nodejs10.x": time.Date(2021, time.July, 30, 0, 0, 0, 0, time.UTC),
"ruby2.5": time.Date(2021, time.July, 30, 0, 0, 0, 0, time.UTC),
"python2.7": time.Date(2021, time.July, 15, 0, 0, 0, 0, time.UTC),
"dotnetcore2.1": time.Date(2021, time.September, 20, 0, 0, 0, 0, time.UTC),
}
var cases []caseStudy
now := time.Now().UTC()
for runtime, eosDate := range eosRuntimes {
if now.Before(eosDate) {
continue
}
study := caseStudy{
Name: runtime + " end of support",
Content: `
resource "aws_lambda_function" "function" {
function_name = "test_function"
role = "test_role"
runtime = "` + runtime + `"
}
`,
Expected: helper.Issues{
{
Rule: NewAwsLambdaFunctionDeprecatedRuntimeRule(),
Message: "The \"" + runtime + "\" runtime has reached the end of support",
Range: hcl.Range{
Filename: "resource.tf",
Start: hcl.Pos{Line: 5, Column: 12},
End: hcl.Pos{Line: 5, Column: len(runtime) + 14},
},
},
},
}
cases = append(cases, study)
}
eolRuntimes := map[string]time.Time{
"dotnetcore1.0": time.Date(2019, time.July, 30, 0, 0, 0, 0, time.UTC),
"dotnetcore2.0": time.Date(2019, time.May, 30, 0, 0, 0, 0, time.UTC),
"nodejs": time.Date(2016, time.October, 31, 0, 0, 0, 0, time.UTC),
"nodejs4.3": time.Date(2020, time.March, 06, 0, 0, 0, 0, time.UTC),
"nodejs4.3-edge": time.Date(2019, time.April, 30, 0, 0, 0, 0, time.UTC),
"nodejs6.10": time.Date(2019, time.August, 12, 0, 0, 0, 0, time.UTC),
"nodejs8.10": time.Date(2020, time.March, 06, 0, 0, 0, 0, time.UTC),
"nodejs10.x": time.Date(2021, time.August, 30, 0, 0, 0, 0, time.UTC),
"ruby2.5": time.Date(2021, time.August, 30, 0, 0, 0, 0, time.UTC),
"python2.7": time.Date(2021, time.September, 30, 0, 0, 0, 0, time.UTC),
"dotnetcore2.1": time.Date(2021, time.October, 30, 0, 0, 0, 0, time.UTC),
}
for runtime, eolDate := range eolRuntimes {
if now.Before(eolDate) {
continue
}
study := caseStudy{
Name: runtime + " end of life",
Content: `
resource "aws_lambda_function" "function" {
function_name = "test_function"
role = "test_role"
runtime = "` + runtime + `"
}
`,
Expected: helper.Issues{
{
Rule: NewAwsLambdaFunctionDeprecatedRuntimeRule(),
Message: "The \"" + runtime + "\" runtime has reached the end of life",
Range: hcl.Range{
Filename: "resource.tf",
Start: hcl.Pos{Line: 5, Column: 12},
End: hcl.Pos{Line: 5, Column: len(runtime) + 14},
},
},
},
}
cases = append(cases, study)
}

rule := NewAwsLambdaFunctionDeprecatedRuntimeRule()

for _, tc := range cases {
runner := helper.TestRunner(t, map[string]string{"resource.tf": tc.Content})

if err := rule.Check(runner); err != nil {
t.Fatalf("Unexpected error occurred: %s", err)
}

helper.AssertIssues(t, tc.Expected, runner.Issues)
}
}
1 change: 1 addition & 0 deletions rules/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,5 @@ var Rules = append([]tflint.Rule{
NewAwsElastiCacheReplicationGroupInvalidTypeRule(),
NewAwsElastiCacheReplicationGroupPreviousTypeRule(),
NewAwsIAMPolicySidInvalidCharactersRule(),
NewAwsLambdaFunctionDeprecatedRuntimeRule(),
}, models.Rules...)