Add support for plugin protocol v6 (#27826)
* Add support for plugin protocol v6 This PR turns on support for plugin protocol v6. A provider can advertise itself as supporting protocol version 6 and terraform will use the correct client. Todo: The "unmanaged" providers functionality does not support protocol version, so at the moment terraform will continue to assume that "unmanaged" providers are on protocol v5. This will require some upstream work on go-plugin (I believe). I would like to convert the builtin providers to use protocol v6 in a future PR; however it is not necessary until we remove protocol v6. * add e2e test for using both plugin protocol versions - copied grpcwrap and made a version that returns protocol v6 provider - copied the test provider, provider-simple, and made a version that's using protocol v6 with the above fun - added an e2etest
This commit is contained in:
parent
1de8216a9e
commit
7b7273e3aa
|
@ -0,0 +1,70 @@
|
||||||
|
package e2etest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/e2e"
|
||||||
|
"github.com/hashicorp/terraform/internal/getproviders"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestProviderProtocols verifies that Terraform can execute provider plugins
|
||||||
|
// with both supported protocol versions.
|
||||||
|
func TestProviderProtocols(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tf := e2e.NewBinary(terraformBin, "testdata/provider-plugin")
|
||||||
|
defer tf.Close()
|
||||||
|
|
||||||
|
// In order to do a decent end-to-end test for this case we will need a real
|
||||||
|
// enough provider plugin to try to run and make sure we are able to
|
||||||
|
// actually run it. Here will build the simple and simple6 (built with
|
||||||
|
// protocol v6) providers.
|
||||||
|
simple6Provider := filepath.Join(tf.WorkDir(), "terraform-provider-simple6")
|
||||||
|
simple6ProviderExe := e2e.GoBuild("github.com/hashicorp/terraform/internal/provider-simple-v6/main", simple6Provider)
|
||||||
|
|
||||||
|
simpleProvider := filepath.Join(tf.WorkDir(), "terraform-provider-simple")
|
||||||
|
simpleProviderExe := e2e.GoBuild("github.com/hashicorp/terraform/internal/provider-simple/main", simpleProvider)
|
||||||
|
|
||||||
|
// Move the provider binaries into a directory that we will point terraform
|
||||||
|
// to using the -plugin-dir cli flag.
|
||||||
|
platform := getproviders.CurrentPlatform.String()
|
||||||
|
hashiDir := "cache/registry.terraform.io/hashicorp/"
|
||||||
|
if err := os.MkdirAll(tf.Path(hashiDir, "simple6/0.0.1/", platform), os.ModePerm); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := os.Rename(simple6ProviderExe, tf.Path(hashiDir, "simple6/0.0.1/", platform, "terraform-provider-simple6")); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.MkdirAll(tf.Path(hashiDir, "simple/0.0.1/", platform), os.ModePerm); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := os.Rename(simpleProviderExe, tf.Path(hashiDir, "simple/0.0.1/", platform, "terraform-provider-simple")); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
//// INIT
|
||||||
|
_, stderr, err := tf.Run("init", "-plugin-dir=cache")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected init error: %s\nstderr:\n%s", err, stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
//// PLAN
|
||||||
|
_, stderr, err = tf.Run("plan", "-out=tfplan")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected plan error: %s\nstderr:\n%s", err, stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
//// APPLY
|
||||||
|
stdout, stderr, err := tf.Run("apply", "tfplan")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected apply error: %s\nstderr:\n%s", err, stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(stdout, "Apply complete! Resources: 2 added, 0 changed, 0 destroyed.") {
|
||||||
|
t.Fatalf("wrong output:\n%s", stdout)
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"github.com/hashicorp/terraform/e2e"
|
"github.com/hashicorp/terraform/e2e"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestProviderDevOverrides is a test that terraform can execute a 3rd party
|
// TestProvisionerPlugin is a test that terraform can execute a 3rd party
|
||||||
// provisioner plugin.
|
// provisioner plugin.
|
||||||
func TestProvisionerPlugin(t *testing.T) {
|
func TestProvisionerPlugin(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
// the provider-plugin tests uses the -plugin-cache flag so terraform pulls the
|
||||||
|
// test binaries instead of reaching out to the registry.
|
||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
simple5 = {
|
||||||
|
source = "registry.terraform.io/hashicorp/simple"
|
||||||
|
}
|
||||||
|
simple6 = {
|
||||||
|
source = "registry.terraform.io/hashicorp/simple6"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "simple_resource" "test-proto5" {
|
||||||
|
provider = simple5
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "simple_resource" "test-proto6" {
|
||||||
|
provider = simple6
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"github.com/hashicorp/terraform/internal/logging"
|
"github.com/hashicorp/terraform/internal/logging"
|
||||||
"github.com/hashicorp/terraform/internal/providercache"
|
"github.com/hashicorp/terraform/internal/providercache"
|
||||||
tfplugin "github.com/hashicorp/terraform/plugin"
|
tfplugin "github.com/hashicorp/terraform/plugin"
|
||||||
|
tfplugin6 "github.com/hashicorp/terraform/plugin6"
|
||||||
"github.com/hashicorp/terraform/providers"
|
"github.com/hashicorp/terraform/providers"
|
||||||
"github.com/hashicorp/terraform/tfdiags"
|
"github.com/hashicorp/terraform/tfdiags"
|
||||||
)
|
)
|
||||||
|
@ -360,10 +361,19 @@ func providerFactory(meta *providercache.CachedProvider) providers.Factory {
|
||||||
}
|
}
|
||||||
|
|
||||||
// store the client so that the plugin can kill the child process
|
// store the client so that the plugin can kill the child process
|
||||||
p := raw.(*tfplugin.GRPCProvider)
|
protoVer := client.NegotiatedVersion()
|
||||||
p.PluginClient = client
|
switch protoVer {
|
||||||
|
case 5:
|
||||||
return p, nil
|
p := raw.(*tfplugin.GRPCProvider)
|
||||||
|
p.PluginClient = client
|
||||||
|
return p, nil
|
||||||
|
case 6:
|
||||||
|
p := raw.(*tfplugin6.GRPCProvider)
|
||||||
|
p.PluginClient = client
|
||||||
|
return p, nil
|
||||||
|
default:
|
||||||
|
panic("unsupported protocol version")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,415 @@
|
||||||
|
package grpcwrap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/internal/tfplugin6"
|
||||||
|
"github.com/hashicorp/terraform/plugin6/convert"
|
||||||
|
"github.com/hashicorp/terraform/providers"
|
||||||
|
"github.com/zclconf/go-cty/cty"
|
||||||
|
ctyjson "github.com/zclconf/go-cty/cty/json"
|
||||||
|
"github.com/zclconf/go-cty/cty/msgpack"
|
||||||
|
)
|
||||||
|
|
||||||
|
// New wraps a providers.Interface to implement a grpc ProviderServer using
|
||||||
|
// plugin protocol v6. This is useful for creating a test binary out of an
|
||||||
|
// internal provider implementation.
|
||||||
|
func Provider6(p providers.Interface) tfplugin6.ProviderServer {
|
||||||
|
return &provider6{
|
||||||
|
provider: p,
|
||||||
|
schema: p.GetProviderSchema(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type provider6 struct {
|
||||||
|
provider providers.Interface
|
||||||
|
schema providers.GetProviderSchemaResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider6) GetProviderSchema(_ context.Context, req *tfplugin6.GetProviderSchema_Request) (*tfplugin6.GetProviderSchema_Response, error) {
|
||||||
|
resp := &tfplugin6.GetProviderSchema_Response{
|
||||||
|
ResourceSchemas: make(map[string]*tfplugin6.Schema),
|
||||||
|
DataSourceSchemas: make(map[string]*tfplugin6.Schema),
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.Provider = &tfplugin6.Schema{
|
||||||
|
Block: &tfplugin6.Schema_Block{},
|
||||||
|
}
|
||||||
|
if p.schema.Provider.Block != nil {
|
||||||
|
resp.Provider.Block = convert.ConfigSchemaToProto(p.schema.Provider.Block)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.ProviderMeta = &tfplugin6.Schema{
|
||||||
|
Block: &tfplugin6.Schema_Block{},
|
||||||
|
}
|
||||||
|
if p.schema.ProviderMeta.Block != nil {
|
||||||
|
resp.ProviderMeta.Block = convert.ConfigSchemaToProto(p.schema.ProviderMeta.Block)
|
||||||
|
}
|
||||||
|
|
||||||
|
for typ, res := range p.schema.ResourceTypes {
|
||||||
|
resp.ResourceSchemas[typ] = &tfplugin6.Schema{
|
||||||
|
Version: res.Version,
|
||||||
|
Block: convert.ConfigSchemaToProto(res.Block),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for typ, dat := range p.schema.DataSources {
|
||||||
|
resp.DataSourceSchemas[typ] = &tfplugin6.Schema{
|
||||||
|
Version: dat.Version,
|
||||||
|
Block: convert.ConfigSchemaToProto(dat.Block),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// include any diagnostics from the original GetSchema call
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, p.schema.Diagnostics)
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider6) ValidateProviderConfig(_ context.Context, req *tfplugin6.ValidateProviderConfig_Request) (*tfplugin6.ValidateProviderConfig_Response, error) {
|
||||||
|
resp := &tfplugin6.ValidateProviderConfig_Response{}
|
||||||
|
ty := p.schema.Provider.Block.ImpliedType()
|
||||||
|
|
||||||
|
configVal, err := decodeDynamicValue6(req.Config, ty)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
prepareResp := p.provider.ValidateProviderConfig(providers.ValidateProviderConfigRequest{
|
||||||
|
Config: configVal,
|
||||||
|
})
|
||||||
|
|
||||||
|
// the PreparedConfig value is no longer used
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, prepareResp.Diagnostics)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider6) ValidateResourceConfig(_ context.Context, req *tfplugin6.ValidateResourceConfig_Request) (*tfplugin6.ValidateResourceConfig_Response, error) {
|
||||||
|
resp := &tfplugin6.ValidateResourceConfig_Response{}
|
||||||
|
ty := p.schema.ResourceTypes[req.TypeName].Block.ImpliedType()
|
||||||
|
|
||||||
|
configVal, err := decodeDynamicValue6(req.Config, ty)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
validateResp := p.provider.ValidateResourceConfig(providers.ValidateResourceConfigRequest{
|
||||||
|
TypeName: req.TypeName,
|
||||||
|
Config: configVal,
|
||||||
|
})
|
||||||
|
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, validateResp.Diagnostics)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider6) ValidateDataSourceConfig(_ context.Context, req *tfplugin6.ValidateDataSourceConfig_Request) (*tfplugin6.ValidateDataSourceConfig_Response, error) {
|
||||||
|
resp := &tfplugin6.ValidateDataSourceConfig_Response{}
|
||||||
|
ty := p.schema.DataSources[req.TypeName].Block.ImpliedType()
|
||||||
|
|
||||||
|
configVal, err := decodeDynamicValue6(req.Config, ty)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
validateResp := p.provider.ValidateDataSourceConfig(providers.ValidateDataSourceConfigRequest{
|
||||||
|
TypeName: req.TypeName,
|
||||||
|
Config: configVal,
|
||||||
|
})
|
||||||
|
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, validateResp.Diagnostics)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider6) UpgradeResourceState(_ context.Context, req *tfplugin6.UpgradeResourceState_Request) (*tfplugin6.UpgradeResourceState_Response, error) {
|
||||||
|
resp := &tfplugin6.UpgradeResourceState_Response{}
|
||||||
|
ty := p.schema.ResourceTypes[req.TypeName].Block.ImpliedType()
|
||||||
|
|
||||||
|
upgradeResp := p.provider.UpgradeResourceState(providers.UpgradeResourceStateRequest{
|
||||||
|
TypeName: req.TypeName,
|
||||||
|
Version: req.Version,
|
||||||
|
RawStateJSON: req.RawState.Json,
|
||||||
|
})
|
||||||
|
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, upgradeResp.Diagnostics)
|
||||||
|
if upgradeResp.Diagnostics.HasErrors() {
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dv, err := encodeDynamicValue6(upgradeResp.UpgradedState, ty)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.UpgradedState = dv
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider6) ConfigureProvider(_ context.Context, req *tfplugin6.ConfigureProvider_Request) (*tfplugin6.ConfigureProvider_Response, error) {
|
||||||
|
resp := &tfplugin6.ConfigureProvider_Response{}
|
||||||
|
ty := p.schema.Provider.Block.ImpliedType()
|
||||||
|
|
||||||
|
configVal, err := decodeDynamicValue6(req.Config, ty)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
configureResp := p.provider.ConfigureProvider(providers.ConfigureProviderRequest{
|
||||||
|
TerraformVersion: req.TerraformVersion,
|
||||||
|
Config: configVal,
|
||||||
|
})
|
||||||
|
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, configureResp.Diagnostics)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider6) ReadResource(_ context.Context, req *tfplugin6.ReadResource_Request) (*tfplugin6.ReadResource_Response, error) {
|
||||||
|
resp := &tfplugin6.ReadResource_Response{}
|
||||||
|
ty := p.schema.ResourceTypes[req.TypeName].Block.ImpliedType()
|
||||||
|
|
||||||
|
stateVal, err := decodeDynamicValue6(req.CurrentState, ty)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
metaTy := p.schema.ProviderMeta.Block.ImpliedType()
|
||||||
|
metaVal, err := decodeDynamicValue6(req.ProviderMeta, metaTy)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
readResp := p.provider.ReadResource(providers.ReadResourceRequest{
|
||||||
|
TypeName: req.TypeName,
|
||||||
|
PriorState: stateVal,
|
||||||
|
Private: req.Private,
|
||||||
|
ProviderMeta: metaVal,
|
||||||
|
})
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, readResp.Diagnostics)
|
||||||
|
if readResp.Diagnostics.HasErrors() {
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
resp.Private = readResp.Private
|
||||||
|
|
||||||
|
dv, err := encodeDynamicValue6(readResp.NewState, ty)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
resp.NewState = dv
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider6) PlanResourceChange(_ context.Context, req *tfplugin6.PlanResourceChange_Request) (*tfplugin6.PlanResourceChange_Response, error) {
|
||||||
|
resp := &tfplugin6.PlanResourceChange_Response{}
|
||||||
|
ty := p.schema.ResourceTypes[req.TypeName].Block.ImpliedType()
|
||||||
|
|
||||||
|
priorStateVal, err := decodeDynamicValue6(req.PriorState, ty)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
proposedStateVal, err := decodeDynamicValue6(req.ProposedNewState, ty)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
configVal, err := decodeDynamicValue6(req.Config, ty)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
metaTy := p.schema.ProviderMeta.Block.ImpliedType()
|
||||||
|
metaVal, err := decodeDynamicValue6(req.ProviderMeta, metaTy)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
planResp := p.provider.PlanResourceChange(providers.PlanResourceChangeRequest{
|
||||||
|
TypeName: req.TypeName,
|
||||||
|
PriorState: priorStateVal,
|
||||||
|
ProposedNewState: proposedStateVal,
|
||||||
|
Config: configVal,
|
||||||
|
PriorPrivate: req.PriorPrivate,
|
||||||
|
ProviderMeta: metaVal,
|
||||||
|
})
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, planResp.Diagnostics)
|
||||||
|
if planResp.Diagnostics.HasErrors() {
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.PlannedPrivate = planResp.PlannedPrivate
|
||||||
|
|
||||||
|
resp.PlannedState, err = encodeDynamicValue6(planResp.PlannedState, ty)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, path := range planResp.RequiresReplace {
|
||||||
|
resp.RequiresReplace = append(resp.RequiresReplace, convert.PathToAttributePath(path))
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider6) ApplyResourceChange(_ context.Context, req *tfplugin6.ApplyResourceChange_Request) (*tfplugin6.ApplyResourceChange_Response, error) {
|
||||||
|
resp := &tfplugin6.ApplyResourceChange_Response{}
|
||||||
|
ty := p.schema.ResourceTypes[req.TypeName].Block.ImpliedType()
|
||||||
|
|
||||||
|
priorStateVal, err := decodeDynamicValue6(req.PriorState, ty)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
plannedStateVal, err := decodeDynamicValue6(req.PlannedState, ty)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
configVal, err := decodeDynamicValue6(req.Config, ty)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
metaTy := p.schema.ProviderMeta.Block.ImpliedType()
|
||||||
|
metaVal, err := decodeDynamicValue6(req.ProviderMeta, metaTy)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
applyResp := p.provider.ApplyResourceChange(providers.ApplyResourceChangeRequest{
|
||||||
|
TypeName: req.TypeName,
|
||||||
|
PriorState: priorStateVal,
|
||||||
|
PlannedState: plannedStateVal,
|
||||||
|
Config: configVal,
|
||||||
|
PlannedPrivate: req.PlannedPrivate,
|
||||||
|
ProviderMeta: metaVal,
|
||||||
|
})
|
||||||
|
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, applyResp.Diagnostics)
|
||||||
|
if applyResp.Diagnostics.HasErrors() {
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
resp.Private = applyResp.Private
|
||||||
|
|
||||||
|
resp.NewState, err = encodeDynamicValue6(applyResp.NewState, ty)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider6) ImportResourceState(_ context.Context, req *tfplugin6.ImportResourceState_Request) (*tfplugin6.ImportResourceState_Response, error) {
|
||||||
|
resp := &tfplugin6.ImportResourceState_Response{}
|
||||||
|
|
||||||
|
importResp := p.provider.ImportResourceState(providers.ImportResourceStateRequest{
|
||||||
|
TypeName: req.TypeName,
|
||||||
|
ID: req.Id,
|
||||||
|
})
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, importResp.Diagnostics)
|
||||||
|
|
||||||
|
for _, res := range importResp.ImportedResources {
|
||||||
|
ty := p.schema.ResourceTypes[res.TypeName].Block.ImpliedType()
|
||||||
|
state, err := encodeDynamicValue6(res.State, ty)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.ImportedResources = append(resp.ImportedResources, &tfplugin6.ImportResourceState_ImportedResource{
|
||||||
|
TypeName: res.TypeName,
|
||||||
|
State: state,
|
||||||
|
Private: res.Private,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider6) ReadDataSource(_ context.Context, req *tfplugin6.ReadDataSource_Request) (*tfplugin6.ReadDataSource_Response, error) {
|
||||||
|
resp := &tfplugin6.ReadDataSource_Response{}
|
||||||
|
ty := p.schema.DataSources[req.TypeName].Block.ImpliedType()
|
||||||
|
|
||||||
|
configVal, err := decodeDynamicValue6(req.Config, ty)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
metaTy := p.schema.ProviderMeta.Block.ImpliedType()
|
||||||
|
metaVal, err := decodeDynamicValue6(req.ProviderMeta, metaTy)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
readResp := p.provider.ReadDataSource(providers.ReadDataSourceRequest{
|
||||||
|
TypeName: req.TypeName,
|
||||||
|
Config: configVal,
|
||||||
|
ProviderMeta: metaVal,
|
||||||
|
})
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, readResp.Diagnostics)
|
||||||
|
if readResp.Diagnostics.HasErrors() {
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.State, err = encodeDynamicValue6(readResp.State, ty)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider6) StopProvider(context.Context, *tfplugin6.StopProvider_Request) (*tfplugin6.StopProvider_Response, error) {
|
||||||
|
resp := &tfplugin6.StopProvider_Response{}
|
||||||
|
err := p.provider.Stop()
|
||||||
|
if err != nil {
|
||||||
|
resp.Error = err.Error()
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// decode a DynamicValue from either the JSON or MsgPack encoding.
|
||||||
|
func decodeDynamicValue6(v *tfplugin6.DynamicValue, ty cty.Type) (cty.Value, error) {
|
||||||
|
// always return a valid value
|
||||||
|
var err error
|
||||||
|
res := cty.NullVal(ty)
|
||||||
|
if v == nil {
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case len(v.Msgpack) > 0:
|
||||||
|
res, err = msgpack.Unmarshal(v.Msgpack, ty)
|
||||||
|
case len(v.Json) > 0:
|
||||||
|
res, err = ctyjson.Unmarshal(v.Json, ty)
|
||||||
|
}
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode a cty.Value into a DynamicValue msgpack payload.
|
||||||
|
func encodeDynamicValue6(v cty.Value, ty cty.Type) (*tfplugin6.DynamicValue, error) {
|
||||||
|
mp, err := msgpack.Marshal(v, ty)
|
||||||
|
return &tfplugin6.DynamicValue{
|
||||||
|
Msgpack: mp,
|
||||||
|
}, err
|
||||||
|
}
|
|
@ -13,7 +13,7 @@ import (
|
||||||
"github.com/hashicorp/terraform/provisioners"
|
"github.com/hashicorp/terraform/provisioners"
|
||||||
)
|
)
|
||||||
|
|
||||||
// New wraps a providers.Interface to implement a grpc ProviderServer.
|
// New wraps a provisioners.Interface to implement a grpc ProviderServer.
|
||||||
// This is useful for creating a test binary out of an internal provider
|
// This is useful for creating a test binary out of an internal provider
|
||||||
// implementation.
|
// implementation.
|
||||||
func Provisioner(p provisioners.Interface) tfplugin5.ProvisionerServer {
|
func Provisioner(p provisioners.Interface) tfplugin5.ProvisionerServer {
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hashicorp/terraform/internal/grpcwrap"
|
||||||
|
simple "github.com/hashicorp/terraform/internal/provider-simple-v6"
|
||||||
|
"github.com/hashicorp/terraform/internal/tfplugin6"
|
||||||
|
plugin "github.com/hashicorp/terraform/plugin6"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
plugin.Serve(&plugin.ServeOpts{
|
||||||
|
GRPCProviderFunc: func() tfplugin6.ProviderServer {
|
||||||
|
return grpcwrap.Provider6(simple.Provider())
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,128 @@
|
||||||
|
// simple provider a minimal provider implementation for testing
|
||||||
|
package simple
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/configs/configschema"
|
||||||
|
"github.com/hashicorp/terraform/providers"
|
||||||
|
"github.com/zclconf/go-cty/cty"
|
||||||
|
ctyjson "github.com/zclconf/go-cty/cty/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
type simple struct {
|
||||||
|
schema providers.GetProviderSchemaResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
func Provider() providers.Interface {
|
||||||
|
simpleResource := providers.Schema{
|
||||||
|
Block: &configschema.Block{
|
||||||
|
Attributes: map[string]*configschema.Attribute{
|
||||||
|
"id": {
|
||||||
|
Computed: true,
|
||||||
|
Type: cty.String,
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
Optional: true,
|
||||||
|
Type: cty.String,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return simple{
|
||||||
|
schema: providers.GetProviderSchemaResponse{
|
||||||
|
Provider: providers.Schema{
|
||||||
|
Block: nil,
|
||||||
|
},
|
||||||
|
ResourceTypes: map[string]providers.Schema{
|
||||||
|
"simple_resource": simpleResource,
|
||||||
|
},
|
||||||
|
DataSources: map[string]providers.Schema{
|
||||||
|
"simple_resource": simpleResource,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s simple) GetProviderSchema() providers.GetProviderSchemaResponse {
|
||||||
|
return s.schema
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s simple) ValidateProviderConfig(req providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) {
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s simple) ValidateResourceConfig(req providers.ValidateResourceConfigRequest) (resp providers.ValidateResourceConfigResponse) {
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s simple) ValidateDataSourceConfig(req providers.ValidateDataSourceConfigRequest) (resp providers.ValidateDataSourceConfigResponse) {
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p simple) UpgradeResourceState(req providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) {
|
||||||
|
ty := p.schema.ResourceTypes[req.TypeName].Block.ImpliedType()
|
||||||
|
val, err := ctyjson.Unmarshal(req.RawStateJSON, ty)
|
||||||
|
resp.Diagnostics = resp.Diagnostics.Append(err)
|
||||||
|
resp.UpgradedState = val
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s simple) ConfigureProvider(providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s simple) Stop() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s simple) ReadResource(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
|
||||||
|
// just return the same state we received
|
||||||
|
resp.NewState = req.PriorState
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s simple) PlanResourceChange(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
|
||||||
|
m := req.ProposedNewState.AsValueMap()
|
||||||
|
_, ok := m["id"]
|
||||||
|
if !ok {
|
||||||
|
m["id"] = cty.UnknownVal(cty.String)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.PlannedState = cty.ObjectVal(m)
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s simple) ApplyResourceChange(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
|
||||||
|
if req.PlannedState.IsNull() {
|
||||||
|
resp.NewState = req.PlannedState
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
m := req.PlannedState.AsValueMap()
|
||||||
|
_, ok := m["id"]
|
||||||
|
if !ok {
|
||||||
|
m["id"] = cty.StringVal(time.Now().String())
|
||||||
|
}
|
||||||
|
resp.NewState = cty.ObjectVal(m)
|
||||||
|
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s simple) ImportResourceState(providers.ImportResourceStateRequest) (resp providers.ImportResourceStateResponse) {
|
||||||
|
resp.Diagnostics = resp.Diagnostics.Append(errors.New("unsupported"))
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s simple) ReadDataSource(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
|
||||||
|
m := req.Config.AsValueMap()
|
||||||
|
m["id"] = cty.StringVal("static_id")
|
||||||
|
resp.State = cty.ObjectVal(m)
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s simple) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -2,11 +2,18 @@ package plugin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/hashicorp/go-plugin"
|
"github.com/hashicorp/go-plugin"
|
||||||
|
"github.com/hashicorp/terraform/plugin6"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// VersionedPlugins includes both protocol 5 and 6 because this is the function
|
||||||
|
// called in providerFactory (command/meta_providers.go) to set up the initial
|
||||||
|
// plugin client config.
|
||||||
var VersionedPlugins = map[int]plugin.PluginSet{
|
var VersionedPlugins = map[int]plugin.PluginSet{
|
||||||
5: {
|
5: {
|
||||||
"provider": &GRPCProviderPlugin{},
|
"provider": &GRPCProviderPlugin{},
|
||||||
"provisioner": &GRPCProvisionerPlugin{},
|
"provisioner": &GRPCProvisionerPlugin{},
|
||||||
},
|
},
|
||||||
|
6: {
|
||||||
|
"provider": &plugin6.GRPCProviderPlugin{},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ func (p *GRPCProviderPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Serve
|
||||||
|
|
||||||
// GRPCProvider handles the client, or core side of the plugin rpc connection.
|
// GRPCProvider handles the client, or core side of the plugin rpc connection.
|
||||||
// The GRPCProvider methods are mostly a translation layer between the
|
// The GRPCProvider methods are mostly a translation layer between the
|
||||||
// terraform provioders types and the grpc proto types, directly converting
|
// terraform providers types and the grpc proto types, directly converting
|
||||||
// between the two.
|
// between the two.
|
||||||
type GRPCProvider struct {
|
type GRPCProvider struct {
|
||||||
// PluginClient provides a reference to the plugin.Client which controls the plugin process.
|
// PluginClient provides a reference to the plugin.Client which controls the plugin process.
|
||||||
|
@ -72,10 +72,10 @@ func New(client proto6.ProviderClient, ctx context.Context) GRPCProvider {
|
||||||
|
|
||||||
// getSchema is used internally to get the saved provider schema. The schema
|
// getSchema is used internally to get the saved provider schema. The schema
|
||||||
// should have already been fetched from the provider, but we have to
|
// should have already been fetched from the provider, but we have to
|
||||||
// synchronize access to avoid being called concurrently with GetSchema.
|
// synchronize access to avoid being called concurrently with GetProviderSchema.
|
||||||
func (p *GRPCProvider) getSchema() providers.GetProviderSchemaResponse {
|
func (p *GRPCProvider) getSchema() providers.GetProviderSchemaResponse {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
// unlock inline in case GetSchema needs to be called
|
// unlock inline in case GetProviderSchema needs to be called
|
||||||
if p.schemas.Provider.Block != nil {
|
if p.schemas.Provider.Block != nil {
|
||||||
p.mu.Unlock()
|
p.mu.Unlock()
|
||||||
return p.schemas
|
return p.schemas
|
||||||
|
@ -85,7 +85,7 @@ func (p *GRPCProvider) getSchema() providers.GetProviderSchemaResponse {
|
||||||
// the schema should have been fetched already, but give it another shot
|
// the schema should have been fetched already, but give it another shot
|
||||||
// just in case things are being called out of order. This may happen for
|
// just in case things are being called out of order. This may happen for
|
||||||
// tests.
|
// tests.
|
||||||
schemas := p.GetSchema()
|
schemas := p.GetProviderSchema()
|
||||||
if schemas.Diagnostics.HasErrors() {
|
if schemas.Diagnostics.HasErrors() {
|
||||||
panic(schemas.Diagnostics.Err())
|
panic(schemas.Diagnostics.Err())
|
||||||
}
|
}
|
||||||
|
@ -122,8 +122,8 @@ func (p *GRPCProvider) getProviderMetaSchema() providers.Schema {
|
||||||
return schema.ProviderMeta
|
return schema.ProviderMeta
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *GRPCProvider) GetSchema() (resp providers.GetProviderSchemaResponse) {
|
func (p *GRPCProvider) GetProviderSchema() (resp providers.GetProviderSchemaResponse) {
|
||||||
logger.Trace("GRPCProvider.v6: GetSchema")
|
logger.Trace("GRPCProvider.v6: GetProviderSchema")
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
@ -286,8 +286,8 @@ func (p *GRPCProvider) UpgradeResourceState(r providers.UpgradeResourceStateRequ
|
||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *GRPCProvider) Configure(r providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
|
func (p *GRPCProvider) ConfigureProvider(r providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
|
||||||
logger.Trace("GRPCProvider.v6: Configure")
|
logger.Trace("GRPCProvider.v6: ConfigureProvider")
|
||||||
|
|
||||||
schema := p.getSchema()
|
schema := p.getSchema()
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,722 @@
|
||||||
|
package plugin6
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"github.com/google/go-cmp/cmp/cmpopts"
|
||||||
|
"github.com/hashicorp/terraform/configs/hcl2shim"
|
||||||
|
"github.com/hashicorp/terraform/providers"
|
||||||
|
"github.com/hashicorp/terraform/tfdiags"
|
||||||
|
"github.com/zclconf/go-cty/cty"
|
||||||
|
|
||||||
|
proto "github.com/hashicorp/terraform/internal/tfplugin6"
|
||||||
|
mockproto "github.com/hashicorp/terraform/plugin6/mock_proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ providers.Interface = (*GRPCProvider)(nil)
|
||||||
|
|
||||||
|
var (
|
||||||
|
equateEmpty = cmpopts.EquateEmpty()
|
||||||
|
typeComparer = cmp.Comparer(cty.Type.Equals)
|
||||||
|
valueComparer = cmp.Comparer(cty.Value.RawEquals)
|
||||||
|
)
|
||||||
|
|
||||||
|
func mockProviderClient(t *testing.T) *mockproto.MockProviderClient {
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
client := mockproto.NewMockProviderClient(ctrl)
|
||||||
|
|
||||||
|
// we always need a GetSchema method
|
||||||
|
client.EXPECT().GetProviderSchema(
|
||||||
|
gomock.Any(),
|
||||||
|
gomock.Any(),
|
||||||
|
gomock.Any(),
|
||||||
|
).Return(providerProtoSchema(), nil)
|
||||||
|
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkDiags(t *testing.T, d tfdiags.Diagnostics) {
|
||||||
|
t.Helper()
|
||||||
|
if d.HasErrors() {
|
||||||
|
t.Fatal(d.Err())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func providerProtoSchema() *proto.GetProviderSchema_Response {
|
||||||
|
return &proto.GetProviderSchema_Response{
|
||||||
|
Provider: &proto.Schema{
|
||||||
|
Block: &proto.Schema_Block{
|
||||||
|
Attributes: []*proto.Schema_Attribute{
|
||||||
|
{
|
||||||
|
Name: "attr",
|
||||||
|
Type: []byte(`"string"`),
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ResourceSchemas: map[string]*proto.Schema{
|
||||||
|
"resource": {
|
||||||
|
Version: 1,
|
||||||
|
Block: &proto.Schema_Block{
|
||||||
|
Attributes: []*proto.Schema_Attribute{
|
||||||
|
{
|
||||||
|
Name: "attr",
|
||||||
|
Type: []byte(`"string"`),
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
DataSourceSchemas: map[string]*proto.Schema{
|
||||||
|
"data": {
|
||||||
|
Version: 1,
|
||||||
|
Block: &proto.Schema_Block{
|
||||||
|
Attributes: []*proto.Schema_Attribute{
|
||||||
|
{
|
||||||
|
Name: "attr",
|
||||||
|
Type: []byte(`"string"`),
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGRPCProvider_GetSchema(t *testing.T) {
|
||||||
|
p := &GRPCProvider{
|
||||||
|
client: mockProviderClient(t),
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := p.GetProviderSchema()
|
||||||
|
checkDiags(t, resp.Diagnostics)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGRPCProvider_PrepareProviderConfig(t *testing.T) {
|
||||||
|
client := mockProviderClient(t)
|
||||||
|
p := &GRPCProvider{
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
|
||||||
|
client.EXPECT().ValidateProviderConfig(
|
||||||
|
gomock.Any(),
|
||||||
|
gomock.Any(),
|
||||||
|
).Return(&proto.ValidateProviderConfig_Response{}, nil)
|
||||||
|
|
||||||
|
cfg := hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{"attr": "value"})
|
||||||
|
resp := p.ValidateProviderConfig(providers.ValidateProviderConfigRequest{Config: cfg})
|
||||||
|
checkDiags(t, resp.Diagnostics)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGRPCProvider_ValidateResourceConfig(t *testing.T) {
|
||||||
|
client := mockProviderClient(t)
|
||||||
|
p := &GRPCProvider{
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
|
||||||
|
client.EXPECT().ValidateResourceConfig(
|
||||||
|
gomock.Any(),
|
||||||
|
gomock.Any(),
|
||||||
|
).Return(&proto.ValidateResourceConfig_Response{}, nil)
|
||||||
|
|
||||||
|
cfg := hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{"attr": "value"})
|
||||||
|
resp := p.ValidateResourceConfig(providers.ValidateResourceConfigRequest{
|
||||||
|
TypeName: "resource",
|
||||||
|
Config: cfg,
|
||||||
|
})
|
||||||
|
checkDiags(t, resp.Diagnostics)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGRPCProvider_ValidateDataSourceConfig(t *testing.T) {
|
||||||
|
client := mockProviderClient(t)
|
||||||
|
p := &GRPCProvider{
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
|
||||||
|
client.EXPECT().ValidateDataSourceConfig(
|
||||||
|
gomock.Any(),
|
||||||
|
gomock.Any(),
|
||||||
|
).Return(&proto.ValidateDataSourceConfig_Response{}, nil)
|
||||||
|
|
||||||
|
cfg := hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{"attr": "value"})
|
||||||
|
resp := p.ValidateDataSourceConfig(providers.ValidateDataSourceConfigRequest{
|
||||||
|
TypeName: "data",
|
||||||
|
Config: cfg,
|
||||||
|
})
|
||||||
|
checkDiags(t, resp.Diagnostics)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGRPCProvider_UpgradeResourceState(t *testing.T) {
|
||||||
|
client := mockProviderClient(t)
|
||||||
|
p := &GRPCProvider{
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
|
||||||
|
client.EXPECT().UpgradeResourceState(
|
||||||
|
gomock.Any(),
|
||||||
|
gomock.Any(),
|
||||||
|
).Return(&proto.UpgradeResourceState_Response{
|
||||||
|
UpgradedState: &proto.DynamicValue{
|
||||||
|
Msgpack: []byte("\x81\xa4attr\xa3bar"),
|
||||||
|
},
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
resp := p.UpgradeResourceState(providers.UpgradeResourceStateRequest{
|
||||||
|
TypeName: "resource",
|
||||||
|
Version: 0,
|
||||||
|
RawStateJSON: []byte(`{"old_attr":"bar"}`),
|
||||||
|
})
|
||||||
|
checkDiags(t, resp.Diagnostics)
|
||||||
|
|
||||||
|
expected := cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("bar"),
|
||||||
|
})
|
||||||
|
|
||||||
|
if !cmp.Equal(expected, resp.UpgradedState, typeComparer, valueComparer, equateEmpty) {
|
||||||
|
t.Fatal(cmp.Diff(expected, resp.UpgradedState, typeComparer, valueComparer, equateEmpty))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGRPCProvider_UpgradeResourceStateJSON(t *testing.T) {
|
||||||
|
client := mockProviderClient(t)
|
||||||
|
p := &GRPCProvider{
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
|
||||||
|
client.EXPECT().UpgradeResourceState(
|
||||||
|
gomock.Any(),
|
||||||
|
gomock.Any(),
|
||||||
|
).Return(&proto.UpgradeResourceState_Response{
|
||||||
|
UpgradedState: &proto.DynamicValue{
|
||||||
|
Json: []byte(`{"attr":"bar"}`),
|
||||||
|
},
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
resp := p.UpgradeResourceState(providers.UpgradeResourceStateRequest{
|
||||||
|
TypeName: "resource",
|
||||||
|
Version: 0,
|
||||||
|
RawStateJSON: []byte(`{"old_attr":"bar"}`),
|
||||||
|
})
|
||||||
|
checkDiags(t, resp.Diagnostics)
|
||||||
|
|
||||||
|
expected := cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("bar"),
|
||||||
|
})
|
||||||
|
|
||||||
|
if !cmp.Equal(expected, resp.UpgradedState, typeComparer, valueComparer, equateEmpty) {
|
||||||
|
t.Fatal(cmp.Diff(expected, resp.UpgradedState, typeComparer, valueComparer, equateEmpty))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGRPCProvider_Configure(t *testing.T) {
|
||||||
|
client := mockProviderClient(t)
|
||||||
|
p := &GRPCProvider{
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
|
||||||
|
client.EXPECT().ConfigureProvider(
|
||||||
|
gomock.Any(),
|
||||||
|
gomock.Any(),
|
||||||
|
).Return(&proto.ConfigureProvider_Response{}, nil)
|
||||||
|
|
||||||
|
resp := p.ConfigureProvider(providers.ConfigureProviderRequest{
|
||||||
|
Config: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("foo"),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
checkDiags(t, resp.Diagnostics)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGRPCProvider_Stop(t *testing.T) {
|
||||||
|
client := mockProviderClient(t)
|
||||||
|
p := &GRPCProvider{
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
|
||||||
|
client.EXPECT().StopProvider(
|
||||||
|
gomock.Any(),
|
||||||
|
gomock.Any(),
|
||||||
|
).Return(&proto.StopProvider_Response{}, nil)
|
||||||
|
|
||||||
|
err := p.Stop()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGRPCProvider_ReadResource(t *testing.T) {
|
||||||
|
client := mockProviderClient(t)
|
||||||
|
p := &GRPCProvider{
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
|
||||||
|
client.EXPECT().ReadResource(
|
||||||
|
gomock.Any(),
|
||||||
|
gomock.Any(),
|
||||||
|
).Return(&proto.ReadResource_Response{
|
||||||
|
NewState: &proto.DynamicValue{
|
||||||
|
Msgpack: []byte("\x81\xa4attr\xa3bar"),
|
||||||
|
},
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
resp := p.ReadResource(providers.ReadResourceRequest{
|
||||||
|
TypeName: "resource",
|
||||||
|
PriorState: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("foo"),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
checkDiags(t, resp.Diagnostics)
|
||||||
|
|
||||||
|
expected := cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("bar"),
|
||||||
|
})
|
||||||
|
|
||||||
|
if !cmp.Equal(expected, resp.NewState, typeComparer, valueComparer, equateEmpty) {
|
||||||
|
t.Fatal(cmp.Diff(expected, resp.NewState, typeComparer, valueComparer, equateEmpty))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGRPCProvider_ReadResourceJSON(t *testing.T) {
|
||||||
|
client := mockProviderClient(t)
|
||||||
|
p := &GRPCProvider{
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
|
||||||
|
client.EXPECT().ReadResource(
|
||||||
|
gomock.Any(),
|
||||||
|
gomock.Any(),
|
||||||
|
).Return(&proto.ReadResource_Response{
|
||||||
|
NewState: &proto.DynamicValue{
|
||||||
|
Json: []byte(`{"attr":"bar"}`),
|
||||||
|
},
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
resp := p.ReadResource(providers.ReadResourceRequest{
|
||||||
|
TypeName: "resource",
|
||||||
|
PriorState: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("foo"),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
checkDiags(t, resp.Diagnostics)
|
||||||
|
|
||||||
|
expected := cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("bar"),
|
||||||
|
})
|
||||||
|
|
||||||
|
if !cmp.Equal(expected, resp.NewState, typeComparer, valueComparer, equateEmpty) {
|
||||||
|
t.Fatal(cmp.Diff(expected, resp.NewState, typeComparer, valueComparer, equateEmpty))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGRPCProvider_ReadEmptyJSON(t *testing.T) {
|
||||||
|
client := mockProviderClient(t)
|
||||||
|
p := &GRPCProvider{
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
|
||||||
|
client.EXPECT().ReadResource(
|
||||||
|
gomock.Any(),
|
||||||
|
gomock.Any(),
|
||||||
|
).Return(&proto.ReadResource_Response{
|
||||||
|
NewState: &proto.DynamicValue{
|
||||||
|
Json: []byte(``),
|
||||||
|
},
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
obj := cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("foo"),
|
||||||
|
})
|
||||||
|
resp := p.ReadResource(providers.ReadResourceRequest{
|
||||||
|
TypeName: "resource",
|
||||||
|
PriorState: obj,
|
||||||
|
})
|
||||||
|
|
||||||
|
checkDiags(t, resp.Diagnostics)
|
||||||
|
|
||||||
|
expected := cty.NullVal(obj.Type())
|
||||||
|
|
||||||
|
if !cmp.Equal(expected, resp.NewState, typeComparer, valueComparer, equateEmpty) {
|
||||||
|
t.Fatal(cmp.Diff(expected, resp.NewState, typeComparer, valueComparer, equateEmpty))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGRPCProvider_PlanResourceChange(t *testing.T) {
|
||||||
|
client := mockProviderClient(t)
|
||||||
|
p := &GRPCProvider{
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedPrivate := []byte(`{"meta": "data"}`)
|
||||||
|
|
||||||
|
client.EXPECT().PlanResourceChange(
|
||||||
|
gomock.Any(),
|
||||||
|
gomock.Any(),
|
||||||
|
).Return(&proto.PlanResourceChange_Response{
|
||||||
|
PlannedState: &proto.DynamicValue{
|
||||||
|
Msgpack: []byte("\x81\xa4attr\xa3bar"),
|
||||||
|
},
|
||||||
|
RequiresReplace: []*proto.AttributePath{
|
||||||
|
{
|
||||||
|
Steps: []*proto.AttributePath_Step{
|
||||||
|
{
|
||||||
|
Selector: &proto.AttributePath_Step_AttributeName{
|
||||||
|
AttributeName: "attr",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PlannedPrivate: expectedPrivate,
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
resp := p.PlanResourceChange(providers.PlanResourceChangeRequest{
|
||||||
|
TypeName: "resource",
|
||||||
|
PriorState: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("foo"),
|
||||||
|
}),
|
||||||
|
ProposedNewState: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("bar"),
|
||||||
|
}),
|
||||||
|
Config: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("bar"),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
checkDiags(t, resp.Diagnostics)
|
||||||
|
|
||||||
|
expectedState := cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("bar"),
|
||||||
|
})
|
||||||
|
|
||||||
|
if !cmp.Equal(expectedState, resp.PlannedState, typeComparer, valueComparer, equateEmpty) {
|
||||||
|
t.Fatal(cmp.Diff(expectedState, resp.PlannedState, typeComparer, valueComparer, equateEmpty))
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedReplace := `[]cty.Path{cty.Path{cty.GetAttrStep{Name:"attr"}}}`
|
||||||
|
replace := fmt.Sprintf("%#v", resp.RequiresReplace)
|
||||||
|
if expectedReplace != replace {
|
||||||
|
t.Fatalf("expected %q, got %q", expectedReplace, replace)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(expectedPrivate, resp.PlannedPrivate) {
|
||||||
|
t.Fatalf("expected %q, got %q", expectedPrivate, resp.PlannedPrivate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGRPCProvider_PlanResourceChangeJSON(t *testing.T) {
|
||||||
|
client := mockProviderClient(t)
|
||||||
|
p := &GRPCProvider{
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedPrivate := []byte(`{"meta": "data"}`)
|
||||||
|
|
||||||
|
client.EXPECT().PlanResourceChange(
|
||||||
|
gomock.Any(),
|
||||||
|
gomock.Any(),
|
||||||
|
).Return(&proto.PlanResourceChange_Response{
|
||||||
|
PlannedState: &proto.DynamicValue{
|
||||||
|
Json: []byte(`{"attr":"bar"}`),
|
||||||
|
},
|
||||||
|
RequiresReplace: []*proto.AttributePath{
|
||||||
|
{
|
||||||
|
Steps: []*proto.AttributePath_Step{
|
||||||
|
{
|
||||||
|
Selector: &proto.AttributePath_Step_AttributeName{
|
||||||
|
AttributeName: "attr",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PlannedPrivate: expectedPrivate,
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
resp := p.PlanResourceChange(providers.PlanResourceChangeRequest{
|
||||||
|
TypeName: "resource",
|
||||||
|
PriorState: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("foo"),
|
||||||
|
}),
|
||||||
|
ProposedNewState: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("bar"),
|
||||||
|
}),
|
||||||
|
Config: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("bar"),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
checkDiags(t, resp.Diagnostics)
|
||||||
|
|
||||||
|
expectedState := cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("bar"),
|
||||||
|
})
|
||||||
|
|
||||||
|
if !cmp.Equal(expectedState, resp.PlannedState, typeComparer, valueComparer, equateEmpty) {
|
||||||
|
t.Fatal(cmp.Diff(expectedState, resp.PlannedState, typeComparer, valueComparer, equateEmpty))
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedReplace := `[]cty.Path{cty.Path{cty.GetAttrStep{Name:"attr"}}}`
|
||||||
|
replace := fmt.Sprintf("%#v", resp.RequiresReplace)
|
||||||
|
if expectedReplace != replace {
|
||||||
|
t.Fatalf("expected %q, got %q", expectedReplace, replace)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(expectedPrivate, resp.PlannedPrivate) {
|
||||||
|
t.Fatalf("expected %q, got %q", expectedPrivate, resp.PlannedPrivate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGRPCProvider_ApplyResourceChange(t *testing.T) {
|
||||||
|
client := mockProviderClient(t)
|
||||||
|
p := &GRPCProvider{
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedPrivate := []byte(`{"meta": "data"}`)
|
||||||
|
|
||||||
|
client.EXPECT().ApplyResourceChange(
|
||||||
|
gomock.Any(),
|
||||||
|
gomock.Any(),
|
||||||
|
).Return(&proto.ApplyResourceChange_Response{
|
||||||
|
NewState: &proto.DynamicValue{
|
||||||
|
Msgpack: []byte("\x81\xa4attr\xa3bar"),
|
||||||
|
},
|
||||||
|
Private: expectedPrivate,
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
resp := p.ApplyResourceChange(providers.ApplyResourceChangeRequest{
|
||||||
|
TypeName: "resource",
|
||||||
|
PriorState: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("foo"),
|
||||||
|
}),
|
||||||
|
PlannedState: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("bar"),
|
||||||
|
}),
|
||||||
|
Config: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("bar"),
|
||||||
|
}),
|
||||||
|
PlannedPrivate: expectedPrivate,
|
||||||
|
})
|
||||||
|
|
||||||
|
checkDiags(t, resp.Diagnostics)
|
||||||
|
|
||||||
|
expectedState := cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("bar"),
|
||||||
|
})
|
||||||
|
|
||||||
|
if !cmp.Equal(expectedState, resp.NewState, typeComparer, valueComparer, equateEmpty) {
|
||||||
|
t.Fatal(cmp.Diff(expectedState, resp.NewState, typeComparer, valueComparer, equateEmpty))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(expectedPrivate, resp.Private) {
|
||||||
|
t.Fatalf("expected %q, got %q", expectedPrivate, resp.Private)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func TestGRPCProvider_ApplyResourceChangeJSON(t *testing.T) {
|
||||||
|
client := mockProviderClient(t)
|
||||||
|
p := &GRPCProvider{
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedPrivate := []byte(`{"meta": "data"}`)
|
||||||
|
|
||||||
|
client.EXPECT().ApplyResourceChange(
|
||||||
|
gomock.Any(),
|
||||||
|
gomock.Any(),
|
||||||
|
).Return(&proto.ApplyResourceChange_Response{
|
||||||
|
NewState: &proto.DynamicValue{
|
||||||
|
Json: []byte(`{"attr":"bar"}`),
|
||||||
|
},
|
||||||
|
Private: expectedPrivate,
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
resp := p.ApplyResourceChange(providers.ApplyResourceChangeRequest{
|
||||||
|
TypeName: "resource",
|
||||||
|
PriorState: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("foo"),
|
||||||
|
}),
|
||||||
|
PlannedState: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("bar"),
|
||||||
|
}),
|
||||||
|
Config: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("bar"),
|
||||||
|
}),
|
||||||
|
PlannedPrivate: expectedPrivate,
|
||||||
|
})
|
||||||
|
|
||||||
|
checkDiags(t, resp.Diagnostics)
|
||||||
|
|
||||||
|
expectedState := cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("bar"),
|
||||||
|
})
|
||||||
|
|
||||||
|
if !cmp.Equal(expectedState, resp.NewState, typeComparer, valueComparer, equateEmpty) {
|
||||||
|
t.Fatal(cmp.Diff(expectedState, resp.NewState, typeComparer, valueComparer, equateEmpty))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(expectedPrivate, resp.Private) {
|
||||||
|
t.Fatalf("expected %q, got %q", expectedPrivate, resp.Private)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGRPCProvider_ImportResourceState(t *testing.T) {
|
||||||
|
client := mockProviderClient(t)
|
||||||
|
p := &GRPCProvider{
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedPrivate := []byte(`{"meta": "data"}`)
|
||||||
|
|
||||||
|
client.EXPECT().ImportResourceState(
|
||||||
|
gomock.Any(),
|
||||||
|
gomock.Any(),
|
||||||
|
).Return(&proto.ImportResourceState_Response{
|
||||||
|
ImportedResources: []*proto.ImportResourceState_ImportedResource{
|
||||||
|
{
|
||||||
|
TypeName: "resource",
|
||||||
|
State: &proto.DynamicValue{
|
||||||
|
Msgpack: []byte("\x81\xa4attr\xa3bar"),
|
||||||
|
},
|
||||||
|
Private: expectedPrivate,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
resp := p.ImportResourceState(providers.ImportResourceStateRequest{
|
||||||
|
TypeName: "resource",
|
||||||
|
ID: "foo",
|
||||||
|
})
|
||||||
|
|
||||||
|
checkDiags(t, resp.Diagnostics)
|
||||||
|
|
||||||
|
expectedResource := providers.ImportedResource{
|
||||||
|
TypeName: "resource",
|
||||||
|
State: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("bar"),
|
||||||
|
}),
|
||||||
|
Private: expectedPrivate,
|
||||||
|
}
|
||||||
|
|
||||||
|
imported := resp.ImportedResources[0]
|
||||||
|
if !cmp.Equal(expectedResource, imported, typeComparer, valueComparer, equateEmpty) {
|
||||||
|
t.Fatal(cmp.Diff(expectedResource, imported, typeComparer, valueComparer, equateEmpty))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func TestGRPCProvider_ImportResourceStateJSON(t *testing.T) {
|
||||||
|
client := mockProviderClient(t)
|
||||||
|
p := &GRPCProvider{
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedPrivate := []byte(`{"meta": "data"}`)
|
||||||
|
|
||||||
|
client.EXPECT().ImportResourceState(
|
||||||
|
gomock.Any(),
|
||||||
|
gomock.Any(),
|
||||||
|
).Return(&proto.ImportResourceState_Response{
|
||||||
|
ImportedResources: []*proto.ImportResourceState_ImportedResource{
|
||||||
|
{
|
||||||
|
TypeName: "resource",
|
||||||
|
State: &proto.DynamicValue{
|
||||||
|
Json: []byte(`{"attr":"bar"}`),
|
||||||
|
},
|
||||||
|
Private: expectedPrivate,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
resp := p.ImportResourceState(providers.ImportResourceStateRequest{
|
||||||
|
TypeName: "resource",
|
||||||
|
ID: "foo",
|
||||||
|
})
|
||||||
|
|
||||||
|
checkDiags(t, resp.Diagnostics)
|
||||||
|
|
||||||
|
expectedResource := providers.ImportedResource{
|
||||||
|
TypeName: "resource",
|
||||||
|
State: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("bar"),
|
||||||
|
}),
|
||||||
|
Private: expectedPrivate,
|
||||||
|
}
|
||||||
|
|
||||||
|
imported := resp.ImportedResources[0]
|
||||||
|
if !cmp.Equal(expectedResource, imported, typeComparer, valueComparer, equateEmpty) {
|
||||||
|
t.Fatal(cmp.Diff(expectedResource, imported, typeComparer, valueComparer, equateEmpty))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGRPCProvider_ReadDataSource(t *testing.T) {
|
||||||
|
client := mockProviderClient(t)
|
||||||
|
p := &GRPCProvider{
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
|
||||||
|
client.EXPECT().ReadDataSource(
|
||||||
|
gomock.Any(),
|
||||||
|
gomock.Any(),
|
||||||
|
).Return(&proto.ReadDataSource_Response{
|
||||||
|
State: &proto.DynamicValue{
|
||||||
|
Msgpack: []byte("\x81\xa4attr\xa3bar"),
|
||||||
|
},
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
resp := p.ReadDataSource(providers.ReadDataSourceRequest{
|
||||||
|
TypeName: "data",
|
||||||
|
Config: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("foo"),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
checkDiags(t, resp.Diagnostics)
|
||||||
|
|
||||||
|
expected := cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("bar"),
|
||||||
|
})
|
||||||
|
|
||||||
|
if !cmp.Equal(expected, resp.State, typeComparer, valueComparer, equateEmpty) {
|
||||||
|
t.Fatal(cmp.Diff(expected, resp.State, typeComparer, valueComparer, equateEmpty))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGRPCProvider_ReadDataSourceJSON(t *testing.T) {
|
||||||
|
client := mockProviderClient(t)
|
||||||
|
p := &GRPCProvider{
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
|
||||||
|
client.EXPECT().ReadDataSource(
|
||||||
|
gomock.Any(),
|
||||||
|
gomock.Any(),
|
||||||
|
).Return(&proto.ReadDataSource_Response{
|
||||||
|
State: &proto.DynamicValue{
|
||||||
|
Json: []byte(`{"attr":"bar"}`),
|
||||||
|
},
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
resp := p.ReadDataSource(providers.ReadDataSourceRequest{
|
||||||
|
TypeName: "data",
|
||||||
|
Config: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("foo"),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
checkDiags(t, resp.Diagnostics)
|
||||||
|
|
||||||
|
expected := cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"attr": cty.StringVal("bar"),
|
||||||
|
})
|
||||||
|
|
||||||
|
if !cmp.Equal(expected, resp.State, typeComparer, valueComparer, equateEmpty) {
|
||||||
|
t.Fatal(cmp.Diff(expected, resp.State, typeComparer, valueComparer, equateEmpty))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
//go:generate go run github.com/golang/mock/mockgen -destination mock.go github.com/hashicorp/terraform/internal/tfplugin6 ProviderClient
|
||||||
|
|
||||||
|
package mock_tfplugin6
|
|
@ -0,0 +1,276 @@
|
||||||
|
// Code generated by MockGen. DO NOT EDIT.
|
||||||
|
// Source: github.com/hashicorp/terraform/internal/tfplugin6 (interfaces: ProviderClient)
|
||||||
|
|
||||||
|
// Package mock_tfplugin6 is a generated GoMock package.
|
||||||
|
package mock_tfplugin6
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
gomock "github.com/golang/mock/gomock"
|
||||||
|
tfplugin6 "github.com/hashicorp/terraform/internal/tfplugin6"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
reflect "reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockProviderClient is a mock of ProviderClient interface
|
||||||
|
type MockProviderClient struct {
|
||||||
|
ctrl *gomock.Controller
|
||||||
|
recorder *MockProviderClientMockRecorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockProviderClientMockRecorder is the mock recorder for MockProviderClient
|
||||||
|
type MockProviderClientMockRecorder struct {
|
||||||
|
mock *MockProviderClient
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMockProviderClient creates a new mock instance
|
||||||
|
func NewMockProviderClient(ctrl *gomock.Controller) *MockProviderClient {
|
||||||
|
mock := &MockProviderClient{ctrl: ctrl}
|
||||||
|
mock.recorder = &MockProviderClientMockRecorder{mock}
|
||||||
|
return mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPECT returns an object that allows the caller to indicate expected use
|
||||||
|
func (m *MockProviderClient) EXPECT() *MockProviderClientMockRecorder {
|
||||||
|
return m.recorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyResourceChange mocks base method
|
||||||
|
func (m *MockProviderClient) ApplyResourceChange(arg0 context.Context, arg1 *tfplugin6.ApplyResourceChange_Request, arg2 ...grpc.CallOption) (*tfplugin6.ApplyResourceChange_Response, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
varargs := []interface{}{arg0, arg1}
|
||||||
|
for _, a := range arg2 {
|
||||||
|
varargs = append(varargs, a)
|
||||||
|
}
|
||||||
|
ret := m.ctrl.Call(m, "ApplyResourceChange", varargs...)
|
||||||
|
ret0, _ := ret[0].(*tfplugin6.ApplyResourceChange_Response)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyResourceChange indicates an expected call of ApplyResourceChange
|
||||||
|
func (mr *MockProviderClientMockRecorder) ApplyResourceChange(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApplyResourceChange", reflect.TypeOf((*MockProviderClient)(nil).ApplyResourceChange), varargs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigureProvider mocks base method
|
||||||
|
func (m *MockProviderClient) ConfigureProvider(arg0 context.Context, arg1 *tfplugin6.ConfigureProvider_Request, arg2 ...grpc.CallOption) (*tfplugin6.ConfigureProvider_Response, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
varargs := []interface{}{arg0, arg1}
|
||||||
|
for _, a := range arg2 {
|
||||||
|
varargs = append(varargs, a)
|
||||||
|
}
|
||||||
|
ret := m.ctrl.Call(m, "ConfigureProvider", varargs...)
|
||||||
|
ret0, _ := ret[0].(*tfplugin6.ConfigureProvider_Response)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigureProvider indicates an expected call of ConfigureProvider
|
||||||
|
func (mr *MockProviderClientMockRecorder) ConfigureProvider(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigureProvider", reflect.TypeOf((*MockProviderClient)(nil).ConfigureProvider), varargs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProviderSchema mocks base method
|
||||||
|
func (m *MockProviderClient) GetProviderSchema(arg0 context.Context, arg1 *tfplugin6.GetProviderSchema_Request, arg2 ...grpc.CallOption) (*tfplugin6.GetProviderSchema_Response, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
varargs := []interface{}{arg0, arg1}
|
||||||
|
for _, a := range arg2 {
|
||||||
|
varargs = append(varargs, a)
|
||||||
|
}
|
||||||
|
ret := m.ctrl.Call(m, "GetProviderSchema", varargs...)
|
||||||
|
ret0, _ := ret[0].(*tfplugin6.GetProviderSchema_Response)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProviderSchema indicates an expected call of GetProviderSchema
|
||||||
|
func (mr *MockProviderClientMockRecorder) GetProviderSchema(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProviderSchema", reflect.TypeOf((*MockProviderClient)(nil).GetProviderSchema), varargs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImportResourceState mocks base method
|
||||||
|
func (m *MockProviderClient) ImportResourceState(arg0 context.Context, arg1 *tfplugin6.ImportResourceState_Request, arg2 ...grpc.CallOption) (*tfplugin6.ImportResourceState_Response, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
varargs := []interface{}{arg0, arg1}
|
||||||
|
for _, a := range arg2 {
|
||||||
|
varargs = append(varargs, a)
|
||||||
|
}
|
||||||
|
ret := m.ctrl.Call(m, "ImportResourceState", varargs...)
|
||||||
|
ret0, _ := ret[0].(*tfplugin6.ImportResourceState_Response)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImportResourceState indicates an expected call of ImportResourceState
|
||||||
|
func (mr *MockProviderClientMockRecorder) ImportResourceState(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ImportResourceState", reflect.TypeOf((*MockProviderClient)(nil).ImportResourceState), varargs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlanResourceChange mocks base method
|
||||||
|
func (m *MockProviderClient) PlanResourceChange(arg0 context.Context, arg1 *tfplugin6.PlanResourceChange_Request, arg2 ...grpc.CallOption) (*tfplugin6.PlanResourceChange_Response, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
varargs := []interface{}{arg0, arg1}
|
||||||
|
for _, a := range arg2 {
|
||||||
|
varargs = append(varargs, a)
|
||||||
|
}
|
||||||
|
ret := m.ctrl.Call(m, "PlanResourceChange", varargs...)
|
||||||
|
ret0, _ := ret[0].(*tfplugin6.PlanResourceChange_Response)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlanResourceChange indicates an expected call of PlanResourceChange
|
||||||
|
func (mr *MockProviderClientMockRecorder) PlanResourceChange(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PlanResourceChange", reflect.TypeOf((*MockProviderClient)(nil).PlanResourceChange), varargs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadDataSource mocks base method
|
||||||
|
func (m *MockProviderClient) ReadDataSource(arg0 context.Context, arg1 *tfplugin6.ReadDataSource_Request, arg2 ...grpc.CallOption) (*tfplugin6.ReadDataSource_Response, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
varargs := []interface{}{arg0, arg1}
|
||||||
|
for _, a := range arg2 {
|
||||||
|
varargs = append(varargs, a)
|
||||||
|
}
|
||||||
|
ret := m.ctrl.Call(m, "ReadDataSource", varargs...)
|
||||||
|
ret0, _ := ret[0].(*tfplugin6.ReadDataSource_Response)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadDataSource indicates an expected call of ReadDataSource
|
||||||
|
func (mr *MockProviderClientMockRecorder) ReadDataSource(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadDataSource", reflect.TypeOf((*MockProviderClient)(nil).ReadDataSource), varargs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadResource mocks base method
|
||||||
|
func (m *MockProviderClient) ReadResource(arg0 context.Context, arg1 *tfplugin6.ReadResource_Request, arg2 ...grpc.CallOption) (*tfplugin6.ReadResource_Response, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
varargs := []interface{}{arg0, arg1}
|
||||||
|
for _, a := range arg2 {
|
||||||
|
varargs = append(varargs, a)
|
||||||
|
}
|
||||||
|
ret := m.ctrl.Call(m, "ReadResource", varargs...)
|
||||||
|
ret0, _ := ret[0].(*tfplugin6.ReadResource_Response)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadResource indicates an expected call of ReadResource
|
||||||
|
func (mr *MockProviderClientMockRecorder) ReadResource(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadResource", reflect.TypeOf((*MockProviderClient)(nil).ReadResource), varargs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StopProvider mocks base method
|
||||||
|
func (m *MockProviderClient) StopProvider(arg0 context.Context, arg1 *tfplugin6.StopProvider_Request, arg2 ...grpc.CallOption) (*tfplugin6.StopProvider_Response, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
varargs := []interface{}{arg0, arg1}
|
||||||
|
for _, a := range arg2 {
|
||||||
|
varargs = append(varargs, a)
|
||||||
|
}
|
||||||
|
ret := m.ctrl.Call(m, "StopProvider", varargs...)
|
||||||
|
ret0, _ := ret[0].(*tfplugin6.StopProvider_Response)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// StopProvider indicates an expected call of StopProvider
|
||||||
|
func (mr *MockProviderClientMockRecorder) StopProvider(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StopProvider", reflect.TypeOf((*MockProviderClient)(nil).StopProvider), varargs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpgradeResourceState mocks base method
|
||||||
|
func (m *MockProviderClient) UpgradeResourceState(arg0 context.Context, arg1 *tfplugin6.UpgradeResourceState_Request, arg2 ...grpc.CallOption) (*tfplugin6.UpgradeResourceState_Response, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
varargs := []interface{}{arg0, arg1}
|
||||||
|
for _, a := range arg2 {
|
||||||
|
varargs = append(varargs, a)
|
||||||
|
}
|
||||||
|
ret := m.ctrl.Call(m, "UpgradeResourceState", varargs...)
|
||||||
|
ret0, _ := ret[0].(*tfplugin6.UpgradeResourceState_Response)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpgradeResourceState indicates an expected call of UpgradeResourceState
|
||||||
|
func (mr *MockProviderClientMockRecorder) UpgradeResourceState(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpgradeResourceState", reflect.TypeOf((*MockProviderClient)(nil).UpgradeResourceState), varargs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateDataSourceConfig mocks base method
|
||||||
|
func (m *MockProviderClient) ValidateDataSourceConfig(arg0 context.Context, arg1 *tfplugin6.ValidateDataSourceConfig_Request, arg2 ...grpc.CallOption) (*tfplugin6.ValidateDataSourceConfig_Response, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
varargs := []interface{}{arg0, arg1}
|
||||||
|
for _, a := range arg2 {
|
||||||
|
varargs = append(varargs, a)
|
||||||
|
}
|
||||||
|
ret := m.ctrl.Call(m, "ValidateDataSourceConfig", varargs...)
|
||||||
|
ret0, _ := ret[0].(*tfplugin6.ValidateDataSourceConfig_Response)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateDataSourceConfig indicates an expected call of ValidateDataSourceConfig
|
||||||
|
func (mr *MockProviderClientMockRecorder) ValidateDataSourceConfig(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateDataSourceConfig", reflect.TypeOf((*MockProviderClient)(nil).ValidateDataSourceConfig), varargs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateProviderConfig mocks base method
|
||||||
|
func (m *MockProviderClient) ValidateProviderConfig(arg0 context.Context, arg1 *tfplugin6.ValidateProviderConfig_Request, arg2 ...grpc.CallOption) (*tfplugin6.ValidateProviderConfig_Response, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
varargs := []interface{}{arg0, arg1}
|
||||||
|
for _, a := range arg2 {
|
||||||
|
varargs = append(varargs, a)
|
||||||
|
}
|
||||||
|
ret := m.ctrl.Call(m, "ValidateProviderConfig", varargs...)
|
||||||
|
ret0, _ := ret[0].(*tfplugin6.ValidateProviderConfig_Response)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateProviderConfig indicates an expected call of ValidateProviderConfig
|
||||||
|
func (mr *MockProviderClientMockRecorder) ValidateProviderConfig(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateProviderConfig", reflect.TypeOf((*MockProviderClient)(nil).ValidateProviderConfig), varargs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateResourceConfig mocks base method
|
||||||
|
func (m *MockProviderClient) ValidateResourceConfig(arg0 context.Context, arg1 *tfplugin6.ValidateResourceConfig_Request, arg2 ...grpc.CallOption) (*tfplugin6.ValidateResourceConfig_Response, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
varargs := []interface{}{arg0, arg1}
|
||||||
|
for _, a := range arg2 {
|
||||||
|
varargs = append(varargs, a)
|
||||||
|
}
|
||||||
|
ret := m.ctrl.Call(m, "ValidateResourceConfig", varargs...)
|
||||||
|
ret0, _ := ret[0].(*tfplugin6.ValidateResourceConfig_Response)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateResourceConfig indicates an expected call of ValidateResourceConfig
|
||||||
|
func (mr *MockProviderClientMockRecorder) ValidateResourceConfig(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateResourceConfig", reflect.TypeOf((*MockProviderClient)(nil).ValidateResourceConfig), varargs...)
|
||||||
|
}
|
|
@ -8,24 +8,21 @@ import (
|
||||||
const (
|
const (
|
||||||
// The constants below are the names of the plugins that can be dispensed
|
// The constants below are the names of the plugins that can be dispensed
|
||||||
// from the plugin server.
|
// from the plugin server.
|
||||||
ProviderPluginName = "provider"
|
ProviderPluginName = "provider"
|
||||||
ProvisionerPluginName = "provisioner"
|
|
||||||
|
|
||||||
// DefaultProtocolVersion is the protocol version assumed for legacy clients that don't specify
|
// DefaultProtocolVersion is the protocol version assumed for legacy clients
|
||||||
// a particular version during their handshake. This is the version used when Terraform 0.10
|
// that don't specify a particular version during their handshake. Since we
|
||||||
// and 0.11 launch plugins that were built with support for both versions 4 and 5, and must
|
// explicitly set VersionedPlugins in Serve, this number does not need to
|
||||||
// stay unchanged at 4 until we intentionally build plugins that are not compatible with 0.10 and
|
// change with the protocol version and can effectively stay 4 forever
|
||||||
// 0.11.
|
// (unless we need the "biggest hammer" approach to break all provider
|
||||||
|
// compatibility).
|
||||||
DefaultProtocolVersion = 4
|
DefaultProtocolVersion = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
// Handshake is the HandshakeConfig used to configure clients and servers.
|
// Handshake is the HandshakeConfig used to configure clients and servers.
|
||||||
var Handshake = plugin.HandshakeConfig{
|
var Handshake = plugin.HandshakeConfig{
|
||||||
// The ProtocolVersion is the version that must match between TF core
|
// The ProtocolVersion is the version that must match between TF core
|
||||||
// and TF plugins. This should be bumped whenever a change happens in
|
// and TF plugins.
|
||||||
// one or the other that makes it so that they can't safely communicate.
|
|
||||||
// This could be adding a new interface value, it could be how
|
|
||||||
// helper/schema computes diffs, etc.
|
|
||||||
ProtocolVersion: DefaultProtocolVersion,
|
ProtocolVersion: DefaultProtocolVersion,
|
||||||
|
|
||||||
// The magic cookie values should NEVER be changed.
|
// The magic cookie values should NEVER be changed.
|
||||||
|
@ -37,8 +34,6 @@ type GRPCProviderFunc func() proto.ProviderServer
|
||||||
|
|
||||||
// ServeOpts are the configurations to serve a plugin.
|
// ServeOpts are the configurations to serve a plugin.
|
||||||
type ServeOpts struct {
|
type ServeOpts struct {
|
||||||
// Wrapped versions of the above plugins will automatically shimmed and
|
|
||||||
// added to the GRPC functions when possible.
|
|
||||||
GRPCProviderFunc GRPCProviderFunc
|
GRPCProviderFunc GRPCProviderFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +52,7 @@ func pluginSet(opts *ServeOpts) map[int]plugin.PluginSet {
|
||||||
|
|
||||||
// add the new protocol versions if they're configured
|
// add the new protocol versions if they're configured
|
||||||
if opts.GRPCProviderFunc != nil {
|
if opts.GRPCProviderFunc != nil {
|
||||||
plugins[5] = plugin.PluginSet{}
|
plugins[6] = plugin.PluginSet{}
|
||||||
if opts.GRPCProviderFunc != nil {
|
if opts.GRPCProviderFunc != nil {
|
||||||
plugins[6]["provider"] = &GRPCProviderPlugin{
|
plugins[6]["provider"] = &GRPCProviderPlugin{
|
||||||
GRPCProvider: opts.GRPCProviderFunc,
|
GRPCProvider: opts.GRPCProviderFunc,
|
||||||
|
|
Loading…
Reference in New Issue