github.com/jpreese/tflint@v0.19.2-0.20200908152133-b01686250fb6/plugin/server.go (about) 1 package plugin 2 3 import ( 4 hcl "github.com/hashicorp/hcl/v2" 5 "github.com/hashicorp/terraform/configs" 6 client "github.com/terraform-linters/tflint-plugin-sdk/tflint" 7 tfplugin "github.com/terraform-linters/tflint-plugin-sdk/tflint/client" 8 "github.com/terraform-linters/tflint/tflint" 9 "github.com/zclconf/go-cty/cty" 10 ) 11 12 // Server is a RPC server for responding to requests from plugins 13 type Server struct { 14 runner *tflint.Runner 15 sources map[string][]byte 16 } 17 18 // NewServer initializes a RPC server for plugins 19 func NewServer(runner *tflint.Runner, sources map[string][]byte) *Server { 20 return &Server{runner: runner, sources: sources} 21 } 22 23 // Attributes returns corresponding hcl.Attributes 24 func (s *Server) Attributes(req *tfplugin.AttributesRequest, resp *tfplugin.AttributesResponse) error { 25 ret := []*tfplugin.Attribute{} 26 err := s.runner.WalkResourceAttributes(req.Resource, req.AttributeName, func(attr *hcl.Attribute) error { 27 ret = append(ret, &tfplugin.Attribute{ 28 Name: attr.Name, 29 Expr: attr.Expr.Range().SliceBytes(s.sources[attr.Expr.Range().Filename]), 30 ExprRange: attr.Expr.Range(), 31 Range: attr.Range, 32 NameRange: attr.NameRange, 33 }) 34 return nil 35 }) 36 *resp = tfplugin.AttributesResponse{Attributes: ret, Err: err} 37 return nil 38 } 39 40 // Blocks returns corresponding hcl.Blocks 41 func (s *Server) Blocks(req *tfplugin.BlocksRequest, resp *tfplugin.BlocksResponse) error { 42 ret := []*tfplugin.Block{} 43 err := s.runner.WalkResourceBlocks(req.Resource, req.BlockType, func(block *hcl.Block) error { 44 bodyRange := tflint.HCLBodyRange(block.Body, block.DefRange) 45 ret = append(ret, &tfplugin.Block{ 46 Type: block.Type, 47 Labels: block.Labels, 48 Body: bodyRange.SliceBytes(s.runner.File(block.DefRange.Filename).Bytes), 49 BodyRange: bodyRange, 50 DefRange: block.DefRange, 51 TypeRange: block.TypeRange, 52 LabelRanges: block.LabelRanges, 53 }) 54 return nil 55 }) 56 *resp = tfplugin.BlocksResponse{Blocks: ret, Err: err} 57 return nil 58 } 59 60 // Resources returns corresponding configs.Resource as tfplugin.Resource 61 func (s *Server) Resources(req *tfplugin.ResourcesRequest, resp *tfplugin.ResourcesResponse) error { 62 var ret []*tfplugin.Resource 63 err := s.runner.WalkResources(req.Name, func(resource *configs.Resource) error { 64 ret = append(ret, s.encodeResource(resource)) 65 return nil 66 }) 67 *resp = tfplugin.ResourcesResponse{Resources: ret, Err: err} 68 return nil 69 } 70 71 // ModuleCalls returns all configs.ModuleCall as tfplugin.ModuleCall 72 func (s *Server) ModuleCalls(req *tfplugin.ModuleCallsRequest, resp *tfplugin.ModuleCallsResponse) error { 73 ret := []*tfplugin.ModuleCall{} 74 err := s.runner.WalkModuleCalls(func(call *configs.ModuleCall) error { 75 ret = append(ret, s.encodeModuleCall(call)) 76 return nil 77 }) 78 *resp = tfplugin.ModuleCallsResponse{ModuleCalls: ret, Err: err} 79 return nil 80 } 81 82 // Backend returns corresponding configs.Backend as tfplugin.Backend 83 func (s *Server) Backend(req *tfplugin.BackendRequest, resp *tfplugin.BackendResponse) error { 84 backend := s.runner.Backend() 85 if backend == nil { 86 return nil 87 } 88 89 *resp = tfplugin.BackendResponse{ 90 Backend: s.encodeBackend(backend), 91 } 92 93 return nil 94 } 95 96 // EvalExpr returns a value of the evaluated expression 97 func (s *Server) EvalExpr(req *tfplugin.EvalExprRequest, resp *tfplugin.EvalExprResponse) error { 98 expr, diags := tflint.ParseExpression(req.Expr, req.ExprRange.Filename, req.ExprRange.Start) 99 if diags.HasErrors() { 100 return diags 101 } 102 103 val, err := s.runner.EvalExpr(expr, req.Ret, cty.Type{}) 104 if err != nil { 105 if appErr, ok := err.(*tflint.Error); ok { 106 err = client.Error(*appErr) 107 } 108 } 109 *resp = tfplugin.EvalExprResponse{Val: val, Err: err} 110 return nil 111 } 112 113 // EmitIssue reflects a issue to the Runner 114 func (s *Server) EmitIssue(req *tfplugin.EmitIssueRequest, resp *interface{}) error { 115 if req.Expr != nil { 116 expr, diags := tflint.ParseExpression(req.Expr, req.ExprRange.Filename, req.ExprRange.Start) 117 if diags.HasErrors() { 118 return diags 119 } 120 121 s.runner.WithExpressionContext(expr, func() error { 122 s.runner.EmitIssue(req.Rule, req.Message, req.Location) 123 return nil 124 }) 125 } else { 126 s.runner.EmitIssue(req.Rule, req.Message, req.Location) 127 return nil 128 } 129 return nil 130 }