Skip to content

Commit 4309a0e

Browse files
kibbles-n-bytesstaebler
authored andcommitted
add alpha asynchronous binding operation support (openshift#1512)
* add types changes * add binding polling queue * add async bind conditions * add polling handling to current reconciliation functions * add generated files * fix existing tests * add polling functions * add tests for async binding operations * add validation * add integration test support * add feature gate * rebase * fixup int test * address comments * rebase * address comments
1 parent 617c823 commit 4309a0e

19 files changed

+2147
-75
lines changed

charts/catalog/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ chart and their default values.
5555
| `controllerManager.brokerRelistInterval` | How often the controller should relist the catalogs of ready brokers; duration format (`20m`, `1h`, etc) | `24h` |
5656
| `useAggregator` | whether or not to set up the controller-manager to go through the main Kubernetes API server's API aggregator | `true` |
5757
| `rbacEnable` | If true, create & use RBAC resources | `true` |
58+
| `asyncBindingOperationsEnabled` | Whether or not alpha support for async binding operations is enabled | `false` |
5859

5960
Specify each parameter using the `--set key=value[,key=value]` argument to
6061
`helm install`.

charts/catalog/templates/controller-manager-deployment.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ spec:
7171
- --feature-gates
7272
- OriginatingIdentity=true
7373
{{- end }}
74+
{{- if .Values.asyncBindingOperationsEnabled }}
75+
- --feature-gates
76+
- AsyncBindingOperations=true
77+
{{- end }}
7478
ports:
7579
- containerPort: 8080
7680
volumeMounts:

charts/catalog/values.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,5 @@ controllerManager:
9191
apiserverSkipVerify: true
9292
# Whether the OriginatingIdentity alpha feature should be enabled
9393
originatingIdentityEnabled: false
94+
# Whether the AsyncBindingOperations alpha feature should be enabled
95+
asyncBindingOperationsEnabled: false

pkg/apis/servicecatalog/types.go

+22
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,13 @@ type ClusterServiceClassSpec struct {
257257
// Bindable which overrides the value of this field.
258258
Bindable bool
259259

260+
// Currently, this field is ALPHA: it may change or disappear at any time
261+
// and its data will not be migrated.
262+
//
263+
// BindingRetrievable indicates whether fetching a binding via a GET on
264+
// its endpoint is supported for all plans.
265+
BindingRetrievable bool
266+
260267
// PlanUpdatable indicates whether instances provisioned from this
261268
// ClusterServiceClass may change ClusterServicePlans after being provisioned.
262269
PlanUpdatable bool
@@ -724,6 +731,21 @@ type ServiceBindingSpec struct {
724731
type ServiceBindingStatus struct {
725732
Conditions []ServiceBindingCondition
726733

734+
// Currently, this field is ALPHA: it may change or disappear at any time
735+
// and its data will not be migrated.
736+
//
737+
// AsyncOpInProgress is set to true if there is an ongoing async operation
738+
// against this ServiceBinding in progress.
739+
AsyncOpInProgress bool
740+
741+
// Currently, this field is ALPHA: it may change or disappear at any time
742+
// and its data will not be migrated.
743+
//
744+
// LastOperation is the string that the broker may have returned when
745+
// an async operation started, it should be sent back to the broker
746+
// on poll requests as a query param.
747+
LastOperation *string
748+
727749
// CurrentOperation is the operation the Controller is currently performing
728750
// on the ServiceBinding.
729751
CurrentOperation ServiceBindingOperation

pkg/apis/servicecatalog/v1beta1/types.go

+22
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,13 @@ type ClusterServiceClassSpec struct {
259259
// this field.
260260
Bindable bool `json:"bindable"`
261261

262+
// Currently, this field is ALPHA: it may change or disappear at any time
263+
// and its data will not be migrated.
264+
//
265+
// BindingRetrievable indicates whether fetching a binding via a GET on
266+
// its endpoint is supported for all plans.
267+
BindingRetrievable bool `json:"binding_retrievable"`
268+
262269
// PlanUpdatable indicates whether instances provisioned from this
263270
// ClusterServiceClass may change ClusterServicePlans after being
264271
// provisioned.
@@ -747,6 +754,21 @@ type ServiceBindingSpec struct {
747754
type ServiceBindingStatus struct {
748755
Conditions []ServiceBindingCondition `json:"conditions"`
749756

757+
// Currently, this field is ALPHA: it may change or disappear at any time
758+
// and its data will not be migrated.
759+
//
760+
// AsyncOpInProgress is set to true if there is an ongoing async operation
761+
// against this ServiceBinding in progress.
762+
AsyncOpInProgress bool `json:"asyncOpInProgress"`
763+
764+
// Currently, this field is ALPHA: it may change or disappear at any time
765+
// and its data will not be migrated.
766+
//
767+
// LastOperation is the string that the broker may have returned when
768+
// an async operation started, it should be sent back to the broker
769+
// on poll requests as a query param.
770+
LastOperation *string `json:"lastOperation,omitempty"`
771+
750772
// CurrentOperation is the operation the Controller is currently performing
751773
// on the ServiceBinding.
752774
CurrentOperation ServiceBindingOperation `json:"currentOperation,omitempty"`

pkg/apis/servicecatalog/v1beta1/zz_generated.conversion.go

+6
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ func autoConvert_v1beta1_ClusterServiceClassSpec_To_servicecatalog_ClusterServic
341341
out.ExternalID = in.ExternalID
342342
out.Description = in.Description
343343
out.Bindable = in.Bindable
344+
out.BindingRetrievable = in.BindingRetrievable
344345
out.PlanUpdatable = in.PlanUpdatable
345346
out.ExternalMetadata = (*runtime.RawExtension)(unsafe.Pointer(in.ExternalMetadata))
346347
out.Tags = *(*[]string)(unsafe.Pointer(&in.Tags))
@@ -359,6 +360,7 @@ func autoConvert_servicecatalog_ClusterServiceClassSpec_To_v1beta1_ClusterServic
359360
out.ExternalID = in.ExternalID
360361
out.Description = in.Description
361362
out.Bindable = in.Bindable
363+
out.BindingRetrievable = in.BindingRetrievable
362364
out.PlanUpdatable = in.PlanUpdatable
363365
out.ExternalMetadata = (*runtime.RawExtension)(unsafe.Pointer(in.ExternalMetadata))
364366
out.Tags = *(*[]string)(unsafe.Pointer(&in.Tags))
@@ -761,6 +763,8 @@ func Convert_servicecatalog_ServiceBindingSpec_To_v1beta1_ServiceBindingSpec(in
761763

762764
func autoConvert_v1beta1_ServiceBindingStatus_To_servicecatalog_ServiceBindingStatus(in *ServiceBindingStatus, out *servicecatalog.ServiceBindingStatus, s conversion.Scope) error {
763765
out.Conditions = *(*[]servicecatalog.ServiceBindingCondition)(unsafe.Pointer(&in.Conditions))
766+
out.AsyncOpInProgress = in.AsyncOpInProgress
767+
out.LastOperation = (*string)(unsafe.Pointer(in.LastOperation))
764768
out.CurrentOperation = servicecatalog.ServiceBindingOperation(in.CurrentOperation)
765769
out.ReconciledGeneration = in.ReconciledGeneration
766770
out.OperationStartTime = (*v1.Time)(unsafe.Pointer(in.OperationStartTime))
@@ -777,6 +781,8 @@ func Convert_v1beta1_ServiceBindingStatus_To_servicecatalog_ServiceBindingStatus
777781

778782
func autoConvert_servicecatalog_ServiceBindingStatus_To_v1beta1_ServiceBindingStatus(in *servicecatalog.ServiceBindingStatus, out *ServiceBindingStatus, s conversion.Scope) error {
779783
out.Conditions = *(*[]ServiceBindingCondition)(unsafe.Pointer(&in.Conditions))
784+
out.AsyncOpInProgress = in.AsyncOpInProgress
785+
out.LastOperation = (*string)(unsafe.Pointer(in.LastOperation))
780786
out.CurrentOperation = ServiceBindingOperation(in.CurrentOperation)
781787
out.ReconciledGeneration = in.ReconciledGeneration
782788
out.OperationStartTime = (*v1.Time)(unsafe.Pointer(in.OperationStartTime))

pkg/apis/servicecatalog/v1beta1/zz_generated.deepcopy.go

+9
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,15 @@ func (in *ServiceBindingStatus) DeepCopyInto(out *ServiceBindingStatus) {
899899
(*in)[i].DeepCopyInto(&(*out)[i])
900900
}
901901
}
902+
if in.LastOperation != nil {
903+
in, out := &in.LastOperation, &out.LastOperation
904+
if *in == nil {
905+
*out = nil
906+
} else {
907+
*out = new(string)
908+
**out = **in
909+
}
910+
}
902911
if in.OperationStartTime != nil {
903912
in, out := &in.OperationStartTime, &out.OperationStartTime
904913
if *in == nil {

pkg/apis/servicecatalog/validation/binding.go

+3
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ func validateServiceBindingStatus(status *sc.ServiceBindingStatus, fldPath *fiel
9494
if status.OperationStartTime != nil {
9595
allErrs = append(allErrs, field.Forbidden(fldPath.Child("operationStartTime"), "operationStartTime must not be present when currentOperation is not present"))
9696
}
97+
if status.AsyncOpInProgress {
98+
allErrs = append(allErrs, field.Forbidden(fldPath.Child("asyncOpInProgress"), "asyncOpInProgress cannot be true when there is no currentOperation"))
99+
}
97100
} else {
98101
if status.OperationStartTime == nil && !status.OrphanMitigationInProgress {
99102
allErrs = append(allErrs, field.Required(fldPath.Child("operationStartTime"), "operationStartTime is required when currentOperation is present and no orphan mitigation in progress"))

pkg/apis/servicecatalog/zz_generated.deepcopy.go

+9
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,15 @@ func (in *ServiceBindingStatus) DeepCopyInto(out *ServiceBindingStatus) {
899899
(*in)[i].DeepCopyInto(&(*out)[i])
900900
}
901901
}
902+
if in.LastOperation != nil {
903+
in, out := &in.LastOperation, &out.LastOperation
904+
if *in == nil {
905+
*out = nil
906+
} else {
907+
*out = new(string)
908+
**out = **in
909+
}
910+
}
902911
if in.OperationStartTime != nil {
903912
in, out := &in.OperationStartTime, &out.OperationStartTime
904913
if *in == nil {

pkg/controller/controller.go

+17-8
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"k8s.io/apimachinery/pkg/util/wait"
3232

3333
corev1 "k8s.io/api/core/v1"
34+
utilfeature "k8s.io/apiserver/pkg/util/feature"
3435
"k8s.io/client-go/kubernetes"
3536
"k8s.io/client-go/tools/cache"
3637
"k8s.io/client-go/tools/record"
@@ -40,6 +41,7 @@ import (
4041
servicecatalogclientset "github.com/kubernetes-incubator/service-catalog/pkg/client/clientset_generated/clientset/typed/servicecatalog/v1beta1"
4142
informers "github.com/kubernetes-incubator/service-catalog/pkg/client/informers_generated/externalversions/servicecatalog/v1beta1"
4243
listers "github.com/kubernetes-incubator/service-catalog/pkg/client/listers_generated/servicecatalog/v1beta1"
44+
scfeatures "github.com/kubernetes-incubator/service-catalog/pkg/features"
4345
pretty "github.com/kubernetes-incubator/service-catalog/pkg/pretty"
4446
)
4547

@@ -87,7 +89,8 @@ func NewController(
8789
servicePlanQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "service-plan"),
8890
instanceQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "service-instance"),
8991
bindingQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "service-binding"),
90-
pollingQueue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemExponentialFailureRateLimiter(pollingStartInterval, pollingMaxBackoffDuration), "poller"),
92+
instancePollingQueue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemExponentialFailureRateLimiter(pollingStartInterval, pollingMaxBackoffDuration), "instance-poller"),
93+
bindingPollingQueue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemExponentialFailureRateLimiter(pollingStartInterval, pollingMaxBackoffDuration), "binding-poller"),
9194
}
9295

9396
controller.brokerLister = brokerInformer.Lister()
@@ -156,11 +159,8 @@ type controller struct {
156159
servicePlanQueue workqueue.RateLimitingInterface
157160
instanceQueue workqueue.RateLimitingInterface
158161
bindingQueue workqueue.RateLimitingInterface
159-
// pollingQueue is separate from instanceQueue because we want
160-
// it to have different backoff / timeout characteristics from
161-
// a reconciling of an instance.
162-
// TODO(vaikas): get rid of two queues per instance.
163-
pollingQueue workqueue.RateLimitingInterface
162+
instancePollingQueue workqueue.RateLimitingInterface
163+
bindingPollingQueue workqueue.RateLimitingInterface
164164
}
165165

166166
// Run runs the controller until the given stop channel can be read from.
@@ -177,7 +177,11 @@ func (c *controller) Run(workers int, stopCh <-chan struct{}) {
177177
createWorker(c.servicePlanQueue, "ClusterServicePlan", maxRetries, true, c.reconcileClusterServicePlanKey, stopCh, &waitGroup)
178178
createWorker(c.instanceQueue, "ServiceInstance", maxRetries, true, c.reconcileServiceInstanceKey, stopCh, &waitGroup)
179179
createWorker(c.bindingQueue, "ServiceBinding", maxRetries, true, c.reconcileServiceBindingKey, stopCh, &waitGroup)
180-
createWorker(c.pollingQueue, "Poller", maxRetries, false, c.requeueServiceInstanceForPoll, stopCh, &waitGroup)
180+
createWorker(c.instancePollingQueue, "InstancePoller", maxRetries, false, c.requeueServiceInstanceForPoll, stopCh, &waitGroup)
181+
182+
if utilfeature.DefaultFeatureGate.Enabled(scfeatures.AsyncBindingOperations) {
183+
createWorker(c.bindingPollingQueue, "BindingPoller", maxRetries, false, c.requeueServiceBindingForPoll, stopCh, &waitGroup)
184+
}
181185
}
182186

183187
<-stopCh
@@ -188,7 +192,8 @@ func (c *controller) Run(workers int, stopCh <-chan struct{}) {
188192
c.servicePlanQueue.ShutDown()
189193
c.instanceQueue.ShutDown()
190194
c.bindingQueue.ShutDown()
191-
c.pollingQueue.ShutDown()
195+
c.instancePollingQueue.ShutDown()
196+
c.bindingPollingQueue.ShutDown()
192197

193198
waitGroup.Wait()
194199
}
@@ -502,6 +507,10 @@ func convertCatalog(in *osb.CatalogResponse) ([]*v1beta1.ClusterServiceClass, []
502507
},
503508
}
504509

510+
if utilfeature.DefaultFeatureGate.Enabled(scfeatures.AsyncBindingOperations) {
511+
serviceClasses[i].Spec.BindingRetrievable = svc.BindingRetrievable
512+
}
513+
505514
if svc.Metadata != nil {
506515
metadata, err := json.Marshal(svc.Metadata)
507516
if err != nil {

0 commit comments

Comments
 (0)