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