7 "github.com/hashicorp/go-multierror"
8 "github.com/hashicorp/terraform/helper/shadow"
11 // newShadowComponentFactory creates a shadowed contextComponentFactory
12 // so that requests to create new components result in both a real and
14 func newShadowComponentFactory(
15 f contextComponentFactory) (contextComponentFactory, *shadowComponentFactory) {
16 // Create the shared data
17 shared := &shadowComponentFactoryShared{contextComponentFactory: f}
19 // Create the real side
20 real := &shadowComponentFactory{
21 shadowComponentFactoryShared: shared,
25 shadow := &shadowComponentFactory{
26 shadowComponentFactoryShared: shared,
33 // shadowComponentFactory is the shadow side. Any components created
34 // with this factory are fake and will not cause real work to happen.
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
43 Shadow bool // True if this should return the shadow
47 func (f *shadowComponentFactory) ResourceProvider(
48 n, uid string) (ResourceProvider, error) {
52 real, shadow, err := f.shadowComponentFactoryShared.ResourceProvider(n, uid)
53 var result ResourceProvider = real
61 func (f *shadowComponentFactory) ResourceProvisioner(
62 n, uid string) (ResourceProvisioner, error) {
66 real, shadow, err := f.shadowComponentFactoryShared.ResourceProvisioner(n, uid)
67 var result ResourceProvisioner = real
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
84 // Lock ourselves so we don't modify state
88 // Grab our shared state
89 shared := f.shadowComponentFactoryShared
91 // If we're already closed, its an error
93 return fmt.Errorf("component factory shadow already closed")
96 // Close all the providers and provisioners and return the 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)
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)
116 // Mark ourselves as closed
122 func (f *shadowComponentFactory) ShadowError() error {
123 // If we aren't the shadow, just return
128 // Lock ourselves so we don't modify state
130 defer f.lock.Unlock()
132 // Grab our shared state
133 shared := f.shadowComponentFactoryShared
135 // If we're not closed, its an error
137 return fmt.Errorf("component factory must be closed to retrieve errors")
140 // Close all the providers and provisioners and return the 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)
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)
163 // shadowComponentFactoryShared is shared data between the two factories.
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
171 providers shadow.KeyedValue
172 providerKeys []string
173 provisioners shadow.KeyedValue
174 provisionerKeys []string
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
185 type shadowComponentFactoryProvisionerEntry struct {
186 Real ResourceProvisioner
187 Shadow shadowResourceProvisioner
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)
197 var entry shadowComponentFactoryProviderEntry
199 // No value, initialize. Create the original
200 p, err := f.contextComponentFactory.ResourceProvider(n, uid)
203 p = nil // Just to be sure
208 real, shadow := newShadowResourceProvider(p)
210 entry.Shadow = shadow
218 f.providers.SetValue(uid, &entry)
219 f.providerKeys = append(f.providerKeys, uid)
224 entry, ok := raw.(*shadowComponentFactoryProviderEntry)
226 return nil, nil, fmt.Errorf("Unknown value for shadow provider: %#v", raw)
230 return entry.Real, entry.Shadow, entry.Err
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)
239 var entry shadowComponentFactoryProvisionerEntry
241 // No value, initialize. Create the original
242 p, err := f.contextComponentFactory.ResourceProvisioner(n, uid)
245 p = nil // Just to be sure
249 // For now, just create a mock since we don't support provisioners yet
250 real, shadow := newShadowResourceProvisioner(p)
252 entry.Shadow = shadow
260 f.provisioners.SetValue(uid, &entry)
261 f.provisionerKeys = append(f.provisionerKeys, uid)
266 entry, ok := raw.(*shadowComponentFactoryProvisionerEntry)
268 return nil, nil, fmt.Errorf("Unknown value for shadow provisioner: %#v", raw)
272 return entry.Real, entry.Shadow, entry.Err