Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Api State Removal - backend #844

Merged
4 changes: 2 additions & 2 deletions docs/contributor/09-10-ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Follow the steps below to run BTP Manager with UI:
```
3. Set the **IMG** environment variable to the image of BTP Manager with UI.
```shell
export IMG=europe-docker.pkg.dev/kyma-project/dev/btp-manager:PR-849
export IMG=europe-docker.pkg.dev/kyma-project/dev/btp-manager:PR-844
```
4. Run `deploy` makefile rule to deploy BTP Manager with UI.
```shell
Expand All @@ -42,7 +42,7 @@ Follow the steps below to run BTP Manager with UI:
```
If you encounter the following error during Pod creation due to Warden's admission webhook:
```
Error creating: admission webhook "validation.webhook.warden.kyma-project.io" denied the request: Pod images europe-docker.pkg.dev/kyma-project/dev/btp-manager:PR-849 validation failed
Error creating: admission webhook "validation.webhook.warden.kyma-project.io" denied the request: Pod images europe-docker.pkg.dev/kyma-project/dev/btp-manager:PR-844 validation failed
```
you must scale the BTP Manager deployment to 0 replicas, delete the webhook, and then scale the deployment back to 1 replica.
```shell
Expand Down
166 changes: 127 additions & 39 deletions internal/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,28 @@ import (
"github.com/kyma-project/btp-manager/internal/api/requests"
"github.com/kyma-project/btp-manager/internal/api/responses"
clusterobject "github.com/kyma-project/btp-manager/internal/cluster-object"
servicemanager "github.com/kyma-project/btp-manager/internal/service-manager"
"github.com/kyma-project/btp-manager/internal/service-manager/types"
corev1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type SMClient interface {
SetForGivenSecret(ctx context.Context, name, namespace string) error
ServiceInstances() (*types.ServiceInstances, error)
CreateServiceInstance(*types.ServiceInstance) (*types.ServiceInstance, error)
ServiceOfferingDetails(id string) (*types.ServiceOfferingDetails, error)
ServiceOfferings() (*types.ServiceOfferings, error)
ServiceInstanceWithPlanName(id string) (*types.ServiceInstance, error)
UpdateServiceInstance(*types.ServiceInstanceUpdateRequest) (*types.ServiceInstance, error)
DeleteServiceInstance(id string) error
ServiceBindingsFor(serviceInstanceID string) (*types.ServiceBindings, error)
CreateServiceBinding(*types.ServiceBinding) (*types.ServiceBinding, error)
ServiceBinding(id string) (*types.ServiceBinding, error)
DeleteServiceBinding(id string) error
ServiceInstance(id string) (*types.ServiceInstance, error)
}

type Config struct {
Port string `envconfig:"default=8080"`
ReadTimeout time.Duration `envconfig:"default=30s"`
Expand All @@ -33,13 +48,13 @@ type Config struct {

type API struct {
server *http.Server
smClient *servicemanager.Client
smClient SMClient
secretManager clusterobject.Manager[*corev1.SecretList, *corev1.Secret]
frontendFS http.FileSystem
logger *slog.Logger
}

func NewAPI(cfg Config, serviceManagerClient *servicemanager.Client, secretManager clusterobject.Manager[*corev1.SecretList, *corev1.Secret], fs http.FileSystem) *API {
func NewAPI(cfg Config, serviceManagerClient SMClient, secretManager clusterobject.Manager[*corev1.SecretList, *corev1.Secret], fs http.FileSystem) *API {
srv := &http.Server{
Addr: fmt.Sprintf(":%s", cfg.Port),
ReadTimeout: cfg.ReadTimeout,
Expand All @@ -65,18 +80,15 @@ func (a *API) Start() {

func (a *API) AttachRoutes(router *http.ServeMux) {
router.HandleFunc("GET /api/secrets", a.ListSecrets)
router.HandleFunc("GET /api/service-offerings/{namespace}/{name}", a.ListServiceOfferings)
router.HandleFunc("GET /api/service-offerings/{id}", a.GetServiceOffering)
router.HandleFunc("GET /api/service-instances", a.ListServiceInstances)
router.HandleFunc("GET /api/service-instances/{id}", a.GetServiceInstance)
router.HandleFunc("GET /api/service-offerings", a.HandleGetServiceOffering)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing plural.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted to the ID's in the path so it's gone

router.HandleFunc("GET /api/service-instances", a.HandleGetServiceInstances)
router.HandleFunc("POST /api/service-instances", a.CreateServiceInstance)
router.HandleFunc("PATCH /api/service-instances/{id}", a.UpdateServiceInstance)
router.HandleFunc("DELETE /api/service-instances/{id}", a.DeleteServiceInstance)
router.HandleFunc("GET /api/service-bindings", a.ListServiceBindings)
router.HandleFunc("GET /api/service-bindings/{id}", a.GetServiceBinding)
router.HandleFunc("PATCH /api/service-instances", a.UpdateServiceInstance)
router.HandleFunc("DELETE /api/service-instances", a.DeleteServiceInstance)
router.HandleFunc("GET /api/service-bindings", a.HandleGetServiceBinding)
router.HandleFunc("POST /api/service-bindings", a.CreateServiceBinding)
router.HandleFunc("DELETE /api/service-bindings/{id}", a.DeleteServiceBinding)
Copy link
Member

@ralikio ralikio Aug 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep ids in the path.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted.

router.HandleFunc("PUT /api/service-bindings/{id}", a.RestoreSecret)
router.HandleFunc("DELETE /api/service-bindings", a.DeleteServiceBinding)
router.HandleFunc("PUT /api/service-bindings", a.RestoreSecret)

router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
Expand All @@ -99,6 +111,13 @@ func (a *API) Address() string {

func (a *API) CreateServiceInstance(writer http.ResponseWriter, request *http.Request) {
a.setupCors(writer, request)
namespace := request.URL.Query().Get("sm_secret_namespace")
name := request.URL.Query().Get("sm_secret_name")
err := a.smClient.SetForGivenSecret(context.Background(), name, namespace)
if err != nil {
a.handleError(writer, err)
return
}
csiRequest, err := a.decodeCreateServiceInstanceRequest(request)
if err != nil {
a.handleError(writer, err)
Expand All @@ -119,9 +138,7 @@ func (a *API) CreateServiceInstance(writer http.ResponseWriter, request *http.Re
a.sendResponse(writer, response, http.StatusCreated)
}

func (a *API) GetServiceOffering(writer http.ResponseWriter, request *http.Request) {
a.setupCors(writer, request)
id := request.PathValue("id")
func (a *API) getServiceOffering(writer http.ResponseWriter, id string) {
details, err := a.smClient.ServiceOfferingDetails(id)
if err != nil {
a.handleError(writer, err)
Expand All @@ -135,26 +152,35 @@ func (a *API) GetServiceOffering(writer http.ResponseWriter, request *http.Reque
a.sendResponse(writer, response)
}

func (a *API) ListServiceOfferings(writer http.ResponseWriter, request *http.Request) {
a.setupCors(writer, request)
namespace := request.PathValue("namespace")
name := request.PathValue("name")
err := a.smClient.SetForGivenSecret(context.Background(), name, namespace)
func (a *API) listServiceOfferings(writer http.ResponseWriter) {
offerings, err := a.smClient.ServiceOfferings()
if err != nil {
a.handleError(writer, err)
return
}
offerings, err := a.smClient.ServiceOfferings()
response, err := json.Marshal(responses.ToServiceOfferingsVM(offerings))
if err != nil {
a.handleError(writer, err)
return
}
response, err := json.Marshal(responses.ToServiceOfferingsVM(offerings))
a.sendResponse(writer, response)
}

func (a *API) HandleGetServiceOffering(writer http.ResponseWriter, request *http.Request) {
a.setupCors(writer, request)
namespace := request.URL.Query().Get("sm_secret_namespace")
name := request.URL.Query().Get("sm_secret_name")
err := a.smClient.SetForGivenSecret(context.Background(), name, namespace)
if err != nil {
a.handleError(writer, err)
return
}
a.sendResponse(writer, response)
id := request.URL.Query().Get("id")
if id == "" {
a.listServiceOfferings(writer)
return
}
a.getServiceOffering(writer, id)
}

func (a *API) ListSecrets(writer http.ResponseWriter, request *http.Request) {
Expand All @@ -172,9 +198,7 @@ func (a *API) ListSecrets(writer http.ResponseWriter, request *http.Request) {
a.sendResponse(writer, response)
}

func (a *API) GetServiceInstance(writer http.ResponseWriter, request *http.Request) {
a.setupCors(writer, request)
id := request.PathValue("id")
func (a *API) GetServiceInstance(writer http.ResponseWriter, request *http.Request, id string) {
si, err := a.smClient.ServiceInstanceWithPlanName(id)
if err != nil {
a.handleError(writer, err)
Expand All @@ -189,7 +213,6 @@ func (a *API) GetServiceInstance(writer http.ResponseWriter, request *http.Reque
}

func (a *API) ListServiceInstances(writer http.ResponseWriter, request *http.Request) {
a.setupCors(writer, request)
sis, err := a.smClient.ServiceInstances()
if err != nil {
a.handleError(writer, err)
Expand All @@ -203,10 +226,24 @@ func (a *API) ListServiceInstances(writer http.ResponseWriter, request *http.Req
a.sendResponse(writer, response)
}

func (a *API) ListServiceBindings(writer http.ResponseWriter, request *http.Request) {
func (a *API) HandleGetServiceInstances(writer http.ResponseWriter, request *http.Request) {
a.setupCors(writer, request)
queryParams := request.URL.Query()
serviceInstanceId := queryParams.Get("service_instance_id")
namespace := request.URL.Query().Get("sm_secret_namespace")
name := request.URL.Query().Get("sm_secret_name")
err := a.smClient.SetForGivenSecret(context.Background(), name, namespace)
if err != nil {
a.handleError(writer, err)
return
}
id := request.URL.Query().Get("id")
if id == "" {
a.ListServiceInstances(writer, request)
return
}
a.GetServiceInstance(writer, request, id)
}

func (a *API) listServiceBindings(writer http.ResponseWriter, serviceInstanceId string) {
sbs, err := a.smClient.ServiceBindingsFor(serviceInstanceId)
if err != nil {
a.handleError(writer, err)
Expand All @@ -232,8 +269,15 @@ func (a *API) ListServiceBindings(writer http.ResponseWriter, request *http.Requ

func (a *API) CreateServiceBinding(writer http.ResponseWriter, request *http.Request) {
a.setupCors(writer, request)
namespace := request.URL.Query().Get("sm_secret_namespace")
name := request.URL.Query().Get("sm_secret_name")
err := a.smClient.SetForGivenSecret(context.Background(), name, namespace)
if err != nil {
a.handleError(writer, err)
return
}
serviceBindingRequest := &requests.CreateServiceBinding{}
err := json.NewDecoder(request.Body).Decode(serviceBindingRequest)
err = json.NewDecoder(request.Body).Decode(serviceBindingRequest)
if err != nil {
a.handleError(writer, err)
return
Expand Down Expand Up @@ -290,9 +334,7 @@ func (a *API) CreateServiceBinding(writer http.ResponseWriter, request *http.Req
a.sendResponse(writer, response, http.StatusCreated)
}

func (a *API) GetServiceBinding(writer http.ResponseWriter, request *http.Request) {
a.setupCors(writer, request)
id := request.PathValue("id")
func (a *API) getServiceBinding(writer http.ResponseWriter, id string) {
sb, err := a.smClient.ServiceBinding(id)
if err != nil {
a.handleError(writer, err)
Expand Down Expand Up @@ -320,9 +362,34 @@ func (a *API) GetServiceBinding(writer http.ResponseWriter, request *http.Reques
a.sendResponse(writer, response)
}

func (a *API) HandleGetServiceBinding(writer http.ResponseWriter, request *http.Request) {
a.setupCors(writer, request)
namespace := request.URL.Query().Get("sm_secret_namespace")
name := request.URL.Query().Get("sm_secret_name")
err := a.smClient.SetForGivenSecret(context.Background(), name, namespace)
if err != nil {
a.handleError(writer, err)
return
}
id := request.URL.Query().Get("id")
if id == "" {
serviceInstanceId := request.URL.Query().Get("service_instance_id")
a.listServiceBindings(writer, serviceInstanceId)
return
}
a.getServiceBinding(writer, id)
}

func (a *API) DeleteServiceBinding(writer http.ResponseWriter, request *http.Request) {
a.setupCors(writer, request)
id := request.PathValue("id")
namespace := request.URL.Query().Get("sm_secret_namespace")
name := request.URL.Query().Get("sm_secret_name")
err := a.smClient.SetForGivenSecret(context.Background(), name, namespace)
if err != nil {
a.handleError(writer, err)
return
}
id := request.URL.Query().Get("id")
secrets, err := a.secretsForGivenServiceBindingID(id)
if err != nil {
a.handleError(writer, err)
Expand Down Expand Up @@ -366,7 +433,14 @@ func (a *API) decodeCreateServiceInstanceRequest(request *http.Request) (*reques

func (a *API) UpdateServiceInstance(writer http.ResponseWriter, request *http.Request) {
a.setupCors(writer, request)
id := request.PathValue("id")
namespace := request.URL.Query().Get("sm_secret_namespace")
name := request.URL.Query().Get("sm_secret_name")
err := a.smClient.SetForGivenSecret(context.Background(), name, namespace)
if err != nil {
a.handleError(writer, err)
return
}
id := request.URL.Query().Get("id")
siuReq, err := a.decodeServiceInstanceUpdateRequest(request)
if err != nil {
a.handleError(writer, err)
Expand Down Expand Up @@ -397,7 +471,14 @@ func (a *API) decodeServiceInstanceUpdateRequest(request *http.Request) (*types.

func (a *API) DeleteServiceInstance(writer http.ResponseWriter, request *http.Request) {
a.setupCors(writer, request)
id := request.PathValue("id")
namespace := request.URL.Query().Get("sm_secret_namespace")
name := request.URL.Query().Get("sm_secret_name")
err := a.smClient.SetForGivenSecret(context.Background(), name, namespace)
if err != nil {
a.handleError(writer, err)
return
}
id := request.URL.Query().Get("id")
if err := a.smClient.DeleteServiceInstance(id); err != nil {
a.handleError(writer, err)
return
Expand Down Expand Up @@ -477,7 +558,14 @@ func (a *API) secretExists(secretName, secretNamespace string) (bool, error) {

func (a *API) RestoreSecret(writer http.ResponseWriter, request *http.Request) {
a.setupCors(writer, request)
sbID := request.PathValue("id")
namespace := request.URL.Query().Get("sm_secret_namespace")
name := request.URL.Query().Get("sm_secret_name")
err := a.smClient.SetForGivenSecret(context.Background(), name, namespace)
if err != nil {
a.handleError(writer, err)
return
}
sbID := request.URL.Query().Get("id")
sb, err := a.smClient.ServiceBinding(sbID)
if err != nil {
a.handleError(writer, err)
Expand Down
Loading
Loading