github.com/skyscape-cloud-services/terraform@v0.9.2-0.20170609144644-7ece028a1747/terraform/shadow_resource_provider.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 "log" 6 "sync" 7 8 "github.com/hashicorp/go-multierror" 9 "github.com/hashicorp/terraform/helper/shadow" 10 ) 11 12 // shadowResourceProvider implements ResourceProvider for the shadow 13 // eval context defined in eval_context_shadow.go. 14 // 15 // This is used to verify behavior with a real provider. This shouldn't 16 // be used directly. 17 type shadowResourceProvider interface { 18 ResourceProvider 19 Shadow 20 } 21 22 // newShadowResourceProvider creates a new shadowed ResourceProvider. 23 // 24 // This will assume a well behaved real ResourceProvider. For example, 25 // it assumes that the `Resources` call underneath doesn't change values 26 // since once it is called on the real provider, it will be cached and 27 // returned in the shadow since number of calls to that shouldn't affect 28 // actual behavior. 29 // 30 // However, with calls like Apply, call order is taken into account, 31 // parameters are checked for equality, etc. 32 func newShadowResourceProvider(p ResourceProvider) (ResourceProvider, shadowResourceProvider) { 33 // Create the shared data 34 shared := shadowResourceProviderShared{} 35 36 // Create the real provider that does actual work 37 real := &shadowResourceProviderReal{ 38 ResourceProvider: p, 39 Shared: &shared, 40 } 41 42 // Create the shadow that watches the real value 43 shadow := &shadowResourceProviderShadow{ 44 Shared: &shared, 45 46 resources: p.Resources(), 47 dataSources: p.DataSources(), 48 } 49 50 return real, shadow 51 } 52 53 // shadowResourceProviderReal is the real resource provider. Function calls 54 // to this will perform real work. This records the parameters and return 55 // values and call order for the shadow to reproduce. 56 type shadowResourceProviderReal struct { 57 ResourceProvider 58 59 Shared *shadowResourceProviderShared 60 } 61 62 func (p *shadowResourceProviderReal) Close() error { 63 var result error 64 if c, ok := p.ResourceProvider.(ResourceProviderCloser); ok { 65 result = c.Close() 66 } 67 68 p.Shared.CloseErr.SetValue(result) 69 return result 70 } 71 72 func (p *shadowResourceProviderReal) Input( 73 input UIInput, c *ResourceConfig) (*ResourceConfig, error) { 74 cCopy := c.DeepCopy() 75 76 result, err := p.ResourceProvider.Input(input, c) 77 p.Shared.Input.SetValue(&shadowResourceProviderInput{ 78 Config: cCopy, 79 Result: result.DeepCopy(), 80 ResultErr: err, 81 }) 82 83 return result, err 84 } 85 86 func (p *shadowResourceProviderReal) Validate(c *ResourceConfig) ([]string, []error) { 87 warns, errs := p.ResourceProvider.Validate(c) 88 p.Shared.Validate.SetValue(&shadowResourceProviderValidate{ 89 Config: c.DeepCopy(), 90 ResultWarn: warns, 91 ResultErr: errs, 92 }) 93 94 return warns, errs 95 } 96 97 func (p *shadowResourceProviderReal) Configure(c *ResourceConfig) error { 98 cCopy := c.DeepCopy() 99 100 err := p.ResourceProvider.Configure(c) 101 p.Shared.Configure.SetValue(&shadowResourceProviderConfigure{ 102 Config: cCopy, 103 Result: err, 104 }) 105 106 return err 107 } 108 109 func (p *shadowResourceProviderReal) Stop() error { 110 return p.ResourceProvider.Stop() 111 } 112 113 func (p *shadowResourceProviderReal) ValidateResource( 114 t string, c *ResourceConfig) ([]string, []error) { 115 key := t 116 configCopy := c.DeepCopy() 117 118 // Real operation 119 warns, errs := p.ResourceProvider.ValidateResource(t, c) 120 121 // Initialize to ensure we always have a wrapper with a lock 122 p.Shared.ValidateResource.Init( 123 key, &shadowResourceProviderValidateResourceWrapper{}) 124 125 // Get the result 126 raw := p.Shared.ValidateResource.Value(key) 127 wrapper, ok := raw.(*shadowResourceProviderValidateResourceWrapper) 128 if !ok { 129 // If this fails then we just continue with our day... the shadow 130 // will fail to but there isn't much we can do. 131 log.Printf( 132 "[ERROR] unknown value in ValidateResource shadow value: %#v", raw) 133 return warns, errs 134 } 135 136 // Lock the wrapper for writing and record our call 137 wrapper.Lock() 138 defer wrapper.Unlock() 139 140 wrapper.Calls = append(wrapper.Calls, &shadowResourceProviderValidateResource{ 141 Config: configCopy, 142 Warns: warns, 143 Errors: errs, 144 }) 145 146 // With it locked, call SetValue again so that it triggers WaitForChange 147 p.Shared.ValidateResource.SetValue(key, wrapper) 148 149 // Return the result 150 return warns, errs 151 } 152 153 func (p *shadowResourceProviderReal) Apply( 154 info *InstanceInfo, 155 state *InstanceState, 156 diff *InstanceDiff) (*InstanceState, error) { 157 // Thse have to be copied before the call since call can modify 158 stateCopy := state.DeepCopy() 159 diffCopy := diff.DeepCopy() 160 161 result, err := p.ResourceProvider.Apply(info, state, diff) 162 p.Shared.Apply.SetValue(info.uniqueId(), &shadowResourceProviderApply{ 163 State: stateCopy, 164 Diff: diffCopy, 165 Result: result.DeepCopy(), 166 ResultErr: err, 167 }) 168 169 return result, err 170 } 171 172 func (p *shadowResourceProviderReal) Diff( 173 info *InstanceInfo, 174 state *InstanceState, 175 desired *ResourceConfig) (*InstanceDiff, error) { 176 // Thse have to be copied before the call since call can modify 177 stateCopy := state.DeepCopy() 178 desiredCopy := desired.DeepCopy() 179 180 result, err := p.ResourceProvider.Diff(info, state, desired) 181 p.Shared.Diff.SetValue(info.uniqueId(), &shadowResourceProviderDiff{ 182 State: stateCopy, 183 Desired: desiredCopy, 184 Result: result.DeepCopy(), 185 ResultErr: err, 186 }) 187 188 return result, err 189 } 190 191 func (p *shadowResourceProviderReal) Refresh( 192 info *InstanceInfo, 193 state *InstanceState) (*InstanceState, error) { 194 // Thse have to be copied before the call since call can modify 195 stateCopy := state.DeepCopy() 196 197 result, err := p.ResourceProvider.Refresh(info, state) 198 p.Shared.Refresh.SetValue(info.uniqueId(), &shadowResourceProviderRefresh{ 199 State: stateCopy, 200 Result: result.DeepCopy(), 201 ResultErr: err, 202 }) 203 204 return result, err 205 } 206 207 func (p *shadowResourceProviderReal) ValidateDataSource( 208 t string, c *ResourceConfig) ([]string, []error) { 209 key := t 210 configCopy := c.DeepCopy() 211 212 // Real operation 213 warns, errs := p.ResourceProvider.ValidateDataSource(t, c) 214 215 // Initialize 216 p.Shared.ValidateDataSource.Init( 217 key, &shadowResourceProviderValidateDataSourceWrapper{}) 218 219 // Get the result 220 raw := p.Shared.ValidateDataSource.Value(key) 221 wrapper, ok := raw.(*shadowResourceProviderValidateDataSourceWrapper) 222 if !ok { 223 // If this fails then we just continue with our day... the shadow 224 // will fail to but there isn't much we can do. 225 log.Printf( 226 "[ERROR] unknown value in ValidateDataSource shadow value: %#v", raw) 227 return warns, errs 228 } 229 230 // Lock the wrapper for writing and record our call 231 wrapper.Lock() 232 defer wrapper.Unlock() 233 234 wrapper.Calls = append(wrapper.Calls, &shadowResourceProviderValidateDataSource{ 235 Config: configCopy, 236 Warns: warns, 237 Errors: errs, 238 }) 239 240 // Set it 241 p.Shared.ValidateDataSource.SetValue(key, wrapper) 242 243 // Return the result 244 return warns, errs 245 } 246 247 func (p *shadowResourceProviderReal) ReadDataDiff( 248 info *InstanceInfo, 249 desired *ResourceConfig) (*InstanceDiff, error) { 250 // These have to be copied before the call since call can modify 251 desiredCopy := desired.DeepCopy() 252 253 result, err := p.ResourceProvider.ReadDataDiff(info, desired) 254 p.Shared.ReadDataDiff.SetValue(info.uniqueId(), &shadowResourceProviderReadDataDiff{ 255 Desired: desiredCopy, 256 Result: result.DeepCopy(), 257 ResultErr: err, 258 }) 259 260 return result, err 261 } 262 263 func (p *shadowResourceProviderReal) ReadDataApply( 264 info *InstanceInfo, 265 diff *InstanceDiff) (*InstanceState, error) { 266 // Thse have to be copied before the call since call can modify 267 diffCopy := diff.DeepCopy() 268 269 result, err := p.ResourceProvider.ReadDataApply(info, diff) 270 p.Shared.ReadDataApply.SetValue(info.uniqueId(), &shadowResourceProviderReadDataApply{ 271 Diff: diffCopy, 272 Result: result.DeepCopy(), 273 ResultErr: err, 274 }) 275 276 return result, err 277 } 278 279 // shadowResourceProviderShadow is the shadow resource provider. Function 280 // calls never affect real resources. This is paired with the "real" side 281 // which must be called properly to enable recording. 282 type shadowResourceProviderShadow struct { 283 Shared *shadowResourceProviderShared 284 285 // Cached values that are expected to not change 286 resources []ResourceType 287 dataSources []DataSource 288 289 Error error // Error is the list of errors from the shadow 290 ErrorLock sync.Mutex 291 } 292 293 type shadowResourceProviderShared struct { 294 // NOTE: Anytime a value is added here, be sure to add it to 295 // the Close() method so that it is closed. 296 297 CloseErr shadow.Value 298 Input shadow.Value 299 Validate shadow.Value 300 Configure shadow.Value 301 ValidateResource shadow.KeyedValue 302 Apply shadow.KeyedValue 303 Diff shadow.KeyedValue 304 Refresh shadow.KeyedValue 305 ValidateDataSource shadow.KeyedValue 306 ReadDataDiff shadow.KeyedValue 307 ReadDataApply shadow.KeyedValue 308 } 309 310 func (p *shadowResourceProviderShared) Close() error { 311 return shadow.Close(p) 312 } 313 314 func (p *shadowResourceProviderShadow) CloseShadow() error { 315 err := p.Shared.Close() 316 if err != nil { 317 err = fmt.Errorf("close error: %s", err) 318 } 319 320 return err 321 } 322 323 func (p *shadowResourceProviderShadow) ShadowError() error { 324 return p.Error 325 } 326 327 func (p *shadowResourceProviderShadow) Resources() []ResourceType { 328 return p.resources 329 } 330 331 func (p *shadowResourceProviderShadow) DataSources() []DataSource { 332 return p.dataSources 333 } 334 335 func (p *shadowResourceProviderShadow) Close() error { 336 v := p.Shared.CloseErr.Value() 337 if v == nil { 338 return nil 339 } 340 341 return v.(error) 342 } 343 344 func (p *shadowResourceProviderShadow) Input( 345 input UIInput, c *ResourceConfig) (*ResourceConfig, error) { 346 // Get the result of the input call 347 raw := p.Shared.Input.Value() 348 if raw == nil { 349 return nil, nil 350 } 351 352 result, ok := raw.(*shadowResourceProviderInput) 353 if !ok { 354 p.ErrorLock.Lock() 355 defer p.ErrorLock.Unlock() 356 p.Error = multierror.Append(p.Error, fmt.Errorf( 357 "Unknown 'input' shadow value: %#v", raw)) 358 return nil, nil 359 } 360 361 // Compare the parameters, which should be identical 362 if !c.Equal(result.Config) { 363 p.ErrorLock.Lock() 364 p.Error = multierror.Append(p.Error, fmt.Errorf( 365 "Input had unequal configurations (real, then shadow):\n\n%#v\n\n%#v", 366 result.Config, c)) 367 p.ErrorLock.Unlock() 368 } 369 370 // Return the results 371 return result.Result, result.ResultErr 372 } 373 374 func (p *shadowResourceProviderShadow) Validate(c *ResourceConfig) ([]string, []error) { 375 // Get the result of the validate call 376 raw := p.Shared.Validate.Value() 377 if raw == nil { 378 return nil, nil 379 } 380 381 result, ok := raw.(*shadowResourceProviderValidate) 382 if !ok { 383 p.ErrorLock.Lock() 384 defer p.ErrorLock.Unlock() 385 p.Error = multierror.Append(p.Error, fmt.Errorf( 386 "Unknown 'validate' shadow value: %#v", raw)) 387 return nil, nil 388 } 389 390 // Compare the parameters, which should be identical 391 if !c.Equal(result.Config) { 392 p.ErrorLock.Lock() 393 p.Error = multierror.Append(p.Error, fmt.Errorf( 394 "Validate had unequal configurations (real, then shadow):\n\n%#v\n\n%#v", 395 result.Config, c)) 396 p.ErrorLock.Unlock() 397 } 398 399 // Return the results 400 return result.ResultWarn, result.ResultErr 401 } 402 403 func (p *shadowResourceProviderShadow) Configure(c *ResourceConfig) error { 404 // Get the result of the call 405 raw := p.Shared.Configure.Value() 406 if raw == nil { 407 return nil 408 } 409 410 result, ok := raw.(*shadowResourceProviderConfigure) 411 if !ok { 412 p.ErrorLock.Lock() 413 defer p.ErrorLock.Unlock() 414 p.Error = multierror.Append(p.Error, fmt.Errorf( 415 "Unknown 'configure' shadow value: %#v", raw)) 416 return nil 417 } 418 419 // Compare the parameters, which should be identical 420 if !c.Equal(result.Config) { 421 p.ErrorLock.Lock() 422 p.Error = multierror.Append(p.Error, fmt.Errorf( 423 "Configure had unequal configurations (real, then shadow):\n\n%#v\n\n%#v", 424 result.Config, c)) 425 p.ErrorLock.Unlock() 426 } 427 428 // Return the results 429 return result.Result 430 } 431 432 // Stop returns immediately. 433 func (p *shadowResourceProviderShadow) Stop() error { 434 return nil 435 } 436 437 func (p *shadowResourceProviderShadow) ValidateResource(t string, c *ResourceConfig) ([]string, []error) { 438 // Unique key 439 key := t 440 441 // Get the initial value 442 raw := p.Shared.ValidateResource.Value(key) 443 444 // Find a validation with our configuration 445 var result *shadowResourceProviderValidateResource 446 for { 447 // Get the value 448 if raw == nil { 449 p.ErrorLock.Lock() 450 defer p.ErrorLock.Unlock() 451 p.Error = multierror.Append(p.Error, fmt.Errorf( 452 "Unknown 'ValidateResource' call for %q:\n\n%#v", 453 key, c)) 454 return nil, nil 455 } 456 457 wrapper, ok := raw.(*shadowResourceProviderValidateResourceWrapper) 458 if !ok { 459 p.ErrorLock.Lock() 460 defer p.ErrorLock.Unlock() 461 p.Error = multierror.Append(p.Error, fmt.Errorf( 462 "Unknown 'ValidateResource' shadow value for %q: %#v", key, raw)) 463 return nil, nil 464 } 465 466 // Look for the matching call with our configuration 467 wrapper.RLock() 468 for _, call := range wrapper.Calls { 469 if call.Config.Equal(c) { 470 result = call 471 break 472 } 473 } 474 wrapper.RUnlock() 475 476 // If we found a result, exit 477 if result != nil { 478 break 479 } 480 481 // Wait for a change so we can get the wrapper again 482 raw = p.Shared.ValidateResource.WaitForChange(key) 483 } 484 485 return result.Warns, result.Errors 486 } 487 488 func (p *shadowResourceProviderShadow) Apply( 489 info *InstanceInfo, 490 state *InstanceState, 491 diff *InstanceDiff) (*InstanceState, error) { 492 // Unique key 493 key := info.uniqueId() 494 raw := p.Shared.Apply.Value(key) 495 if raw == nil { 496 p.ErrorLock.Lock() 497 defer p.ErrorLock.Unlock() 498 p.Error = multierror.Append(p.Error, fmt.Errorf( 499 "Unknown 'apply' call for %q:\n\n%#v\n\n%#v", 500 key, state, diff)) 501 return nil, nil 502 } 503 504 result, ok := raw.(*shadowResourceProviderApply) 505 if !ok { 506 p.ErrorLock.Lock() 507 defer p.ErrorLock.Unlock() 508 p.Error = multierror.Append(p.Error, fmt.Errorf( 509 "Unknown 'apply' shadow value for %q: %#v", key, raw)) 510 return nil, nil 511 } 512 513 // Compare the parameters, which should be identical 514 if !state.Equal(result.State) { 515 p.ErrorLock.Lock() 516 p.Error = multierror.Append(p.Error, fmt.Errorf( 517 "Apply %q: state had unequal states (real, then shadow):\n\n%#v\n\n%#v", 518 key, result.State, state)) 519 p.ErrorLock.Unlock() 520 } 521 522 if !diff.Equal(result.Diff) { 523 p.ErrorLock.Lock() 524 p.Error = multierror.Append(p.Error, fmt.Errorf( 525 "Apply %q: unequal diffs (real, then shadow):\n\n%#v\n\n%#v", 526 key, result.Diff, diff)) 527 p.ErrorLock.Unlock() 528 } 529 530 return result.Result, result.ResultErr 531 } 532 533 func (p *shadowResourceProviderShadow) Diff( 534 info *InstanceInfo, 535 state *InstanceState, 536 desired *ResourceConfig) (*InstanceDiff, error) { 537 // Unique key 538 key := info.uniqueId() 539 raw := p.Shared.Diff.Value(key) 540 if raw == nil { 541 p.ErrorLock.Lock() 542 defer p.ErrorLock.Unlock() 543 p.Error = multierror.Append(p.Error, fmt.Errorf( 544 "Unknown 'diff' call for %q:\n\n%#v\n\n%#v", 545 key, state, desired)) 546 return nil, nil 547 } 548 549 result, ok := raw.(*shadowResourceProviderDiff) 550 if !ok { 551 p.ErrorLock.Lock() 552 defer p.ErrorLock.Unlock() 553 p.Error = multierror.Append(p.Error, fmt.Errorf( 554 "Unknown 'diff' shadow value for %q: %#v", key, raw)) 555 return nil, nil 556 } 557 558 // Compare the parameters, which should be identical 559 if !state.Equal(result.State) { 560 p.ErrorLock.Lock() 561 p.Error = multierror.Append(p.Error, fmt.Errorf( 562 "Diff %q had unequal states (real, then shadow):\n\n%#v\n\n%#v", 563 key, result.State, state)) 564 p.ErrorLock.Unlock() 565 } 566 if !desired.Equal(result.Desired) { 567 p.ErrorLock.Lock() 568 p.Error = multierror.Append(p.Error, fmt.Errorf( 569 "Diff %q had unequal states (real, then shadow):\n\n%#v\n\n%#v", 570 key, result.Desired, desired)) 571 p.ErrorLock.Unlock() 572 } 573 574 return result.Result, result.ResultErr 575 } 576 577 func (p *shadowResourceProviderShadow) Refresh( 578 info *InstanceInfo, 579 state *InstanceState) (*InstanceState, error) { 580 // Unique key 581 key := info.uniqueId() 582 raw := p.Shared.Refresh.Value(key) 583 if raw == nil { 584 p.ErrorLock.Lock() 585 defer p.ErrorLock.Unlock() 586 p.Error = multierror.Append(p.Error, fmt.Errorf( 587 "Unknown 'refresh' call for %q:\n\n%#v", 588 key, state)) 589 return nil, nil 590 } 591 592 result, ok := raw.(*shadowResourceProviderRefresh) 593 if !ok { 594 p.ErrorLock.Lock() 595 defer p.ErrorLock.Unlock() 596 p.Error = multierror.Append(p.Error, fmt.Errorf( 597 "Unknown 'refresh' shadow value: %#v", raw)) 598 return nil, nil 599 } 600 601 // Compare the parameters, which should be identical 602 if !state.Equal(result.State) { 603 p.ErrorLock.Lock() 604 p.Error = multierror.Append(p.Error, fmt.Errorf( 605 "Refresh %q had unequal states (real, then shadow):\n\n%#v\n\n%#v", 606 key, result.State, state)) 607 p.ErrorLock.Unlock() 608 } 609 610 return result.Result, result.ResultErr 611 } 612 613 func (p *shadowResourceProviderShadow) ValidateDataSource( 614 t string, c *ResourceConfig) ([]string, []error) { 615 // Unique key 616 key := t 617 618 // Get the initial value 619 raw := p.Shared.ValidateDataSource.Value(key) 620 621 // Find a validation with our configuration 622 var result *shadowResourceProviderValidateDataSource 623 for { 624 // Get the value 625 if raw == nil { 626 p.ErrorLock.Lock() 627 defer p.ErrorLock.Unlock() 628 p.Error = multierror.Append(p.Error, fmt.Errorf( 629 "Unknown 'ValidateDataSource' call for %q:\n\n%#v", 630 key, c)) 631 return nil, nil 632 } 633 634 wrapper, ok := raw.(*shadowResourceProviderValidateDataSourceWrapper) 635 if !ok { 636 p.ErrorLock.Lock() 637 defer p.ErrorLock.Unlock() 638 p.Error = multierror.Append(p.Error, fmt.Errorf( 639 "Unknown 'ValidateDataSource' shadow value: %#v", raw)) 640 return nil, nil 641 } 642 643 // Look for the matching call with our configuration 644 wrapper.RLock() 645 for _, call := range wrapper.Calls { 646 if call.Config.Equal(c) { 647 result = call 648 break 649 } 650 } 651 wrapper.RUnlock() 652 653 // If we found a result, exit 654 if result != nil { 655 break 656 } 657 658 // Wait for a change so we can get the wrapper again 659 raw = p.Shared.ValidateDataSource.WaitForChange(key) 660 } 661 662 return result.Warns, result.Errors 663 } 664 665 func (p *shadowResourceProviderShadow) ReadDataDiff( 666 info *InstanceInfo, 667 desired *ResourceConfig) (*InstanceDiff, error) { 668 // Unique key 669 key := info.uniqueId() 670 raw := p.Shared.ReadDataDiff.Value(key) 671 if raw == nil { 672 p.ErrorLock.Lock() 673 defer p.ErrorLock.Unlock() 674 p.Error = multierror.Append(p.Error, fmt.Errorf( 675 "Unknown 'ReadDataDiff' call for %q:\n\n%#v", 676 key, desired)) 677 return nil, nil 678 } 679 680 result, ok := raw.(*shadowResourceProviderReadDataDiff) 681 if !ok { 682 p.ErrorLock.Lock() 683 defer p.ErrorLock.Unlock() 684 p.Error = multierror.Append(p.Error, fmt.Errorf( 685 "Unknown 'ReadDataDiff' shadow value for %q: %#v", key, raw)) 686 return nil, nil 687 } 688 689 // Compare the parameters, which should be identical 690 if !desired.Equal(result.Desired) { 691 p.ErrorLock.Lock() 692 p.Error = multierror.Append(p.Error, fmt.Errorf( 693 "ReadDataDiff %q had unequal configs (real, then shadow):\n\n%#v\n\n%#v", 694 key, result.Desired, desired)) 695 p.ErrorLock.Unlock() 696 } 697 698 return result.Result, result.ResultErr 699 } 700 701 func (p *shadowResourceProviderShadow) ReadDataApply( 702 info *InstanceInfo, 703 d *InstanceDiff) (*InstanceState, error) { 704 // Unique key 705 key := info.uniqueId() 706 raw := p.Shared.ReadDataApply.Value(key) 707 if raw == nil { 708 p.ErrorLock.Lock() 709 defer p.ErrorLock.Unlock() 710 p.Error = multierror.Append(p.Error, fmt.Errorf( 711 "Unknown 'ReadDataApply' call for %q:\n\n%#v", 712 key, d)) 713 return nil, nil 714 } 715 716 result, ok := raw.(*shadowResourceProviderReadDataApply) 717 if !ok { 718 p.ErrorLock.Lock() 719 defer p.ErrorLock.Unlock() 720 p.Error = multierror.Append(p.Error, fmt.Errorf( 721 "Unknown 'ReadDataApply' shadow value for %q: %#v", key, raw)) 722 return nil, nil 723 } 724 725 // Compare the parameters, which should be identical 726 if !d.Equal(result.Diff) { 727 p.ErrorLock.Lock() 728 p.Error = multierror.Append(p.Error, fmt.Errorf( 729 "ReadDataApply: unequal diffs (real, then shadow):\n\n%#v\n\n%#v", 730 result.Diff, d)) 731 p.ErrorLock.Unlock() 732 } 733 734 return result.Result, result.ResultErr 735 } 736 737 func (p *shadowResourceProviderShadow) ImportState(info *InstanceInfo, id string) ([]*InstanceState, error) { 738 panic("import not supported by shadow graph") 739 } 740 741 // The structs for the various function calls are put below. These structs 742 // are used to carry call information across the real/shadow boundaries. 743 744 type shadowResourceProviderInput struct { 745 Config *ResourceConfig 746 Result *ResourceConfig 747 ResultErr error 748 } 749 750 type shadowResourceProviderValidate struct { 751 Config *ResourceConfig 752 ResultWarn []string 753 ResultErr []error 754 } 755 756 type shadowResourceProviderConfigure struct { 757 Config *ResourceConfig 758 Result error 759 } 760 761 type shadowResourceProviderValidateResourceWrapper struct { 762 sync.RWMutex 763 764 Calls []*shadowResourceProviderValidateResource 765 } 766 767 type shadowResourceProviderValidateResource struct { 768 Config *ResourceConfig 769 Warns []string 770 Errors []error 771 } 772 773 type shadowResourceProviderApply struct { 774 State *InstanceState 775 Diff *InstanceDiff 776 Result *InstanceState 777 ResultErr error 778 } 779 780 type shadowResourceProviderDiff struct { 781 State *InstanceState 782 Desired *ResourceConfig 783 Result *InstanceDiff 784 ResultErr error 785 } 786 787 type shadowResourceProviderRefresh struct { 788 State *InstanceState 789 Result *InstanceState 790 ResultErr error 791 } 792 793 type shadowResourceProviderValidateDataSourceWrapper struct { 794 sync.RWMutex 795 796 Calls []*shadowResourceProviderValidateDataSource 797 } 798 799 type shadowResourceProviderValidateDataSource struct { 800 Config *ResourceConfig 801 Warns []string 802 Errors []error 803 } 804 805 type shadowResourceProviderReadDataDiff struct { 806 Desired *ResourceConfig 807 Result *InstanceDiff 808 ResultErr error 809 } 810 811 type shadowResourceProviderReadDataApply struct { 812 Diff *InstanceDiff 813 Result *InstanceState 814 ResultErr error 815 }