github.com/hashicorp/terraform-plugin-sdk@v1.17.2/plugin/resource_provider.go (about) 1 package plugin 2 3 import ( 4 "net/rpc" 5 6 "github.com/hashicorp/go-plugin" 7 "github.com/hashicorp/terraform-plugin-sdk/terraform" 8 ) 9 10 // ResourceProviderPlugin is the plugin.Plugin implementation. 11 type ResourceProviderPlugin struct { 12 ResourceProvider func() terraform.ResourceProvider 13 } 14 15 func (p *ResourceProviderPlugin) Server(b *plugin.MuxBroker) (interface{}, error) { 16 return &ResourceProviderServer{ 17 Broker: b, 18 Provider: p.ResourceProvider(), 19 }, nil 20 } 21 22 func (p *ResourceProviderPlugin) Client( 23 b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) { 24 return &ResourceProvider{Broker: b, Client: c}, nil 25 } 26 27 // ResourceProvider is an implementation of terraform.ResourceProvider 28 // that communicates over RPC. 29 type ResourceProvider struct { 30 Broker *plugin.MuxBroker 31 Client *rpc.Client 32 } 33 34 func (p *ResourceProvider) Stop() error { 35 var resp ResourceProviderStopResponse 36 err := p.Client.Call("Plugin.Stop", new(interface{}), &resp) 37 if err != nil { 38 return err 39 } 40 if resp.Error != nil { 41 err = resp.Error 42 } 43 44 return err 45 } 46 47 func (p *ResourceProvider) GetSchema(req *terraform.ProviderSchemaRequest) (*terraform.ProviderSchema, error) { 48 var result ResourceProviderGetSchemaResponse 49 args := &ResourceProviderGetSchemaArgs{ 50 Req: req, 51 } 52 53 err := p.Client.Call("Plugin.GetSchema", args, &result) 54 if err != nil { 55 return nil, err 56 } 57 58 if result.Error != nil { 59 err = result.Error 60 } 61 62 return result.Schema, err 63 } 64 65 func (p *ResourceProvider) Input( 66 input terraform.UIInput, 67 c *terraform.ResourceConfig) (*terraform.ResourceConfig, error) { 68 id := p.Broker.NextId() 69 go p.Broker.AcceptAndServe(id, &UIInputServer{ 70 UIInput: input, 71 }) 72 73 var resp ResourceProviderInputResponse 74 args := ResourceProviderInputArgs{ 75 InputId: id, 76 Config: c, 77 } 78 79 err := p.Client.Call("Plugin.Input", &args, &resp) 80 if err != nil { 81 return nil, err 82 } 83 if resp.Error != nil { 84 err = resp.Error 85 return nil, err 86 } 87 88 return resp.Config, nil 89 } 90 91 func (p *ResourceProvider) Validate(c *terraform.ResourceConfig) ([]string, []error) { 92 var resp ResourceProviderValidateResponse 93 args := ResourceProviderValidateArgs{ 94 Config: c, 95 } 96 97 err := p.Client.Call("Plugin.Validate", &args, &resp) 98 if err != nil { 99 return nil, []error{err} 100 } 101 102 var errs []error 103 if len(resp.Errors) > 0 { 104 errs = make([]error, len(resp.Errors)) 105 for i, err := range resp.Errors { 106 errs[i] = err 107 } 108 } 109 110 return resp.Warnings, errs 111 } 112 113 func (p *ResourceProvider) ValidateResource( 114 t string, c *terraform.ResourceConfig) ([]string, []error) { 115 var resp ResourceProviderValidateResourceResponse 116 args := ResourceProviderValidateResourceArgs{ 117 Config: c, 118 Type: t, 119 } 120 121 err := p.Client.Call("Plugin.ValidateResource", &args, &resp) 122 if err != nil { 123 return nil, []error{err} 124 } 125 126 var errs []error 127 if len(resp.Errors) > 0 { 128 errs = make([]error, len(resp.Errors)) 129 for i, err := range resp.Errors { 130 errs[i] = err 131 } 132 } 133 134 return resp.Warnings, errs 135 } 136 137 func (p *ResourceProvider) Configure(c *terraform.ResourceConfig) error { 138 var resp ResourceProviderConfigureResponse 139 err := p.Client.Call("Plugin.Configure", c, &resp) 140 if err != nil { 141 return err 142 } 143 if resp.Error != nil { 144 err = resp.Error 145 } 146 147 return err 148 } 149 150 func (p *ResourceProvider) Apply( 151 info *terraform.InstanceInfo, 152 s *terraform.InstanceState, 153 d *terraform.InstanceDiff) (*terraform.InstanceState, error) { 154 var resp ResourceProviderApplyResponse 155 args := &ResourceProviderApplyArgs{ 156 Info: info, 157 State: s, 158 Diff: d, 159 } 160 161 err := p.Client.Call("Plugin.Apply", args, &resp) 162 if err != nil { 163 return nil, err 164 } 165 if resp.Error != nil { 166 err = resp.Error 167 } 168 169 return resp.State, err 170 } 171 172 func (p *ResourceProvider) Diff( 173 info *terraform.InstanceInfo, 174 s *terraform.InstanceState, 175 c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { 176 var resp ResourceProviderDiffResponse 177 args := &ResourceProviderDiffArgs{ 178 Info: info, 179 State: s, 180 Config: c, 181 } 182 err := p.Client.Call("Plugin.Diff", args, &resp) 183 if err != nil { 184 return nil, err 185 } 186 if resp.Error != nil { 187 err = resp.Error 188 } 189 190 return resp.Diff, err 191 } 192 193 func (p *ResourceProvider) ValidateDataSource( 194 t string, c *terraform.ResourceConfig) ([]string, []error) { 195 var resp ResourceProviderValidateResourceResponse 196 args := ResourceProviderValidateResourceArgs{ 197 Config: c, 198 Type: t, 199 } 200 201 err := p.Client.Call("Plugin.ValidateDataSource", &args, &resp) 202 if err != nil { 203 return nil, []error{err} 204 } 205 206 var errs []error 207 if len(resp.Errors) > 0 { 208 errs = make([]error, len(resp.Errors)) 209 for i, err := range resp.Errors { 210 errs[i] = err 211 } 212 } 213 214 return resp.Warnings, errs 215 } 216 217 func (p *ResourceProvider) Refresh( 218 info *terraform.InstanceInfo, 219 s *terraform.InstanceState) (*terraform.InstanceState, error) { 220 var resp ResourceProviderRefreshResponse 221 args := &ResourceProviderRefreshArgs{ 222 Info: info, 223 State: s, 224 } 225 226 err := p.Client.Call("Plugin.Refresh", args, &resp) 227 if err != nil { 228 return nil, err 229 } 230 if resp.Error != nil { 231 err = resp.Error 232 } 233 234 return resp.State, err 235 } 236 237 func (p *ResourceProvider) ImportState( 238 info *terraform.InstanceInfo, 239 id string) ([]*terraform.InstanceState, error) { 240 var resp ResourceProviderImportStateResponse 241 args := &ResourceProviderImportStateArgs{ 242 Info: info, 243 Id: id, 244 } 245 246 err := p.Client.Call("Plugin.ImportState", args, &resp) 247 if err != nil { 248 return nil, err 249 } 250 if resp.Error != nil { 251 err = resp.Error 252 } 253 254 return resp.State, err 255 } 256 257 func (p *ResourceProvider) Resources() []terraform.ResourceType { 258 var result []terraform.ResourceType 259 260 err := p.Client.Call("Plugin.Resources", new(interface{}), &result) 261 if err != nil { 262 // TODO: panic, log, what? 263 return nil 264 } 265 266 return result 267 } 268 269 func (p *ResourceProvider) ReadDataDiff( 270 info *terraform.InstanceInfo, 271 c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { 272 var resp ResourceProviderReadDataDiffResponse 273 args := &ResourceProviderReadDataDiffArgs{ 274 Info: info, 275 Config: c, 276 } 277 278 err := p.Client.Call("Plugin.ReadDataDiff", args, &resp) 279 if err != nil { 280 return nil, err 281 } 282 if resp.Error != nil { 283 err = resp.Error 284 } 285 286 return resp.Diff, err 287 } 288 289 func (p *ResourceProvider) ReadDataApply( 290 info *terraform.InstanceInfo, 291 d *terraform.InstanceDiff) (*terraform.InstanceState, error) { 292 var resp ResourceProviderReadDataApplyResponse 293 args := &ResourceProviderReadDataApplyArgs{ 294 Info: info, 295 Diff: d, 296 } 297 298 err := p.Client.Call("Plugin.ReadDataApply", args, &resp) 299 if err != nil { 300 return nil, err 301 } 302 if resp.Error != nil { 303 err = resp.Error 304 } 305 306 return resp.State, err 307 } 308 309 func (p *ResourceProvider) DataSources() []terraform.DataSource { 310 var result []terraform.DataSource 311 312 err := p.Client.Call("Plugin.DataSources", new(interface{}), &result) 313 if err != nil { 314 // TODO: panic, log, what? 315 return nil 316 } 317 318 return result 319 } 320 321 func (p *ResourceProvider) Close() error { 322 return p.Client.Close() 323 } 324 325 // ResourceProviderServer is a net/rpc compatible structure for serving 326 // a ResourceProvider. This should not be used directly. 327 type ResourceProviderServer struct { 328 Broker *plugin.MuxBroker 329 Provider terraform.ResourceProvider 330 } 331 332 type ResourceProviderStopResponse struct { 333 Error *plugin.BasicError 334 } 335 336 type ResourceProviderGetSchemaArgs struct { 337 Req *terraform.ProviderSchemaRequest 338 } 339 340 type ResourceProviderGetSchemaResponse struct { 341 Schema *terraform.ProviderSchema 342 Error *plugin.BasicError 343 } 344 345 type ResourceProviderConfigureResponse struct { 346 Error *plugin.BasicError 347 } 348 349 type ResourceProviderInputArgs struct { 350 InputId uint32 351 Config *terraform.ResourceConfig 352 } 353 354 type ResourceProviderInputResponse struct { 355 Config *terraform.ResourceConfig 356 Error *plugin.BasicError 357 } 358 359 type ResourceProviderApplyArgs struct { 360 Info *terraform.InstanceInfo 361 State *terraform.InstanceState 362 Diff *terraform.InstanceDiff 363 } 364 365 type ResourceProviderApplyResponse struct { 366 State *terraform.InstanceState 367 Error *plugin.BasicError 368 } 369 370 type ResourceProviderDiffArgs struct { 371 Info *terraform.InstanceInfo 372 State *terraform.InstanceState 373 Config *terraform.ResourceConfig 374 } 375 376 type ResourceProviderDiffResponse struct { 377 Diff *terraform.InstanceDiff 378 Error *plugin.BasicError 379 } 380 381 type ResourceProviderRefreshArgs struct { 382 Info *terraform.InstanceInfo 383 State *terraform.InstanceState 384 } 385 386 type ResourceProviderRefreshResponse struct { 387 State *terraform.InstanceState 388 Error *plugin.BasicError 389 } 390 391 type ResourceProviderImportStateArgs struct { 392 Info *terraform.InstanceInfo 393 Id string 394 } 395 396 type ResourceProviderImportStateResponse struct { 397 State []*terraform.InstanceState 398 Error *plugin.BasicError 399 } 400 401 type ResourceProviderReadDataApplyArgs struct { 402 Info *terraform.InstanceInfo 403 Diff *terraform.InstanceDiff 404 } 405 406 type ResourceProviderReadDataApplyResponse struct { 407 State *terraform.InstanceState 408 Error *plugin.BasicError 409 } 410 411 type ResourceProviderReadDataDiffArgs struct { 412 Info *terraform.InstanceInfo 413 Config *terraform.ResourceConfig 414 } 415 416 type ResourceProviderReadDataDiffResponse struct { 417 Diff *terraform.InstanceDiff 418 Error *plugin.BasicError 419 } 420 421 type ResourceProviderValidateArgs struct { 422 Config *terraform.ResourceConfig 423 } 424 425 type ResourceProviderValidateResponse struct { 426 Warnings []string 427 Errors []*plugin.BasicError 428 } 429 430 type ResourceProviderValidateResourceArgs struct { 431 Config *terraform.ResourceConfig 432 Type string 433 } 434 435 type ResourceProviderValidateResourceResponse struct { 436 Warnings []string 437 Errors []*plugin.BasicError 438 } 439 440 func (s *ResourceProviderServer) Stop( 441 _ interface{}, 442 reply *ResourceProviderStopResponse) error { 443 err := s.Provider.Stop() 444 *reply = ResourceProviderStopResponse{ 445 Error: plugin.NewBasicError(err), 446 } 447 448 return nil 449 } 450 451 func (s *ResourceProviderServer) GetSchema( 452 args *ResourceProviderGetSchemaArgs, 453 result *ResourceProviderGetSchemaResponse, 454 ) error { 455 schema, err := s.Provider.GetSchema(args.Req) 456 result.Schema = schema 457 if err != nil { 458 result.Error = plugin.NewBasicError(err) 459 } 460 return nil 461 } 462 463 func (s *ResourceProviderServer) Input( 464 args *ResourceProviderInputArgs, 465 reply *ResourceProviderInputResponse) error { 466 conn, err := s.Broker.Dial(args.InputId) 467 if err != nil { 468 *reply = ResourceProviderInputResponse{ 469 Error: plugin.NewBasicError(err), 470 } 471 return nil 472 } 473 client := rpc.NewClient(conn) 474 defer client.Close() 475 476 input := &UIInput{Client: client} 477 478 config, err := s.Provider.Input(input, args.Config) 479 *reply = ResourceProviderInputResponse{ 480 Config: config, 481 Error: plugin.NewBasicError(err), 482 } 483 484 return nil 485 } 486 487 func (s *ResourceProviderServer) Validate( 488 args *ResourceProviderValidateArgs, 489 reply *ResourceProviderValidateResponse) error { 490 warns, errs := s.Provider.Validate(args.Config) 491 berrs := make([]*plugin.BasicError, len(errs)) 492 for i, err := range errs { 493 berrs[i] = plugin.NewBasicError(err) 494 } 495 *reply = ResourceProviderValidateResponse{ 496 Warnings: warns, 497 Errors: berrs, 498 } 499 return nil 500 } 501 502 func (s *ResourceProviderServer) ValidateResource( 503 args *ResourceProviderValidateResourceArgs, 504 reply *ResourceProviderValidateResourceResponse) error { 505 warns, errs := s.Provider.ValidateResource(args.Type, args.Config) 506 berrs := make([]*plugin.BasicError, len(errs)) 507 for i, err := range errs { 508 berrs[i] = plugin.NewBasicError(err) 509 } 510 *reply = ResourceProviderValidateResourceResponse{ 511 Warnings: warns, 512 Errors: berrs, 513 } 514 return nil 515 } 516 517 func (s *ResourceProviderServer) Configure( 518 config *terraform.ResourceConfig, 519 reply *ResourceProviderConfigureResponse) error { 520 err := s.Provider.Configure(config) 521 *reply = ResourceProviderConfigureResponse{ 522 Error: plugin.NewBasicError(err), 523 } 524 return nil 525 } 526 527 func (s *ResourceProviderServer) Apply( 528 args *ResourceProviderApplyArgs, 529 result *ResourceProviderApplyResponse) error { 530 state, err := s.Provider.Apply(args.Info, args.State, args.Diff) 531 *result = ResourceProviderApplyResponse{ 532 State: state, 533 Error: plugin.NewBasicError(err), 534 } 535 return nil 536 } 537 538 func (s *ResourceProviderServer) Diff( 539 args *ResourceProviderDiffArgs, 540 result *ResourceProviderDiffResponse) error { 541 diff, err := s.Provider.Diff(args.Info, args.State, args.Config) 542 *result = ResourceProviderDiffResponse{ 543 Diff: diff, 544 Error: plugin.NewBasicError(err), 545 } 546 return nil 547 } 548 549 func (s *ResourceProviderServer) Refresh( 550 args *ResourceProviderRefreshArgs, 551 result *ResourceProviderRefreshResponse) error { 552 newState, err := s.Provider.Refresh(args.Info, args.State) 553 *result = ResourceProviderRefreshResponse{ 554 State: newState, 555 Error: plugin.NewBasicError(err), 556 } 557 return nil 558 } 559 560 func (s *ResourceProviderServer) ImportState( 561 args *ResourceProviderImportStateArgs, 562 result *ResourceProviderImportStateResponse) error { 563 states, err := s.Provider.ImportState(args.Info, args.Id) 564 *result = ResourceProviderImportStateResponse{ 565 State: states, 566 Error: plugin.NewBasicError(err), 567 } 568 return nil 569 } 570 571 func (s *ResourceProviderServer) Resources( 572 nothing interface{}, 573 result *[]terraform.ResourceType) error { 574 *result = s.Provider.Resources() 575 return nil 576 } 577 578 func (s *ResourceProviderServer) ValidateDataSource( 579 args *ResourceProviderValidateResourceArgs, 580 reply *ResourceProviderValidateResourceResponse) error { 581 warns, errs := s.Provider.ValidateDataSource(args.Type, args.Config) 582 berrs := make([]*plugin.BasicError, len(errs)) 583 for i, err := range errs { 584 berrs[i] = plugin.NewBasicError(err) 585 } 586 *reply = ResourceProviderValidateResourceResponse{ 587 Warnings: warns, 588 Errors: berrs, 589 } 590 return nil 591 } 592 593 func (s *ResourceProviderServer) ReadDataDiff( 594 args *ResourceProviderReadDataDiffArgs, 595 result *ResourceProviderReadDataDiffResponse) error { 596 diff, err := s.Provider.ReadDataDiff(args.Info, args.Config) 597 *result = ResourceProviderReadDataDiffResponse{ 598 Diff: diff, 599 Error: plugin.NewBasicError(err), 600 } 601 return nil 602 } 603 604 func (s *ResourceProviderServer) ReadDataApply( 605 args *ResourceProviderReadDataApplyArgs, 606 result *ResourceProviderReadDataApplyResponse) error { 607 newState, err := s.Provider.ReadDataApply(args.Info, args.Diff) 608 *result = ResourceProviderReadDataApplyResponse{ 609 State: newState, 610 Error: plugin.NewBasicError(err), 611 } 612 return nil 613 } 614 615 func (s *ResourceProviderServer) DataSources( 616 nothing interface{}, 617 result *[]terraform.DataSource) error { 618 *result = s.Provider.DataSources() 619 return nil 620 }