github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/terraform/shadow_components.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  
     7  	"github.com/hashicorp/go-multierror"
     8  	"github.com/hashicorp/terraform/helper/shadow"
     9  )
    10  
    11  // newShadowComponentFactory creates a shadowed contextComponentFactory
    12  // so that requests to create new components result in both a real and
    13  // shadow side.
    14  func newShadowComponentFactory(
    15  	f contextComponentFactory) (contextComponentFactory, *shadowComponentFactory) {
    16  	// Create the shared data
    17  	shared := &shadowComponentFactoryShared{contextComponentFactory: f}
    18  
    19  	// Create the real side
    20  	real := &shadowComponentFactory{
    21  		shadowComponentFactoryShared: shared,
    22  	}
    23  
    24  	// Create the shadow
    25  	shadow := &shadowComponentFactory{
    26  		shadowComponentFactoryShared: shared,
    27  		Shadow: true,
    28  	}
    29  
    30  	return real, shadow
    31  }
    32  
    33  // shadowComponentFactory is the shadow side. Any components created
    34  // with this factory are fake and will not cause real work to happen.
    35  //
    36  // Unlike other shadowers, the shadow component factory will allow the
    37  // shadow to create _any_ component even if it is never requested on the
    38  // real side. This is because errors will happen later downstream as function
    39  // calls are made to the shadows that are never matched on the real side.
    40  type shadowComponentFactory struct {
    41  	*shadowComponentFactoryShared
    42  
    43  	Shadow bool // True if this should return the shadow
    44  	lock   sync.Mutex
    45  }
    46  
    47  func (f *shadowComponentFactory) ResourceProvider(
    48  	n, uid string) (ResourceProvider, error) {
    49  	f.lock.Lock()
    50  	defer f.lock.Unlock()
    51  
    52  	real, shadow, err := f.shadowComponentFactoryShared.ResourceProvider(n, uid)
    53  	var result ResourceProvider = real
    54  	if f.Shadow {
    55  		result = shadow
    56  	}
    57  
    58  	return result, err
    59  }
    60  
    61  func (f *shadowComponentFactory) ResourceProvisioner(
    62  	n, uid string) (ResourceProvisioner, error) {
    63  	f.lock.Lock()
    64  	defer f.lock.Unlock()
    65  
    66  	real, shadow, err := f.shadowComponentFactoryShared.ResourceProvisioner(n, uid)
    67  	var result ResourceProvisioner = real
    68  	if f.Shadow {
    69  		result = shadow
    70  	}
    71  
    72  	return result, err
    73  }
    74  
    75  // CloseShadow is called when the _real_ side is complete. This will cause
    76  // all future blocking operations to return immediately on the shadow to
    77  // ensure the shadow also completes.
    78  func (f *shadowComponentFactory) CloseShadow() error {
    79  	// If we aren't the shadow, just return
    80  	if !f.Shadow {
    81  		return nil
    82  	}
    83  
    84  	// Lock ourselves so we don't modify state
    85  	f.lock.Lock()
    86  	defer f.lock.Unlock()
    87  
    88  	// Grab our shared state
    89  	shared := f.shadowComponentFactoryShared
    90  
    91  	// If we're already closed, its an error
    92  	if shared.closed {
    93  		return fmt.Errorf("component factory shadow already closed")
    94  	}
    95  
    96  	// Close all the providers and provisioners and return the error
    97  	var result error
    98  	for _, n := range shared.providerKeys {
    99  		_, shadow, err := shared.ResourceProvider(n, n)
   100  		if err == nil && shadow != nil {
   101  			if err := shadow.CloseShadow(); err != nil {
   102  				result = multierror.Append(result, err)
   103  			}
   104  		}
   105  	}
   106  
   107  	for _, n := range shared.provisionerKeys {
   108  		_, shadow, err := shared.ResourceProvisioner(n, n)
   109  		if err == nil && shadow != nil {
   110  			if err := shadow.CloseShadow(); err != nil {
   111  				result = multierror.Append(result, err)
   112  			}
   113  		}
   114  	}
   115  
   116  	// Mark ourselves as closed
   117  	shared.closed = true
   118  
   119  	return result
   120  }
   121  
   122  func (f *shadowComponentFactory) ShadowError() error {
   123  	// If we aren't the shadow, just return
   124  	if !f.Shadow {
   125  		return nil
   126  	}
   127  
   128  	// Lock ourselves so we don't modify state
   129  	f.lock.Lock()
   130  	defer f.lock.Unlock()
   131  
   132  	// Grab our shared state
   133  	shared := f.shadowComponentFactoryShared
   134  
   135  	// If we're not closed, its an error
   136  	if !shared.closed {
   137  		return fmt.Errorf("component factory must be closed to retrieve errors")
   138  	}
   139  
   140  	// Close all the providers and provisioners and return the error
   141  	var result error
   142  	for _, n := range shared.providerKeys {
   143  		_, shadow, err := shared.ResourceProvider(n, n)
   144  		if err == nil && shadow != nil {
   145  			if err := shadow.ShadowError(); err != nil {
   146  				result = multierror.Append(result, err)
   147  			}
   148  		}
   149  	}
   150  
   151  	for _, n := range shared.provisionerKeys {
   152  		_, shadow, err := shared.ResourceProvisioner(n, n)
   153  		if err == nil && shadow != nil {
   154  			if err := shadow.ShadowError(); err != nil {
   155  				result = multierror.Append(result, err)
   156  			}
   157  		}
   158  	}
   159  
   160  	return result
   161  }
   162  
   163  // shadowComponentFactoryShared is shared data between the two factories.
   164  //
   165  // It is NOT SAFE to run any function on this struct in parallel. Lock
   166  // access to this struct.
   167  type shadowComponentFactoryShared struct {
   168  	contextComponentFactory
   169  
   170  	closed          bool
   171  	providers       shadow.KeyedValue
   172  	providerKeys    []string
   173  	provisioners    shadow.KeyedValue
   174  	provisionerKeys []string
   175  }
   176  
   177  // shadowResourceProviderFactoryEntry is the entry that is stored in
   178  // the Shadows key/value for a provider.
   179  type shadowComponentFactoryProviderEntry struct {
   180  	Real   ResourceProvider
   181  	Shadow shadowResourceProvider
   182  	Err    error
   183  }
   184  
   185  type shadowComponentFactoryProvisionerEntry struct {
   186  	Real   ResourceProvisioner
   187  	Shadow shadowResourceProvisioner
   188  	Err    error
   189  }
   190  
   191  func (f *shadowComponentFactoryShared) ResourceProvider(
   192  	n, uid string) (ResourceProvider, shadowResourceProvider, error) {
   193  	// Determine if we already have a value
   194  	raw, ok := f.providers.ValueOk(uid)
   195  	if !ok {
   196  		// Build the entry
   197  		var entry shadowComponentFactoryProviderEntry
   198  
   199  		// No value, initialize. Create the original
   200  		p, err := f.contextComponentFactory.ResourceProvider(n, uid)
   201  		if err != nil {
   202  			entry.Err = err
   203  			p = nil // Just to be sure
   204  		}
   205  
   206  		if p != nil {
   207  			// Create the shadow
   208  			real, shadow := newShadowResourceProvider(p)
   209  			entry.Real = real
   210  			entry.Shadow = shadow
   211  
   212  			if f.closed {
   213  				shadow.CloseShadow()
   214  			}
   215  		}
   216  
   217  		// Store the value
   218  		f.providers.SetValue(uid, &entry)
   219  		f.providerKeys = append(f.providerKeys, uid)
   220  		raw = &entry
   221  	}
   222  
   223  	// Read the entry
   224  	entry, ok := raw.(*shadowComponentFactoryProviderEntry)
   225  	if !ok {
   226  		return nil, nil, fmt.Errorf("Unknown value for shadow provider: %#v", raw)
   227  	}
   228  
   229  	// Return
   230  	return entry.Real, entry.Shadow, entry.Err
   231  }
   232  
   233  func (f *shadowComponentFactoryShared) ResourceProvisioner(
   234  	n, uid string) (ResourceProvisioner, shadowResourceProvisioner, error) {
   235  	// Determine if we already have a value
   236  	raw, ok := f.provisioners.ValueOk(uid)
   237  	if !ok {
   238  		// Build the entry
   239  		var entry shadowComponentFactoryProvisionerEntry
   240  
   241  		// No value, initialize. Create the original
   242  		p, err := f.contextComponentFactory.ResourceProvisioner(n, uid)
   243  		if err != nil {
   244  			entry.Err = err
   245  			p = nil // Just to be sure
   246  		}
   247  
   248  		if p != nil {
   249  			// For now, just create a mock since we don't support provisioners yet
   250  			real, shadow := newShadowResourceProvisioner(p)
   251  			entry.Real = real
   252  			entry.Shadow = shadow
   253  
   254  			if f.closed {
   255  				shadow.CloseShadow()
   256  			}
   257  		}
   258  
   259  		// Store the value
   260  		f.provisioners.SetValue(uid, &entry)
   261  		f.provisionerKeys = append(f.provisionerKeys, uid)
   262  		raw = &entry
   263  	}
   264  
   265  	// Read the entry
   266  	entry, ok := raw.(*shadowComponentFactoryProvisionerEntry)
   267  	if !ok {
   268  		return nil, nil, fmt.Errorf("Unknown value for shadow provisioner: %#v", raw)
   269  	}
   270  
   271  	// Return
   272  	return entry.Real, entry.Shadow, entry.Err
   273  }