github.com/pulumi/terraform@v1.4.0/pkg/plugin6/grpc_provider.go (about)

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