diff --git a/workspaces/backend/README.md b/workspaces/backend/README.md index c684acc3..25d96513 100644 --- a/workspaces/backend/README.md +++ b/workspaces/backend/README.md @@ -26,7 +26,8 @@ make run PORT=8000 | URL Pattern | Handler | Action | |----------------------------------------------|------------------------|-----------------------------------------| -| GET /api/v1/healthcheck | healthcheck_handler | Show application information. | +| GET /api/v1/healthcheck | healthcheck_handler | Show application information | +| GET /api/v1/namespaces | namespaces_handler | Get all Namespaces | | GET /api/v1/workspaces | workspaces_handler | Get all Workspaces | | GET /api/v1/workspaces/{namespace} | workspaces_handler | Get all Workspaces from a namespace | | POST /api/v1/workspaces/{namespace} | workspaces_handler | Create a Workspace in a given namespace | @@ -47,6 +48,10 @@ make run PORT=8000 curl -i localhost:4000/api/v1/healthcheck ``` ``` +# GET /api/v1/namespaces +curl -i localhost:4000/api/v1/namespaces +``` +``` # GET /api/v1/workspaces/ curl -i localhost:4000/api/v1/workspaces ``` diff --git a/workspaces/backend/api/app.go b/workspaces/backend/api/app.go index 235ab45c..127c6b59 100644 --- a/workspaces/backend/api/app.go +++ b/workspaces/backend/api/app.go @@ -46,6 +46,9 @@ const ( AllWorkspaceKindsPath = PathPrefix + "/workspacekinds" WorkspaceKindNamePathParam = "name" WorkspaceKindsByNamePath = AllWorkspaceKindsPath + "/:" + WorkspaceNamePathParam + + //namespaces + AllNamespacesPath = PathPrefix + "/namespaces" ) type App struct { @@ -75,6 +78,7 @@ func (a *App) Routes() http.Handler { router.MethodNotAllowed = http.HandlerFunc(a.methodNotAllowedResponse) router.GET(HealthCheckPath, a.HealthcheckHandler) + router.GET(AllNamespacesPath, a.GetNamespacesHandler) router.GET(AllWorkspacesPath, a.GetWorkspacesHandler) router.GET(WorkspacesByNamespacePath, a.GetWorkspacesHandler) diff --git a/workspaces/backend/api/namespaces_handler.go b/workspaces/backend/api/namespaces_handler.go new file mode 100644 index 00000000..fca44e1a --- /dev/null +++ b/workspaces/backend/api/namespaces_handler.go @@ -0,0 +1,45 @@ +/* + * + * Copyright 2024. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * / + */ + +package api + +import ( + "github.com/julienschmidt/httprouter" + "github.com/kubeflow/notebooks/workspaces/backend/internal/models" + "net/http" +) + +type NamespacesEnvelope Envelope[[]models.NamespaceModel] + +func (a *App) GetNamespacesHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + + namespaces, err := a.repositories.Namespace.GetNamespaces(r.Context()) + if err != nil { + a.serverErrorResponse(w, r, err) + return + } + + namespacesEnvelope := NamespacesEnvelope{ + Data: namespaces, + } + + err = a.WriteJSON(w, http.StatusOK, namespacesEnvelope, nil) + if err != nil { + a.serverErrorResponse(w, r, err) + } +} diff --git a/workspaces/backend/api/workspaceskind_handler_test.go b/workspaces/backend/api/workspacekinds_handler_test.go similarity index 100% rename from workspaces/backend/api/workspaceskind_handler_test.go rename to workspaces/backend/api/workspacekinds_handler_test.go diff --git a/workspaces/backend/internal/models/namespaces.go b/workspaces/backend/internal/models/namespaces.go new file mode 100644 index 00000000..63037528 --- /dev/null +++ b/workspaces/backend/internal/models/namespaces.go @@ -0,0 +1,29 @@ +/* + * + * Copyright 2024. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * / + */ + +package models + +type NamespaceModel struct { + Name string `json:"name"` +} + +func NewNamespaceModelFromNamespace(name string) NamespaceModel { + return NamespaceModel{ + Name: name, + } +} diff --git a/workspaces/backend/internal/repositories/namespaces.go b/workspaces/backend/internal/repositories/namespaces.go new file mode 100644 index 00000000..9eda3be2 --- /dev/null +++ b/workspaces/backend/internal/repositories/namespaces.go @@ -0,0 +1,53 @@ +/* + * + * Copyright 2024. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * / + */ + +package repositories + +import ( + "context" + "github.com/kubeflow/notebooks/workspaces/backend/internal/models" + v1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type NamespaceRepository struct { + client client.Client +} + +func NewNamespaceRepository(client client.Client) *NamespaceRepository { + return &NamespaceRepository{ + client: client, + } +} + +func (r *NamespaceRepository) GetNamespaces(ctx context.Context) ([]models.NamespaceModel, error) { + + //TODO (ederign) Implement subject access review here to fetch only + // namespaces that "kubeflow-userid" has access + namespaceList := &v1.NamespaceList{} + err := r.client.List(ctx, namespaceList, &client.ListOptions{}) + if err != nil { + return nil, err + } + + namespaces := make([]models.NamespaceModel, len(namespaceList.Items)) + for i, ns := range namespaceList.Items { + namespaces[i] = models.NewNamespaceModelFromNamespace(ns.Name) + } + return namespaces, nil +} diff --git a/workspaces/backend/internal/repositories/repositories.go b/workspaces/backend/internal/repositories/repositories.go index f3dccbc8..491b5919 100644 --- a/workspaces/backend/internal/repositories/repositories.go +++ b/workspaces/backend/internal/repositories/repositories.go @@ -27,6 +27,7 @@ type Repositories struct { HealthCheck *HealthCheckRepository Workspace *WorkspaceRepository WorkspaceKind *WorkspaceKindRepository + Namespace *NamespaceRepository } func NewRepositories(client client.Client) *Repositories { @@ -34,5 +35,6 @@ func NewRepositories(client client.Client) *Repositories { HealthCheck: NewHealthCheckRepository(), Workspace: NewWorkspaceRepository(client), WorkspaceKind: NewWorkspaceKindRepository(client), + Namespace: NewNamespaceRepository(client), } }