kubeform.dev/terraform-backend-sdk@v0.0.0-20220310143633-45f07fe731c5/plugin6/grpc_provider.go (about)

     1  package plugin6
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"sync"
     7  
     8  	"github.com/zclconf/go-cty/cty"
     9  
    10  	plugin "github.com/hashicorp/go-plugin"
    11  	"kubeform.dev/terraform-backend-sdk/logging"
    12  	"kubeform.dev/terraform-backend-sdk/plugin6/convert"
    13  	"kubeform.dev/terraform-backend-sdk/providers"
    14  	proto6 "kubeform.dev/terraform-backend-sdk/tfplugin6"
    15  	ctyjson "github.com/zclconf/go-cty/cty/json"
    16  	"github.com/zclconf/go-cty/cty/msgpack"
    17  	"google.golang.org/grpc"
    18  )
    19  
    20  var logger = logging.HCLogger()
    21  
    22  // GRPCProviderPlugin implements plugin.GRPCPlugin for the go-plugin package.
    23  type GRPCProviderPlugin struct {
    24  	plugin.Plugin
    25  	GRPCProvider func() proto6.ProviderServer
    26  }
    27  
    28  func (p *GRPCProviderPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
    29  	return &GRPCProvider{
    30  		client: proto6.NewProviderClient(c),
    31  		ctx:    ctx,
    32  	}, nil
    33  }
    34  
    35  func (p *GRPCProviderPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error {
    36  	proto6.RegisterProviderServer(s, p.GRPCProvider())
    37  	return nil
    38  }
    39  
    40  // GRPCProvider handles the client, or core side of the plugin rpc connection.
    41  // The GRPCProvider methods are mostly a translation layer between the
    42  // terraform providers types and the grpc proto types, directly converting
    43  // between the two.
    44  type GRPCProvider struct {
    45  	// PluginClient provides a reference to the plugin.Client which controls the plugin process.
    46  	// This allows the GRPCProvider a way to shutdown the plugin process.
    47  	PluginClient *plugin.Client
    48  
    49  	// TestServer contains a grpc.Server to close when the GRPCProvider is being
    50  	// used in an end to end test of a provider.
    51  	TestServer *grpc.Server
    52  
    53  	// Proto client use to make the grpc service calls.
    54  	client proto6.ProviderClient
    55  
    56  	// this context is created by the plugin package, and is canceled when the
    57  	// plugin process ends.
    58  	ctx context.Context
    59  
    60  	// schema stores the schema for this provider. This is used to properly
    61  	// serialize the state for requests.
    62  	mu      sync.Mutex
    63  	schemas providers.GetProviderSchemaResponse
    64  }
    65  
    66  func New(client proto6.ProviderClient, ctx context.Context) GRPCProvider {
    67  	return GRPCProvider{
    68  		client: client,
    69  		ctx:    ctx,
    70  	}
    71  }
    72  
    73  // getSchema is used internally to get the saved provider schema.  The schema
    74  // should have already been fetched from the provider, but we have to
    75  // synchronize access to avoid being called concurrently with GetProviderSchema.
    76  func (p *GRPCProvider) getSchema() providers.GetProviderSchemaResponse {
    77  	p.mu.Lock()
    78  	// unlock inline in case GetProviderSchema needs to be called
    79  	if p.schemas.Provider.Block != nil {
    80  		p.mu.Unlock()
    81  		return p.schemas
    82  	}
    83  	p.mu.Unlock()
    84  
    85  	// the schema should have been fetched already, but give it another shot
    86  	// just in case things are being called out of order. This may happen for
    87  	// tests.
    88  	schemas := p.GetProviderSchema()
    89  	if schemas.Diagnostics.HasErrors() {
    90  		panic(schemas.Diagnostics.Err())
    91  	}
    92  
    93  	return schemas
    94  }
    95  
    96  // getResourceSchema is a helper to extract the schema for a resource, and
    97  // panics if the schema is not available.
    98  func (p *GRPCProvider) getResourceSchema(name string) providers.Schema {
    99  	schema := p.getSchema()
   100  	resSchema, ok := schema.ResourceTypes[name]
   101  	if !ok {
   102  		panic("unknown resource type " + name)
   103  	}
   104  	return resSchema
   105  }
   106  
   107  // gettDatasourceSchema is a helper to extract the schema for a datasource, and
   108  // panics if that schema is not available.
   109  func (p *GRPCProvider) getDatasourceSchema(name string) providers.Schema {
   110  	schema := p.getSchema()
   111  	dataSchema, ok := schema.DataSources[name]
   112  	if !ok {
   113  		panic("unknown data source " + name)
   114  	}
   115  	return dataSchema
   116  }
   117  
   118  // getProviderMetaSchema is a helper to extract the schema for the meta info
   119  // defined for a provider,
   120  func (p *GRPCProvider) getProviderMetaSchema() providers.Schema {
   121  	schema := p.getSchema()
   122  	return schema.ProviderMeta
   123  }
   124  
   125  func (p *GRPCProvider) GetProviderSchema() (resp providers.GetProviderSchemaResponse) {
   126  	logger.Trace("GRPCProvider.v6: GetProviderSchema")
   127  	p.mu.Lock()
   128  	defer p.mu.Unlock()
   129  
   130  	if p.schemas.Provider.Block != nil {
   131  		return p.schemas
   132  	}
   133  
   134  	resp.ResourceTypes = make(map[string]providers.Schema)
   135  	resp.DataSources = make(map[string]providers.Schema)
   136  
   137  	// Some providers may generate quite large schemas, and the internal default
   138  	// grpc response size limit is 4MB. 64MB should cover most any use case, and
   139  	// if we get providers nearing that we may want to consider a finer-grained
   140  	// API to fetch individual resource schemas.
   141  	// Note: this option is marked as EXPERIMENTAL in the grpc API.
   142  	const maxRecvSize = 64 << 20
   143  	protoResp, err := p.client.GetProviderSchema(p.ctx, new(proto6.GetProviderSchema_Request), grpc.MaxRecvMsgSizeCallOption{MaxRecvMsgSize: maxRecvSize})
   144  	if err != nil {
   145  		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
   146  		return resp
   147  	}
   148  
   149  	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
   150  
   151  	if protoResp.Provider == nil {
   152  		resp.Diagnostics = resp.Diagnostics.Append(errors.New("missing provider schema"))
   153  		return resp
   154  	}
   155  
   156  	resp.Provider = convert.ProtoToProviderSchema(protoResp.Provider)
   157  	if protoResp.ProviderMeta == nil {
   158  		logger.Debug("No provider meta schema returned")
   159  	} else {
   160  		resp.ProviderMeta = convert.ProtoToProviderSchema(protoResp.ProviderMeta)
   161  	}
   162  
   163  	for name, res := range protoResp.ResourceSchemas {
   164  		resp.ResourceTypes[name] = convert.ProtoToProviderSchema(res)
   165  	}
   166  
   167  	for name, data := range protoResp.DataSourceSchemas {
   168  		resp.DataSources[name] = convert.ProtoToProviderSchema(data)
   169  	}
   170  
   171  	p.schemas = resp
   172  
   173  	return resp
   174  }
   175  
   176  func (p *GRPCProvider) ValidateProviderConfig(r providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) {
   177  	logger.Trace("GRPCProvider.v6: ValidateProviderConfig")
   178  
   179  	schema := p.getSchema()
   180  	ty := schema.Provider.Block.ImpliedType()
   181  
   182  	mp, err := msgpack.Marshal(r.Config, ty)
   183  	if err != nil {
   184  		resp.Diagnostics = resp.Diagnostics.Append(err)
   185  		return resp
   186  	}
   187  
   188  	protoReq := &proto6.ValidateProviderConfig_Request{
   189  		Config: &proto6.DynamicValue{Msgpack: mp},
   190  	}
   191  
   192  	protoResp, err := p.client.ValidateProviderConfig(p.ctx, protoReq)
   193  	if err != nil {
   194  		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
   195  		return resp
   196  	}
   197  
   198  	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
   199  	return resp
   200  }
   201  
   202  func (p *GRPCProvider) ValidateResourceConfig(r providers.ValidateResourceConfigRequest) (resp providers.ValidateResourceConfigResponse) {
   203  	logger.Trace("GRPCProvider.v6: ValidateResourceConfig")
   204  	resourceSchema := p.getResourceSchema(r.TypeName)
   205  
   206  	mp, err := msgpack.Marshal(r.Config, resourceSchema.Block.ImpliedType())
   207  	if err != nil {
   208  		resp.Diagnostics = resp.Diagnostics.Append(err)
   209  		return resp
   210  	}
   211  
   212  	protoReq := &proto6.ValidateResourceConfig_Request{
   213  		TypeName: r.TypeName,
   214  		Config:   &proto6.DynamicValue{Msgpack: mp},
   215  	}
   216  
   217  	protoResp, err := p.client.ValidateResourceConfig(p.ctx, protoReq)
   218  	if err != nil {
   219  		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
   220  		return resp
   221  	}
   222  
   223  	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
   224  	return resp
   225  }
   226  
   227  func (p *GRPCProvider) ValidateDataResourceConfig(r providers.ValidateDataResourceConfigRequest) (resp providers.ValidateDataResourceConfigResponse) {
   228  	logger.Trace("GRPCProvider.v6: ValidateDataResourceConfig")
   229  
   230  	dataSchema := p.getDatasourceSchema(r.TypeName)
   231  
   232  	mp, err := msgpack.Marshal(r.Config, dataSchema.Block.ImpliedType())
   233  	if err != nil {
   234  		resp.Diagnostics = resp.Diagnostics.Append(err)
   235  		return resp
   236  	}
   237  
   238  	protoReq := &proto6.ValidateDataResourceConfig_Request{
   239  		TypeName: r.TypeName,
   240  		Config:   &proto6.DynamicValue{Msgpack: mp},
   241  	}
   242  
   243  	protoResp, err := p.client.ValidateDataResourceConfig(p.ctx, protoReq)
   244  	if err != nil {
   245  		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
   246  		return resp
   247  	}
   248  	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
   249  	return resp
   250  }
   251  
   252  func (p *GRPCProvider) UpgradeResourceState(r providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) {
   253  	logger.Trace("GRPCProvider.v6: UpgradeResourceState")
   254  
   255  	resSchema := p.getResourceSchema(r.TypeName)
   256  
   257  	protoReq := &proto6.UpgradeResourceState_Request{
   258  		TypeName: r.TypeName,
   259  		Version:  int64(r.Version),
   260  		RawState: &proto6.RawState{
   261  			Json:    r.RawStateJSON,
   262  			Flatmap: r.RawStateFlatmap,
   263  		},
   264  	}
   265  
   266  	protoResp, err := p.client.UpgradeResourceState(p.ctx, protoReq)
   267  	if err != nil {
   268  		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
   269  		return resp
   270  	}
   271  	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
   272  
   273  	ty := resSchema.Block.ImpliedType()
   274  	resp.UpgradedState = cty.NullVal(ty)
   275  	if protoResp.UpgradedState == nil {
   276  		return resp
   277  	}
   278  
   279  	state, err := decodeDynamicValue(protoResp.UpgradedState, ty)
   280  	if err != nil {
   281  		resp.Diagnostics = resp.Diagnostics.Append(err)
   282  		return resp
   283  	}
   284  	resp.UpgradedState = state
   285  
   286  	return resp
   287  }
   288  
   289  func (p *GRPCProvider) ConfigureProvider(r providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
   290  	logger.Trace("GRPCProvider.v6: ConfigureProvider")
   291  
   292  	schema := p.getSchema()
   293  
   294  	var mp []byte
   295  
   296  	// we don't have anything to marshal if there's no config
   297  	mp, err := msgpack.Marshal(r.Config, schema.Provider.Block.ImpliedType())
   298  	if err != nil {
   299  		resp.Diagnostics = resp.Diagnostics.Append(err)
   300  		return resp
   301  	}
   302  
   303  	protoReq := &proto6.ConfigureProvider_Request{
   304  		TerraformVersion: r.TerraformVersion,
   305  		Config: &proto6.DynamicValue{
   306  			Msgpack: mp,
   307  		},
   308  	}
   309  
   310  	protoResp, err := p.client.ConfigureProvider(p.ctx, protoReq)
   311  	if err != nil {
   312  		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
   313  		return resp
   314  	}
   315  	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
   316  	return resp
   317  }
   318  
   319  func (p *GRPCProvider) Stop() error {
   320  	logger.Trace("GRPCProvider.v6: Stop")
   321  
   322  	resp, err := p.client.StopProvider(p.ctx, new(proto6.StopProvider_Request))
   323  	if err != nil {
   324  		return err
   325  	}
   326  
   327  	if resp.Error != "" {
   328  		return errors.New(resp.Error)
   329  	}
   330  	return nil
   331  }
   332  
   333  func (p *GRPCProvider) ReadResource(r providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
   334  	logger.Trace("GRPCProvider.v6: ReadResource")
   335  
   336  	resSchema := p.getResourceSchema(r.TypeName)
   337  	metaSchema := p.getProviderMetaSchema()
   338  
   339  	mp, err := msgpack.Marshal(r.PriorState, resSchema.Block.ImpliedType())
   340  	if err != nil {
   341  		resp.Diagnostics = resp.Diagnostics.Append(err)
   342  		return resp
   343  	}
   344  
   345  	protoReq := &proto6.ReadResource_Request{
   346  		TypeName:     r.TypeName,
   347  		CurrentState: &proto6.DynamicValue{Msgpack: mp},
   348  		Private:      r.Private,
   349  	}
   350  
   351  	if metaSchema.Block != nil {
   352  		metaMP, err := msgpack.Marshal(r.ProviderMeta, metaSchema.Block.ImpliedType())
   353  		if err != nil {
   354  			resp.Diagnostics = resp.Diagnostics.Append(err)
   355  			return resp
   356  		}
   357  		protoReq.ProviderMeta = &proto6.DynamicValue{Msgpack: metaMP}
   358  	}
   359  
   360  	protoResp, err := p.client.ReadResource(p.ctx, protoReq)
   361  	if err != nil {
   362  		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
   363  		return resp
   364  	}
   365  	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
   366  
   367  	state, err := decodeDynamicValue(protoResp.NewState, resSchema.Block.ImpliedType())
   368  	if err != nil {
   369  		resp.Diagnostics = resp.Diagnostics.Append(err)
   370  		return resp
   371  	}
   372  	resp.NewState = state
   373  	resp.Private = protoResp.Private
   374  
   375  	return resp
   376  }
   377  
   378  func (p *GRPCProvider) PlanResourceChange(r providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
   379  	logger.Trace("GRPCProvider.v6: PlanResourceChange")
   380  
   381  	resSchema := p.getResourceSchema(r.TypeName)
   382  	metaSchema := p.getProviderMetaSchema()
   383  
   384  	priorMP, err := msgpack.Marshal(r.PriorState, resSchema.Block.ImpliedType())
   385  	if err != nil {
   386  		resp.Diagnostics = resp.Diagnostics.Append(err)
   387  		return resp
   388  	}
   389  
   390  	configMP, err := msgpack.Marshal(r.Config, resSchema.Block.ImpliedType())
   391  	if err != nil {
   392  		resp.Diagnostics = resp.Diagnostics.Append(err)
   393  		return resp
   394  	}
   395  
   396  	propMP, err := msgpack.Marshal(r.ProposedNewState, resSchema.Block.ImpliedType())
   397  	if err != nil {
   398  		resp.Diagnostics = resp.Diagnostics.Append(err)
   399  		return resp
   400  	}
   401  
   402  	protoReq := &proto6.PlanResourceChange_Request{
   403  		TypeName:         r.TypeName,
   404  		PriorState:       &proto6.DynamicValue{Msgpack: priorMP},
   405  		Config:           &proto6.DynamicValue{Msgpack: configMP},
   406  		ProposedNewState: &proto6.DynamicValue{Msgpack: propMP},
   407  		PriorPrivate:     r.PriorPrivate,
   408  	}
   409  
   410  	if metaSchema.Block != nil {
   411  		metaMP, err := msgpack.Marshal(r.ProviderMeta, metaSchema.Block.ImpliedType())
   412  		if err != nil {
   413  			resp.Diagnostics = resp.Diagnostics.Append(err)
   414  			return resp
   415  		}
   416  		protoReq.ProviderMeta = &proto6.DynamicValue{Msgpack: metaMP}
   417  	}
   418  
   419  	protoResp, err := p.client.PlanResourceChange(p.ctx, protoReq)
   420  	if err != nil {
   421  		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
   422  		return resp
   423  	}
   424  	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
   425  
   426  	state, err := decodeDynamicValue(protoResp.PlannedState, resSchema.Block.ImpliedType())
   427  	if err != nil {
   428  		resp.Diagnostics = resp.Diagnostics.Append(err)
   429  		return resp
   430  	}
   431  	resp.PlannedState = state
   432  
   433  	for _, p := range protoResp.RequiresReplace {
   434  		resp.RequiresReplace = append(resp.RequiresReplace, convert.AttributePathToPath(p))
   435  	}
   436  
   437  	resp.PlannedPrivate = protoResp.PlannedPrivate
   438  
   439  	return resp
   440  }
   441  
   442  func (p *GRPCProvider) ApplyResourceChange(r providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   443  	logger.Trace("GRPCProvider.v6: ApplyResourceChange")
   444  
   445  	resSchema := p.getResourceSchema(r.TypeName)
   446  	metaSchema := p.getProviderMetaSchema()
   447  
   448  	priorMP, err := msgpack.Marshal(r.PriorState, resSchema.Block.ImpliedType())
   449  	if err != nil {
   450  		resp.Diagnostics = resp.Diagnostics.Append(err)
   451  		return resp
   452  	}
   453  	plannedMP, err := msgpack.Marshal(r.PlannedState, resSchema.Block.ImpliedType())
   454  	if err != nil {
   455  		resp.Diagnostics = resp.Diagnostics.Append(err)
   456  		return resp
   457  	}
   458  	configMP, err := msgpack.Marshal(r.Config, resSchema.Block.ImpliedType())
   459  	if err != nil {
   460  		resp.Diagnostics = resp.Diagnostics.Append(err)
   461  		return resp
   462  	}
   463  
   464  	protoReq := &proto6.ApplyResourceChange_Request{
   465  		TypeName:       r.TypeName,
   466  		PriorState:     &proto6.DynamicValue{Msgpack: priorMP},
   467  		PlannedState:   &proto6.DynamicValue{Msgpack: plannedMP},
   468  		Config:         &proto6.DynamicValue{Msgpack: configMP},
   469  		PlannedPrivate: r.PlannedPrivate,
   470  	}
   471  
   472  	if metaSchema.Block != nil {
   473  		metaMP, err := msgpack.Marshal(r.ProviderMeta, metaSchema.Block.ImpliedType())
   474  		if err != nil {
   475  			resp.Diagnostics = resp.Diagnostics.Append(err)
   476  			return resp
   477  		}
   478  		protoReq.ProviderMeta = &proto6.DynamicValue{Msgpack: metaMP}
   479  	}
   480  
   481  	protoResp, err := p.client.ApplyResourceChange(p.ctx, protoReq)
   482  	if err != nil {
   483  		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
   484  		return resp
   485  	}
   486  	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
   487  
   488  	resp.Private = protoResp.Private
   489  
   490  	state, err := decodeDynamicValue(protoResp.NewState, resSchema.Block.ImpliedType())
   491  	if err != nil {
   492  		resp.Diagnostics = resp.Diagnostics.Append(err)
   493  		return resp
   494  	}
   495  	resp.NewState = state
   496  
   497  	return resp
   498  }
   499  
   500  func (p *GRPCProvider) ImportResourceState(r providers.ImportResourceStateRequest) (resp providers.ImportResourceStateResponse) {
   501  	logger.Trace("GRPCProvider.v6: ImportResourceState")
   502  
   503  	protoReq := &proto6.ImportResourceState_Request{
   504  		TypeName: r.TypeName,
   505  		Id:       r.ID,
   506  	}
   507  
   508  	protoResp, err := p.client.ImportResourceState(p.ctx, protoReq)
   509  	if err != nil {
   510  		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
   511  		return resp
   512  	}
   513  	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
   514  
   515  	for _, imported := range protoResp.ImportedResources {
   516  		resource := providers.ImportedResource{
   517  			TypeName: imported.TypeName,
   518  			Private:  imported.Private,
   519  		}
   520  
   521  		resSchema := p.getResourceSchema(resource.TypeName)
   522  		state, err := decodeDynamicValue(imported.State, resSchema.Block.ImpliedType())
   523  		if err != nil {
   524  			resp.Diagnostics = resp.Diagnostics.Append(err)
   525  			return resp
   526  		}
   527  		resource.State = state
   528  		resp.ImportedResources = append(resp.ImportedResources, resource)
   529  	}
   530  
   531  	return resp
   532  }
   533  
   534  func (p *GRPCProvider) ReadDataSource(r providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
   535  	logger.Trace("GRPCProvider.v6: ReadDataSource")
   536  
   537  	dataSchema := p.getDatasourceSchema(r.TypeName)
   538  	metaSchema := p.getProviderMetaSchema()
   539  
   540  	config, err := msgpack.Marshal(r.Config, dataSchema.Block.ImpliedType())
   541  	if err != nil {
   542  		resp.Diagnostics = resp.Diagnostics.Append(err)
   543  		return resp
   544  	}
   545  
   546  	protoReq := &proto6.ReadDataSource_Request{
   547  		TypeName: r.TypeName,
   548  		Config: &proto6.DynamicValue{
   549  			Msgpack: config,
   550  		},
   551  	}
   552  
   553  	if metaSchema.Block != nil {
   554  		metaMP, err := msgpack.Marshal(r.ProviderMeta, metaSchema.Block.ImpliedType())
   555  		if err != nil {
   556  			resp.Diagnostics = resp.Diagnostics.Append(err)
   557  			return resp
   558  		}
   559  		protoReq.ProviderMeta = &proto6.DynamicValue{Msgpack: metaMP}
   560  	}
   561  
   562  	protoResp, err := p.client.ReadDataSource(p.ctx, protoReq)
   563  	if err != nil {
   564  		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
   565  		return resp
   566  	}
   567  	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
   568  
   569  	state, err := decodeDynamicValue(protoResp.State, dataSchema.Block.ImpliedType())
   570  	if err != nil {
   571  		resp.Diagnostics = resp.Diagnostics.Append(err)
   572  		return resp
   573  	}
   574  	resp.State = state
   575  
   576  	return resp
   577  }
   578  
   579  // closing the grpc connection is final, and terraform will call it at the end of every phase.
   580  func (p *GRPCProvider) Close() error {
   581  	logger.Trace("GRPCProvider.v6: Close")
   582  
   583  	// Make sure to stop the server if we're not running within go-plugin.
   584  	if p.TestServer != nil {
   585  		p.TestServer.Stop()
   586  	}
   587  
   588  	// Check this since it's not automatically inserted during plugin creation.
   589  	// It's currently only inserted by the command package, because that is
   590  	// where the factory is built and is the only point with access to the
   591  	// plugin.Client.
   592  	if p.PluginClient == nil {
   593  		logger.Debug("provider has no plugin.Client")
   594  		return nil
   595  	}
   596  
   597  	p.PluginClient.Kill()
   598  	return nil
   599  }
   600  
   601  // Decode a DynamicValue from either the JSON or MsgPack encoding.
   602  func decodeDynamicValue(v *proto6.DynamicValue, ty cty.Type) (cty.Value, error) {
   603  	// always return a valid value
   604  	var err error
   605  	res := cty.NullVal(ty)
   606  	if v == nil {
   607  		return res, nil
   608  	}
   609  
   610  	switch {
   611  	case len(v.Msgpack) > 0:
   612  		res, err = msgpack.Unmarshal(v.Msgpack, ty)
   613  	case len(v.Json) > 0:
   614  		res, err = ctyjson.Unmarshal(v.Json, ty)
   615  	}
   616  	return res, err
   617  }