Skip to content

Commit 103a95a

Browse files
committed
tflint: Add Runner.Config()
1 parent b8bc40c commit 103a95a

File tree

4 files changed

+168
-0
lines changed

4 files changed

+168
-0
lines changed

helper/runner.go

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package helper
22

33
import (
4+
"fmt"
5+
46
"github.com/hashicorp/go-version"
57
"github.com/hashicorp/hcl/v2"
68
"github.com/hashicorp/hcl/v2/gohcl"
79
"github.com/terraform-linters/tflint-plugin-sdk/terraform"
10+
"github.com/terraform-linters/tflint-plugin-sdk/terraform/configs"
811
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
912
"github.com/zclconf/go-cty/cty/gocty"
1013
)
@@ -203,6 +206,74 @@ func (r *Runner) Backend() (*terraform.Backend, error) {
203206
return nil, nil
204207
}
205208

209+
// Config returns the Terraform configuration
210+
func (r *Runner) Config() (*configs.Config, error) {
211+
config := &configs.Config{
212+
Module: &configs.Module{},
213+
}
214+
215+
for _, file := range r.Files {
216+
content, diags := file.Body.Content(configFileSchema)
217+
if diags.HasErrors() {
218+
return nil, diags
219+
}
220+
221+
for _, block := range content.Blocks {
222+
switch block.Type {
223+
case "terraform":
224+
content, diags := block.Body.Content(terraformBlockSchema)
225+
if diags.HasErrors() {
226+
return nil, diags
227+
}
228+
229+
for _, block := range content.Blocks {
230+
switch block.Type {
231+
case "backend":
232+
config.Module.Backend = &terraform.Backend{
233+
Type: block.Labels[0],
234+
TypeRange: block.LabelRanges[0],
235+
Config: block.Body,
236+
DeclRange: block.DefRange,
237+
}
238+
case "required_providers":
239+
// TODO
240+
case "provider_meta":
241+
// TODO
242+
default:
243+
continue
244+
}
245+
}
246+
case "provider":
247+
// TODO
248+
case "variable":
249+
// TODO
250+
case "locals":
251+
// TODO
252+
case "output":
253+
// TODO
254+
case "module":
255+
call, diags := simpleDecodeModuleCallBlock(block)
256+
if diags.HasErrors() {
257+
return nil, diags
258+
}
259+
config.Module.ModuleCalls[call.Name] = call
260+
case "resource":
261+
resource, diags := simpleDecodeResouceBlock(block)
262+
if diags.HasErrors() {
263+
return nil, diags
264+
}
265+
config.Module.ManagedResources[fmt.Sprintf("%s.%s", resource.Type, resource.Name)] = resource
266+
case "data":
267+
// TODO
268+
default:
269+
continue
270+
}
271+
}
272+
}
273+
274+
return nil, nil
275+
}
276+
206277
// EvaluateExpr returns a value of the passed expression.
207278
// Note that there is no evaluation, no type conversion, etc.
208279
func (r *Runner) EvaluateExpr(expr hcl.Expression, ret interface{}) error {
@@ -505,3 +576,65 @@ func decodeProviderConfigRef(expr hcl.Expression) (*terraform.ProviderConfigRef,
505576

506577
return ref, nil
507578
}
579+
580+
// configFileSchema is the schema for the top-level of a config file.
581+
// @see https://github.com/hashicorp/terraform/blob/v0.13.2/configs/parser_config.go#L197-L239
582+
var configFileSchema = &hcl.BodySchema{
583+
Blocks: []hcl.BlockHeaderSchema{
584+
{
585+
Type: "terraform",
586+
},
587+
{
588+
Type: "required_providers",
589+
},
590+
{
591+
Type: "provider",
592+
LabelNames: []string{"name"},
593+
},
594+
{
595+
Type: "variable",
596+
LabelNames: []string{"name"},
597+
},
598+
{
599+
Type: "locals",
600+
},
601+
{
602+
Type: "output",
603+
LabelNames: []string{"name"},
604+
},
605+
{
606+
Type: "module",
607+
LabelNames: []string{"name"},
608+
},
609+
{
610+
Type: "resource",
611+
LabelNames: []string{"type", "name"},
612+
},
613+
{
614+
Type: "data",
615+
LabelNames: []string{"type", "name"},
616+
},
617+
},
618+
}
619+
620+
// terraformBlockSchema is the schema for a top-level "terraform" block in a configuration file.
621+
// @see https://github.com/hashicorp/terraform/blob/v0.13.2/configs/parser_config.go#L241-L261
622+
var terraformBlockSchema = &hcl.BodySchema{
623+
Attributes: []hcl.AttributeSchema{
624+
{Name: "required_version"},
625+
{Name: "experiments"},
626+
},
627+
Blocks: []hcl.BlockHeaderSchema{
628+
{
629+
Type: "backend",
630+
LabelNames: []string{"type"},
631+
},
632+
{
633+
Type: "required_providers",
634+
},
635+
{
636+
Type: "provider_meta",
637+
LabelNames: []string{"provider"},
638+
},
639+
},
640+
}

tflint/client/client.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
hcl "github.com/hashicorp/hcl/v2"
1111
"github.com/terraform-linters/tflint-plugin-sdk/terraform"
12+
"github.com/terraform-linters/tflint-plugin-sdk/terraform/configs"
1213
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
1314
"github.com/zclconf/go-cty/cty/gocty"
1415
)
@@ -150,6 +151,26 @@ func (c *Client) Backend() (*terraform.Backend, error) {
150151
return backend, nil
151152
}
152153

154+
// Config calls the server-side Config method and returns the Terraform configuration.
155+
func (c *Client) Config() (*configs.Config, error) {
156+
log.Print("[DEBUG] Accessing to Config")
157+
158+
var response ConfigResponse
159+
if err := c.rpcClient.Call("Plugin.Config", ConfigRequest{}, &response); err != nil {
160+
return nil, err
161+
}
162+
if response.Err != nil {
163+
return nil, response.Err
164+
}
165+
166+
config, diags := decodeConfig(response.Config)
167+
if diags.HasErrors() {
168+
return nil, diags
169+
}
170+
171+
return config, nil
172+
}
173+
153174
// EvaluateExpr calls the server-side EvalExpr method and reflects the response
154175
// in the passed argument.
155176
func (c *Client) EvaluateExpr(expr hcl.Expression, ret interface{}) error {

tflint/client/rpc.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,15 @@ type ResourcesResponse struct {
5858
Err error
5959
}
6060

61+
// ConfigRequest is a request to the server-side Config method.
62+
type ConfigRequest struct{}
63+
64+
// ConfigResponse is a response to the server-side Config method.
65+
type ConfigResponse struct {
66+
Config *Config
67+
Err error
68+
}
69+
6170
// EvalExprRequest is a request to the server-side EvalExpr method.
6271
type EvalExprRequest struct {
6372
Expr []byte

tflint/interface.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package tflint
33
import (
44
"github.com/hashicorp/hcl/v2"
55
"github.com/terraform-linters/tflint-plugin-sdk/terraform"
6+
"github.com/terraform-linters/tflint-plugin-sdk/terraform/configs"
67
)
78

89
// Runner acts as a client for each plugin to query the host process about the Terraform configurations.
@@ -26,6 +27,10 @@ type Runner interface {
2627
// Backend returns the backend configuration, if any.
2728
Backend() (*terraform.Backend, error)
2829

30+
// Config returns the Terraform configuration.
31+
// This object contains almost all accessible data structures from plugins.
32+
Config() (*configs.Config, error)
33+
2934
// EvaluateExpr evaluates the passed expression and reflects the result in ret.
3035
// Since this function returns an application error, it is expected to use the EnsureNoError
3136
// to determine whether to continue processing.

0 commit comments

Comments
 (0)