Skip to content

Commit

Permalink
Reorder class and plan creation; test plan conflict handling (#1459)
Browse files Browse the repository at this point in the history
  • Loading branch information
nilebox authored and Ville Aikas committed Oct 23, 2017
1 parent 4bea012 commit b70c076
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 75 deletions.
92 changes: 46 additions & 46 deletions pkg/controller/controller_broker.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,44 +299,44 @@ func (c *controller) reconcileClusterServiceBroker(broker *v1beta1.ClusterServic
existingServiceClassMap := convertServiceClassListToMap(existingServiceClasses)
existingServicePlanMap := convertServicePlanListToMap(existingServicePlans)

// reconcile the plans that were part of the broker's catalog payload
for _, payloadServicePlan := range payloadServicePlans {
existingServicePlan, _ := existingServicePlanMap[payloadServicePlan.Name]
delete(existingServicePlanMap, payloadServicePlan.Name)
// reconcile the serviceClasses that were part of the broker's catalog
// payload
for _, payloadServiceClass := range payloadServiceClasses {
existingServiceClass, _ := existingServiceClassMap[payloadServiceClass.Name]
delete(existingServiceClassMap, payloadServiceClass.Name)

glog.V(4).Infof(
"ClusterServiceBroker %q: reconciling %s",
broker.Name, pretty.ClusterServicePlanName(payloadServicePlan),
)
if err := c.reconcileClusterServicePlanFromClusterServiceBrokerCatalog(broker, payloadServicePlan, existingServicePlan); err != nil {
glog.V(4).Info(pcb.Messagef("Reconciling %s", pretty.ClusterServiceClassName(payloadServiceClass)))
if err := c.reconcileClusterServiceClassFromClusterServiceBrokerCatalog(broker, payloadServiceClass, existingServiceClass); err != nil {
s := fmt.Sprintf(
"Error reconciling %s: %s",
pretty.ClusterServicePlanName(payloadServicePlan), err,
"Error reconciling %s (broker %q): %s",
pretty.ClusterServiceClassName(payloadServiceClass), broker.Name, err,
)
glog.Warning(pcb.Message(s))
c.recorder.Eventf(broker, corev1.EventTypeWarning, errorSyncingCatalogReason, s)
c.updateClusterServiceBrokerCondition(broker, v1beta1.ServiceBrokerConditionReady, v1beta1.ConditionFalse, errorSyncingCatalogReason,
errorSyncingCatalogMessage+s)
if err := c.updateClusterServiceBrokerCondition(broker, v1beta1.ServiceBrokerConditionReady, v1beta1.ConditionFalse, errorSyncingCatalogReason,
errorSyncingCatalogMessage+s); err != nil {
return err
}
return err
}
glog.V(5).Info(pcb.Messagef("Reconciled %s", pretty.ClusterServicePlanName(payloadServicePlan)))

glog.V(5).Info(pcb.Messagef("Reconciled %s", pretty.ClusterServiceClassName(payloadServiceClass)))
}

// handle the servicePlans that were not in the broker's payload;
// mark these as deleted
for _, existingServicePlan := range existingServicePlanMap {
if existingServicePlan.Status.RemovedFromBrokerCatalog {
// handle the serviceClasses that were not in the broker's payload;
// mark these as having been removed from the broker's catalog
for _, existingServiceClass := range existingServiceClassMap {
if existingServiceClass.Status.RemovedFromBrokerCatalog {
continue
}
glog.V(4).Info(pcb.Messagef("%s has been removed from broker's catalog; marking", pretty.ClusterServicePlanName(existingServicePlan)))
existingServicePlan.Status.RemovedFromBrokerCatalog = true
_, err := c.serviceCatalogClient.ClusterServicePlans().UpdateStatus(existingServicePlan)

glog.V(4).Info(pcb.Messagef("%s has been removed from broker's catalog; marking", pretty.ClusterServiceClassName(existingServiceClass)))
existingServiceClass.Status.RemovedFromBrokerCatalog = true
_, err := c.serviceCatalogClient.ClusterServiceClasses().UpdateStatus(existingServiceClass)
if err != nil {
s := fmt.Sprintf(
"Error updating status of %s: %v",
pretty.ClusterServicePlanName(existingServicePlan),
err,
pretty.ClusterServiceClassName(existingServiceClass), err,
)
glog.Warning(pcb.Message(s))
c.recorder.Eventf(broker, corev1.EventTypeWarning, errorSyncingCatalogReason, s)
Expand All @@ -348,44 +348,44 @@ func (c *controller) reconcileClusterServiceBroker(broker *v1beta1.ClusterServic
}
}

// reconcile the serviceClasses that were part of the broker's catalog
// payload
for _, payloadServiceClass := range payloadServiceClasses {
existingServiceClass, _ := existingServiceClassMap[payloadServiceClass.Name]
delete(existingServiceClassMap, payloadServiceClass.Name)
// reconcile the plans that were part of the broker's catalog payload
for _, payloadServicePlan := range payloadServicePlans {
existingServicePlan, _ := existingServicePlanMap[payloadServicePlan.Name]
delete(existingServicePlanMap, payloadServicePlan.Name)

glog.V(4).Info(pcb.Messagef("Reconciling %s", pretty.ClusterServiceClassName(payloadServiceClass)))
if err := c.reconcileClusterServiceClassFromClusterServiceBrokerCatalog(broker, payloadServiceClass, existingServiceClass); err != nil {
glog.V(4).Infof(
"ClusterServiceBroker %q: reconciling %s",
broker.Name, pretty.ClusterServicePlanName(payloadServicePlan),
)
if err := c.reconcileClusterServicePlanFromClusterServiceBrokerCatalog(broker, payloadServicePlan, existingServicePlan); err != nil {
s := fmt.Sprintf(
"Error reconciling %s (broker %q): %s",
pretty.ClusterServiceClassName(payloadServiceClass), broker.Name, err,
"Error reconciling %s: %s",
pretty.ClusterServicePlanName(payloadServicePlan), err,
)
glog.Warning(pcb.Message(s))
c.recorder.Eventf(broker, corev1.EventTypeWarning, errorSyncingCatalogReason, s)
if err := c.updateClusterServiceBrokerCondition(broker, v1beta1.ServiceBrokerConditionReady, v1beta1.ConditionFalse, errorSyncingCatalogReason,
errorSyncingCatalogMessage+s); err != nil {
return err
}
c.updateClusterServiceBrokerCondition(broker, v1beta1.ServiceBrokerConditionReady, v1beta1.ConditionFalse, errorSyncingCatalogReason,
errorSyncingCatalogMessage+s)
return err
}
glog.V(5).Info(pcb.Messagef("Reconciled %s", pretty.ClusterServicePlanName(payloadServicePlan)))

glog.V(5).Info(pcb.Messagef("Reconciled %s", pretty.ClusterServiceClassName(payloadServiceClass)))
}

// handle the serviceClasses that were not in the broker's payload;
// mark these as having been removed from the broker's catalog
for _, existingServiceClass := range existingServiceClassMap {
if existingServiceClass.Status.RemovedFromBrokerCatalog {
// handle the servicePlans that were not in the broker's payload;
// mark these as deleted
for _, existingServicePlan := range existingServicePlanMap {
if existingServicePlan.Status.RemovedFromBrokerCatalog {
continue
}

glog.V(4).Info(pcb.Messagef("%s has been removed from broker's catalog; marking", pretty.ClusterServiceClassName(existingServiceClass)))
existingServiceClass.Status.RemovedFromBrokerCatalog = true
_, err := c.serviceCatalogClient.ClusterServiceClasses().UpdateStatus(existingServiceClass)
glog.V(4).Info(pcb.Messagef("%s has been removed from broker's catalog; marking", pretty.ClusterServicePlanName(existingServicePlan)))
existingServicePlan.Status.RemovedFromBrokerCatalog = true
_, err := c.serviceCatalogClient.ClusterServicePlans().UpdateStatus(existingServicePlan)
if err != nil {
s := fmt.Sprintf(
"Error updating status of %s: %v",
pretty.ClusterServiceClassName(existingServiceClass), err,
pretty.ClusterServicePlanName(existingServicePlan),
err,
)
glog.Warning(pcb.Message(s))
c.recorder.Eventf(broker, corev1.EventTypeWarning, errorSyncingCatalogReason, s)
Expand Down
96 changes: 67 additions & 29 deletions pkg/controller/controller_broker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,9 @@ func TestReconcileClusterServiceBrokerExistingServiceClassAndServicePlan(t *test
assertNumberOfActions(t, actions, 6)
assertList(t, actions[0], &v1beta1.ClusterServiceClass{}, listRestrictions)
assertList(t, actions[1], &v1beta1.ClusterServicePlan{}, listRestrictions)
assertCreate(t, actions[2], testClusterServicePlan)
assertCreate(t, actions[3], testClusterServicePlanNonbindable)
assertUpdate(t, actions[4], testClusterServiceClass)
assertUpdate(t, actions[2], testClusterServiceClass)
assertCreate(t, actions[3], testClusterServicePlan)
assertCreate(t, actions[4], testClusterServicePlanNonbindable)

// 4 update action for broker status subresource
updatedClusterServiceBroker := assertUpdateStatus(t, actions[5], getTestClusterServiceBroker())
Expand Down Expand Up @@ -281,10 +281,10 @@ func TestReconcileClusterServiceBrokerRemovedClusterServiceClass(t *testing.T) {
assertNumberOfActions(t, actions, 7)
assertList(t, actions[0], &v1beta1.ClusterServiceClass{}, listRestrictions)
assertList(t, actions[1], &v1beta1.ClusterServicePlan{}, listRestrictions)
assertCreate(t, actions[2], testClusterServicePlan)
assertCreate(t, actions[3], testClusterServicePlanNonbindable)
assertUpdate(t, actions[4], testClusterServiceClass)
assertUpdateStatus(t, actions[5], testRemovedClusterServiceClass)
assertUpdate(t, actions[2], testClusterServiceClass)
assertUpdateStatus(t, actions[3], testRemovedClusterServiceClass)
assertCreate(t, actions[4], testClusterServicePlan)
assertCreate(t, actions[5], testClusterServicePlanNonbindable)

updatedClusterServiceBroker := assertUpdateStatus(t, actions[6], getTestClusterServiceBroker())
assertClusterServiceBrokerReadyTrue(t, updatedClusterServiceBroker)
Expand Down Expand Up @@ -336,10 +336,10 @@ func TestReconcileClusterServiceBrokerRemovedClusterServicePlan(t *testing.T) {
assertNumberOfActions(t, actions, 7)
assertList(t, actions[0], &v1beta1.ClusterServiceClass{}, listRestrictions)
assertList(t, actions[1], &v1beta1.ClusterServicePlan{}, listRestrictions)
assertCreate(t, actions[2], testClusterServicePlan)
assertCreate(t, actions[3], testClusterServicePlanNonbindable)
assertUpdateStatus(t, actions[4], testRemovedClusterServicePlan)
assertUpdate(t, actions[5], testClusterServiceClass)
assertUpdate(t, actions[2], testClusterServiceClass)
assertCreate(t, actions[3], testClusterServicePlan)
assertCreate(t, actions[4], testClusterServicePlanNonbindable)
assertUpdateStatus(t, actions[5], testRemovedClusterServicePlan)

updatedClusterServiceBroker := assertUpdateStatus(t, actions[6], getTestClusterServiceBroker())
assertClusterServiceBrokerReadyTrue(t, updatedClusterServiceBroker)
Expand All @@ -358,15 +358,54 @@ func TestReconcileClusterServiceBrokerExistingClusterServiceClassDifferentBroker
testClusterServiceClass := getTestClusterServiceClass()
testClusterServiceClass.Spec.ClusterServiceBrokerName = "notTheSame"

sharedInformers.ClusterServiceClasses().Informer().GetStore().Add(testClusterServiceClass)

if err := testController.reconcileClusterServiceBroker(getTestClusterServiceBroker()); err == nil {
t.Fatal("The same service class should not belong to two different brokers.")
}

brokerActions := fakeClusterServiceBrokerClient.Actions()
assertNumberOfClusterServiceBrokerActions(t, brokerActions, 1)
assertGetCatalog(t, brokerActions[0])

actions := fakeCatalogClient.Actions()
assertNumberOfActions(t, actions, 3)

listRestrictions := clientgotesting.ListRestrictions{
Labels: labels.Everything(),
Fields: fields.OneTermEqualSelector("spec.clusterServiceBrokerName", "test-broker"),
}
assertList(t, actions[0], &v1beta1.ClusterServiceClass{}, listRestrictions)
assertList(t, actions[1], &v1beta1.ClusterServicePlan{}, listRestrictions)
updatedClusterServiceBroker := assertUpdateStatus(t, actions[2], getTestClusterServiceBroker())
assertClusterServiceBrokerReadyFalse(t, updatedClusterServiceBroker)

// verify no kube resources created
kubeActions := fakeKubeClient.Actions()
assertNumberOfActions(t, kubeActions, 0)

events := getRecordedEvents(testController)
assertNumEvents(t, events, 1)

expectedEvent := corev1.EventTypeWarning + " " + errorSyncingCatalogReason + ` Error reconciling ClusterServiceClass (K8S: "SCGUID" ExternalName: "test-serviceclass") (broker "test-broker"): ClusterServiceClass (K8S: "SCGUID" ExternalName: "test-serviceclass") already exists for Broker "notTheSame"`
if e, a := expectedEvent, events[0]; e != a {
t.Fatalf("Received unexpected event; expected\n%v, got\n%v", e, a)
}
}

// TestReconcileClusterServiceBrokerExistingClusterServicePlanDifferentClass simulates catalog
// refresh where broker lists a service plan which matches an existing, already
// cataloged service plan but the plan points to a different ClusterServiceClass. Results in an error.
func TestReconcileClusterServiceBrokerExistingClusterServicePlanDifferentClass(t *testing.T) {
fakeKubeClient, fakeCatalogClient, fakeClusterServiceBrokerClient, testController, sharedInformers := newTestController(t, getTestCatalogConfig())

testClusterServicePlan := getTestClusterServicePlan()
testClusterServicePlan.Spec.ClusterServiceBrokerName = "notTheSame"
testClusterServicePlan.Spec.ClusterServiceClassRef = v1beta1.ClusterObjectReference{
Name: "notTheSameClass",
}

testClusterServicePlanNonbindable := getTestClusterServicePlanNonbindable()
testClusterServicePlanNonbindable.Spec.ClusterServiceBrokerName = "notTheSame"

sharedInformers.ClusterServiceClasses().Informer().GetStore().Add(testClusterServiceClass)
sharedInformers.ClusterServicePlans().Informer().GetStore().Add(testClusterServicePlan)
sharedInformers.ClusterServicePlans().Informer().GetStore().Add(testClusterServicePlanNonbindable)

if err := testController.reconcileClusterServiceBroker(getTestClusterServiceBroker()); err == nil {
t.Fatal("The same service class should not belong to two different brokers.")
Expand All @@ -377,15 +416,16 @@ func TestReconcileClusterServiceBrokerExistingClusterServiceClassDifferentBroker
assertGetCatalog(t, brokerActions[0])

actions := fakeCatalogClient.Actions()
assertNumberOfActions(t, actions, 3)
assertNumberOfActions(t, actions, 4)

listRestrictions := clientgotesting.ListRestrictions{
Labels: labels.Everything(),
Fields: fields.OneTermEqualSelector("spec.clusterServiceBrokerName", "test-broker"),
}
assertList(t, actions[0], &v1beta1.ClusterServiceClass{}, listRestrictions)
assertList(t, actions[1], &v1beta1.ClusterServicePlan{}, listRestrictions)
updatedClusterServiceBroker := assertUpdateStatus(t, actions[2], getTestClusterServiceBroker())
assertCreate(t, actions[2], getTestClusterServiceClass())
updatedClusterServiceBroker := assertUpdateStatus(t, actions[3], getTestClusterServiceBroker())
assertClusterServiceBrokerReadyFalse(t, updatedClusterServiceBroker)

// verify no kube resources created
Expand Down Expand Up @@ -737,28 +777,26 @@ func TestReconcileClusterServiceBrokerWithReconcileError(t *testing.T) {
assertGetCatalog(t, brokerActions[0])

actions := fakeCatalogClient.Actions()
assertNumberOfActions(t, actions, 6)
assertNumberOfActions(t, actions, 4)

listRestrictions := clientgotesting.ListRestrictions{
Labels: labels.Everything(),
Fields: fields.OneTermEqualSelector("spec.clusterServiceBrokerName", broker.Name),
}
assertList(t, actions[0], &v1beta1.ClusterServiceClass{}, listRestrictions)
assertList(t, actions[1], &v1beta1.ClusterServicePlan{}, listRestrictions)
assertCreate(t, actions[2], getTestClusterServicePlan())
assertCreate(t, actions[3], getTestClusterServicePlanNonbindable())

// the two plans in the catalog as two separate actions

createSCAction := actions[4].(clientgotesting.CreateAction)
createSCAction := actions[2].(clientgotesting.CreateAction)
createdSC, ok := createSCAction.GetObject().(*v1beta1.ClusterServiceClass)
if !ok {
t.Fatalf("couldn't convert to a ClusterServiceClass: %+v", createSCAction.GetObject())
}
if e, a := getTestClusterServiceClass(), createdSC; !reflect.DeepEqual(e, a) {
t.Fatalf("unexpected diff for created ClusterServiceClass: %v,\n\nEXPECTED: %+v\n\nACTUAL: %+v", diff.ObjectReflectDiff(e, a), e, a)
}
updatedClusterServiceBroker := assertUpdateStatus(t, actions[5], broker)
updatedClusterServiceBroker := assertUpdateStatus(t, actions[3], broker)
assertClusterServiceBrokerReadyFalse(t, updatedClusterServiceBroker)

kubeActions := fakeKubeClient.Actions()
Expand Down Expand Up @@ -807,9 +845,9 @@ func TestReconcileClusterServiceBrokerSuccessOnFinalRetry(t *testing.T) {

assertList(t, actions[1], &v1beta1.ClusterServiceClass{}, listRestrictions)
assertList(t, actions[2], &v1beta1.ClusterServicePlan{}, listRestrictions)
assertCreate(t, actions[3], getTestClusterServicePlan())
assertCreate(t, actions[4], getTestClusterServicePlanNonbindable())
assertCreate(t, actions[5], testClusterServiceClass)
assertCreate(t, actions[3], testClusterServiceClass)
assertCreate(t, actions[4], getTestClusterServicePlan())
assertCreate(t, actions[5], getTestClusterServicePlanNonbindable())

updatedClusterServiceBroker = assertUpdateStatus(t, actions[6], getTestClusterServiceBroker())
assertClusterServiceBrokerReadyTrue(t, updatedClusterServiceBroker)
Expand Down Expand Up @@ -904,9 +942,9 @@ func TestReconcileClusterServiceBrokerWithStatusUpdateError(t *testing.T) {

assertList(t, actions[0], &v1beta1.ClusterServiceClass{}, listRestrictions)
assertList(t, actions[1], &v1beta1.ClusterServicePlan{}, listRestrictions)
assertCreate(t, actions[2], getTestClusterServicePlan())
assertCreate(t, actions[3], getTestClusterServicePlanNonbindable())
assertCreate(t, actions[4], testClusterServiceClass)
assertCreate(t, actions[2], testClusterServiceClass)
assertCreate(t, actions[3], getTestClusterServicePlan())
assertCreate(t, actions[4], getTestClusterServicePlanNonbindable())

// 4 update action for broker status subresource
updatedClusterServiceBroker := assertUpdateStatus(t, actions[5], getTestClusterServiceBroker())
Expand Down

0 comments on commit b70c076

Please sign in to comment.