providers/aws/lambda.go (188 lines of code) (raw):
// Copyright 2019 The Terraformer Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package aws
import (
"context"
"encoding/json"
"errors"
"github.com/GoogleCloudPlatform/terraformer/terraformutils"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/lambda"
"github.com/aws/smithy-go"
)
var lambdaAllowEmptyValues = []string{"tags."}
type LambdaGenerator struct {
AWSService
}
type Statement struct {
Sid string `json:"Sid"`
}
type Policy struct {
Version string `json:"Version"`
ID string `json:"Id"`
Statement []*Statement `json:"Statement"`
}
func (g *LambdaGenerator) InitResources() error {
config, e := g.generateConfig()
if e != nil {
return e
}
svc := lambda.NewFromConfig(config)
err := g.addFunctions(svc)
if err != nil {
return err
}
err = g.addEventSourceMappings(svc)
if err != nil {
return err
}
err = g.addLayerVersions(svc)
return err
}
func (g *LambdaGenerator) PostConvertHook() error {
for i, r := range g.Resources {
if _, exist := r.Item["environment"]; !exist {
continue
}
variables := g.Resources[i].Item["environment"].([]interface{})[0].(map[string]interface{})["variables"]
g.Resources[i].Item["environment"] = []interface{}{
map[string]interface{}{
"variables": []map[string]interface{}{variables.(map[string]interface{})},
},
}
}
for _, r := range g.Resources {
if r.InstanceInfo.Type != "aws_lambda_function_event_invoke_config" {
continue
}
if r.InstanceState.Attributes["maximum_event_age_in_seconds"] == "0" {
delete(r.Item, "maximum_event_age_in_seconds")
}
}
return nil
}
func (g *LambdaGenerator) addFunctions(svc *lambda.Client) error {
p := lambda.NewListFunctionsPaginator(svc, &lambda.ListFunctionsInput{})
for p.HasMorePages() {
page, err := p.NextPage(context.TODO())
if err != nil {
return err
}
for _, function := range page.Functions {
g.Resources = append(g.Resources, terraformutils.NewResource(
*function.FunctionArn,
*function.FunctionName,
"aws_lambda_function",
"aws",
map[string]string{
"function_name": *function.FunctionName,
},
lambdaAllowEmptyValues,
map[string]interface{}{},
))
gp, err := svc.GetPolicy(context.TODO(), &lambda.GetPolicyInput{
FunctionName: aws.String(*function.FunctionArn),
})
if err != nil {
// skip ResourceNotFoundException, because there may be only inline policy defined
var apiErr smithy.APIError
if !errors.As(err, &apiErr) || apiErr.ErrorCode() != "ResourceNotFoundException" {
return err
}
}
if gp != nil {
outputPolicy := *gp.Policy
var policy Policy
err = json.Unmarshal([]byte(outputPolicy), &policy)
if err != nil {
return err
}
for _, statement := range policy.Statement {
g.Resources = append(g.Resources, terraformutils.NewResource(
statement.Sid,
statement.Sid,
"aws_lambda_permission",
"aws",
map[string]string{
"statement_id": statement.Sid,
"function_name": *function.FunctionArn,
},
lambdaAllowEmptyValues,
map[string]interface{}{},
))
}
}
pi := lambda.NewListFunctionEventInvokeConfigsPaginator(svc,
&lambda.ListFunctionEventInvokeConfigsInput{
FunctionName: function.FunctionName,
})
for pi.HasMorePages() {
piage, err := pi.NextPage(context.TODO())
if err != nil {
return err
}
for _, functionEventInvokeConfig := range piage.FunctionEventInvokeConfigs {
g.Resources = append(g.Resources, terraformutils.NewSimpleResource(
*function.FunctionArn,
"feic_"+*functionEventInvokeConfig.FunctionArn,
"aws_lambda_function_event_invoke_config",
"aws",
lambdaAllowEmptyValues,
))
}
}
}
}
return nil
}
func (g *LambdaGenerator) addEventSourceMappings(svc *lambda.Client) error {
p := lambda.NewListEventSourceMappingsPaginator(svc, &lambda.ListEventSourceMappingsInput{})
for p.HasMorePages() {
page, err := p.NextPage(context.TODO())
if err != nil {
return err
}
for _, mapping := range page.EventSourceMappings {
g.Resources = append(g.Resources, terraformutils.NewResource(
*mapping.UUID,
*mapping.UUID,
"aws_lambda_event_source_mapping",
"aws",
map[string]string{
"event_source_arn": *mapping.EventSourceArn,
"function_name": *mapping.FunctionArn,
},
lambdaAllowEmptyValues,
map[string]interface{}{},
))
}
}
return nil
}
func (g *LambdaGenerator) addLayerVersions(svc *lambda.Client) error {
pl := lambda.NewListLayersPaginator(svc, &lambda.ListLayersInput{})
for pl.HasMorePages() {
plage, err := pl.NextPage(context.TODO())
if err != nil {
return err
}
for _, layer := range plage.Layers {
pv := lambda.NewListLayerVersionsPaginator(svc, &lambda.ListLayerVersionsInput{
LayerName: layer.LayerName,
})
for pv.HasMorePages() {
pvage, err := pv.NextPage(context.TODO())
if err != nil {
return err
}
for _, layerVersion := range pvage.LayerVersions {
g.Resources = append(g.Resources, terraformutils.NewSimpleResource(
*layerVersion.LayerVersionArn,
*layerVersion.LayerVersionArn,
"aws_lambda_layer_version",
"aws",
lambdaAllowEmptyValues,
))
}
}
}
}
return nil
}