Skip to content

Commit

Permalink
Filter service instances and bindings by plan guid
Browse files Browse the repository at this point in the history
Co-authored-by: Danail Branekov <[email protected]>
  • Loading branch information
zabanov-lab and danail-branekov committed Nov 1, 2024
1 parent 2630f19 commit 3e88807
Show file tree
Hide file tree
Showing 14 changed files with 144 additions and 34 deletions.
2 changes: 2 additions & 0 deletions api/handlers/service_binding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ var _ = Describe("ServiceBinding", func() {
AppGUIDs: "a1,a2",
ServiceInstanceGUIDs: "s1,s2",
LabelSelector: "label=value",
PlanGUIDs: "p1,p2",
}
requestValidator.DecodeAndValidateURLValuesStub = decodeAndValidateURLValuesStub(&payload)
})
Expand All @@ -320,6 +321,7 @@ var _ = Describe("ServiceBinding", func() {
Expect(message.AppGUIDs).To(ConsistOf([]string{"a1", "a2"}))
Expect(message.ServiceInstanceGUIDs).To(ConsistOf([]string{"s1", "s2"}))
Expect(message.LabelSelector).To(Equal("label=value"))
Expect(message.PlanGUIDs).To(ConsistOf("p1", "p2"))

Expect(rr).To(HaveHTTPStatus(http.StatusOK))
Expect(rr).To(HaveHTTPHeaderWithValue("Content-Type", "application/json"))
Expand Down
2 changes: 2 additions & 0 deletions api/handlers/service_instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ var _ = Describe("ServiceInstance", func() {
Names: "sc1,sc2",
SpaceGUIDs: "space1,space2",
GUIDs: "g1,g2",
PlanGUIDs: "p1,p2",
LabelSelector: "label=value",
})
})
Expand All @@ -279,6 +280,7 @@ var _ = Describe("ServiceInstance", func() {
Expect(message.SpaceGUIDs).To(ConsistOf("space1", "space2"))
Expect(message.GUIDs).To(ConsistOf("g1", "g2"))
Expect(message.LabelSelector).To(Equal("label=value"))
Expect(message.PlanGUIDs).To(ConsistOf("p1", "p2"))
})

It("correctly sets query parameters in response pagination links", func() {
Expand Down
5 changes: 4 additions & 1 deletion api/payloads/service_binding.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,25 +48,28 @@ type ServiceBindingList struct {
ServiceInstanceGUIDs string
Include string
LabelSelector string
PlanGUIDs string
}

func (l *ServiceBindingList) ToMessage() repositories.ListServiceBindingsMessage {
return repositories.ListServiceBindingsMessage{
ServiceInstanceGUIDs: parse.ArrayParam(l.ServiceInstanceGUIDs),
AppGUIDs: parse.ArrayParam(l.AppGUIDs),
LabelSelector: l.LabelSelector,
PlanGUIDs: parse.ArrayParam(l.PlanGUIDs),
}
}

func (l *ServiceBindingList) SupportedKeys() []string {
return []string{"app_guids", "service_instance_guids", "include", "type", "per_page", "page", "label_selector"}
return []string{"app_guids", "service_instance_guids", "include", "type", "per_page", "page", "label_selector", "service_plan_guids"}
}

func (l *ServiceBindingList) DecodeFromURLValues(values url.Values) error {
l.AppGUIDs = values.Get("app_guids")
l.ServiceInstanceGUIDs = values.Get("service_instance_guids")
l.Include = values.Get("include")
l.LabelSelector = values.Get("label_selector")
l.PlanGUIDs = values.Get("service_plan_guids")
return nil
}

Expand Down
3 changes: 3 additions & 0 deletions api/payloads/service_binding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ var _ = Describe("ServiceBindingList", func() {
Entry("service_instance_guids", "service_instance_guids=si_guid", payloads.ServiceBindingList{ServiceInstanceGUIDs: "si_guid"}),
Entry("include", "include=include", payloads.ServiceBindingList{Include: "include"}),
Entry("label_selector=foo", "label_selector=foo", payloads.ServiceBindingList{LabelSelector: "foo"}),
Entry("service_plan_guids=plan-guid", "service_plan_guids=plan-guid", payloads.ServiceBindingList{PlanGUIDs: "plan-guid"}),
)

Describe("ToMessage", func() {
Expand All @@ -36,6 +37,7 @@ var _ = Describe("ServiceBindingList", func() {
ServiceInstanceGUIDs: "s1,s2",
Include: "include",
LabelSelector: "foo=bar",
PlanGUIDs: "p1,p2",
}
})

Expand All @@ -48,6 +50,7 @@ var _ = Describe("ServiceBindingList", func() {
AppGUIDs: []string{"app1", "app2"},
ServiceInstanceGUIDs: []string{"s1", "s2"},
LabelSelector: "foo=bar",
PlanGUIDs: []string{"p1", "p2"},
}))
})
})
Expand Down
4 changes: 4 additions & 0 deletions api/payloads/service_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ type ServiceInstanceList struct {
Names string
GUIDs string
SpaceGUIDs string
PlanGUIDs string
OrderBy string
LabelSelector string
IncludeResourceRules []params.IncludeResourceRule
Expand Down Expand Up @@ -212,6 +213,7 @@ func (l *ServiceInstanceList) ToMessage() repositories.ListServiceInstanceMessag
GUIDs: parse.ArrayParam(l.GUIDs),
OrderBy: l.OrderBy,
LabelSelector: l.LabelSelector,
PlanGUIDs: parse.ArrayParam(l.PlanGUIDs),
}
}

Expand All @@ -225,6 +227,7 @@ func (l *ServiceInstanceList) SupportedKeys() []string {
"fields[service_plan.service_offering]",
"fields[service_plan.service_offering.service_broker]",
"fields[service_plan]",
"service_plan_guids",
}
}

Expand All @@ -242,5 +245,6 @@ func (l *ServiceInstanceList) DecodeFromURLValues(values url.Values) error {
l.OrderBy = values.Get("order_by")
l.LabelSelector = values.Get("label_selector")
l.IncludeResourceRules = append(l.IncludeResourceRules, params.ParseFields(values)...)
l.PlanGUIDs = values.Get("service_plan_guids")
return nil
}
3 changes: 3 additions & 0 deletions api/payloads/service_instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ var _ = Describe("ServiceInstanceList", func() {
Fields: []string{"guid", "name", "relationships.service_offering"},
}}}),
Entry("label_selector=foo", "label_selector=foo", payloads.ServiceInstanceList{LabelSelector: "foo"}),
Entry("service_plan_guids=plan-guid", "service_plan_guids=plan-guid", payloads.ServiceInstanceList{PlanGUIDs: "plan-guid"}),
)

DescribeTable("invalid query",
Expand Down Expand Up @@ -77,6 +78,7 @@ var _ = Describe("ServiceInstanceList", func() {
SpaceGUIDs: "sg1,sg2",
OrderBy: "order",
LabelSelector: "foo=bar",
PlanGUIDs: "p1,p2",
}
})

Expand All @@ -91,6 +93,7 @@ var _ = Describe("ServiceInstanceList", func() {
GUIDs: []string{"g1", "g2"},
OrderBy: "order",
LabelSelector: "foo=bar",
PlanGUIDs: []string{"p1", "p2"},
}))
})
})
Expand Down
24 changes: 0 additions & 24 deletions api/repositories/repositories_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -397,30 +397,6 @@ func createServiceInstanceCR(ctx context.Context, k8sClient client.Client, servi
return serviceInstance
}

func createServiceBindingCR(ctx context.Context, k8sClient client.Client, serviceBindingGUID, spaceGUID string, name *string, serviceInstanceName, appName string) *korifiv1alpha1.CFServiceBinding {
toReturn := &korifiv1alpha1.CFServiceBinding{
ObjectMeta: metav1.ObjectMeta{
Name: serviceBindingGUID,
Namespace: spaceGUID,
},
Spec: korifiv1alpha1.CFServiceBindingSpec{
DisplayName: name,
Service: corev1.ObjectReference{
Kind: "ServiceInstance",
Name: serviceInstanceName,
APIVersion: "korifi.cloudfoundry.org/v1alpha1",
},
AppRef: corev1.LocalObjectReference{
Name: appName,
},
},
}
Expect(
k8sClient.Create(ctx, toReturn),
).To(Succeed())
return toReturn
}

func createApp(space string) *korifiv1alpha1.CFApp {
return createAppWithGUID(space, uuid.NewString())
}
Expand Down
4 changes: 3 additions & 1 deletion api/repositories/service_binding_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,13 @@ type ListServiceBindingsMessage struct {
AppGUIDs []string
ServiceInstanceGUIDs []string
LabelSelector string
PlanGUIDs []string
}

func (m *ListServiceBindingsMessage) matches(serviceBinding korifiv1alpha1.CFServiceBinding) bool {
return tools.EmptyOrContains(m.ServiceInstanceGUIDs, serviceBinding.Spec.Service.Name) &&
tools.EmptyOrContains(m.AppGUIDs, serviceBinding.Spec.AppRef.Name)
tools.EmptyOrContains(m.AppGUIDs, serviceBinding.Spec.AppRef.Name) &&
tools.EmptyOrContains(m.PlanGUIDs, serviceBinding.Labels[korifiv1alpha1.PlanGUIDLabelKey])
}

func (m CreateServiceBindingMessage) toCFServiceBinding() *korifiv1alpha1.CFServiceBinding {
Expand Down
79 changes: 75 additions & 4 deletions api/repositories/service_binding_repository_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -614,19 +614,75 @@ var _ = Describe("ServiceBindingRepo", func() {
cfApp1 = createAppCR(testCtx, k8sClient, "app-1-name", prefixedGUID("app-1"), space.Name, "STOPPED")
serviceInstance1GUID = prefixedGUID("instance-1")
cfServiceInstance1 := createServiceInstanceCR(testCtx, k8sClient, serviceInstance1GUID, space.Name, "service-instance-1-name", "secret-1-name")
serviceBinding1Name := "service-binding-1-name"
serviceBinding1 = createServiceBindingCR(testCtx, k8sClient, prefixedGUID("binding-1"), space.Name, &serviceBinding1Name, cfServiceInstance1.Name, cfApp1.Name)
serviceBinding1 = &korifiv1alpha1.CFServiceBinding{
ObjectMeta: metav1.ObjectMeta{
Name: prefixedGUID("binding-1"),
Namespace: space.Name,
Labels: map[string]string{
korifiv1alpha1.PlanGUIDLabelKey: "plan-1",
},
},
Spec: korifiv1alpha1.CFServiceBindingSpec{
Service: corev1.ObjectReference{
Kind: "ServiceInstance",
Name: cfServiceInstance1.Name,
APIVersion: "korifi.cloudfoundry.org/v1alpha1",
},
AppRef: corev1.LocalObjectReference{
Name: cfApp1.Name,
},
},
}
Expect(k8sClient.Create(ctx, serviceBinding1)).To(Succeed())

space2 = createSpaceWithCleanup(testCtx, org.Name, prefixedGUID("space-2"))
cfApp2 = createAppCR(testCtx, k8sClient, "app-2-name", prefixedGUID("app-2"), space2.Name, "STOPPED")
serviceInstance2GUID = prefixedGUID("instance-2")
cfServiceInstance2 := createServiceInstanceCR(testCtx, k8sClient, serviceInstance2GUID, space2.Name, "service-instance-2-name", "secret-2-name")
serviceBinding2 = createServiceBindingCR(testCtx, k8sClient, prefixedGUID("binding-2"), space2.Name, nil, cfServiceInstance2.Name, cfApp2.Name)
serviceBinding2 = &korifiv1alpha1.CFServiceBinding{
ObjectMeta: metav1.ObjectMeta{
Name: prefixedGUID("binding-2"),
Namespace: space2.Name,
Labels: map[string]string{
korifiv1alpha1.PlanGUIDLabelKey: "plan-2",
},
},
Spec: korifiv1alpha1.CFServiceBindingSpec{
Service: corev1.ObjectReference{
Kind: "ServiceInstance",
Name: cfServiceInstance2.Name,
APIVersion: "korifi.cloudfoundry.org/v1alpha1",
},
AppRef: corev1.LocalObjectReference{
Name: cfApp2.Name,
},
},
}
Expect(k8sClient.Create(ctx, serviceBinding2)).To(Succeed())

cfApp3 = createAppCR(testCtx, k8sClient, "app-3-name", prefixedGUID("app-3"), space2.Name, "STOPPED")
serviceInstance3GUID = prefixedGUID("instance-3")
cfServiceInstance3 := createServiceInstanceCR(testCtx, k8sClient, serviceInstance3GUID, space2.Name, "service-instance-3-name", "secret-3-name")
serviceBinding3 = createServiceBindingCR(testCtx, k8sClient, prefixedGUID("binding-3"), space2.Name, nil, cfServiceInstance3.Name, cfApp3.Name)
serviceBinding3 = &korifiv1alpha1.CFServiceBinding{
ObjectMeta: metav1.ObjectMeta{
Name: prefixedGUID("binding-3"),
Namespace: space2.Name,
Labels: map[string]string{
korifiv1alpha1.PlanGUIDLabelKey: "plan-3",
},
},
Spec: korifiv1alpha1.CFServiceBindingSpec{
Service: corev1.ObjectReference{
Kind: "ServiceInstance",
Name: cfServiceInstance3.Name,
APIVersion: "korifi.cloudfoundry.org/v1alpha1",
},
AppRef: corev1.LocalObjectReference{
Name: cfApp3.Name,
},
},
}
Expect(k8sClient.Create(ctx, serviceBinding3)).To(Succeed())

requestMessage = repositories.ListServiceBindingsMessage{}
})
Expand Down Expand Up @@ -780,6 +836,21 @@ var _ = Describe("ServiceBindingRepo", func() {
))
})
})

When("filtered by plan guid", func() {
BeforeEach(func() {
requestMessage = repositories.ListServiceBindingsMessage{
PlanGUIDs: []string{"plan-1", "plan-3"},
}
})

It("returns only the ServiceBindings that match the provided plan guids", func() {
Expect(responseServiceBindings).To(ConsistOf(
MatchFields(IgnoreExtras, Fields{"GUID": Equal(serviceBinding1.Name)}),
MatchFields(IgnoreExtras, Fields{"GUID": Equal(serviceBinding3.Name)}),
))
})
})
})

When("the user does not have access to any namespaces", func() {
Expand Down
4 changes: 3 additions & 1 deletion api/repositories/service_instance_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,13 @@ type ListServiceInstanceMessage struct {
GUIDs []string
LabelSelector string
OrderBy string
PlanGUIDs []string
}

func (m *ListServiceInstanceMessage) matches(serviceInstance korifiv1alpha1.CFServiceInstance) bool {
return tools.EmptyOrContains(m.Names, serviceInstance.Spec.DisplayName) &&
tools.EmptyOrContains(m.GUIDs, serviceInstance.Name)
tools.EmptyOrContains(m.GUIDs, serviceInstance.Name) &&
tools.EmptyOrContains(m.PlanGUIDs, serviceInstance.Spec.PlanGUID)
}

func (m *ListServiceInstanceMessage) matchesNamespace(ns string) bool {
Expand Down
19 changes: 19 additions & 0 deletions api/repositories/service_instance_repository_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,7 @@ var _ = Describe("ServiceInstanceRepository", func() {
Spec: korifiv1alpha1.CFServiceInstanceSpec{
DisplayName: "service-instance-1",
Type: korifiv1alpha1.UserProvidedType,
PlanGUID: "plan-1",
},
}
Expect(k8sClient.Create(ctx, cfServiceInstance1)).To(Succeed())
Expand All @@ -664,6 +665,7 @@ var _ = Describe("ServiceInstanceRepository", func() {
Spec: korifiv1alpha1.CFServiceInstanceSpec{
DisplayName: "service-instance-2",
Type: korifiv1alpha1.UserProvidedType,
PlanGUID: "plan-2",
},
}
Expect(k8sClient.Create(ctx, cfServiceInstance2)).To(Succeed())
Expand All @@ -676,6 +678,7 @@ var _ = Describe("ServiceInstanceRepository", func() {
Spec: korifiv1alpha1.CFServiceInstanceSpec{
DisplayName: "service-instance-3",
Type: korifiv1alpha1.UserProvidedType,
PlanGUID: "plan-3",
},
}
Expect(k8sClient.Create(ctx, cfServiceInstance3)).To(Succeed())
Expand Down Expand Up @@ -846,6 +849,22 @@ var _ = Describe("ServiceInstanceRepository", func() {
})
})
})

When("filtering by plan guids", func() {
BeforeEach(func() {
filters = repositories.ListServiceInstanceMessage{
PlanGUIDs: []string{"plan-1", "plan-3"},
}
})

It("returns only records for the ServiceInstances within the matching plans", func() {
Expect(listErr).NotTo(HaveOccurred())
Expect(serviceInstanceList).To(ConsistOf(
MatchFields(IgnoreExtras, Fields{"GUID": Equal(cfServiceInstance1.Name)}),
MatchFields(IgnoreExtras, Fields{"GUID": Equal(cfServiceInstance3.Name)}),
))
})
})
})
})

Expand Down
1 change: 1 addition & 0 deletions controllers/api/v1alpha1/cfservicebinding_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const (
BindingRequestedCondition = "BindingRequested"

ServiceInstanceTypeAnnotationKey = "korifi.cloudfoundry.org/service-instance-type"
PlanGUIDLabelKey = "korifi.cloudfoundry.org/plan-guid"
)

// CFServiceBindingSpec defines the desired state of CFServiceBinding
Expand Down
10 changes: 7 additions & 3 deletions controllers/controllers/services/bindings/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ func (r *Reconciler) ReconcileResource(ctx context.Context, cfServiceBinding *ko
return ctrl.Result{}, err
}

res, err := r.reconcileCredentialsSecrets(ctx, cfServiceInstance.Spec.Type, cfServiceBinding)
res, err := r.reconcileByType(ctx, cfServiceInstance, cfServiceBinding)
if needsRequeue(res, err) {
log.Error(err, "failed to reconcile binding credentials")
return res, err
Expand All @@ -191,11 +191,15 @@ func (r *Reconciler) ReconcileResource(ctx context.Context, cfServiceBinding *ko
return ctrl.Result{}, nil
}

func (r *Reconciler) reconcileCredentialsSecrets(ctx context.Context, instanceType korifiv1alpha1.InstanceType, cfServiceBinding *korifiv1alpha1.CFServiceBinding) (ctrl.Result, error) {
if instanceType == korifiv1alpha1.UserProvidedType {
func (r *Reconciler) reconcileByType(ctx context.Context, cfServiceInstance *korifiv1alpha1.CFServiceInstance, cfServiceBinding *korifiv1alpha1.CFServiceBinding) (ctrl.Result, error) {
if cfServiceInstance.Spec.Type == korifiv1alpha1.UserProvidedType {
return r.upsiCredentialsReconciler.ReconcileResource(ctx, cfServiceBinding)
}

if cfServiceBinding.Labels == nil {
cfServiceBinding.Labels = map[string]string{}
}
cfServiceBinding.Labels[korifiv1alpha1.PlanGUIDLabelKey] = cfServiceInstance.Spec.PlanGUID
return r.managedCredentialsReconciler.ReconcileResource(ctx, cfServiceBinding)
}

Expand Down
Loading

0 comments on commit 3e88807

Please sign in to comment.