github.com/kevinklinger/open_terraform@v1.3.6/noninternal/plugin/grpc_provider.go (about)

     1  package plugin
     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/kevinklinger/open_terraform/noninternal/logging"
    13  	"github.com/kevinklinger/open_terraform/noninternal/plugin/convert"
    14  	"github.com/kevinklinger/open_terraform/noninternal/providers"
    15  	proto "github.com/kevinklinger/open_terraform/noninternal/tfplugin5"
    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() proto.ProviderServer
    27  }
    28  
    29  func (p *GRPCProviderPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
    30  	return &GRPCProvider{
    31  		client: proto.NewProviderClient(c),
    32  		ctx:    ctx,
    33  	}, nil
    34  }
    35  
    36  func (p *GRPCProviderPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error {
    37  	proto.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 proto.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  // getSchema is used internally to get the cached provider schema
    68  func (p *GRPCProvider) getSchema() providers.GetProviderSchemaResponse {
    69  	p.mu.Lock()
    70  	// unlock inline in case GetSchema needs to be called
    71  	if p.schemas.Provider.Block != nil {
    72  		p.mu.Unlock()
    73  		return p.schemas
    74  	}
    75  	p.mu.Unlock()
    76  
    77  	return p.GetProviderSchema()
    78  }
    79  
    80  func (p *GRPCProvider) GetProviderSchema() (resp providers.GetProviderSchemaResponse) {
    81  	logger.Trace("GRPCProvider: GetProviderSchema")
    82  	p.mu.Lock()
    83  	defer p.mu.Unlock()
    84  
    85  	if p.schemas.Provider.Block != nil {
    86  		return p.schemas
    87  	}
    88  
    89  	resp.ResourceTypes = make(map[string]providers.Schema)
    90  	resp.DataSources = make(map[string]providers.Schema)
    91  
    92  	// Some providers may generate quite large schemas, and the internal default
    93  	// grpc response size limit is 4MB. 64MB should cover most any use case, and
    94  	// if we get providers nearing that we may want to consider a finer-grained
    95  	// API to fetch individual resource schemas.
    96  	// Note: this option is marked as EXPERIMENTAL in the grpc API. We keep
    97  	// this for compatibility, but recent providers all set the max message
    98  	// size much higher on the server side, which is the supported method for
    99  	// determining payload size.
   100  	const maxRecvSize = 64 << 20
   101  	protoResp, err := p.client.GetSchema(p.ctx, new(proto.GetProviderSchema_Request), grpc.MaxRecvMsgSizeCallOption{MaxRecvMsgSize: maxRecvSize})
   102  	if err != nil {
   103  		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
   104  		return resp
   105  	}
   106  
   107  	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
   108  
   109  	if resp.Diagnostics.HasErrors() {
   110  		return resp
   111  	}
   112  
   113  	if protoResp.Provider == nil {
   114  		resp.Diagnostics = resp.Diagnostics.Append(errors.New("missing provider schema"))
   115  		return resp
   116  	}
   117  
   118  	resp.Provider = convert.ProtoToProviderSchema(protoResp.Provider)
   119  	if protoResp.ProviderMeta == nil {
   120  		logger.Debug("No provider meta schema returned")
   121  	} else {
   122  		resp.ProviderMeta = convert.ProtoToProviderSchema(protoResp.ProviderMeta)
   123  	}
   124  
   125  	for name, res := range protoResp.ResourceSchemas {
   126  		resp.ResourceTypes[name] = convert.ProtoToProviderSchema(res)
   127  	}
   128  
   129  	for name, data := range protoResp.DataSourceSchemas {
   130  		resp.DataSources[name] = convert.ProtoToProviderSchema(data)
   131  	}
   132  
   133  	if protoResp.ServerCapabilities != nil {
   134  		resp.ServerCapabilities.PlanDestroy = protoResp.ServerCapabilities.PlanDestroy
   135  	}
   136  
   137  	p.schemas = resp
   138  
   139  	return resp
   140  }
   141  
   142  func (p *GRPCProvider) ValidateProviderConfig(r providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) {
   143  	logger.Trace("GRPCProvider: ValidateProviderConfig")
   144  
   145  	schema := p.getSchema()
   146  	if schema.Diagnostics.HasErrors() {
   147  		resp.Diagnostics = schema.Diagnostics
   148  		return resp
   149  	}
   150  
   151  	ty := schema.Provider.Block.ImpliedType()
   152  
   153  	mp, err := msgpack.Marshal(r.Config, ty)
   154  	if err != nil {
   155  		resp.Diagnostics = resp.Diagnostics.Append(err)
   156  		return resp
   157  	}
   158  
   159  	protoReq := &proto.PrepareProviderConfig_Request{
   160  		Config: &proto.DynamicValue{Msgpack: mp},
   161  	}
   162  
   163  	protoResp, err := p.client.PrepareProviderConfig(p.ctx, protoReq)
   164  	if err != nil {
   165  		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
   166  		return resp
   167  	}
   168  
   169  	config, err := decodeDynamicValue(protoResp.PreparedConfig, ty)
   170  	if err != nil {
   171  		resp.Diagnostics = resp.Diagnostics.Append(err)
   172  		return resp
   173  	}
   174  	resp.PreparedConfig = config
   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: 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 := &proto.ValidateResourceTypeConfig_Request{
   202  		TypeName: r.TypeName,
   203  		Config:   &proto.DynamicValue{Msgpack: mp},
   204  	}
   205  
   206  	protoResp, err := p.client.ValidateResourceTypeConfig(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: 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 := &proto.ValidateDataSourceConfig_Request{
   238  		TypeName: r.TypeName,
   239  		Config:   &proto.DynamicValue{Msgpack: mp},
   240  	}
   241  
   242  	protoResp, err := p.client.ValidateDataSourceConfig(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: 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 := &proto.UpgradeResourceState_Request{
   267  		TypeName: r.TypeName,
   268  		Version:  int64(r.Version),
   269  		RawState: &proto.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: ConfigureProvider")
   300  
   301  	schema := p.getSchema()
   302  	if schema.Diagnostics.HasErrors() {
   303  		resp.Diagnostics = schema.Diagnostics
   304  		return resp
   305  	}
   306  
   307  	var mp []byte
   308  
   309  	// we don't have anything to marshal if there's no config
   310  	mp, err := msgpack.Marshal(r.Config, schema.Provider.Block.ImpliedType())
   311  	if err != nil {
   312  		resp.Diagnostics = resp.Diagnostics.Append(err)
   313  		return resp
   314  	}
   315  
   316  	protoReq := &proto.Configure_Request{
   317  		TerraformVersion: r.TerraformVersion,
   318  		Config: &proto.DynamicValue{
   319  			Msgpack: mp,
   320  		},
   321  	}
   322  
   323  	protoResp, err := p.client.Configure(p.ctx, protoReq)
   324  	if err != nil {
   325  		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
   326  		return resp
   327  	}
   328  	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
   329  	return resp
   330  }
   331  
   332  func (p *GRPCProvider) Stop() error {
   333  	logger.Trace("GRPCProvider: Stop")
   334  
   335  	resp, err := p.client.Stop(p.ctx, new(proto.Stop_Request))
   336  	if err != nil {
   337  		return err
   338  	}
   339  
   340  	if resp.Error != "" {
   341  		return errors.New(resp.Error)
   342  	}
   343  	return nil
   344  }
   345  
   346  func (p *GRPCProvider) ReadResource(r providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
   347  	logger.Trace("GRPCProvider: ReadResource")
   348  
   349  	schema := p.getSchema()
   350  	if schema.Diagnostics.HasErrors() {
   351  		resp.Diagnostics = schema.Diagnostics
   352  		return resp
   353  	}
   354  
   355  	resSchema, ok := schema.ResourceTypes[r.TypeName]
   356  	if !ok {
   357  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unknown resource type " + r.TypeName))
   358  		return resp
   359  	}
   360  
   361  	metaSchema := schema.ProviderMeta
   362  
   363  	mp, err := msgpack.Marshal(r.PriorState, resSchema.Block.ImpliedType())
   364  	if err != nil {
   365  		resp.Diagnostics = resp.Diagnostics.Append(err)
   366  		return resp
   367  	}
   368  
   369  	protoReq := &proto.ReadResource_Request{
   370  		TypeName:     r.TypeName,
   371  		CurrentState: &proto.DynamicValue{Msgpack: mp},
   372  		Private:      r.Private,
   373  	}
   374  
   375  	if metaSchema.Block != nil {
   376  		metaMP, err := msgpack.Marshal(r.ProviderMeta, metaSchema.Block.ImpliedType())
   377  		if err != nil {
   378  			resp.Diagnostics = resp.Diagnostics.Append(err)
   379  			return resp
   380  		}
   381  		protoReq.ProviderMeta = &proto.DynamicValue{Msgpack: metaMP}
   382  	}
   383  
   384  	protoResp, err := p.client.ReadResource(p.ctx, protoReq)
   385  	if err != nil {
   386  		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
   387  		return resp
   388  	}
   389  	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
   390  
   391  	state, err := decodeDynamicValue(protoResp.NewState, resSchema.Block.ImpliedType())
   392  	if err != nil {
   393  		resp.Diagnostics = resp.Diagnostics.Append(err)
   394  		return resp
   395  	}
   396  	resp.NewState = state
   397  	resp.Private = protoResp.Private
   398  
   399  	return resp
   400  }
   401  
   402  func (p *GRPCProvider) PlanResourceChange(r providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
   403  	logger.Trace("GRPCProvider: PlanResourceChange")
   404  
   405  	schema := p.getSchema()
   406  	if schema.Diagnostics.HasErrors() {
   407  		resp.Diagnostics = schema.Diagnostics
   408  		return resp
   409  	}
   410  
   411  	resSchema, ok := schema.ResourceTypes[r.TypeName]
   412  	if !ok {
   413  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unknown resource type %q", r.TypeName))
   414  		return resp
   415  	}
   416  
   417  	metaSchema := schema.ProviderMeta
   418  	capabilities := schema.ServerCapabilities
   419  
   420  	// If the provider doesn't support planning a destroy operation, we can
   421  	// return immediately.
   422  	if r.ProposedNewState.IsNull() && !capabilities.PlanDestroy {
   423  		resp.PlannedState = r.ProposedNewState
   424  		resp.PlannedPrivate = r.PriorPrivate
   425  		return resp
   426  	}
   427  
   428  	priorMP, err := msgpack.Marshal(r.PriorState, resSchema.Block.ImpliedType())
   429  	if err != nil {
   430  		resp.Diagnostics = resp.Diagnostics.Append(err)
   431  		return resp
   432  	}
   433  
   434  	configMP, err := msgpack.Marshal(r.Config, resSchema.Block.ImpliedType())
   435  	if err != nil {
   436  		resp.Diagnostics = resp.Diagnostics.Append(err)
   437  		return resp
   438  	}
   439  
   440  	propMP, err := msgpack.Marshal(r.ProposedNewState, resSchema.Block.ImpliedType())
   441  	if err != nil {
   442  		resp.Diagnostics = resp.Diagnostics.Append(err)
   443  		return resp
   444  	}
   445  
   446  	protoReq := &proto.PlanResourceChange_Request{
   447  		TypeName:         r.TypeName,
   448  		PriorState:       &proto.DynamicValue{Msgpack: priorMP},
   449  		Config:           &proto.DynamicValue{Msgpack: configMP},
   450  		ProposedNewState: &proto.DynamicValue{Msgpack: propMP},
   451  		PriorPrivate:     r.PriorPrivate,
   452  	}
   453  
   454  	if metaSchema.Block != nil {
   455  		metaMP, err := msgpack.Marshal(r.ProviderMeta, metaSchema.Block.ImpliedType())
   456  		if err != nil {
   457  			resp.Diagnostics = resp.Diagnostics.Append(err)
   458  			return resp
   459  		}
   460  		protoReq.ProviderMeta = &proto.DynamicValue{Msgpack: metaMP}
   461  	}
   462  
   463  	protoResp, err := p.client.PlanResourceChange(p.ctx, protoReq)
   464  	if err != nil {
   465  		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
   466  		return resp
   467  	}
   468  	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
   469  
   470  	state, err := decodeDynamicValue(protoResp.PlannedState, resSchema.Block.ImpliedType())
   471  	if err != nil {
   472  		resp.Diagnostics = resp.Diagnostics.Append(err)
   473  		return resp
   474  	}
   475  	resp.PlannedState = state
   476  
   477  	for _, p := range protoResp.RequiresReplace {
   478  		resp.RequiresReplace = append(resp.RequiresReplace, convert.AttributePathToPath(p))
   479  	}
   480  
   481  	resp.PlannedPrivate = protoResp.PlannedPrivate
   482  
   483  	resp.LegacyTypeSystem = protoResp.LegacyTypeSystem
   484  
   485  	return resp
   486  }
   487  
   488  func (p *GRPCProvider) ApplyResourceChange(r providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   489  	logger.Trace("GRPCProvider: ApplyResourceChange")
   490  
   491  	schema := p.getSchema()
   492  	if schema.Diagnostics.HasErrors() {
   493  		resp.Diagnostics = schema.Diagnostics
   494  		return resp
   495  	}
   496  
   497  	resSchema, ok := schema.ResourceTypes[r.TypeName]
   498  	if !ok {
   499  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unknown resource type %q", r.TypeName))
   500  		return resp
   501  	}
   502  
   503  	metaSchema := schema.ProviderMeta
   504  
   505  	priorMP, err := msgpack.Marshal(r.PriorState, resSchema.Block.ImpliedType())
   506  	if err != nil {
   507  		resp.Diagnostics = resp.Diagnostics.Append(err)
   508  		return resp
   509  	}
   510  	plannedMP, err := msgpack.Marshal(r.PlannedState, resSchema.Block.ImpliedType())
   511  	if err != nil {
   512  		resp.Diagnostics = resp.Diagnostics.Append(err)
   513  		return resp
   514  	}
   515  	configMP, err := msgpack.Marshal(r.Config, resSchema.Block.ImpliedType())
   516  	if err != nil {
   517  		resp.Diagnostics = resp.Diagnostics.Append(err)
   518  		return resp
   519  	}
   520  
   521  	protoReq := &proto.ApplyResourceChange_Request{
   522  		TypeName:       r.TypeName,
   523  		PriorState:     &proto.DynamicValue{Msgpack: priorMP},
   524  		PlannedState:   &proto.DynamicValue{Msgpack: plannedMP},
   525  		Config:         &proto.DynamicValue{Msgpack: configMP},
   526  		PlannedPrivate: r.PlannedPrivate,
   527  	}
   528  
   529  	if metaSchema.Block != nil {
   530  		metaMP, err := msgpack.Marshal(r.ProviderMeta, metaSchema.Block.ImpliedType())
   531  		if err != nil {
   532  			resp.Diagnostics = resp.Diagnostics.Append(err)
   533  			return resp
   534  		}
   535  		protoReq.ProviderMeta = &proto.DynamicValue{Msgpack: metaMP}
   536  	}
   537  
   538  	protoResp, err := p.client.ApplyResourceChange(p.ctx, protoReq)
   539  	if err != nil {
   540  		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
   541  		return resp
   542  	}
   543  	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
   544  
   545  	resp.Private = protoResp.Private
   546  
   547  	state, err := decodeDynamicValue(protoResp.NewState, resSchema.Block.ImpliedType())
   548  	if err != nil {
   549  		resp.Diagnostics = resp.Diagnostics.Append(err)
   550  		return resp
   551  	}
   552  	resp.NewState = state
   553  
   554  	resp.LegacyTypeSystem = protoResp.LegacyTypeSystem
   555  
   556  	return resp
   557  }
   558  
   559  func (p *GRPCProvider) ImportResourceState(r providers.ImportResourceStateRequest) (resp providers.ImportResourceStateResponse) {
   560  	logger.Trace("GRPCProvider: ImportResourceState")
   561  
   562  	schema := p.getSchema()
   563  	if schema.Diagnostics.HasErrors() {
   564  		resp.Diagnostics = schema.Diagnostics
   565  		return resp
   566  	}
   567  
   568  	protoReq := &proto.ImportResourceState_Request{
   569  		TypeName: r.TypeName,
   570  		Id:       r.ID,
   571  	}
   572  
   573  	protoResp, err := p.client.ImportResourceState(p.ctx, protoReq)
   574  	if err != nil {
   575  		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
   576  		return resp
   577  	}
   578  	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
   579  
   580  	for _, imported := range protoResp.ImportedResources {
   581  		resource := providers.ImportedResource{
   582  			TypeName: imported.TypeName,
   583  			Private:  imported.Private,
   584  		}
   585  
   586  		resSchema, ok := schema.ResourceTypes[r.TypeName]
   587  		if !ok {
   588  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unknown resource type %q", r.TypeName))
   589  			continue
   590  		}
   591  
   592  		state, err := decodeDynamicValue(imported.State, resSchema.Block.ImpliedType())
   593  		if err != nil {
   594  			resp.Diagnostics = resp.Diagnostics.Append(err)
   595  			return resp
   596  		}
   597  		resource.State = state
   598  		resp.ImportedResources = append(resp.ImportedResources, resource)
   599  	}
   600  
   601  	return resp
   602  }
   603  
   604  func (p *GRPCProvider) ReadDataSource(r providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
   605  	logger.Trace("GRPCProvider: ReadDataSource")
   606  
   607  	schema := p.getSchema()
   608  	if schema.Diagnostics.HasErrors() {
   609  		resp.Diagnostics = schema.Diagnostics
   610  		return resp
   611  	}
   612  
   613  	dataSchema, ok := schema.DataSources[r.TypeName]
   614  	if !ok {
   615  		schema.Diagnostics = schema.Diagnostics.Append(fmt.Errorf("unknown data source %q", r.TypeName))
   616  	}
   617  
   618  	metaSchema := schema.ProviderMeta
   619  
   620  	config, err := msgpack.Marshal(r.Config, dataSchema.Block.ImpliedType())
   621  	if err != nil {
   622  		resp.Diagnostics = resp.Diagnostics.Append(err)
   623  		return resp
   624  	}
   625  
   626  	protoReq := &proto.ReadDataSource_Request{
   627  		TypeName: r.TypeName,
   628  		Config: &proto.DynamicValue{
   629  			Msgpack: config,
   630  		},
   631  	}
   632  
   633  	if metaSchema.Block != nil {
   634  		metaMP, err := msgpack.Marshal(r.ProviderMeta, metaSchema.Block.ImpliedType())
   635  		if err != nil {
   636  			resp.Diagnostics = resp.Diagnostics.Append(err)
   637  			return resp
   638  		}
   639  		protoReq.ProviderMeta = &proto.DynamicValue{Msgpack: metaMP}
   640  	}
   641  
   642  	protoResp, err := p.client.ReadDataSource(p.ctx, protoReq)
   643  	if err != nil {
   644  		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
   645  		return resp
   646  	}
   647  	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
   648  
   649  	state, err := decodeDynamicValue(protoResp.State, dataSchema.Block.ImpliedType())
   650  	if err != nil {
   651  		resp.Diagnostics = resp.Diagnostics.Append(err)
   652  		return resp
   653  	}
   654  	resp.State = state
   655  
   656  	return resp
   657  }
   658  
   659  // closing the grpc connection is final, and terraform will call it at the end of every phase.
   660  func (p *GRPCProvider) Close() error {
   661  	logger.Trace("GRPCProvider: Close")
   662  
   663  	// Make sure to stop the server if we're not running within go-plugin.
   664  	if p.TestServer != nil {
   665  		p.TestServer.Stop()
   666  	}
   667  
   668  	// Check this since it's not automatically inserted during plugin creation.
   669  	// It's currently only inserted by the command package, because that is
   670  	// where the factory is built and is the only point with access to the
   671  	// plugin.Client.
   672  	if p.PluginClient == nil {
   673  		logger.Debug("provider has no plugin.Client")
   674  		return nil
   675  	}
   676  
   677  	p.PluginClient.Kill()
   678  	return nil
   679  }
   680  
   681  // Decode a DynamicValue from either the JSON or MsgPack encoding.
   682  func decodeDynamicValue(v *proto.DynamicValue, ty cty.Type) (cty.Value, error) {
   683  	// always return a valid value
   684  	var err error
   685  	res := cty.NullVal(ty)
   686  	if v == nil {
   687  		return res, nil
   688  	}
   689  
   690  	switch {
   691  	case len(v.Msgpack) > 0:
   692  		res, err = msgpack.Unmarshal(v.Msgpack, ty)
   693  	case len(v.Json) > 0:
   694  		res, err = ctyjson.Unmarshal(v.Json, ty)
   695  	}
   696  	return res, err
   697  }