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