Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

host2plugin: Allow plugins to set host version constraints #202

Merged
merged 1 commit into from
Oct 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/google/go-cmp v0.5.9
github.com/hashicorp/go-hclog v1.3.0
github.com/hashicorp/go-plugin v1.4.5
github.com/hashicorp/go-version v1.6.0
github.com/hashicorp/hcl/v2 v2.14.0
github.com/zclconf/go-cty v1.11.0
golang.org/x/tools v0.1.12
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ github.com/hashicorp/go-hclog v1.3.0 h1:G0ACM8Z2WilWgPv3Vdzwm3V0BQu/kSmrkVtpe1fy
github.com/hashicorp/go-hclog v1.3.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-plugin v1.4.5 h1:oTE/oQR4eghggRg8VY7PAz3dr++VwDNBGCcOfIvHpBo=
github.com/hashicorp/go-plugin v1.4.5/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s=
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/hcl/v2 v2.14.0 h1:jX6+Q38Ly9zaAJlAjnFVyeNSNCKKW8D0wvyg7vij5Wc=
github.com/hashicorp/hcl/v2 v2.14.0/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M=
Expand Down
8 changes: 7 additions & 1 deletion plugin/fromproto/fromproto.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/terraform-linters/tflint-plugin-sdk/hclext"
"github.com/terraform-linters/tflint-plugin-sdk/plugin/proto"
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

Expand Down Expand Up @@ -251,7 +252,12 @@ func Error(err error) error {
return err
}

// If the error status has no details, retrieve an error from the gRPC error status.
// Unimplemented is an unexpected error, so return as-is.
if st.Code() == codes.Unimplemented {
return err
}

// If the error status has no details, return an error from the gRPC error status.
// Remove the status code because some statuses are expected and should not be shown to users.
if len(st.Details()) == 0 {
return errors.New(st.Message())
Expand Down
14 changes: 14 additions & 0 deletions plugin/host2plugin/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"os/exec"

"github.com/hashicorp/go-plugin"
"github.com/hashicorp/go-version"
"github.com/terraform-linters/tflint-plugin-sdk/hclext"
"github.com/terraform-linters/tflint-plugin-sdk/logger"
"github.com/terraform-linters/tflint-plugin-sdk/plugin/fromproto"
Expand Down Expand Up @@ -67,6 +68,19 @@ func (c *GRPCClient) RuleNames() ([]string, error) {
return resp.Names, nil
}

// VersionConstraints returns constraints of TFLint versions.
func (c *GRPCClient) VersionConstraints() (version.Constraints, error) {
resp, err := c.client.GetVersionConstraint(context.Background(), &proto.GetVersionConstraint_Request{})
if err != nil {
return nil, fromproto.Error(err)
}

if resp.Constraint == "" {
return version.Constraints{}, nil
}
return version.NewConstraint(resp.Constraint)
}

// ConfigSchema fetches the config schema from a plugin.
func (c *GRPCClient) ConfigSchema() (*hclext.BodySchema, error) {
resp, err := c.client.GetConfigSchema(context.Background(), &proto.GetConfigSchema_Request{})
Expand Down
62 changes: 62 additions & 0 deletions plugin/host2plugin/host2plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type mockRuleSet struct {

type mockRuleSetImpl struct {
ruleNames func() []string
versionConstraint func() string
configSchema func() *hclext.BodySchema
applyGlobalConfig func(*tflint.Config) error
applyConfig func(*hclext.BodyContent) error
Expand All @@ -50,6 +51,13 @@ func (r *mockRuleSet) RuleNames() []string {
return []string{}
}

func (r *mockRuleSet) VersionConstraint() string {
if r.impl.versionConstraint != nil {
return r.impl.versionConstraint()
}
return ""
}

func (r *mockRuleSet) ConfigSchema() *hclext.BodySchema {
if r.impl.configSchema != nil {
return r.impl.configSchema()
Expand Down Expand Up @@ -192,6 +200,60 @@ func TestRuleNames(t *testing.T) {
}
}

func TestVersionConstraints(t *testing.T) {
// default error check helper
neverHappend := func(err error) bool { return err != nil }

tests := []struct {
Name string
ServerImpl func() string
Want string
ErrCheck func(error) bool
}{
{
Name: "default",
ServerImpl: func() string {
return ""
},
Want: "",
ErrCheck: neverHappend,
},
{
Name: "valid constraint",
ServerImpl: func() string {
return ">= 1.0"
},
Want: ">= 1.0",
ErrCheck: neverHappend,
},
{
Name: "invalid constraint",
ServerImpl: func() string {
return ">> 1.0"
},
Want: "",
ErrCheck: func(err error) bool {
return err == nil || err.Error() != "Malformed constraint: >> 1.0"
},
},
}

for _, test := range tests {
t.Run(test.Name, func(t *testing.T) {
client := startTestGRPCPluginServer(t, newMockRuleSet("test_ruleset", "0.1.0", mockRuleSetImpl{versionConstraint: test.ServerImpl}))

got, err := client.VersionConstraints()
if test.ErrCheck(err) {
t.Fatalf("failed to call VersionConstraints: %s", err)
}

if got.String() != test.Want {
t.Errorf("want: %s, got: %s", test.Want, got)
}
})
}
}

func TestConfigSchema(t *testing.T) {
// default error check helper
neverHappend := func(err error) bool { return err != nil }
Expand Down
5 changes: 5 additions & 0 deletions plugin/host2plugin/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ func (s *GRPCServer) GetRuleNames(ctx context.Context, req *proto.GetRuleNames_R
return &proto.GetRuleNames_Response{Names: s.impl.RuleNames()}, nil
}

// GetVersionConstraint returns a constraint of TFLint versions.
func (s *GRPCServer) GetVersionConstraint(ctx context.Context, req *proto.GetVersionConstraint_Request) (*proto.GetVersionConstraint_Response, error) {
return &proto.GetVersionConstraint_Response{Constraint: s.impl.VersionConstraint()}, nil
}

// GetConfigSchema returns the config schema of the plugin.
func (s *GRPCServer) GetConfigSchema(ctx context.Context, req *proto.GetConfigSchema_Request) (*proto.GetConfigSchema_Response, error) {
return &proto.GetConfigSchema_Response{Schema: toproto.BodySchema(s.impl.ConfigSchema())}, nil
Expand Down
Loading