outputs/requried_output.go (69 lines of code) (raw):
package outputs
import (
"fmt"
"github.com/hashicorp/hcl/v2"
"github.com/terraform-linters/tflint-plugin-sdk/hclext"
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
)
// variableBodySchema is the schema for the variable block that we want to extract from the config.
var outputBodySchema = &hclext.BodySchema{
Blocks: []hclext.BlockSchema{
{
Type: "output",
LabelNames: []string{"name"},
Body: &hclext.BodySchema{},
},
},
}
// Check interface compliance with the tflint.Rule.
var _ tflint.Rule = new(RequiredOutputRule)
// RequiredOutputRule is the struct that represents a rule that
// check for the correct usage of an interface.
type RequiredOutputRule struct {
tflint.DefaultRule
outputName string
link string
ruleName string
}
// NewRequiredOutputRule returns a new rule with the given variable.
func NewRequiredOutputRule(ruleName, requiredOutputName, link string) *RequiredOutputRule {
return &RequiredOutputRule{
ruleName: ruleName,
outputName: requiredOutputName,
link: link,
}
}
// Name returns the rule name.
func (or *RequiredOutputRule) Name() string {
return or.ruleName
}
// Link returns the link to the rule documentation.
func (or *RequiredOutputRule) Link() string {
return or.link
}
// Enabled returns whether the rule is enabled.
func (or *RequiredOutputRule) Enabled() bool {
return true
}
// Severity returns the severity of the rule.
func (or *RequiredOutputRule) Severity() tflint.Severity {
return tflint.ERROR
}
// Check checks whether the module satisfies the interface.
// It will search for a variable with the same name as the interface.
// It will check the type, default value and nullable attributes.
func (vcr *RequiredOutputRule) Check(r tflint.Runner) error {
path, err := r.GetModulePath()
if err != nil {
return err
}
if !path.IsRoot() {
// This rule does not evaluate child modules.
return nil
}
// Define the schema that we want to pull out of the module content.
body, err := r.GetModuleContent(
outputBodySchema,
&tflint.GetModuleContentOption{ExpandMode: tflint.ExpandModeNone})
if err != nil {
return err
}
// Iterate over the outputs and check for the name we are interested in.
for _, b := range body.Blocks {
if b.Labels[0] == vcr.outputName {
return nil
}
}
return r.EmitIssue(
vcr,
fmt.Sprintf("module owners MUST output the `%s` in their modules", vcr.outputName),
hcl.Range{
Filename: "outputs.tf",
},
)
}