Skip to content

Commit

Permalink
Added service binding of type key
Browse files Browse the repository at this point in the history
Also, added key type filter when listing bindings

Co-authored-by: Danail Branekov <[email protected]>
Co-authored-by: Dimitar Draganov <[email protected]>
  • Loading branch information
danail-branekov and ddraganovv committed Jan 14, 2025
1 parent 6f87111 commit 38c24d8
Show file tree
Hide file tree
Showing 27 changed files with 563 additions and 238 deletions.
1 change: 1 addition & 0 deletions api/actions/manifest/applier.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ func (a *Applier) applyServices(ctx context.Context, authInfo authorization.Info
}

_, err = a.serviceBindingRepo.CreateServiceBinding(ctx, authInfo, repositories.CreateServiceBindingMessage{
Type: korifiv1alpha1.CFServiceBindingTypeApp,
Name: manifestService.BindingName,
ServiceInstanceGUID: serviceInstanceRecord.GUID,
AppGUID: appState.App.GUID,
Expand Down
5 changes: 4 additions & 1 deletion api/actions/manifest/applier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
apierrors "code.cloudfoundry.org/korifi/api/errors"
"code.cloudfoundry.org/korifi/api/payloads"
"code.cloudfoundry.org/korifi/api/repositories"
korifiv1alpha1 "code.cloudfoundry.org/korifi/controllers/api/v1alpha1"
"code.cloudfoundry.org/korifi/tools"

. "github.com/onsi/ginkgo/v2"
Expand Down Expand Up @@ -469,7 +470,7 @@ var _ = Describe("Applier", func() {
}
})

It("creates a service binding", func() {
It("creates a service binding of type app", func() {
Expect(applierErr).NotTo(HaveOccurred())

Expect(serviceInstanceRepo.ListServiceInstancesCallCount()).To(Equal(1))
Expand All @@ -481,6 +482,7 @@ var _ = Describe("Applier", func() {
Expect(serviceBindingRepo.CreateServiceBindingCallCount()).To(Equal(1))
_, _, createMsg := serviceBindingRepo.CreateServiceBindingArgsForCall(0)
Expect(createMsg).To(Equal(repositories.CreateServiceBindingMessage{
Type: korifiv1alpha1.CFServiceBindingTypeApp,
ServiceInstanceGUID: "service-guid",
AppGUID: "app-guid",
SpaceGUID: "space-guid",
Expand All @@ -501,6 +503,7 @@ var _ = Describe("Applier", func() {
Expect(serviceBindingRepo.CreateServiceBindingCallCount()).To(Equal(1))
_, _, createMsg := serviceBindingRepo.CreateServiceBindingArgsForCall(0)
Expect(createMsg).To(Equal(repositories.CreateServiceBindingMessage{
Type: korifiv1alpha1.CFServiceBindingTypeApp,
Name: tools.PtrTo("service-binding"),
ServiceInstanceGUID: "service-guid",
AppGUID: "app-guid",
Expand Down
62 changes: 45 additions & 17 deletions api/handlers/service_binding.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,40 +57,68 @@ func (h *ServiceBinding) create(r *http.Request) (*routing.Response, error) {
return nil, apierrors.LogAndReturn(logger, err, "failed to decode payload")
}

app, err := h.appRepo.GetApp(r.Context(), authInfo, payload.Relationships.App.Data.GUID)
if err != nil {
return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "failed to get "+repositories.AppResourceType)
}

serviceInstance, err := h.serviceInstanceRepo.GetServiceInstance(r.Context(), authInfo, payload.Relationships.ServiceInstance.Data.GUID)
if err != nil {
return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "failed to get "+repositories.ServiceInstanceResourceType)
}

if app.SpaceGUID != serviceInstance.SpaceGUID {
ctx := logr.NewContext(r.Context(), logger.WithValues("service-instance", serviceInstance.GUID))

if payload.Type == korifiv1alpha1.CFServiceBindingTypeApp {
var app repositories.AppRecord
if app, err = h.appRepo.GetApp(ctx, authInfo, payload.Relationships.App.Data.GUID); err != nil {
return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "failed to get "+repositories.AppResourceType)
}

if app.SpaceGUID != serviceInstance.SpaceGUID {
return nil, apierrors.LogAndReturn(
logger,
apierrors.NewUnprocessableEntityError(nil, "The service instance and the app are in different spaces"),
"App and ServiceInstance in different spaces", "App GUID", app.GUID,
"ServiceInstance GUID", serviceInstance.GUID,
)
}
}

if serviceInstance.Type == korifiv1alpha1.UserProvidedType {
return h.createUserProvided(ctx, &payload, serviceInstance)
}

return h.createManaged(ctx, &payload, serviceInstance)
}

func (h *ServiceBinding) createUserProvided(ctx context.Context, payload *payloads.ServiceBindingCreate, serviceInstance repositories.ServiceInstanceRecord) (*routing.Response, error) {
authInfo, _ := authorization.InfoFromContext(ctx)
logger := logr.FromContextOrDiscard(ctx).WithName("handlers.service-binding.create-user-provided")

if payload.Type == korifiv1alpha1.CFServiceBindingTypeKey {
return nil, apierrors.LogAndReturn(
logger,
apierrors.NewUnprocessableEntityError(nil, "The service instance and the app are in different spaces"),
"App and ServiceInstance in different spaces", "App GUID", app.GUID,
"ServiceInstance GUID", serviceInstance.GUID,
apierrors.NewUnprocessableEntityError(nil, "Service credential bindings of type 'key' are not supported for user-provided service instances."),
"",
)
}

ctx := logr.NewContext(r.Context(), logger.WithValues("app", app.GUID, "service-instance", serviceInstance.GUID))

serviceBinding, err := h.serviceBindingRepo.CreateServiceBinding(ctx, authInfo, payload.ToMessage(app.SpaceGUID))
serviceBinding, err := h.serviceBindingRepo.CreateServiceBinding(ctx, authInfo, payload.ToMessage(serviceInstance.SpaceGUID))
if err != nil {
return nil, apierrors.LogAndReturn(logr.FromContextOrDiscard(ctx), err, "failed to create ServiceBinding")
}

if serviceInstance.Type == korifiv1alpha1.ManagedType {
return routing.NewResponse(http.StatusAccepted).
WithHeader("Location", presenter.JobURLForRedirects(serviceBinding.GUID, presenter.ManagedServiceBindingCreateOperation, h.serverURL)), nil
}

return routing.NewResponse(http.StatusCreated).WithBody(presenter.ForServiceBinding(serviceBinding, h.serverURL)), nil
}

func (h *ServiceBinding) createManaged(ctx context.Context, payload *payloads.ServiceBindingCreate, serviceInstance repositories.ServiceInstanceRecord) (*routing.Response, error) {
authInfo, _ := authorization.InfoFromContext(ctx)
logger := logr.FromContextOrDiscard(ctx).WithName("handlers.service-binding.create-managed")

serviceBinding, err := h.serviceBindingRepo.CreateServiceBinding(ctx, authInfo, payload.ToMessage(serviceInstance.SpaceGUID))
if err != nil {
return nil, apierrors.LogAndReturn(logger, err, "failed to create ServiceBinding")
}
return routing.NewResponse(http.StatusAccepted).
WithHeader("Location", presenter.JobURLForRedirects(serviceBinding.GUID, presenter.ManagedServiceBindingCreateOperation, h.serverURL)), nil
}

func (h *ServiceBinding) delete(r *http.Request) (*routing.Response, error) {
authInfo, _ := authorization.InfoFromContext(r.Context())
logger := logr.FromContextOrDiscard(r.Context()).WithName("handlers.service-binding.delete")
Expand Down
Loading

0 comments on commit 38c24d8

Please sign in to comment.