github.com/terraform-linters/tflint-plugin-sdk@v0.22.0/plugin/internal/host2plugin/client.go (about)

     1  package host2plugin
     2  
     3  import (
     4  	"context"
     5  	"os/exec"
     6  
     7  	"github.com/hashicorp/go-plugin"
     8  	"github.com/hashicorp/go-version"
     9  	"github.com/terraform-linters/tflint-plugin-sdk/hclext"
    10  	"github.com/terraform-linters/tflint-plugin-sdk/logger"
    11  	"github.com/terraform-linters/tflint-plugin-sdk/plugin/internal/fromproto"
    12  	"github.com/terraform-linters/tflint-plugin-sdk/plugin/internal/interceptor"
    13  	"github.com/terraform-linters/tflint-plugin-sdk/plugin/internal/plugin2host"
    14  	"github.com/terraform-linters/tflint-plugin-sdk/plugin/internal/proto"
    15  	"github.com/terraform-linters/tflint-plugin-sdk/plugin/internal/toproto"
    16  	"github.com/terraform-linters/tflint-plugin-sdk/tflint"
    17  	"google.golang.org/grpc"
    18  )
    19  
    20  // GRPCClient is a host-side implementation. Host can send requests through the client to plugin's gRPC server.
    21  type GRPCClient struct {
    22  	broker *plugin.GRPCBroker
    23  	client proto.RuleSetClient
    24  }
    25  
    26  // ClientOpts is an option for initializing a Client.
    27  type ClientOpts struct {
    28  	Cmd *exec.Cmd
    29  }
    30  
    31  // NewClient is a wrapper of plugin.NewClient.
    32  func NewClient(opts *ClientOpts) *plugin.Client {
    33  	return plugin.NewClient(&plugin.ClientConfig{
    34  		HandshakeConfig: handshakeConfig,
    35  		Plugins: map[string]plugin.Plugin{
    36  			"ruleset": &RuleSetPlugin{},
    37  		},
    38  		Cmd:              opts.Cmd,
    39  		AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC},
    40  		Logger:           logger.Logger(),
    41  	})
    42  }
    43  
    44  // RuleSetName returns the name of a plugin.
    45  func (c *GRPCClient) RuleSetName() (string, error) {
    46  	resp, err := c.client.GetName(context.Background(), &proto.GetName_Request{})
    47  	if err != nil {
    48  		return "", fromproto.Error(err)
    49  	}
    50  	return resp.Name, nil
    51  }
    52  
    53  // RuleSetVersion returns the version of a plugin.
    54  func (c *GRPCClient) RuleSetVersion() (string, error) {
    55  	resp, err := c.client.GetVersion(context.Background(), &proto.GetVersion_Request{})
    56  	if err != nil {
    57  		return "", fromproto.Error(err)
    58  	}
    59  	return resp.Version, nil
    60  }
    61  
    62  // RuleNames returns the list of rule names provided by a plugin.
    63  func (c *GRPCClient) RuleNames() ([]string, error) {
    64  	resp, err := c.client.GetRuleNames(context.Background(), &proto.GetRuleNames_Request{})
    65  	if err != nil {
    66  		return []string{}, fromproto.Error(err)
    67  	}
    68  	return resp.Names, nil
    69  }
    70  
    71  // VersionConstraints returns constraints of TFLint versions.
    72  func (c *GRPCClient) VersionConstraints() (version.Constraints, error) {
    73  	resp, err := c.client.GetVersionConstraint(context.Background(), &proto.GetVersionConstraint_Request{})
    74  	if err != nil {
    75  		return nil, fromproto.Error(err)
    76  	}
    77  
    78  	if resp.Constraint == "" {
    79  		return version.Constraints{}, nil
    80  	}
    81  	return version.NewConstraint(resp.Constraint)
    82  }
    83  
    84  // SDKVersion returns the SDK version.
    85  func (c *GRPCClient) SDKVersion() (*version.Version, error) {
    86  	resp, err := c.client.GetSDKVersion(context.Background(), &proto.GetSDKVersion_Request{})
    87  	if err != nil {
    88  		return nil, fromproto.Error(err)
    89  	}
    90  	return version.NewVersion(resp.Version)
    91  }
    92  
    93  // ConfigSchema fetches the config schema from a plugin.
    94  func (c *GRPCClient) ConfigSchema() (*hclext.BodySchema, error) {
    95  	resp, err := c.client.GetConfigSchema(context.Background(), &proto.GetConfigSchema_Request{})
    96  	if err != nil {
    97  		return nil, fromproto.Error(err)
    98  	}
    99  	return fromproto.BodySchema(resp.Schema), nil
   100  }
   101  
   102  // ApplyGlobalConfig applies a common config to a plugin.
   103  func (c *GRPCClient) ApplyGlobalConfig(config *tflint.Config) error {
   104  	_, err := c.client.ApplyGlobalConfig(context.Background(), &proto.ApplyGlobalConfig_Request{Config: toproto.Config(config)})
   105  	if err != nil {
   106  		return fromproto.Error(err)
   107  	}
   108  	return nil
   109  }
   110  
   111  // ApplyConfig applies the config to a plugin.
   112  func (c *GRPCClient) ApplyConfig(content *hclext.BodyContent, sources map[string][]byte) error {
   113  	_, err := c.client.ApplyConfig(context.Background(), &proto.ApplyConfig_Request{Content: toproto.BodyContent(content, sources)})
   114  	if err != nil {
   115  		return fromproto.Error(err)
   116  	}
   117  	return nil
   118  }
   119  
   120  // Check calls its own plugin implementation with an gRPC client that can send
   121  // requests to the host process.
   122  func (c *GRPCClient) Check(runner plugin2host.Server) error {
   123  	brokerID := c.broker.NextId()
   124  	logger.Debug("starting host-side gRPC server")
   125  	go c.broker.AcceptAndServe(brokerID, func(opts []grpc.ServerOption) *grpc.Server {
   126  		opts = append(opts, grpc.UnaryInterceptor(interceptor.RequestLogging("plugin2host")))
   127  		server := grpc.NewServer(opts...)
   128  		proto.RegisterRunnerServer(server, &plugin2host.GRPCServer{Impl: runner})
   129  		return server
   130  	})
   131  
   132  	_, err := c.client.Check(context.Background(), &proto.Check_Request{Runner: brokerID})
   133  
   134  	if err != nil {
   135  		return fromproto.Error(err)
   136  	}
   137  	return nil
   138  }