From 0c952d4c1d5d6057d404ef9c34a75b62f2730a4c Mon Sep 17 00:00:00 2001 From: "taekyu.kang" Date: Mon, 26 Feb 2024 14:10:04 +0900 Subject: [PATCH] feature. add interface project-namespace-k8s-resources --- api/swagger/docs.go | 98 +++++++++++++++++++++++++++++++ api/swagger/swagger.json | 98 +++++++++++++++++++++++++++++++ api/swagger/swagger.yaml | 64 ++++++++++++++++++++ internal/delivery/api/endpoint.go | 9 +++ internal/delivery/http/project.go | 53 +++++++++++++++++ internal/route/route.go | 1 + internal/usecase/project.go | 19 ++++++ pkg/domain/project.go | 16 +++++ 8 files changed, 358 insertions(+) diff --git a/api/swagger/docs.go b/api/swagger/docs.go index 25c5a8d6..d071dd1e 100644 --- a/api/swagger/docs.go +++ b/api/swagger/docs.go @@ -4117,6 +4117,64 @@ const docTemplate = `{ } } }, + "/organizations/{organizationId}/projects/{projectId}/namespaces/{projectNamespace}/stacks/{stackId}/k8s-resources": { + "get": { + "security": [ + { + "JWT": [] + } + ], + "description": "Get k8s resources for project namespace", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Projects" + ], + "summary": "Get k8s resources for project namespace", + "parameters": [ + { + "type": "string", + "description": "Organization ID", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Project ID", + "name": "projectId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Stack ID", + "name": "stackId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Project Namespace", + "name": "projectNamespace", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.GetProjectNamespaceK8sResourcesResponse" + } + } + } + } + }, "/organizations/{organizationId}/stacks": { "get": { "security": [ @@ -7167,6 +7225,14 @@ const docTemplate = `{ } } }, + "domain.GetProjectNamespaceK8sResourcesResponse": { + "type": "object", + "properties": { + "k8sResources": { + "$ref": "#/definitions/domain.ProjectNamespaceK8sResources" + } + } + }, "domain.GetProjectNamespaceResponse": { "type": "object", "properties": { @@ -7714,6 +7780,38 @@ const docTemplate = `{ } } }, + "domain.ProjectNamespaceK8sResources": { + "type": "object", + "properties": { + "cronjobs": { + "type": "integer" + }, + "demonsets": { + "type": "integer" + }, + "deployments": { + "type": "integer" + }, + "ingresses": { + "type": "integer" + }, + "jobs": { + "type": "integer" + }, + "pods": { + "type": "integer" + }, + "pvcs": { + "type": "integer" + }, + "services": { + "type": "integer" + }, + "statefulsets": { + "type": "integer" + } + } + }, "domain.ProjectNamespaceResponse": { "type": "object", "properties": { diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index 54a4cacd..97c10867 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -4111,6 +4111,64 @@ } } }, + "/organizations/{organizationId}/projects/{projectId}/namespaces/{projectNamespace}/stacks/{stackId}/k8s-resources": { + "get": { + "security": [ + { + "JWT": [] + } + ], + "description": "Get k8s resources for project namespace", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Projects" + ], + "summary": "Get k8s resources for project namespace", + "parameters": [ + { + "type": "string", + "description": "Organization ID", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Project ID", + "name": "projectId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Stack ID", + "name": "stackId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Project Namespace", + "name": "projectNamespace", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.GetProjectNamespaceK8sResourcesResponse" + } + } + } + } + }, "/organizations/{organizationId}/stacks": { "get": { "security": [ @@ -7161,6 +7219,14 @@ } } }, + "domain.GetProjectNamespaceK8sResourcesResponse": { + "type": "object", + "properties": { + "k8sResources": { + "$ref": "#/definitions/domain.ProjectNamespaceK8sResources" + } + } + }, "domain.GetProjectNamespaceResponse": { "type": "object", "properties": { @@ -7708,6 +7774,38 @@ } } }, + "domain.ProjectNamespaceK8sResources": { + "type": "object", + "properties": { + "cronjobs": { + "type": "integer" + }, + "demonsets": { + "type": "integer" + }, + "deployments": { + "type": "integer" + }, + "ingresses": { + "type": "integer" + }, + "jobs": { + "type": "integer" + }, + "pods": { + "type": "integer" + }, + "pvcs": { + "type": "integer" + }, + "services": { + "type": "integer" + }, + "statefulsets": { + "type": "integer" + } + } + }, "domain.ProjectNamespaceResponse": { "type": "object", "properties": { diff --git a/api/swagger/swagger.yaml b/api/swagger/swagger.yaml index aa05361a..f9abcd33 100644 --- a/api/swagger/swagger.yaml +++ b/api/swagger/swagger.yaml @@ -1342,6 +1342,11 @@ definitions: $ref: '#/definitions/domain.ProjectMemberResponse' type: array type: object + domain.GetProjectNamespaceK8sResourcesResponse: + properties: + k8sResources: + $ref: '#/definitions/domain.ProjectNamespaceK8sResources' + type: object domain.GetProjectNamespaceResponse: properties: projectNamespace: @@ -1707,6 +1712,27 @@ definitions: updatedAt: type: string type: object + domain.ProjectNamespaceK8sResources: + properties: + cronjobs: + type: integer + demonsets: + type: integer + deployments: + type: integer + ingresses: + type: integer + jobs: + type: integer + pods: + type: integer + pvcs: + type: integer + services: + type: integer + statefulsets: + type: integer + type: object domain.ProjectNamespaceResponse: properties: appCount: @@ -4941,6 +4967,44 @@ paths: summary: Check project namespace exist tags: - Projects + /organizations/{organizationId}/projects/{projectId}/namespaces/{projectNamespace}/stacks/{stackId}/k8s-resources: + get: + consumes: + - application/json + description: Get k8s resources for project namespace + parameters: + - description: Organization ID + in: path + name: organizationId + required: true + type: string + - description: Project ID + in: path + name: projectId + required: true + type: string + - description: Stack ID + in: path + name: stackId + required: true + type: string + - description: Project Namespace + in: path + name: projectNamespace + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.GetProjectNamespaceK8sResourcesResponse' + security: + - JWT: [] + summary: Get k8s resources for project namespace + tags: + - Projects /organizations/{organizationId}/projects/existence: get: consumes: diff --git a/internal/delivery/api/endpoint.go b/internal/delivery/api/endpoint.go index 21ee33c4..fe167f60 100644 --- a/internal/delivery/api/endpoint.go +++ b/internal/delivery/api/endpoint.go @@ -150,6 +150,7 @@ const ( UnSetFavoriteProject UnSetFavoriteProjectNamespace GetProjectKubeconfig + GetProjectNamespaceK8sResources ) var ApiMap = map[Endpoint]EndpointInfo{ @@ -613,6 +614,10 @@ var ApiMap = map[Endpoint]EndpointInfo{ Name: "GetProjectKubeconfig", Group: "Project", }, + GetProjectNamespaceK8sResources: { + Name: "GetProjectNamespaceK8sResources", + Group: "Project", + }, } func (e Endpoint) String() string { @@ -847,6 +852,8 @@ func (e Endpoint) String() string { return "UnSetFavoriteProjectNamespace" case GetProjectKubeconfig: return "GetProjectKubeconfig" + case GetProjectNamespaceK8sResources: + return "GetProjectNamespaceK8sResources" default: return "" } @@ -1083,6 +1090,8 @@ func GetEndpoint(name string) Endpoint { return UnSetFavoriteProjectNamespace case "GetProjectKubeconfig": return GetProjectKubeconfig + case "GetProjectNamespaceK8sResources": + return GetProjectNamespaceK8sResources default: return -1 } diff --git a/internal/delivery/http/project.go b/internal/delivery/http/project.go index cc864945..8824422c 100644 --- a/internal/delivery/http/project.go +++ b/internal/delivery/http/project.go @@ -49,6 +49,7 @@ type IProjectHandler interface { UnSetFavoriteProjectNamespace(w http.ResponseWriter, r *http.Request) GetProjectKubeconfig(w http.ResponseWriter, r *http.Request) + GetProjectNamespaceK8sResources(w http.ResponseWriter, r *http.Request) } type ProjectHandler struct { @@ -1359,3 +1360,55 @@ func (p ProjectHandler) GetProjectKubeconfig(w http.ResponseWriter, r *http.Requ ResponseJSON(w, r, http.StatusOK, out) } + +// GetProjectNamespaceK8sResources godoc +// @Tags Projects +// @Summary Get k8s resources for project namespace +// @Description Get k8s resources for project namespace +// @Accept json +// @Produce json +// @Param organizationId path string true "Organization ID" +// @Param projectId path string true "Project ID" +// @Param stackId path string true "Stack ID" +// @Param projectNamespace path string true "Project Namespace" +// @Success 200 {object} domain.GetProjectNamespaceK8sResourcesResponse +// @Router /organizations/{organizationId}/projects/{projectId}/namespaces/{projectNamespace}/stacks/{stackId}/k8s-resources [get] +// @Security JWT +func (p ProjectHandler) GetProjectNamespaceK8sResources(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + organizationId, ok := vars["organizationId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("organizationId not found in path"), "C_INVALID_ORGANIZATION_ID", "")) + return + } + + projectId, ok := vars["projectId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("projectId not found in path"), "C_INVALID_PROJECT_ID", "")) + return + } + + projectNamespace, ok := vars["projectNamespace"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid projectNamespace"), "C_INVALID_PROJECT_NAMESPACE", "")) + return + } + stackId, ok := vars["stackId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid stackId"), "C_INVALID_STACK_ID", "")) + return + } + + k8sResources, err := p.usecase.GetK8sResources(r.Context(), organizationId, projectId, projectNamespace, stackId) + if err != nil { + log.ErrorWithContext(r.Context(), "Failed to get project resources.", err) + ErrorJSON(w, r, err) + return + } + + var out domain.GetProjectNamespaceK8sResourcesResponse + if err = serializer.Map(k8sResources, &out.K8sResources); err != nil { + log.Error(err) + } + ResponseJSON(w, r, http.StatusOK, out) +} diff --git a/internal/route/route.go b/internal/route/route.go index e97a514a..95f46961 100644 --- a/internal/route/route.go +++ b/internal/route/route.go @@ -232,6 +232,7 @@ func SetupRouter(db *gorm.DB, argoClient argowf.ArgoClient, kc keycloak.IKeycloa r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/projects/{projectId}/members/{projectMemberId}/role", customMiddleware.Handle(internalApi.UpdateProjectMemberRole, http.HandlerFunc(projectHandler.UpdateProjectMemberRole))).Methods(http.MethodPut) r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/projects/{projectId}/namespaces", customMiddleware.Handle(internalApi.CreateProjectNamespace, http.HandlerFunc(projectHandler.CreateProjectNamespace))).Methods(http.MethodPost) r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/projects/{projectId}/namespaces/{projectNamespace}/stacks/{stackId}/existence", customMiddleware.Handle(internalApi.GetProjectNamespace, http.HandlerFunc(projectHandler.IsProjectNamespaceExist))).Methods(http.MethodGet) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/projects/{projectId}/namespaces/{projectNamespace}/stacks/{stackId}/k8s-resources", customMiddleware.Handle(internalApi.GetProjectNamespaceK8sResources, http.HandlerFunc(projectHandler.GetProjectNamespaceK8sResources))).Methods(http.MethodGet) r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/projects/{projectId}/namespaces", customMiddleware.Handle(internalApi.GetProjectNamespaces, http.HandlerFunc(projectHandler.GetProjectNamespaces))).Methods(http.MethodGet) r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/projects/{projectId}/namespaces/{projectNamespace}/stacks/{stackId}", customMiddleware.Handle(internalApi.GetProjectNamespace, http.HandlerFunc(projectHandler.GetProjectNamespace))).Methods(http.MethodGet) r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/projects/{projectId}/namespaces/{projectNamespace}/stacks/{stackId}", customMiddleware.Handle(internalApi.UpdateProjectNamespace, http.HandlerFunc(projectHandler.UpdateProjectNamespace))).Methods(http.MethodPut) diff --git a/internal/usecase/project.go b/internal/usecase/project.go index 4817bff8..7afc25e1 100644 --- a/internal/usecase/project.go +++ b/internal/usecase/project.go @@ -1,6 +1,8 @@ package usecase import ( + "context" + "github.com/google/uuid" "github.com/openinfradev/tks-api/internal/kubernetes" "github.com/openinfradev/tks-api/internal/repository" @@ -42,6 +44,7 @@ type IProjectUsecase interface { UpdateProjectNamespace(pn *domain.ProjectNamespace) error DeleteProjectNamespace(organizationId string, projectId string, projectNamespace string, stackId string) error GetProjectKubeconfig(organizationId string, projectId string) (string, error) + GetK8sResources(ctx context.Context, organizationId string, projectId string, projectNamespace string, stackId string) (out domain.ProjectNamespaceK8sResources, err error) } type ProjectUsecase struct { @@ -416,3 +419,19 @@ func (u *ProjectUsecase) GetProjectKubeconfig(organizationId string, projectId s return kubernetes.MergeKubeconfigsWithSingleUser(kubeconfigs) } + +func (u *ProjectUsecase) GetK8sResources(ctx context.Context, organizationId string, projectId string, projectNamespace string, stackId string) (out domain.ProjectNamespaceK8sResources, err error) { + + // to be implemented + out.Pods = 1 + out.Deployments = 2 + out.Statefulsets = 3 + out.Demonsets = 4 + out.Jobs = 5 + out.Cronjobs = 6 + out.PVCs = 7 + out.Services = 8 + out.Ingresses = 9 + + return +} diff --git a/pkg/domain/project.go b/pkg/domain/project.go index 10e5d9a4..3fc02157 100644 --- a/pkg/domain/project.go +++ b/pkg/domain/project.go @@ -254,3 +254,19 @@ type UpdateProjectNamespaceRequest struct { type GetProjectKubeconfigResponse struct { Kubeconfig string `json:"kubeconfig"` } + +type ProjectNamespaceK8sResources struct { + Pods int `json:"pods"` + Deployments int `json:"deployments"` + Statefulsets int `json:"statefulsets"` + Demonsets int `json:"demonsets"` + Jobs int `json:"jobs"` + Cronjobs int `json:"cronjobs"` + PVCs int `json:"pvcs"` + Services int `json:"services"` + Ingresses int `json:"ingresses"` +} + +type GetProjectNamespaceK8sResourcesResponse struct { + K8sResources ProjectNamespaceK8sResources `json:"k8sResources"` +}