6
6
package servicemanager
7
7
8
8
import (
9
+ "encoding/json"
9
10
"reflect"
10
11
"time"
11
12
@@ -48,7 +49,9 @@ func (h *serviceClassEntityHandler) Add(obj entitystore.Entity) (err error) {
48
49
// Update updates service class entities
49
50
func (h * serviceClassEntityHandler ) Update (obj entitystore.Entity ) error {
50
51
defer trace .Trace ("" )()
51
- return errors .Errorf ("ServiceClass is not updateable" )
52
+ sc := obj .(* entities.ServiceClass )
53
+ _ , err := h .Store .Update (sc .Revision , sc )
54
+ return err
52
55
}
53
56
54
57
// Delete removes service class entities
@@ -64,6 +67,24 @@ func (h *serviceClassEntityHandler) Delete(obj entitystore.Entity) error {
64
67
return nil
65
68
}
66
69
70
+ func (h * serviceClassEntityHandler ) needsUpdate (actual * entities.ServiceClass , existing * entities.ServiceClass ) (* entities.ServiceClass , bool ) {
71
+ if actual .Status == entitystore .StatusUNKNOWN {
72
+ return nil , false
73
+ }
74
+ // Keys are sorted, so encoding should produce a comparable result
75
+ actualJSON , _ := json .Marshal (actual .Plans )
76
+ existingJSON , _ := json .Marshal (existing .Plans )
77
+ if string (actualJSON ) != string (existingJSON ) ||
78
+ actual .Status != existing .Status ||
79
+ actual .Bindable != existing .Bindable {
80
+ existing .Status = actual .Status
81
+ existing .Bindable = actual .Bindable
82
+ existing .Plans = actual .Plans
83
+ return existing , true
84
+ }
85
+ return nil , false
86
+ }
87
+
67
88
// Sync reconsiles the actual state from the service catalog with the dispatch state
68
89
func (h * serviceClassEntityHandler ) Sync (organizationID string , resyncPeriod time.Duration ) ([]entitystore.Entity , error ) {
69
90
defer trace .Trace ("" )()
@@ -94,8 +115,9 @@ func (h *serviceClassEntityHandler) Sync(organizationID string, resyncPeriod tim
94
115
class .SetStatus (entitystore .StatusDELETING )
95
116
} else {
96
117
delete (actualMap , class .ServiceID )
97
- if actual .Status == entitystore .StatusUNKNOWN || actual .Status == class .Status {
98
- // If status is unknown or hasn't changed, no need to update
118
+ var ok bool
119
+ class , ok = h .needsUpdate (actual , class )
120
+ if ! ok {
99
121
continue
100
122
}
101
123
}
@@ -151,11 +173,6 @@ func (h *serviceInstanceEntityHandler) Add(obj entitystore.Entity) (err error) {
151
173
if err = h .BrokerClient .CreateService (& sc , si ); err != nil {
152
174
return
153
175
}
154
- if si .Bind {
155
- si .Binding .ServiceInstance = si .Name
156
- log .Debugf ("Adding new service binding %s" , si .Name )
157
- _ , err = h .Store .Add (si .Binding )
158
- }
159
176
return
160
177
}
161
178
@@ -185,6 +202,9 @@ func (h *serviceInstanceEntityHandler) Delete(obj entitystore.Entity) error {
185
202
log .Error (err )
186
203
}
187
204
205
+ // TODO (bjung): We really shoudn't actually delete the entity until the the resource
206
+ // is actually deleted. As-is it works, but we are repeatedly calling delete as the controller
207
+ // thinks the resource has been orphaned (which it has)
188
208
var deleted entities.ServiceInstance
189
209
err = h .Store .Delete (si .GetOrganizationID (), si .GetName (), & deleted )
190
210
if err != nil {
@@ -223,6 +243,14 @@ func (h *serviceInstanceEntityHandler) Sync(organizationID string, resyncPeriod
223
243
synced = append (synced , instance )
224
244
continue
225
245
}
246
+ if instance .Delete {
247
+ // Marked for deletion... ignore actual status - though we need to start tracking
248
+ // actual state separately from desired stated (i.e. marked for delete, but is currently
249
+ // in ready state)
250
+ delete (actualMap , instance .ID )
251
+ synced = append (synced , instance )
252
+ continue
253
+ }
226
254
actual , ok := actualMap [instance .ID ]
227
255
if ! ok {
228
256
instance .SetDelete (true )
@@ -281,14 +309,17 @@ func (h *serviceBindingEntityHandler) Add(obj entitystore.Entity) (err error) {
281
309
defer trace .Trace ("" )()
282
310
b := obj .(* entities.ServiceBinding )
283
311
284
- defer func () { h .Store .UpdateWithError (b , err ) }()
285
-
286
312
var si entities.ServiceInstance
287
- log .Debugf ("Fetching service for name %s" , b .Name )
288
- if err = h .Store .Get (b .OrganizationID , b .Name , entitystore.Options {}, & si ); err != nil {
313
+ log .Debugf ("Fetching service for name %s" , b .ServiceInstance )
314
+ if err = h .Store .Get (b .OrganizationID , b .ServiceInstance , entitystore.Options {}, & si ); err != nil {
289
315
return
290
316
}
291
- log .Debugf ("Got service %s" , si .Name )
317
+ if si .Status != entitystore .StatusREADY {
318
+ log .Debugf ("Service %s not ready for binding %s" , si .Name , si .Status )
319
+ return
320
+ }
321
+ defer func () { h .Store .UpdateWithError (b , err ) }()
322
+
292
323
err = h .BrokerClient .CreateBinding (& si , b )
293
324
return
294
325
}
@@ -312,6 +343,9 @@ func (h *serviceBindingEntityHandler) Delete(obj entitystore.Entity) error {
312
343
return err
313
344
}
314
345
346
+ // TODO (bjung): We really shoudn't actually delete the entity until the the resource
347
+ // is actually deleted. As-is it works, but we are repeatedly calling delete as the controller
348
+ // thinks the resource has been orphaned (which it has)
315
349
var deleted entities.ServiceBinding
316
350
err = h .Store .Delete (obj .GetOrganizationID (), obj .GetName (), & deleted )
317
351
if err != nil {
@@ -353,7 +387,7 @@ func (h *serviceBindingEntityHandler) Sync(organizationID string, resyncPeriod t
353
387
354
388
for _ , binding := range existing {
355
389
log .Debugf ("Processing service binding %s [%s]" , binding .Name , binding .Status )
356
- if _ , ok := serviceMap [binding .Name ]; ! ok {
390
+ if _ , ok := serviceMap [binding .ServiceInstance ]; ! ok {
357
391
log .Debugf ("Service for binding %s missing, delete" , binding .Name )
358
392
// No matching service exists... delete
359
393
binding .SetDelete (true )
@@ -366,6 +400,14 @@ func (h *serviceBindingEntityHandler) Sync(organizationID string, resyncPeriod t
366
400
synced = append (synced , binding )
367
401
continue
368
402
}
403
+ if binding .Delete {
404
+ // Marked for deletion... ignore actual status - though we need to start tracking
405
+ // actual state separately from desired stated (i.e. marked for delete, but is currently
406
+ // in ready state)
407
+ delete (actualMap , binding .BindingID )
408
+ synced = append (synced , binding )
409
+ continue
410
+ }
369
411
actual , ok := actualMap [binding .BindingID ]
370
412
// If binding isn't present... delete
371
413
// TODO (bjung): would it be better to set the status to INITIALIZED and recreate?
0 commit comments