in tflint-ruleset-aws-serverless/rules/aws_lambda_event_invoke_config_async_on_failure.go [75:280]
func (r *AwsLambdaEventInvokeConfigAsyncOnFailureRule) Check(runner tflint.Runner) error {
var asyncPerms []AsyncPermission
// Scan permissions
err := runner.WalkResources(r.permissionType, func(resource *configs.Resource) error {
body, _, diags := resource.Config.PartialContent(&hcl.BodySchema{
Attributes: []hcl.AttributeSchema{
{
Name: r.functionName,
},
{
Name: r.principal,
},
},
})
if diags.HasErrors() {
return diags
}
// Get the permission principal
var principalVal string
principal, ok := body.Attributes[r.principal]
if !ok {
runner.EmitIssue(
r,
fmt.Sprintf("\"%s\" is not present.", r.attributeName),
body.MissingItemRange,
)
return nil
}
err := runner.EvaluateExpr(principal.Expr, &principalVal, nil)
if err != nil {
return err
}
// Check if the permission is for a principal that invokes the function asynchronously
isAsync := false
for _, asyncPrincipal := range r.enumPrincipal {
if principalVal == asyncPrincipal {
isAsync = true
break
}
}
// Permission is not async, break early
if !isAsync {
return nil
}
// Get the function name
var functionNameVal string
functionName, ok := body.Attributes[r.functionName]
if !ok {
runner.EmitIssue(
r,
fmt.Sprintf("\"%s\" is not present.", r.attributeName),
body.MissingItemRange,
)
return nil
}
err = runner.EvaluateExpr(functionName.Expr, &functionNameVal, nil)
if err != nil {
return err
}
// Add the function name to the list of async functions
asyncPerms = append(asyncPerms, AsyncPermission{
functionName: functionNameVal,
found: false,
expression: functionName.Expr,
})
return nil
})
if err != nil {
return err
}
// Scan Event Invoke Config
err = runner.WalkResources(r.eventInvokeConfigType, func(resource *configs.Resource) error {
body, _, diags := resource.Config.PartialContent(&hcl.BodySchema{
Attributes: []hcl.AttributeSchema{
{
Name: r.functionName,
},
},
Blocks: []hcl.BlockHeaderSchema{
{
Type: r.block1Name,
},
},
})
if diags.HasErrors() {
return diags
}
// Get the function name
var functionNameVal string
functionName, ok := body.Attributes[r.functionName]
if !ok {
runner.EmitIssue(
r,
fmt.Sprintf("\"%s\" is not present.", r.attributeName),
body.MissingItemRange,
)
return nil
}
err = runner.EvaluateExpr(functionName.Expr, &functionNameVal, nil)
if err != nil {
return err
}
// Check if the function is async
isAsync := false
for pos := range asyncPerms {
if functionNameVal == asyncPerms[pos].functionName {
asyncPerms[pos].found = true
isAsync = true
break
}
}
// Function is not async, break early
if !isAsync {
return nil
}
// Check for block level 1
blocks := body.Blocks.OfType(r.block1Name)
if len(blocks) != 1 {
runner.EmitIssue(
r,
fmt.Sprintf("\"%s\" is not present.", r.block1Name),
body.MissingItemRange,
)
return nil
}
// Check for block level 2
body, _, diags = blocks[0].Body.PartialContent(&hcl.BodySchema{
Blocks: []hcl.BlockHeaderSchema{
{
Type: r.block2Name,
},
},
})
if diags.HasErrors() {
return diags
}
blocks = body.Blocks.OfType(r.block2Name)
if len(blocks) != 1 {
runner.EmitIssue(
r,
fmt.Sprintf("\"%s\" is not present.", r.block2Name),
body.MissingItemRange,
)
return nil
}
// Check for attribute in block
body, _, diags = blocks[0].Body.PartialContent(&hcl.BodySchema{
Attributes: []hcl.AttributeSchema{
{
Name: r.attributeName,
},
},
})
if diags.HasErrors() {
return diags
}
if _, ok = body.Attributes[r.attributeName]; !ok {
runner.EmitIssue(
r,
fmt.Sprintf("\"%s\" is not present.", r.attributeName),
body.MissingItemRange,
)
}
return nil
})
if err != nil {
return err
}
// Scan for missing Event Invoke Config.
for _, asyncPerm := range asyncPerms {
if !asyncPerm.found {
runner.EmitIssueOnExpr(
r,
fmt.Sprintf("missing \"%s\" resource for %s.", r.eventInvokeConfigType, r.functionName),
asyncPerm.expression,
)
}
}
return nil
}