Skip to content
This repository was archived by the owner on Nov 16, 2020. It is now read-only.

Commit 02cd0df

Browse files
authored
Add missing service tests (#378)
* Add missing service tests This commit fill out a lot of the missing service tests. * Fix issues brought up by tests * Remove embeded Binding on ServiceInstance entity (was confusing) * Small refactor to build bindings in handler * allow serviceclasses to be updated
1 parent 885a1fc commit 02cd0df

File tree

6 files changed

+574
-36
lines changed

6 files changed

+574
-36
lines changed

pkg/service-manager/clients/k8s_service_catalog.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,12 @@ func (c *k8sServiceCatalogClient) ListServiceClasses() ([]entitystore.Entity, er
113113
if err != nil {
114114
return nil, errors.Wrapf(err, "Error retreiving plan for service class %s", csc.Spec.ExternalName)
115115
}
116+
log.Debugf("Fetch plans for %s [%d plans]", csc.Spec.ExternalName, len(plans))
116117
var serviceClassPlans []entities.ServicePlan
117118
for _, plan := range plans {
119+
log.Debugf("Parsing plan %s", plan.Spec.ExternalName)
118120
if plan.Status.RemovedFromBrokerCatalog {
121+
log.Debugf("Plan %s removed from broker catalog", plan.Spec.ExternalName)
119122
continue
120123
}
121124
marshall := func(ps *runtime.RawExtension) (*spec.Schema, error) {
@@ -130,14 +133,17 @@ func (c *k8sServiceCatalogClient) ListServiceClasses() ([]entitystore.Entity, er
130133
}
131134
create, err := marshall(plan.Spec.ServiceInstanceCreateParameterSchema)
132135
if err != nil {
136+
log.Debugf("Plan %s failed to marshall create schema", plan.Spec.ExternalName)
133137
return nil, errors.Wrap(err, "Error marshalling create schema")
134138
}
135139
update, err := marshall(plan.Spec.ServiceInstanceUpdateParameterSchema)
136140
if err != nil {
141+
log.Debugf("Plan %s failed to marshall update schema", plan.Spec.ExternalName)
137142
return nil, errors.Wrap(err, "Error marshalling update schema")
138143
}
139144
bind, err := marshall(plan.Spec.ServiceBindingCreateParameterSchema)
140145
if err != nil {
146+
log.Debugf("Plan %s failed to marshall bind schema", plan.Spec.ExternalName)
141147
return nil, errors.Wrap(err, "Error marshalling bind schema")
142148
}
143149

@@ -417,7 +423,10 @@ func (c *k8sServiceCatalogClient) deleteSecret(secretName string) error {
417423
Context: context.Background(),
418424
}, apiKeyAuth)
419425
if err != nil {
420-
return errors.Wrapf(err, "failed to delete secret %s for binding", secretName)
426+
_, ok := err.(*secret.GetSecretNotFound)
427+
if !ok {
428+
return errors.Wrapf(err, "failed to delete secret %s for binding", secretName)
429+
}
421430
}
422431
return nil
423432
}

pkg/service-manager/controller.go

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package servicemanager
77

88
import (
9+
"encoding/json"
910
"reflect"
1011
"time"
1112

@@ -48,7 +49,9 @@ func (h *serviceClassEntityHandler) Add(obj entitystore.Entity) (err error) {
4849
// Update updates service class entities
4950
func (h *serviceClassEntityHandler) Update(obj entitystore.Entity) error {
5051
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
5255
}
5356

5457
// Delete removes service class entities
@@ -64,6 +67,24 @@ func (h *serviceClassEntityHandler) Delete(obj entitystore.Entity) error {
6467
return nil
6568
}
6669

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+
6788
// Sync reconsiles the actual state from the service catalog with the dispatch state
6889
func (h *serviceClassEntityHandler) Sync(organizationID string, resyncPeriod time.Duration) ([]entitystore.Entity, error) {
6990
defer trace.Trace("")()
@@ -94,8 +115,9 @@ func (h *serviceClassEntityHandler) Sync(organizationID string, resyncPeriod tim
94115
class.SetStatus(entitystore.StatusDELETING)
95116
} else {
96117
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 {
99121
continue
100122
}
101123
}
@@ -151,11 +173,6 @@ func (h *serviceInstanceEntityHandler) Add(obj entitystore.Entity) (err error) {
151173
if err = h.BrokerClient.CreateService(&sc, si); err != nil {
152174
return
153175
}
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-
}
159176
return
160177
}
161178

@@ -185,6 +202,9 @@ func (h *serviceInstanceEntityHandler) Delete(obj entitystore.Entity) error {
185202
log.Error(err)
186203
}
187204

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)
188208
var deleted entities.ServiceInstance
189209
err = h.Store.Delete(si.GetOrganizationID(), si.GetName(), &deleted)
190210
if err != nil {
@@ -223,6 +243,14 @@ func (h *serviceInstanceEntityHandler) Sync(organizationID string, resyncPeriod
223243
synced = append(synced, instance)
224244
continue
225245
}
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+
}
226254
actual, ok := actualMap[instance.ID]
227255
if !ok {
228256
instance.SetDelete(true)
@@ -281,14 +309,17 @@ func (h *serviceBindingEntityHandler) Add(obj entitystore.Entity) (err error) {
281309
defer trace.Trace("")()
282310
b := obj.(*entities.ServiceBinding)
283311

284-
defer func() { h.Store.UpdateWithError(b, err) }()
285-
286312
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 {
289315
return
290316
}
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+
292323
err = h.BrokerClient.CreateBinding(&si, b)
293324
return
294325
}
@@ -312,6 +343,9 @@ func (h *serviceBindingEntityHandler) Delete(obj entitystore.Entity) error {
312343
return err
313344
}
314345

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)
315349
var deleted entities.ServiceBinding
316350
err = h.Store.Delete(obj.GetOrganizationID(), obj.GetName(), &deleted)
317351
if err != nil {
@@ -353,7 +387,7 @@ func (h *serviceBindingEntityHandler) Sync(organizationID string, resyncPeriod t
353387

354388
for _, binding := range existing {
355389
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 {
357391
log.Debugf("Service for binding %s missing, delete", binding.Name)
358392
// No matching service exists... delete
359393
binding.SetDelete(true)
@@ -366,6 +400,14 @@ func (h *serviceBindingEntityHandler) Sync(organizationID string, resyncPeriod t
366400
synced = append(synced, binding)
367401
continue
368402
}
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+
}
369411
actual, ok := actualMap[binding.BindingID]
370412
// If binding isn't present... delete
371413
// TODO (bjung): would it be better to set the status to INITIALIZED and recreate?

0 commit comments

Comments
 (0)