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