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 }