Skip to content

Commit 41984a5

Browse files
dmitri-dJay Boyd
authored and
Jay Boyd
committed
Check for existing bindings only for instances with DeprovisionStatus == ServiceInstanceDeprovisionStatusRequired. (openshift#1640)
Closes openshift#1588
1 parent 706e555 commit 41984a5

File tree

3 files changed

+110
-83
lines changed

3 files changed

+110
-83
lines changed

pkg/controller/controller_instance.go

+9-5
Original file line numberDiff line numberDiff line change
@@ -469,11 +469,6 @@ func (c *controller) reconcileServiceInstanceDelete(instance *v1beta1.ServiceIns
469469

470470
instance = instance.DeepCopy()
471471

472-
// We don't want to delete the instance if there are any bindings associated.
473-
if err := c.checkServiceInstanceHasExistingBindings(instance); err != nil {
474-
return c.handleServiceInstanceReconciliationError(instance, err)
475-
}
476-
477472
// If the deprovisioning succeeded or is not needed, then no need to
478473
// make a request to the broker.
479474
if instance.Status.DeprovisionStatus == v1beta1.ServiceInstanceDeprovisionStatusNotRequired ||
@@ -492,6 +487,11 @@ func (c *controller) reconcileServiceInstanceDelete(instance *v1beta1.ServiceIns
492487
return c.processDeprovisionFailure(instance, readyCond, failedCond)
493488
}
494489

490+
// We don't want to delete the instance if there are any bindings associated.
491+
if err := c.checkServiceInstanceHasExistingBindings(instance); err != nil {
492+
return c.handleServiceInstanceReconciliationError(instance, err)
493+
}
494+
495495
serviceClass, servicePlan, brokerName, brokerClient, err := c.getClusterServiceClassPlanAndClusterServiceBroker(instance)
496496
if err != nil {
497497
return c.handleServiceInstanceReconciliationError(instance, err)
@@ -1179,7 +1179,11 @@ func (c *controller) checkServiceInstanceHasExistingBindings(instance *v1beta1.S
11791179
if err != nil {
11801180
return err
11811181
}
1182+
11821183
for _, binding := range bindingList {
1184+
// Note that as we are potentially looking at a stale binding resource
1185+
// and cannot rely on UnbindStatus == ServiceBindingUnbindStatusNotRequired
1186+
// to filter out binding requests that have yet to be sent to the broker.
11831187
if instance.Name == binding.Spec.ServiceInstanceRef.Name {
11841188
return &operationError{
11851189
reason: errorDeprovisionBlockedByCredentialsReason,

pkg/controller/controller_instance_test.go

+81-78
Original file line numberDiff line numberDiff line change
@@ -1725,51 +1725,6 @@ func TestReconcileServiceInstanceDeleteAsynchronous(t *testing.T) {
17251725
}
17261726
}
17271727

1728-
// TestReconcileServiceInstanceDeleteFailedProvisionWithoutRequest tests that
1729-
// an instance that failed to provision without making a provision request
1730-
// will be finalized, but no deprovision request will be sent to the broker.
1731-
func TestReconcileServiceInstanceDeleteFailedProvisionWithoutRequest(t *testing.T) {
1732-
fakeKubeClient, fakeCatalogClient, fakeClusterServiceBrokerClient, testController, sharedInformers := newTestController(t, noFakeActions())
1733-
1734-
sharedInformers.ClusterServiceBrokers().Informer().GetStore().Add(getTestClusterServiceBroker())
1735-
sharedInformers.ClusterServiceClasses().Informer().GetStore().Add(getTestClusterServiceClass())
1736-
sharedInformers.ClusterServicePlans().Informer().GetStore().Add(getTestClusterServicePlan())
1737-
1738-
instance := getTestServiceInstanceWithFailedStatus()
1739-
instance.ObjectMeta.DeletionTimestamp = &metav1.Time{}
1740-
instance.ObjectMeta.Finalizers = []string{v1beta1.FinalizerServiceCatalog}
1741-
instance.Status.ExternalProperties = &v1beta1.ServiceInstancePropertiesState{}
1742-
instance.Status.DeprovisionStatus = v1beta1.ServiceInstanceDeprovisionStatusNotRequired
1743-
1744-
instance.Generation = 1
1745-
instance.Status.ReconciledGeneration = 0
1746-
1747-
fakeCatalogClient.AddReactor("get", "serviceinstances", func(action clientgotesting.Action) (bool, runtime.Object, error) {
1748-
return true, instance, nil
1749-
})
1750-
1751-
err := testController.reconcileServiceInstance(instance)
1752-
if err != nil {
1753-
t.Fatalf("Unexpected error from reconcileServiceInstance: %v", err)
1754-
}
1755-
1756-
brokerActions := fakeClusterServiceBrokerClient.Actions()
1757-
assertNumberOfClusterServiceBrokerActions(t, brokerActions, 0)
1758-
1759-
// Verify no core kube actions occurred
1760-
kubeActions := fakeKubeClient.Actions()
1761-
assertNumberOfActions(t, kubeActions, 0)
1762-
1763-
actions := fakeCatalogClient.Actions()
1764-
assertNumberOfActions(t, actions, 1)
1765-
1766-
updatedServiceInstance := assertUpdateStatus(t, actions[0], instance)
1767-
assertEmptyFinalizers(t, updatedServiceInstance)
1768-
1769-
events := getRecordedEvents(testController)
1770-
assertNumEvents(t, events, 0)
1771-
}
1772-
17731728
// TestReconcileServiceInstanceDeleteFailedProvisionWithRequest tests that an
17741729
// instance that failed to provision but for which a provision request was
17751730
// made will have a deprovision request sent to the broker.
@@ -1832,49 +1787,97 @@ func TestReconcileServiceInstanceDeleteFailedProvisionWithRequest(t *testing.T)
18321787
}
18331788
}
18341789

1835-
// TestReconcileServiceInstanceDeleteWhenAlreadyDeprovisionedSuccessfully
1836-
// tests that an instance that has already been deprovisioned will be
1837-
// finalized, but no deprovision request will be sent to the broker.
1838-
func TestReconcileServiceInstanceDeleteWhenAlreadyDeprovisionedSuccessfully(t *testing.T) {
1839-
fakeKubeClient, fakeCatalogClient, fakeClusterServiceBrokerClient, testController, sharedInformers := newTestController(t, noFakeActions())
1790+
// TestReconsileServiceInstanceDeleteWithParameters tests that
1791+
// an instance will be finalized under various conditions defined by test parameters
1792+
func TestReconsileServiceInstanceDeleteWithParameters(t *testing.T) {
1793+
cases := []struct {
1794+
name string
1795+
externalProperties *v1beta1.ServiceInstancePropertiesState
1796+
deprovisionStatus v1beta1.ServiceInstanceDeprovisionStatus
1797+
serviceBinding *v1beta1.ServiceBinding
1798+
generation int64
1799+
reconceiledGeneration int64
1800+
}{
1801+
{
1802+
name: "With a failed to provision instance and without making a provision request",
1803+
externalProperties: &v1beta1.ServiceInstancePropertiesState{},
1804+
deprovisionStatus: v1beta1.ServiceInstanceDeprovisionStatusNotRequired,
1805+
serviceBinding: nil,
1806+
generation: 1,
1807+
reconceiledGeneration: 0,
1808+
},
1809+
{
1810+
name: "With a failed to provision instance, with inactive binding, and without making a provision request",
1811+
externalProperties: &v1beta1.ServiceInstancePropertiesState{},
1812+
deprovisionStatus: v1beta1.ServiceInstanceDeprovisionStatusNotRequired,
1813+
serviceBinding: getTestServiceInactiveBinding(),
1814+
generation: 1,
1815+
reconceiledGeneration: 0,
1816+
},
1817+
{
1818+
name: "With a deprovisioned instance and without making a deprovision request",
1819+
externalProperties: nil,
1820+
deprovisionStatus: v1beta1.ServiceInstanceDeprovisionStatusSucceeded,
1821+
serviceBinding: nil,
1822+
generation: 2,
1823+
reconceiledGeneration: 1,
1824+
},
1825+
{
1826+
name: "With a deprovisioned instance, with inactive binding, and without making a deprovision request",
1827+
externalProperties: nil,
1828+
deprovisionStatus: v1beta1.ServiceInstanceDeprovisionStatusSucceeded,
1829+
serviceBinding: getTestServiceInactiveBinding(),
1830+
generation: 2,
1831+
reconceiledGeneration: 1,
1832+
},
1833+
}
18401834

1841-
sharedInformers.ClusterServiceBrokers().Informer().GetStore().Add(getTestClusterServiceBroker())
1842-
sharedInformers.ClusterServiceClasses().Informer().GetStore().Add(getTestClusterServiceClass())
1843-
sharedInformers.ClusterServicePlans().Informer().GetStore().Add(getTestClusterServicePlan())
1835+
for _, tc := range cases {
1836+
t.Run(tc.name, func(t *testing.T) {
1837+
fakeKubeClient, fakeCatalogClient, fakeClusterServiceBrokerClient, testController, sharedInformers := newTestController(t, noFakeActions())
18441838

1845-
instance := getTestServiceInstanceWithFailedStatus()
1846-
instance.ObjectMeta.DeletionTimestamp = &metav1.Time{}
1847-
instance.ObjectMeta.Finalizers = []string{v1beta1.FinalizerServiceCatalog}
1848-
instance.Status.ExternalProperties = nil
1849-
instance.Status.DeprovisionStatus = v1beta1.ServiceInstanceDeprovisionStatusSucceeded
1839+
sharedInformers.ClusterServiceBrokers().Informer().GetStore().Add(getTestClusterServiceBroker())
1840+
sharedInformers.ClusterServiceClasses().Informer().GetStore().Add(getTestClusterServiceClass())
1841+
sharedInformers.ClusterServicePlans().Informer().GetStore().Add(getTestClusterServicePlan())
1842+
if tc.serviceBinding != nil {
1843+
sharedInformers.ClusterServicePlans().Informer().GetStore().Add(tc.serviceBinding)
1844+
}
18501845

1851-
instance.Generation = 2
1852-
instance.Status.ReconciledGeneration = 1
1846+
instance := getTestServiceInstanceWithFailedStatus()
1847+
instance.ObjectMeta.DeletionTimestamp = &metav1.Time{}
1848+
instance.ObjectMeta.Finalizers = []string{v1beta1.FinalizerServiceCatalog}
1849+
instance.Status.ExternalProperties = tc.externalProperties
1850+
instance.Status.DeprovisionStatus = tc.deprovisionStatus
18531851

1854-
fakeCatalogClient.AddReactor("get", "serviceinstances", func(action clientgotesting.Action) (bool, runtime.Object, error) {
1855-
return true, instance, nil
1856-
})
1852+
instance.Generation = tc.generation
1853+
instance.Status.ReconciledGeneration = tc.reconceiledGeneration
18571854

1858-
err := testController.reconcileServiceInstance(instance)
1859-
if err != nil {
1860-
t.Fatalf("Unexpected error from reconcileServiceInstance: %v", err)
1861-
}
1855+
fakeCatalogClient.AddReactor("get", "serviceinstances", func(action clientgotesting.Action) (bool, runtime.Object, error) {
1856+
return true, instance, nil
1857+
})
18621858

1863-
brokerActions := fakeClusterServiceBrokerClient.Actions()
1864-
assertNumberOfClusterServiceBrokerActions(t, brokerActions, 0)
1859+
err := testController.reconcileServiceInstance(instance)
1860+
if err != nil {
1861+
t.Fatalf("Unexpected error from reconcileServiceInstance: %v", err)
1862+
}
18651863

1866-
// Verify no core kube actions occurred
1867-
kubeActions := fakeKubeClient.Actions()
1868-
assertNumberOfActions(t, kubeActions, 0)
1864+
brokerActions := fakeClusterServiceBrokerClient.Actions()
1865+
assertNumberOfClusterServiceBrokerActions(t, brokerActions, 0)
18691866

1870-
actions := fakeCatalogClient.Actions()
1871-
assertNumberOfActions(t, actions, 1)
1867+
// Verify no core kube actions occurred
1868+
kubeActions := fakeKubeClient.Actions()
1869+
assertNumberOfActions(t, kubeActions, 0)
18721870

1873-
updatedServiceInstance := assertUpdateStatus(t, actions[0], instance)
1874-
assertEmptyFinalizers(t, updatedServiceInstance)
1871+
actions := fakeCatalogClient.Actions()
1872+
assertNumberOfActions(t, actions, 1)
18751873

1876-
events := getRecordedEvents(testController)
1877-
assertNumEvents(t, events, 0)
1874+
updatedServiceInstance := assertUpdateStatus(t, actions[0], instance)
1875+
assertEmptyFinalizers(t, updatedServiceInstance)
1876+
1877+
events := getRecordedEvents(testController)
1878+
assertNumEvents(t, events, 0)
1879+
})
1880+
}
18781881
}
18791882

18801883
// TestReconcileServiceInstanceDeleteWhenAlreadyDeprovisionedUnsuccessfully

pkg/controller/controller_test.go

+20
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,26 @@ func getTestServiceBinding() *v1beta1.ServiceBinding {
853853
}
854854
}
855855

856+
// instantiates a yet-to-be-created binding
857+
func getTestServiceInactiveBinding() *v1beta1.ServiceBinding {
858+
return &v1beta1.ServiceBinding{
859+
ObjectMeta: metav1.ObjectMeta{
860+
Name: testServiceBindingName,
861+
Namespace: testNamespace,
862+
Finalizers: []string{v1beta1.FinalizerServiceCatalog},
863+
Generation: 1,
864+
},
865+
Spec: v1beta1.ServiceBindingSpec{
866+
ServiceInstanceRef: v1beta1.LocalObjectReference{Name: testServiceInstanceName},
867+
ExternalID: testServiceBindingGUID,
868+
},
869+
Status: v1beta1.ServiceBindingStatus{
870+
Conditions: []v1beta1.ServiceBindingCondition{},
871+
UnbindStatus: v1beta1.ServiceBindingUnbindStatusNotRequired,
872+
},
873+
}
874+
}
875+
856876
func getTestServiceBindingUnbinding() *v1beta1.ServiceBinding {
857877
binding := &v1beta1.ServiceBinding{
858878
ObjectMeta: metav1.ObjectMeta{

0 commit comments

Comments
 (0)