Skip to content

Commit

Permalink
aws_lambda_end_of_life (#154)
Browse files Browse the repository at this point in the history
* aws_lambda_end_of_life -  Added lambda End of Life rules

* aws_lambda_end_of_life -  Added end of support

* Updated to have one rule called deprecated_runtime
  • Loading branch information
Rihoj authored Aug 12, 2021
1 parent 8047cf5 commit 20a1464
Show file tree
Hide file tree
Showing 4 changed files with 228 additions and 0 deletions.
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 @@ -34,4 +34,5 @@ var Rules = append([]tflint.Rule{
NewAwsElastiCacheReplicationGroupPreviousTypeRule(),
NewAwsIAMPolicySidInvalidCharactersRule(),
NewAwsIAMPolicyTooLongPolicyRule(),
NewAwsLambdaFunctionDeprecatedRuntimeRule(),
}, models.Rules...)

0 comments on commit 20a1464

Please sign in to comment.