From efc7657ee0f174db5aa9683ab915ccb631e34372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Wa=C5=82ach?= Date: Mon, 29 Apr 2019 11:10:52 +0200 Subject: [PATCH] Replace tableconvertor with APC (#20) --- charts/catalog/templates/crds.yaml | 94 +++++++++- charts/catalog/values.yaml | 2 +- cmd/svcat/testdata/output/get-binding.json | 3 +- cmd/svcat/testdata/output/get-binding.yaml | 1 + cmd/svcat/testdata/output/get-bindings.json | 3 +- cmd/svcat/testdata/output/get-bindings.yaml | 1 + cmd/svcat/testdata/output/get-broker.json | 3 +- cmd/svcat/testdata/output/get-broker.yaml | 1 + cmd/svcat/testdata/output/get-brokers.json | 6 +- cmd/svcat/testdata/output/get-brokers.yaml | 2 + cmd/svcat/testdata/output/get-instance.json | 5 +- cmd/svcat/testdata/output/get-instance.yaml | 3 + cmd/svcat/testdata/output/get-instances.json | 5 +- cmd/svcat/testdata/output/get-instances.yaml | 3 + .../catalog/clusterservicebrokers.json | 1 + .../clusterservicebrokers/ups-broker.json | 1 + .../namespaces/default/servicebindings.json | 1 + .../default/servicebindings/ups-binding.json | 1 + .../namespaces/default/servicebrokers.json | 1 + .../default/servicebrokers/ups-broker.json | 1 + .../namespaces/default/serviceinstances.json | 1 + .../serviceinstances/ups-instance.json | 1 + .../namespaces/test-ns/servicebindings.json | 3 +- .../test-ns/servicebindings/ups-binding.json | 1 + .../namespaces/test-ns/servicebrokers.json | 1 + .../test-ns/servicebrokers/ups-broker-ns.json | 1 + .../namespaces/test-ns/serviceinstances.json | 1 + .../serviceinstances/ups-instance.json | 1 + .../responses/catalog/serviceinstances.json | 6 + ...=86064792-7ea2-467b-af93-ac9694d96d52.json | 5 +- pkg/apis/servicecatalog/types.go | 20 +++ pkg/apis/servicecatalog/v1beta1/types.go | 20 +++ .../v1beta1/zz_generated.conversion.go | 10 ++ pkg/controller/controller_binding.go | 12 ++ pkg/controller/controller_binding_test.go | 12 ++ .../controller_clusterservicebroker.go | 1 + .../controller_clusterservicebroker_test.go | 9 + pkg/controller/controller_instance.go | 54 ++++++ pkg/controller/controller_instance_ns_test.go | 4 +- pkg/controller/controller_instance_test.go | 165 ++++++++++++------ pkg/controller/controller_ns_test.go | 16 +- pkg/controller/controller_servicebroker.go | 13 ++ .../controller_servicebroker_test.go | 61 +++++++ pkg/controller/controller_test.go | 38 ++++ pkg/openapi/openapi_generated.go | 59 ++++++- 45 files changed, 576 insertions(+), 77 deletions(-) diff --git a/charts/catalog/templates/crds.yaml b/charts/catalog/templates/crds.yaml index 65c23cfcd80..286b0a040c1 100644 --- a/charts/catalog/templates/crds.yaml +++ b/charts/catalog/templates/crds.yaml @@ -12,6 +12,16 @@ spec: plural: clusterservicebrokers singular: clusterservicebroker kind: ClusterServiceBroker + additionalPrinterColumns: + - name: URL + type: string + JSONPath: .spec.url + - name: Status + type: string + JSONPath: .status.lastConditionState + - name: Age + type: date + JSONPath: .metadata.creationTimestamp subresources: status: {} @@ -31,6 +41,16 @@ spec: plural: servicebrokers singular: servicebroker kind: ServiceBroker + additionalPrinterColumns: + - name: URL + type: string + JSONPath: .spec.url + - name: Status + type: string + JSONPath: .status.lastConditionState + - name: Age + type: date + JSONPath: .metadata.creationTimestamp subresources: status: {} @@ -50,6 +70,16 @@ spec: plural: serviceclasses singular: serviceclass kind: ServiceClass + additionalPrinterColumns: + - name: External-Name + type: string + JSONPath: .spec.externalName + - name: Broker + type: string + JSONPath: .spec.clusterServiceBrokerName + - name: Age + type: date + JSONPath: .metadata.creationTimestamp subresources: status: {} @@ -69,6 +99,16 @@ spec: plural: clusterserviceclasses singular: clusterserviceclass kind: ClusterServiceClass + additionalPrinterColumns: + - name: External-Name + type: string + JSONPath: .spec.externalName + - name: Broker + type: string + JSONPath: .spec.clusterServiceBrokerName + - name: Age + type: date + JSONPath: .metadata.creationTimestamp subresources: status: {} @@ -88,6 +128,19 @@ spec: plural: serviceplans singular: serviceplan kind: ServicePlan + additionalPrinterColumns: + - name: External-Name + type: string + JSONPath: .spec.externalName + - name: Broker + type: string + JSONPath: .spec.serviceBrokerName + - name: Class + type: string + JSONPath: .spec.serviceClassRef.Name + - name: Age + type: date + JSONPath: .metadata.creationTimestamp subresources: status: {} @@ -107,6 +160,19 @@ spec: plural: clusterserviceplans singular: clusterserviceplan kind: ClusterServicePlan + additionalPrinterColumns: + - name: External-Name + type: string + JSONPath: .spec.externalName + - name: Broker + type: string + JSONPath: .spec.clusterServiceBrokerName + - name: Class + type: string + JSONPath: .spec.clusterServiceClassRef.name + - name: Age + type: date + JSONPath: .metadata.creationTimestamp subresources: status: {} @@ -126,6 +192,19 @@ spec: plural: serviceinstances singular: serviceinstance kind: ServiceInstance + additionalPrinterColumns: + - name: Class + type: string + JSONPath: .status.userSpecifiedClassName + - name: Plan + type: string + JSONPath: .status.userSpecifiedPlanName + - name: Status + type: string + JSONPath: .status.lastConditionState + - name: Age + type: date + JSONPath: .metadata.creationTimestamp subresources: status: {} @@ -145,7 +224,20 @@ spec: plural: servicebindings singular: servicebinding kind: ServiceBinding + additionalPrinterColumns: + - name: Service-Instance + type: string + JSONPath: .spec.instanceRef.name + - name: Secret-Name + type: string + JSONPath: .spec.secretName + - name: Status + type: string + JSONPath: .status.lastConditionState + - name: Age + type: date + JSONPath: .metadata.creationTimestamp subresources: status: {} ---- \ No newline at end of file +--- diff --git a/charts/catalog/values.yaml b/charts/catalog/values.yaml index bfb0c9a6ea3..e61958a3529 100644 --- a/charts/catalog/values.yaml +++ b/charts/catalog/values.yaml @@ -1,6 +1,6 @@ # Default values for Service Catalog # service-catalog image to use -image: eu.gcr.io/kyma-project/develop/service-catalog/service-catalog-amd64:crd-0.0.5 +image: eu.gcr.io/kyma-project/develop/service-catalog/service-catalog-amd64:crd-0.0.11 # imagePullPolicy for the service-catalog; valid values are "IfNotPresent", # "Never", and "Always" imagePullPolicy: Always diff --git a/cmd/svcat/testdata/output/get-binding.json b/cmd/svcat/testdata/output/get-binding.json index f3b43485a6d..725ad013087 100644 --- a/cmd/svcat/testdata/output/get-binding.json +++ b/cmd/svcat/testdata/output/get-binding.json @@ -58,6 +58,7 @@ "parameterChecksum": "23ca85e0f9fc05340ea0a13ef945602cd5cdc3f52d763e750cb0ab0cb172a94f" }, "orphanMitigationInProgress": false, - "unbindStatus": "Required" + "unbindStatus": "Required", + "lastConditionState": "Ready" } } \ No newline at end of file diff --git a/cmd/svcat/testdata/output/get-binding.yaml b/cmd/svcat/testdata/output/get-binding.yaml index a81b4f4e62c..07e6281d574 100644 --- a/cmd/svcat/testdata/output/get-binding.yaml +++ b/cmd/svcat/testdata/output/get-binding.yaml @@ -39,6 +39,7 @@ status: ps2: two secretparam1: secretparam2: + lastConditionState: Ready orphanMitigationInProgress: false reconciledGeneration: 1 unbindStatus: Required diff --git a/cmd/svcat/testdata/output/get-bindings.json b/cmd/svcat/testdata/output/get-bindings.json index 4f37bec6fe1..c205a990890 100644 --- a/cmd/svcat/testdata/output/get-bindings.json +++ b/cmd/svcat/testdata/output/get-bindings.json @@ -42,7 +42,8 @@ "parameterChecksum": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a" }, "orphanMitigationInProgress": false, - "unbindStatus": "Required" + "unbindStatus": "Required", + "lastConditionState": "Ready" } } ] diff --git a/cmd/svcat/testdata/output/get-bindings.yaml b/cmd/svcat/testdata/output/get-bindings.yaml index 1bee257b125..16ffba71c6d 100644 --- a/cmd/svcat/testdata/output/get-bindings.yaml +++ b/cmd/svcat/testdata/output/get-bindings.yaml @@ -26,6 +26,7 @@ items: externalProperties: parameterChecksum: 44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a parameters: {} + lastConditionState: Ready orphanMitigationInProgress: false reconciledGeneration: 1 unbindStatus: Required diff --git a/cmd/svcat/testdata/output/get-broker.json b/cmd/svcat/testdata/output/get-broker.json index cad6e6065f1..06640b945b9 100644 --- a/cmd/svcat/testdata/output/get-broker.json +++ b/cmd/svcat/testdata/output/get-broker.json @@ -27,6 +27,7 @@ } ], "reconciledGeneration": 2, - "lastCatalogRetrievalTime": "2018-01-12T02:10:27Z" + "lastCatalogRetrievalTime": "2018-01-12T02:10:27Z", + "lastConditionState": "Ready" } } \ No newline at end of file diff --git a/cmd/svcat/testdata/output/get-broker.yaml b/cmd/svcat/testdata/output/get-broker.yaml index bc52b1c1be8..7d1ac065a6f 100644 --- a/cmd/svcat/testdata/output/get-broker.yaml +++ b/cmd/svcat/testdata/output/get-broker.yaml @@ -20,4 +20,5 @@ status: status: "True" type: Ready lastCatalogRetrievalTime: "2018-01-12T02:10:27Z" + lastConditionState: Ready reconciledGeneration: 2 diff --git a/cmd/svcat/testdata/output/get-brokers.json b/cmd/svcat/testdata/output/get-brokers.json index 21bb14c1d23..61d881021fd 100644 --- a/cmd/svcat/testdata/output/get-brokers.json +++ b/cmd/svcat/testdata/output/get-brokers.json @@ -28,7 +28,8 @@ } ], "reconciledGeneration": 2, - "lastCatalogRetrievalTime": "2018-01-12T02:10:27Z" + "lastCatalogRetrievalTime": "2018-01-12T02:10:27Z", + "lastConditionState": "Ready" } }, { @@ -60,7 +61,8 @@ } ], "reconciledGeneration": 2, - "lastCatalogRetrievalTime": "2018-01-12T02:10:27Z" + "lastCatalogRetrievalTime": "2018-01-12T02:10:27Z", + "lastConditionState": "Ready" } } ] \ No newline at end of file diff --git a/cmd/svcat/testdata/output/get-brokers.yaml b/cmd/svcat/testdata/output/get-brokers.yaml index 331f47acc24..8d846214575 100644 --- a/cmd/svcat/testdata/output/get-brokers.yaml +++ b/cmd/svcat/testdata/output/get-brokers.yaml @@ -20,6 +20,7 @@ status: "True" type: Ready lastCatalogRetrievalTime: "2018-01-12T02:10:27Z" + lastConditionState: Ready reconciledGeneration: 2 - metadata: creationTimestamp: "2018-01-11T20:53:30Z" @@ -43,4 +44,5 @@ status: "True" type: Ready lastCatalogRetrievalTime: "2018-01-12T02:10:27Z" + lastConditionState: Ready reconciledGeneration: 2 diff --git a/cmd/svcat/testdata/output/get-instance.json b/cmd/svcat/testdata/output/get-instance.json index a611eb6bd87..f99233fe179 100644 --- a/cmd/svcat/testdata/output/get-instance.json +++ b/cmd/svcat/testdata/output/get-instance.json @@ -67,6 +67,9 @@ "parameterChecksum": "23ca85e0f9fc05340ea0a13ef945602cd5cdc3f52d763e750cb0ab0cb172a94f" }, "provisionStatus": "", - "deprovisionStatus": "Required" + "deprovisionStatus": "Required", + "lastConditionState": "Ready", + "userSpecifiedPlanName": "", + "userSpecifiedClassName": "" } } \ No newline at end of file diff --git a/cmd/svcat/testdata/output/get-instance.yaml b/cmd/svcat/testdata/output/get-instance.yaml index 75b0ba7945d..5ae13cb959d 100644 --- a/cmd/svcat/testdata/output/get-instance.yaml +++ b/cmd/svcat/testdata/output/get-instance.yaml @@ -46,7 +46,10 @@ status: ps2: two secretparam1: secretparam2: + lastConditionState: Ready observedGeneration: 0 orphanMitigationInProgress: false provisionStatus: "" reconciledGeneration: 1 + userSpecifiedClassName: "" + userSpecifiedPlanName: "" diff --git a/cmd/svcat/testdata/output/get-instances.json b/cmd/svcat/testdata/output/get-instances.json index b97fc05e04f..9e104880a12 100644 --- a/cmd/svcat/testdata/output/get-instances.json +++ b/cmd/svcat/testdata/output/get-instances.json @@ -51,7 +51,10 @@ "parameterChecksum": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a" }, "provisionStatus": "", - "deprovisionStatus": "Required" + "deprovisionStatus": "Required", + "lastConditionState": "Ready", + "userSpecifiedPlanName": "", + "userSpecifiedClassName": "" } } ] diff --git a/cmd/svcat/testdata/output/get-instances.yaml b/cmd/svcat/testdata/output/get-instances.yaml index 9eea9fe458b..8aab1ddf126 100644 --- a/cmd/svcat/testdata/output/get-instances.yaml +++ b/cmd/svcat/testdata/output/get-instances.yaml @@ -33,10 +33,13 @@ items: clusterServicePlanExternalName: default parameterChecksum: 44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a parameters: {} + lastConditionState: Ready observedGeneration: 0 orphanMitigationInProgress: false provisionStatus: "" reconciledGeneration: 1 + userSpecifiedClassName: "" + userSpecifiedPlanName: "" metadata: resourceVersion: "109" selfLink: /apis/servicecatalog.k8s.io/v1beta1/serviceinstances diff --git a/cmd/svcat/testdata/responses/catalog/clusterservicebrokers.json b/cmd/svcat/testdata/responses/catalog/clusterservicebrokers.json index 0465f33c94e..cdb6c106371 100644 --- a/cmd/svcat/testdata/responses/catalog/clusterservicebrokers.json +++ b/cmd/svcat/testdata/responses/catalog/clusterservicebrokers.json @@ -34,6 +34,7 @@ "message": "Successfully fetched catalog entries from broker." } ], + "lastConditionState": "Ready", "reconciledGeneration": 2, "lastCatalogRetrievalTime": "2018-01-12T02:10:27Z" } diff --git a/cmd/svcat/testdata/responses/catalog/clusterservicebrokers/ups-broker.json b/cmd/svcat/testdata/responses/catalog/clusterservicebrokers/ups-broker.json index 49aacdeefd1..9c778f4a7b5 100644 --- a/cmd/svcat/testdata/responses/catalog/clusterservicebrokers/ups-broker.json +++ b/cmd/svcat/testdata/responses/catalog/clusterservicebrokers/ups-broker.json @@ -28,6 +28,7 @@ "message": "Successfully fetched catalog entries from broker." } ], + "lastConditionState": "Ready", "reconciledGeneration": 2, "lastCatalogRetrievalTime": "2018-01-12T02:10:27Z" } diff --git a/cmd/svcat/testdata/responses/catalog/namespaces/default/servicebindings.json b/cmd/svcat/testdata/responses/catalog/namespaces/default/servicebindings.json index f6b9076abce..135942fd0bf 100644 --- a/cmd/svcat/testdata/responses/catalog/namespaces/default/servicebindings.json +++ b/cmd/svcat/testdata/responses/catalog/namespaces/default/servicebindings.json @@ -37,6 +37,7 @@ "message": "Injected bind result" } ], + "lastConditionState": "Ready", "asyncOpInProgress": false, "reconciledGeneration": 1, "externalProperties": { diff --git a/cmd/svcat/testdata/responses/catalog/namespaces/default/servicebindings/ups-binding.json b/cmd/svcat/testdata/responses/catalog/namespaces/default/servicebindings/ups-binding.json index 8600c7c04c8..cef29814805 100644 --- a/cmd/svcat/testdata/responses/catalog/namespaces/default/servicebindings/ups-binding.json +++ b/cmd/svcat/testdata/responses/catalog/namespaces/default/servicebindings/ups-binding.json @@ -31,6 +31,7 @@ "message": "Injected bind result" } ], + "lastConditionState": "Ready", "asyncOpInProgress": false, "reconciledGeneration": 1, "externalProperties": { diff --git a/cmd/svcat/testdata/responses/catalog/namespaces/default/servicebrokers.json b/cmd/svcat/testdata/responses/catalog/namespaces/default/servicebrokers.json index c39af62d821..29f8a6e80df 100644 --- a/cmd/svcat/testdata/responses/catalog/namespaces/default/servicebrokers.json +++ b/cmd/svcat/testdata/responses/catalog/namespaces/default/servicebrokers.json @@ -34,6 +34,7 @@ "message": "Successfully fetched catalog entries from broker." } ], + "lastConditionState": "Ready", "reconciledGeneration": 2, "lastCatalogRetrievalTime": "2018-01-12T02:10:27Z" } diff --git a/cmd/svcat/testdata/responses/catalog/namespaces/default/servicebrokers/ups-broker.json b/cmd/svcat/testdata/responses/catalog/namespaces/default/servicebrokers/ups-broker.json index 53441ae6a67..7ff4fbd2934 100644 --- a/cmd/svcat/testdata/responses/catalog/namespaces/default/servicebrokers/ups-broker.json +++ b/cmd/svcat/testdata/responses/catalog/namespaces/default/servicebrokers/ups-broker.json @@ -28,6 +28,7 @@ "message": "Successfully fetched catalog entries from broker." } ], + "lastConditionState": "Ready", "reconciledGeneration": 2, "lastCatalogRetrievalTime": "2018-01-12T02:10:27Z" } diff --git a/cmd/svcat/testdata/responses/catalog/namespaces/default/serviceinstances.json b/cmd/svcat/testdata/responses/catalog/namespaces/default/serviceinstances.json index 7864bae88e0..645c1480a4d 100644 --- a/cmd/svcat/testdata/responses/catalog/namespaces/default/serviceinstances.json +++ b/cmd/svcat/testdata/responses/catalog/namespaces/default/serviceinstances.json @@ -42,6 +42,7 @@ "message": "The instance was provisioned successfully" } ], + "lastConditionState": "Ready", "asyncOpInProgress": false, "orphanMitigationInProgress": false, "reconciledGeneration": 1, diff --git a/cmd/svcat/testdata/responses/catalog/namespaces/default/serviceinstances/ups-instance.json b/cmd/svcat/testdata/responses/catalog/namespaces/default/serviceinstances/ups-instance.json index 0a593d7629c..6ba9b97f910 100644 --- a/cmd/svcat/testdata/responses/catalog/namespaces/default/serviceinstances/ups-instance.json +++ b/cmd/svcat/testdata/responses/catalog/namespaces/default/serviceinstances/ups-instance.json @@ -36,6 +36,7 @@ "message": "The instance was provisioned successfully" } ], + "lastConditionState": "Ready", "asyncOpInProgress": false, "orphanMitigationInProgress": false, "reconciledGeneration": 1, diff --git a/cmd/svcat/testdata/responses/catalog/namespaces/test-ns/servicebindings.json b/cmd/svcat/testdata/responses/catalog/namespaces/test-ns/servicebindings.json index 16afdd1650f..99672371796 100644 --- a/cmd/svcat/testdata/responses/catalog/namespaces/test-ns/servicebindings.json +++ b/cmd/svcat/testdata/responses/catalog/namespaces/test-ns/servicebindings.json @@ -44,7 +44,8 @@ "parameterChecksum": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a" }, "orphanMitigationInProgress": false, - "unbindStatus": "Required" + "unbindStatus": "Required", + "lastConditionState": "Ready" } } ] diff --git a/cmd/svcat/testdata/responses/catalog/namespaces/test-ns/servicebindings/ups-binding.json b/cmd/svcat/testdata/responses/catalog/namespaces/test-ns/servicebindings/ups-binding.json index fc4e6fb73dc..b217469f88e 100644 --- a/cmd/svcat/testdata/responses/catalog/namespaces/test-ns/servicebindings/ups-binding.json +++ b/cmd/svcat/testdata/responses/catalog/namespaces/test-ns/servicebindings/ups-binding.json @@ -34,6 +34,7 @@ "message": "Injected bind result" } ], + "lastConditionState": "Ready", "asyncOpInProgress": false, "reconciledGeneration": 1, "externalProperties": { diff --git a/cmd/svcat/testdata/responses/catalog/namespaces/test-ns/servicebrokers.json b/cmd/svcat/testdata/responses/catalog/namespaces/test-ns/servicebrokers.json index b8c1afba70f..b34d947390f 100644 --- a/cmd/svcat/testdata/responses/catalog/namespaces/test-ns/servicebrokers.json +++ b/cmd/svcat/testdata/responses/catalog/namespaces/test-ns/servicebrokers.json @@ -35,6 +35,7 @@ "message": "Successfully fetched catalog entries from broker." } ], + "lastConditionState": "Ready", "reconciledGeneration": 2, "lastCatalogRetrievalTime": "2018-01-12T02:10:27Z" } diff --git a/cmd/svcat/testdata/responses/catalog/namespaces/test-ns/servicebrokers/ups-broker-ns.json b/cmd/svcat/testdata/responses/catalog/namespaces/test-ns/servicebrokers/ups-broker-ns.json index b2c5f5e5422..1eaf6dd2505 100644 --- a/cmd/svcat/testdata/responses/catalog/namespaces/test-ns/servicebrokers/ups-broker-ns.json +++ b/cmd/svcat/testdata/responses/catalog/namespaces/test-ns/servicebrokers/ups-broker-ns.json @@ -29,6 +29,7 @@ "message": "Successfully fetched catalog entries from broker." } ], + "lastConditionState": "Ready", "reconciledGeneration": 2, "lastCatalogRetrievalTime": "2018-01-12T02:10:27Z" } diff --git a/cmd/svcat/testdata/responses/catalog/namespaces/test-ns/serviceinstances.json b/cmd/svcat/testdata/responses/catalog/namespaces/test-ns/serviceinstances.json index 6ce4229a4b3..8e5dffb0c42 100644 --- a/cmd/svcat/testdata/responses/catalog/namespaces/test-ns/serviceinstances.json +++ b/cmd/svcat/testdata/responses/catalog/namespaces/test-ns/serviceinstances.json @@ -42,6 +42,7 @@ "message": "The instance was provisioned successfully" } ], + "lastConditionState": "Ready", "asyncOpInProgress": false, "orphanMitigationInProgress": false, "reconciledGeneration": 1, diff --git a/cmd/svcat/testdata/responses/catalog/namespaces/test-ns/serviceinstances/ups-instance.json b/cmd/svcat/testdata/responses/catalog/namespaces/test-ns/serviceinstances/ups-instance.json index 8bb574e47d0..28272ce183e 100644 --- a/cmd/svcat/testdata/responses/catalog/namespaces/test-ns/serviceinstances/ups-instance.json +++ b/cmd/svcat/testdata/responses/catalog/namespaces/test-ns/serviceinstances/ups-instance.json @@ -39,6 +39,7 @@ "message": "The instance was provisioned successfully" } ], + "lastConditionState": "Ready", "asyncOpInProgress": false, "orphanMitigationInProgress": false, "reconciledGeneration": 1, diff --git a/cmd/svcat/testdata/responses/catalog/serviceinstances.json b/cmd/svcat/testdata/responses/catalog/serviceinstances.json index 297e5c06d41..a76fb042e72 100644 --- a/cmd/svcat/testdata/responses/catalog/serviceinstances.json +++ b/cmd/svcat/testdata/responses/catalog/serviceinstances.json @@ -42,6 +42,9 @@ "message": "The instance was provisioned successfully" } ], + "lastConditionState": "Ready", + "userSpecifiedPlanName": "", + "userSpecifiedClassName": "", "asyncOpInProgress": false, "orphanMitigationInProgress": false, "reconciledGeneration": 1, @@ -90,6 +93,9 @@ "message": "The instance was provisioned successfully" } ], + "lastConditionState": "Ready", + "userSpecifiedPlanName": "", + "userSpecifiedClassName": "", "asyncOpInProgress": false, "orphanMitigationInProgress": false, "reconciledGeneration": 1, diff --git a/cmd/svcat/testdata/responses/catalog/serviceinstances_labelSelector=servicecatalog.k8s.io_spec.clusterServicePlanRef.name=86064792-7ea2-467b-af93-ac9694d96d52.json b/cmd/svcat/testdata/responses/catalog/serviceinstances_labelSelector=servicecatalog.k8s.io_spec.clusterServicePlanRef.name=86064792-7ea2-467b-af93-ac9694d96d52.json index 6ce4229a4b3..8d78eacb369 100644 --- a/cmd/svcat/testdata/responses/catalog/serviceinstances_labelSelector=servicecatalog.k8s.io_spec.clusterServicePlanRef.name=86064792-7ea2-467b-af93-ac9694d96d52.json +++ b/cmd/svcat/testdata/responses/catalog/serviceinstances_labelSelector=servicecatalog.k8s.io_spec.clusterServicePlanRef.name=86064792-7ea2-467b-af93-ac9694d96d52.json @@ -51,7 +51,10 @@ "parameters": {}, "parameterChecksum": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a" }, - "deprovisionStatus": "Required" + "deprovisionStatus": "Required", + "lastConditionState": "Ready", + "userSpecifiedPlanName": "", + "userSpecifiedClassName": "" } } ] diff --git a/pkg/apis/servicecatalog/types.go b/pkg/apis/servicecatalog/types.go index 3df14ca69fb..e2874c0ccd6 100644 --- a/pkg/apis/servicecatalog/types.go +++ b/pkg/apis/servicecatalog/types.go @@ -288,6 +288,10 @@ type CommonServiceBrokerStatus struct { // LastCatalogRetrievalTime is the time the Catalog was last fetched from // the Service Broker LastCatalogRetrievalTime *metav1.Time + + // LastConditionState aggregates state from the Conditions array + // It is used for printing in a kubectl output via additionalPrinterColumns + LastConditionState string `json:"lastConditionState"` } // ClusterServiceBrokerStatus represents the current status of a @@ -898,6 +902,18 @@ type ServiceInstanceStatus struct { // DefaultProvisionParameters are the default parameters applied to this // instance. DefaultProvisionParameters *runtime.RawExtension + + // LastConditionState aggregates state from the Conditions array + // It is used for printing in a kubectl output via additionalPrinterColumns + LastConditionState string `json:"lastConditionState"` + + // UserSpecifiedPlanName aggregates cluster or namespace PlanName + // It is used for printing in a kubectl output via additionalPrinterColumns + UserSpecifiedPlanName string `json:"userSpecifiedPlanName"` + + // UserSpecifiedClassName aggregates cluster or namespace ClassName + // It is used for printing in a kubectl output via additionalPrinterColumns + UserSpecifiedClassName string `json:"userSpecifiedClassName"` } // ServiceInstanceCondition contains condition information about an Instance. @@ -1148,6 +1164,10 @@ type ServiceBindingStatus struct { // UnbindStatus describes what has been done to unbind a ServiceBinding UnbindStatus ServiceBindingUnbindStatus + + // LastConditionState aggregates state from the Conditions array + // It is used for printing in a kubectl output via additionalPrinterColumns + LastConditionState string `json:"lastConditionState"` } // ServiceBindingCondition condition information for a ServiceBinding. diff --git a/pkg/apis/servicecatalog/v1beta1/types.go b/pkg/apis/servicecatalog/v1beta1/types.go index 1e1bf7c3e95..8542c0e50c4 100644 --- a/pkg/apis/servicecatalog/v1beta1/types.go +++ b/pkg/apis/servicecatalog/v1beta1/types.go @@ -309,6 +309,10 @@ type CommonServiceBrokerStatus struct { // LastCatalogRetrievalTime is the time the Catalog was last fetched from // the Service Broker LastCatalogRetrievalTime *metav1.Time `json:"lastCatalogRetrievalTime,omitempty"` + + // LastConditionState aggregates state from the Conditions array + // It is used for printing in a kubectl output via additionalPrinterColumns + LastConditionState string `json:"lastConditionState"` } // ClusterServiceBrokerStatus represents the current status of a @@ -987,6 +991,18 @@ type ServiceInstanceStatus struct { // DefaultProvisionParameters are the default parameters applied to this // instance. DefaultProvisionParameters *runtime.RawExtension `json:"defaultProvisionParameters,omitempty"` + + // LastConditionState aggregates state from the Conditions array + // It is used for printing in a kubectl output via additionalPrinterColumns + LastConditionState string `json:"lastConditionState"` + + // UserSpecifiedPlanName aggregates cluster or namespace PlanName + // It is used for printing in a kubectl output via additionalPrinterColumns + UserSpecifiedPlanName string `json:"userSpecifiedPlanName"` + + // UserSpecifiedClassName aggregates cluster or namespace ClassName + // It is used for printing in a kubectl output via additionalPrinterColumns + UserSpecifiedClassName string `json:"userSpecifiedClassName"` } // ServiceInstanceCondition contains condition information about an Instance. @@ -1248,6 +1264,10 @@ type ServiceBindingStatus struct { // UnbindStatus describes what has been done to unbind the ServiceBinding. UnbindStatus ServiceBindingUnbindStatus `json:"unbindStatus"` + + // LastConditionState aggregates state from the Conditions array + // It is used for printing in a kubectl output via additionalPrinterColumns + LastConditionState string `json:"lastConditionState"` } // ServiceBindingCondition condition information for a ServiceBinding. diff --git a/pkg/apis/servicecatalog/v1beta1/zz_generated.conversion.go b/pkg/apis/servicecatalog/v1beta1/zz_generated.conversion.go index c9852a8cb20..58a9e17691b 100644 --- a/pkg/apis/servicecatalog/v1beta1/zz_generated.conversion.go +++ b/pkg/apis/servicecatalog/v1beta1/zz_generated.conversion.go @@ -1204,6 +1204,7 @@ func autoConvert_v1beta1_CommonServiceBrokerStatus_To_servicecatalog_CommonServi out.ReconciledGeneration = in.ReconciledGeneration out.OperationStartTime = (*v1.Time)(unsafe.Pointer(in.OperationStartTime)) out.LastCatalogRetrievalTime = (*v1.Time)(unsafe.Pointer(in.LastCatalogRetrievalTime)) + out.LastConditionState = in.LastConditionState return nil } @@ -1217,6 +1218,7 @@ func autoConvert_servicecatalog_CommonServiceBrokerStatus_To_v1beta1_CommonServi out.ReconciledGeneration = in.ReconciledGeneration out.OperationStartTime = (*v1.Time)(unsafe.Pointer(in.OperationStartTime)) out.LastCatalogRetrievalTime = (*v1.Time)(unsafe.Pointer(in.LastCatalogRetrievalTime)) + out.LastConditionState = in.LastConditionState return nil } @@ -1690,6 +1692,7 @@ func autoConvert_v1beta1_ServiceBindingStatus_To_servicecatalog_ServiceBindingSt out.ExternalProperties = (*servicecatalog.ServiceBindingPropertiesState)(unsafe.Pointer(in.ExternalProperties)) out.OrphanMitigationInProgress = in.OrphanMitigationInProgress out.UnbindStatus = servicecatalog.ServiceBindingUnbindStatus(in.UnbindStatus) + out.LastConditionState = in.LastConditionState return nil } @@ -1709,6 +1712,7 @@ func autoConvert_servicecatalog_ServiceBindingStatus_To_v1beta1_ServiceBindingSt out.ExternalProperties = (*ServiceBindingPropertiesState)(unsafe.Pointer(in.ExternalProperties)) out.OrphanMitigationInProgress = in.OrphanMitigationInProgress out.UnbindStatus = ServiceBindingUnbindStatus(in.UnbindStatus) + out.LastConditionState = in.LastConditionState return nil } @@ -2146,6 +2150,9 @@ func autoConvert_v1beta1_ServiceInstanceStatus_To_servicecatalog_ServiceInstance out.ProvisionStatus = servicecatalog.ServiceInstanceProvisionStatus(in.ProvisionStatus) out.DeprovisionStatus = servicecatalog.ServiceInstanceDeprovisionStatus(in.DeprovisionStatus) out.DefaultProvisionParameters = (*runtime.RawExtension)(unsafe.Pointer(in.DefaultProvisionParameters)) + out.LastConditionState = in.LastConditionState + out.UserSpecifiedPlanName = in.UserSpecifiedPlanName + out.UserSpecifiedClassName = in.UserSpecifiedClassName return nil } @@ -2169,6 +2176,9 @@ func autoConvert_servicecatalog_ServiceInstanceStatus_To_v1beta1_ServiceInstance out.ProvisionStatus = ServiceInstanceProvisionStatus(in.ProvisionStatus) out.DeprovisionStatus = ServiceInstanceDeprovisionStatus(in.DeprovisionStatus) out.DefaultProvisionParameters = (*runtime.RawExtension)(unsafe.Pointer(in.DefaultProvisionParameters)) + out.LastConditionState = in.LastConditionState + out.UserSpecifiedPlanName = in.UserSpecifiedPlanName + out.UserSpecifiedClassName = in.UserSpecifiedClassName return nil } diff --git a/pkg/controller/controller_binding.go b/pkg/controller/controller_binding.go index 9c5c16a00bc..c4470c7ff01 100644 --- a/pkg/controller/controller_binding.go +++ b/pkg/controller/controller_binding.go @@ -672,6 +672,7 @@ func setServiceBindingCondition(toUpdate *v1beta1.ServiceBinding, reason, message string) { setServiceBindingConditionInternal(toUpdate, conditionType, status, reason, message, metav1.Now()) + toUpdate.Status.LastConditionState = getServiceBindingLastConditionState(toUpdate.Status) } // setServiceBindingConditionInternal is @@ -1633,3 +1634,14 @@ func (c *controller) handleServiceBindingPollingError(binding *v1beta1.ServiceBi klog.V(4).Info(pcb.Messagef("Error during polling: %v", err)) return c.continuePollingServiceBinding(binding) } + +func getServiceBindingLastConditionState(status v1beta1.ServiceBindingStatus) string { + if len(status.Conditions) > 0 { + condition := status.Conditions[len(status.Conditions)-1] + if condition.Status == v1beta1.ConditionTrue { + return string(condition.Type) + } + return condition.Reason + } + return "" +} diff --git a/pkg/controller/controller_binding_test.go b/pkg/controller/controller_binding_test.go index daf05676a92..1c857fad562 100644 --- a/pkg/controller/controller_binding_test.go +++ b/pkg/controller/controller_binding_test.go @@ -1853,6 +1853,7 @@ func TestUpdateServiceBindingCondition(t *testing.T) { reason string message string transitionTimeChanged bool + expectedLastCondition string }{ { @@ -1860,12 +1861,14 @@ func TestUpdateServiceBindingCondition(t *testing.T) { input: getTestServiceBinding(), status: v1beta1.ConditionFalse, transitionTimeChanged: true, + expectedLastCondition: "", }, { name: "not ready -> not ready", input: getTestServiceBindingWithStatus(v1beta1.ConditionFalse), status: v1beta1.ConditionFalse, transitionTimeChanged: false, + expectedLastCondition: "", }, { name: "not ready -> not ready, message and reason change", @@ -1874,24 +1877,29 @@ func TestUpdateServiceBindingCondition(t *testing.T) { reason: "foo", message: "bar", transitionTimeChanged: false, + expectedLastCondition: "foo", }, { name: "not ready -> ready", input: getTestServiceBindingWithStatus(v1beta1.ConditionFalse), status: v1beta1.ConditionTrue, transitionTimeChanged: true, + expectedLastCondition: "Ready", }, { name: "ready -> ready", input: getTestServiceBindingWithStatus(v1beta1.ConditionTrue), status: v1beta1.ConditionTrue, transitionTimeChanged: false, + expectedLastCondition: "Ready", }, { name: "ready -> not ready", input: getTestServiceBindingWithStatus(v1beta1.ConditionTrue), status: v1beta1.ConditionFalse, + reason: "foo", transitionTimeChanged: true, + expectedLastCondition: "foo", }, } @@ -1920,6 +1928,10 @@ func TestUpdateServiceBindingCondition(t *testing.T) { t.Fatalf("%v: couldn't convert to binding", tc.name) } + if updateActionObject.Status.LastConditionState != tc.expectedLastCondition { + t.Fatalf("LastConditionState has unexpected value. Expected: %v, got: %v", tc.expectedLastCondition, updateActionObject.Status.LastConditionState) + } + var initialTs metav1.Time if len(inputClone.Status.Conditions) != 0 { initialTs = inputClone.Status.Conditions[0].LastTransitionTime diff --git a/pkg/controller/controller_clusterservicebroker.go b/pkg/controller/controller_clusterservicebroker.go index dbab4e21c12..9247486362f 100644 --- a/pkg/controller/controller_clusterservicebroker.go +++ b/pkg/controller/controller_clusterservicebroker.go @@ -678,6 +678,7 @@ func (c *controller) updateClusterServiceBrokerCondition(broker *v1beta1.Cluster now := metav1.NewTime(t) toUpdate.Status.LastCatalogRetrievalTime = &now } + toUpdate.Status.LastConditionState = getServiceBrokerLastConditionState(toUpdate.Status.CommonServiceBrokerStatus) klog.V(4).Info(pcb.Messagef("Updating ready condition to %v", status)) _, err := c.serviceCatalogClient.ClusterServiceBrokers().UpdateStatus(toUpdate) diff --git a/pkg/controller/controller_clusterservicebroker_test.go b/pkg/controller/controller_clusterservicebroker_test.go index 1aa7cdc09df..7734b72fab5 100644 --- a/pkg/controller/controller_clusterservicebroker_test.go +++ b/pkg/controller/controller_clusterservicebroker_test.go @@ -286,6 +286,15 @@ func TestReconcileClusterServiceBrokerExistingServiceClassAndServicePlan(t *test // verify no kube resources created kubeActions := fakeKubeClient.Actions() assertNumberOfActions(t, kubeActions, 0) + + updateObject, ok := updatedClusterServiceBroker.(*v1beta1.ClusterServiceBroker) + if !ok { + t.Fatalf("couldn't convert to *v1beta1.ClusterServiceBroker") + } + + if updateObject.Status.LastConditionState != "Ready" { + t.Fatalf("LastConditionState has unexpected value. Expected: %v, got: %v", "Ready", updateObject.Status.LastConditionState) + } } func TestReconcileClusterServiceBrokerRemovedClusterServiceClass(t *testing.T) { diff --git a/pkg/controller/controller_instance.go b/pkg/controller/controller_instance.go index dbe69599b7c..f04495fe94f 100644 --- a/pkg/controller/controller_instance.go +++ b/pkg/controller/controller_instance.go @@ -539,6 +539,14 @@ func (c *controller) reconcileServiceInstanceAdd(instance *v1beta1.ServiceInstan return nil } + if c.resolveServiceInstanceUserSpecifiedClassAndPlan(instance) { + updatedInstance, err := c.updateServiceInstanceStatus(instance) + if err != nil { + return err + } + instance.ResourceVersion = updatedInstance.ResourceVersion + } + if utilfeature.DefaultFeatureGate.Enabled(scfeatures.ServicePlanDefaults) { // Apply default provisioning parameters, this must be done after we've resolved the class and plan modified, err = c.applyDefaultProvisioningParameters(instance) @@ -772,6 +780,14 @@ func (c *controller) reconcileServiceInstanceUpdate(instance *v1beta1.ServiceIns )) } + if c.resolveServiceInstanceUserSpecifiedClassAndPlan(instance) { + updatedInstance, err := c.updateServiceInstanceStatus(instance) + if err != nil { + return err + } + instance.ResourceVersion = updatedInstance.ResourceVersion + } + c.setRetryBackoffRequired(instance) response, err := brokerClient.UpdateInstance(request) if err != nil { @@ -1909,6 +1925,7 @@ func (c *controller) updateServiceInstanceStatusWithRetries( const interval = 100 * time.Millisecond const timeout = 10 * time.Second var updatedInstance *v1beta1.ServiceInstance + instance.Status.LastConditionState = getServiceInstanceLastConditionState(instance.Status) instanceToUpdate := instance err := wait.PollImmediate(interval, timeout, func() (bool, error) { @@ -1954,6 +1971,7 @@ func (c *controller) updateServiceInstanceCondition( toUpdate := instance.DeepCopy() setServiceInstanceCondition(toUpdate, conditionType, status, reason, message) + toUpdate.Status.LastConditionState = getServiceInstanceLastConditionState(toUpdate.Status) klog.V(4).Info(pcb.Messagef("Updating %v condition to %v", conditionType, status)) updatedInstance, err := c.serviceCatalogClient.ServiceInstances(instance.Namespace).UpdateStatus(toUpdate) @@ -2916,3 +2934,39 @@ func setServiceInstanceLastOperation(instance *v1beta1.ServiceInstance, operatio instance.Status.LastOperation = &key } } + +func getServiceInstanceLastConditionState(status v1beta1.ServiceInstanceStatus) string { + if len(status.Conditions) > 0 { + condition := status.Conditions[len(status.Conditions)-1] + if condition.Status == v1beta1.ConditionTrue { + return string(condition.Type) + } + return condition.Reason + } + return "" +} + +func (c *controller) resolveServiceInstanceUserSpecifiedClassAndPlan(instance *v1beta1.ServiceInstance) bool { + if instance.Status.UserSpecifiedPlanName != "" || + instance.Status.UserSpecifiedClassName != "" { + return false + } + + class, plan := getServiceInstanceCommonClassAndPlan(*instance) + instance.Status.UserSpecifiedClassName = class + instance.Status.UserSpecifiedPlanName = plan + + return true +} + +func getServiceInstanceCommonClassAndPlan(instance v1beta1.ServiceInstance) (string, string) { + var class, plan string + if instance.Spec.ClusterServiceClassSpecified() && instance.Spec.ClusterServicePlanSpecified() { + class = fmt.Sprintf("ClusterServiceClass/%s", instance.Spec.GetSpecifiedClusterServiceClass()) + plan = instance.Spec.GetSpecifiedClusterServicePlan() + } else { + class = fmt.Sprintf("ServiceClass/%s", instance.Spec.GetSpecifiedServiceClass()) + plan = instance.Spec.GetSpecifiedServicePlan() + } + return class, plan +} diff --git a/pkg/controller/controller_instance_ns_test.go b/pkg/controller/controller_instance_ns_test.go index f0051dace08..374e7d3f22f 100644 --- a/pkg/controller/controller_instance_ns_test.go +++ b/pkg/controller/controller_instance_ns_test.go @@ -63,7 +63,7 @@ func TestReconcileServiceInstanceNamespacedRefs(t *testing.T) { t.Fatalf("unexpected error: %v", err) } - instance = assertServiceInstanceProvisionInProgressIsTheOnlyCatalogClientAction(t, fakeCatalogClient, instance) + instance = assertServiceInstanceProvisionInProgressAndUserSpecifiedFieldsClientActions(t, fakeCatalogClient, instance) fakeCatalogClient.ClearActions() assertNumberOfBrokerActions(t, fakeBrokerClient.Actions(), 0) @@ -150,7 +150,7 @@ func TestReconcileServiceInstanceAsynchronousNamespacedRefs(t *testing.T) { t.Fatalf("unexpected error: %v", err) } - instance = assertServiceInstanceProvisionInProgressIsTheOnlyCatalogClientAction(t, fakeCatalogClient, instance) + instance = assertServiceInstanceProvisionInProgressAndUserSpecifiedFieldsClientActions(t, fakeCatalogClient, instance) fakeCatalogClient.ClearActions() fakeKubeClient.ClearActions() diff --git a/pkg/controller/controller_instance_test.go b/pkg/controller/controller_instance_test.go index 2157c3ad00c..f7365c18d5f 100644 --- a/pkg/controller/controller_instance_test.go +++ b/pkg/controller/controller_instance_test.go @@ -218,10 +218,10 @@ func TestReconcileServiceInstanceNonExistentClusterServiceBroker(t *testing.T) { assertNumberOfBrokerActions(t, brokerActions, 0) actions := fakeCatalogClient.Actions() - assertNumberOfActions(t, actions, 1) + assertNumberOfActions(t, actions, 2) // There should only be one action that says it failed because no such broker exists. - updatedServiceInstance := assertUpdateStatus(t, actions[0], instance) + updatedServiceInstance := assertUpdateStatus(t, actions[1], instance) assertServiceInstanceErrorBeforeRequest(t, updatedServiceInstance, errorNonexistentClusterServiceBrokerReason, instance) events := getRecordedEvents(testController) @@ -262,10 +262,10 @@ func TestReconcileServiceInstanceWithNotExistingBroker(t *testing.T) { // verify that one catalog client action occurred actions := fakeCatalogClient.Actions() - assertNumberOfActions(t, actions, 1) + assertNumberOfActions(t, actions, 2) // There should only be one action that says it failed fetching auth credentials. - updatedServiceInstance := assertUpdateStatus(t, actions[0], instance) + updatedServiceInstance := assertUpdateStatus(t, actions[1], instance) assertServiceInstanceErrorBeforeRequest(t, updatedServiceInstance, errorNonexistentClusterServiceBrokerReason, instance) // verify that one event was emitted @@ -679,8 +679,8 @@ func TestReconcileServiceInstanceWithParameters(t *testing.T) { } actions := fakeCatalogClient.Actions() - assertNumberOfActions(t, actions, 1) - updatedServiceInstance := assertUpdateStatus(t, actions[0], instance) + assertNumberOfActions(t, actions, 2) + updatedServiceInstance := assertUpdateStatus(t, actions[1], instance) events := getRecordedEvents(testController) if tc.expectedError { @@ -884,11 +884,11 @@ func TestReconcileServiceInstanceAppliesDefaultProvisioningParams(t *testing.T) } actions := fakeCatalogClient.Actions() - assertNumberOfActions(t, actions, 2) + assertNumberOfActions(t, actions, 3) // Check that the default provisioning parameters defined on the plan is // now on the service instance - updatedServiceInstance := assertUpdate(t, actions[0], instance) + updatedServiceInstance := assertUpdate(t, actions[1], instance) updateObject, ok := updatedServiceInstance.(*v1beta1.ServiceInstance) if !ok { t.Fatalf("couldn't convert to *v1beta1.ServiceInstance") @@ -901,7 +901,7 @@ func TestReconcileServiceInstanceAppliesDefaultProvisioningParams(t *testing.T) } // Check that the default parameters were saved on the status - updatedServiceInstance = assertUpdateStatus(t, actions[1], instance) + updatedServiceInstance = assertUpdateStatus(t, actions[2], instance) updateObject, ok = updatedServiceInstance.(*v1beta1.ServiceInstance) if !ok { t.Fatalf("couldn't convert to *v1beta1.ServiceInstance") @@ -955,11 +955,11 @@ func TestReconcileServiceInstanceRespectsServicePlanDefaultsMutableFeatureGate(t } actions := fakeCatalogClient.Actions() - assertNumberOfActions(t, actions, 1) + assertNumberOfActions(t, actions, 2) // Check that the default parameters were not saved on the status // because the feature is disabled - updatedServiceInstance := assertUpdateStatus(t, actions[0], instance) + updatedServiceInstance := assertUpdateStatus(t, actions[1], instance) updateObject, ok := updatedServiceInstance.(*v1beta1.ServiceInstance) if !ok { t.Fatalf("couldn't convert to *v1beta1.ServiceInstance") @@ -1062,7 +1062,7 @@ func TestReconcileServiceInstanceWithProvisionCallFailure(t *testing.T) { t.Fatalf("unexpected error: %v", err) } - instance = assertServiceInstanceProvisionInProgressIsTheOnlyCatalogClientAction(t, fakeCatalogClient, instance) + instance = assertServiceInstanceProvisionInProgressAndUserSpecifiedFieldsClientActions(t, fakeCatalogClient, instance) fakeCatalogClient.ClearActions() fakeKubeClient.ClearActions() @@ -1147,11 +1147,11 @@ func TestReconcileServiceInstanceWithTemporaryProvisionFailure(t *testing.T) { } actions := fakeCatalogClient.Actions() - assertNumberOfActions(t, actions, 1) - updatedServiceInstance := assertUpdateStatus(t, actions[0], instance) + assertNumberOfActions(t, actions, 2) + updatedServiceInstance := assertUpdateStatus(t, actions[1], instance) events := getRecordedEvents(testController) - updatedServiceInstance = assertUpdateStatus(t, actions[0], instance) + updatedServiceInstance = assertUpdateStatus(t, actions[1], instance) assertServiceInstanceOperationInProgress(t, updatedServiceInstance, v1beta1.ServiceInstanceOperationProvision, @@ -1248,7 +1248,7 @@ func TestReconcileServiceInstanceWithTerminalProvisionFailure(t *testing.T) { t.Fatalf("unexpected error: %v", err) } - instance = assertServiceInstanceProvisionInProgressIsTheOnlyCatalogClientAction(t, fakeCatalogClient, instance) + instance = assertServiceInstanceProvisionInProgressAndUserSpecifiedFieldsClientActions(t, fakeCatalogClient, instance) fakeCatalogClient.ClearActions() fakeKubeClient.ClearActions() @@ -1326,7 +1326,7 @@ func TestReconcileServiceInstance(t *testing.T) { t.Fatalf("unexpected error: %v", err) } - instance = assertServiceInstanceProvisionInProgressIsTheOnlyCatalogClientAction(t, fakeCatalogClient, instance) + instance = assertServiceInstanceProvisionInProgressAndUserSpecifiedFieldsClientActions(t, fakeCatalogClient, instance) fakeCatalogClient.ClearActions() assertNumberOfBrokerActions(t, fakeClusterServiceBrokerClient.Actions(), 0) @@ -1408,13 +1408,13 @@ func TestReconcileServiceInstanceFailsWithDeletedPlan(t *testing.T) { } actions := fakeCatalogClient.Actions() - assertNumberOfActions(t, actions, 1) + assertNumberOfActions(t, actions, 2) // verify no kube actions kubeActions := fakeKubeClient.Actions() assertNumberOfActions(t, kubeActions, 0) - updatedServiceInstance := assertUpdateStatus(t, actions[0], instance) + updatedServiceInstance := assertUpdateStatus(t, actions[1], instance) assertServiceInstanceReadyFalse(t, updatedServiceInstance, errorDeletedClusterServicePlanReason) events := getRecordedEvents(testController) @@ -1458,13 +1458,13 @@ func TestReconcileServiceInstanceFailsWithDeletedClass(t *testing.T) { } actions := fakeCatalogClient.Actions() - assertNumberOfActions(t, actions, 1) + assertNumberOfActions(t, actions, 2) // verify no kube actions kubeActions := fakeKubeClient.Actions() assertNumberOfActions(t, kubeActions, 0) - updatedServiceInstance := assertUpdateStatus(t, actions[0], instance) + updatedServiceInstance := assertUpdateStatus(t, actions[1], instance) assertServiceInstanceReadyFalse(t, updatedServiceInstance, errorDeletedClusterServiceClassReason) events := getRecordedEvents(testController) @@ -1523,7 +1523,7 @@ func TestReconcileServiceInstanceSuccessWithK8SNames(t *testing.T) { t.Fatalf("This should not fail : %v", err) } - instance = assertServiceInstanceProvisionInProgressIsTheOnlyCatalogClientAction(t, fakeCatalogClient, instance) + instance = assertServiceInstanceProvisionInProgressAndUserSpecifiedFieldsClientActions(t, fakeCatalogClient, instance) fakeCatalogClient.ClearActions() fakeKubeClient.ClearActions() @@ -1601,7 +1601,7 @@ func TestReconcileServiceInstanceAsynchronous(t *testing.T) { t.Fatalf("unexpected error: %v", err) } - instance = assertServiceInstanceProvisionInProgressIsTheOnlyCatalogClientAction(t, fakeCatalogClient, instance) + instance = assertServiceInstanceProvisionInProgressAndUserSpecifiedFieldsClientActions(t, fakeCatalogClient, instance) fakeCatalogClient.ClearActions() fakeKubeClient.ClearActions() @@ -1671,7 +1671,7 @@ func TestReconcileServiceInstanceAsynchronousNoOperation(t *testing.T) { t.Fatalf("unexpected error: %v", err) } - instance = assertServiceInstanceProvisionInProgressIsTheOnlyCatalogClientAction(t, fakeCatalogClient, instance) + instance = assertServiceInstanceProvisionInProgressAndUserSpecifiedFieldsClientActions(t, fakeCatalogClient, instance) fakeCatalogClient.ClearActions() fakeKubeClient.ClearActions() @@ -1748,9 +1748,9 @@ func TestReconcileServiceInstanceNamespaceError(t *testing.T) { } actions := fakeCatalogClient.Actions() - assertNumberOfActions(t, actions, 1) + assertNumberOfActions(t, actions, 2) - updatedServiceInstance := assertUpdateStatus(t, actions[0], instance) + updatedServiceInstance := assertUpdateStatus(t, actions[1], instance) assertServiceInstanceErrorBeforeRequest(t, updatedServiceInstance, errorFindingNamespaceServiceInstanceReason, instance) events := getRecordedEvents(testController) @@ -2500,7 +2500,7 @@ func TestReconcileServiceInstanceWithFailedCondition(t *testing.T) { if err := reconcileServiceInstance(t, testController, instance); err != nil { t.Fatalf("unexpected error: %v", err) } - instance = assertServiceInstanceProvisionInProgressIsTheOnlyCatalogClientAction(t, fakeCatalogClient, instance) + instance = assertServiceInstanceProvisionInProgressAndUserSpecifiedFieldsClientActions(t, fakeCatalogClient, instance) fakeCatalogClient.ClearActions() fakeKubeClient.ClearActions() @@ -3316,9 +3316,9 @@ func TestReconcileServiceInstanceSuccessOnFinalRetry(t *testing.T) { Context: testContext}) actions := fakeCatalogClient.Actions() - assertNumberOfActions(t, actions, 1) + assertNumberOfActions(t, actions, 2) - updatedServiceInstance := assertUpdateStatus(t, actions[0], instance) + updatedServiceInstance := assertUpdateStatus(t, actions[1], instance) assertServiceInstanceOperationSuccess(t, updatedServiceInstance, v1beta1.ServiceInstanceOperationProvision, testClusterServicePlanName, testClusterServicePlanGUID, instance) // verify no kube resources created @@ -3402,8 +3402,8 @@ func TestReconcileServiceInstanceUpdateInProgressPropertiesOnRetry(t *testing.T) expectedParametersChecksum := generateChecksumOfParametersOrFail(t, expectedParameters) actions := fakeCatalogClient.Actions() - assertNumberOfActions(t, actions, 1) - updatedServiceInstance := assertUpdateStatus(t, actions[0], instance).(*v1beta1.ServiceInstance) + assertNumberOfActions(t, actions, 2) + updatedServiceInstance := assertUpdateStatus(t, actions[1], instance).(*v1beta1.ServiceInstance) assertServiceInstanceOperationInProgressWithParameters(t, updatedServiceInstance, v1beta1.ServiceInstanceOperationProvision, testClusterServicePlanName, testClusterServicePlanGUID, expectedParameters, expectedParametersChecksum, instance) // verify no kube resources created @@ -3468,9 +3468,9 @@ func TestReconcileServiceInstanceFailureOnFinalRetry(t *testing.T) { } actions := fakeCatalogClient.Actions() - assertNumberOfActions(t, actions, 1) + assertNumberOfActions(t, actions, 2) - updatedServiceInstance := assertUpdateStatus(t, actions[0], instance) + updatedServiceInstance := assertUpdateStatus(t, actions[1], instance) assertServiceInstanceProvisionRequestFailingErrorNoOrphanMitigation( t, updatedServiceInstance, @@ -3624,6 +3624,8 @@ func TestReconcileServiceInstanceWithStatusUpdateError(t *testing.T) { sharedInformers.ClusterServicePlans().Informer().GetStore().Add(getTestClusterServicePlan()) instance := getTestServiceInstanceWithClusterRefs() + instance.Status.UserSpecifiedClassName = fmt.Sprintf("ClusterServiceClass/%s", instance.Spec.GetSpecifiedClusterServiceClass()) + instance.Status.UserSpecifiedClassName = instance.Spec.GetSpecifiedClusterServicePlan() fakeCatalogClient.AddReactor("update", "serviceinstances", func(action clientgotesting.Action) (bool, runtime.Object, error) { return true, nil, errors.New("update error") @@ -3839,6 +3841,7 @@ func TestUpdateServiceInstanceCondition(t *testing.T) { reason string message string transitionTimeChanged bool + expectedLastCondition string }{ { @@ -3847,12 +3850,14 @@ func TestUpdateServiceInstanceCondition(t *testing.T) { status: v1beta1.ConditionFalse, message: "message", transitionTimeChanged: true, + expectedLastCondition: "", }, { name: "not ready -> not ready", input: getTestServiceInstanceWithStatus(v1beta1.ConditionFalse), status: v1beta1.ConditionFalse, transitionTimeChanged: false, + expectedLastCondition: "", }, { name: "not ready -> not ready, reason and message change", @@ -3861,6 +3866,7 @@ func TestUpdateServiceInstanceCondition(t *testing.T) { reason: "foo", message: "bar", transitionTimeChanged: false, + expectedLastCondition: "foo", }, { name: "not ready -> ready", @@ -3868,6 +3874,7 @@ func TestUpdateServiceInstanceCondition(t *testing.T) { status: v1beta1.ConditionTrue, message: "message", transitionTimeChanged: true, + expectedLastCondition: "Ready", }, { name: "ready -> ready", @@ -3875,6 +3882,7 @@ func TestUpdateServiceInstanceCondition(t *testing.T) { status: v1beta1.ConditionTrue, message: "message", transitionTimeChanged: false, + expectedLastCondition: "Ready", }, { name: "ready -> not ready", @@ -3882,6 +3890,7 @@ func TestUpdateServiceInstanceCondition(t *testing.T) { status: v1beta1.ConditionFalse, message: "message", transitionTimeChanged: true, + expectedLastCondition: "", }, { name: "message -> message2", @@ -3889,6 +3898,7 @@ func TestUpdateServiceInstanceCondition(t *testing.T) { status: v1beta1.ConditionFalse, message: "message2", transitionTimeChanged: true, + expectedLastCondition: "", }, } @@ -3903,7 +3913,6 @@ func TestUpdateServiceInstanceCondition(t *testing.T) { if err != nil { t.Fatalf("%v: error updating instance condition: %v", tc.name, err) } - brokerActions := fakeClusterServiceBrokerClient.Actions() assertNumberOfBrokerActions(t, brokerActions, 0) @@ -3921,6 +3930,10 @@ func TestUpdateServiceInstanceCondition(t *testing.T) { t.Fatalf("%v: couldn't convert to instance", tc.name) } + if updateActionObject.Status.LastConditionState != tc.expectedLastCondition { + t.Fatalf("LastConditionState has unexpected value. Expected: %v, got: %v", tc.expectedLastCondition, updateActionObject.Status.LastConditionState) + } + var initialTs metav1.Time if len(inputClone.Status.Conditions) != 0 { initialTs = inputClone.Status.Conditions[0].LastTransitionTime @@ -3978,8 +3991,8 @@ func TestReconcileInstanceUsingOriginatingIdentity(t *testing.T) { } actions := fakeCatalogClient.Actions() - assertNumberOfActions(t, actions, 1) - updatedServiceInstance := assertUpdateStatus(t, actions[0], instance) + assertNumberOfActions(t, actions, 2) + updatedServiceInstance := assertUpdateStatus(t, actions[1], instance) instance = updatedServiceInstance.(*v1beta1.ServiceInstance) @@ -4180,7 +4193,7 @@ func TestReconcileServiceInstanceWithHTTPStatusCodeErrorOrphanMitigation(t *test t.Fatalf("unexpected error: %v", err) } - instance = assertServiceInstanceProvisionInProgressIsTheOnlyCatalogClientAction(t, fakeCatalogClient, instance) + instance = assertServiceInstanceProvisionInProgressAndUserSpecifiedFieldsClientActions(t, fakeCatalogClient, instance) fakeCatalogClient.ClearActions() err := reconcileServiceInstance(t, testController, instance) @@ -4230,7 +4243,7 @@ func TestReconcileServiceInstanceTimeoutTriggersOrphanMitigation(t *testing.T) { t.Fatalf("unexpected error: %v", err) } - instance = assertServiceInstanceProvisionInProgressIsTheOnlyCatalogClientAction(t, fakeCatalogClient, instance) + instance = assertServiceInstanceProvisionInProgressAndUserSpecifiedFieldsClientActions(t, fakeCatalogClient, instance) fakeCatalogClient.ClearActions() if err := reconcileServiceInstance(t, testController, instance); err == nil { @@ -4567,8 +4580,8 @@ func TestReconcileServiceInstanceWithSecretParameters(t *testing.T) { "b": "2", }) actions := fakeCatalogClient.Actions() - assertNumberOfActions(t, actions, 1) - updatedServiceInstance := assertUpdateStatus(t, actions[0], instance) + assertNumberOfActions(t, actions, 2) + updatedServiceInstance := assertUpdateStatus(t, actions[1], instance) assertServiceInstanceOperationInProgressWithParameters(t, updatedServiceInstance, v1beta1.ServiceInstanceOperationProvision, testClusterServicePlanName, testClusterServicePlanGUID, expectedParameters, expectedParametersChecksum, instance) instance = updatedServiceInstance.(*v1beta1.ServiceInstance) @@ -4806,9 +4819,9 @@ func TestReconcileServiceInstanceUpdateParameters(t *testing.T) { }) actions := fakeCatalogClient.Actions() - assertNumberOfActions(t, actions, 1) + assertNumberOfActions(t, actions, 2) - updatedServiceInstance := assertUpdateStatus(t, actions[0], instance) + updatedServiceInstance := assertUpdateStatus(t, actions[1], instance) assertServiceInstanceOperationSuccessWithParameters(t, updatedServiceInstance, v1beta1.ServiceInstanceOperationUpdate, testClusterServicePlanName, testClusterServicePlanGUID, expectedParameters, expectedParametersChecksum, instance) updateObject, ok := updatedServiceInstance.(*v1beta1.ServiceInstance) @@ -4816,6 +4829,10 @@ func TestReconcileServiceInstanceUpdateParameters(t *testing.T) { t.Fatalf("couldn't convert to *v1beta1.ServiceInstance") } + if updateObject.Status.LastConditionState != "Ready" { + t.Fatalf("LastConditionState has unexpected value. Expected: %v, got: %v", "Ready", updateObject.Status.LastConditionState) + } + // Verify parameters are what we'd expect them to be, basically name, map with two values in it. if len(updateObject.Spec.Parameters.Raw) == 0 { t.Fatalf("Parameters was unexpectedly empty") @@ -4903,9 +4920,9 @@ func TestReconcileServiceInstanceDeleteParameters(t *testing.T) { }) actions := fakeCatalogClient.Actions() - assertNumberOfActions(t, actions, 1) + assertNumberOfActions(t, actions, 2) - updatedServiceInstance := assertUpdateStatus(t, actions[0], instance) + updatedServiceInstance := assertUpdateStatus(t, actions[1], instance) assertServiceInstanceOperationSuccess(t, updatedServiceInstance, v1beta1.ServiceInstanceOperationUpdate, testClusterServicePlanName, testClusterServicePlanGUID, instance) updateObject, ok := updatedServiceInstance.(*v1beta1.ServiceInstance) @@ -5132,9 +5149,9 @@ func TestReconcileServiceInstanceUpdateDashboardURLResponse(t *testing.T) { }) actions := fakeCatalogClient.Actions() - assertNumberOfActions(t, actions, 1) + assertNumberOfActions(t, actions, 2) - updatedServiceInstance := assertUpdateStatus(t, actions[0], instance) + updatedServiceInstance := assertUpdateStatus(t, actions[1], instance) if tc.enableUpdateDashboardURL { if tc.newDashboardURL != "" { @@ -5243,9 +5260,9 @@ func TestReconcileServiceInstanceUpdatePlan(t *testing.T) { }) actions := fakeCatalogClient.Actions() - assertNumberOfActions(t, actions, 1) + assertNumberOfActions(t, actions, 2) - updatedServiceInstance := assertUpdateStatus(t, actions[0], instance) + updatedServiceInstance := assertUpdateStatus(t, actions[1], instance) assertServiceInstanceOperationSuccessWithParameters(t, updatedServiceInstance, v1beta1.ServiceInstanceOperationUpdate, testClusterServicePlanName, testClusterServicePlanGUID, oldParameters, oldParametersChecksum, instance) updateObject, ok := updatedServiceInstance.(*v1beta1.ServiceInstance) @@ -5322,9 +5339,9 @@ func TestReconcileServiceInstanceWithUpdateCallFailure(t *testing.T) { } actions := fakeCatalogClient.Actions() - assertNumberOfActions(t, actions, 1) + assertNumberOfActions(t, actions, 2) - updatedServiceInstance := assertUpdateStatus(t, actions[0], instance) + updatedServiceInstance := assertUpdateStatus(t, actions[1], instance) assertServiceInstanceRequestRetriableError(t, updatedServiceInstance, v1beta1.ServiceInstanceOperationUpdate, errorErrorCallingUpdateInstanceReason, testClusterServicePlanName, testClusterServicePlanGUID, instance) events := getRecordedEvents(testController) @@ -5420,9 +5437,9 @@ func TestReconcileServiceInstanceWithUpdateFailure(t *testing.T) { } actions := fakeCatalogClient.Actions() - assertNumberOfActions(t, actions, 1) + assertNumberOfActions(t, actions, 2) - updatedServiceInstance := assertUpdateStatus(t, actions[0], instance) + updatedServiceInstance := assertUpdateStatus(t, actions[1], instance) assertServiceInstanceUpdateRequestFailingErrorNoOrphanMitigation(t, updatedServiceInstance, v1beta1.ServiceInstanceOperationUpdate, errorUpdateInstanceCallFailedReason, tc.expectedFailureReason, instance) events := getRecordedEvents(testController) @@ -5699,9 +5716,9 @@ func TestReconcileServiceInstanceUpdateAsynchronous(t *testing.T) { Context: testContext}) actions := fakeCatalogClient.Actions() - assertNumberOfActions(t, actions, 1) + assertNumberOfActions(t, actions, 2) - updatedServiceInstance := assertUpdateStatus(t, actions[0], instance) + updatedServiceInstance := assertUpdateStatus(t, actions[1], instance) assertServiceInstanceAsyncStartInProgress(t, updatedServiceInstance, v1beta1.ServiceInstanceOperationUpdate, testOperation, testClusterServicePlanName, testClusterServicePlanGUID, instance) // verify no kube resources created. @@ -6378,3 +6395,43 @@ func reconcileServiceInstance(t *testing.T, testController *controller, instance } return err } + +func assertServiceInstanceProvisionInProgressAndUserSpecifiedFieldsClientActions(t *testing.T, fakeCatalogClient *fake.Clientset, instance *v1beta1.ServiceInstance) *v1beta1.ServiceInstance { + var planName, planGUID string + if instance.Spec.ClusterServiceClassSpecified() { + planName = testClusterServicePlanName + planGUID = testClusterServicePlanGUID + } else { + planName = testServicePlanName + planGUID = testServicePlanGUID + } + return assertServiceInstanceOperationInProgressAndUserSpecifiedFieldsClientActions(t, fakeCatalogClient, instance, v1beta1.ServiceInstanceOperationProvision, planName, planGUID) +} + +func assertServiceInstanceOperationInProgressAndUserSpecifiedFieldsClientActions(t *testing.T, fakeCatalogClient *fake.Clientset, instance *v1beta1.ServiceInstance, operation v1beta1.ServiceInstanceOperation, planName string, planGUID string) *v1beta1.ServiceInstance { + return assertServiceInstanceOperationInProgressWithParameterAndUserSpecifiedFieldsClientActions(t, fakeCatalogClient, instance, operation, planName, planGUID, nil, "") +} + +func assertServiceInstanceOperationInProgressWithParameterAndUserSpecifiedFieldsClientActions(t *testing.T, fakeCatalogClient *fake.Clientset, instance *v1beta1.ServiceInstance, operation v1beta1.ServiceInstanceOperation, planName string, planGUID string, parameters map[string]interface{}, parametersChecksum string) *v1beta1.ServiceInstance { + actions := fakeCatalogClient.Actions() + assertNumberOfActions(t, actions, 2) + + updateServiceInstance := assertUpdateStatus(t, actions[1], instance) + assertServiceInstanceOperationInProgressWithParameters(t, updateServiceInstance, operation, planName, planGUID, parameters, parametersChecksum, instance) + + updateObject, ok := updateServiceInstance.(*v1beta1.ServiceInstance) + if !ok { + t.Fatalf("couldn't convert to *v1beta1.ServiceInstance") + } + + class, plan := getServiceInstanceCommonClassAndPlan(*updateObject) + if updateObject.Status.UserSpecifiedClassName != class { + t.Fatalf("Unexpected ClassName: expected %v, got %v", class, updateObject.Status.UserSpecifiedClassName) + } + + if updateObject.Status.UserSpecifiedPlanName != plan { + t.Fatalf("Unexpected PlanName %v, got %v", plan, updateObject.Status.UserSpecifiedPlanName) + } + + return updateObject +} diff --git a/pkg/controller/controller_ns_test.go b/pkg/controller/controller_ns_test.go index 15e122d381e..fee777d7527 100644 --- a/pkg/controller/controller_ns_test.go +++ b/pkg/controller/controller_ns_test.go @@ -26,11 +26,13 @@ import ( ) const ( - testServiceClassGUID = "scguid" - testServicePlanGUID = "spguid" - testServiceBrokerName = "test-servicebroker" - testServiceClassName = "test-serviceclass" - testServicePlanName = "test-serviceplan" + testServiceClassGUID = "scguid" + testServicePlanGUID = "spguid" + testServiceBrokerName = "test-servicebroker" + testServiceClassName = "test-serviceclass" + testServicePlanName = "test-serviceplan" + testNonbindableServicePlanName = "test-unbindable-serviceplan" + testNonbindableServicePlanGUID = "unbindable-serviceplan" ) func getTestCommonServiceBrokerSpec() v1beta1.CommonServiceBrokerSpec { @@ -79,6 +81,10 @@ func assertServiceBrokerReadyFalse(t *testing.T, obj runtime.Object) { assertServiceBrokerCondition(t, obj, v1beta1.ServiceBrokerConditionReady, v1beta1.ConditionFalse) } +func assertServiceBrokerReadyTrue(t *testing.T, obj runtime.Object) { + assertServiceBrokerCondition(t, obj, v1beta1.ServiceBrokerConditionReady, v1beta1.ConditionTrue) +} + func assertServiceBrokerCondition(t *testing.T, obj runtime.Object, conditionType v1beta1.ServiceBrokerConditionType, status v1beta1.ConditionStatus) { broker, ok := obj.(*v1beta1.ServiceBroker) if !ok { diff --git a/pkg/controller/controller_servicebroker.go b/pkg/controller/controller_servicebroker.go index 183411bd8b7..8979caf286a 100644 --- a/pkg/controller/controller_servicebroker.go +++ b/pkg/controller/controller_servicebroker.go @@ -649,6 +649,8 @@ func updateCommonStatusCondition(pcb *pretty.ContextBuilder, meta metav1.ObjectM now := metav1.NewTime(t) commonStatus.LastCatalogRetrievalTime = &now } + + commonStatus.LastConditionState = getServiceBrokerLastConditionState(*commonStatus) } // updateServiceBrokerCondition updates the ready condition for the given ServiceBroker @@ -762,3 +764,14 @@ func convertServicePlanListToMap(list []v1beta1.ServicePlan) map[string]*v1beta1 return ret } + +func getServiceBrokerLastConditionState(status v1beta1.CommonServiceBrokerStatus) string { + if len(status.Conditions) > 0 { + condition := status.Conditions[len(status.Conditions)-1] + if condition.Status == v1beta1.ConditionTrue { + return string(condition.Type) + } + return condition.Reason + } + return "" +} diff --git a/pkg/controller/controller_servicebroker_test.go b/pkg/controller/controller_servicebroker_test.go index 7e0da97b142..03d77de5b93 100644 --- a/pkg/controller/controller_servicebroker_test.go +++ b/pkg/controller/controller_servicebroker_test.go @@ -57,6 +57,7 @@ func TestReconcileServiceBrokerUpdatesBrokerClient(t *testing.T) { if !found { t.Error("expected predefined OSB client") } + } func getServiceBrokerReactor(broker *v1beta1.ServiceBroker) (string, string, clientgotesting.ReactionFunc) { @@ -402,3 +403,63 @@ func TestReconcileServicePlanFromServiceBrokerCatalog(t *testing.T) { }) } } + +func TestReconcileServiceBrokerExistingServiceClassAndServicePlan(t *testing.T) { + err := utilfeature.DefaultFeatureGate.Set(fmt.Sprintf("%v=true", scfeatures.NamespacedServiceBroker)) + if err != nil { + t.Fatalf("Failed to enable namespaced service broker feature: %v", err) + } + defer utilfeature.DefaultFeatureGate.Set(fmt.Sprintf("%v=false", scfeatures.NamespacedServiceBroker)) + + fakeKubeClient, fakeCatalogClient, fakeServiceBrokerClient, testController, sharedInformers := newTestController(t, getTestNamespacedCatalogConfig()) + + testServiceClass := getTestServiceClass() + testServicePlan := getTestServicePlan() + sharedInformers.ServiceClasses().Informer().GetStore().Add(testServiceClass) + + fakeCatalogClient.AddReactor("list", "serviceclasses", func(action clientgotesting.Action) (bool, runtime.Object, error) { + return true, &v1beta1.ServiceClassList{ + Items: []v1beta1.ServiceClass{ + *testServiceClass, + }, + }, nil + }) + + if err := reconcileServiceBroker(t, testController, getTestServiceBroker()); err != nil { + t.Fatalf("This should not fail: %v", err) + } + + brokerActions := fakeServiceBrokerClient.Actions() + assertNumberOfBrokerActions(t, brokerActions, 1) + assertGetCatalog(t, brokerActions[0]) + + listRestrictions := clientgotesting.ListRestrictions{ + Labels: labels.SelectorFromSet(labels.Set{ + v1beta1.GroupName + "/" + v1beta1.FilterSpecServiceBrokerName: testServiceBrokerName, + }), + Fields: fields.Everything(), + } + + actions := fakeCatalogClient.Actions() + assertNumberOfActions(t, actions, 6) + assertList(t, actions[0], &v1beta1.ServiceClass{}, listRestrictions) + assertList(t, actions[1], &v1beta1.ServicePlan{}, listRestrictions) + assertUpdate(t, actions[2], testServiceClass) + assertCreate(t, actions[3], testServicePlan) + + updatedServiceBroker := assertUpdateStatus(t, actions[5], getTestServiceBroker()) + assertServiceBrokerReadyTrue(t, updatedServiceBroker) + + // verify no kube resources created + kubeActions := fakeKubeClient.Actions() + assertNumberOfActions(t, kubeActions, 0) + + updateObject, ok := updatedServiceBroker.(*v1beta1.ServiceBroker) + if !ok { + t.Fatalf("couldn't convert to *v1beta1.ServiceBroker") + } + + if updateObject.Status.LastConditionState != "Ready" { + t.Fatalf("LastConditionState has unexpected value. Expected: %v, got: %v", "Ready", updateObject.Status.LastConditionState) + } +} diff --git a/pkg/controller/controller_test.go b/pkg/controller/controller_test.go index ba27684eb10..1f30bd955aa 100644 --- a/pkg/controller/controller_test.go +++ b/pkg/controller/controller_test.go @@ -837,6 +837,36 @@ func getTestCatalog() *osb.CatalogResponse { } } +// broker catalog that provides the service class named in of +// getTestNamespacedServiceClass() +func getTestNamespacedCatalog() *osb.CatalogResponse { + return &osb.CatalogResponse{ + Services: []osb.Service{ + { + Name: testServiceClassName, + ID: testServiceClassGUID, + Description: "a test service", + Bindable: true, + Plans: []osb.Plan{ + { + Name: testServicePlanName, + Free: truePtr(), + ID: testServicePlanGUID, + Description: "a test plan", + }, + { + Name: testNonbindableServicePlanName, + Free: truePtr(), + ID: testNonbindableServicePlanGUID, + Description: "a test plan", + Bindable: falsePtr(), + }, + }, + }, + }, + } +} + // instance referencing the result of getTestClusterServiceClass() // and getTestClusterServicePlan() // This version sets: @@ -4045,6 +4075,14 @@ func getTestCatalogConfig() fakeosb.FakeClientConfiguration { } } +func getTestNamespacedCatalogConfig() fakeosb.FakeClientConfiguration { + return fakeosb.FakeClientConfiguration{ + CatalogReaction: &fakeosb.CatalogReaction{ + Response: getTestNamespacedCatalog(), + }, + } +} + func addGetNamespaceReaction(fakeKubeClient *clientgofake.Clientset) { fakeKubeClient.AddReactor("get", "namespaces", func(action clientgotesting.Action) (bool, runtime.Object, error) { return true, &corev1.Namespace{ diff --git a/pkg/openapi/openapi_generated.go b/pkg/openapi/openapi_generated.go index 6fc09d0da12..cc52a5b93a5 100644 --- a/pkg/openapi/openapi_generated.go +++ b/pkg/openapi/openapi_generated.go @@ -784,8 +784,15 @@ func schema_pkg_apis_servicecatalog_v1beta1_ClusterServiceBrokerStatus(ref commo Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, + "lastConditionState": { + SchemaProps: spec.SchemaProps{ + Description: "LastConditionState aggregates state from the Conditions array It is used for printing in a kubectl output via additionalPrinterColumns", + Type: []string{"string"}, + Format: "", + }, + }, }, - Required: []string{"conditions", "reconciledGeneration"}, + Required: []string{"conditions", "reconciledGeneration", "lastConditionState"}, }, }, Dependencies: []string{ @@ -1339,8 +1346,15 @@ func schema_pkg_apis_servicecatalog_v1beta1_CommonServiceBrokerStatus(ref common Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, + "lastConditionState": { + SchemaProps: spec.SchemaProps{ + Description: "LastConditionState aggregates state from the Conditions array It is used for printing in a kubectl output via additionalPrinterColumns", + Type: []string{"string"}, + Format: "", + }, + }, }, - Required: []string{"conditions", "reconciledGeneration"}, + Required: []string{"conditions", "reconciledGeneration", "lastConditionState"}, }, }, Dependencies: []string{ @@ -2192,8 +2206,15 @@ func schema_pkg_apis_servicecatalog_v1beta1_ServiceBindingStatus(ref common.Refe Format: "", }, }, + "lastConditionState": { + SchemaProps: spec.SchemaProps{ + Description: "LastConditionState aggregates state from the Conditions array It is used for printing in a kubectl output via additionalPrinterColumns", + Type: []string{"string"}, + Format: "", + }, + }, }, - Required: []string{"conditions", "asyncOpInProgress", "reconciledGeneration", "orphanMitigationInProgress", "unbindStatus"}, + Required: []string{"conditions", "asyncOpInProgress", "reconciledGeneration", "orphanMitigationInProgress", "unbindStatus", "lastConditionState"}, }, }, Dependencies: []string{ @@ -2484,8 +2505,15 @@ func schema_pkg_apis_servicecatalog_v1beta1_ServiceBrokerStatus(ref common.Refer Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, + "lastConditionState": { + SchemaProps: spec.SchemaProps{ + Description: "LastConditionState aggregates state from the Conditions array It is used for printing in a kubectl output via additionalPrinterColumns", + Type: []string{"string"}, + Format: "", + }, + }, }, - Required: []string{"conditions", "reconciledGeneration"}, + Required: []string{"conditions", "reconciledGeneration", "lastConditionState"}, }, }, Dependencies: []string{ @@ -3194,8 +3222,29 @@ func schema_pkg_apis_servicecatalog_v1beta1_ServiceInstanceStatus(ref common.Ref Ref: ref("k8s.io/apimachinery/pkg/runtime.RawExtension"), }, }, + "lastConditionState": { + SchemaProps: spec.SchemaProps{ + Description: "LastConditionState aggregates state from the Conditions array It is used for printing in a kubectl output via additionalPrinterColumns", + Type: []string{"string"}, + Format: "", + }, + }, + "userSpecifiedPlanName": { + SchemaProps: spec.SchemaProps{ + Description: "UserSpecifiedPlanName aggregates cluster or namespace PlanName It is used for printing in a kubectl output via additionalPrinterColumns", + Type: []string{"string"}, + Format: "", + }, + }, + "userSpecifiedClassName": { + SchemaProps: spec.SchemaProps{ + Description: "UserSpecifiedClassName aggregates cluster or namespace ClassName It is used for printing in a kubectl output via additionalPrinterColumns", + Type: []string{"string"}, + Format: "", + }, + }, }, - Required: []string{"conditions", "asyncOpInProgress", "orphanMitigationInProgress", "reconciledGeneration", "observedGeneration", "provisionStatus", "deprovisionStatus"}, + Required: []string{"conditions", "asyncOpInProgress", "orphanMitigationInProgress", "reconciledGeneration", "observedGeneration", "provisionStatus", "deprovisionStatus", "lastConditionState", "userSpecifiedPlanName", "userSpecifiedClassName"}, }, }, Dependencies: []string{