From d1264aecd628ea31f8b8bfb808231a565731583b Mon Sep 17 00:00:00 2001 From: Robert Choi Date: Tue, 20 Jun 2023 17:52:53 +0900 Subject: [PATCH 01/54] [721] add API to return num of apps on given stack --- internal/delivery/http/app-serve-app.go | 32 +++++++++++++++++++++++++ internal/repository/app-serve-app.go | 13 ++++++++++ internal/route/route.go | 1 + internal/usecase/app-serve-app.go | 10 ++++++++ 4 files changed, 56 insertions(+) diff --git a/internal/delivery/http/app-serve-app.go b/internal/delivery/http/app-serve-app.go index e805167c..632e50ef 100644 --- a/internal/delivery/http/app-serve-app.go +++ b/internal/delivery/http/app-serve-app.go @@ -299,6 +299,38 @@ func (h *AppServeAppHandler) GetAppServeAppLatestTask(w http.ResponseWriter, r * ResponseJSON(w, r, http.StatusOK, out) } +// GetNumOfAppsOnStack godoc +// @Tags AppServeApps +// @Summary Get number of apps on given stack +// @Description Get number of apps on given stack +// @Accept json +// @Produce json +// @Success 200 {object} int64 +// @Router /organizations/{organizationId}/app-serve-apps/count [get] +// @Security JWT +func (h *AppServeAppHandler) GetNumOfAppsOnStack(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + + organizationId, ok := vars["organizationId"] + fmt.Printf("organizationId = [%v]\n", organizationId) + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid organizationId"), "", "")) + return + } + + urlParams := r.URL.Query() + stackId := urlParams.Get("stackId") + fmt.Printf("stackId = [%s]\n", stackId) + + numApps, err := h.usecase.GetNumOfAppsOnStack(organizationId, stackId) + if err != nil { + ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) + return + } + + ResponseJSON(w, r, http.StatusOK, numApps) +} + func makeStages(app *domain.AppServeApp) []domain.StageResponse { stages := make([]domain.StageResponse, 0) diff --git a/internal/repository/app-serve-app.go b/internal/repository/app-serve-app.go index 2ed1643d..a2e40c27 100644 --- a/internal/repository/app-serve-app.go +++ b/internal/repository/app-serve-app.go @@ -15,6 +15,7 @@ type IAppServeAppRepository interface { GetAppServeApps(organizationId string, showAll bool) ([]domain.AppServeApp, error) GetAppServeAppById(appId string) (*domain.AppServeApp, error) GetAppServeAppLatestTask(appId string) (*domain.AppServeAppTask, error) + GetNumOfAppsOnStack(organizationId string, clusterId string) (int64, error) IsAppServeAppExist(appId string) (int64, error) IsAppServeAppNameExist(orgId string, appName string) (int64, error) CreateTask(task *domain.AppServeAppTask) (taskId string, err error) @@ -133,6 +134,18 @@ func (r *AppServeAppRepository) GetAppServeAppLatestTask(appId string) (*domain. return &task, nil } +func (r *AppServeAppRepository) GetNumOfAppsOnStack(organizationId string, clusterId string) (int64, error) { + var apps []domain.AppServeApp + + queryStr := fmt.Sprintf("organization_id = '%s' AND target_cluster_id = '%s' AND status <> 'DELETE_SUCCESS'", organizationId, clusterId) + res := r.db.Find(&apps, queryStr) + if res.Error != nil { + return -1, fmt.Errorf("Error while finding appServeApps with organizationId: %s", organizationId) + } + + return res.RowsAffected, nil +} + func (r *AppServeAppRepository) IsAppServeAppExist(appId string) (int64, error) { var result int64 diff --git a/internal/route/route.go b/internal/route/route.go index ebf23d8f..429e8c1c 100644 --- a/internal/route/route.go +++ b/internal/route/route.go @@ -126,6 +126,7 @@ func SetupRouter(db *gorm.DB, argoClient argowf.ArgoClient, kc keycloak.IKeycloa appServeAppHandler := delivery.NewAppServeAppHandler(usecase.NewAppServeAppUsecase(repoFactory, argoClient)) r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/app-serve-apps", authMiddleware.Handle(http.HandlerFunc(appServeAppHandler.CreateAppServeApp))).Methods(http.MethodPost) r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/app-serve-apps", authMiddleware.Handle(http.HandlerFunc(appServeAppHandler.GetAppServeApps))).Methods(http.MethodGet) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/app-serve-apps/count", authMiddleware.Handle(http.HandlerFunc(appServeAppHandler.GetNumOfAppsOnStack))).Methods(http.MethodGet) r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/app-serve-apps/{appId}", authMiddleware.Handle(http.HandlerFunc(appServeAppHandler.GetAppServeApp))).Methods(http.MethodGet) // TODO: To be implemented // r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/app-serve-apps/{appId}/tasks/{taskId}", authMiddleware.Handle(http.HandlerFunc(appServeAppHandler.GetAppServeAppTask))).Methods(http.MethodGet) diff --git a/internal/usecase/app-serve-app.go b/internal/usecase/app-serve-app.go index 95907b63..746d2d9b 100644 --- a/internal/usecase/app-serve-app.go +++ b/internal/usecase/app-serve-app.go @@ -22,6 +22,7 @@ type IAppServeAppUsecase interface { GetAppServeApps(organizationId string, showAll bool) ([]domain.AppServeApp, error) GetAppServeAppById(appId string) (*domain.AppServeApp, error) GetAppServeAppLatestTask(appId string) (*domain.AppServeAppTask, error) + GetNumOfAppsOnStack(organizationId string, clusterId string) (int64, error) IsAppServeAppExist(appId string) (bool, error) IsAppServeAppNameExist(orgId string, appName string) (bool, error) UpdateAppServeAppStatus(appId string, taskId string, status string, output string) (ret string, err error) @@ -168,6 +169,15 @@ func (u *AppServeAppUsecase) GetAppServeAppLatestTask(appId string) (*domain.App return task, nil } +func (u *AppServeAppUsecase) GetNumOfAppsOnStack(organizationId string, clusterId string) (int64, error) { + numApps, err := u.repo.GetNumOfAppsOnStack(organizationId, clusterId) + if err != nil { + return -1, err + } + + return numApps, nil +} + func (u *AppServeAppUsecase) IsAppServeAppExist(appId string) (bool, error) { count, err := u.repo.IsAppServeAppExist(appId) if err != nil { From 72f0b316751593252d7505f52e4d9f1d95e39c8f Mon Sep 17 00:00:00 2001 From: Taekyu Date: Tue, 20 Jun 2023 17:54:28 +0900 Subject: [PATCH 02/54] feature. fix stack to not be deleted, if appServeApp exists. --- internal/usecase/stack.go | 12 ++++++++++++ pkg/httpErrors/errorCode.go | 1 + 2 files changed, 13 insertions(+) diff --git a/internal/usecase/stack.go b/internal/usecase/stack.go index 4181e4c4..8d4ac8d2 100644 --- a/internal/usecase/stack.go +++ b/internal/usecase/stack.go @@ -37,6 +37,7 @@ type StackUsecase struct { cloudAccountRepo repository.ICloudAccountRepository organizationRepo repository.IOrganizationRepository stackTemplateRepo repository.IStackTemplateRepository + appServeAppRepo repository.IAppServeAppRepository argo argowf.ArgoClient } @@ -47,6 +48,7 @@ func NewStackUsecase(r repository.Repository, argoClient argowf.ArgoClient) ISta cloudAccountRepo: r.CloudAccount, organizationRepo: r.Organization, stackTemplateRepo: r.StackTemplate, + appServeAppRepo: r.AppServeApp, argo: argoClient, } } @@ -312,6 +314,16 @@ func (u *StackUsecase) Delete(ctx context.Context, dto domain.Stack) (err error) } } + appServeApps, err := u.appServeAppRepo.GetAppServeApps(dto.OrganizationId, true) + if err != nil { + return err + } + for _, app := range appServeApps { + if app.TargetClusterId == dto.ID.String() && app.Status != "ERROR" { + return httpErrors.NewBadRequestError(fmt.Errorf("existed appServeApps in %s", dto.OrganizationId), "S_FAILED_DELETE_EXISTED_ASA", "") + } + } + workflow := "" if strings.Contains(cluster.StackTemplate.Template, "aws-reference") || strings.Contains(cluster.StackTemplate.Template, "eks-reference") { workflow = "tks-stack-delete-aws" diff --git a/pkg/httpErrors/errorCode.go b/pkg/httpErrors/errorCode.go index e13cf2fa..61785284 100644 --- a/pkg/httpErrors/errorCode.go +++ b/pkg/httpErrors/errorCode.go @@ -52,6 +52,7 @@ var errorMap = map[ErrorCode]string{ "S_FAILED_TO_CALL_WORKFLOW": "스택 생성에 실패하였습니다. 관리자에게 문의하세요.", "S_REMAIN_CLUSTER_FOR_DELETION": "프라이머리 클러스터를 지우기 위해서는 조직내의 모든 클러스터를 삭제해야 합니다.", "S_FAILED_GET_CLUSTERS": "클러스터를 가져오는데 실패했습니다.", + "S_FAILED_DELETE_EXISTED_ASA": "지우고자 하는 스택에 남아 있는 앱서빙앱이 있습니다.", // Alert "AL_NOT_FOUND_ALERT": "지정한 앨럿이 존재하지 않습니다.", From 7652de155017c910cd1613388382d4d7a65cba6c Mon Sep 17 00:00:00 2001 From: Robert Choi Date: Tue, 20 Jun 2023 18:12:54 +0900 Subject: [PATCH 03/54] trivial: use log.Debugf --- internal/delivery/http/app-serve-app.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/delivery/http/app-serve-app.go b/internal/delivery/http/app-serve-app.go index 632e50ef..fb513661 100644 --- a/internal/delivery/http/app-serve-app.go +++ b/internal/delivery/http/app-serve-app.go @@ -312,7 +312,7 @@ func (h *AppServeAppHandler) GetNumOfAppsOnStack(w http.ResponseWriter, r *http. vars := mux.Vars(r) organizationId, ok := vars["organizationId"] - fmt.Printf("organizationId = [%v]\n", organizationId) + log.Debugf("organizationId = [%s]\n", organizationId) if !ok { ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid organizationId"), "", "")) return From 1e64feb6ce59f4abf525a85a3ca5c0dd0aea4f22 Mon Sep 17 00:00:00 2001 From: Robert Choi Date: Tue, 20 Jun 2023 17:52:53 +0900 Subject: [PATCH 04/54] [721] add API to return num of apps on given stack --- internal/delivery/http/app-serve-app.go | 32 +++++++++++++++++++++++++ internal/repository/app-serve-app.go | 13 ++++++++++ internal/route/route.go | 1 + internal/usecase/app-serve-app.go | 10 ++++++++ 4 files changed, 56 insertions(+) diff --git a/internal/delivery/http/app-serve-app.go b/internal/delivery/http/app-serve-app.go index e805167c..632e50ef 100644 --- a/internal/delivery/http/app-serve-app.go +++ b/internal/delivery/http/app-serve-app.go @@ -299,6 +299,38 @@ func (h *AppServeAppHandler) GetAppServeAppLatestTask(w http.ResponseWriter, r * ResponseJSON(w, r, http.StatusOK, out) } +// GetNumOfAppsOnStack godoc +// @Tags AppServeApps +// @Summary Get number of apps on given stack +// @Description Get number of apps on given stack +// @Accept json +// @Produce json +// @Success 200 {object} int64 +// @Router /organizations/{organizationId}/app-serve-apps/count [get] +// @Security JWT +func (h *AppServeAppHandler) GetNumOfAppsOnStack(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + + organizationId, ok := vars["organizationId"] + fmt.Printf("organizationId = [%v]\n", organizationId) + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid organizationId"), "", "")) + return + } + + urlParams := r.URL.Query() + stackId := urlParams.Get("stackId") + fmt.Printf("stackId = [%s]\n", stackId) + + numApps, err := h.usecase.GetNumOfAppsOnStack(organizationId, stackId) + if err != nil { + ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) + return + } + + ResponseJSON(w, r, http.StatusOK, numApps) +} + func makeStages(app *domain.AppServeApp) []domain.StageResponse { stages := make([]domain.StageResponse, 0) diff --git a/internal/repository/app-serve-app.go b/internal/repository/app-serve-app.go index 2ed1643d..a2e40c27 100644 --- a/internal/repository/app-serve-app.go +++ b/internal/repository/app-serve-app.go @@ -15,6 +15,7 @@ type IAppServeAppRepository interface { GetAppServeApps(organizationId string, showAll bool) ([]domain.AppServeApp, error) GetAppServeAppById(appId string) (*domain.AppServeApp, error) GetAppServeAppLatestTask(appId string) (*domain.AppServeAppTask, error) + GetNumOfAppsOnStack(organizationId string, clusterId string) (int64, error) IsAppServeAppExist(appId string) (int64, error) IsAppServeAppNameExist(orgId string, appName string) (int64, error) CreateTask(task *domain.AppServeAppTask) (taskId string, err error) @@ -133,6 +134,18 @@ func (r *AppServeAppRepository) GetAppServeAppLatestTask(appId string) (*domain. return &task, nil } +func (r *AppServeAppRepository) GetNumOfAppsOnStack(organizationId string, clusterId string) (int64, error) { + var apps []domain.AppServeApp + + queryStr := fmt.Sprintf("organization_id = '%s' AND target_cluster_id = '%s' AND status <> 'DELETE_SUCCESS'", organizationId, clusterId) + res := r.db.Find(&apps, queryStr) + if res.Error != nil { + return -1, fmt.Errorf("Error while finding appServeApps with organizationId: %s", organizationId) + } + + return res.RowsAffected, nil +} + func (r *AppServeAppRepository) IsAppServeAppExist(appId string) (int64, error) { var result int64 diff --git a/internal/route/route.go b/internal/route/route.go index ebf23d8f..429e8c1c 100644 --- a/internal/route/route.go +++ b/internal/route/route.go @@ -126,6 +126,7 @@ func SetupRouter(db *gorm.DB, argoClient argowf.ArgoClient, kc keycloak.IKeycloa appServeAppHandler := delivery.NewAppServeAppHandler(usecase.NewAppServeAppUsecase(repoFactory, argoClient)) r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/app-serve-apps", authMiddleware.Handle(http.HandlerFunc(appServeAppHandler.CreateAppServeApp))).Methods(http.MethodPost) r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/app-serve-apps", authMiddleware.Handle(http.HandlerFunc(appServeAppHandler.GetAppServeApps))).Methods(http.MethodGet) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/app-serve-apps/count", authMiddleware.Handle(http.HandlerFunc(appServeAppHandler.GetNumOfAppsOnStack))).Methods(http.MethodGet) r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/app-serve-apps/{appId}", authMiddleware.Handle(http.HandlerFunc(appServeAppHandler.GetAppServeApp))).Methods(http.MethodGet) // TODO: To be implemented // r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/app-serve-apps/{appId}/tasks/{taskId}", authMiddleware.Handle(http.HandlerFunc(appServeAppHandler.GetAppServeAppTask))).Methods(http.MethodGet) diff --git a/internal/usecase/app-serve-app.go b/internal/usecase/app-serve-app.go index 95907b63..746d2d9b 100644 --- a/internal/usecase/app-serve-app.go +++ b/internal/usecase/app-serve-app.go @@ -22,6 +22,7 @@ type IAppServeAppUsecase interface { GetAppServeApps(organizationId string, showAll bool) ([]domain.AppServeApp, error) GetAppServeAppById(appId string) (*domain.AppServeApp, error) GetAppServeAppLatestTask(appId string) (*domain.AppServeAppTask, error) + GetNumOfAppsOnStack(organizationId string, clusterId string) (int64, error) IsAppServeAppExist(appId string) (bool, error) IsAppServeAppNameExist(orgId string, appName string) (bool, error) UpdateAppServeAppStatus(appId string, taskId string, status string, output string) (ret string, err error) @@ -168,6 +169,15 @@ func (u *AppServeAppUsecase) GetAppServeAppLatestTask(appId string) (*domain.App return task, nil } +func (u *AppServeAppUsecase) GetNumOfAppsOnStack(organizationId string, clusterId string) (int64, error) { + numApps, err := u.repo.GetNumOfAppsOnStack(organizationId, clusterId) + if err != nil { + return -1, err + } + + return numApps, nil +} + func (u *AppServeAppUsecase) IsAppServeAppExist(appId string) (bool, error) { count, err := u.repo.IsAppServeAppExist(appId) if err != nil { From 3ae8d7197eb1590d7c0878768f65fb6e65e6cec5 Mon Sep 17 00:00:00 2001 From: Robert Choi Date: Tue, 20 Jun 2023 18:12:54 +0900 Subject: [PATCH 05/54] trivial: use log.Debugf --- internal/delivery/http/app-serve-app.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/delivery/http/app-serve-app.go b/internal/delivery/http/app-serve-app.go index 632e50ef..fb513661 100644 --- a/internal/delivery/http/app-serve-app.go +++ b/internal/delivery/http/app-serve-app.go @@ -312,7 +312,7 @@ func (h *AppServeAppHandler) GetNumOfAppsOnStack(w http.ResponseWriter, r *http. vars := mux.Vars(r) organizationId, ok := vars["organizationId"] - fmt.Printf("organizationId = [%v]\n", organizationId) + log.Debugf("organizationId = [%s]\n", organizationId) if !ok { ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid organizationId"), "", "")) return From d7b1533443efc452ce4bfb48609ce251d28388f2 Mon Sep 17 00:00:00 2001 From: Taekyu Date: Tue, 20 Jun 2023 23:28:36 +0900 Subject: [PATCH 06/54] feature. split error status. ERROR -> (INSTALL ERROR & DELETE ERROR) --- api/swagger/docs.go | 37 ++++++++++++++++++++++++++++ api/swagger/swagger.json | 37 ++++++++++++++++++++++++++++ api/swagger/swagger.yaml | 23 +++++++++++++++++ internal/repository/alert.go | 4 ++- internal/repository/cloud-account.go | 3 +++ internal/usecase/cloud-account.go | 4 +-- internal/usecase/stack.go | 21 ++++++++++------ pkg/domain/app-group.go | 6 +++-- pkg/domain/cloud-account.go | 11 ++++++--- pkg/domain/cluster.go | 8 +++--- pkg/domain/stack.go | 16 ++++++------ 11 files changed, 144 insertions(+), 26 deletions(-) diff --git a/api/swagger/docs.go b/api/swagger/docs.go index e7aca169..c7739f2b 100644 --- a/api/swagger/docs.go +++ b/api/swagger/docs.go @@ -1135,6 +1135,34 @@ const docTemplate = `{ } } }, + "/organizations/{organizationId}/app-serve-apps/count": { + "get": { + "security": [ + { + "JWT": [] + } + ], + "description": "Get number of apps on given stack", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AppServeApps" + ], + "summary": "Get number of apps on given stack", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "integer" + } + } + } + } + }, "/organizations/{organizationId}/app-serve-apps/name/{name}/existence": { "get": { "security": [ @@ -3532,6 +3560,9 @@ const docTemplate = `{ "createdAt": { "type": "string" }, + "createdIAM": { + "type": "boolean" + }, "creator": { "$ref": "#/definitions/domain.User" }, @@ -3591,6 +3622,9 @@ const docTemplate = `{ "createdAt": { "type": "string" }, + "createdIAM": { + "type": "boolean" + }, "creator": { "$ref": "#/definitions/domain.SimpleUserResponse" }, @@ -4904,6 +4938,9 @@ const docTemplate = `{ "clusters": { "type": "integer" }, + "createdIAM": { + "type": "boolean" + }, "description": { "type": "string" }, diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index f35af473..8134fa75 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -1128,6 +1128,34 @@ } } }, + "/organizations/{organizationId}/app-serve-apps/count": { + "get": { + "security": [ + { + "JWT": [] + } + ], + "description": "Get number of apps on given stack", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AppServeApps" + ], + "summary": "Get number of apps on given stack", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "integer" + } + } + } + } + }, "/organizations/{organizationId}/app-serve-apps/name/{name}/existence": { "get": { "security": [ @@ -3525,6 +3553,9 @@ "createdAt": { "type": "string" }, + "createdIAM": { + "type": "boolean" + }, "creator": { "$ref": "#/definitions/domain.User" }, @@ -3584,6 +3615,9 @@ "createdAt": { "type": "string" }, + "createdIAM": { + "type": "boolean" + }, "creator": { "$ref": "#/definitions/domain.SimpleUserResponse" }, @@ -4897,6 +4931,9 @@ "clusters": { "type": "integer" }, + "createdIAM": { + "type": "boolean" + }, "description": { "type": "string" }, diff --git a/api/swagger/swagger.yaml b/api/swagger/swagger.yaml index 227552be..3e8a57de 100644 --- a/api/swagger/swagger.yaml +++ b/api/swagger/swagger.yaml @@ -287,6 +287,8 @@ definitions: type: integer createdAt: type: string + createdIAM: + type: boolean creator: $ref: '#/definitions/domain.User' creatorId: @@ -326,6 +328,8 @@ definitions: type: integer createdAt: type: string + createdIAM: + type: boolean creator: $ref: '#/definitions/domain.SimpleUserResponse' description: @@ -1201,6 +1205,8 @@ definitions: type: string clusters: type: integer + createdIAM: + type: boolean description: type: string id: @@ -2580,6 +2586,23 @@ paths: summary: Get appServeApp tags: - AppServeApps + /organizations/{organizationId}/app-serve-apps/count: + get: + consumes: + - application/json + description: Get number of apps on given stack + produces: + - application/json + responses: + "200": + description: OK + schema: + type: integer + security: + - JWT: [] + summary: Get number of apps on given stack + tags: + - AppServeApps /organizations/{organizationId}/app-serve-apps/name/{name}/existence: get: consumes: diff --git a/internal/repository/alert.go b/internal/repository/alert.go index ad64b983..75ac663f 100644 --- a/internal/repository/alert.go +++ b/internal/repository/alert.go @@ -106,7 +106,9 @@ func (r *AlertRepository) Fetch(organizationId string) (out []domain.Alert, err }).Preload("AlertActions.Taker"). Preload("Cluster", "status = 2"). Preload("Organization"). - Order("created_at desc").Limit(1000).Find(&alerts, "organization_id = ?", organizationId) + Joins("join clusters on clusters.id = alerts.cluster_id AND clusters.status = 2"). + Order("created_at desc").Limit(1000). + Find(&alerts, "alerts.organization_id = ?", organizationId) if res.Error != nil { return nil, res.Error } diff --git a/internal/repository/cloud-account.go b/internal/repository/cloud-account.go index 72713761..e42115f0 100644 --- a/internal/repository/cloud-account.go +++ b/internal/repository/cloud-account.go @@ -47,6 +47,7 @@ type CloudAccount struct { Status domain.CloudAccountStatus StatusDesc string AwsAccountId string + CreatedIAM bool CreatorId *uuid.UUID `gorm:"type:uuid"` Creator User `gorm:"foreignKey:CreatorId"` UpdatorId *uuid.UUID `gorm:"type:uuid"` @@ -112,6 +113,7 @@ func (r *CloudAccountRepository) Create(dto domain.CloudAccount) (cloudAccountId CloudService: dto.CloudService, Resource: dto.Resource, AwsAccountId: dto.AwsAccountId, + CreatedIAM: false, Status: domain.CloudAccountStatus_PENDING, CreatorId: &dto.CreatorId} res := r.db.Create(&cloudAccount) @@ -162,6 +164,7 @@ func reflectCloudAccount(cloudAccount CloudAccount) domain.CloudAccount { Status: cloudAccount.Status, StatusDesc: cloudAccount.StatusDesc, AwsAccountId: cloudAccount.AwsAccountId, + CreatedIAM: cloudAccount.CreatedIAM, Creator: reflectSimpleUser(cloudAccount.Creator), Updator: reflectSimpleUser(cloudAccount.Updator), CreatedAt: cloudAccount.CreatedAt, diff --git a/internal/usecase/cloud-account.go b/internal/usecase/cloud-account.go index e78916dd..b9548271 100644 --- a/internal/usecase/cloud-account.go +++ b/internal/usecase/cloud-account.go @@ -210,8 +210,8 @@ func (u *CloudAccountUsecase) DeleteForce(ctx context.Context, cloudAccountId uu return err } - if cloudAccount.Status != domain.CloudAccountStatus_ERROR { - return fmt.Errorf("The status is not ERROR. %s", cloudAccount.Status) + if cloudAccount.Status != domain.CloudAccountStatus_CREATE_ERROR { + return fmt.Errorf("The status is not CREATE_ERROR. %s", cloudAccount.Status) } if u.getClusterCnt(cloudAccountId) > 0 { diff --git a/internal/usecase/stack.go b/internal/usecase/stack.go index 8d4ac8d2..491d83ea 100644 --- a/internal/usecase/stack.go +++ b/internal/usecase/stack.go @@ -292,16 +292,15 @@ func (u *StackUsecase) Delete(ctx context.Context, dto domain.Stack) (err error) } for _, cl := range clusters { - if cl.ID != cluster.ID && - cl.Status != domain.ClusterStatus_DELETED && - cl.Status != domain.ClusterStatus_ERROR { + if cl.ID != cluster.ID && (cl.Status == domain.ClusterStatus_RUNNING || + cl.Status == domain.ClusterStatus_INSTALLING || + cl.Status == domain.ClusterStatus_DELETING) { return httpErrors.NewBadRequestError(fmt.Errorf("Failed to delete 'Primary' cluster. The clusters remain in organization"), "S_REMAIN_CLUSTER_FOR_DELETION", "") } } break } } - appGroups, err := u.appGroupRepo.Fetch(domain.ClusterId(dto.ID)) if err != nil { return errors.Wrap(err, "Failed to get appGroups") @@ -522,8 +521,11 @@ func getStackStatus(cluster domain.Cluster, appGroups []domain.AppGroup) (domain if appGroup.Status == domain.AppGroupStatus_DELETING { return domain.StackStatus_APPGROUP_DELETING, appGroup.StatusDesc } - if appGroup.Status == domain.AppGroupStatus_ERROR { - return domain.StackStatus_APPGROUP_ERROR, appGroup.StatusDesc + if appGroup.Status == domain.AppGroupStatus_INSTALL_ERROR { + return domain.StackStatus_APPGROUP_INSTALL_ERROR, appGroup.StatusDesc + } + if appGroup.Status == domain.AppGroupStatus_DELETE_ERROR { + return domain.StackStatus_APPGROUP_DELETE_ERROR, appGroup.StatusDesc } } @@ -536,8 +538,11 @@ func getStackStatus(cluster domain.Cluster, appGroups []domain.AppGroup) (domain if cluster.Status == domain.ClusterStatus_DELETED { return domain.StackStatus_CLUSTER_DELETED, cluster.StatusDesc } - if cluster.Status == domain.ClusterStatus_ERROR { - return domain.StackStatus_CLUSTER_ERROR, cluster.StatusDesc + if cluster.Status == domain.ClusterStatus_INSTALL_ERROR { + return domain.StackStatus_CLUSTER_INSTALL_ERROR, cluster.StatusDesc + } + if cluster.Status == domain.ClusterStatus_DELETE_ERROR { + return domain.StackStatus_CLUSTER_DELETE_ERROR, cluster.StatusDesc } // workflow 중간 중간 비는 status 처리... diff --git a/pkg/domain/app-group.go b/pkg/domain/app-group.go index 76907997..9750f2e6 100644 --- a/pkg/domain/app-group.go +++ b/pkg/domain/app-group.go @@ -26,7 +26,8 @@ const ( AppGroupStatus_RUNNING AppGroupStatus_DELETING AppGroupStatus_DELETED - AppGroupStatus_ERROR + AppGroupStatus_INSTALL_ERROR + AppGroupStatus_DELETE_ERROR ) var appGroupStatus = [...]string{ @@ -35,7 +36,8 @@ var appGroupStatus = [...]string{ "RUNNING", "DELETING", "DELETED", - "ERROR", + "INSTALL_ERROR", + "DELETE_ERROR", } func (m AppGroupStatus) String() string { return appGroupStatus[(m)] } diff --git a/pkg/domain/cloud-account.go b/pkg/domain/cloud-account.go index d40706c5..e13b8f6f 100644 --- a/pkg/domain/cloud-account.go +++ b/pkg/domain/cloud-account.go @@ -22,7 +22,8 @@ const ( CloudAccountStatus_CREATED CloudAccountStatus_DELETING CloudAccountStatus_DELETED - CloudAccountStatus_ERROR + CloudAccountStatus_CREATE_ERROR + CloudAccountStatus_DELETE_ERROR ) var cloudAccountStatus = [...]string{ @@ -31,7 +32,8 @@ var cloudAccountStatus = [...]string{ "CREATED", "DELETING", "DELETED", - "ERROR", + "CREATE_ERROR", + "DELETE_ERROR", } func (m CloudAccountStatus) String() string { return cloudAccountStatus[(m)] } @@ -41,7 +43,7 @@ func (m CloudAccountStatus) FromString(s string) CloudAccountStatus { return CloudAccountStatus(i) } } - return CloudAccountStatus_ERROR + return CloudAccountStatus_PENDING } // 내부 @@ -59,6 +61,7 @@ type CloudAccount struct { SessionToken string Status CloudAccountStatus StatusDesc string + CreatedIAM bool CreatorId uuid.UUID Creator User UpdatorId uuid.UUID @@ -77,6 +80,7 @@ type CloudAccountResponse struct { Clusters int `json:"clusters"` Status string `json:"status"` AwsAccountId string `json:"awsAccountId"` + CreatedIAM bool `json:"createdIAM"` Creator SimpleUserResponse `json:"creator"` Updator SimpleUserResponse `json:"updator"` CreatedAt time.Time `json:"createdAt"` @@ -90,6 +94,7 @@ type SimpleCloudAccountResponse struct { Description string `json:"description"` CloudService string `json:"cloudService"` AwsAccountId string `json:"awsAccountId"` + CreatedIAM bool `json:"createdIAM"` Clusters int `json:"clusters"` } diff --git a/pkg/domain/cluster.go b/pkg/domain/cluster.go index 28446dc1..ada7a8cf 100644 --- a/pkg/domain/cluster.go +++ b/pkg/domain/cluster.go @@ -26,7 +26,8 @@ const ( ClusterStatus_RUNNING ClusterStatus_DELETING ClusterStatus_DELETED - ClusterStatus_ERROR + ClusterStatus_INSTALL_ERROR + ClusterStatus_DELETE_ERROR ) var clusterStatus = [...]string{ @@ -35,7 +36,8 @@ var clusterStatus = [...]string{ "RUNNING", "DELETING", "DELETED", - "ERROR", + "INSTALL_ERROR", + "DELETE_ERROR", } func (m ClusterStatus) String() string { return clusterStatus[(m)] } @@ -45,7 +47,7 @@ func (m ClusterStatus) FromString(s string) ClusterStatus { return ClusterStatus(i) } } - return ClusterStatus_ERROR + return ClusterStatus_PENDING } // model diff --git a/pkg/domain/stack.go b/pkg/domain/stack.go index 9e1b742c..121f5edb 100644 --- a/pkg/domain/stack.go +++ b/pkg/domain/stack.go @@ -25,28 +25,30 @@ const ( StackStatus_APPGROUP_INSTALLING StackStatus_APPGROUP_DELETING - StackStatus_APPGROUP_ERROR + StackStatus_APPGROUP_INSTALL_ERROR + StackStatus_APPGROUP_DELETE_ERROR StackStatus_CLUSTER_INSTALLING StackStatus_CLUSTER_DELETING StackStatus_CLUSTER_DELETED - StackStatus_CLUSTER_ERROR + StackStatus_CLUSTER_INSTALL_ERROR + StackStatus_CLUSTER_DELETE_ERROR StackStatus_RUNNING - StackStatus_ERROR ) var stackStatus = [...]string{ "PENDING", "APPGROUP_INSTALLING", "APPGROUP_DELETING", - "APPGROUP_ERROR", + "APPGROUP_INSTALL_ERROR", + "APPGROUP_DELETE_ERROR", "CLUSTER_INSTALLING", "CLUSTER_DELETING", "CLUSTER_DELETED", - "CLUSTER_ERROR", + "CLUSTER_INSTALL_ERROR", + "CLUSTER_DELETE_ERROR", "RUNNING", - "ERROR", } func (m StackStatus) String() string { return stackStatus[(m)] } @@ -56,7 +58,7 @@ func (m StackStatus) FromString(s string) StackStatus { return StackStatus(i) } } - return StackStatus_ERROR + return StackStatus_PENDING } const MAX_STEP_CLUSTER_CREATE = 13 From 50dd4bd2ef1526909c3cb4efe85fd0f1fea375b9 Mon Sep 17 00:00:00 2001 From: Taekyu Date: Wed, 21 Jun 2023 14:02:10 +0900 Subject: [PATCH 07/54] trivial. fix check logic for stack deleting --- internal/usecase/stack.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/internal/usecase/stack.go b/internal/usecase/stack.go index 491d83ea..a344eb2e 100644 --- a/internal/usecase/stack.go +++ b/internal/usecase/stack.go @@ -313,14 +313,12 @@ func (u *StackUsecase) Delete(ctx context.Context, dto domain.Stack) (err error) } } - appServeApps, err := u.appServeAppRepo.GetAppServeApps(dto.OrganizationId, true) + appsCnt, err := u.appServeAppRepo.GetNumOfAppsOnStack(dto.OrganizationId, dto.ID.String()) if err != nil { - return err + return errors.Wrap(err, "Failed to get numOfAppsOnStack") } - for _, app := range appServeApps { - if app.TargetClusterId == dto.ID.String() && app.Status != "ERROR" { - return httpErrors.NewBadRequestError(fmt.Errorf("existed appServeApps in %s", dto.OrganizationId), "S_FAILED_DELETE_EXISTED_ASA", "") - } + if appsCnt > 0 { + return httpErrors.NewBadRequestError(fmt.Errorf("existed appServeApps in %s", dto.OrganizationId), "S_FAILED_DELETE_EXISTED_ASA", "") } workflow := "" From 7d335772001cbd8c040849173369d6b0bbc6d84e Mon Sep 17 00:00:00 2001 From: Taekyu Date: Thu, 22 Jun 2023 10:28:53 +0900 Subject: [PATCH 08/54] trivial. minor fix. --- internal/usecase/cloud-account.go | 5 +++-- internal/usecase/cluster.go | 4 ++-- pkg/domain/cloud-account.go | 2 ++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/internal/usecase/cloud-account.go b/internal/usecase/cloud-account.go index b9548271..6f4f141b 100644 --- a/internal/usecase/cloud-account.go +++ b/internal/usecase/cloud-account.go @@ -69,7 +69,7 @@ func (u *CloudAccountUsecase) Create(ctx context.Context, dto domain.CloudAccoun log.InfoWithContext(ctx, "newly created CloudAccount ID:", cloudAccountId) // FOR TEST. ADD MAGIC KEYWORD - if strings.Contains(dto.Name, "INCLUSTER") { + if strings.Contains(dto.Name, domain.CLOUD_ACCOUNT_INCLUSTER) { if err := u.repo.InitWorkflow(cloudAccountId, "", domain.CloudAccountStatus_CREATED); err != nil { return uuid.Nil, errors.Wrap(err, "Failed to initialize status") } @@ -210,7 +210,8 @@ func (u *CloudAccountUsecase) DeleteForce(ctx context.Context, cloudAccountId uu return err } - if cloudAccount.Status != domain.CloudAccountStatus_CREATE_ERROR { + if !strings.Contains(cloudAccount.Name, domain.CLOUD_ACCOUNT_INCLUSTER) && + cloudAccount.Status != domain.CloudAccountStatus_CREATE_ERROR { return fmt.Errorf("The status is not CREATE_ERROR. %s", cloudAccount.Status) } diff --git a/internal/usecase/cluster.go b/internal/usecase/cluster.go index 75119f5a..8fc09539 100644 --- a/internal/usecase/cluster.go +++ b/internal/usecase/cluster.go @@ -133,7 +133,7 @@ func (u *ClusterUsecase) Create(ctx context.Context, dto domain.Cluster) (cluste if ca.ID == dto.CloudAccountId { // FOR TEST. ADD MAGIC KEYWORD - if strings.Contains(ca.Name, "INCLUSTER") { + if strings.Contains(ca.Name, domain.CLOUD_ACCOUNT_INCLUSTER) { tksCloudAccountId = "NULL" } isExist = true @@ -237,7 +237,7 @@ func (u *ClusterUsecase) Delete(ctx context.Context, clusterId domain.ClusterId) return httpErrors.NewInternalServerError(fmt.Errorf("Failed to get cloudAccount"), "", "") } tksCloudAccountId := cluster.CloudAccountId.String() - if strings.Contains(cloudAccount.Name, "INCLUSTER") { + if strings.Contains(cloudAccount.Name, domain.CLOUD_ACCOUNT_INCLUSTER) { tksCloudAccountId = "NULL" } diff --git a/pkg/domain/cloud-account.go b/pkg/domain/cloud-account.go index e13b8f6f..a27002a5 100644 --- a/pkg/domain/cloud-account.go +++ b/pkg/domain/cloud-account.go @@ -6,6 +6,8 @@ import ( "github.com/google/uuid" ) +const CLOUD_ACCOUNT_INCLUSTER = "INCLUSTER" + const ( CloudService_UNDEFINED = "UNDEFINED" CloudService_AWS = "AWS" From 3f7bc81607bf3ad6a9db90021346b0c144d15efa Mon Sep 17 00:00:00 2001 From: donggyu Date: Thu, 22 Jun 2023 11:14:36 +0900 Subject: [PATCH 09/54] minor fix: change default secret value to variable value for production --- internal/keycloak/keycloak.go | 12 ++++++------ internal/usecase/auth.go | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/internal/keycloak/keycloak.go b/internal/keycloak/keycloak.go index 6393e429..45976edb 100644 --- a/internal/keycloak/keycloak.go +++ b/internal/keycloak/keycloak.go @@ -58,7 +58,7 @@ func (k *Keycloak) LoginAdmin(accountId string, password string) (*domain.User, func (k *Keycloak) Login(accountId string, password string, organizationId string) (*domain.User, error) { ctx := context.Background() - JWTToken, err := k.client.Login(ctx, DefaultClientID, DefaultClientSecret, organizationId, accountId, password) + JWTToken, err := k.client.Login(ctx, DefaultClientID, k.config.ClientSecret, organizationId, accountId, password) if err != nil { log.Error(err) return nil, err @@ -109,7 +109,7 @@ func (k *Keycloak) InitializeKeycloak() error { var redirectURIs []string redirectURIs = append(redirectURIs, viper.GetString("external-address")+"/*") - tksClient, err := k.ensureClient(ctx, token, DefaultMasterRealm, DefaultClientID, DefaultClientSecret, &redirectURIs) + tksClient, err := k.ensureClient(ctx, token, DefaultMasterRealm, DefaultClientID, k.config.ClientSecret, &redirectURIs) if err != nil { log.Fatal(err) return err @@ -122,7 +122,7 @@ func (k *Keycloak) InitializeKeycloak() error { } } - adminCliClient, err := k.ensureClient(ctx, token, DefaultMasterRealm, AdminCliClientID, DefaultClientSecret, nil) + adminCliClient, err := k.ensureClient(ctx, token, DefaultMasterRealm, AdminCliClientID, k.config.ClientSecret, nil) if err != nil { log.Fatal(err) return err @@ -139,7 +139,7 @@ func (k *Keycloak) InitializeKeycloak() error { _ = getRefreshTokenExpiredDuration(k.adminCliToken) go func() { for { - if token, err := k.client.RefreshToken(context.Background(), k.adminCliToken.RefreshToken, AdminCliClientID, DefaultClientSecret, DefaultMasterRealm); err != nil { + if token, err := k.client.RefreshToken(context.Background(), k.adminCliToken.RefreshToken, AdminCliClientID, k.config.ClientSecret, DefaultMasterRealm); err != nil { log.Errorf("[Refresh]error is :%s(%T)", err.Error(), err) log.Info("[Do Keycloak Admin CLI Login]") k.adminCliToken, err = k.client.LoginAdmin(ctx, k.config.AdminId, k.config.AdminPassword, DefaultMasterRealm) @@ -168,7 +168,7 @@ func (k *Keycloak) CreateRealm(organizationId string) (string, error) { var redirectURIs []string redirectURIs = append(redirectURIs, viper.GetString("external-address")+"/*") - clientUUID, err := k.createDefaultClient(context.Background(), token.AccessToken, organizationId, DefaultClientID, DefaultClientSecret, &redirectURIs) + clientUUID, err := k.createDefaultClient(context.Background(), token.AccessToken, organizationId, DefaultClientID, k.config.ClientSecret, &redirectURIs) if err != nil { log.Error(err, "createDefaultClient") return "", err @@ -366,7 +366,7 @@ func (k *Keycloak) DeleteUser(organizationId string, userAccountId string) error func (k *Keycloak) VerifyAccessToken(token string, organizationId string) error { ctx := context.Background() - rptResult, err := k.client.RetrospectToken(ctx, token, DefaultClientID, DefaultClientSecret, organizationId) + rptResult, err := k.client.RetrospectToken(ctx, token, DefaultClientID, k.config.ClientSecret, organizationId) if err != nil { return err } diff --git a/internal/usecase/auth.go b/internal/usecase/auth.go index 81e999a1..94438339 100644 --- a/internal/usecase/auth.go +++ b/internal/usecase/auth.go @@ -349,7 +349,7 @@ func makingCookie(organizationId, userName, password string) ([]*http.Cookie, er baseUrl := viper.GetString("keycloak-address") + "/realms/" + organizationId + "/protocol/openid-connect" var oauth2Config = &oauth2.Config{ ClientID: keycloak.DefaultClientID, - ClientSecret: keycloak.DefaultClientSecret, + ClientSecret: viper.GetString("keycloak-client-secret"), RedirectURL: viper.GetString("external-address") + internal.API_PREFIX + internal.API_VERSION + "/auth/callback", Scopes: []string{"openid"}, Endpoint: oauth2.Endpoint{ From a24fae1856a1dfb76060b455dcbabf8a33131806 Mon Sep 17 00:00:00 2001 From: Taekyu Date: Thu, 22 Jun 2023 11:36:12 +0900 Subject: [PATCH 10/54] bugfix. add condition awsAccountId on cloud account creation --- internal/repository/cloud-account.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/repository/cloud-account.go b/internal/repository/cloud-account.go index e42115f0..51960663 100644 --- a/internal/repository/cloud-account.go +++ b/internal/repository/cloud-account.go @@ -83,7 +83,7 @@ func (r *CloudAccountRepository) GetByName(organizationId string, name string) ( func (r *CloudAccountRepository) GetByAwsAccountId(awsAccountId string) (out domain.CloudAccount, err error) { var cloudAccount CloudAccount - res := r.db.Preload(clause.Associations).First(&cloudAccount, "aws_account_id = ?", awsAccountId) + res := r.db.Preload(clause.Associations).First(&cloudAccount, "aws_account_id = ? AND status != ?", awsAccountId, domain.CloudAccountStatus_DELETED) if res.Error != nil { return domain.CloudAccount{}, res.Error From 69bda8ab76e514f34314616f62484edf6c043830 Mon Sep 17 00:00:00 2001 From: Taekyu Date: Thu, 22 Jun 2023 13:47:33 +0900 Subject: [PATCH 11/54] trivial. logging every error response for management --- internal/delivery/http/handler.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/delivery/http/handler.go b/internal/delivery/http/handler.go index 1b39901d..46cdf4db 100644 --- a/internal/delivery/http/handler.go +++ b/internal/delivery/http/handler.go @@ -28,11 +28,12 @@ func init() { } func ErrorJSON(w http.ResponseWriter, r *http.Request, err error) { + log.ErrorfWithContext(r.Context(), "error is :%s(%T)", err.Error(), err) errorResponse, status := httpErrors.ErrorResponse(err) ResponseJSON(w, r, status, errorResponse) } -const MAX_LOG_LEN = 500 +const MAX_LOG_LEN = 1000 func ResponseJSON(w http.ResponseWriter, r *http.Request, httpStatus int, data interface{}) { out := data From 56157b8f5c8aa91ddb09258cc2ab005b945a66d4 Mon Sep 17 00:00:00 2001 From: Robert Choi Date: Fri, 23 Jun 2023 09:59:22 +0900 Subject: [PATCH 12/54] bugfix: app-serving: change action button order --- internal/delivery/http/app-serve-app.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/delivery/http/app-serve-app.go b/internal/delivery/http/app-serve-app.go index fb513661..1f4c9118 100644 --- a/internal/delivery/http/app-serve-app.go +++ b/internal/delivery/http/app-serve-app.go @@ -421,22 +421,22 @@ func makeStage(app *domain.AppServeApp, pl string) domain.StageResponse { } else if stage.Status == "PROMOTE_WAIT" && strategy == "blue-green" { action := domain.ActionResponse{ - Name: "PROMOTE", + Name: "ABORT", Uri: fmt.Sprintf(internal.API_PREFIX+internal.API_VERSION+ "/organizations/%v/app-serve-apps/%v", app.OrganizationId, app.ID), Type: "API", Method: "PUT", - Body: map[string]string{"strategy": "blue-green", "promote": "true"}, + Body: map[string]string{"strategy": "blue-green", "abort": "true"}, } actions = append(actions, action) action = domain.ActionResponse{ - Name: "ABORT", + Name: "PROMOTE", Uri: fmt.Sprintf(internal.API_PREFIX+internal.API_VERSION+ "/organizations/%v/app-serve-apps/%v", app.OrganizationId, app.ID), Type: "API", Method: "PUT", - Body: map[string]string{"strategy": "blue-green", "abort": "true"}, + Body: map[string]string{"strategy": "blue-green", "promote": "true"}, } actions = append(actions, action) } From f3b3d6b0d87c4188e52f2277275ca1fbefe3644b Mon Sep 17 00:00:00 2001 From: Robert Choi Date: Fri, 23 Jun 2023 15:51:09 +0900 Subject: [PATCH 13/54] bugfix: app-serving: update initial status on delete tks-issues-728 --- internal/usecase/app-serve-app.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/internal/usecase/app-serve-app.go b/internal/usecase/app-serve-app.go index 746d2d9b..1a2bc463 100644 --- a/internal/usecase/app-serve-app.go +++ b/internal/usecase/app-serve-app.go @@ -277,6 +277,15 @@ func (u *AppServeAppUsecase) DeleteAppServeApp(appId string) (res string, err er return "", errors.Wrap(err, "Failed to create delete task.") } + log.Info("Updating app status to 'DELETING'..") + + err = u.repo.UpdateStatus(appId, taskId, "DELETING", "") + if err != nil { + log.Debug("appId = ", appId) + log.Debug("taskId = ", taskId) + return "", fmt.Errorf("failed to update app status on DeleteAppServeApp. Err: %s", err) + } + workflow := "delete-java-app" log.Info("Submitting workflow: ", workflow) From cb87f4988ddb61728b7d12bf887976d0ac22ab0a Mon Sep 17 00:00:00 2001 From: Robert Choi Date: Mon, 26 Jun 2023 11:15:50 +0900 Subject: [PATCH 14/54] app-serving: update swagger spec --- internal/delivery/http/app-serve-app.go | 46 ++++++++++++++++--------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/internal/delivery/http/app-serve-app.go b/internal/delivery/http/app-serve-app.go index 1f4c9118..493c2db9 100644 --- a/internal/delivery/http/app-serve-app.go +++ b/internal/delivery/http/app-serve-app.go @@ -79,7 +79,8 @@ func NewAppServeAppHandler(h usecase.IAppServeAppUsecase) *AppServeAppHandler { // @Description Install appServeApp // @Accept json // @Produce json -// @Param object body domain.CreateAppServeAppRequest true "create appserve request" +// @Param organizationId path string true "Organization ID" +// @Param object body domain.CreateAppServeAppRequest true "Request body to create app" // @Success 200 {object} string // @Router /organizations/{organizationId}/app-serve-apps [post] // @Security JWT @@ -163,8 +164,8 @@ func (h *AppServeAppHandler) CreateAppServeApp(w http.ResponseWriter, r *http.Re // @Description Get appServeApp list by giving params // @Accept json // @Produce json -// @Param organization_Id query string false "organization_Id" -// @Param showAll query string false "show_all" +// @Param organizationId path string true "Organization ID" +// @Param showAll query boolean false "Show all apps including deleted apps" // @Success 200 {object} []domain.AppServeApp // @Router /organizations/{organizationId}/app-serve-apps [get] // @Security JWT @@ -210,6 +211,8 @@ func (h *AppServeAppHandler) GetAppServeApps(w http.ResponseWriter, r *http.Requ // @Description Get appServeApp by giving params // @Accept json // @Produce json +// @Param organizationId path string true "Organization ID" +// @Param appId path string true "App ID" // @Success 200 {object} domain.GetAppServeAppResponse // @Router /organizations/{organizationId}/app-serve-apps/{appId} [get] // @Security JWT @@ -264,6 +267,8 @@ func (h *AppServeAppHandler) GetAppServeApp(w http.ResponseWriter, r *http.Reque // @Description Get latest task from appServeApp // @Accept json // @Produce json +// @Param organizationId path string true "Organization ID" +// @Param appId path string true "App ID" // @Success 200 {object} domain.GetAppServeAppTaskResponse // @Router /organizations/{organizationId}/app-serve-apps/{appId}/latest-task [get] // @Security JWT @@ -305,6 +310,8 @@ func (h *AppServeAppHandler) GetAppServeAppLatestTask(w http.ResponseWriter, r * // @Description Get number of apps on given stack // @Accept json // @Produce json +// @Param organizationId path string true "Organization ID" +// @Param stackId query string true "Stack ID" // @Success 200 {object} int64 // @Router /organizations/{organizationId}/app-serve-apps/count [get] // @Security JWT @@ -453,7 +460,7 @@ func makeStage(app *domain.AppServeApp, pl string) domain.StageResponse { // @Accept json // @Produce json // @Success 200 {object} bool -// @Router /organizations/{organizationId}/app-serve-apps/app-id/exist [get] +// @Router /organizations/{organizationId}/app-serve-apps/{appId}/exist [get] // @Security JWT func (h *AppServeAppHandler) IsAppServeAppExist(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) @@ -491,7 +498,7 @@ func (h *AppServeAppHandler) IsAppServeAppExist(w http.ResponseWriter, r *http.R // @Description Check duplicate appServeAppName by giving params // @Accept json // @Produce json -// @Param organizationId path string true "organizationId" +// @Param organizationId path string true "Organization ID" // @Param name path string true "name" // @Success 200 {object} bool // @Router /organizations/{organizationId}/app-serve-apps/name/{name}/existence [get] @@ -530,8 +537,10 @@ func (h *AppServeAppHandler) IsAppServeAppNameExist(w http.ResponseWriter, r *ht // @Description Update appServeApp // @Accept json // @Produce json -// @Param object body domain.UpdateAppServeAppRequest true "update appserve request" -// @Success 200 {object} object +// @Param organizationId path string true "Organization ID" +// @Param appId path string true "App ID" +// @Param object body domain.UpdateAppServeAppRequest true "Request body to update app" +// @Success 200 {object} string // @Router /organizations/{organizationId}/app-serve-apps/{appId} [put] // @Security JWT func (h *AppServeAppHandler) UpdateAppServeApp(w http.ResponseWriter, r *http.Request) { @@ -637,9 +646,10 @@ func (h *AppServeAppHandler) UpdateAppServeApp(w http.ResponseWriter, r *http.Re // @Description Update app status // @Accept json // @Produce json -// @Param appId path string true "appId" -// @Param body body domain.UpdateAppServeAppStatusRequest true "update app status request" -// @Success 200 {object} object +// @Param organizationId path string true "Organization ID" +// @Param appId path string true "App ID" +// @Param body body domain.UpdateAppServeAppStatusRequest true "Request body to update app status" +// @Success 200 {object} string // @Router /organizations/{organizationId}/app-serve-apps/{appId}/status [patch] // @Security JWT func (h *AppServeAppHandler) UpdateAppServeAppStatus(w http.ResponseWriter, r *http.Request) { @@ -679,9 +689,10 @@ func (h *AppServeAppHandler) UpdateAppServeAppStatus(w http.ResponseWriter, r *h // @Description Update app endpoint // @Accept json // @Produce json +// @Param organizationId path string true "Organization ID" // @Param appId path string true "appId" -// @Param body body domain.UpdateAppServeAppEndpointRequest true "update app endpoint request" -// @Success 200 {object} object +// @Param body body domain.UpdateAppServeAppEndpointRequest true "Request body to update app endpoint" +// @Success 200 {object} string // @Router /organizations/{organizationId}/app-serve-apps/{appId}/endpoint [patch] // @Security JWT func (h *AppServeAppHandler) UpdateAppServeAppEndpoint(w http.ResponseWriter, r *http.Request) { @@ -726,8 +737,9 @@ func (h *AppServeAppHandler) UpdateAppServeAppEndpoint(w http.ResponseWriter, r // @Description Uninstall appServeApp // @Accept json // @Produce json -// @Param object body string true "body" -// @Success 200 {object} object +// @Param organizationId path string true "Organization ID" +// @Param appId path string true "App ID" +// @Success 200 {object} string // @Router /organizations/{organizationId}/app-serve-apps/{appId} [delete] // @Security JWT func (h *AppServeAppHandler) DeleteAppServeApp(w http.ResponseWriter, r *http.Request) { @@ -761,8 +773,10 @@ func (h *AppServeAppHandler) DeleteAppServeApp(w http.ResponseWriter, r *http.Re // @Description Rollback appServeApp // @Accept json // @Produce json -// @Param object body domain.RollbackAppServeAppRequest true "rollback appserve request" -// @Success 200 {object} object +// @Param organizationId path string true "Organization ID" +// @Param appId path string true "App ID" +// @Param object body domain.RollbackAppServeAppRequest true "Request body to rollback app" +// @Success 200 {object} string // @Router /organizations/{organizationId}/app-serve-apps/{appId}/rollback [post] // @Security JWT func (h *AppServeAppHandler) RollbackAppServeApp(w http.ResponseWriter, r *http.Request) { From 7f0b18d3f423438a0f0bf2c082f4ecc69cdadd09 Mon Sep 17 00:00:00 2001 From: Robert Choi Date: Mon, 26 Jun 2023 11:29:07 +0900 Subject: [PATCH 15/54] app-serving: add validation for stackId param --- internal/delivery/http/app-serve-app.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/delivery/http/app-serve-app.go b/internal/delivery/http/app-serve-app.go index 493c2db9..39656c0d 100644 --- a/internal/delivery/http/app-serve-app.go +++ b/internal/delivery/http/app-serve-app.go @@ -327,6 +327,9 @@ func (h *AppServeAppHandler) GetNumOfAppsOnStack(w http.ResponseWriter, r *http. urlParams := r.URL.Query() stackId := urlParams.Get("stackId") + if stackId == "" { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("StackId must be provided."), "", "")) + } fmt.Printf("stackId = [%s]\n", stackId) numApps, err := h.usecase.GetNumOfAppsOnStack(organizationId, stackId) From c1168cee318e7c595f3d6d88ba4e6477a5802c17 Mon Sep 17 00:00:00 2001 From: Taekyu Date: Mon, 26 Jun 2023 14:35:11 +0900 Subject: [PATCH 16/54] feature. fix github action for gitflow --- .github/workflows/build-and-push.yml | 4 ++++ .github/workflows/build.yml | 3 ++- .github/workflows/lint.yml | 6 +++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-and-push.yml b/.github/workflows/build-and-push.yml index ee74c6a7..f943a8d4 100644 --- a/.github/workflows/build-and-push.yml +++ b/.github/workflows/build-and-push.yml @@ -4,6 +4,9 @@ on: branches: - main - develop + - release + workflow_dispatch: + env: SERVICE: tks-api TAG: ${{github.sha}} @@ -44,6 +47,7 @@ jobs: if [[ ${{github.ref}} == *"develop"* ]]; then ( cd cicd-manifests/${SERVICE}/overlay/development && kustomize edit set image docker.io/sktcloud/${SERVICE}:${TAG} && git add kustomization.yaml ) + elif [[ ${{github.ref}} == *"release"* ]]; then ( cd cicd-manifests/${SERVICE}/overlay/ft && kustomize edit set image docker.io/sktcloud/${SERVICE}:${TAG} && git add kustomization.yaml ) elif [[ ${{github.ref}} == *"main"* ]]; then ( cd cicd-manifests/${SERVICE}/overlay/cicd && kustomize edit set image docker.io/sktcloud/${SERVICE}:${TAG} && git add kustomization.yaml ) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 858deeff..e8644715 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,9 +1,10 @@ -name: Build image +name: Build Image on: pull_request_target: branches: - main - develop + - release env: SERVICE: tks-api diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index deccaf17..5df838e9 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,4 +1,4 @@ -name: golangci-lint +name: Lint on: push: tags: @@ -6,12 +6,12 @@ on: branches: - main - develop - - "release**" + - release pull_request: branches: - main - develop - - "release**" + - release jobs: golangci: name: lint From 9903a63ace479eeb7ae966c5251e4aa9738824e6 Mon Sep 17 00:00:00 2001 From: Taekyu Date: Mon, 26 Jun 2023 14:36:25 +0900 Subject: [PATCH 17/54] trivial. build swagger docs --- api/swagger/docs.go | 207 +++++++++++++++++++++++++++++---------- api/swagger/swagger.json | 207 +++++++++++++++++++++++++++++---------- api/swagger/swagger.yaml | 151 ++++++++++++++++++++-------- 3 files changed, 422 insertions(+), 143 deletions(-) diff --git a/api/swagger/docs.go b/api/swagger/docs.go index c7739f2b..b9d06719 100644 --- a/api/swagger/docs.go +++ b/api/swagger/docs.go @@ -1046,13 +1046,14 @@ const docTemplate = `{ "parameters": [ { "type": "string", - "description": "organization_Id", - "name": "organization_Id", - "in": "query" + "description": "Organization ID", + "name": "organizationId", + "in": "path", + "required": true }, { - "type": "string", - "description": "show_all", + "type": "boolean", + "description": "Show all apps including deleted apps", "name": "showAll", "in": "query" } @@ -1088,7 +1089,14 @@ const docTemplate = `{ "summary": "Install appServeApp", "parameters": [ { - "description": "create appserve request", + "type": "string", + "description": "Organization ID", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "description": "Request body to create app", "name": "object", "in": "body", "required": true, @@ -1107,34 +1115,6 @@ const docTemplate = `{ } } }, - "/organizations/{organizationId}/app-serve-apps/app-id/exist": { - "get": { - "security": [ - { - "JWT": [] - } - ], - "description": "Get appServeApp by giving params", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "AppServeApps" - ], - "summary": "Get appServeApp", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "boolean" - } - } - } - } - }, "/organizations/{organizationId}/app-serve-apps/count": { "get": { "security": [ @@ -1153,6 +1133,22 @@ const docTemplate = `{ "AppServeApps" ], "summary": "Get number of apps on given stack", + "parameters": [ + { + "type": "string", + "description": "Organization ID", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Stack ID", + "name": "stackId", + "in": "query", + "required": true + } + ], "responses": { "200": { "description": "OK", @@ -1184,7 +1180,7 @@ const docTemplate = `{ "parameters": [ { "type": "string", - "description": "organizationId", + "description": "Organization ID", "name": "organizationId", "in": "path", "required": true @@ -1225,6 +1221,22 @@ const docTemplate = `{ "AppServeApps" ], "summary": "Get appServeApp", + "parameters": [ + { + "type": "string", + "description": "Organization ID", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "App ID", + "name": "appId", + "in": "path", + "required": true + } + ], "responses": { "200": { "description": "OK", @@ -1253,7 +1265,21 @@ const docTemplate = `{ "summary": "Update appServeApp", "parameters": [ { - "description": "update appserve request", + "type": "string", + "description": "Organization ID", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "App ID", + "name": "appId", + "in": "path", + "required": true + }, + { + "description": "Request body to update app", "name": "object", "in": "body", "required": true, @@ -1266,7 +1292,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object" + "type": "string" } } } @@ -1290,20 +1316,25 @@ const docTemplate = `{ "summary": "Uninstall appServeApp", "parameters": [ { - "description": "body", - "name": "object", - "in": "body", - "required": true, - "schema": { - "type": "string" - } + "type": "string", + "description": "Organization ID", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "App ID", + "name": "appId", + "in": "path", + "required": true } ], "responses": { "200": { "description": "OK", "schema": { - "type": "object" + "type": "string" } } } @@ -1328,6 +1359,13 @@ const docTemplate = `{ ], "summary": "Update app endpoint", "parameters": [ + { + "type": "string", + "description": "Organization ID", + "name": "organizationId", + "in": "path", + "required": true + }, { "type": "string", "description": "appId", @@ -1336,7 +1374,7 @@ const docTemplate = `{ "required": true }, { - "description": "update app endpoint request", + "description": "Request body to update app endpoint", "name": "body", "in": "body", "required": true, @@ -1349,7 +1387,35 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object" + "type": "string" + } + } + } + } + }, + "/organizations/{organizationId}/app-serve-apps/{appId}/exist": { + "get": { + "security": [ + { + "JWT": [] + } + ], + "description": "Get appServeApp by giving params", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AppServeApps" + ], + "summary": "Get appServeApp", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "boolean" } } } @@ -1373,6 +1439,22 @@ const docTemplate = `{ "AppServeApps" ], "summary": "Get latest task from appServeApp", + "parameters": [ + { + "type": "string", + "description": "Organization ID", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "App ID", + "name": "appId", + "in": "path", + "required": true + } + ], "responses": { "200": { "description": "OK", @@ -1403,7 +1485,21 @@ const docTemplate = `{ "summary": "Rollback appServeApp", "parameters": [ { - "description": "rollback appserve request", + "type": "string", + "description": "Organization ID", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "App ID", + "name": "appId", + "in": "path", + "required": true + }, + { + "description": "Request body to rollback app", "name": "object", "in": "body", "required": true, @@ -1416,7 +1512,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object" + "type": "string" } } } @@ -1443,13 +1539,20 @@ const docTemplate = `{ "parameters": [ { "type": "string", - "description": "appId", + "description": "Organization ID", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "App ID", "name": "appId", "in": "path", "required": true }, { - "description": "update app status request", + "description": "Request body to update app status", "name": "body", "in": "body", "required": true, @@ -1462,7 +1565,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "object" + "type": "string" } } } diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index 8134fa75..a79499dd 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -1039,13 +1039,14 @@ "parameters": [ { "type": "string", - "description": "organization_Id", - "name": "organization_Id", - "in": "query" + "description": "Organization ID", + "name": "organizationId", + "in": "path", + "required": true }, { - "type": "string", - "description": "show_all", + "type": "boolean", + "description": "Show all apps including deleted apps", "name": "showAll", "in": "query" } @@ -1081,7 +1082,14 @@ "summary": "Install appServeApp", "parameters": [ { - "description": "create appserve request", + "type": "string", + "description": "Organization ID", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "description": "Request body to create app", "name": "object", "in": "body", "required": true, @@ -1100,34 +1108,6 @@ } } }, - "/organizations/{organizationId}/app-serve-apps/app-id/exist": { - "get": { - "security": [ - { - "JWT": [] - } - ], - "description": "Get appServeApp by giving params", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "AppServeApps" - ], - "summary": "Get appServeApp", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "boolean" - } - } - } - } - }, "/organizations/{organizationId}/app-serve-apps/count": { "get": { "security": [ @@ -1146,6 +1126,22 @@ "AppServeApps" ], "summary": "Get number of apps on given stack", + "parameters": [ + { + "type": "string", + "description": "Organization ID", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Stack ID", + "name": "stackId", + "in": "query", + "required": true + } + ], "responses": { "200": { "description": "OK", @@ -1177,7 +1173,7 @@ "parameters": [ { "type": "string", - "description": "organizationId", + "description": "Organization ID", "name": "organizationId", "in": "path", "required": true @@ -1218,6 +1214,22 @@ "AppServeApps" ], "summary": "Get appServeApp", + "parameters": [ + { + "type": "string", + "description": "Organization ID", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "App ID", + "name": "appId", + "in": "path", + "required": true + } + ], "responses": { "200": { "description": "OK", @@ -1246,7 +1258,21 @@ "summary": "Update appServeApp", "parameters": [ { - "description": "update appserve request", + "type": "string", + "description": "Organization ID", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "App ID", + "name": "appId", + "in": "path", + "required": true + }, + { + "description": "Request body to update app", "name": "object", "in": "body", "required": true, @@ -1259,7 +1285,7 @@ "200": { "description": "OK", "schema": { - "type": "object" + "type": "string" } } } @@ -1283,20 +1309,25 @@ "summary": "Uninstall appServeApp", "parameters": [ { - "description": "body", - "name": "object", - "in": "body", - "required": true, - "schema": { - "type": "string" - } + "type": "string", + "description": "Organization ID", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "App ID", + "name": "appId", + "in": "path", + "required": true } ], "responses": { "200": { "description": "OK", "schema": { - "type": "object" + "type": "string" } } } @@ -1321,6 +1352,13 @@ ], "summary": "Update app endpoint", "parameters": [ + { + "type": "string", + "description": "Organization ID", + "name": "organizationId", + "in": "path", + "required": true + }, { "type": "string", "description": "appId", @@ -1329,7 +1367,7 @@ "required": true }, { - "description": "update app endpoint request", + "description": "Request body to update app endpoint", "name": "body", "in": "body", "required": true, @@ -1342,7 +1380,35 @@ "200": { "description": "OK", "schema": { - "type": "object" + "type": "string" + } + } + } + } + }, + "/organizations/{organizationId}/app-serve-apps/{appId}/exist": { + "get": { + "security": [ + { + "JWT": [] + } + ], + "description": "Get appServeApp by giving params", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AppServeApps" + ], + "summary": "Get appServeApp", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "boolean" } } } @@ -1366,6 +1432,22 @@ "AppServeApps" ], "summary": "Get latest task from appServeApp", + "parameters": [ + { + "type": "string", + "description": "Organization ID", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "App ID", + "name": "appId", + "in": "path", + "required": true + } + ], "responses": { "200": { "description": "OK", @@ -1396,7 +1478,21 @@ "summary": "Rollback appServeApp", "parameters": [ { - "description": "rollback appserve request", + "type": "string", + "description": "Organization ID", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "App ID", + "name": "appId", + "in": "path", + "required": true + }, + { + "description": "Request body to rollback app", "name": "object", "in": "body", "required": true, @@ -1409,7 +1505,7 @@ "200": { "description": "OK", "schema": { - "type": "object" + "type": "string" } } } @@ -1436,13 +1532,20 @@ "parameters": [ { "type": "string", - "description": "appId", + "description": "Organization ID", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "App ID", "name": "appId", "in": "path", "required": true }, { - "description": "update app status request", + "description": "Request body to update app status", "name": "body", "in": "body", "required": true, @@ -1455,7 +1558,7 @@ "200": { "description": "OK", "schema": { - "type": "object" + "type": "string" } } } diff --git a/api/swagger/swagger.yaml b/api/swagger/swagger.yaml index 3e8a57de..e93bbd50 100644 --- a/api/swagger/swagger.yaml +++ b/api/swagger/swagger.yaml @@ -2362,14 +2362,15 @@ paths: - application/json description: Get appServeApp list by giving params parameters: - - description: organization_Id - in: query - name: organization_Id + - description: Organization ID + in: path + name: organizationId + required: true type: string - - description: show_all + - description: Show all apps including deleted apps in: query name: showAll - type: string + type: boolean produces: - application/json responses: @@ -2389,7 +2390,12 @@ paths: - application/json description: Install appServeApp parameters: - - description: create appserve request + - description: Organization ID + in: path + name: organizationId + required: true + type: string + - description: Request body to create app in: body name: object required: true @@ -2413,19 +2419,23 @@ paths: - application/json description: Uninstall appServeApp parameters: - - description: body - in: body - name: object + - description: Organization ID + in: path + name: organizationId required: true - schema: - type: string + type: string + - description: App ID + in: path + name: appId + required: true + type: string produces: - application/json responses: "200": description: OK schema: - type: object + type: string security: - JWT: [] summary: Uninstall appServeApp @@ -2435,6 +2445,17 @@ paths: consumes: - application/json description: Get appServeApp by giving params + parameters: + - description: Organization ID + in: path + name: organizationId + required: true + type: string + - description: App ID + in: path + name: appId + required: true + type: string produces: - application/json responses: @@ -2452,7 +2473,17 @@ paths: - application/json description: Update appServeApp parameters: - - description: update appserve request + - description: Organization ID + in: path + name: organizationId + required: true + type: string + - description: App ID + in: path + name: appId + required: true + type: string + - description: Request body to update app in: body name: object required: true @@ -2464,7 +2495,7 @@ paths: "200": description: OK schema: - type: object + type: string security: - JWT: [] summary: Update appServeApp @@ -2476,12 +2507,17 @@ paths: - application/json description: Update app endpoint parameters: + - description: Organization ID + in: path + name: organizationId + required: true + type: string - description: appId in: path name: appId required: true type: string - - description: update app endpoint request + - description: Request body to update app endpoint in: body name: body required: true @@ -2493,17 +2529,45 @@ paths: "200": description: OK schema: - type: object + type: string security: - JWT: [] summary: Update app endpoint tags: - AppServeApps + /organizations/{organizationId}/app-serve-apps/{appId}/exist: + get: + consumes: + - application/json + description: Get appServeApp by giving params + produces: + - application/json + responses: + "200": + description: OK + schema: + type: boolean + security: + - JWT: [] + summary: Get appServeApp + tags: + - AppServeApps /organizations/{organizationId}/app-serve-apps/{appId}/latest-task: get: consumes: - application/json description: Get latest task from appServeApp + parameters: + - description: Organization ID + in: path + name: organizationId + required: true + type: string + - description: App ID + in: path + name: appId + required: true + type: string produces: - application/json responses: @@ -2522,7 +2586,17 @@ paths: - application/json description: Rollback appServeApp parameters: - - description: rollback appserve request + - description: Organization ID + in: path + name: organizationId + required: true + type: string + - description: App ID + in: path + name: appId + required: true + type: string + - description: Request body to rollback app in: body name: object required: true @@ -2534,7 +2608,7 @@ paths: "200": description: OK schema: - type: object + type: string security: - JWT: [] summary: Rollback appServeApp @@ -2546,12 +2620,17 @@ paths: - application/json description: Update app status parameters: - - description: appId + - description: Organization ID + in: path + name: organizationId + required: true + type: string + - description: App ID in: path name: appId required: true type: string - - description: update app status request + - description: Request body to update app status in: body name: body required: true @@ -2563,34 +2642,28 @@ paths: "200": description: OK schema: - type: object + type: string security: - JWT: [] summary: Update app status tags: - AppServeApps - /organizations/{organizationId}/app-serve-apps/app-id/exist: - get: - consumes: - - application/json - description: Get appServeApp by giving params - produces: - - application/json - responses: - "200": - description: OK - schema: - type: boolean - security: - - JWT: [] - summary: Get appServeApp - tags: - - AppServeApps /organizations/{organizationId}/app-serve-apps/count: get: consumes: - application/json description: Get number of apps on given stack + parameters: + - description: Organization ID + in: path + name: organizationId + required: true + type: string + - description: Stack ID + in: query + name: stackId + required: true + type: string produces: - application/json responses: @@ -2609,7 +2682,7 @@ paths: - application/json description: Check duplicate appServeAppName by giving params parameters: - - description: organizationId + - description: Organization ID in: path name: organizationId required: true From 2ce85072e68afa18edcc60c402338821b4f37a3f Mon Sep 17 00:00:00 2001 From: Taekyu Date: Thu, 29 Jun 2023 18:23:09 +0900 Subject: [PATCH 18/54] trivial. increase max stage to 39 on creating lma. --- pkg/domain/stack.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/domain/stack.go b/pkg/domain/stack.go index 121f5edb..f881bb4b 100644 --- a/pkg/domain/stack.go +++ b/pkg/domain/stack.go @@ -63,7 +63,7 @@ func (m StackStatus) FromString(s string) StackStatus { const MAX_STEP_CLUSTER_CREATE = 13 const MAX_STEP_CLUSTER_REMOVE = 11 -const MAX_STEP_LMA_CREATE_PRIMARY = 36 +const MAX_STEP_LMA_CREATE_PRIMARY = 39 const MAX_STEP_LMA_CREATE_MEMBER = 27 const MAX_STEP_LMA_REMOVE = 11 const MAX_STEP_SM_CREATE = 22 From 561d57f088c874f60efbed55d4ab6b985cf13aa1 Mon Sep 17 00:00:00 2001 From: Taekyu Date: Thu, 6 Jul 2023 10:15:22 +0900 Subject: [PATCH 19/54] feature. add "revision" to workflow parameter . --- internal/usecase/organization.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/usecase/organization.go b/internal/usecase/organization.go index d84197c8..9cb6323b 100644 --- a/internal/usecase/organization.go +++ b/internal/usecase/organization.go @@ -64,6 +64,7 @@ func (u *OrganizationUsecase) Create(ctx context.Context, in *domain.Organizatio argowf.SubmitOptions{ Parameters: []string{ "contract_id=" + organizationId, + "revision=" + viper.GetString("revision"), "keycloak_url=" + strings.TrimSuffix(viper.GetString("keycloak-address"), "/auth"), }, }) From 9bb6bf571d02f5a952b6882865ec855bb4e94384 Mon Sep 17 00:00:00 2001 From: Taekyu Date: Thu, 6 Jul 2023 11:23:32 +0900 Subject: [PATCH 20/54] trivial. add workflow parameter "revision" to tks-create-usercluster. --- internal/usecase/cluster.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/usecase/cluster.go b/internal/usecase/cluster.go index 8fc09539..e6a1086e 100644 --- a/internal/usecase/cluster.go +++ b/internal/usecase/cluster.go @@ -184,6 +184,7 @@ func (u *ClusterUsecase) Create(ctx context.Context, dto domain.Cluster) (cluste "git_account=" + viper.GetString("git-account"), "creator=" + user.GetUserId().String(), "cloud_account_id=" + tksCloudAccountId, + "revision=" + viper.GetString("revision"), //"manifest_repo_url=" + viper.GetString("git-base-url") + "/" + viper.GetString("git-account") + "/" + clusterId + "-manifests", }, }) From 60b52ad15137fbf8b7583faf0a09ef38f0266f5f Mon Sep 17 00:00:00 2001 From: Taekyu Date: Thu, 6 Jul 2023 11:23:32 +0900 Subject: [PATCH 21/54] trivial. add workflow parameter "revision" to tks-create-usercluster. --- internal/usecase/app-group.go | 2 +- internal/usecase/cluster.go | 1 + internal/usecase/organization.go | 2 +- internal/usecase/stack.go | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/internal/usecase/app-group.go b/internal/usecase/app-group.go index 1aa528ef..5995aa81 100644 --- a/internal/usecase/app-group.go +++ b/internal/usecase/app-group.go @@ -92,7 +92,7 @@ func (u *AppGroupUsecase) Create(ctx context.Context, dto domain.AppGroup) (id d "cluster_id=" + dto.ClusterId.String(), "github_account=" + viper.GetString("git-account"), "manifest_repo_url=" + viper.GetString("git-base-url") + "/" + viper.GetString("git-account") + "/" + dto.ClusterId.String() + "-manifests", - "revision=" + viper.GetString("revision"), + "base_repo_branch=" + viper.GetString("revision"), "app_group_id=" + dto.ID.String(), "keycloak_url=" + strings.TrimSuffix(viper.GetString("keycloak-address"), "/auth"), "console_url=" + viper.GetString("console-address"), diff --git a/internal/usecase/cluster.go b/internal/usecase/cluster.go index 8fc09539..237c22fd 100644 --- a/internal/usecase/cluster.go +++ b/internal/usecase/cluster.go @@ -184,6 +184,7 @@ func (u *ClusterUsecase) Create(ctx context.Context, dto domain.Cluster) (cluste "git_account=" + viper.GetString("git-account"), "creator=" + user.GetUserId().String(), "cloud_account_id=" + tksCloudAccountId, + "base_repo_branch=" + viper.GetString("revision"), //"manifest_repo_url=" + viper.GetString("git-base-url") + "/" + viper.GetString("git-account") + "/" + clusterId + "-manifests", }, }) diff --git a/internal/usecase/organization.go b/internal/usecase/organization.go index 9cb6323b..108c5bff 100644 --- a/internal/usecase/organization.go +++ b/internal/usecase/organization.go @@ -64,7 +64,7 @@ func (u *OrganizationUsecase) Create(ctx context.Context, in *domain.Organizatio argowf.SubmitOptions{ Parameters: []string{ "contract_id=" + organizationId, - "revision=" + viper.GetString("revision"), + "base_repo_branch=" + viper.GetString("revision"), "keycloak_url=" + strings.TrimSuffix(viper.GetString("keycloak-address"), "/auth"), }, }) diff --git a/internal/usecase/stack.go b/internal/usecase/stack.go index a344eb2e..d32b653a 100644 --- a/internal/usecase/stack.go +++ b/internal/usecase/stack.go @@ -108,6 +108,7 @@ func (u *StackUsecase) Create(ctx context.Context, dto domain.Stack) (stackId do "cloud_account_id=" + dto.CloudAccountId.String(), "stack_template_id=" + dto.StackTemplateId.String(), "creator=" + user.GetUserId().String(), + "base_repo_branch=" + viper.GetString("revision"), "infra_conf=" + strings.Replace(helper.ModelToJson(stackConf), "\"", "\\\"", -1), }, }) From ba852694598f9fa6197fc284a78b28d283b991ea Mon Sep 17 00:00:00 2001 From: Taekyu Date: Thu, 6 Jul 2023 17:40:32 +0900 Subject: [PATCH 22/54] trivial. add parameter to remove appgroup workflow --- internal/usecase/app-group.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/usecase/app-group.go b/internal/usecase/app-group.go index 5995aa81..fd48beb2 100644 --- a/internal/usecase/app-group.go +++ b/internal/usecase/app-group.go @@ -167,6 +167,7 @@ func (u *AppGroupUsecase) Delete(ctx context.Context, organizationId string, id "cluster_id=" + clusterId.String(), "app_group_id=" + id.String(), "keycloak_url=" + strings.TrimSuffix(viper.GetString("keycloak-address"), "/auth"), + "base_repo_branch=" + viper.GetString("revision"), } workflowId, err := u.argo.SumbitWorkflowFromWftpl(workflowTemplate, opts) From 1cc631f82b1aaf54c3cb0c78f8cccdb412e7c24d Mon Sep 17 00:00:00 2001 From: Taekyu Date: Fri, 7 Jul 2023 13:56:03 +0900 Subject: [PATCH 23/54] feature. implementation pagination on alerts --- api/swagger/docs.go | 43 +++++++++++++ api/swagger/swagger.json | 43 +++++++++++++ api/swagger/swagger.yaml | 28 +++++++++ internal/delivery/http/alert.go | 10 ++- internal/pagination/pagination.go | 100 ++++++++++++++++++++++++++++++ internal/repository/alert.go | 52 ++++++++++++++-- internal/usecase/alert.go | 7 ++- pkg/domain/alert.go | 3 +- pkg/domain/pagination.go | 16 +++++ 9 files changed, 291 insertions(+), 11 deletions(-) create mode 100644 internal/pagination/pagination.go create mode 100644 pkg/domain/pagination.go diff --git a/api/swagger/docs.go b/api/swagger/docs.go index b9d06719..16dfa69e 100644 --- a/api/swagger/docs.go +++ b/api/swagger/docs.go @@ -4461,6 +4461,17 @@ const docTemplate = `{ } } }, + "domain.FilterResponse": { + "type": "object", + "properties": { + "column": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, "domain.FindIdRequest": { "type": "object", "required": [ @@ -4535,6 +4546,9 @@ const docTemplate = `{ "items": { "$ref": "#/definitions/domain.AlertResponse" } + }, + "pagination": { + "$ref": "#/definitions/domain.PaginationResponse" } } }, @@ -4998,6 +5012,35 @@ const docTemplate = `{ } } }, + "domain.PaginationResponse": { + "type": "object", + "properties": { + "filters": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.FilterResponse" + } + }, + "limit": { + "type": "integer" + }, + "page": { + "type": "integer" + }, + "sortColumn": { + "type": "string" + }, + "sortOrder": { + "type": "string" + }, + "totalPages": { + "type": "integer" + }, + "totalRows": { + "type": "integer" + } + } + }, "domain.Role": { "type": "object", "properties": { diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index a79499dd..bb2adbe0 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -4454,6 +4454,17 @@ } } }, + "domain.FilterResponse": { + "type": "object", + "properties": { + "column": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, "domain.FindIdRequest": { "type": "object", "required": [ @@ -4528,6 +4539,9 @@ "items": { "$ref": "#/definitions/domain.AlertResponse" } + }, + "pagination": { + "$ref": "#/definitions/domain.PaginationResponse" } } }, @@ -4991,6 +5005,35 @@ } } }, + "domain.PaginationResponse": { + "type": "object", + "properties": { + "filters": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.FilterResponse" + } + }, + "limit": { + "type": "integer" + }, + "page": { + "type": "integer" + }, + "sortColumn": { + "type": "string" + }, + "sortOrder": { + "type": "string" + }, + "totalPages": { + "type": "integer" + }, + "totalRows": { + "type": "integer" + } + } + }, "domain.Role": { "type": "object", "properties": { diff --git a/api/swagger/swagger.yaml b/api/swagger/swagger.yaml index e93bbd50..9024d4fc 100644 --- a/api/swagger/swagger.yaml +++ b/api/swagger/swagger.yaml @@ -828,6 +828,13 @@ definitions: - accessKeyId - secretAccessKey type: object + domain.FilterResponse: + properties: + column: + type: string + value: + type: string + type: object domain.FindIdRequest: properties: code: @@ -879,6 +886,8 @@ definitions: items: $ref: '#/definitions/domain.AlertResponse' type: array + pagination: + $ref: '#/definitions/domain.PaginationResponse' type: object domain.GetAppGroupResponse: properties: @@ -1177,6 +1186,25 @@ definitions: updatedAt: type: string type: object + domain.PaginationResponse: + properties: + filters: + items: + $ref: '#/definitions/domain.FilterResponse' + type: array + limit: + type: integer + page: + type: integer + sortColumn: + type: string + sortOrder: + type: string + totalPages: + type: integer + totalRows: + type: integer + type: object domain.Role: properties: createdAt: diff --git a/internal/delivery/http/alert.go b/internal/delivery/http/alert.go index 2a44f647..1b7245ae 100644 --- a/internal/delivery/http/alert.go +++ b/internal/delivery/http/alert.go @@ -8,6 +8,7 @@ import ( "github.com/google/uuid" "github.com/gorilla/mux" "github.com/openinfradev/tks-api/internal/helper" + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/internal/usecase" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -87,7 +88,10 @@ func (h *AlertHandler) GetAlerts(w http.ResponseWriter, r *http.Request) { return } - alerts, err := h.usecase.Fetch(r.Context(), organizationId) + urlParams := r.URL.Query() + pg := pagination.NewPagination(&urlParams) + + alerts, err := h.usecase.Fetch(r.Context(), organizationId, &pg) if err != nil { ErrorJSON(w, r, err) return @@ -112,6 +116,10 @@ func (h *AlertHandler) GetAlerts(w http.ResponseWriter, r *http.Request) { } } + if err := domain.Map(pg, &out.Pagination); err != nil { + log.InfoWithContext(r.Context(), err) + } + ResponseJSON(w, r, http.StatusOK, out) } diff --git a/internal/pagination/pagination.go b/internal/pagination/pagination.go new file mode 100644 index 00000000..bbe692b6 --- /dev/null +++ b/internal/pagination/pagination.go @@ -0,0 +1,100 @@ +package pagination + +import ( + "encoding/json" + "net/url" + "strconv" +) + +type Pagination struct { + Limit int `json:"limit"` + Page int `json:"page"` + SortColumn string `json:"sortColumn"` + SortOrder string `json:"sortOrder" validate:"oneof=ASC asc DESC desc"` + Filters []Filter `json:"filter,omitempty"` + TotalRows int64 `json:"totalRows"` + TotalPages int `json:"totalPages"` +} + +type Filter struct { + Column string `json:"column"` + Value string `json:"value"` +} + +var DEFAULT_LIMIT = 10 + +func (p *Pagination) GetOffset() int { + return (p.GetPage() - 1) * p.GetLimit() +} + +func (p *Pagination) GetLimit() int { + if p.Limit == 0 { + p.Limit = DEFAULT_LIMIT + } + return p.Limit +} + +func (p *Pagination) GetPage() int { + if p.Page == 0 { + p.Page = 1 + } + return p.Page +} + +func (p *Pagination) GetSortColumn() string { + return p.SortColumn +} + +func (p *Pagination) GetSortOrder() string { + return p.SortOrder +} + +func (p *Pagination) GetFilter() []Filter { + return p.Filters +} + +/* + { + sortingColumn : "id", + order : "ASC", + page : 1, + limit : 10, + } +*/ +func NewPagination(urlParams *url.Values) Pagination { + var pg Pagination + + pg.SortColumn = urlParams.Get("sortColumn") + if pg.SortColumn == "" { + pg.SortColumn = "created_at" + } + pg.SortOrder = urlParams.Get("sortOrder") + if pg.SortOrder == "" { + pg.SortOrder = "ASC" + } + + page := urlParams.Get("page") + if page == "" { + pg.Page = 1 + } else { + pg.Page, _ = strconv.Atoi(page) + } + + limit := urlParams.Get("limit") + if limit == "" { + pg.Limit = DEFAULT_LIMIT + } else { + limitNum, err := strconv.Atoi(limit) + if err == nil { + pg.Limit = limitNum + } + } + + // [TODO] filter + filter := urlParams.Get("filter") + if filter != "" { + _ = json.Unmarshal([]byte(filter), &pg.Filters) + } + + return pg +} diff --git a/internal/repository/alert.go b/internal/repository/alert.go index 75ac663f..84c3d371 100644 --- a/internal/repository/alert.go +++ b/internal/repository/alert.go @@ -1,6 +1,8 @@ package repository import ( + "fmt" + "math" "time" "github.com/google/uuid" @@ -8,14 +10,16 @@ import ( "gorm.io/gorm" "gorm.io/gorm/clause" + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/pkg/domain" + "github.com/openinfradev/tks-api/pkg/log" ) // Interfaces type IAlertRepository interface { Get(alertId uuid.UUID) (domain.Alert, error) GetByName(organizationId string, name string) (domain.Alert, error) - Fetch(organizationId string) ([]domain.Alert, error) + Fetch(organizationId string, pg *pagination.Pagination) ([]domain.Alert, error) FetchPodRestart(organizationId string, start time.Time, end time.Time) ([]domain.Alert, error) Create(dto domain.Alert) (alertId uuid.UUID, err error) Update(dto domain.Alert) (err error) @@ -99,15 +103,51 @@ func (r *AlertRepository) GetByName(organizationId string, name string) (out dom return } -func (r *AlertRepository) Fetch(organizationId string) (out []domain.Alert, err error) { +/* + var historiesWithUser []HistoryWithUser + + var total int64 + r.db.Find(&History{}, "project_id = '' OR project_id = ?", projectId).Count(&total) + + pagination.TotalRows = total + pagination.TotalPages = int(math.Ceil(float64(total) / float64(pagination.Limit))) + + log.Info(total) + log.Info(pagination.Limit) + + res := r.db.Offset(pagination.GetOffset()).Limit(pagination.GetLimit()).Order(pagination.GetSort()). + Model(&History{}). + Select("histories.*, users.account_id").Joins("left join users on histories.user_id::text=users.id::text").Where("project_id = '' OR project_id = ?", projectId). + Scan(&historiesWithUser) + + if res.RowsAffected == 0 || res.Error != nil { + return nil, fmt.Errorf("No history") + } + +*/ + +func (r *AlertRepository) Fetch(organizationId string, pg *pagination.Pagination) (out []domain.Alert, err error) { var alerts []Alert - res := r.db.Preload("AlertActions", func(db *gorm.DB) *gorm.DB { - return db.Order("created_at ASC") - }).Preload("AlertActions.Taker"). + var total int64 + + // [TODO] filter + r.db.Find(&alerts, "organization_id = ?", organizationId).Count(&total) + + pg.TotalRows = total + pg.TotalPages = int(math.Ceil(float64(total) / float64(pg.Limit))) + + log.Info(total) + log.Info(pg.Limit) + + orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) + + res := r.db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery). + Preload("AlertActions", func(db *gorm.DB) *gorm.DB { + return db.Order("created_at ASC") + }).Preload("AlertActions.Taker"). Preload("Cluster", "status = 2"). Preload("Organization"). Joins("join clusters on clusters.id = alerts.cluster_id AND clusters.status = 2"). - Order("created_at desc").Limit(1000). Find(&alerts, "alerts.organization_id = ?", organizationId) if res.Error != nil { return nil, res.Error diff --git a/internal/usecase/alert.go b/internal/usecase/alert.go index 6e8b8882..ab88c141 100644 --- a/internal/usecase/alert.go +++ b/internal/usecase/alert.go @@ -10,6 +10,7 @@ import ( "github.com/openinfradev/tks-api/internal/middleware/auth/request" "github.com/google/uuid" + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/internal/repository" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -21,7 +22,7 @@ import ( type IAlertUsecase interface { Get(ctx context.Context, alertId uuid.UUID) (domain.Alert, error) GetByName(ctx context.Context, organizationId string, name string) (domain.Alert, error) - Fetch(ctx context.Context, organizationId string) ([]domain.Alert, error) + Fetch(ctx context.Context, organizationId string, pg *pagination.Pagination) ([]domain.Alert, error) Create(ctx context.Context, dto domain.CreateAlertRequest) (err error) Update(ctx context.Context, dto domain.Alert) error Delete(ctx context.Context, dto domain.Alert) error @@ -149,8 +150,8 @@ func (u *AlertUsecase) GetByName(ctx context.Context, organizationId string, nam return } -func (u *AlertUsecase) Fetch(ctx context.Context, organizationId string) (alerts []domain.Alert, err error) { - alerts, err = u.repo.Fetch(organizationId) +func (u *AlertUsecase) Fetch(ctx context.Context, organizationId string, pg *pagination.Pagination) (alerts []domain.Alert, err error) { + alerts, err = u.repo.Fetch(organizationId, pg) if err != nil { return nil, err } diff --git a/pkg/domain/alert.go b/pkg/domain/alert.go index fb40c92c..7201ef24 100644 --- a/pkg/domain/alert.go +++ b/pkg/domain/alert.go @@ -155,7 +155,8 @@ type AlertActionResponse struct { } type GetAlertsResponse struct { - Alerts []AlertResponse `json:"alerts"` + Alerts []AlertResponse `json:"alerts"` + Pagination PaginationResponse `json:"pagination"` } type GetAlertResponse struct { diff --git a/pkg/domain/pagination.go b/pkg/domain/pagination.go new file mode 100644 index 00000000..74ca9ea9 --- /dev/null +++ b/pkg/domain/pagination.go @@ -0,0 +1,16 @@ +package domain + +type PaginationResponse struct { + Limit int `json:"limit"` + Page int `json:"page"` + SortColumn string `json:"sortColumn"` + SortOrder string `json:"sortOrder"` + Filters []FilterResponse `json:"filters,omitempty"` + TotalRows int64 `json:"totalRows"` + TotalPages int `json:"totalPages"` +} + +type FilterResponse struct { + Column string `json:"column"` + Value string `json:"value"` +} From a5bd3a1fca5f59997dfe191be27bd955b9031569 Mon Sep 17 00:00:00 2001 From: Taekyu Date: Fri, 7 Jul 2023 14:09:00 +0900 Subject: [PATCH 24/54] trivial. fix swagger docs --- api/swagger/docs.go | 33 +++++++++++++++++++++++++++++++++ api/swagger/swagger.json | 33 +++++++++++++++++++++++++++++++++ api/swagger/swagger.yaml | 22 ++++++++++++++++++++++ internal/delivery/http/alert.go | 5 +++++ 4 files changed, 93 insertions(+) diff --git a/api/swagger/docs.go b/api/swagger/docs.go index 16dfa69e..11cb3aac 100644 --- a/api/swagger/docs.go +++ b/api/swagger/docs.go @@ -855,6 +855,39 @@ const docTemplate = `{ "name": "organizationId", "in": "path", "required": true + }, + { + "type": "string", + "description": "limit", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "page", + "name": "page", + "in": "query" + }, + { + "type": "string", + "description": "sortColumn", + "name": "soertColumn", + "in": "query" + }, + { + "type": "string", + "description": "sortOrder", + "name": "sortOrder", + "in": "query" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "description": "filters", + "name": "filters", + "in": "query" } ], "responses": { diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index bb2adbe0..778be46f 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -848,6 +848,39 @@ "name": "organizationId", "in": "path", "required": true + }, + { + "type": "string", + "description": "limit", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "page", + "name": "page", + "in": "query" + }, + { + "type": "string", + "description": "sortColumn", + "name": "soertColumn", + "in": "query" + }, + { + "type": "string", + "description": "sortOrder", + "name": "sortOrder", + "in": "query" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "description": "filters", + "name": "filters", + "in": "query" } ], "responses": { diff --git a/api/swagger/swagger.yaml b/api/swagger/swagger.yaml index 9024d4fc..6c1ce7fe 100644 --- a/api/swagger/swagger.yaml +++ b/api/swagger/swagger.yaml @@ -2272,6 +2272,28 @@ paths: name: organizationId required: true type: string + - description: limit + in: query + name: limit + type: string + - description: page + in: query + name: page + type: string + - description: sortColumn + in: query + name: soertColumn + type: string + - description: sortOrder + in: query + name: sortOrder + type: string + - description: filters + in: query + items: + type: string + name: filters + type: array produces: - application/json responses: diff --git a/internal/delivery/http/alert.go b/internal/delivery/http/alert.go index 1b7245ae..350e5739 100644 --- a/internal/delivery/http/alert.go +++ b/internal/delivery/http/alert.go @@ -77,6 +77,11 @@ func (h *AlertHandler) CreateAlert(w http.ResponseWriter, r *http.Request) { // @Accept json // @Produce json // @Param organizationId path string true "organizationId" +// @Param limit query string false "limit" +// @Param page query string false "page" +// @Param soertColumn query string false "sortColumn" +// @Param sortOrder query string false "sortOrder" +// @Param filters query []string false "filters" // @Success 200 {object} domain.GetAlertsResponse // @Router /organizations/{organizationId}/alerts [get] // @Security JWT From ded9513fcecb66ed924876bbe42443740ddec144 Mon Sep 17 00:00:00 2001 From: Taekyu Date: Mon, 10 Jul 2023 15:48:11 +0900 Subject: [PATCH 25/54] feature. implementaion pagination on stacks --- api/swagger/docs.go | 44 ++++++++++++++++++++++++++++--- api/swagger/swagger.json | 44 ++++++++++++++++++++++++++++--- api/swagger/swagger.yaml | 32 +++++++++++++++++++--- internal/delivery/http/alert.go | 4 +-- internal/delivery/http/stack.go | 16 ++++++++++- internal/pagination/pagination.go | 32 ++++++++++++++-------- internal/repository/alert.go | 23 ---------------- internal/repository/cluster.go | 24 ++++++++++++++--- internal/usecase/cluster.go | 2 +- internal/usecase/dashboard.go | 4 +-- internal/usecase/stack.go | 11 ++++---- pkg/domain/pagination.go | 4 +-- pkg/domain/stack.go | 3 ++- 13 files changed, 179 insertions(+), 64 deletions(-) diff --git a/api/swagger/docs.go b/api/swagger/docs.go index 11cb3aac..e8ed6050 100644 --- a/api/swagger/docs.go +++ b/api/swagger/docs.go @@ -858,13 +858,13 @@ const docTemplate = `{ }, { "type": "string", - "description": "limit", + "description": "pageSize", "name": "limit", "in": "query" }, { "type": "string", - "description": "page", + "description": "pageNumber", "name": "page", "in": "query" }, @@ -2403,6 +2403,39 @@ const docTemplate = `{ "name": "organizationId", "in": "path", "required": true + }, + { + "type": "string", + "description": "pageSize", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "pageNumber", + "name": "page", + "in": "query" + }, + { + "type": "string", + "description": "sortColumn", + "name": "soertColumn", + "in": "query" + }, + { + "type": "string", + "description": "sortOrder", + "name": "sortOrder", + "in": "query" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "description": "filters", + "name": "filters", + "in": "query" } ], "responses": { @@ -4828,6 +4861,9 @@ const docTemplate = `{ "domain.GetStacksResponse": { "type": "object", "properties": { + "pagination": { + "$ref": "#/definitions/domain.PaginationResponse" + }, "stacks": { "type": "array", "items": { @@ -5054,10 +5090,10 @@ const docTemplate = `{ "$ref": "#/definitions/domain.FilterResponse" } }, - "limit": { + "pageNumber": { "type": "integer" }, - "page": { + "pageSize": { "type": "integer" }, "sortColumn": { diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index 778be46f..afe7f1a5 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -851,13 +851,13 @@ }, { "type": "string", - "description": "limit", + "description": "pageSize", "name": "limit", "in": "query" }, { "type": "string", - "description": "page", + "description": "pageNumber", "name": "page", "in": "query" }, @@ -2396,6 +2396,39 @@ "name": "organizationId", "in": "path", "required": true + }, + { + "type": "string", + "description": "pageSize", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "pageNumber", + "name": "page", + "in": "query" + }, + { + "type": "string", + "description": "sortColumn", + "name": "soertColumn", + "in": "query" + }, + { + "type": "string", + "description": "sortOrder", + "name": "sortOrder", + "in": "query" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "description": "filters", + "name": "filters", + "in": "query" } ], "responses": { @@ -4821,6 +4854,9 @@ "domain.GetStacksResponse": { "type": "object", "properties": { + "pagination": { + "$ref": "#/definitions/domain.PaginationResponse" + }, "stacks": { "type": "array", "items": { @@ -5047,10 +5083,10 @@ "$ref": "#/definitions/domain.FilterResponse" } }, - "limit": { + "pageNumber": { "type": "integer" }, - "page": { + "pageSize": { "type": "integer" }, "sortColumn": { diff --git a/api/swagger/swagger.yaml b/api/swagger/swagger.yaml index 6c1ce7fe..52346bf6 100644 --- a/api/swagger/swagger.yaml +++ b/api/swagger/swagger.yaml @@ -1044,6 +1044,8 @@ definitions: type: object domain.GetStacksResponse: properties: + pagination: + $ref: '#/definitions/domain.PaginationResponse' stacks: items: $ref: '#/definitions/domain.StackResponse' @@ -1192,9 +1194,9 @@ definitions: items: $ref: '#/definitions/domain.FilterResponse' type: array - limit: + pageNumber: type: integer - page: + pageSize: type: integer sortColumn: type: string @@ -2272,11 +2274,11 @@ paths: name: organizationId required: true type: string - - description: limit + - description: pageSize in: query name: limit type: string - - description: page + - description: pageNumber in: query name: page type: string @@ -3256,6 +3258,28 @@ paths: name: organizationId required: true type: string + - description: pageSize + in: query + name: limit + type: string + - description: pageNumber + in: query + name: page + type: string + - description: sortColumn + in: query + name: soertColumn + type: string + - description: sortOrder + in: query + name: sortOrder + type: string + - description: filters + in: query + items: + type: string + name: filters + type: array produces: - application/json responses: diff --git a/internal/delivery/http/alert.go b/internal/delivery/http/alert.go index 350e5739..855b4d0b 100644 --- a/internal/delivery/http/alert.go +++ b/internal/delivery/http/alert.go @@ -77,8 +77,8 @@ func (h *AlertHandler) CreateAlert(w http.ResponseWriter, r *http.Request) { // @Accept json // @Produce json // @Param organizationId path string true "organizationId" -// @Param limit query string false "limit" -// @Param page query string false "page" +// @Param limit query string false "pageSize" +// @Param page query string false "pageNumber" // @Param soertColumn query string false "sortColumn" // @Param sortOrder query string false "sortOrder" // @Param filters query []string false "filters" diff --git a/internal/delivery/http/stack.go b/internal/delivery/http/stack.go index b03a5ca8..386cc1e2 100644 --- a/internal/delivery/http/stack.go +++ b/internal/delivery/http/stack.go @@ -5,6 +5,7 @@ import ( "net/http" "github.com/gorilla/mux" + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/internal/usecase" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -76,6 +77,11 @@ func (h *StackHandler) CreateStack(w http.ResponseWriter, r *http.Request) { // @Accept json // @Produce json // @Param organizationId path string true "organizationId" +// @Param limit query string false "pageSize" +// @Param page query string false "pageNumber" +// @Param soertColumn query string false "sortColumn" +// @Param sortOrder query string false "sortOrder" +// @Param filters query []string false "filters" // @Success 200 {object} domain.GetStacksResponse // @Router /organizations/{organizationId}/stacks [get] // @Security JWT @@ -86,7 +92,11 @@ func (h *StackHandler) GetStacks(w http.ResponseWriter, r *http.Request) { ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("Invalid organizationId"), "C_INVALID_ORGANIZATION_ID", "")) return } - stacks, err := h.usecase.Fetch(r.Context(), organizationId) + + urlParams := r.URL.Query() + pg := pagination.NewPagination(&urlParams) + + stacks, err := h.usecase.Fetch(r.Context(), organizationId, &pg) if err != nil { ErrorJSON(w, r, err) return @@ -101,6 +111,10 @@ func (h *StackHandler) GetStacks(w http.ResponseWriter, r *http.Request) { } } + if err := domain.Map(pg, &out.Pagination); err != nil { + log.InfoWithContext(r.Context(), err) + } + ResponseJSON(w, r, http.StatusOK, out) } diff --git a/internal/pagination/pagination.go b/internal/pagination/pagination.go index bbe692b6..bccf1a55 100644 --- a/internal/pagination/pagination.go +++ b/internal/pagination/pagination.go @@ -7,21 +7,22 @@ import ( ) type Pagination struct { - Limit int `json:"limit"` - Page int `json:"page"` - SortColumn string `json:"sortColumn"` - SortOrder string `json:"sortOrder" validate:"oneof=ASC asc DESC desc"` - Filters []Filter `json:"filter,omitempty"` - TotalRows int64 `json:"totalRows"` - TotalPages int `json:"totalPages"` + Limit int + Page int + SortColumn string + SortOrder string + Filters []Filter + TotalRows int64 + TotalPages int } type Filter struct { - Column string `json:"column"` - Value string `json:"value"` + Column string + Value string } var DEFAULT_LIMIT = 10 +var MAX_LIMIT = 1000 func (p *Pagination) GetOffset() int { return (p.GetPage() - 1) * p.GetLimit() @@ -73,14 +74,14 @@ func NewPagination(urlParams *url.Values) Pagination { pg.SortOrder = "ASC" } - page := urlParams.Get("page") + page := urlParams.Get("pageNumber") if page == "" { pg.Page = 1 } else { pg.Page, _ = strconv.Atoi(page) } - limit := urlParams.Get("limit") + limit := urlParams.Get("pageSize") if limit == "" { pg.Limit = DEFAULT_LIMIT } else { @@ -98,3 +99,12 @@ func NewPagination(urlParams *url.Values) Pagination { return pg } + +func NewDefaultPagination() Pagination { + return Pagination{ + SortColumn: "created_at", + SortOrder: "ASC", + Page: 1, + Limit: MAX_LIMIT, + } +} diff --git a/internal/repository/alert.go b/internal/repository/alert.go index 84c3d371..6dae27a9 100644 --- a/internal/repository/alert.go +++ b/internal/repository/alert.go @@ -103,29 +103,6 @@ func (r *AlertRepository) GetByName(organizationId string, name string) (out dom return } -/* - var historiesWithUser []HistoryWithUser - - var total int64 - r.db.Find(&History{}, "project_id = '' OR project_id = ?", projectId).Count(&total) - - pagination.TotalRows = total - pagination.TotalPages = int(math.Ceil(float64(total) / float64(pagination.Limit))) - - log.Info(total) - log.Info(pagination.Limit) - - res := r.db.Offset(pagination.GetOffset()).Limit(pagination.GetLimit()).Order(pagination.GetSort()). - Model(&History{}). - Select("histories.*, users.account_id").Joins("left join users on histories.user_id::text=users.id::text").Where("project_id = '' OR project_id = ?", projectId). - Scan(&historiesWithUser) - - if res.RowsAffected == 0 || res.Error != nil { - return nil, fmt.Errorf("No history") - } - -*/ - func (r *AlertRepository) Fetch(organizationId string, pg *pagination.Pagination) (out []domain.Alert, err error) { var alerts []Alert var total int64 diff --git a/internal/repository/cluster.go b/internal/repository/cluster.go index 98221bb3..b9647b4d 100644 --- a/internal/repository/cluster.go +++ b/internal/repository/cluster.go @@ -2,12 +2,14 @@ package repository import ( "fmt" + "math" "github.com/google/uuid" "gorm.io/gorm" "gorm.io/gorm/clause" "github.com/openinfradev/tks-api/internal/helper" + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/log" ) @@ -16,8 +18,8 @@ import ( type IClusterRepository interface { WithTrx(*gorm.DB) IClusterRepository Fetch() (res []domain.Cluster, err error) - FetchByOrganizationId(organizationId string) (res []domain.Cluster, err error) FetchByCloudAccountId(cloudAccountId uuid.UUID) (res []domain.Cluster, err error) + FetchByOrganizationId(organizationId string, pg *pagination.Pagination) (res []domain.Cluster, err error) Get(id domain.ClusterId) (domain.Cluster, error) GetByName(organizationId string, name string) (domain.Cluster, error) Create(dto domain.Cluster) (clusterId domain.ClusterId, err error) @@ -95,10 +97,24 @@ func (r *ClusterRepository) Fetch() (out []domain.Cluster, err error) { return out, nil } -// [TODO] Need refactoring about filters and pagination -func (r *ClusterRepository) FetchByOrganizationId(organizationId string) (out []domain.Cluster, err error) { +func (r *ClusterRepository) FetchByOrganizationId(organizationId string, pg *pagination.Pagination) (out []domain.Cluster, err error) { var clusters []Cluster - res := r.db.Preload(clause.Associations).Order("updated_at desc, created_at desc").Find(&clusters, "organization_id = ? AND status != ?", organizationId, domain.ClusterStatus_DELETED) + var total int64 + + if pg == nil { + *pg = pagination.NewDefaultPagination() + } + + r.db.Find(&clusters, "organization_id = ? AND status != ?", organizationId, domain.ClusterStatus_DELETED).Count(&total) + + pg.TotalRows = total + pg.TotalPages = int(math.Ceil(float64(total) / float64(pg.Limit))) + + orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) + + res := r.db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery). + Preload(clause.Associations).Order("updated_at desc, created_at desc"). + Find(&clusters, "organization_id = ? AND status != ?", organizationId, domain.ClusterStatus_DELETED) if res.Error != nil { return nil, res.Error diff --git a/internal/usecase/cluster.go b/internal/usecase/cluster.go index 237c22fd..0bcd8e21 100644 --- a/internal/usecase/cluster.go +++ b/internal/usecase/cluster.go @@ -88,7 +88,7 @@ func (u *ClusterUsecase) Fetch(ctx context.Context, organizationId string) (out // [TODO] 사용자가 속한 organization 리스트 out, err = u.repo.Fetch() } else { - out, err = u.repo.FetchByOrganizationId(organizationId) + out, err = u.repo.FetchByOrganizationId(organizationId, nil) } if err != nil { diff --git a/internal/usecase/dashboard.go b/internal/usecase/dashboard.go index 97a23384..f6e3024d 100644 --- a/internal/usecase/dashboard.go +++ b/internal/usecase/dashboard.go @@ -70,7 +70,7 @@ func (u *DashboardUsecase) GetCharts(ctx context.Context, organizationId string, } func (u *DashboardUsecase) GetStacks(ctx context.Context, organizationId string) (out []domain.DashboardStack, err error) { - clusters, err := u.clusterRepo.FetchByOrganizationId(organizationId) + clusters, err := u.clusterRepo.FetchByOrganizationId(organizationId, nil) if err != nil { return out, err } @@ -146,7 +146,7 @@ func (u *DashboardUsecase) GetResources(ctx context.Context, organizationId stri } // Stack - clusters, err := u.clusterRepo.FetchByOrganizationId(organizationId) + clusters, err := u.clusterRepo.FetchByOrganizationId(organizationId, nil) if err != nil { return out, err } diff --git a/internal/usecase/stack.go b/internal/usecase/stack.go index d32b653a..08c46bf5 100644 --- a/internal/usecase/stack.go +++ b/internal/usecase/stack.go @@ -10,6 +10,7 @@ import ( "github.com/openinfradev/tks-api/internal/helper" "github.com/openinfradev/tks-api/internal/kubernetes" + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/internal/repository" argowf "github.com/openinfradev/tks-api/pkg/argo-client" "github.com/openinfradev/tks-api/pkg/domain" @@ -23,7 +24,7 @@ import ( type IStackUsecase interface { Get(ctx context.Context, stackId domain.StackId) (domain.Stack, error) GetByName(ctx context.Context, organizationId string, name string) (domain.Stack, error) - Fetch(ctx context.Context, organizationId string) ([]domain.Stack, error) + Fetch(ctx context.Context, organizationId string, pg *pagination.Pagination) ([]domain.Stack, error) Create(ctx context.Context, dto domain.Stack) (stackId domain.StackId, err error) Update(ctx context.Context, dto domain.Stack) error Delete(ctx context.Context, dto domain.Stack) error @@ -74,7 +75,7 @@ func (u *StackUsecase) Create(ctx context.Context, dto domain.Stack) (stackId do return "", httpErrors.NewInternalServerError(errors.Wrap(err, "Invalid cloudAccountId"), "S_INVALID_CLOUD_ACCOUNT", "") } - clusters, err := u.clusterRepo.FetchByOrganizationId(dto.OrganizationId) + clusters, err := u.clusterRepo.FetchByOrganizationId(dto.OrganizationId, nil) if err != nil { return "", httpErrors.NewInternalServerError(errors.Wrap(err, "Failed to get clusters"), "S_FAILED_GET_CLUSTERS", "") } @@ -207,13 +208,13 @@ func (u *StackUsecase) GetByName(ctx context.Context, organizationId string, nam return } -func (u *StackUsecase) Fetch(ctx context.Context, organizationId string) (out []domain.Stack, err error) { +func (u *StackUsecase) Fetch(ctx context.Context, organizationId string, pg *pagination.Pagination) (out []domain.Stack, err error) { organization, err := u.organizationRepo.Get(organizationId) if err != nil { return out, httpErrors.NewInternalServerError(errors.Wrap(err, fmt.Sprintf("Failed to get organization for clusterId %s", organizationId)), "S_FAILED_FETCH_ORGANIZATION", "") } - clusters, err := u.clusterRepo.FetchByOrganizationId(organizationId) + clusters, err := u.clusterRepo.FetchByOrganizationId(organizationId, pg) if err != nil { return out, err } @@ -287,7 +288,7 @@ func (u *StackUsecase) Delete(ctx context.Context, dto domain.Stack) (err error) for _, organization := range *organizations { if organization.PrimaryClusterId == cluster.ID.String() { - clusters, err := u.clusterRepo.FetchByOrganizationId(organization.ID) + clusters, err := u.clusterRepo.FetchByOrganizationId(organization.ID, nil) if err != nil { return errors.Wrap(err, "Failed to get organizations") } diff --git a/pkg/domain/pagination.go b/pkg/domain/pagination.go index 74ca9ea9..e91e9c4a 100644 --- a/pkg/domain/pagination.go +++ b/pkg/domain/pagination.go @@ -1,8 +1,8 @@ package domain type PaginationResponse struct { - Limit int `json:"limit"` - Page int `json:"page"` + Limit int `json:"pageSize"` + Page int `json:"pageNumber"` SortColumn string `json:"sortColumn"` SortOrder string `json:"sortOrder"` Filters []FilterResponse `json:"filters,omitempty"` diff --git a/pkg/domain/stack.go b/pkg/domain/stack.go index f881bb4b..8f65f12b 100644 --- a/pkg/domain/stack.go +++ b/pkg/domain/stack.go @@ -153,7 +153,8 @@ type StackResponse struct { } type GetStacksResponse struct { - Stacks []StackResponse `json:"stacks"` + Stacks []StackResponse `json:"stacks"` + Pagination PaginationResponse `json:"pagination"` } type GetStackResponse struct { From 4e4ffa373ef7724ea6319c840cc9d95906037652 Mon Sep 17 00:00:00 2001 From: Taekyu Date: Tue, 11 Jul 2023 13:47:30 +0900 Subject: [PATCH 26/54] feature. implementation pagination ( cluster, appgroup, organization, stack-template, cloudAccount, user ) --- api/swagger/docs.go | 247 +++++++++++++++++++++++ api/swagger/swagger.json | 247 +++++++++++++++++++++++ api/swagger/swagger.yaml | 164 +++++++++++++++ internal/delivery/http/alert.go | 5 +- internal/delivery/http/app-group.go | 13 +- internal/delivery/http/app-serve-app.go | 13 +- internal/delivery/http/cloud-account.go | 14 +- internal/delivery/http/cluster.go | 13 +- internal/delivery/http/organization.go | 15 +- internal/delivery/http/stack-template.go | 15 +- internal/delivery/http/stack.go | 5 +- internal/delivery/http/user.go | 14 +- internal/pagination/pagination.go | 8 +- internal/repository/alert.go | 4 +- internal/repository/app-group.go | 5 +- internal/repository/app-serve-app.go | 8 +- internal/repository/cloud-account.go | 20 +- internal/repository/cluster.go | 39 +++- internal/repository/organization.go | 24 ++- internal/repository/stack-template.go | 22 +- internal/repository/user.go | 38 +++- internal/usecase/alert.go | 4 +- internal/usecase/app-group.go | 10 +- internal/usecase/app-serve-app.go | 7 +- internal/usecase/auth.go | 10 +- internal/usecase/cloud-account.go | 9 +- internal/usecase/cluster.go | 19 +- internal/usecase/dashboard.go | 2 +- internal/usecase/organization.go | 16 +- internal/usecase/stack-template.go | 7 +- internal/usecase/stack.go | 17 +- internal/usecase/user.go | 20 +- pkg/domain/app-group.go | 3 +- pkg/domain/app-serve-app.go | 3 +- pkg/domain/cloud-account.go | 1 + pkg/domain/cluster.go | 3 +- pkg/domain/organization.go | 1 + pkg/domain/stack-template.go | 1 + pkg/domain/user.go | 3 +- 39 files changed, 953 insertions(+), 116 deletions(-) diff --git a/api/swagger/docs.go b/api/swagger/docs.go index e8ed6050..4211d035 100644 --- a/api/swagger/docs.go +++ b/api/swagger/docs.go @@ -47,6 +47,39 @@ const docTemplate = `{ "description": "clusterId", "name": "clusterId", "in": "query" + }, + { + "type": "string", + "description": "pageSize", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "pageNumber", + "name": "page", + "in": "query" + }, + { + "type": "string", + "description": "sortColumn", + "name": "soertColumn", + "in": "query" + }, + { + "type": "string", + "description": "sortOrder", + "name": "sortOrder", + "in": "query" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "description": "filters", + "name": "filters", + "in": "query" } ], "responses": { @@ -488,6 +521,39 @@ const docTemplate = `{ "description": "organizationId", "name": "organizationId", "in": "query" + }, + { + "type": "string", + "description": "pageSize", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "pageNumber", + "name": "page", + "in": "query" + }, + { + "type": "string", + "description": "sortColumn", + "name": "soertColumn", + "in": "query" + }, + { + "type": "string", + "description": "sortOrder", + "name": "sortOrder", + "in": "query" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "description": "filters", + "name": "filters", + "in": "query" } ], "responses": { @@ -664,6 +730,41 @@ const docTemplate = `{ "Organizations" ], "summary": "Get organization list", + "parameters": [ + { + "type": "string", + "description": "pageSize", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "pageNumber", + "name": "page", + "in": "query" + }, + { + "type": "string", + "description": "sortColumn", + "name": "soertColumn", + "in": "query" + }, + { + "type": "string", + "description": "sortOrder", + "name": "sortOrder", + "in": "query" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "description": "filters", + "name": "filters", + "in": "query" + } + ], "responses": { "200": { "description": "OK", @@ -1089,6 +1190,39 @@ const docTemplate = `{ "description": "Show all apps including deleted apps", "name": "showAll", "in": "query" + }, + { + "type": "string", + "description": "pageSize", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "pageNumber", + "name": "page", + "in": "query" + }, + { + "type": "string", + "description": "sortColumn", + "name": "soertColumn", + "in": "query" + }, + { + "type": "string", + "description": "sortOrder", + "name": "sortOrder", + "in": "query" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "description": "filters", + "name": "filters", + "in": "query" } ], "responses": { @@ -1629,6 +1763,39 @@ const docTemplate = `{ "name": "organizationId", "in": "path", "required": true + }, + { + "type": "string", + "description": "pageSize", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "pageNumber", + "name": "page", + "in": "query" + }, + { + "type": "string", + "description": "sortColumn", + "name": "soertColumn", + "in": "query" + }, + { + "type": "string", + "description": "sortOrder", + "name": "sortOrder", + "in": "query" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "description": "filters", + "name": "filters", + "in": "query" } ], "responses": { @@ -2784,6 +2951,39 @@ const docTemplate = `{ "name": "organizationId", "in": "path", "required": true + }, + { + "type": "string", + "description": "pageSize", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "pageNumber", + "name": "page", + "in": "query" + }, + { + "type": "string", + "description": "sortColumn", + "name": "soertColumn", + "in": "query" + }, + { + "type": "string", + "description": "sortOrder", + "name": "sortOrder", + "in": "query" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "description": "filters", + "name": "filters", + "in": "query" } ], "responses": { @@ -3121,6 +3321,41 @@ const docTemplate = `{ "StackTemplates" ], "summary": "Get StackTemplates", + "parameters": [ + { + "type": "string", + "description": "pageSize", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "pageNumber", + "name": "page", + "in": "query" + }, + { + "type": "string", + "description": "sortColumn", + "name": "soertColumn", + "in": "query" + }, + { + "type": "string", + "description": "sortOrder", + "name": "sortOrder", + "in": "query" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "description": "filters", + "name": "filters", + "in": "query" + } + ], "responses": { "200": { "description": "OK", @@ -4634,6 +4869,9 @@ const docTemplate = `{ "items": { "$ref": "#/definitions/domain.AppGroupResponse" } + }, + "pagination": { + "$ref": "#/definitions/domain.PaginationResponse" } } }, @@ -4686,6 +4924,9 @@ const docTemplate = `{ "items": { "$ref": "#/definitions/domain.CloudAccountResponse" } + }, + "pagination": { + "$ref": "#/definitions/domain.PaginationResponse" } } }, @@ -4697,6 +4938,9 @@ const docTemplate = `{ "items": { "$ref": "#/definitions/domain.ClusterResponse" } + }, + "pagination": { + "$ref": "#/definitions/domain.PaginationResponse" } } }, @@ -4850,6 +5094,9 @@ const docTemplate = `{ "domain.GetStackTemplatesResponse": { "type": "object", "properties": { + "pagination": { + "$ref": "#/definitions/domain.PaginationResponse" + }, "stackTemplates": { "type": "array", "items": { diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index afe7f1a5..d7df0b40 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -40,6 +40,39 @@ "description": "clusterId", "name": "clusterId", "in": "query" + }, + { + "type": "string", + "description": "pageSize", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "pageNumber", + "name": "page", + "in": "query" + }, + { + "type": "string", + "description": "sortColumn", + "name": "soertColumn", + "in": "query" + }, + { + "type": "string", + "description": "sortOrder", + "name": "sortOrder", + "in": "query" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "description": "filters", + "name": "filters", + "in": "query" } ], "responses": { @@ -481,6 +514,39 @@ "description": "organizationId", "name": "organizationId", "in": "query" + }, + { + "type": "string", + "description": "pageSize", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "pageNumber", + "name": "page", + "in": "query" + }, + { + "type": "string", + "description": "sortColumn", + "name": "soertColumn", + "in": "query" + }, + { + "type": "string", + "description": "sortOrder", + "name": "sortOrder", + "in": "query" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "description": "filters", + "name": "filters", + "in": "query" } ], "responses": { @@ -657,6 +723,41 @@ "Organizations" ], "summary": "Get organization list", + "parameters": [ + { + "type": "string", + "description": "pageSize", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "pageNumber", + "name": "page", + "in": "query" + }, + { + "type": "string", + "description": "sortColumn", + "name": "soertColumn", + "in": "query" + }, + { + "type": "string", + "description": "sortOrder", + "name": "sortOrder", + "in": "query" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "description": "filters", + "name": "filters", + "in": "query" + } + ], "responses": { "200": { "description": "OK", @@ -1082,6 +1183,39 @@ "description": "Show all apps including deleted apps", "name": "showAll", "in": "query" + }, + { + "type": "string", + "description": "pageSize", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "pageNumber", + "name": "page", + "in": "query" + }, + { + "type": "string", + "description": "sortColumn", + "name": "soertColumn", + "in": "query" + }, + { + "type": "string", + "description": "sortOrder", + "name": "sortOrder", + "in": "query" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "description": "filters", + "name": "filters", + "in": "query" } ], "responses": { @@ -1622,6 +1756,39 @@ "name": "organizationId", "in": "path", "required": true + }, + { + "type": "string", + "description": "pageSize", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "pageNumber", + "name": "page", + "in": "query" + }, + { + "type": "string", + "description": "sortColumn", + "name": "soertColumn", + "in": "query" + }, + { + "type": "string", + "description": "sortOrder", + "name": "sortOrder", + "in": "query" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "description": "filters", + "name": "filters", + "in": "query" } ], "responses": { @@ -2777,6 +2944,39 @@ "name": "organizationId", "in": "path", "required": true + }, + { + "type": "string", + "description": "pageSize", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "pageNumber", + "name": "page", + "in": "query" + }, + { + "type": "string", + "description": "sortColumn", + "name": "soertColumn", + "in": "query" + }, + { + "type": "string", + "description": "sortOrder", + "name": "sortOrder", + "in": "query" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "description": "filters", + "name": "filters", + "in": "query" } ], "responses": { @@ -3114,6 +3314,41 @@ "StackTemplates" ], "summary": "Get StackTemplates", + "parameters": [ + { + "type": "string", + "description": "pageSize", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "pageNumber", + "name": "page", + "in": "query" + }, + { + "type": "string", + "description": "sortColumn", + "name": "soertColumn", + "in": "query" + }, + { + "type": "string", + "description": "sortOrder", + "name": "sortOrder", + "in": "query" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "description": "filters", + "name": "filters", + "in": "query" + } + ], "responses": { "200": { "description": "OK", @@ -4627,6 +4862,9 @@ "items": { "$ref": "#/definitions/domain.AppGroupResponse" } + }, + "pagination": { + "$ref": "#/definitions/domain.PaginationResponse" } } }, @@ -4679,6 +4917,9 @@ "items": { "$ref": "#/definitions/domain.CloudAccountResponse" } + }, + "pagination": { + "$ref": "#/definitions/domain.PaginationResponse" } } }, @@ -4690,6 +4931,9 @@ "items": { "$ref": "#/definitions/domain.ClusterResponse" } + }, + "pagination": { + "$ref": "#/definitions/domain.PaginationResponse" } } }, @@ -4843,6 +5087,9 @@ "domain.GetStackTemplatesResponse": { "type": "object", "properties": { + "pagination": { + "$ref": "#/definitions/domain.PaginationResponse" + }, "stackTemplates": { "type": "array", "items": { diff --git a/api/swagger/swagger.yaml b/api/swagger/swagger.yaml index 52346bf6..ce331393 100644 --- a/api/swagger/swagger.yaml +++ b/api/swagger/swagger.yaml @@ -900,6 +900,8 @@ definitions: items: $ref: '#/definitions/domain.AppGroupResponse' type: array + pagination: + $ref: '#/definitions/domain.PaginationResponse' type: object domain.GetAppServeAppResponse: properties: @@ -933,6 +935,8 @@ definitions: items: $ref: '#/definitions/domain.CloudAccountResponse' type: array + pagination: + $ref: '#/definitions/domain.PaginationResponse' type: object domain.GetClustersResponse: properties: @@ -940,6 +944,8 @@ definitions: items: $ref: '#/definitions/domain.ClusterResponse' type: array + pagination: + $ref: '#/definitions/domain.PaginationResponse' type: object domain.GetDashboardChartResponse: properties: @@ -1037,6 +1043,8 @@ definitions: type: object domain.GetStackTemplatesResponse: properties: + pagination: + $ref: '#/definitions/domain.PaginationResponse' stackTemplates: items: $ref: '#/definitions/domain.StackTemplateResponse' @@ -1779,6 +1787,28 @@ paths: in: query name: clusterId type: string + - description: pageSize + in: query + name: limit + type: string + - description: pageNumber + in: query + name: page + type: string + - description: sortColumn + in: query + name: soertColumn + type: string + - description: sortOrder + in: query + name: sortOrder + type: string + - description: filters + in: query + items: + type: string + name: filters + type: array produces: - application/json responses: @@ -2045,6 +2075,28 @@ paths: in: query name: organizationId type: string + - description: pageSize + in: query + name: limit + type: string + - description: pageNumber + in: query + name: page + type: string + - description: sortColumn + in: query + name: soertColumn + type: string + - description: sortOrder + in: query + name: sortOrder + type: string + - description: filters + in: query + items: + type: string + name: filters + type: array produces: - application/json responses: @@ -2153,6 +2205,29 @@ paths: consumes: - application/json description: Get organization list + parameters: + - description: pageSize + in: query + name: limit + type: string + - description: pageNumber + in: query + name: page + type: string + - description: sortColumn + in: query + name: soertColumn + type: string + - description: sortOrder + in: query + name: sortOrder + type: string + - description: filters + in: query + items: + type: string + name: filters + type: array produces: - application/json responses: @@ -2423,6 +2498,28 @@ paths: in: query name: showAll type: boolean + - description: pageSize + in: query + name: limit + type: string + - description: pageNumber + in: query + name: page + type: string + - description: sortColumn + in: query + name: soertColumn + type: string + - description: sortOrder + in: query + name: sortOrder + type: string + - description: filters + in: query + items: + type: string + name: filters + type: array produces: - application/json responses: @@ -2767,6 +2864,28 @@ paths: name: organizationId required: true type: string + - description: pageSize + in: query + name: limit + type: string + - description: pageNumber + in: query + name: page + type: string + - description: sortColumn + in: query + name: soertColumn + type: string + - description: sortOrder + in: query + name: sortOrder + type: string + - description: filters + in: query + items: + type: string + name: filters + type: array produces: - application/json responses: @@ -3502,6 +3621,28 @@ paths: name: organizationId required: true type: string + - description: pageSize + in: query + name: limit + type: string + - description: pageNumber + in: query + name: page + type: string + - description: sortColumn + in: query + name: soertColumn + type: string + - description: sortOrder + in: query + name: sortOrder + type: string + - description: filters + in: query + items: + type: string + name: filters + type: array produces: - application/json responses: @@ -3716,6 +3857,29 @@ paths: consumes: - application/json description: Get StackTemplates + parameters: + - description: pageSize + in: query + name: limit + type: string + - description: pageNumber + in: query + name: page + type: string + - description: sortColumn + in: query + name: soertColumn + type: string + - description: sortOrder + in: query + name: sortOrder + type: string + - description: filters + in: query + items: + type: string + name: filters + type: array produces: - application/json responses: diff --git a/internal/delivery/http/alert.go b/internal/delivery/http/alert.go index 855b4d0b..5e08e873 100644 --- a/internal/delivery/http/alert.go +++ b/internal/delivery/http/alert.go @@ -95,8 +95,7 @@ func (h *AlertHandler) GetAlerts(w http.ResponseWriter, r *http.Request) { urlParams := r.URL.Query() pg := pagination.NewPagination(&urlParams) - - alerts, err := h.usecase.Fetch(r.Context(), organizationId, &pg) + alerts, err := h.usecase.Fetch(r.Context(), organizationId, pg) if err != nil { ErrorJSON(w, r, err) return @@ -121,7 +120,7 @@ func (h *AlertHandler) GetAlerts(w http.ResponseWriter, r *http.Request) { } } - if err := domain.Map(pg, &out.Pagination); err != nil { + if err := domain.Map(*pg, &out.Pagination); err != nil { log.InfoWithContext(r.Context(), err) } diff --git a/internal/delivery/http/app-group.go b/internal/delivery/http/app-group.go index 34d52ec3..ae169b70 100644 --- a/internal/delivery/http/app-group.go +++ b/internal/delivery/http/app-group.go @@ -7,6 +7,7 @@ import ( "github.com/gorilla/mux" "github.com/openinfradev/tks-api/internal/helper" "github.com/openinfradev/tks-api/internal/middleware/auth/request" + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/internal/usecase" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -65,6 +66,11 @@ func (h *AppGroupHandler) CreateAppGroup(w http.ResponseWriter, r *http.Request) // @Accept json // @Produce json // @Param clusterId query string false "clusterId" +// @Param limit query string false "pageSize" +// @Param page query string false "pageNumber" +// @Param soertColumn query string false "sortColumn" +// @Param sortOrder query string false "sortOrder" +// @Param filters query []string false "filters" // @Success 200 {object} domain.GetAppGroupsResponse // @Router /app-groups [get] // @Security JWT @@ -76,8 +82,9 @@ func (h *AppGroupHandler) GetAppGroups(w http.ResponseWriter, r *http.Request) { ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("Invalid clusterId"), "C_INVALID_CLUSTER_ID", "")) return } + pg := pagination.NewPagination(&urlParams) - appGroups, err := h.usecase.Fetch(r.Context(), domain.ClusterId(clusterId)) + appGroups, err := h.usecase.Fetch(r.Context(), domain.ClusterId(clusterId), pg) if err != nil { ErrorJSON(w, r, err) return @@ -92,6 +99,10 @@ func (h *AppGroupHandler) GetAppGroups(w http.ResponseWriter, r *http.Request) { } } + if err := domain.Map(*pg, &out.Pagination); err != nil { + log.InfoWithContext(r.Context(), err) + } + ResponseJSON(w, r, http.StatusOK, out) } diff --git a/internal/delivery/http/app-serve-app.go b/internal/delivery/http/app-serve-app.go index 39656c0d..b30a3a40 100644 --- a/internal/delivery/http/app-serve-app.go +++ b/internal/delivery/http/app-serve-app.go @@ -10,6 +10,7 @@ import ( "github.com/gorilla/mux" "github.com/openinfradev/tks-api/internal" + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/internal/usecase" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -166,6 +167,11 @@ func (h *AppServeAppHandler) CreateAppServeApp(w http.ResponseWriter, r *http.Re // @Produce json // @Param organizationId path string true "Organization ID" // @Param showAll query boolean false "Show all apps including deleted apps" +// @Param limit query string false "pageSize" +// @Param page query string false "pageNumber" +// @Param soertColumn query string false "sortColumn" +// @Param sortOrder query string false "sortOrder" +// @Param filters query []string false "filters" // @Success 200 {object} []domain.AppServeApp // @Router /organizations/{organizationId}/app-serve-apps [get] // @Security JWT @@ -191,8 +197,9 @@ func (h *AppServeAppHandler) GetAppServeApps(w http.ResponseWriter, r *http.Requ ErrorJSON(w, r, err) return } + pg := pagination.NewPagination(&urlParams) - apps, err := h.usecase.GetAppServeApps(organizationId, showAll) + apps, err := h.usecase.GetAppServeApps(organizationId, showAll, pg) if err != nil { log.ErrorWithContext(r.Context(), "Failed to get Failed to get app-serve-apps ", err) ErrorJSON(w, r, err) @@ -202,6 +209,10 @@ func (h *AppServeAppHandler) GetAppServeApps(w http.ResponseWriter, r *http.Requ var out domain.GetAppServeAppsResponse out.AppServeApps = apps + if err := domain.Map(*pg, &out.Pagination); err != nil { + log.InfoWithContext(r.Context(), err) + } + ResponseJSON(w, r, http.StatusOK, out) } diff --git a/internal/delivery/http/cloud-account.go b/internal/delivery/http/cloud-account.go index 732a765e..32e61bc8 100644 --- a/internal/delivery/http/cloud-account.go +++ b/internal/delivery/http/cloud-account.go @@ -7,6 +7,7 @@ import ( "github.com/google/uuid" "github.com/gorilla/mux" "github.com/openinfradev/tks-api/internal/middleware/auth/request" + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/internal/usecase" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -75,6 +76,11 @@ func (h *CloudAccountHandler) CreateCloudAccount(w http.ResponseWriter, r *http. // @Accept json // @Produce json // @Param organizationId path string true "organizationId" +// @Param limit query string false "pageSize" +// @Param page query string false "pageNumber" +// @Param soertColumn query string false "sortColumn" +// @Param sortOrder query string false "sortOrder" +// @Param filters query []string false "filters" // @Success 200 {object} domain.GetCloudAccountsResponse // @Router /organizations/{organizationId}/cloud-accounts [get] // @Security JWT @@ -86,7 +92,9 @@ func (h *CloudAccountHandler) GetCloudAccounts(w http.ResponseWriter, r *http.Re return } - cloudAccounts, err := h.usecase.Fetch(r.Context(), organizationId) + urlParams := r.URL.Query() + pg := pagination.NewPagination(&urlParams) + cloudAccounts, err := h.usecase.Fetch(r.Context(), organizationId, pg) if err != nil { ErrorJSON(w, r, err) return @@ -101,6 +109,10 @@ func (h *CloudAccountHandler) GetCloudAccounts(w http.ResponseWriter, r *http.Re } } + if err := domain.Map(*pg, &out.Pagination); err != nil { + log.InfoWithContext(r.Context(), err) + } + ResponseJSON(w, r, http.StatusOK, out) } diff --git a/internal/delivery/http/cluster.go b/internal/delivery/http/cluster.go index 9f94ae76..16d697fd 100644 --- a/internal/delivery/http/cluster.go +++ b/internal/delivery/http/cluster.go @@ -5,6 +5,7 @@ import ( "net/http" "github.com/gorilla/mux" + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/internal/usecase" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -28,6 +29,11 @@ func NewClusterHandler(h usecase.IClusterUsecase) *ClusterHandler { // @Accept json // @Produce json // @Param organizationId query string false "organizationId" +// @Param limit query string false "pageSize" +// @Param page query string false "pageNumber" +// @Param soertColumn query string false "sortColumn" +// @Param sortOrder query string false "sortOrder" +// @Param filters query []string false "filters" // @Success 200 {object} domain.GetClustersResponse // @Router /clusters [get] // @Security JWT @@ -35,7 +41,8 @@ func (h *ClusterHandler) GetClusters(w http.ResponseWriter, r *http.Request) { urlParams := r.URL.Query() organizationId := urlParams.Get("organizationId") - clusters, err := h.usecase.Fetch(r.Context(), organizationId) + pg := pagination.NewPagination(&urlParams) + clusters, err := h.usecase.Fetch(r.Context(), organizationId, pg) if err != nil { ErrorJSON(w, r, err) return @@ -50,6 +57,10 @@ func (h *ClusterHandler) GetClusters(w http.ResponseWriter, r *http.Request) { } } + if err := domain.Map(*pg, &out.Pagination); err != nil { + log.InfoWithContext(r.Context(), err) + } + ResponseJSON(w, r, http.StatusOK, out) } diff --git a/internal/delivery/http/organization.go b/internal/delivery/http/organization.go index a9652fbe..ba6e1111 100644 --- a/internal/delivery/http/organization.go +++ b/internal/delivery/http/organization.go @@ -6,6 +6,7 @@ import ( "github.com/gorilla/mux" "github.com/openinfradev/tks-api/internal/middleware/auth/request" + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/internal/usecase" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -79,11 +80,19 @@ func (h *OrganizationHandler) CreateOrganization(w http.ResponseWriter, r *http. // @Description Get organization list // @Accept json // @Produce json +// @Param limit query string false "pageSize" +// @Param page query string false "pageNumber" +// @Param soertColumn query string false "sortColumn" +// @Param sortOrder query string false "sortOrder" +// @Param filters query []string false "filters" // @Success 200 {object} []domain.ListOrganizationBody // @Router /organizations [get] // @Security JWT func (h *OrganizationHandler) GetOrganizations(w http.ResponseWriter, r *http.Request) { - organizations, err := h.usecase.Fetch() + urlParams := r.URL.Query() + pg := pagination.NewPagination(&urlParams) + + organizations, err := h.usecase.Fetch(pg) if err != nil { log.ErrorfWithContext(r.Context(), "error is :%s(%T)", err.Error(), err) @@ -102,6 +111,10 @@ func (h *OrganizationHandler) GetOrganizations(w http.ResponseWriter, r *http.Re log.InfoWithContext(r.Context(), organization) } + if err := domain.Map(*pg, &out.Pagination); err != nil { + log.InfoWithContext(r.Context(), err) + } + ResponseJSON(w, r, http.StatusOK, out) } diff --git a/internal/delivery/http/stack-template.go b/internal/delivery/http/stack-template.go index fa2a898d..f1a017dd 100644 --- a/internal/delivery/http/stack-template.go +++ b/internal/delivery/http/stack-template.go @@ -7,6 +7,7 @@ import ( "github.com/google/uuid" "github.com/gorilla/mux" + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/internal/usecase" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -44,11 +45,19 @@ func (h *StackTemplateHandler) CreateStackTemplate(w http.ResponseWriter, r *htt // @Description Get StackTemplates // @Accept json // @Produce json +// @Param limit query string false "pageSize" +// @Param page query string false "pageNumber" +// @Param soertColumn query string false "sortColumn" +// @Param sortOrder query string false "sortOrder" +// @Param filters query []string false "filters" // @Success 200 {object} domain.GetStackTemplatesResponse // @Router /stack-templates [get] // @Security JWT func (h *StackTemplateHandler) GetStackTemplates(w http.ResponseWriter, r *http.Request) { - stackTemplates, err := h.usecase.Fetch(r.Context()) + urlParams := r.URL.Query() + pg := pagination.NewPagination(&urlParams) + + stackTemplates, err := h.usecase.Fetch(r.Context(), pg) if err != nil { ErrorJSON(w, r, err) return @@ -67,6 +76,10 @@ func (h *StackTemplateHandler) GetStackTemplates(w http.ResponseWriter, r *http. } } + if err := domain.Map(*pg, &out.Pagination); err != nil { + log.InfoWithContext(r.Context(), err) + } + ResponseJSON(w, r, http.StatusOK, out) } diff --git a/internal/delivery/http/stack.go b/internal/delivery/http/stack.go index 386cc1e2..1c69d591 100644 --- a/internal/delivery/http/stack.go +++ b/internal/delivery/http/stack.go @@ -95,8 +95,7 @@ func (h *StackHandler) GetStacks(w http.ResponseWriter, r *http.Request) { urlParams := r.URL.Query() pg := pagination.NewPagination(&urlParams) - - stacks, err := h.usecase.Fetch(r.Context(), organizationId, &pg) + stacks, err := h.usecase.Fetch(r.Context(), organizationId, pg) if err != nil { ErrorJSON(w, r, err) return @@ -111,7 +110,7 @@ func (h *StackHandler) GetStacks(w http.ResponseWriter, r *http.Request) { } } - if err := domain.Map(pg, &out.Pagination); err != nil { + if err := domain.Map(*pg, &out.Pagination); err != nil { log.InfoWithContext(r.Context(), err) } diff --git a/internal/delivery/http/user.go b/internal/delivery/http/user.go index 36bcf2fb..787d07dc 100644 --- a/internal/delivery/http/user.go +++ b/internal/delivery/http/user.go @@ -7,6 +7,7 @@ import ( "github.com/gorilla/mux" "github.com/openinfradev/tks-api/internal/middleware/auth/request" + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/internal/usecase" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -157,6 +158,11 @@ func (u UserHandler) Get(w http.ResponseWriter, r *http.Request) { // @Accept json // @Produce json // @Param organizationId path string true "organizationId" +// @Param limit query string false "pageSize" +// @Param page query string false "pageNumber" +// @Param soertColumn query string false "sortColumn" +// @Param sortOrder query string false "sortOrder" +// @Param filters query []string false "filters" // @Success 200 {object} []domain.ListUserBody // @Router /organizations/{organizationId}/users [get] // @Security JWT @@ -168,7 +174,9 @@ func (u UserHandler) List(w http.ResponseWriter, r *http.Request) { return } - users, err := u.usecase.List(r.Context(), organizationId) + urlParams := r.URL.Query() + pg := pagination.NewPagination(&urlParams) + users, err := u.usecase.List(r.Context(), organizationId, pg) if err != nil { if _, status := httpErrors.ErrorResponse(err); status == http.StatusNotFound { ResponseJSON(w, r, http.StatusNoContent, domain.ListUserResponse{}) @@ -188,6 +196,10 @@ func (u UserHandler) List(w http.ResponseWriter, r *http.Request) { } } + if err := domain.Map(*pg, &out.Pagination); err != nil { + log.InfoWithContext(r.Context(), err) + } + ResponseJSON(w, r, http.StatusOK, out) } diff --git a/internal/pagination/pagination.go b/internal/pagination/pagination.go index bccf1a55..b8b43d3d 100644 --- a/internal/pagination/pagination.go +++ b/internal/pagination/pagination.go @@ -62,7 +62,7 @@ func (p *Pagination) GetFilter() []Filter { limit : 10, } */ -func NewPagination(urlParams *url.Values) Pagination { +func NewPagination(urlParams *url.Values) *Pagination { var pg Pagination pg.SortColumn = urlParams.Get("sortColumn") @@ -97,11 +97,11 @@ func NewPagination(urlParams *url.Values) Pagination { _ = json.Unmarshal([]byte(filter), &pg.Filters) } - return pg + return &pg } -func NewDefaultPagination() Pagination { - return Pagination{ +func NewDefaultPagination() *Pagination { + return &Pagination{ SortColumn: "created_at", SortOrder: "ASC", Page: 1, diff --git a/internal/repository/alert.go b/internal/repository/alert.go index 6dae27a9..2ab031e4 100644 --- a/internal/repository/alert.go +++ b/internal/repository/alert.go @@ -107,7 +107,9 @@ func (r *AlertRepository) Fetch(organizationId string, pg *pagination.Pagination var alerts []Alert var total int64 - // [TODO] filter + if pg == nil { + pg = pagination.NewDefaultPagination() + } r.db.Find(&alerts, "organization_id = ?", organizationId).Count(&total) pg.TotalRows = total diff --git a/internal/repository/app-group.go b/internal/repository/app-group.go index 9656e212..1d3afccd 100644 --- a/internal/repository/app-group.go +++ b/internal/repository/app-group.go @@ -8,13 +8,14 @@ import ( "gorm.io/gorm" "github.com/openinfradev/tks-api/internal/helper" + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/log" ) // Interfaces type IAppGroupRepository interface { - Fetch(clusterId domain.ClusterId) (res []domain.AppGroup, err error) + Fetch(clusterId domain.ClusterId, pg *pagination.Pagination) (res []domain.AppGroup, err error) Get(id domain.AppGroupId) (domain.AppGroup, error) Create(dto domain.AppGroup) (id domain.AppGroupId, err error) Update(dto domain.AppGroup) (err error) @@ -74,7 +75,7 @@ func (c *Application) BeforeCreate(tx *gorm.DB) (err error) { } // Logics -func (r *AppGroupRepository) Fetch(clusterId domain.ClusterId) (out []domain.AppGroup, err error) { +func (r *AppGroupRepository) Fetch(clusterId domain.ClusterId, pg *pagination.Pagination) (out []domain.AppGroup, err error) { var appGroups []AppGroup out = []domain.AppGroup{} diff --git a/internal/repository/app-serve-app.go b/internal/repository/app-serve-app.go index a2e40c27..124901a4 100644 --- a/internal/repository/app-serve-app.go +++ b/internal/repository/app-serve-app.go @@ -4,15 +4,15 @@ import ( "fmt" "time" + "github.com/openinfradev/tks-api/internal/pagination" + "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/log" "gorm.io/gorm" - - "github.com/openinfradev/tks-api/pkg/domain" ) type IAppServeAppRepository interface { CreateAppServeApp(app *domain.AppServeApp) (appId string, taskId string, err error) - GetAppServeApps(organizationId string, showAll bool) ([]domain.AppServeApp, error) + GetAppServeApps(organizationId string, showAll bool, pg *pagination.Pagination) ([]domain.AppServeApp, error) GetAppServeAppById(appId string) (*domain.AppServeApp, error) GetAppServeAppLatestTask(appId string) (*domain.AppServeAppTask, error) GetNumOfAppsOnStack(organizationId string, clusterId string) (int64, error) @@ -56,7 +56,7 @@ func (r *AppServeAppRepository) CreateTask( return task.ID, nil } -func (r *AppServeAppRepository) GetAppServeApps(organizationId string, showAll bool) ([]domain.AppServeApp, error) { +func (r *AppServeAppRepository) GetAppServeApps(organizationId string, showAll bool, pg *pagination.Pagination) ([]domain.AppServeApp, error) { var apps []domain.AppServeApp var clusters []Cluster diff --git a/internal/repository/cloud-account.go b/internal/repository/cloud-account.go index 51960663..bfa052db 100644 --- a/internal/repository/cloud-account.go +++ b/internal/repository/cloud-account.go @@ -2,11 +2,13 @@ package repository import ( "fmt" + "math" "github.com/google/uuid" "gorm.io/gorm" "gorm.io/gorm/clause" + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/pkg/domain" ) @@ -15,7 +17,7 @@ type ICloudAccountRepository interface { Get(cloudAccountId uuid.UUID) (domain.CloudAccount, error) GetByName(organizationId string, name string) (domain.CloudAccount, error) GetByAwsAccountId(awsAccountId string) (domain.CloudAccount, error) - Fetch(organizationId string) ([]domain.CloudAccount, error) + Fetch(organizationId string, pg *pagination.Pagination) ([]domain.CloudAccount, error) Create(dto domain.CloudAccount) (cloudAccountId uuid.UUID, err error) Update(dto domain.CloudAccount) (err error) Delete(cloudAccountId uuid.UUID) (err error) @@ -92,9 +94,21 @@ func (r *CloudAccountRepository) GetByAwsAccountId(awsAccountId string) (out dom return } -func (r *CloudAccountRepository) Fetch(organizationId string) (out []domain.CloudAccount, err error) { +func (r *CloudAccountRepository) Fetch(organizationId string, pg *pagination.Pagination) (out []domain.CloudAccount, err error) { var cloudAccounts []CloudAccount - res := r.db.Preload(clause.Associations).Find(&cloudAccounts, "organization_id = ? AND status != ?", organizationId, domain.CloudAccountStatus_DELETED) + var total int64 + + if pg == nil { + pg = pagination.NewDefaultPagination() + } + r.db.Find(&cloudAccounts, "organization_id = ? AND status != ?", organizationId, domain.CloudAccountStatus_DELETED).Count(&total) + + pg.TotalRows = total + pg.TotalPages = int(math.Ceil(float64(total) / float64(pg.Limit))) + + orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) + res := r.db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery). + Preload(clause.Associations).Find(&cloudAccounts, "organization_id = ? AND status != ?", organizationId, domain.CloudAccountStatus_DELETED) if res.Error != nil { return nil, res.Error } diff --git a/internal/repository/cluster.go b/internal/repository/cluster.go index b9647b4d..310b4d22 100644 --- a/internal/repository/cluster.go +++ b/internal/repository/cluster.go @@ -17,8 +17,8 @@ import ( // Interfaces type IClusterRepository interface { WithTrx(*gorm.DB) IClusterRepository - Fetch() (res []domain.Cluster, err error) - FetchByCloudAccountId(cloudAccountId uuid.UUID) (res []domain.Cluster, err error) + Fetch(pg *pagination.Pagination) (res []domain.Cluster, err error) + FetchByCloudAccountId(cloudAccountId uuid.UUID, pg *pagination.Pagination) (res []domain.Cluster, err error) FetchByOrganizationId(organizationId string, pg *pagination.Pagination) (res []domain.Cluster, err error) Get(id domain.ClusterId) (domain.Cluster, error) GetByName(organizationId string, name string) (domain.Cluster, error) @@ -84,9 +84,21 @@ func (r *ClusterRepository) WithTrx(trxHandle *gorm.DB) IClusterRepository { return r } -func (r *ClusterRepository) Fetch() (out []domain.Cluster, err error) { +func (r *ClusterRepository) Fetch(pg *pagination.Pagination) (out []domain.Cluster, err error) { var clusters []Cluster - res := r.db.Preload(clause.Associations).Find(&clusters) + var total int64 + + if pg == nil { + pg = pagination.NewDefaultPagination() + } + r.db.Find(&clusters).Count(&total) + + pg.TotalRows = total + pg.TotalPages = int(math.Ceil(float64(total) / float64(pg.Limit))) + + orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) + res := r.db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery). + Preload(clause.Associations).Find(&clusters) if res.Error != nil { return nil, res.Error } @@ -102,16 +114,14 @@ func (r *ClusterRepository) FetchByOrganizationId(organizationId string, pg *pag var total int64 if pg == nil { - *pg = pagination.NewDefaultPagination() + pg = pagination.NewDefaultPagination() } - r.db.Find(&clusters, "organization_id = ? AND status != ?", organizationId, domain.ClusterStatus_DELETED).Count(&total) pg.TotalRows = total pg.TotalPages = int(math.Ceil(float64(total) / float64(pg.Limit))) orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) - res := r.db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery). Preload(clause.Associations).Order("updated_at desc, created_at desc"). Find(&clusters, "organization_id = ? AND status != ?", organizationId, domain.ClusterStatus_DELETED) @@ -132,10 +142,21 @@ func (r *ClusterRepository) FetchByOrganizationId(organizationId string, pg *pag return } -func (r *ClusterRepository) FetchByCloudAccountId(cloudAccountId uuid.UUID) (out []domain.Cluster, err error) { +func (r *ClusterRepository) FetchByCloudAccountId(cloudAccountId uuid.UUID, pg *pagination.Pagination) (out []domain.Cluster, err error) { var clusters []Cluster + var total int64 + + if pg == nil { + pg = pagination.NewDefaultPagination() + } + r.db.Find(&clusters, "cloud_account_id = ?", cloudAccountId).Count(&total) - res := r.db.Preload("CloudAccount").Order("updated_at desc, created_at desc").Find(&clusters, "cloud_account_id = ?", cloudAccountId) + pg.TotalRows = total + pg.TotalPages = int(math.Ceil(float64(total) / float64(pg.Limit))) + + orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) + res := r.db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery). + Preload("CloudAccount").Order("updated_at desc, created_at desc").Find(&clusters, "cloud_account_id = ?", cloudAccountId) if res.Error != nil { return nil, res.Error diff --git a/internal/repository/organization.go b/internal/repository/organization.go index 4c7fce43..3f4e8773 100644 --- a/internal/repository/organization.go +++ b/internal/repository/organization.go @@ -1,18 +1,20 @@ package repository import ( - "github.com/openinfradev/tks-api/pkg/log" + "fmt" + "math" "github.com/google/uuid" - "gorm.io/gorm" - + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/pkg/domain" + "github.com/openinfradev/tks-api/pkg/log" + "gorm.io/gorm" ) // Interfaces type IOrganizationRepository interface { Create(organizationId string, name string, creator uuid.UUID, phone string, description string) (domain.Organization, error) - Fetch() (res *[]domain.Organization, err error) + Fetch(pg *pagination.Pagination) (res *[]domain.Organization, err error) Get(organizationId string) (res domain.Organization, err error) Update(organizationId string, in domain.UpdateOrganizationRequest) (domain.Organization, error) UpdatePrimaryClusterId(organizationId string, primaryClusterId string) error @@ -69,11 +71,21 @@ func (r *OrganizationRepository) Create(organizationId string, name string, crea return r.reflect(organization), nil } -func (r *OrganizationRepository) Fetch() (*[]domain.Organization, error) { +func (r *OrganizationRepository) Fetch(pg *pagination.Pagination) (*[]domain.Organization, error) { var organizations []Organization var out []domain.Organization + var total int64 + + if pg == nil { + pg = pagination.NewDefaultPagination() + } + r.db.Find(&organizations).Count(&total) + + pg.TotalRows = total + pg.TotalPages = int(math.Ceil(float64(total) / float64(pg.Limit))) - res := r.db.Find(&organizations) + orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) + res := r.db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery).Find(&organizations) if res.Error != nil { log.Errorf("error is :%s(%T)", res.Error.Error(), res.Error) return nil, res.Error diff --git a/internal/repository/stack-template.go b/internal/repository/stack-template.go index e82b40ef..460b66c6 100644 --- a/internal/repository/stack-template.go +++ b/internal/repository/stack-template.go @@ -1,18 +1,22 @@ package repository import ( + "fmt" + "math" + "github.com/google/uuid" "gorm.io/datatypes" "gorm.io/gorm" "gorm.io/gorm/clause" + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/pkg/domain" ) // Interfaces type IStackTemplateRepository interface { Get(stackTemplateId uuid.UUID) (domain.StackTemplate, error) - Fetch() ([]domain.StackTemplate, error) + Fetch(pg *pagination.Pagination) ([]domain.StackTemplate, error) Create(dto domain.StackTemplate) (stackTemplateId uuid.UUID, err error) Update(dto domain.StackTemplate) (err error) Delete(dto domain.StackTemplate) (err error) @@ -67,9 +71,21 @@ func (r *StackTemplateRepository) Get(stackTemplateId uuid.UUID) (out domain.Sta } // [TODO] organizationId 별로 생성하지 않고, 하나의 stackTemplate 을 모든 organization 에서 재사용한다. ( 5월 한정, 추후 rearchitecture 필요) -func (r *StackTemplateRepository) Fetch() (out []domain.StackTemplate, err error) { +func (r *StackTemplateRepository) Fetch(pg *pagination.Pagination) (out []domain.StackTemplate, err error) { var stackTemplates []StackTemplate - res := r.db.Preload(clause.Associations).Find(&stackTemplates) + var total int64 + + if pg == nil { + pg = pagination.NewDefaultPagination() + } + r.db.Find(&stackTemplates).Count(&total) + + pg.TotalRows = total + pg.TotalPages = int(math.Ceil(float64(total) / float64(pg.Limit))) + + orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) + res := r.db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery). + Preload(clause.Associations).Find(&stackTemplates) if res.Error != nil { return nil, res.Error } diff --git a/internal/repository/user.go b/internal/repository/user.go index 2c3f91f7..bf8857f2 100644 --- a/internal/repository/user.go +++ b/internal/repository/user.go @@ -1,14 +1,16 @@ package repository import ( + "fmt" + "math" "time" "github.com/google/uuid" - "github.com/openinfradev/tks-api/pkg/httpErrors" - "gorm.io/gorm" - + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/pkg/domain" + "github.com/openinfradev/tks-api/pkg/httpErrors" "github.com/openinfradev/tks-api/pkg/log" + "gorm.io/gorm" ) // Interface @@ -16,7 +18,7 @@ type IUserRepository interface { Create(accountId string, organizationId string, password string, name string) (domain.User, error) CreateWithUuid(uuid uuid.UUID, accountId string, name string, password string, email string, department string, description string, organizationId string, roleId uuid.UUID) (domain.User, error) - List(...FilterFunc) (out *[]domain.User, err error) + List(pg *pagination.Pagination, filters ...FilterFunc) (out *[]domain.User, err error) Get(accountId string, organizationId string) (domain.User, error) GetByUuid(userId uuid.UUID) (domain.User, error) UpdateWithUuid(uuid uuid.UUID, accountId string, name string, password string, roleId uuid.UUID, email string, @@ -140,11 +142,24 @@ func (r *UserRepository) NameFilter(name string) FilterFunc { return user.Where("name = ?", name) } } -func (r *UserRepository) List(filters ...FilterFunc) (*[]domain.User, error) { - var users []User + +func (r *UserRepository) List(pg *pagination.Pagination, filters ...FilterFunc) (*[]domain.User, error) { var res *gorm.DB + var users []User + var total int64 + + if pg == nil { + pg = pagination.NewDefaultPagination() + } + if filters == nil { - res = r.db.Model(&User{}).Preload("Organization").Preload("Role").Find(&users) + r.db.Find(&users).Count(&total) + + pg.TotalRows = total + pg.TotalPages = int(math.Ceil(float64(total) / float64(pg.Limit))) + orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) + res = r.db.Model(&User{}).Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery). + Preload("Organization").Preload("Role").Find(&users) } else { combinedFilter := func(filters ...FilterFunc) FilterFunc { return func(user *gorm.DB) *gorm.DB { @@ -155,7 +170,14 @@ func (r *UserRepository) List(filters ...FilterFunc) (*[]domain.User, error) { } } cFunc := combinedFilter(filters...) - res = cFunc(r.db.Model(&User{}).Preload("Organization").Preload("Role")).Find(&users) + cFunc(r.db.Model(&User{})).Find(&total) + + pg.TotalRows = total + pg.TotalPages = int(math.Ceil(float64(total) / float64(pg.Limit))) + orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) + res = cFunc(r.db.Model(&User{}).Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery). + Preload("Organization").Preload("Role")).Find(&users) + } if res.Error != nil { log.Errorf("error is :%s(%T)", res.Error.Error(), res.Error) diff --git a/internal/usecase/alert.go b/internal/usecase/alert.go index ab88c141..fb46007f 100644 --- a/internal/usecase/alert.go +++ b/internal/usecase/alert.go @@ -51,7 +51,7 @@ func (u *AlertUsecase) Create(ctx context.Context, input domain.CreateAlertReque return fmt.Errorf("No data found") } - allClusters, err := u.clusterRepo.Fetch() + allClusters, err := u.clusterRepo.Fetch(nil) if err != nil { return fmt.Errorf("No clusters") } @@ -244,7 +244,7 @@ func (u *AlertUsecase) makeAdditionalInfo(alert *domain.Alert) { func (u *AlertUsecase) makeGrafanaUrl(ctx context.Context, primaryCluster domain.Cluster, alert domain.CreateAlertRequestAlert, clusterId domain.ClusterId) (url string) { primaryGrafanaEndpoint := "" - appGroups, err := u.appGroupRepo.Fetch(primaryCluster.ID) + appGroups, err := u.appGroupRepo.Fetch(primaryCluster.ID, nil) if err == nil { for _, appGroup := range appGroups { if appGroup.AppGroupType == domain.AppGroupType_LMA { diff --git a/internal/usecase/app-group.go b/internal/usecase/app-group.go index fd48beb2..14eab49c 100644 --- a/internal/usecase/app-group.go +++ b/internal/usecase/app-group.go @@ -6,7 +6,7 @@ import ( "strings" "github.com/openinfradev/tks-api/internal/middleware/auth/request" - + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/internal/repository" argowf "github.com/openinfradev/tks-api/pkg/argo-client" "github.com/openinfradev/tks-api/pkg/domain" @@ -17,7 +17,7 @@ import ( ) type IAppGroupUsecase interface { - Fetch(ctx context.Context, clusterId domain.ClusterId) ([]domain.AppGroup, error) + Fetch(ctx context.Context, clusterId domain.ClusterId, pg *pagination.Pagination) ([]domain.AppGroup, error) Create(ctx context.Context, dto domain.AppGroup) (id domain.AppGroupId, err error) Get(ctx context.Context, id domain.AppGroupId) (out domain.AppGroup, err error) Delete(ctx context.Context, organizationId string, id domain.AppGroupId) (err error) @@ -39,8 +39,8 @@ func NewAppGroupUsecase(r repository.Repository, argoClient argowf.ArgoClient) I } } -func (u *AppGroupUsecase) Fetch(ctx context.Context, clusterId domain.ClusterId) (out []domain.AppGroup, err error) { - out, err = u.repo.Fetch(clusterId) +func (u *AppGroupUsecase) Fetch(ctx context.Context, clusterId domain.ClusterId, pg *pagination.Pagination) (out []domain.AppGroup, err error) { + out, err = u.repo.Fetch(clusterId, pg) if err != nil { return nil, err } @@ -60,7 +60,7 @@ func (u *AppGroupUsecase) Create(ctx context.Context, dto domain.AppGroup) (id d return "", httpErrors.NewBadRequestError(err, "AG_NOT_FOUND_CLUSTER", "") } - resAppGroups, err := u.repo.Fetch(dto.ClusterId) + resAppGroups, err := u.repo.Fetch(dto.ClusterId, nil) if err != nil { return "", httpErrors.NewBadRequestError(err, "AG_NOT_FOUND_APPGROUP", "") } diff --git a/internal/usecase/app-serve-app.go b/internal/usecase/app-serve-app.go index 1a2bc463..77111f02 100644 --- a/internal/usecase/app-serve-app.go +++ b/internal/usecase/app-serve-app.go @@ -10,6 +10,7 @@ import ( "github.com/pkg/errors" "github.com/spf13/viper" + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/internal/repository" argowf "github.com/openinfradev/tks-api/pkg/argo-client" "github.com/openinfradev/tks-api/pkg/domain" @@ -19,7 +20,7 @@ import ( type IAppServeAppUsecase interface { CreateAppServeApp(app *domain.AppServeApp) (appId string, taskId string, err error) - GetAppServeApps(organizationId string, showAll bool) ([]domain.AppServeApp, error) + GetAppServeApps(organizationId string, showAll bool, pg *pagination.Pagination) ([]domain.AppServeApp, error) GetAppServeAppById(appId string) (*domain.AppServeApp, error) GetAppServeAppLatestTask(appId string) (*domain.AppServeAppTask, error) GetNumOfAppsOnStack(organizationId string, clusterId string) (int64, error) @@ -142,8 +143,8 @@ func (u *AppServeAppUsecase) CreateAppServeApp(app *domain.AppServeApp) (string, return appId, app.Name, nil } -func (u *AppServeAppUsecase) GetAppServeApps(organizationId string, showAll bool) ([]domain.AppServeApp, error) { - apps, err := u.repo.GetAppServeApps(organizationId, showAll) +func (u *AppServeAppUsecase) GetAppServeApps(organizationId string, showAll bool, pg *pagination.Pagination) ([]domain.AppServeApp, error) { + apps, err := u.repo.GetAppServeApps(organizationId, showAll, pg) if err != nil { fmt.Println(apps) } diff --git a/internal/usecase/auth.go b/internal/usecase/auth.go index 94438339..668f665b 100644 --- a/internal/usecase/auth.go +++ b/internal/usecase/auth.go @@ -104,7 +104,7 @@ func (u *AuthUsecase) Logout(accessToken string, organizationName string) error return nil } func (u *AuthUsecase) FindId(code string, email string, userName string, organizationId string) (string, error) { - users, err := u.userRepository.List(u.userRepository.OrganizationFilter(organizationId), + users, err := u.userRepository.List(nil, u.userRepository.OrganizationFilter(organizationId), u.userRepository.NameFilter(userName), u.userRepository.EmailFilter(email)) if err != nil && users == nil { return "", httpErrors.NewBadRequestError(err, "A_INVALID_ID", "") @@ -134,7 +134,7 @@ func (u *AuthUsecase) FindId(code string, email string, userName string, organiz } func (u *AuthUsecase) FindPassword(code string, accountId string, email string, userName string, organizationId string) error { - users, err := u.userRepository.List(u.userRepository.OrganizationFilter(organizationId), + users, err := u.userRepository.List(nil, u.userRepository.OrganizationFilter(organizationId), u.userRepository.AccountIdFilter(accountId), u.userRepository.NameFilter(userName), u.userRepository.EmailFilter(email)) if err != nil && users == nil { @@ -198,10 +198,10 @@ func (u *AuthUsecase) VerifyIdentity(accountId string, email string, userName st var err error if accountId == "" { - users, err = u.userRepository.List(u.userRepository.OrganizationFilter(organizationId), + users, err = u.userRepository.List(nil, u.userRepository.OrganizationFilter(organizationId), u.userRepository.NameFilter(userName), u.userRepository.EmailFilter(email)) } else { - users, err = u.userRepository.List(u.userRepository.OrganizationFilter(organizationId), + users, err = u.userRepository.List(nil, u.userRepository.OrganizationFilter(organizationId), u.userRepository.AccountIdFilter(accountId), u.userRepository.NameFilter(userName), u.userRepository.EmailFilter(email)) } @@ -265,7 +265,7 @@ func (u *AuthUsecase) SingleSignOut(organizationId string) (string, []*http.Cook return "", nil, err } - appGroupsInPrimaryCluster, err := u.appgroupRepository.Fetch(domain.ClusterId(organization.PrimaryClusterId)) + appGroupsInPrimaryCluster, err := u.appgroupRepository.Fetch(domain.ClusterId(organization.PrimaryClusterId), nil) if err != nil { return "", nil, err } diff --git a/internal/usecase/cloud-account.go b/internal/usecase/cloud-account.go index 6f4f141b..713f953d 100644 --- a/internal/usecase/cloud-account.go +++ b/internal/usecase/cloud-account.go @@ -8,6 +8,7 @@ import ( "github.com/openinfradev/tks-api/internal/middleware/auth/request" "github.com/google/uuid" + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/internal/repository" argowf "github.com/openinfradev/tks-api/pkg/argo-client" "github.com/openinfradev/tks-api/pkg/domain" @@ -23,7 +24,7 @@ type ICloudAccountUsecase interface { Get(ctx context.Context, cloudAccountId uuid.UUID) (domain.CloudAccount, error) GetByName(ctx context.Context, organizationId string, name string) (domain.CloudAccount, error) GetByAwsAccountId(ctx context.Context, awsAccountId string) (domain.CloudAccount, error) - Fetch(ctx context.Context, organizationId string) ([]domain.CloudAccount, error) + Fetch(ctx context.Context, organizationId string, pg *pagination.Pagination) ([]domain.CloudAccount, error) Create(ctx context.Context, dto domain.CloudAccount) (cloudAccountId uuid.UUID, err error) Update(ctx context.Context, dto domain.CloudAccount) error Delete(ctx context.Context, dto domain.CloudAccount) error @@ -151,8 +152,8 @@ func (u *CloudAccountUsecase) GetByAwsAccountId(ctx context.Context, awsAccountI return } -func (u *CloudAccountUsecase) Fetch(ctx context.Context, organizationId string) (cloudAccounts []domain.CloudAccount, err error) { - cloudAccounts, err = u.repo.Fetch(organizationId) +func (u *CloudAccountUsecase) Fetch(ctx context.Context, organizationId string, pg *pagination.Pagination) (cloudAccounts []domain.CloudAccount, err error) { + cloudAccounts, err = u.repo.Fetch(organizationId, pg) if err != nil { return nil, err } @@ -230,7 +231,7 @@ func (u *CloudAccountUsecase) DeleteForce(ctx context.Context, cloudAccountId uu func (u *CloudAccountUsecase) getClusterCnt(cloudAccountId uuid.UUID) (cnt int) { cnt = 0 - clusters, err := u.clusterRepo.FetchByCloudAccountId(cloudAccountId) + clusters, err := u.clusterRepo.FetchByCloudAccountId(cloudAccountId, nil) if err != nil { log.Error("Failed to get clusters by cloudAccountId. err : ", err) return cnt diff --git a/internal/usecase/cluster.go b/internal/usecase/cluster.go index 0bcd8e21..8048c068 100644 --- a/internal/usecase/cluster.go +++ b/internal/usecase/cluster.go @@ -8,6 +8,7 @@ import ( "github.com/openinfradev/tks-api/internal/middleware/auth/request" "github.com/google/uuid" + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/internal/repository" argowf "github.com/openinfradev/tks-api/pkg/argo-client" "github.com/openinfradev/tks-api/pkg/domain" @@ -21,8 +22,8 @@ import ( type IClusterUsecase interface { WithTrx(*gorm.DB) IClusterUsecase - Fetch(ctx context.Context, organizationId string) ([]domain.Cluster, error) - FetchByCloudAccountId(ctx context.Context, cloudAccountId uuid.UUID) (out []domain.Cluster, err error) + Fetch(ctx context.Context, organizationId string, pg *pagination.Pagination) ([]domain.Cluster, error) + FetchByCloudAccountId(ctx context.Context, cloudAccountId uuid.UUID, pg *pagination.Pagination) (out []domain.Cluster, err error) Create(ctx context.Context, dto domain.Cluster) (clusterId domain.ClusterId, err error) Get(ctx context.Context, clusterId domain.ClusterId) (out domain.Cluster, err error) GetClusterSiteValues(ctx context.Context, clusterId domain.ClusterId) (out domain.ClusterSiteValuesResponse, err error) @@ -83,12 +84,12 @@ func (u *ClusterUsecase) WithTrx(trxHandle *gorm.DB) IClusterUsecase { return u } -func (u *ClusterUsecase) Fetch(ctx context.Context, organizationId string) (out []domain.Cluster, err error) { +func (u *ClusterUsecase) Fetch(ctx context.Context, organizationId string, pg *pagination.Pagination) (out []domain.Cluster, err error) { if organizationId == "" { // [TODO] 사용자가 속한 organization 리스트 - out, err = u.repo.Fetch() + out, err = u.repo.Fetch(pg) } else { - out, err = u.repo.FetchByOrganizationId(organizationId, nil) + out, err = u.repo.FetchByOrganizationId(organizationId, pg) } if err != nil { @@ -97,12 +98,12 @@ func (u *ClusterUsecase) Fetch(ctx context.Context, organizationId string) (out return out, nil } -func (u *ClusterUsecase) FetchByCloudAccountId(ctx context.Context, cloudAccountId uuid.UUID) (out []domain.Cluster, err error) { +func (u *ClusterUsecase) FetchByCloudAccountId(ctx context.Context, cloudAccountId uuid.UUID, pg *pagination.Pagination) (out []domain.Cluster, err error) { if cloudAccountId == uuid.Nil { return nil, fmt.Errorf("Invalid cloudAccountId") } - out, err = u.repo.Fetch() + out, err = u.repo.Fetch(pg) if err != nil { return nil, err @@ -122,7 +123,7 @@ func (u *ClusterUsecase) Create(ctx context.Context, dto domain.Cluster) (cluste } // check cloudAccount - cloudAccounts, err := u.cloudAccountRepo.Fetch(dto.OrganizationId) + cloudAccounts, err := u.cloudAccountRepo.Fetch(dto.OrganizationId, nil) if err != nil { return "", httpErrors.NewBadRequestError(fmt.Errorf("Failed to get cloudAccounts"), "", "") } @@ -220,7 +221,7 @@ func (u *ClusterUsecase) Delete(ctx context.Context, clusterId domain.ClusterId) return fmt.Errorf("The cluster can not be deleted. cluster status : %s", cluster.Status) } - resAppGroups, err := u.appGroupRepo.Fetch(clusterId) + resAppGroups, err := u.appGroupRepo.Fetch(clusterId, nil) if err != nil { return errors.Wrap(err, "Failed to get appgroup") } diff --git a/internal/usecase/dashboard.go b/internal/usecase/dashboard.go index f6e3024d..1c4b6d79 100644 --- a/internal/usecase/dashboard.go +++ b/internal/usecase/dashboard.go @@ -96,7 +96,7 @@ func (u *DashboardUsecase) GetStacks(ctx context.Context, organizationId string) } for _, cluster := range clusters { - appGroups, err := u.appGroupRepo.Fetch(cluster.ID) + appGroups, err := u.appGroupRepo.Fetch(cluster.ID, nil) if err != nil { return nil, err } diff --git a/internal/usecase/organization.go b/internal/usecase/organization.go index 108c5bff..3e4cc97d 100644 --- a/internal/usecase/organization.go +++ b/internal/usecase/organization.go @@ -5,22 +5,22 @@ import ( "fmt" "strings" + "github.com/google/uuid" "github.com/openinfradev/tks-api/internal/helper" "github.com/openinfradev/tks-api/internal/keycloak" - "github.com/openinfradev/tks-api/pkg/httpErrors" - "github.com/pkg/errors" - "github.com/spf13/viper" - - "github.com/google/uuid" + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/internal/repository" argowf "github.com/openinfradev/tks-api/pkg/argo-client" "github.com/openinfradev/tks-api/pkg/domain" + "github.com/openinfradev/tks-api/pkg/httpErrors" "github.com/openinfradev/tks-api/pkg/log" + "github.com/pkg/errors" + "github.com/spf13/viper" ) type IOrganizationUsecase interface { Create(context.Context, *domain.Organization) (organizationId string, err error) - Fetch() (*[]domain.Organization, error) + Fetch(pg *pagination.Pagination) (*[]domain.Organization, error) Get(organizationId string) (domain.Organization, error) Update(organizationId string, in domain.UpdateOrganizationRequest) (domain.Organization, error) UpdatePrimaryClusterId(organizationId string, clusterId string) (err error) @@ -80,8 +80,8 @@ func (u *OrganizationUsecase) Create(ctx context.Context, in *domain.Organizatio return organizationId, nil } -func (u *OrganizationUsecase) Fetch() (out *[]domain.Organization, err error) { - organizations, err := u.repo.Fetch() +func (u *OrganizationUsecase) Fetch(pg *pagination.Pagination) (out *[]domain.Organization, err error) { + organizations, err := u.repo.Fetch(pg) if err != nil { return nil, err } diff --git a/internal/usecase/stack-template.go b/internal/usecase/stack-template.go index c0078f94..4e2731ac 100644 --- a/internal/usecase/stack-template.go +++ b/internal/usecase/stack-template.go @@ -4,13 +4,14 @@ import ( "context" "github.com/google/uuid" + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/internal/repository" "github.com/openinfradev/tks-api/pkg/domain" ) type IStackTemplateUsecase interface { Get(ctx context.Context, stackTemplate uuid.UUID) (domain.StackTemplate, error) - Fetch(ctx context.Context) ([]domain.StackTemplate, error) + Fetch(ctx context.Context, pg *pagination.Pagination) ([]domain.StackTemplate, error) Create(ctx context.Context, dto domain.StackTemplate) (stackTemplate uuid.UUID, err error) Update(ctx context.Context, dto domain.StackTemplate) error Delete(ctx context.Context, dto domain.StackTemplate) error @@ -42,8 +43,8 @@ func (u *StackTemplateUsecase) Get(ctx context.Context, stackTemplate uuid.UUID) return } -func (u *StackTemplateUsecase) Fetch(ctx context.Context) (res []domain.StackTemplate, err error) { - res, err = u.repo.Fetch() +func (u *StackTemplateUsecase) Fetch(ctx context.Context, pg *pagination.Pagination) (res []domain.StackTemplate, err error) { + res, err = u.repo.Fetch(pg) if err != nil { return nil, err } diff --git a/internal/usecase/stack.go b/internal/usecase/stack.go index 08c46bf5..f3b69c2b 100644 --- a/internal/usecase/stack.go +++ b/internal/usecase/stack.go @@ -6,10 +6,9 @@ import ( "strings" "time" - "github.com/openinfradev/tks-api/internal/middleware/auth/request" - "github.com/openinfradev/tks-api/internal/helper" "github.com/openinfradev/tks-api/internal/kubernetes" + "github.com/openinfradev/tks-api/internal/middleware/auth/request" "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/internal/repository" argowf "github.com/openinfradev/tks-api/pkg/argo-client" @@ -160,7 +159,7 @@ func (u *StackUsecase) Get(ctx context.Context, stackId domain.StackId) (out dom return out, httpErrors.NewInternalServerError(errors.Wrap(err, fmt.Sprintf("Failed to get organization for clusterId %s", cluster.OrganizationId)), "S_FAILED_FETCH_ORGANIZATION", "") } - appGroups, err := u.appGroupRepo.Fetch(domain.ClusterId(stackId)) + appGroups, err := u.appGroupRepo.Fetch(domain.ClusterId(stackId), nil) if err != nil { return out, err } @@ -170,7 +169,7 @@ func (u *StackUsecase) Get(ctx context.Context, stackId domain.StackId) (out dom out.PrimaryCluster = true } - appGroupsInPrimaryCluster, err := u.appGroupRepo.Fetch(domain.ClusterId(organization.PrimaryClusterId)) + appGroupsInPrimaryCluster, err := u.appGroupRepo.Fetch(domain.ClusterId(organization.PrimaryClusterId), nil) if err != nil { return out, err } @@ -199,7 +198,7 @@ func (u *StackUsecase) GetByName(ctx context.Context, organizationId string, nam return out, err } - appGroups, err := u.appGroupRepo.Fetch(cluster.ID) + appGroups, err := u.appGroupRepo.Fetch(cluster.ID, nil) if err != nil { return out, err } @@ -220,7 +219,7 @@ func (u *StackUsecase) Fetch(ctx context.Context, organizationId string, pg *pag } for _, cluster := range clusters { - appGroups, err := u.appGroupRepo.Fetch(cluster.ID) + appGroups, err := u.appGroupRepo.Fetch(cluster.ID, nil) if err != nil { return nil, err } @@ -280,7 +279,7 @@ func (u *StackUsecase) Delete(ctx context.Context, dto domain.Stack) (err error) } // 지우려고 하는 stack 이 primary cluster 라면, organization 내에 cluster 가 자기 자신만 남아있을 경우이다. - organizations, err := u.organizationRepo.Fetch() + organizations, err := u.organizationRepo.Fetch(nil) if err != nil { return errors.Wrap(err, "Failed to get organizations") } @@ -303,7 +302,7 @@ func (u *StackUsecase) Delete(ctx context.Context, dto domain.Stack) (err error) break } } - appGroups, err := u.appGroupRepo.Fetch(domain.ClusterId(dto.ID)) + appGroups, err := u.appGroupRepo.Fetch(domain.ClusterId(dto.ID), nil) if err != nil { return errors.Wrap(err, "Failed to get appGroups") } @@ -436,7 +435,7 @@ func (u *StackUsecase) GetStepStatus(ctx context.Context, stackId domain.StackId }) } - appGroups, err := u.appGroupRepo.Fetch(domain.ClusterId(stackId)) + appGroups, err := u.appGroupRepo.Fetch(domain.ClusterId(stackId), nil) for _, appGroup := range appGroups { for i, step := range out { if step.Stage == appGroup.AppGroupType.String() { diff --git a/internal/usecase/user.go b/internal/usecase/user.go index 87d2a6f9..41147aa2 100644 --- a/internal/usecase/user.go +++ b/internal/usecase/user.go @@ -5,13 +5,13 @@ import ( "fmt" "net/http" - "github.com/openinfradev/tks-api/internal/aws/ses" - "github.com/openinfradev/tks-api/internal/middleware/auth/request" - "github.com/Nerzal/gocloak/v13" "github.com/google/uuid" + "github.com/openinfradev/tks-api/internal/aws/ses" "github.com/openinfradev/tks-api/internal/helper" "github.com/openinfradev/tks-api/internal/keycloak" + "github.com/openinfradev/tks-api/internal/middleware/auth/request" + "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/internal/repository" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -24,7 +24,7 @@ type IUserUsecase interface { DeleteAdmin(organizationId string) error DeleteAll(ctx context.Context, organizationId string) error Create(ctx context.Context, user *domain.User) (*domain.User, error) - List(ctx context.Context, organizationId string) (*[]domain.User, error) + List(ctx context.Context, organizationId string, pg *pagination.Pagination) (*[]domain.User, error) Get(userId uuid.UUID) (*domain.User, error) Update(ctx context.Context, userId uuid.UUID, user *domain.User) (*domain.User, error) ResetPassword(userId uuid.UUID) error @@ -321,8 +321,8 @@ func (u *UserUsecase) UpdatePasswordByAccountId(ctx context.Context, accountId s return nil } -func (u *UserUsecase) List(ctx context.Context, organizationId string) (*[]domain.User, error) { - users, err := u.userRepository.List(u.userRepository.OrganizationFilter(organizationId)) +func (u *UserUsecase) List(ctx context.Context, organizationId string, pg *pagination.Pagination) (*[]domain.User, error) { + users, err := u.userRepository.List(pg, u.userRepository.OrganizationFilter(organizationId)) if err != nil { return nil, err } @@ -343,7 +343,7 @@ func (u *UserUsecase) Get(userId uuid.UUID) (*domain.User, error) { } func (u *UserUsecase) GetByAccountId(ctx context.Context, accountId string, organizationId string) (*domain.User, error) { - users, err := u.userRepository.List(u.userRepository.OrganizationFilter(organizationId), + users, err := u.userRepository.List(nil, u.userRepository.OrganizationFilter(organizationId), u.userRepository.AccountIdFilter(accountId)) if err != nil { return nil, err @@ -353,7 +353,7 @@ func (u *UserUsecase) GetByAccountId(ctx context.Context, accountId string, orga } func (u *UserUsecase) GetByEmail(ctx context.Context, email string, organizationId string) (*domain.User, error) { - users, err := u.userRepository.List(u.userRepository.OrganizationFilter(organizationId), + users, err := u.userRepository.List(nil, u.userRepository.OrganizationFilter(organizationId), u.userRepository.EmailFilter(email)) if err != nil { return nil, err @@ -395,7 +395,7 @@ func (u *UserUsecase) UpdateByAccountId(ctx context.Context, accountId string, u } } - users, err := u.userRepository.List(u.userRepository.OrganizationFilter(userInfo.GetOrganizationId()), + users, err := u.userRepository.List(nil, u.userRepository.OrganizationFilter(userInfo.GetOrganizationId()), u.userRepository.AccountIdFilter(accountId)) if err != nil { if _, code := httpErrors.ErrorResponse(err); code == http.StatusNotFound { @@ -551,7 +551,7 @@ func (u *UserUsecase) UpdateByAccountIdByAdmin(ctx context.Context, accountId st } } - users, err := u.userRepository.List(u.userRepository.OrganizationFilter(userInfo.GetOrganizationId()), + users, err := u.userRepository.List(nil, u.userRepository.OrganizationFilter(userInfo.GetOrganizationId()), u.userRepository.AccountIdFilter(accountId)) if err != nil { if _, code := httpErrors.ErrorResponse(err); code == http.StatusNotFound { diff --git a/pkg/domain/app-group.go b/pkg/domain/app-group.go index 9750f2e6..d4e3211d 100644 --- a/pkg/domain/app-group.go +++ b/pkg/domain/app-group.go @@ -184,7 +184,8 @@ type CreateApplicationRequest struct { } type GetAppGroupsResponse struct { - AppGroups []AppGroupResponse `json:"appGroups"` + AppGroups []AppGroupResponse `json:"appGroups"` + Pagination PaginationResponse `json:"pagination"` } type GetAppGroupResponse struct { diff --git a/pkg/domain/app-serve-app.go b/pkg/domain/app-serve-app.go index 525a4ce9..e59c33d0 100644 --- a/pkg/domain/app-serve-app.go +++ b/pkg/domain/app-serve-app.go @@ -159,7 +159,8 @@ type RollbackAppServeAppRequest struct { } type GetAppServeAppsResponse struct { - AppServeApps []AppServeApp `json:"appServeApps"` + AppServeApps []AppServeApp `json:"appServeApps"` + Pagination PaginationResponse `json:"pagination"` } type GetAppServeAppResponse struct { diff --git a/pkg/domain/cloud-account.go b/pkg/domain/cloud-account.go index a27002a5..981f7589 100644 --- a/pkg/domain/cloud-account.go +++ b/pkg/domain/cloud-account.go @@ -102,6 +102,7 @@ type SimpleCloudAccountResponse struct { type GetCloudAccountsResponse struct { CloudAccounts []CloudAccountResponse `json:"cloudAccounts"` + Pagination PaginationResponse `json:"pagination"` } type GetCloudAccountResponse struct { diff --git a/pkg/domain/cluster.go b/pkg/domain/cluster.go index ada7a8cf..ab9264ff 100644 --- a/pkg/domain/cluster.go +++ b/pkg/domain/cluster.go @@ -162,7 +162,8 @@ type ClusterSiteValuesResponse struct { } type GetClustersResponse struct { - Clusters []ClusterResponse `json:"clusters"` + Clusters []ClusterResponse `json:"clusters"` + Pagination PaginationResponse `json:"pagination"` } type GetClusterResponse struct { diff --git a/pkg/domain/organization.go b/pkg/domain/organization.go index d7801c88..6e3706da 100644 --- a/pkg/domain/organization.go +++ b/pkg/domain/organization.go @@ -88,6 +88,7 @@ type GetOrganizationResponse struct { } type ListOrganizationResponse struct { Organizations []ListOrganizationBody `json:"organizations"` + Pagination PaginationResponse `json:"pagination"` } type ListOrganizationBody struct { ID string `json:"id"` diff --git a/pkg/domain/stack-template.go b/pkg/domain/stack-template.go index 9cdc71e8..0be6ae35 100644 --- a/pkg/domain/stack-template.go +++ b/pkg/domain/stack-template.go @@ -65,6 +65,7 @@ type SimpleStackTemplateResponse struct { type GetStackTemplatesResponse struct { StackTemplates []StackTemplateResponse `json:"stackTemplates"` + Pagination PaginationResponse `json:"pagination"` } type GetStackTemplateResponse struct { diff --git a/pkg/domain/user.go b/pkg/domain/user.go index 2fc2a1b4..fbea7635 100644 --- a/pkg/domain/user.go +++ b/pkg/domain/user.go @@ -94,7 +94,8 @@ type GetUserResponse struct { } type ListUserResponse struct { - Users []ListUserBody `json:"users"` + Users []ListUserBody `json:"users"` + Pagination PaginationResponse `json:"pagination"` } type ListUserBody struct { ID string `json:"id"` From a86736e91aecc5dae22d4df502822d227666e960 Mon Sep 17 00:00:00 2001 From: Taekyu Date: Thu, 13 Jul 2023 18:04:25 +0900 Subject: [PATCH 27/54] feature. implementation --- .gitignore | 3 +- api/swagger/docs.go | 7 ++- api/swagger/swagger.json | 7 ++- api/swagger/swagger.yaml | 6 +- internal/delivery/http/alert.go | 9 +++ internal/helper/util.go | 10 +++ internal/pagination/pagination.go | 89 ++++++++++++++------------- internal/repository/alert.go | 22 +++---- internal/repository/app-group.go | 15 ++++- internal/repository/app-serve-app.go | 26 +++++--- internal/repository/cloud-account.go | 15 +++-- internal/repository/cluster.go | 59 +++++++----------- internal/repository/organization.go | 12 ++-- internal/repository/repository.go | 25 +++++++- internal/repository/stack-template.go | 44 ++++++++++--- internal/repository/user.go | 4 +- pkg/domain/pagination.go | 4 +- 17 files changed, 217 insertions(+), 140 deletions(-) diff --git a/.gitignore b/.gitignore index 634da0d9..7da128bd 100644 --- a/.gitignore +++ b/.gitignore @@ -8,8 +8,9 @@ *.njsproj *.sln *.sw? +*.sh web main output -vendor \ No newline at end of file +vendor diff --git a/api/swagger/docs.go b/api/swagger/docs.go index 4211d035..e36031ba 100644 --- a/api/swagger/docs.go +++ b/api/swagger/docs.go @@ -4768,8 +4768,11 @@ const docTemplate = `{ "column": { "type": "string" }, - "value": { - "type": "string" + "values": { + "type": "array", + "items": { + "type": "string" + } } } }, diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index d7df0b40..f49ea698 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -4761,8 +4761,11 @@ "column": { "type": "string" }, - "value": { - "type": "string" + "values": { + "type": "array", + "items": { + "type": "string" + } } } }, diff --git a/api/swagger/swagger.yaml b/api/swagger/swagger.yaml index ce331393..e78d1933 100644 --- a/api/swagger/swagger.yaml +++ b/api/swagger/swagger.yaml @@ -832,8 +832,10 @@ definitions: properties: column: type: string - value: - type: string + values: + items: + type: string + type: array type: object domain.FindIdRequest: properties: diff --git a/internal/delivery/http/alert.go b/internal/delivery/http/alert.go index 5e08e873..987dd89e 100644 --- a/internal/delivery/http/alert.go +++ b/internal/delivery/http/alert.go @@ -123,6 +123,15 @@ func (h *AlertHandler) GetAlerts(w http.ResponseWriter, r *http.Request) { if err := domain.Map(*pg, &out.Pagination); err != nil { log.InfoWithContext(r.Context(), err) } + /* + outFilters := make([]domain.FilterResponse, len(pg.Filters)) + for j, filter := range pg.Filters { + if err := domain.Map(filter, &outFilters[j]); err != nil { + log.InfoWithContext(r.Context(), err) + } + } + out.Pagination.Filters = outFilters + */ ResponseJSON(w, r, http.StatusOK, out) } diff --git a/internal/helper/util.go b/internal/helper/util.go index 4da8fa44..c6e92f2a 100644 --- a/internal/helper/util.go +++ b/internal/helper/util.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "math/big" + "regexp" "strconv" "strings" "time" @@ -70,3 +71,12 @@ func SplitAddress(url string) (address string, port int) { return } + +var matchFirstCap = regexp.MustCompile("(.)([A-Z][a-z]+)") +var matchAllCap = regexp.MustCompile("([a-z0-9])([A-Z])") + +func ToSnakeCase(str string) string { + snake := matchFirstCap.ReplaceAllString(str, "${1}_${2}") + snake = matchAllCap.ReplaceAllString(snake, "${1}_${2}") + return strings.ToLower(snake) +} diff --git a/internal/pagination/pagination.go b/internal/pagination/pagination.go index b8b43d3d..7b839c16 100644 --- a/internal/pagination/pagination.go +++ b/internal/pagination/pagination.go @@ -1,11 +1,18 @@ package pagination import ( - "encoding/json" "net/url" "strconv" + "strings" + + "github.com/openinfradev/tks-api/internal/helper" ) +const SORT_COLUMN = "sortColumn" +const SORT_ORDER = "sortOrder" +const PAGE_NUMBER = "pageNumber" +const PAGE_SIZE = "pageSize" + type Pagination struct { Limit int Page int @@ -18,7 +25,7 @@ type Pagination struct { type Filter struct { Column string - Value string + Values []string } var DEFAULT_LIMIT = 10 @@ -50,54 +57,50 @@ func (p *Pagination) GetSortOrder() string { return p.SortOrder } -func (p *Pagination) GetFilter() []Filter { +func (p *Pagination) GetFilters() []Filter { return p.Filters } -/* - { - sortingColumn : "id", - order : "ASC", - page : 1, - limit : 10, - } -*/ func NewPagination(urlParams *url.Values) *Pagination { - var pg Pagination - - pg.SortColumn = urlParams.Get("sortColumn") - if pg.SortColumn == "" { - pg.SortColumn = "created_at" - } - pg.SortOrder = urlParams.Get("sortOrder") - if pg.SortOrder == "" { - pg.SortOrder = "ASC" - } - - page := urlParams.Get("pageNumber") - if page == "" { - pg.Page = 1 - } else { - pg.Page, _ = strconv.Atoi(page) - } - - limit := urlParams.Get("pageSize") - if limit == "" { - pg.Limit = DEFAULT_LIMIT - } else { - limitNum, err := strconv.Atoi(limit) - if err == nil { - pg.Limit = limitNum + pg := NewDefaultPagination() + + for key, value := range *urlParams { + switch key { + case SORT_COLUMN: + if value[0] == "" { + pg.SortColumn = "created_at" + } else { + pg.SortColumn = value[0] + } + case SORT_ORDER: + if value[0] == "" { + pg.SortOrder = "ASC" + } else { + pg.SortOrder = value[0] + } + case PAGE_NUMBER: + if value[0] == "" { + pg.Page = 1 + } else { + pg.Page, _ = strconv.Atoi(value[0]) + } + case PAGE_SIZE: + if value[0] == "" { + pg.Page = DEFAULT_LIMIT + } else { + if limitNum, err := strconv.Atoi(value[0]); err == nil { + pg.Limit = limitNum + } + } + default: + pg.Filters = append(pg.Filters, Filter{ + Column: helper.ToSnakeCase(strings.Replace(key, "[]", "", -1)), + Values: value, + }) } } - // [TODO] filter - filter := urlParams.Get("filter") - if filter != "" { - _ = json.Unmarshal([]byte(filter), &pg.Filters) - } - - return &pg + return pg } func NewDefaultPagination() *Pagination { diff --git a/internal/repository/alert.go b/internal/repository/alert.go index 2ab031e4..eef5b64a 100644 --- a/internal/repository/alert.go +++ b/internal/repository/alert.go @@ -12,7 +12,6 @@ import ( "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/pkg/domain" - "github.com/openinfradev/tks-api/pkg/log" ) // Interfaces @@ -105,29 +104,24 @@ func (r *AlertRepository) GetByName(organizationId string, name string) (out dom func (r *AlertRepository) Fetch(organizationId string, pg *pagination.Pagination) (out []domain.Alert, err error) { var alerts []Alert - var total int64 - if pg == nil { pg = pagination.NewDefaultPagination() } - r.db.Find(&alerts, "organization_id = ?", organizationId).Count(&total) - - pg.TotalRows = total - pg.TotalPages = int(math.Ceil(float64(total) / float64(pg.Limit))) - log.Info(total) - log.Info(pg.Limit) - - orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) - - res := r.db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery). + filterFunc := CombinedGormFilter("alerts", pg.GetFilters()) + db := filterFunc(r.db.Model(&Alert{}). Preload("AlertActions", func(db *gorm.DB) *gorm.DB { return db.Order("created_at ASC") }).Preload("AlertActions.Taker"). Preload("Cluster", "status = 2"). Preload("Organization"). Joins("join clusters on clusters.id = alerts.cluster_id AND clusters.status = 2"). - Find(&alerts, "alerts.organization_id = ?", organizationId) + Where("alerts.organization_id = ?", organizationId)) + db.Count(&pg.TotalRows) + + pg.TotalPages = int(math.Ceil(float64(pg.TotalRows) / float64(pg.Limit))) + orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) + res := db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery).Find(&alerts) if res.Error != nil { return nil, res.Error } diff --git a/internal/repository/app-group.go b/internal/repository/app-group.go index 1d3afccd..ba95dac8 100644 --- a/internal/repository/app-group.go +++ b/internal/repository/app-group.go @@ -2,6 +2,7 @@ package repository import ( "fmt" + "math" "github.com/google/uuid" "gorm.io/datatypes" @@ -77,12 +78,22 @@ func (c *Application) BeforeCreate(tx *gorm.DB) (err error) { // Logics func (r *AppGroupRepository) Fetch(clusterId domain.ClusterId, pg *pagination.Pagination) (out []domain.AppGroup, err error) { var appGroups []AppGroup - out = []domain.AppGroup{} + if pg == nil { + pg = pagination.NewDefaultPagination() + } + + filterFunc := CombinedGormFilter("app_groups", pg.GetFilters()) + db := filterFunc(r.db.Model(&AppGroup{}). + Where("cluster_id = ?", clusterId)) + db.Count(&pg.TotalRows) - res := r.db.Find(&appGroups, "cluster_id = ?", clusterId) + pg.TotalPages = int(math.Ceil(float64(pg.TotalRows) / float64(pg.Limit))) + orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) + res := db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery).Find(&appGroups) if res.Error != nil { return nil, res.Error } + for _, appGroup := range appGroups { outAppGroup := reflectAppGroup(appGroup) out = append(out, outAppGroup) diff --git a/internal/repository/app-serve-app.go b/internal/repository/app-serve-app.go index 124901a4..44c474a9 100644 --- a/internal/repository/app-serve-app.go +++ b/internal/repository/app-serve-app.go @@ -2,6 +2,7 @@ package repository import ( "fmt" + "math" "time" "github.com/openinfradev/tks-api/internal/pagination" @@ -56,15 +57,20 @@ func (r *AppServeAppRepository) CreateTask( return task.ID, nil } -func (r *AppServeAppRepository) GetAppServeApps(organizationId string, showAll bool, pg *pagination.Pagination) ([]domain.AppServeApp, error) { - var apps []domain.AppServeApp +func (r *AppServeAppRepository) GetAppServeApps(organizationId string, showAll bool, pg *pagination.Pagination) (apps []domain.AppServeApp, err error) { var clusters []Cluster - - queryStr := fmt.Sprintf("organization_id = '%s' AND status <> 'DELETE_SUCCESS'", organizationId) - if showAll { - queryStr = fmt.Sprintf("organization_id = '%s'", organizationId) + if pg == nil { + pg = pagination.NewDefaultPagination() } - res := r.db.Order("created_at desc").Find(&apps, queryStr) + + filterFunc := CombinedGormFilter("app_serve_apps", pg.GetFilters()) + db := filterFunc(r.db.Model(&domain.AppServeApp{}). + Where("app_serve_apps.organization_id = ? AND status <> 'DELETE_SUCCESS'", organizationId)) + db.Count(&pg.TotalRows) + + pg.TotalPages = int(math.Ceil(float64(pg.TotalRows) / float64(pg.Limit))) + orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) + res := db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery).Find(&apps) if res.Error != nil { return nil, fmt.Errorf("error while finding appServeApps with organizationId: %s", organizationId) } @@ -75,8 +81,8 @@ func (r *AppServeAppRepository) GetAppServeApps(organizationId string, showAll b } // Add cluster names to apps list - queryStr = fmt.Sprintf("organization_id = '%s' AND status <> '%d'", organizationId, domain.ClusterStatus_DELETED) - res = r.db.Order("created_at desc").Find(&clusters, queryStr) + queryStr := fmt.Sprintf("organization_id = '%s' AND status <> '%d'", organizationId, domain.ClusterStatus_DELETED) + res = r.db.Find(&clusters, queryStr) if res.Error != nil { return nil, fmt.Errorf("error while fetching clusters with organizationId: %s", organizationId) } @@ -90,7 +96,7 @@ func (r *AppServeAppRepository) GetAppServeApps(organizationId string, showAll b } } - return apps, nil + return } func (r *AppServeAppRepository) GetAppServeAppById(appId string) (*domain.AppServeApp, error) { diff --git a/internal/repository/cloud-account.go b/internal/repository/cloud-account.go index bfa052db..c8d4a206 100644 --- a/internal/repository/cloud-account.go +++ b/internal/repository/cloud-account.go @@ -96,19 +96,18 @@ func (r *CloudAccountRepository) GetByAwsAccountId(awsAccountId string) (out dom func (r *CloudAccountRepository) Fetch(organizationId string, pg *pagination.Pagination) (out []domain.CloudAccount, err error) { var cloudAccounts []CloudAccount - var total int64 - if pg == nil { pg = pagination.NewDefaultPagination() } - r.db.Find(&cloudAccounts, "organization_id = ? AND status != ?", organizationId, domain.CloudAccountStatus_DELETED).Count(&total) - - pg.TotalRows = total - pg.TotalPages = int(math.Ceil(float64(total) / float64(pg.Limit))) + filterFunc := CombinedGormFilter("cloud_accounts", pg.GetFilters()) + db := filterFunc(r.db.Model(&CloudAccount{}). + Preload(clause.Associations). + Where("organization_id = ? AND status != ?", organizationId, domain.CloudAccountStatus_DELETED)) + db.Count(&pg.TotalRows) + pg.TotalPages = int(math.Ceil(float64(pg.TotalRows) / float64(pg.Limit))) orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) - res := r.db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery). - Preload(clause.Associations).Find(&cloudAccounts, "organization_id = ? AND status != ?", organizationId, domain.CloudAccountStatus_DELETED) + res := db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery).Find(&cloudAccounts) if res.Error != nil { return nil, res.Error } diff --git a/internal/repository/cluster.go b/internal/repository/cluster.go index 310b4d22..db8ff764 100644 --- a/internal/repository/cluster.go +++ b/internal/repository/cluster.go @@ -86,19 +86,17 @@ func (r *ClusterRepository) WithTrx(trxHandle *gorm.DB) IClusterRepository { func (r *ClusterRepository) Fetch(pg *pagination.Pagination) (out []domain.Cluster, err error) { var clusters []Cluster - var total int64 - if pg == nil { pg = pagination.NewDefaultPagination() } - r.db.Find(&clusters).Count(&total) + filterFunc := CombinedGormFilter("clusters", pg.GetFilters()) + db := filterFunc(r.db.Model(&Cluster{})) - pg.TotalRows = total - pg.TotalPages = int(math.Ceil(float64(total) / float64(pg.Limit))) + db.Count(&pg.TotalRows) + pg.TotalPages = int(math.Ceil(float64(pg.TotalRows) / float64(pg.Limit))) orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) - res := r.db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery). - Preload(clause.Associations).Find(&clusters) + res := db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery).Find(&clusters) if res.Error != nil { return nil, res.Error } @@ -106,71 +104,58 @@ func (r *ClusterRepository) Fetch(pg *pagination.Pagination) (out []domain.Clust outCluster := reflectCluster(cluster) out = append(out, outCluster) } - return out, nil + return } func (r *ClusterRepository) FetchByOrganizationId(organizationId string, pg *pagination.Pagination) (out []domain.Cluster, err error) { var clusters []Cluster - var total int64 - if pg == nil { pg = pagination.NewDefaultPagination() } - r.db.Find(&clusters, "organization_id = ? AND status != ?", organizationId, domain.ClusterStatus_DELETED).Count(&total) + pg.SortColumn = "updated_at" + pg.SortOrder = "DESC" + filterFunc := CombinedGormFilter("clusters", pg.GetFilters()) + db := filterFunc(r.db.Model(&Cluster{}).Preload(clause.Associations). + Where("organization_id = ? AND status != ?", organizationId, domain.ClusterStatus_DELETED)) - pg.TotalRows = total - pg.TotalPages = int(math.Ceil(float64(total) / float64(pg.Limit))) + db.Count(&pg.TotalRows) + pg.TotalPages = int(math.Ceil(float64(pg.TotalRows) / float64(pg.Limit))) orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) - res := r.db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery). - Preload(clause.Associations).Order("updated_at desc, created_at desc"). - Find(&clusters, "organization_id = ? AND status != ?", organizationId, domain.ClusterStatus_DELETED) - + res := db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery).Find(&clusters) if res.Error != nil { return nil, res.Error } - - if res.RowsAffected == 0 { - return out, nil - } - for _, cluster := range clusters { outCluster := reflectCluster(cluster) out = append(out, outCluster) } - return } func (r *ClusterRepository) FetchByCloudAccountId(cloudAccountId uuid.UUID, pg *pagination.Pagination) (out []domain.Cluster, err error) { var clusters []Cluster - var total int64 - if pg == nil { pg = pagination.NewDefaultPagination() } - r.db.Find(&clusters, "cloud_account_id = ?", cloudAccountId).Count(&total) + pg.SortColumn = "updated_at" + pg.SortOrder = "DESC" + filterFunc := CombinedGormFilter("clusters", pg.GetFilters()) + db := filterFunc(r.db.Model(&Cluster{}).Preload("CloudAccount"). + Where("cloud_account_id = ?", cloudAccountId)) - pg.TotalRows = total - pg.TotalPages = int(math.Ceil(float64(total) / float64(pg.Limit))) + db.Count(&pg.TotalRows) + pg.TotalPages = int(math.Ceil(float64(pg.TotalRows) / float64(pg.Limit))) orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) - res := r.db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery). - Preload("CloudAccount").Order("updated_at desc, created_at desc").Find(&clusters, "cloud_account_id = ?", cloudAccountId) - + res := db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery).Find(&clusters) if res.Error != nil { return nil, res.Error } - - if res.RowsAffected == 0 { - return out, nil - } - for _, cluster := range clusters { outCluster := reflectCluster(cluster) out = append(out, outCluster) } - return } diff --git a/internal/repository/organization.go b/internal/repository/organization.go index 3f4e8773..b66830d5 100644 --- a/internal/repository/organization.go +++ b/internal/repository/organization.go @@ -74,20 +74,18 @@ func (r *OrganizationRepository) Create(organizationId string, name string, crea func (r *OrganizationRepository) Fetch(pg *pagination.Pagination) (*[]domain.Organization, error) { var organizations []Organization var out []domain.Organization - var total int64 - if pg == nil { pg = pagination.NewDefaultPagination() } - r.db.Find(&organizations).Count(&total) - pg.TotalRows = total - pg.TotalPages = int(math.Ceil(float64(total) / float64(pg.Limit))) + filterFunc := CombinedGormFilter("organizations", pg.GetFilters()) + db := filterFunc(r.db.Model(&Organization{})) + db.Count(&pg.TotalRows) + pg.TotalPages = int(math.Ceil(float64(pg.TotalRows) / float64(pg.Limit))) orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) - res := r.db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery).Find(&organizations) + res := db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery).Find(&organizations) if res.Error != nil { - log.Errorf("error is :%s(%T)", res.Error.Error(), res.Error) return nil, res.Error } for _, organization := range organizations { diff --git a/internal/repository/repository.go b/internal/repository/repository.go index 01e45574..dc01804a 100644 --- a/internal/repository/repository.go +++ b/internal/repository/repository.go @@ -1,6 +1,11 @@ package repository -import "gorm.io/gorm" +import ( + "fmt" + "gorm.io/gorm" + + "github.com/openinfradev/tks-api/internal/pagination" +) type FilterFunc func(user *gorm.DB) *gorm.DB @@ -15,3 +20,21 @@ type Repository struct { StackTemplate IStackTemplateRepository Alert IAlertRepository } + +func CombinedGormFilter(baseTableName string, filters []pagination.Filter) FilterFunc { + return func(db *gorm.DB) *gorm.DB { + for _, filter := range filters { + if len(filter.Values) > 1 { + inQuery := fmt.Sprintf("%s.%s in (", baseTableName, filter.Column) + for _, val := range filter.Values { + inQuery = inQuery + fmt.Sprintf("'%s',", val) + } + inQuery = inQuery[:len(inQuery)-1] + ")" + db = db.Where(inQuery) + } else { + db = db.Where(fmt.Sprintf("%s.%s = '%s'", baseTableName, filter.Column, filter.Values[0])) + } + } + return db + } +} diff --git a/internal/repository/stack-template.go b/internal/repository/stack-template.go index 460b66c6..17b25292 100644 --- a/internal/repository/stack-template.go +++ b/internal/repository/stack-template.go @@ -71,21 +71,51 @@ func (r *StackTemplateRepository) Get(stackTemplateId uuid.UUID) (out domain.Sta } // [TODO] organizationId 별로 생성하지 않고, 하나의 stackTemplate 을 모든 organization 에서 재사용한다. ( 5월 한정, 추후 rearchitecture 필요) + +/* + var alerts []Alert + if pg == nil { + pg = pagination.NewDefaultPagination() + } + + filterFunc := CombinedGormFilter("alerts", pg.GetFilters()) + db := filterFunc(r.db.Model(&Alert{}). + Preload("AlertActions", func(db *gorm.DB) *gorm.DB { + return db.Order("created_at ASC") + }).Preload("AlertActions.Taker"). + Preload("Cluster", "status = 2"). + Preload("Organization"). + Joins("join clusters on clusters.id = alerts.cluster_id AND clusters.status = 2"). + Where("alerts.organization_id = ?", organizationId)) + db.Count(&pg.TotalRows) + + pg.TotalPages = int(math.Ceil(float64(pg.TotalRows) / float64(pg.Limit))) + orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) + res := db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery).Find(&alerts) + if res.Error != nil { + return nil, res.Error + } + + for _, alert := range alerts { + out = append(out, reflectAlert(alert)) + } + return + +*/ + func (r *StackTemplateRepository) Fetch(pg *pagination.Pagination) (out []domain.StackTemplate, err error) { var stackTemplates []StackTemplate - var total int64 - if pg == nil { pg = pagination.NewDefaultPagination() } - r.db.Find(&stackTemplates).Count(&total) - pg.TotalRows = total - pg.TotalPages = int(math.Ceil(float64(total) / float64(pg.Limit))) + filterFunc := CombinedGormFilter("stack_templates", pg.GetFilters()) + db := filterFunc(r.db.Model(&StackTemplate{})) + db.Count(&pg.TotalRows) + pg.TotalPages = int(math.Ceil(float64(pg.TotalRows) / float64(pg.Limit))) orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) - res := r.db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery). - Preload(clause.Associations).Find(&stackTemplates) + res := db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery).Find(&stackTemplates) if res.Error != nil { return nil, res.Error } diff --git a/internal/repository/user.go b/internal/repository/user.go index bf8857f2..5188c0d7 100644 --- a/internal/repository/user.go +++ b/internal/repository/user.go @@ -153,7 +153,7 @@ func (r *UserRepository) List(pg *pagination.Pagination, filters ...FilterFunc) } if filters == nil { - r.db.Find(&users).Count(&total) + r.db.Model(&User{}).Count(&total) pg.TotalRows = total pg.TotalPages = int(math.Ceil(float64(total) / float64(pg.Limit))) @@ -170,7 +170,7 @@ func (r *UserRepository) List(pg *pagination.Pagination, filters ...FilterFunc) } } cFunc := combinedFilter(filters...) - cFunc(r.db.Model(&User{})).Find(&total) + cFunc(r.db.Model(&User{})).Count(&total) pg.TotalRows = total pg.TotalPages = int(math.Ceil(float64(total) / float64(pg.Limit))) diff --git a/pkg/domain/pagination.go b/pkg/domain/pagination.go index e91e9c4a..33efaef7 100644 --- a/pkg/domain/pagination.go +++ b/pkg/domain/pagination.go @@ -11,6 +11,6 @@ type PaginationResponse struct { } type FilterResponse struct { - Column string `json:"column"` - Value string `json:"value"` + Column string `json:"column"` + Values []string `json:"values"` } From e90d6f0dcdd38734987b6b61ce64662d029718a3 Mon Sep 17 00:00:00 2001 From: Taekyu Date: Fri, 14 Jul 2023 14:18:01 +0900 Subject: [PATCH 28/54] trivial. minor changes --- internal/repository/alert.go | 2 +- internal/repository/app-group.go | 5 +++- internal/repository/app-serve-app.go | 2 +- internal/repository/cloud-account.go | 2 +- internal/repository/cluster.go | 6 ++--- internal/repository/organization.go | 2 +- internal/repository/repository.go | 6 ++--- internal/repository/stack-template.go | 34 +-------------------------- 8 files changed, 15 insertions(+), 44 deletions(-) diff --git a/internal/repository/alert.go b/internal/repository/alert.go index eef5b64a..8031e89f 100644 --- a/internal/repository/alert.go +++ b/internal/repository/alert.go @@ -108,7 +108,7 @@ func (r *AlertRepository) Fetch(organizationId string, pg *pagination.Pagination pg = pagination.NewDefaultPagination() } - filterFunc := CombinedGormFilter("alerts", pg.GetFilters()) + filterFunc := CombinedGormFilter(pg.GetFilters()) db := filterFunc(r.db.Model(&Alert{}). Preload("AlertActions", func(db *gorm.DB) *gorm.DB { return db.Order("created_at ASC") diff --git a/internal/repository/app-group.go b/internal/repository/app-group.go index ba95dac8..49a22cdf 100644 --- a/internal/repository/app-group.go +++ b/internal/repository/app-group.go @@ -82,11 +82,14 @@ func (r *AppGroupRepository) Fetch(clusterId domain.ClusterId, pg *pagination.Pa pg = pagination.NewDefaultPagination() } - filterFunc := CombinedGormFilter("app_groups", pg.GetFilters()) + filterFunc := CombinedGormFilter(pg.GetFilters()) db := filterFunc(r.db.Model(&AppGroup{}). Where("cluster_id = ?", clusterId)) db.Count(&pg.TotalRows) + r.db.Model(&AppGroup{}). + Where("cluster_id = ?", clusterId).Where("id").Where("app_groups.status").Where("app_groups.deleted") + pg.TotalPages = int(math.Ceil(float64(pg.TotalRows) / float64(pg.Limit))) orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) res := db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery).Find(&appGroups) diff --git a/internal/repository/app-serve-app.go b/internal/repository/app-serve-app.go index 44c474a9..46f32297 100644 --- a/internal/repository/app-serve-app.go +++ b/internal/repository/app-serve-app.go @@ -63,7 +63,7 @@ func (r *AppServeAppRepository) GetAppServeApps(organizationId string, showAll b pg = pagination.NewDefaultPagination() } - filterFunc := CombinedGormFilter("app_serve_apps", pg.GetFilters()) + filterFunc := CombinedGormFilter(pg.GetFilters()) db := filterFunc(r.db.Model(&domain.AppServeApp{}). Where("app_serve_apps.organization_id = ? AND status <> 'DELETE_SUCCESS'", organizationId)) db.Count(&pg.TotalRows) diff --git a/internal/repository/cloud-account.go b/internal/repository/cloud-account.go index c8d4a206..21ef0d86 100644 --- a/internal/repository/cloud-account.go +++ b/internal/repository/cloud-account.go @@ -99,7 +99,7 @@ func (r *CloudAccountRepository) Fetch(organizationId string, pg *pagination.Pag if pg == nil { pg = pagination.NewDefaultPagination() } - filterFunc := CombinedGormFilter("cloud_accounts", pg.GetFilters()) + filterFunc := CombinedGormFilter(pg.GetFilters()) db := filterFunc(r.db.Model(&CloudAccount{}). Preload(clause.Associations). Where("organization_id = ? AND status != ?", organizationId, domain.CloudAccountStatus_DELETED)) diff --git a/internal/repository/cluster.go b/internal/repository/cluster.go index db8ff764..e131fdd6 100644 --- a/internal/repository/cluster.go +++ b/internal/repository/cluster.go @@ -89,7 +89,7 @@ func (r *ClusterRepository) Fetch(pg *pagination.Pagination) (out []domain.Clust if pg == nil { pg = pagination.NewDefaultPagination() } - filterFunc := CombinedGormFilter("clusters", pg.GetFilters()) + filterFunc := CombinedGormFilter(pg.GetFilters()) db := filterFunc(r.db.Model(&Cluster{})) db.Count(&pg.TotalRows) @@ -114,7 +114,7 @@ func (r *ClusterRepository) FetchByOrganizationId(organizationId string, pg *pag } pg.SortColumn = "updated_at" pg.SortOrder = "DESC" - filterFunc := CombinedGormFilter("clusters", pg.GetFilters()) + filterFunc := CombinedGormFilter(pg.GetFilters()) db := filterFunc(r.db.Model(&Cluster{}).Preload(clause.Associations). Where("organization_id = ? AND status != ?", organizationId, domain.ClusterStatus_DELETED)) @@ -140,7 +140,7 @@ func (r *ClusterRepository) FetchByCloudAccountId(cloudAccountId uuid.UUID, pg * } pg.SortColumn = "updated_at" pg.SortOrder = "DESC" - filterFunc := CombinedGormFilter("clusters", pg.GetFilters()) + filterFunc := CombinedGormFilter(pg.GetFilters()) db := filterFunc(r.db.Model(&Cluster{}).Preload("CloudAccount"). Where("cloud_account_id = ?", cloudAccountId)) diff --git a/internal/repository/organization.go b/internal/repository/organization.go index b66830d5..0e3b8221 100644 --- a/internal/repository/organization.go +++ b/internal/repository/organization.go @@ -78,7 +78,7 @@ func (r *OrganizationRepository) Fetch(pg *pagination.Pagination) (*[]domain.Org pg = pagination.NewDefaultPagination() } - filterFunc := CombinedGormFilter("organizations", pg.GetFilters()) + filterFunc := CombinedGormFilter(pg.GetFilters()) db := filterFunc(r.db.Model(&Organization{})) db.Count(&pg.TotalRows) diff --git a/internal/repository/repository.go b/internal/repository/repository.go index dc01804a..4cf95fd1 100644 --- a/internal/repository/repository.go +++ b/internal/repository/repository.go @@ -21,18 +21,18 @@ type Repository struct { Alert IAlertRepository } -func CombinedGormFilter(baseTableName string, filters []pagination.Filter) FilterFunc { +func CombinedGormFilter(filters []pagination.Filter) FilterFunc { return func(db *gorm.DB) *gorm.DB { for _, filter := range filters { if len(filter.Values) > 1 { - inQuery := fmt.Sprintf("%s.%s in (", baseTableName, filter.Column) + inQuery := fmt.Sprintf("%s in (", filter.Column) for _, val := range filter.Values { inQuery = inQuery + fmt.Sprintf("'%s',", val) } inQuery = inQuery[:len(inQuery)-1] + ")" db = db.Where(inQuery) } else { - db = db.Where(fmt.Sprintf("%s.%s = '%s'", baseTableName, filter.Column, filter.Values[0])) + db = db.Where(fmt.Sprintf("%s = '%s'", filter.Column, filter.Values[0])) } } return db diff --git a/internal/repository/stack-template.go b/internal/repository/stack-template.go index 17b25292..e5bd5ec6 100644 --- a/internal/repository/stack-template.go +++ b/internal/repository/stack-template.go @@ -71,45 +71,13 @@ func (r *StackTemplateRepository) Get(stackTemplateId uuid.UUID) (out domain.Sta } // [TODO] organizationId 별로 생성하지 않고, 하나의 stackTemplate 을 모든 organization 에서 재사용한다. ( 5월 한정, 추후 rearchitecture 필요) - -/* - var alerts []Alert - if pg == nil { - pg = pagination.NewDefaultPagination() - } - - filterFunc := CombinedGormFilter("alerts", pg.GetFilters()) - db := filterFunc(r.db.Model(&Alert{}). - Preload("AlertActions", func(db *gorm.DB) *gorm.DB { - return db.Order("created_at ASC") - }).Preload("AlertActions.Taker"). - Preload("Cluster", "status = 2"). - Preload("Organization"). - Joins("join clusters on clusters.id = alerts.cluster_id AND clusters.status = 2"). - Where("alerts.organization_id = ?", organizationId)) - db.Count(&pg.TotalRows) - - pg.TotalPages = int(math.Ceil(float64(pg.TotalRows) / float64(pg.Limit))) - orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) - res := db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery).Find(&alerts) - if res.Error != nil { - return nil, res.Error - } - - for _, alert := range alerts { - out = append(out, reflectAlert(alert)) - } - return - -*/ - func (r *StackTemplateRepository) Fetch(pg *pagination.Pagination) (out []domain.StackTemplate, err error) { var stackTemplates []StackTemplate if pg == nil { pg = pagination.NewDefaultPagination() } - filterFunc := CombinedGormFilter("stack_templates", pg.GetFilters()) + filterFunc := CombinedGormFilter(pg.GetFilters()) db := filterFunc(r.db.Model(&StackTemplate{})) db.Count(&pg.TotalRows) From 28ced533803647e6c369afa5384d40b443f9155e Mon Sep 17 00:00:00 2001 From: Taekyu Date: Mon, 17 Jul 2023 13:15:32 +0900 Subject: [PATCH 29/54] feature. add combindedFilter to pagination --- api/swagger/docs.go | 9 ++--- api/swagger/swagger.json | 9 ++--- api/swagger/swagger.yaml | 8 ++--- internal/delivery/http/alert.go | 7 +++- internal/delivery/http/app-group.go | 6 +++- internal/delivery/http/app-serve-app.go | 6 +++- internal/delivery/http/cloud-account.go | 6 +++- internal/delivery/http/cluster.go | 6 +++- internal/delivery/http/organization.go | 6 +++- internal/delivery/http/stack-template.go | 6 +++- internal/delivery/http/stack.go | 8 +++-- internal/delivery/http/user.go | 6 +++- internal/pagination/pagination.go | 42 +++++++++++++++++++----- internal/repository/alert.go | 2 +- internal/repository/app-group.go | 2 +- internal/repository/app-serve-app.go | 2 +- internal/repository/cloud-account.go | 2 +- internal/repository/cluster.go | 6 ++-- internal/repository/organization.go | 2 +- internal/repository/repository.go | 15 ++++++++- internal/repository/stack-template.go | 2 +- 21 files changed, 112 insertions(+), 46 deletions(-) diff --git a/api/swagger/docs.go b/api/swagger/docs.go index e36031ba..cf803d99 100644 --- a/api/swagger/docs.go +++ b/api/swagger/docs.go @@ -2596,12 +2596,9 @@ const docTemplate = `{ "in": "query" }, { - "type": "array", - "items": { - "type": "string" - }, - "description": "filters", - "name": "filters", + "type": "string", + "description": "combinedFilter", + "name": "combinedFilter", "in": "query" } ], diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index f49ea698..2738fb7e 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -2589,12 +2589,9 @@ "in": "query" }, { - "type": "array", - "items": { - "type": "string" - }, - "description": "filters", - "name": "filters", + "type": "string", + "description": "combinedFilter", + "name": "combinedFilter", "in": "query" } ], diff --git a/api/swagger/swagger.yaml b/api/swagger/swagger.yaml index e78d1933..c23032ea 100644 --- a/api/swagger/swagger.yaml +++ b/api/swagger/swagger.yaml @@ -3395,12 +3395,10 @@ paths: in: query name: sortOrder type: string - - description: filters + - description: combinedFilter in: query - items: - type: string - name: filters - type: array + name: combinedFilter + type: string produces: - application/json responses: diff --git a/internal/delivery/http/alert.go b/internal/delivery/http/alert.go index 987dd89e..a749f4a0 100644 --- a/internal/delivery/http/alert.go +++ b/internal/delivery/http/alert.go @@ -94,7 +94,12 @@ func (h *AlertHandler) GetAlerts(w http.ResponseWriter, r *http.Request) { } urlParams := r.URL.Query() - pg := pagination.NewPagination(&urlParams) + pg, err := pagination.NewPagination(&urlParams) + if err != nil { + ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "", "")) + return + } + alerts, err := h.usecase.Fetch(r.Context(), organizationId, pg) if err != nil { ErrorJSON(w, r, err) diff --git a/internal/delivery/http/app-group.go b/internal/delivery/http/app-group.go index ae169b70..624a5779 100644 --- a/internal/delivery/http/app-group.go +++ b/internal/delivery/http/app-group.go @@ -82,7 +82,11 @@ func (h *AppGroupHandler) GetAppGroups(w http.ResponseWriter, r *http.Request) { ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("Invalid clusterId"), "C_INVALID_CLUSTER_ID", "")) return } - pg := pagination.NewPagination(&urlParams) + pg, err := pagination.NewPagination(&urlParams) + if err != nil { + ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "", "")) + return + } appGroups, err := h.usecase.Fetch(r.Context(), domain.ClusterId(clusterId), pg) if err != nil { diff --git a/internal/delivery/http/app-serve-app.go b/internal/delivery/http/app-serve-app.go index b30a3a40..06b8965f 100644 --- a/internal/delivery/http/app-serve-app.go +++ b/internal/delivery/http/app-serve-app.go @@ -197,7 +197,11 @@ func (h *AppServeAppHandler) GetAppServeApps(w http.ResponseWriter, r *http.Requ ErrorJSON(w, r, err) return } - pg := pagination.NewPagination(&urlParams) + pg, err := pagination.NewPagination(&urlParams) + if err != nil { + ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "", "")) + return + } apps, err := h.usecase.GetAppServeApps(organizationId, showAll, pg) if err != nil { diff --git a/internal/delivery/http/cloud-account.go b/internal/delivery/http/cloud-account.go index 32e61bc8..33c71eea 100644 --- a/internal/delivery/http/cloud-account.go +++ b/internal/delivery/http/cloud-account.go @@ -93,7 +93,11 @@ func (h *CloudAccountHandler) GetCloudAccounts(w http.ResponseWriter, r *http.Re } urlParams := r.URL.Query() - pg := pagination.NewPagination(&urlParams) + pg, err := pagination.NewPagination(&urlParams) + if err != nil { + ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "", "")) + return + } cloudAccounts, err := h.usecase.Fetch(r.Context(), organizationId, pg) if err != nil { ErrorJSON(w, r, err) diff --git a/internal/delivery/http/cluster.go b/internal/delivery/http/cluster.go index 16d697fd..6b0613d9 100644 --- a/internal/delivery/http/cluster.go +++ b/internal/delivery/http/cluster.go @@ -41,7 +41,11 @@ func (h *ClusterHandler) GetClusters(w http.ResponseWriter, r *http.Request) { urlParams := r.URL.Query() organizationId := urlParams.Get("organizationId") - pg := pagination.NewPagination(&urlParams) + pg, err := pagination.NewPagination(&urlParams) + if err != nil { + ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "", "")) + return + } clusters, err := h.usecase.Fetch(r.Context(), organizationId, pg) if err != nil { ErrorJSON(w, r, err) diff --git a/internal/delivery/http/organization.go b/internal/delivery/http/organization.go index ba6e1111..12e420fb 100644 --- a/internal/delivery/http/organization.go +++ b/internal/delivery/http/organization.go @@ -90,7 +90,11 @@ func (h *OrganizationHandler) CreateOrganization(w http.ResponseWriter, r *http. // @Security JWT func (h *OrganizationHandler) GetOrganizations(w http.ResponseWriter, r *http.Request) { urlParams := r.URL.Query() - pg := pagination.NewPagination(&urlParams) + pg, err := pagination.NewPagination(&urlParams) + if err != nil { + ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "", "")) + return + } organizations, err := h.usecase.Fetch(pg) if err != nil { diff --git a/internal/delivery/http/stack-template.go b/internal/delivery/http/stack-template.go index f1a017dd..56ebb222 100644 --- a/internal/delivery/http/stack-template.go +++ b/internal/delivery/http/stack-template.go @@ -55,7 +55,11 @@ func (h *StackTemplateHandler) CreateStackTemplate(w http.ResponseWriter, r *htt // @Security JWT func (h *StackTemplateHandler) GetStackTemplates(w http.ResponseWriter, r *http.Request) { urlParams := r.URL.Query() - pg := pagination.NewPagination(&urlParams) + pg, err := pagination.NewPagination(&urlParams) + if err != nil { + ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "", "")) + return + } stackTemplates, err := h.usecase.Fetch(r.Context(), pg) if err != nil { diff --git a/internal/delivery/http/stack.go b/internal/delivery/http/stack.go index 1c69d591..a85c52ed 100644 --- a/internal/delivery/http/stack.go +++ b/internal/delivery/http/stack.go @@ -81,7 +81,7 @@ func (h *StackHandler) CreateStack(w http.ResponseWriter, r *http.Request) { // @Param page query string false "pageNumber" // @Param soertColumn query string false "sortColumn" // @Param sortOrder query string false "sortOrder" -// @Param filters query []string false "filters" +// @Param combinedFilter query string false "combinedFilter" // @Success 200 {object} domain.GetStacksResponse // @Router /organizations/{organizationId}/stacks [get] // @Security JWT @@ -94,7 +94,11 @@ func (h *StackHandler) GetStacks(w http.ResponseWriter, r *http.Request) { } urlParams := r.URL.Query() - pg := pagination.NewPagination(&urlParams) + pg, err := pagination.NewPagination(&urlParams) + if err != nil { + ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "", "")) + return + } stacks, err := h.usecase.Fetch(r.Context(), organizationId, pg) if err != nil { ErrorJSON(w, r, err) diff --git a/internal/delivery/http/user.go b/internal/delivery/http/user.go index 787d07dc..135393ed 100644 --- a/internal/delivery/http/user.go +++ b/internal/delivery/http/user.go @@ -175,7 +175,11 @@ func (u UserHandler) List(w http.ResponseWriter, r *http.Request) { } urlParams := r.URL.Query() - pg := pagination.NewPagination(&urlParams) + pg, err := pagination.NewPagination(&urlParams) + if err != nil { + ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "", "")) + return + } users, err := u.usecase.List(r.Context(), organizationId, pg) if err != nil { if _, status := httpErrors.ErrorResponse(err); status == http.StatusNotFound { diff --git a/internal/pagination/pagination.go b/internal/pagination/pagination.go index 7b839c16..01f8f513 100644 --- a/internal/pagination/pagination.go +++ b/internal/pagination/pagination.go @@ -1,6 +1,7 @@ package pagination import ( + "fmt" "net/url" "strconv" "strings" @@ -12,15 +13,17 @@ const SORT_COLUMN = "sortColumn" const SORT_ORDER = "sortOrder" const PAGE_NUMBER = "pageNumber" const PAGE_SIZE = "pageSize" +const COMBINED_FILTER = "combinedFilter" type Pagination struct { - Limit int - Page int - SortColumn string - SortOrder string - Filters []Filter - TotalRows int64 - TotalPages int + Limit int + Page int + SortColumn string + SortOrder string + Filters []Filter + CombinedFilter CombinedFilter + TotalRows int64 + TotalPages int } type Filter struct { @@ -28,6 +31,11 @@ type Filter struct { Values []string } +type CombinedFilter struct { + Columns []string + Value string +} + var DEFAULT_LIMIT = 10 var MAX_LIMIT = 1000 @@ -61,7 +69,7 @@ func (p *Pagination) GetFilters() []Filter { return p.Filters } -func NewPagination(urlParams *url.Values) *Pagination { +func NewPagination(urlParams *url.Values) (*Pagination, error) { pg := NewDefaultPagination() for key, value := range *urlParams { @@ -92,6 +100,22 @@ func NewPagination(urlParams *url.Values) *Pagination { pg.Limit = limitNum } } + case COMBINED_FILTER: + if len(value[0]) > 0 { + //"combinedFilter=key1,key2:value" + filterArray := strings.Split(value[0], ":") + if len(filterArray) == 2 { + keys := strings.Split(filterArray[0], ",") + value := filterArray[1] + + pg.CombinedFilter = CombinedFilter{ + Columns: keys, + Value: value, + } + } else { + return nil, fmt.Errorf("Invalid query string : combinedFilter ") + } + } default: pg.Filters = append(pg.Filters, Filter{ Column: helper.ToSnakeCase(strings.Replace(key, "[]", "", -1)), @@ -100,7 +124,7 @@ func NewPagination(urlParams *url.Values) *Pagination { } } - return pg + return pg, nil } func NewDefaultPagination() *Pagination { diff --git a/internal/repository/alert.go b/internal/repository/alert.go index 8031e89f..4bd33de7 100644 --- a/internal/repository/alert.go +++ b/internal/repository/alert.go @@ -108,7 +108,7 @@ func (r *AlertRepository) Fetch(organizationId string, pg *pagination.Pagination pg = pagination.NewDefaultPagination() } - filterFunc := CombinedGormFilter(pg.GetFilters()) + filterFunc := CombinedGormFilter(pg.GetFilters(), pg.CombinedFilter) db := filterFunc(r.db.Model(&Alert{}). Preload("AlertActions", func(db *gorm.DB) *gorm.DB { return db.Order("created_at ASC") diff --git a/internal/repository/app-group.go b/internal/repository/app-group.go index 49a22cdf..4d033e48 100644 --- a/internal/repository/app-group.go +++ b/internal/repository/app-group.go @@ -82,7 +82,7 @@ func (r *AppGroupRepository) Fetch(clusterId domain.ClusterId, pg *pagination.Pa pg = pagination.NewDefaultPagination() } - filterFunc := CombinedGormFilter(pg.GetFilters()) + filterFunc := CombinedGormFilter(pg.GetFilters(), pg.CombinedFilter) db := filterFunc(r.db.Model(&AppGroup{}). Where("cluster_id = ?", clusterId)) db.Count(&pg.TotalRows) diff --git a/internal/repository/app-serve-app.go b/internal/repository/app-serve-app.go index 46f32297..64b265a5 100644 --- a/internal/repository/app-serve-app.go +++ b/internal/repository/app-serve-app.go @@ -63,7 +63,7 @@ func (r *AppServeAppRepository) GetAppServeApps(organizationId string, showAll b pg = pagination.NewDefaultPagination() } - filterFunc := CombinedGormFilter(pg.GetFilters()) + filterFunc := CombinedGormFilter(pg.GetFilters(), pg.CombinedFilter) db := filterFunc(r.db.Model(&domain.AppServeApp{}). Where("app_serve_apps.organization_id = ? AND status <> 'DELETE_SUCCESS'", organizationId)) db.Count(&pg.TotalRows) diff --git a/internal/repository/cloud-account.go b/internal/repository/cloud-account.go index 21ef0d86..a4fc7da8 100644 --- a/internal/repository/cloud-account.go +++ b/internal/repository/cloud-account.go @@ -99,7 +99,7 @@ func (r *CloudAccountRepository) Fetch(organizationId string, pg *pagination.Pag if pg == nil { pg = pagination.NewDefaultPagination() } - filterFunc := CombinedGormFilter(pg.GetFilters()) + filterFunc := CombinedGormFilter(pg.GetFilters(), pg.CombinedFilter) db := filterFunc(r.db.Model(&CloudAccount{}). Preload(clause.Associations). Where("organization_id = ? AND status != ?", organizationId, domain.CloudAccountStatus_DELETED)) diff --git a/internal/repository/cluster.go b/internal/repository/cluster.go index e131fdd6..9cc690da 100644 --- a/internal/repository/cluster.go +++ b/internal/repository/cluster.go @@ -89,7 +89,7 @@ func (r *ClusterRepository) Fetch(pg *pagination.Pagination) (out []domain.Clust if pg == nil { pg = pagination.NewDefaultPagination() } - filterFunc := CombinedGormFilter(pg.GetFilters()) + filterFunc := CombinedGormFilter(pg.GetFilters(), pg.CombinedFilter) db := filterFunc(r.db.Model(&Cluster{})) db.Count(&pg.TotalRows) @@ -114,7 +114,7 @@ func (r *ClusterRepository) FetchByOrganizationId(organizationId string, pg *pag } pg.SortColumn = "updated_at" pg.SortOrder = "DESC" - filterFunc := CombinedGormFilter(pg.GetFilters()) + filterFunc := CombinedGormFilter(pg.GetFilters(), pg.CombinedFilter) db := filterFunc(r.db.Model(&Cluster{}).Preload(clause.Associations). Where("organization_id = ? AND status != ?", organizationId, domain.ClusterStatus_DELETED)) @@ -140,7 +140,7 @@ func (r *ClusterRepository) FetchByCloudAccountId(cloudAccountId uuid.UUID, pg * } pg.SortColumn = "updated_at" pg.SortOrder = "DESC" - filterFunc := CombinedGormFilter(pg.GetFilters()) + filterFunc := CombinedGormFilter(pg.GetFilters(), pg.CombinedFilter) db := filterFunc(r.db.Model(&Cluster{}).Preload("CloudAccount"). Where("cloud_account_id = ?", cloudAccountId)) diff --git a/internal/repository/organization.go b/internal/repository/organization.go index 0e3b8221..0a2920f6 100644 --- a/internal/repository/organization.go +++ b/internal/repository/organization.go @@ -78,7 +78,7 @@ func (r *OrganizationRepository) Fetch(pg *pagination.Pagination) (*[]domain.Org pg = pagination.NewDefaultPagination() } - filterFunc := CombinedGormFilter(pg.GetFilters()) + filterFunc := CombinedGormFilter(pg.GetFilters(), pg.CombinedFilter) db := filterFunc(r.db.Model(&Organization{})) db.Count(&pg.TotalRows) diff --git a/internal/repository/repository.go b/internal/repository/repository.go index 4cf95fd1..9f1dd0ed 100644 --- a/internal/repository/repository.go +++ b/internal/repository/repository.go @@ -21,8 +21,9 @@ type Repository struct { Alert IAlertRepository } -func CombinedGormFilter(filters []pagination.Filter) FilterFunc { +func CombinedGormFilter(filters []pagination.Filter, combinedFilter pagination.CombinedFilter) FilterFunc { return func(db *gorm.DB) *gorm.DB { + // and query for _, filter := range filters { if len(filter.Values) > 1 { inQuery := fmt.Sprintf("%s in (", filter.Column) @@ -35,6 +36,18 @@ func CombinedGormFilter(filters []pagination.Filter) FilterFunc { db = db.Where(fmt.Sprintf("%s = '%s'", filter.Column, filter.Values[0])) } } + + // or query + // id = '123' or description = '345' + if len(combinedFilter.Columns) > 0 { + orQuery := "" + for _, column := range combinedFilter.Columns { + orQuery = orQuery + fmt.Sprintf("%s like '%%%s%%' OR ", column, combinedFilter.Value) + } + orQuery = orQuery[:len(orQuery)-3] + db = db.Where(orQuery) + } + return db } } diff --git a/internal/repository/stack-template.go b/internal/repository/stack-template.go index e5bd5ec6..b027ec77 100644 --- a/internal/repository/stack-template.go +++ b/internal/repository/stack-template.go @@ -77,7 +77,7 @@ func (r *StackTemplateRepository) Fetch(pg *pagination.Pagination) (out []domain pg = pagination.NewDefaultPagination() } - filterFunc := CombinedGormFilter(pg.GetFilters()) + filterFunc := CombinedGormFilter(pg.GetFilters(), pg.CombinedFilter) db := filterFunc(r.db.Model(&StackTemplate{})) db.Count(&pg.TotalRows) From 49742cf3a8da66940cfe7cc8ebd7076d819aa7b3 Mon Sep 17 00:00:00 2001 From: Robert Choi Date: Mon, 17 Jul 2023 16:16:31 +0900 Subject: [PATCH 30/54] app-serving: add preprocessing for extraEnv param tks-issues-753 --- internal/usecase/app-serve-app.go | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/internal/usecase/app-serve-app.go b/internal/usecase/app-serve-app.go index 77111f02..e54b165e 100644 --- a/internal/usecase/app-serve-app.go +++ b/internal/usecase/app-serve-app.go @@ -2,6 +2,7 @@ package usecase import ( "fmt" + "encoding/json" "strconv" "strings" @@ -88,6 +89,26 @@ func (u *AppServeAppUsecase) CreateAppServeApp(app *domain.AppServeApp) (string, } } + // Preprocess extraEnv param + extEnv := app.AppServeAppTasks[0].ExtraEnv + log.Debug("extraEnv received: ", extEnv) + + tempMap := map[string]string{} + json.Unmarshal([]byte(extEnv), &tempMap) + log.Debugf("extraEnv marshalled: %v", tempMap) + + newExtEnv := map[string]string{} + for key, val := range tempMap { + newkey := "\"" + key + "\"" + newval := "\"" + val + "\"" + newExtEnv[newkey] = newval + } + + mJson, _ := json.Marshal(newExtEnv) + newExtEnvStr := string(mJson) + + log.Debug("After transform, extraEnv: ", newExtEnvStr) + // TODO: Validate PV params appId, taskId, err := u.repo.CreateAppServeApp(app) @@ -116,7 +137,7 @@ func (u *AppServeAppUsecase) CreateAppServeApp(app *domain.AppServeApp) (string, "image_url=" + app.AppServeAppTasks[0].ImageUrl, "port=" + app.AppServeAppTasks[0].Port, "profile=" + app.AppServeAppTasks[0].Profile, - "extra_env=" + app.AppServeAppTasks[0].ExtraEnv, + "extra_env=" + newExtEnvStr, "app_config=" + app.AppServeAppTasks[0].AppConfig, "app_secret=" + app.AppServeAppTasks[0].AppSecret, "resource_spec=" + app.AppServeAppTasks[0].ResourceSpec, From 2452b63e55d4ee626a7884d945d88842ad1261f3 Mon Sep 17 00:00:00 2001 From: Robert Choi Date: Mon, 17 Jul 2023 16:33:55 +0900 Subject: [PATCH 31/54] trivial: fix lint err --- internal/usecase/app-serve-app.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/internal/usecase/app-serve-app.go b/internal/usecase/app-serve-app.go index e54b165e..c7079cb5 100644 --- a/internal/usecase/app-serve-app.go +++ b/internal/usecase/app-serve-app.go @@ -1,8 +1,8 @@ package usecase import ( - "fmt" "encoding/json" + "fmt" "strconv" "strings" @@ -94,7 +94,11 @@ func (u *AppServeAppUsecase) CreateAppServeApp(app *domain.AppServeApp) (string, log.Debug("extraEnv received: ", extEnv) tempMap := map[string]string{} - json.Unmarshal([]byte(extEnv), &tempMap) + err := json.Unmarshal([]byte(extEnv), &tempMap) + if err != nil { + log.Error(err) + return "", "", errors.Wrap(err, "Failed to process extraEnv param.") + } log.Debugf("extraEnv marshalled: %v", tempMap) newExtEnv := map[string]string{} From cc6753854a6716c2ba232e1f6b8d10db618f5591 Mon Sep 17 00:00:00 2001 From: Robert Choi Date: Mon, 17 Jul 2023 18:17:41 +0900 Subject: [PATCH 32/54] apply same stuff for update logic --- internal/usecase/app-serve-app.go | 47 +++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/internal/usecase/app-serve-app.go b/internal/usecase/app-serve-app.go index c7079cb5..1d010bc5 100644 --- a/internal/usecase/app-serve-app.go +++ b/internal/usecase/app-serve-app.go @@ -89,12 +89,20 @@ func (u *AppServeAppUsecase) CreateAppServeApp(app *domain.AppServeApp) (string, } } - // Preprocess extraEnv param + appId, taskId, err := u.repo.CreateAppServeApp(app) + if err != nil { + log.Error(err) + return "", "", errors.Wrap(err, "Failed to create app.") + } + + fmt.Printf("appId = %s, taskId = %s", appId, taskId) + + /* Preprocess extraEnv param */ extEnv := app.AppServeAppTasks[0].ExtraEnv log.Debug("extraEnv received: ", extEnv) tempMap := map[string]string{} - err := json.Unmarshal([]byte(extEnv), &tempMap) + err = json.Unmarshal([]byte(extEnv), &tempMap) if err != nil { log.Error(err) return "", "", errors.Wrap(err, "Failed to process extraEnv param.") @@ -110,19 +118,10 @@ func (u *AppServeAppUsecase) CreateAppServeApp(app *domain.AppServeApp) (string, mJson, _ := json.Marshal(newExtEnv) newExtEnvStr := string(mJson) - log.Debug("After transform, extraEnv: ", newExtEnvStr) // TODO: Validate PV params - appId, taskId, err := u.repo.CreateAppServeApp(app) - if err != nil { - log.Error(err) - return "", "", errors.Wrap(err, "Failed to create app.") - } - - fmt.Printf("appId = %s, taskId = %s", appId, taskId) - // Call argo workflow workflow := "serve-java-app" @@ -394,6 +393,30 @@ func (u *AppServeAppUsecase) UpdateAppServeApp(app *domain.AppServeApp, appTask return "", fmt.Errorf("failed to update app status on UpdateAppServeApp. Err: %s", err) } + // Preprocess extraEnv param + extEnv := appTask.ExtraEnv + log.Debug("extraEnv received: ", extEnv) + + tempMap := map[string]string{} + err = json.Unmarshal([]byte(extEnv), &tempMap) + if err != nil { + log.Error(err) + return "", errors.Wrap(err, "Failed to process extraEnv param.") + } + log.Debugf("extraEnv marshalled: %v", tempMap) + + newExtEnv := map[string]string{} + for key, val := range tempMap { + newkey := "\"" + key + "\"" + newval := "\"" + val + "\"" + newExtEnv[newkey] = newval + } + + mJson, _ := json.Marshal(newExtEnv) + newExtEnvStr := string(mJson) + + log.Debug("After transform, extraEnv: ", newExtEnvStr) + // Call argo workflow workflow := "serve-java-app" @@ -414,7 +437,7 @@ func (u *AppServeAppUsecase) UpdateAppServeApp(app *domain.AppServeApp, appTask "image_url=" + appTask.ImageUrl, "port=" + appTask.Port, "profile=" + appTask.Profile, - "extra_env=" + appTask.ExtraEnv, + "extra_env=" + newExtEnvStr, "app_config=" + appTask.AppConfig, "app_secret=" + appTask.AppSecret, "resource_spec=" + appTask.ResourceSpec, From 12106f4c1796dd4b1db54151e22922770392a421 Mon Sep 17 00:00:00 2001 From: Taekyu Date: Wed, 19 Jul 2023 10:19:04 +0900 Subject: [PATCH 33/54] feature. implementation filter on pagination. --- internal/delivery/http/alert.go | 17 +++++++++++++++++ internal/repository/alert.go | 13 ++++++++++++- internal/repository/app-group.go | 2 +- internal/repository/app-serve-app.go | 2 +- internal/repository/cloud-account.go | 6 +++--- internal/repository/cluster.go | 10 +++++----- internal/repository/organization.go | 2 +- internal/repository/repository.go | 12 +++++++----- internal/repository/stack-template.go | 6 +++--- internal/usecase/alert.go | 4 ++-- pkg/domain/app-serve-app.go | 4 ++-- 11 files changed, 54 insertions(+), 24 deletions(-) diff --git a/internal/delivery/http/alert.go b/internal/delivery/http/alert.go index a749f4a0..70b2208a 100644 --- a/internal/delivery/http/alert.go +++ b/internal/delivery/http/alert.go @@ -99,6 +99,23 @@ func (h *AlertHandler) GetAlerts(w http.ResponseWriter, r *http.Request) { ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "", "")) return } + // convert status + for i, filter := range pg.GetFilters() { + if filter.Column == "status" { + for j, value := range filter.Values { + switch value { + case "CREATED": + pg.GetFilters()[i].Values[j] = "0" + case "INPROGRESS": + pg.GetFilters()[i].Values[j] = "1" + case "CLOSED": + pg.GetFilters()[i].Values[j] = "2" + case "ERROR": + pg.GetFilters()[i].Values[j] = "3" + } + } + } + } alerts, err := h.usecase.Fetch(r.Context(), organizationId, pg) if err != nil { diff --git a/internal/repository/alert.go b/internal/repository/alert.go index 4bd33de7..e82e1999 100644 --- a/internal/repository/alert.go +++ b/internal/repository/alert.go @@ -57,6 +57,7 @@ type Alert struct { Summary string AlertActions []AlertAction `gorm:"foreignKey:AlertId"` RawData datatypes.JSON + Status domain.AlertActionStatus `gorm:"index"` } func (c *Alert) BeforeCreate(tx *gorm.DB) (err error) { @@ -108,7 +109,7 @@ func (r *AlertRepository) Fetch(organizationId string, pg *pagination.Pagination pg = pagination.NewDefaultPagination() } - filterFunc := CombinedGormFilter(pg.GetFilters(), pg.CombinedFilter) + filterFunc := CombinedGormFilter("alerts", pg.GetFilters(), pg.CombinedFilter) db := filterFunc(r.db.Model(&Alert{}). Preload("AlertActions", func(db *gorm.DB) *gorm.DB { return db.Order("created_at ASC") @@ -117,6 +118,7 @@ func (r *AlertRepository) Fetch(organizationId string, pg *pagination.Pagination Preload("Organization"). Joins("join clusters on clusters.id = alerts.cluster_id AND clusters.status = 2"). Where("alerts.organization_id = ?", organizationId)) + db.Count(&pg.TotalRows) pg.TotalPages = int(math.Ceil(float64(pg.TotalRows) / float64(pg.Limit))) @@ -161,6 +163,7 @@ func (r *AlertRepository) Create(dto domain.Alert) (alertId uuid.UUID, err error CheckPoint: dto.CheckPoint, Summary: dto.Summary, RawData: dto.RawData, + Status: domain.AlertActionStatus_CREATED, } res := r.db.Create(&alert) if res.Error != nil { @@ -198,6 +201,13 @@ func (r *AlertRepository) CreateAlertAction(dto domain.AlertAction) (alertAction if res.Error != nil { return uuid.Nil, res.Error } + res = r.db.Model(&Alert{}). + Where("id = ?", dto.AlertId). + Update("status", dto.Status) + if res.Error != nil { + return uuid.Nil, res.Error + } + return alert.ID, nil } @@ -223,6 +233,7 @@ func reflectAlert(alert Alert) domain.Alert { Summary: alert.Summary, AlertActions: outAlertActions, RawData: alert.RawData, + Status: alert.Status, CreatedAt: alert.CreatedAt, UpdatedAt: alert.UpdatedAt, } diff --git a/internal/repository/app-group.go b/internal/repository/app-group.go index 4d033e48..46f63d9a 100644 --- a/internal/repository/app-group.go +++ b/internal/repository/app-group.go @@ -82,7 +82,7 @@ func (r *AppGroupRepository) Fetch(clusterId domain.ClusterId, pg *pagination.Pa pg = pagination.NewDefaultPagination() } - filterFunc := CombinedGormFilter(pg.GetFilters(), pg.CombinedFilter) + filterFunc := CombinedGormFilter("app_groups", pg.GetFilters(), pg.CombinedFilter) db := filterFunc(r.db.Model(&AppGroup{}). Where("cluster_id = ?", clusterId)) db.Count(&pg.TotalRows) diff --git a/internal/repository/app-serve-app.go b/internal/repository/app-serve-app.go index 64b265a5..1e0ae2fc 100644 --- a/internal/repository/app-serve-app.go +++ b/internal/repository/app-serve-app.go @@ -63,7 +63,7 @@ func (r *AppServeAppRepository) GetAppServeApps(organizationId string, showAll b pg = pagination.NewDefaultPagination() } - filterFunc := CombinedGormFilter(pg.GetFilters(), pg.CombinedFilter) + filterFunc := CombinedGormFilter("app_serve_apps", pg.GetFilters(), pg.CombinedFilter) db := filterFunc(r.db.Model(&domain.AppServeApp{}). Where("app_serve_apps.organization_id = ? AND status <> 'DELETE_SUCCESS'", organizationId)) db.Count(&pg.TotalRows) diff --git a/internal/repository/cloud-account.go b/internal/repository/cloud-account.go index a4fc7da8..95e4b89c 100644 --- a/internal/repository/cloud-account.go +++ b/internal/repository/cloud-account.go @@ -41,8 +41,8 @@ type CloudAccount struct { ID uuid.UUID `gorm:"primarykey"` OrganizationId string Organization Organization `gorm:"foreignKey:OrganizationId"` - Name string - Description string + Name string `gorm:"index"` + Description string `gorm:"index"` Resource string CloudService string WorkflowId string @@ -99,7 +99,7 @@ func (r *CloudAccountRepository) Fetch(organizationId string, pg *pagination.Pag if pg == nil { pg = pagination.NewDefaultPagination() } - filterFunc := CombinedGormFilter(pg.GetFilters(), pg.CombinedFilter) + filterFunc := CombinedGormFilter("cloud_accounts", pg.GetFilters(), pg.CombinedFilter) db := filterFunc(r.db.Model(&CloudAccount{}). Preload(clause.Associations). Where("organization_id = ? AND status != ?", organizationId, domain.CloudAccountStatus_DELETED)) diff --git a/internal/repository/cluster.go b/internal/repository/cluster.go index 9cc690da..80ee8898 100644 --- a/internal/repository/cluster.go +++ b/internal/repository/cluster.go @@ -46,10 +46,10 @@ type Cluster struct { gorm.Model ID domain.ClusterId `gorm:"primarykey"` - Name string + Name string `gorm:"index"` OrganizationId string Organization Organization `gorm:"foreignKey:OrganizationId"` - Description string + Description string `gorm:"index"` WorkflowId string Status domain.ClusterStatus StatusDesc string @@ -89,7 +89,7 @@ func (r *ClusterRepository) Fetch(pg *pagination.Pagination) (out []domain.Clust if pg == nil { pg = pagination.NewDefaultPagination() } - filterFunc := CombinedGormFilter(pg.GetFilters(), pg.CombinedFilter) + filterFunc := CombinedGormFilter("clusters", pg.GetFilters(), pg.CombinedFilter) db := filterFunc(r.db.Model(&Cluster{})) db.Count(&pg.TotalRows) @@ -114,7 +114,7 @@ func (r *ClusterRepository) FetchByOrganizationId(organizationId string, pg *pag } pg.SortColumn = "updated_at" pg.SortOrder = "DESC" - filterFunc := CombinedGormFilter(pg.GetFilters(), pg.CombinedFilter) + filterFunc := CombinedGormFilter("clusters", pg.GetFilters(), pg.CombinedFilter) db := filterFunc(r.db.Model(&Cluster{}).Preload(clause.Associations). Where("organization_id = ? AND status != ?", organizationId, domain.ClusterStatus_DELETED)) @@ -140,7 +140,7 @@ func (r *ClusterRepository) FetchByCloudAccountId(cloudAccountId uuid.UUID, pg * } pg.SortColumn = "updated_at" pg.SortOrder = "DESC" - filterFunc := CombinedGormFilter(pg.GetFilters(), pg.CombinedFilter) + filterFunc := CombinedGormFilter("clusters", pg.GetFilters(), pg.CombinedFilter) db := filterFunc(r.db.Model(&Cluster{}).Preload("CloudAccount"). Where("cloud_account_id = ?", cloudAccountId)) diff --git a/internal/repository/organization.go b/internal/repository/organization.go index 0a2920f6..7e1312a0 100644 --- a/internal/repository/organization.go +++ b/internal/repository/organization.go @@ -78,7 +78,7 @@ func (r *OrganizationRepository) Fetch(pg *pagination.Pagination) (*[]domain.Org pg = pagination.NewDefaultPagination() } - filterFunc := CombinedGormFilter(pg.GetFilters(), pg.CombinedFilter) + filterFunc := CombinedGormFilter("organizations", pg.GetFilters(), pg.CombinedFilter) db := filterFunc(r.db.Model(&Organization{})) db.Count(&pg.TotalRows) diff --git a/internal/repository/repository.go b/internal/repository/repository.go index 9f1dd0ed..087579dd 100644 --- a/internal/repository/repository.go +++ b/internal/repository/repository.go @@ -21,19 +21,21 @@ type Repository struct { Alert IAlertRepository } -func CombinedGormFilter(filters []pagination.Filter, combinedFilter pagination.CombinedFilter) FilterFunc { +func CombinedGormFilter(table string, filters []pagination.Filter, combinedFilter pagination.CombinedFilter) FilterFunc { return func(db *gorm.DB) *gorm.DB { // and query for _, filter := range filters { if len(filter.Values) > 1 { - inQuery := fmt.Sprintf("%s in (", filter.Column) + inQuery := fmt.Sprintf("%s.%s::text in (", table, filter.Column) for _, val := range filter.Values { - inQuery = inQuery + fmt.Sprintf("'%s',", val) + inQuery = inQuery + fmt.Sprintf("LOWER('%s'),", val) } inQuery = inQuery[:len(inQuery)-1] + ")" db = db.Where(inQuery) } else { - db = db.Where(fmt.Sprintf("%s = '%s'", filter.Column, filter.Values[0])) + if len(filter.Values[0]) > 0 { + db = db.Where(fmt.Sprintf("%s.%s::text like LOWER('%%%s%%')", table, filter.Column, filter.Values[0])) + } } } @@ -42,7 +44,7 @@ func CombinedGormFilter(filters []pagination.Filter, combinedFilter pagination.C if len(combinedFilter.Columns) > 0 { orQuery := "" for _, column := range combinedFilter.Columns { - orQuery = orQuery + fmt.Sprintf("%s like '%%%s%%' OR ", column, combinedFilter.Value) + orQuery = orQuery + fmt.Sprintf("%s.%s::text like LOWER('%%%s%%') OR ", table, column, combinedFilter.Value) } orQuery = orQuery[:len(orQuery)-3] db = db.Where(orQuery) diff --git a/internal/repository/stack-template.go b/internal/repository/stack-template.go index b027ec77..dc27b967 100644 --- a/internal/repository/stack-template.go +++ b/internal/repository/stack-template.go @@ -39,8 +39,8 @@ type StackTemplate struct { ID uuid.UUID `gorm:"primarykey"` OrganizationId string Organization Organization `gorm:"foreignKey:OrganizationId"` - Name string - Description string + Name string `gorm:"index"` + Description string `gorm:"index"` Template string Version string CloudService string @@ -77,7 +77,7 @@ func (r *StackTemplateRepository) Fetch(pg *pagination.Pagination) (out []domain pg = pagination.NewDefaultPagination() } - filterFunc := CombinedGormFilter(pg.GetFilters(), pg.CombinedFilter) + filterFunc := CombinedGormFilter("stack_templates", pg.GetFilters(), pg.CombinedFilter) db := filterFunc(r.db.Model(&StackTemplate{})) db.Count(&pg.TotalRows) diff --git a/internal/usecase/alert.go b/internal/usecase/alert.go index fb46007f..99fafa9c 100644 --- a/internal/usecase/alert.go +++ b/internal/usecase/alert.go @@ -225,7 +225,7 @@ func (u *AlertUsecase) getOrganizationFromCluster(clusters *[]domain.Cluster, st func (u *AlertUsecase) makeAdditionalInfo(alert *domain.Alert) { alert.FiredAt = &alert.CreatedAt - alert.Status = domain.AlertActionStatus_CREATED + //alert.Status = domain.AlertActionStatus_CREATED if len(alert.AlertActions) > 0 { alert.TakedAt = &alert.AlertActions[0].CreatedAt @@ -238,7 +238,7 @@ func (u *AlertUsecase) makeAdditionalInfo(alert *domain.Alert) { alert.LastTaker = alert.AlertActions[len(alert.AlertActions)-1].Taker alert.TakedSec = int((alert.AlertActions[0].CreatedAt).Sub(alert.CreatedAt).Seconds()) - alert.Status = alert.AlertActions[len(alert.AlertActions)-1].Status + //alert.Status = alert.AlertActions[len(alert.AlertActions)-1].Status } } diff --git a/pkg/domain/app-serve-app.go b/pkg/domain/app-serve-app.go index e59c33d0..4edcc92d 100644 --- a/pkg/domain/app-serve-app.go +++ b/pkg/domain/app-serve-app.go @@ -9,7 +9,7 @@ import ( type AppServeApp struct { ID string `gorm:"primarykey" json:"id,omitempty"` - Name string `json:"name,omitempty"` // application name + Name string `gorm:"index" json:"name,omitempty"` // application name Namespace string `json:"namespace,omitempty"` // application namespace OrganizationId string `json:"organizationId,omitempty"` // contractId is a contract ID which this app belongs to Type string `json:"type,omitempty"` // type (build/deploy/all) @@ -18,7 +18,7 @@ type AppServeApp struct { PreviewEndpointUrl string `json:"previewEndpointUrl,omitempty"` // preview svc endpoint URL in B/G deployment TargetClusterId string `json:"targetClusterId,omitempty"` // target cluster to which the app is deployed TargetClusterName string `gorm:"-:all" json:"targetClusterName,omitempty"` // target cluster name - Status string `json:"status,omitempty"` // status is status of deployed app + Status string `gorm:"index" json:"status,omitempty"` // status is status of deployed app CreatedAt time.Time `gorm:"autoCreateTime:false" json:"createdAt" ` UpdatedAt *time.Time `gorm:"autoUpdateTime:false" json:"updatedAt"` DeletedAt *time.Time `json:"deletedAt"` From 7b2640cb7b2999bbf6eb6705bc86649998ecbcb0 Mon Sep 17 00:00:00 2001 From: donggyu Date: Wed, 19 Jul 2023 13:46:09 +0900 Subject: [PATCH 34/54] improve email contents with html code --- internal/aws/ses/contents/authcode.html | 107 +++++++++++++ .../ses/contents/organization_creation.html | 129 ++++++++++++++++ .../aws/ses/contents/temporary_password.html | 107 +++++++++++++ internal/aws/ses/ses.go | 146 +++++++++++------- 4 files changed, 432 insertions(+), 57 deletions(-) create mode 100644 internal/aws/ses/contents/authcode.html create mode 100644 internal/aws/ses/contents/organization_creation.html create mode 100644 internal/aws/ses/contents/temporary_password.html diff --git a/internal/aws/ses/contents/authcode.html b/internal/aws/ses/contents/authcode.html new file mode 100644 index 00000000..09f79474 --- /dev/null +++ b/internal/aws/ses/contents/authcode.html @@ -0,0 +1,107 @@ + + + + + 이메일인증 안내 + + + +
+ + + + + + + + + + + + + + + +
SKT Enterprise
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 이메일 인증 안내 +
안녕하세요.
항상 저희 TKS Cloud Service를 사랑해 주시고 성원해 주시는 고객님께 감사드립니다.
+ 고객님께서 입력하신 이메일 주소 인증을 위해 아래 6자리 인증번호를 +
화면에 입력해 주세요.
이메일 인증코드
{{.AuthCode}}
더욱 편리한 서비스를 제공하기 위해 항상 최선을 다하겠습니다.
감사합니다.
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
본 메일은 발신 전용 메일로, 회신 되지 않습니다.
우편번호: 04539 서울특별시중구을지로65 (을지로2가) SK T-타워 SK텔레콤㈜ 대표이사 : 유영상
COPYRIGHT SK TELECOM CO., LTD. ALL RIGHTS RESERVED.
+
+
+ + + diff --git a/internal/aws/ses/contents/organization_creation.html b/internal/aws/ses/contents/organization_creation.html new file mode 100644 index 00000000..988411d7 --- /dev/null +++ b/internal/aws/ses/contents/organization_creation.html @@ -0,0 +1,129 @@ + + + + + 조직 생성 + + + +
+ + + + + + + + + + + + + + + +
SKT Enterprise
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ​ + + + + + + + + + + + + +
+ 조직 생성 안내 +
안녕하세요.
항상 저희 TKS Cloud Service를 사랑해 주시고 성원해 주시는 고객님께 감사드립니다.
+ 조직이 생성되었습니다. +
아래의 정보를 이용하여 로그인 해주시기 바랍니다.
로그인 정보
+ • 조직코드: {{.OrganizationId}} +
• 아이디: {{.Id}} +
• 비밀번호: {{.Password}} +
조직 정보
+ • 조직이름: {{.OrganizationName}} +
• 관리자 이름: {{.AdminName}} +
더욱 편리한 서비스를 제공하기 위해 항상 최선을 다하겠습니다.
감사합니다.
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
본 메일은 발신 전용 메일로, 회신 되지 않습니다.
우편번호: 04539 서울특별시중구을지로65 (을지로2가) SK T-타워 SK텔레콤㈜ 대표이사 : 유영상
COPYRIGHT SK TELECOM CO., LTD. ALL RIGHTS RESERVED.
+
+
+ + + diff --git a/internal/aws/ses/contents/temporary_password.html b/internal/aws/ses/contents/temporary_password.html new file mode 100644 index 00000000..775f434a --- /dev/null +++ b/internal/aws/ses/contents/temporary_password.html @@ -0,0 +1,107 @@ + + + + + 임시 비밀번호 발급 + + + +
+ + + + + + + + + + + + + + + +
SKT Enterprise
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 임시 비밀번호 발급 안내 +
안녕하세요.
항상 저희 TKS Cloud Service를 사랑해 주시고 성원해 주시는 고객님께 감사드립니다.
+ 임시 비밀번호가 발급되었습니다. +
로그인 후 비밀번호를 변경하여 사용해 주시기 바랍니다.
임시 비밀번호
{{.TemporaryPassword}}
더욱 편리한 서비스를 제공하기 위해 항상 최선을 다하겠습니다.
감사합니다.
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
본 메일은 발신 전용 메일로, 회신 되지 않습니다.
우편번호: 04539 서울특별시중구을지로65 (을지로2가) SK T-타워 SK텔레콤㈜ 대표이사 : 유영상
COPYRIGHT SK TELECOM CO., LTD. ALL RIGHTS RESERVED.
+
+
+ + + diff --git a/internal/aws/ses/ses.go b/internal/aws/ses/ses.go index f1cce3a4..ec24c54e 100644 --- a/internal/aws/ses/ses.go +++ b/internal/aws/ses/ses.go @@ -1,8 +1,11 @@ package ses import ( + "bytes" "context" + "embed" "fmt" + "html/template" "os" "github.com/aws/aws-sdk-go-v2/aws" @@ -13,12 +16,13 @@ import ( "github.com/spf13/viper" ) +//go:embed contents/*.html +var templateFS embed.FS + var Client *awsSes.Client const ( senderEmailAddress = "tks-dev@sktelecom.com" - - thanksContent = "TKS Cloud Service를 이용해 주셔서 감사합니다.\nTKS Cloud Service Team 드림" ) func Initialize() error { @@ -55,90 +59,118 @@ func Initialize() error { return nil } func SendEmailForVerityIdentity(client *awsSes.Client, targetEmailAddress string, code string) error { - subject := "[TKS][인증번호:" + code + "] – 요청하신 인증번호를 알려드립니다." - body := "아래의 인증번호를 인증번호 입력창에 입력해 주세요.\n\n" + - "인증번호: " + code + "\n\n" + - thanksContent + subject := "[TKS] [인증번호:" + code + "] 인증번호가 발급되었습니다." - input := &awsSes.SendEmailInput{ - Destination: &types.Destination{ - ToAddresses: []string{targetEmailAddress}, - }, - Message: &types.Message{ - Body: &types.Body{ - Text: &types.Content{ - Data: aws.String(body), - }, - }, - Subject: &types.Content{ - Data: aws.String(subject), - }, - }, - Source: aws.String(senderEmailAddress), + tmpl, err := template.ParseFS(templateFS, "contents/authcode.html") + if err != nil { + log.Errorf("failed to parse template, %v", err) + return err } - if _, err := client.SendEmail(context.Background(), input); err != nil { - log.Errorf("failed to send email, %v", err) + type TemplateData struct { + AuthCode string + } + + data := TemplateData{ + AuthCode: fmt.Sprintf("%s", code), + } + + var tpl bytes.Buffer + if err := tmpl.Execute(&tpl, data); err != nil { + log.Errorf("failed to execute template, %v", err) return err } + body := tpl.String() + + err = sendEmail(client, targetEmailAddress, subject, body) + if err != nil { + return err + } return nil } func SendEmailForTemporaryPassword(client *awsSes.Client, targetEmailAddress string, randomPassword string) error { - subject := "[TKS] 임시 비밀번호 발급" - body := "임시 비밀번호가 발급되었습니다.\n" + - "로그인 후 비밀번호를 변경하여 사용하십시오.\n\n" + - "임시 비밀번호: " + randomPassword + "\n\n" + - thanksContent + subject := "[TKS] 임시 비밀번호가 발급되었습니다." - input := &awsSes.SendEmailInput{ - Destination: &types.Destination{ - ToAddresses: []string{targetEmailAddress}, - }, - Message: &types.Message{ - Body: &types.Body{ - Text: &types.Content{ - Data: aws.String(body), - }, - }, - Subject: &types.Content{ - Data: aws.String(subject), - }, - }, - Source: aws.String(senderEmailAddress), + tmpl, err := template.ParseFS(templateFS, "contents/temporary_password.html") + if err != nil { + log.Errorf("failed to parse template, %v", err) + return err } - if _, err := client.SendEmail(context.Background(), input); err != nil { - log.Errorf("failed to send email, %v", err) + type TemplateData struct { + TemporaryPassword string + } + + data := TemplateData{ + TemporaryPassword: fmt.Sprintf("%s", randomPassword), + } + + var tpl bytes.Buffer + if err := tmpl.Execute(&tpl, data); err != nil { + log.Errorf("failed to execute template, %v", err) return err } + body := tpl.String() + + err = sendEmail(client, targetEmailAddress, subject, body) + if err != nil { + return err + } return nil } func SendEmailForGeneratingOrganization(client *awsSes.Client, organizationId string, organizationName string, targetEmailAddress string, userAccountId string, randomPassword string) error { subject := "[TKS] 조직이 생성되었습니다." - body := "조직이 생성되었습니다. \n" + - "조직코드: " + organizationId + "\n" + - "이름: " + organizationName + "\n" + - "관리자 아이디: " + userAccountId + "\n" + - "관리자 이름: admin\n\n" + - "아래 관리자 계정 정보로 로그인 후 사용하시기 바랍니다.\n" + - "조직코드: " + organizationId + "\n" + - "아이디: " + userAccountId + "\n" + - "비밀번호: " + randomPassword + "\n\n" + - thanksContent + tmpl, err := template.ParseFS(templateFS, "contents/organization_creation.html") + if err != nil { + log.Errorf("failed to parse template, %v", err) + return err + } + + type TemplateData struct { + OrganizationId string + Id string + Password string + OrganizationName string + AdminName string + } + + data := TemplateData{ + OrganizationId: fmt.Sprintf("%s", organizationId), + Id: fmt.Sprintf("%s", userAccountId), + Password: fmt.Sprintf("%s", randomPassword), + OrganizationName: fmt.Sprintf("%s", organizationName), + AdminName: fmt.Sprintf("%s", userAccountId), + } + + var tpl bytes.Buffer + if err := tmpl.Execute(&tpl, data); err != nil { + log.Errorf("failed to execute template, %v", err) + return err + } + body := tpl.String() + + err = sendEmail(client, targetEmailAddress, subject, body) + if err != nil { + return err + } + return nil +} + +func sendEmail(client *awsSes.Client, targetEmailAddress string, subject string, htmlBody string) error { input := &awsSes.SendEmailInput{ Destination: &types.Destination{ ToAddresses: []string{targetEmailAddress}, }, Message: &types.Message{ Body: &types.Body{ - Text: &types.Content{ - Data: aws.String(body), + Html: &types.Content{ + Data: aws.String(htmlBody), }, }, Subject: &types.Content{ From 0bdbe338e1c5a8effb1f1d9e6bccacb693981c51 Mon Sep 17 00:00:00 2001 From: donggyu Date: Wed, 19 Jul 2023 13:58:43 +0900 Subject: [PATCH 35/54] lint fix --- internal/aws/ses/ses.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/internal/aws/ses/ses.go b/internal/aws/ses/ses.go index ec24c54e..f99bdc42 100644 --- a/internal/aws/ses/ses.go +++ b/internal/aws/ses/ses.go @@ -72,7 +72,7 @@ func SendEmailForVerityIdentity(client *awsSes.Client, targetEmailAddress string } data := TemplateData{ - AuthCode: fmt.Sprintf("%s", code), + AuthCode: code, } var tpl bytes.Buffer @@ -104,7 +104,7 @@ func SendEmailForTemporaryPassword(client *awsSes.Client, targetEmailAddress str } data := TemplateData{ - TemporaryPassword: fmt.Sprintf("%s", randomPassword), + TemporaryPassword: randomPassword, } var tpl bytes.Buffer @@ -141,11 +141,11 @@ func SendEmailForGeneratingOrganization(client *awsSes.Client, organizationId st } data := TemplateData{ - OrganizationId: fmt.Sprintf("%s", organizationId), - Id: fmt.Sprintf("%s", userAccountId), - Password: fmt.Sprintf("%s", randomPassword), - OrganizationName: fmt.Sprintf("%s", organizationName), - AdminName: fmt.Sprintf("%s", userAccountId), + OrganizationId: organizationId, + Id: userAccountId, + Password: randomPassword, + OrganizationName: organizationName, + AdminName: userAccountId, } var tpl bytes.Buffer From 3200b83ebe304659b896ea7a113a2f0928584c50 Mon Sep 17 00:00:00 2001 From: Robert Choi Date: Thu, 20 Jul 2023 11:20:43 +0900 Subject: [PATCH 36/54] app-serving: handle case that extraEnv is not given --- internal/usecase/app-serve-app.go | 82 ++++++++++++++++--------------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/internal/usecase/app-serve-app.go b/internal/usecase/app-serve-app.go index 1d010bc5..4b46f41f 100644 --- a/internal/usecase/app-serve-app.go +++ b/internal/usecase/app-serve-app.go @@ -97,29 +97,31 @@ func (u *AppServeAppUsecase) CreateAppServeApp(app *domain.AppServeApp) (string, fmt.Printf("appId = %s, taskId = %s", appId, taskId) - /* Preprocess extraEnv param */ extEnv := app.AppServeAppTasks[0].ExtraEnv - log.Debug("extraEnv received: ", extEnv) + if extEnv != "" { + /* Preprocess extraEnv param */ + log.Debug("extraEnv received: ", extEnv) + + tempMap := map[string]string{} + err = json.Unmarshal([]byte(extEnv), &tempMap) + if err != nil { + log.Error(err) + return "", "", errors.Wrap(err, "Failed to process extraEnv param.") + } + log.Debugf("extraEnv marshalled: %v", tempMap) - tempMap := map[string]string{} - err = json.Unmarshal([]byte(extEnv), &tempMap) - if err != nil { - log.Error(err) - return "", "", errors.Wrap(err, "Failed to process extraEnv param.") - } - log.Debugf("extraEnv marshalled: %v", tempMap) + newExtEnv := map[string]string{} + for key, val := range tempMap { + newkey := "\"" + key + "\"" + newval := "\"" + val + "\"" + newExtEnv[newkey] = newval + } - newExtEnv := map[string]string{} - for key, val := range tempMap { - newkey := "\"" + key + "\"" - newval := "\"" + val + "\"" - newExtEnv[newkey] = newval + mJson, _ := json.Marshal(newExtEnv) + extEnv := string(mJson) + log.Debug("After transform, extraEnv: ", extEnv) } - mJson, _ := json.Marshal(newExtEnv) - newExtEnvStr := string(mJson) - log.Debug("After transform, extraEnv: ", newExtEnvStr) - // TODO: Validate PV params // Call argo workflow @@ -140,7 +142,7 @@ func (u *AppServeAppUsecase) CreateAppServeApp(app *domain.AppServeApp) (string, "image_url=" + app.AppServeAppTasks[0].ImageUrl, "port=" + app.AppServeAppTasks[0].Port, "profile=" + app.AppServeAppTasks[0].Profile, - "extra_env=" + newExtEnvStr, + "extra_env=" + extEnv, "app_config=" + app.AppServeAppTasks[0].AppConfig, "app_secret=" + app.AppServeAppTasks[0].AppSecret, "resource_spec=" + app.AppServeAppTasks[0].ResourceSpec, @@ -393,29 +395,31 @@ func (u *AppServeAppUsecase) UpdateAppServeApp(app *domain.AppServeApp, appTask return "", fmt.Errorf("failed to update app status on UpdateAppServeApp. Err: %s", err) } - // Preprocess extraEnv param extEnv := appTask.ExtraEnv - log.Debug("extraEnv received: ", extEnv) - - tempMap := map[string]string{} - err = json.Unmarshal([]byte(extEnv), &tempMap) - if err != nil { - log.Error(err) - return "", errors.Wrap(err, "Failed to process extraEnv param.") - } - log.Debugf("extraEnv marshalled: %v", tempMap) + if extEnv != "" { + /* Preprocess extraEnv param */ + log.Debug("extraEnv received: ", extEnv) + + tempMap := map[string]string{} + err = json.Unmarshal([]byte(extEnv), &tempMap) + if err != nil { + log.Error(err) + return "", errors.Wrap(err, "Failed to process extraEnv param.") + } + log.Debugf("extraEnv marshalled: %v", tempMap) - newExtEnv := map[string]string{} - for key, val := range tempMap { - newkey := "\"" + key + "\"" - newval := "\"" + val + "\"" - newExtEnv[newkey] = newval - } + newExtEnv := map[string]string{} + for key, val := range tempMap { + newkey := "\"" + key + "\"" + newval := "\"" + val + "\"" + newExtEnv[newkey] = newval + } - mJson, _ := json.Marshal(newExtEnv) - newExtEnvStr := string(mJson) + mJson, _ := json.Marshal(newExtEnv) + extEnv = string(mJson) - log.Debug("After transform, extraEnv: ", newExtEnvStr) + log.Debug("After transform, extraEnv: ", extEnv) + } // Call argo workflow workflow := "serve-java-app" @@ -437,7 +441,7 @@ func (u *AppServeAppUsecase) UpdateAppServeApp(app *domain.AppServeApp, appTask "image_url=" + appTask.ImageUrl, "port=" + appTask.Port, "profile=" + appTask.Profile, - "extra_env=" + newExtEnvStr, + "extra_env=" + extEnv, "app_config=" + appTask.AppConfig, "app_secret=" + appTask.AppSecret, "resource_spec=" + appTask.ResourceSpec, From 788a731d441416dcaeb99a12e99128b66fb97487 Mon Sep 17 00:00:00 2001 From: Taekyu Date: Thu, 20 Jul 2023 11:25:24 +0900 Subject: [PATCH 37/54] feature. re-architecutring pod-restart calendar on dashboard. --- api/swagger/docs.go | 17 ++++ api/swagger/swagger.json | 17 ++++ api/swagger/swagger.yaml | 11 +++ internal/usecase/dashboard.go | 166 ++++------------------------------ pkg/domain/dashboard.go | 12 ++- 5 files changed, 73 insertions(+), 150 deletions(-) diff --git a/api/swagger/docs.go b/api/swagger/docs.go index cf803d99..77172154 100644 --- a/api/swagger/docs.go +++ b/api/swagger/docs.go @@ -3905,6 +3905,12 @@ const docTemplate = `{ "domain.ChartData": { "type": "object", "properties": { + "podCounts": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.PodCount" + } + }, "series": { "type": "array", "items": { @@ -5357,6 +5363,17 @@ const docTemplate = `{ } } }, + "domain.PodCount": { + "type": "object", + "properties": { + "day": { + "type": "integer" + }, + "value": { + "type": "integer" + } + } + }, "domain.Role": { "type": "object", "properties": { diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index 2738fb7e..cd91d143 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -3898,6 +3898,12 @@ "domain.ChartData": { "type": "object", "properties": { + "podCounts": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.PodCount" + } + }, "series": { "type": "array", "items": { @@ -5350,6 +5356,17 @@ } } }, + "domain.PodCount": { + "type": "object", + "properties": { + "day": { + "type": "integer" + }, + "value": { + "type": "integer" + } + } + }, "domain.Role": { "type": "object", "properties": { diff --git a/api/swagger/swagger.yaml b/api/swagger/swagger.yaml index c23032ea..4227bbed 100644 --- a/api/swagger/swagger.yaml +++ b/api/swagger/swagger.yaml @@ -251,6 +251,10 @@ definitions: type: object domain.ChartData: properties: + podCounts: + items: + $ref: '#/definitions/domain.PodCount' + type: array series: items: $ref: '#/definitions/domain.Unit' @@ -1217,6 +1221,13 @@ definitions: totalRows: type: integer type: object + domain.PodCount: + properties: + day: + type: integer + value: + type: integer + type: object domain.Role: properties: createdAt: diff --git a/internal/usecase/dashboard.go b/internal/usecase/dashboard.go index 1c4b6d79..f91732ca 100644 --- a/internal/usecase/dashboard.go +++ b/internal/usecase/dashboard.go @@ -273,101 +273,6 @@ func (u *DashboardUsecase) getChartFromPrometheus(organizationId string, chartTy query = "avg by (taco_cluster) (rate(container_network_receive_bytes_total[1h]))" case domain.ChartType_POD_CALENDAR.String(): - /* - // 입력받은 년,월 을 date 형식으로 - yearInt, _ := strconv.Atoi(year) - monthInt, _ := strconv.Atoi(month) - startDate := time.Date(yearInt, time.Month(monthInt), 1, 0, 0, 0, 0, time.UTC) - endDate := startDate.Add(time.Hour * 24 * 30) - - start := 0 - end := 0 - if now.Year() < yearInt { - return res, fmt.Errorf("Invalid year") - } else if now.Year() == yearInt && int(now.Month()) < monthInt { - return res, fmt.Errorf("Invalid month") - } else if now.Year() == yearInt && int(now.Month()) == monthInt { - start = int(startDate.Unix()) - end = int(now.Unix()) - } else { - start = int(startDate.Unix()) - end = int(endDate.Unix()) - } - - log.Debugf("S : %d E : %d", start, end) - - query = "sum by (__name__) ({__name__=~\"kube_pod_container_status_restarts_total|kube_pod_status_phase\"})" - - result, err := thanosClient.FetchRange(query, start, end, 60*60*24) - if err != nil { - return res, err - } - - for _, val := range result.Data.Result { - xAxisData := []string{} - yAxisData := []string{} - - for _, vals := range val.Values { - x := int(math.Round(vals.([]interface{})[0].(float64))) - y, err := strconv.ParseFloat(vals.([]interface{})[1].(string), 32) - if err != nil { - y = 0 - } - xAxisData = append(xAxisData, strconv.Itoa(x)) - yAxisData = append(yAxisData, fmt.Sprintf("%d", int(y))) - } - - if val.Metric.Name == "kube_pod_container_status_restarts_total" { - chartData.XAxis.Data = xAxisData - chartData.Series = append(chartData.Series, domain.Unit{ - Name: "date", - Data: xAxisData, - }) - chartData.Series = append(chartData.Series, domain.Unit{ - Name: "podRestartCount", - Data: yAxisData, - }) - } - - if val.Metric.Name == "kube_pod_status_phase" { - chartData.Series = append(chartData.Series, domain.Unit{ - Name: "totalPodCount", - Data: yAxisData, - }) - } - } - - - { - series : [ - { - name : date, - data : [ - "timestamp1", - "timestamp2" - "timestamp3" - ] - }, - { - name : podRestartCount, - data : [ - "1", - "2" - "3" - ] - }, - { - name : totalPodCount, - data : [ - "10", - "20" - "30" - ] - }, - ] - } - */ - // 입력받은 년,월 을 date 형식으로 yearInt, _ := strconv.Atoi(year) monthInt, _ := strconv.Atoi(month) @@ -385,20 +290,24 @@ func (u *DashboardUsecase) getChartFromPrometheus(organizationId string, chartTy return res, err } - xAxisData := []string{} - yAxisData := []string{} + organization, err := u.organizationRepo.Get(organizationId) + if err != nil { + return res, err + } + + log.Info(organization.CreatedAt.Format("2006-01-02")) + podCounts := []domain.PodCount{} for day := rangeDate(startDate, endDate); ; { d := day() if d.IsZero() { break } - baseDate := d.Format("2006-01-02") - cntPodRestartStr := "" + baseDate := d.Format("2006-01-02") cntPodRestart := 0 - if baseDate <= now.Format("2006-01-02") { + if baseDate <= now.Format("2006-01-02") && baseDate >= organization.CreatedAt.Format("2006-01-02") { for _, alert := range alerts { strDate := alert.CreatedAt.Format("2006-01-02") @@ -406,55 +315,16 @@ func (u *DashboardUsecase) getChartFromPrometheus(organizationId string, chartTy cntPodRestart += 1 } } - cntPodRestartStr = fmt.Sprintf("%d", int(cntPodRestart)) - } - - dd := time.Date(d.Year(), d.Month(), d.Day(), 0, 0, 0, 0, time.UTC) - xAxisData = append(xAxisData, strconv.Itoa(int(dd.Unix()))) - yAxisData = append(yAxisData, cntPodRestartStr) - } - - chartData.XAxis.Data = xAxisData - chartData.Series = append(chartData.Series, domain.Unit{ - Name: "podRestartCount", - Data: yAxisData, - }) - - /* - for _, alert := range alerts { - xAxisData := []string{} - yAxisData := []string{} - - for _, vals := range val.Values { - x := int(math.Round(vals.([]interface{})[0].(float64))) - y, err := strconv.ParseFloat(vals.([]interface{})[1].(string), 32) - if err != nil { - y = 0 - } - xAxisData = append(xAxisData, strconv.Itoa(x)) - yAxisData = append(yAxisData, fmt.Sprintf("%d", int(y))) - } - - if val.Metric.Name == "kube_pod_container_status_restarts_total" { - chartData.XAxis.Data = xAxisData - chartData.Series = append(chartData.Series, domain.Unit{ - Name: "date", - Data: xAxisData, - }) - chartData.Series = append(chartData.Series, domain.Unit{ - Name: "podRestartCount", - Data: yAxisData, - }) - } - - if val.Metric.Name == "kube_pod_status_phase" { - chartData.Series = append(chartData.Series, domain.Unit{ - Name: "totalPodCount", - Data: yAxisData, - }) + pd := domain.PodCount{ + Day: d.Day(), + Value: int(cntPodRestart), } + podCounts = append(podCounts, pd) } - */ + } + chartData.XAxis = nil + chartData.YAxis = nil + chartData.PodCounts = podCounts return domain.DashboardChart{ ChartType: domain.ChartType_POD_CALENDAR, @@ -508,7 +378,9 @@ func (u *DashboardUsecase) getChartFromPrometheus(organizationId string, chartTy Name: clusterName, Data: yAxisData, }) + } + chartData.XAxis = &domain.Axis{} chartData.XAxis.Data = xAxisData return domain.DashboardChart{ diff --git a/pkg/domain/dashboard.go b/pkg/domain/dashboard.go index b27616a0..c7699fb7 100644 --- a/pkg/domain/dashboard.go +++ b/pkg/domain/dashboard.go @@ -81,10 +81,16 @@ type Axis struct { Data []string `json:"data"` } +type PodCount struct { + Day int `json:"day"` + Value int `json:"value"` +} + type ChartData struct { - XAxis Axis `json:"xAxis"` - YAxis Axis `json:"yAxis"` - Series []Unit `json:"series"` + XAxis *Axis `json:"xAxis,omitempty"` + YAxis *Axis `json:"yAxis,omitempty"` + Series []Unit `json:"series,omitempty"` + PodCounts []PodCount `json:"podCounts,omitempty"` } type DashboardChartResponse struct { From b0255bc2116f0c1d1bba2be9979f011985b967a5 Mon Sep 17 00:00:00 2001 From: Robert Choi Date: Thu, 20 Jul 2023 14:51:50 +0900 Subject: [PATCH 38/54] trivial: remove garbage log msg --- internal/repository/app-serve-app.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/repository/app-serve-app.go b/internal/repository/app-serve-app.go index 1e0ae2fc..d27adfb6 100644 --- a/internal/repository/app-serve-app.go +++ b/internal/repository/app-serve-app.go @@ -120,7 +120,6 @@ func (r *AppServeAppRepository) GetAppServeAppById(appId string) (*domain.AppSer // Add cluster name to app object r.db.Select("name").Where("id = ?", app.TargetClusterId).First(&cluster) app.TargetClusterName = cluster.Name - log.Infof("App struct with cluster name:\n%+v", app) return &app, nil } From 7a0c749b48c432bb9f8b824b8f12f60a61fa32ac Mon Sep 17 00:00:00 2001 From: Taekyu Date: Thu, 20 Jul 2023 15:07:20 +0900 Subject: [PATCH 39/54] feature. change organization paramter for deleting appgroup --- internal/delivery/http/app-group.go | 9 +-------- internal/usecase/app-group.go | 13 ++++++++----- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/internal/delivery/http/app-group.go b/internal/delivery/http/app-group.go index 624a5779..84667143 100644 --- a/internal/delivery/http/app-group.go +++ b/internal/delivery/http/app-group.go @@ -6,7 +6,6 @@ import ( "github.com/gorilla/mux" "github.com/openinfradev/tks-api/internal/helper" - "github.com/openinfradev/tks-api/internal/middleware/auth/request" "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/internal/usecase" "github.com/openinfradev/tks-api/pkg/domain" @@ -157,12 +156,6 @@ func (h *AppGroupHandler) GetAppGroup(w http.ResponseWriter, r *http.Request) { // @Router /app-groups [delete] // @Security JWT func (h *AppGroupHandler) DeleteAppGroup(w http.ResponseWriter, r *http.Request) { - user, ok := request.UserFrom(r.Context()) - if !ok { - ErrorJSON(w, r, httpErrors.NewUnauthorizedError(fmt.Errorf("Invalid token"), "A_INVALID_TOKEN", "")) - return - } - vars := mux.Vars(r) strId, ok := vars["appGroupId"] if !ok { @@ -176,7 +169,7 @@ func (h *AppGroupHandler) DeleteAppGroup(w http.ResponseWriter, r *http.Request) return } - err := h.usecase.Delete(r.Context(), user.GetOrganizationId(), appGroupId) + err := h.usecase.Delete(r.Context(), appGroupId) if err != nil { log.ErrorWithContext(r.Context(), "Failed to delete appGroup err : ", err) ErrorJSON(w, r, err) diff --git a/internal/usecase/app-group.go b/internal/usecase/app-group.go index 14eab49c..ce93c40b 100644 --- a/internal/usecase/app-group.go +++ b/internal/usecase/app-group.go @@ -20,7 +20,7 @@ type IAppGroupUsecase interface { Fetch(ctx context.Context, clusterId domain.ClusterId, pg *pagination.Pagination) ([]domain.AppGroup, error) Create(ctx context.Context, dto domain.AppGroup) (id domain.AppGroupId, err error) Get(ctx context.Context, id domain.AppGroupId) (out domain.AppGroup, err error) - Delete(ctx context.Context, organizationId string, id domain.AppGroupId) (err error) + Delete(ctx context.Context, id domain.AppGroupId) (err error) GetApplications(ctx context.Context, id domain.AppGroupId, applicationType domain.ApplicationType) (out []domain.Application, err error) UpdateApplication(ctx context.Context, dto domain.Application) (err error) } @@ -134,13 +134,16 @@ func (u *AppGroupUsecase) Get(ctx context.Context, id domain.AppGroupId) (out do return appGroup, nil } -func (u *AppGroupUsecase) Delete(ctx context.Context, organizationId string, id domain.AppGroupId) (err error) { +func (u *AppGroupUsecase) Delete(ctx context.Context, id domain.AppGroupId) (err error) { appGroup, err := u.repo.Get(id) if err != nil { return fmt.Errorf("No appGroup for deletiing : %s", id) } - - clusterId := appGroup.ClusterId + cluster, err := u.clusterRepo.Get(appGroup.ClusterId) + if err != nil { + return httpErrors.NewBadRequestError(err, "AG_NOT_FOUND_CLUSTER", "") + } + organizationId := cluster.OrganizationId // Call argo workflow template workflowTemplate := "" @@ -164,7 +167,7 @@ func (u *AppGroupUsecase) Delete(ctx context.Context, organizationId string, id "organization_id=" + organizationId, "app_group=" + appGroupName, "github_account=" + viper.GetString("git-account"), - "cluster_id=" + clusterId.String(), + "cluster_id=" + cluster.ID.String(), "app_group_id=" + id.String(), "keycloak_url=" + strings.TrimSuffix(viper.GetString("keycloak-address"), "/auth"), "base_repo_branch=" + viper.GetString("revision"), From c9183d9e126ff9006bbfe8a5c093d3e7bc35352d Mon Sep 17 00:00:00 2001 From: Taekyu Date: Wed, 26 Jul 2023 15:22:44 +0900 Subject: [PATCH 40/54] feature. add workflow paramter for supporting s3. --- internal/usecase/app-group.go | 37 +++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/internal/usecase/app-group.go b/internal/usecase/app-group.go index ce93c40b..ab1f74bd 100644 --- a/internal/usecase/app-group.go +++ b/internal/usecase/app-group.go @@ -26,16 +26,18 @@ type IAppGroupUsecase interface { } type AppGroupUsecase struct { - repo repository.IAppGroupRepository - clusterRepo repository.IClusterRepository - argo argowf.ArgoClient + repo repository.IAppGroupRepository + clusterRepo repository.IClusterRepository + cloudAccountRepo repository.ICloudAccountRepository + argo argowf.ArgoClient } func NewAppGroupUsecase(r repository.Repository, argoClient argowf.ArgoClient) IAppGroupUsecase { return &AppGroupUsecase{ - repo: r.AppGroup, - clusterRepo: r.Cluster, - argo: argoClient, + repo: r.AppGroup, + clusterRepo: r.Cluster, + cloudAccountRepo: r.CloudAccount, + argo: argoClient, } } @@ -75,6 +77,28 @@ func (u *AppGroupUsecase) Create(ctx context.Context, dto domain.AppGroup) (id d } } + // check cloudAccount + cloudAccounts, err := u.cloudAccountRepo.Fetch(cluster.OrganizationId, nil) + if err != nil { + return "", httpErrors.NewBadRequestError(fmt.Errorf("Failed to get cloudAccounts"), "", "") + } + tksCloudAccountId := cluster.CloudAccountId.String() + isExist := false + for _, ca := range cloudAccounts { + if ca.ID == cluster.CloudAccountId { + + // FOR TEST. ADD MAGIC KEYWORD + if strings.Contains(ca.Name, domain.CLOUD_ACCOUNT_INCLUSTER) { + tksCloudAccountId = "NULL" + } + isExist = true + break + } + } + if !isExist { + return "", httpErrors.NewBadRequestError(fmt.Errorf("Not found cloudAccountId[%s] in organization[%s]", cluster.CloudAccountId, cluster.OrganizationId), "", "") + } + if dto.ID == "" { dto.ID, err = u.repo.Create(dto) } else { @@ -98,6 +122,7 @@ func (u *AppGroupUsecase) Create(ctx context.Context, dto domain.AppGroup) (id d "console_url=" + viper.GetString("console-address"), "alert_tks=" + viper.GetString("external-address") + "/system-api/1.0/alerts", "alert_slack=" + viper.GetString("alert-slack"), + "cloud_account_id=" + tksCloudAccountId, } switch dto.AppGroupType { From 808835f419266edb7273cd8ccaa18e5b36d1509a Mon Sep 17 00:00:00 2001 From: Taekyu Date: Wed, 26 Jul 2023 17:59:09 +0900 Subject: [PATCH 41/54] trivial. change empty value "" for cloud_account_id --- internal/usecase/app-group.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/usecase/app-group.go b/internal/usecase/app-group.go index ab1f74bd..f23366ac 100644 --- a/internal/usecase/app-group.go +++ b/internal/usecase/app-group.go @@ -89,7 +89,7 @@ func (u *AppGroupUsecase) Create(ctx context.Context, dto domain.AppGroup) (id d // FOR TEST. ADD MAGIC KEYWORD if strings.Contains(ca.Name, domain.CLOUD_ACCOUNT_INCLUSTER) { - tksCloudAccountId = "NULL" + tksCloudAccountId = "" } isExist = true break From d4e29bc5933e8abcce3df47fef88f57b14d6fb93 Mon Sep 17 00:00:00 2001 From: Taekyu Date: Thu, 27 Jul 2023 14:46:12 +0900 Subject: [PATCH 42/54] bugfix. add workflow parameter for deleing appgroup --- internal/usecase/app-group.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/internal/usecase/app-group.go b/internal/usecase/app-group.go index f23366ac..e17fa685 100644 --- a/internal/usecase/app-group.go +++ b/internal/usecase/app-group.go @@ -170,6 +170,28 @@ func (u *AppGroupUsecase) Delete(ctx context.Context, id domain.AppGroupId) (err } organizationId := cluster.OrganizationId + // check cloudAccount + cloudAccounts, err := u.cloudAccountRepo.Fetch(cluster.OrganizationId, nil) + if err != nil { + return httpErrors.NewBadRequestError(fmt.Errorf("Failed to get cloudAccounts"), "", "") + } + tksCloudAccountId := cluster.CloudAccountId.String() + isExist := false + for _, ca := range cloudAccounts { + if ca.ID == cluster.CloudAccountId { + + // FOR TEST. ADD MAGIC KEYWORD + if strings.Contains(ca.Name, domain.CLOUD_ACCOUNT_INCLUSTER) { + tksCloudAccountId = "" + } + isExist = true + break + } + } + if !isExist { + return httpErrors.NewBadRequestError(fmt.Errorf("Not found cloudAccountId[%s] in organization[%s]", cluster.CloudAccountId, cluster.OrganizationId), "", "") + } + // Call argo workflow template workflowTemplate := "" appGroupName := "" @@ -196,6 +218,7 @@ func (u *AppGroupUsecase) Delete(ctx context.Context, id domain.AppGroupId) (err "app_group_id=" + id.String(), "keycloak_url=" + strings.TrimSuffix(viper.GetString("keycloak-address"), "/auth"), "base_repo_branch=" + viper.GetString("revision"), + "cloud_account_id=" + tksCloudAccountId, } workflowId, err := u.argo.SumbitWorkflowFromWftpl(workflowTemplate, opts) From 80fed549bf90d5efc9cf928ce43c183e5c3285cb Mon Sep 17 00:00:00 2001 From: Taekyu Date: Fri, 28 Jul 2023 14:58:01 +0900 Subject: [PATCH 43/54] bugfix. fix filtering query as lower case. --- internal/repository/repository.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/repository/repository.go b/internal/repository/repository.go index 087579dd..33142cd3 100644 --- a/internal/repository/repository.go +++ b/internal/repository/repository.go @@ -26,7 +26,7 @@ func CombinedGormFilter(table string, filters []pagination.Filter, combinedFilte // and query for _, filter := range filters { if len(filter.Values) > 1 { - inQuery := fmt.Sprintf("%s.%s::text in (", table, filter.Column) + inQuery := fmt.Sprintf("LOWER(%s.%s::text) in (", table, filter.Column) for _, val := range filter.Values { inQuery = inQuery + fmt.Sprintf("LOWER('%s'),", val) } @@ -34,7 +34,7 @@ func CombinedGormFilter(table string, filters []pagination.Filter, combinedFilte db = db.Where(inQuery) } else { if len(filter.Values[0]) > 0 { - db = db.Where(fmt.Sprintf("%s.%s::text like LOWER('%%%s%%')", table, filter.Column, filter.Values[0])) + db = db.Where(fmt.Sprintf("LOWER(%s.%s::text) like LOWER('%%%s%%')", table, filter.Column, filter.Values[0])) } } } @@ -44,7 +44,7 @@ func CombinedGormFilter(table string, filters []pagination.Filter, combinedFilte if len(combinedFilter.Columns) > 0 { orQuery := "" for _, column := range combinedFilter.Columns { - orQuery = orQuery + fmt.Sprintf("%s.%s::text like LOWER('%%%s%%') OR ", table, column, combinedFilter.Value) + orQuery = orQuery + fmt.Sprintf("LOWER(%s.%s::text) like LOWER('%%%s%%') OR ", table, column, combinedFilter.Value) } orQuery = orQuery[:len(orQuery)-3] db = db.Where(orQuery) From 2033adb3012639b585a4211d8953c98e36f9ed15 Mon Sep 17 00:00:00 2001 From: Robert Choi Date: Mon, 31 Jul 2023 18:06:56 +0900 Subject: [PATCH 44/54] bugfix: validate extraEnv before creating DB record --- internal/usecase/app-serve-app.go | 50 +++++++++++++++---------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/internal/usecase/app-serve-app.go b/internal/usecase/app-serve-app.go index 4b46f41f..501b4580 100644 --- a/internal/usecase/app-serve-app.go +++ b/internal/usecase/app-serve-app.go @@ -89,21 +89,13 @@ func (u *AppServeAppUsecase) CreateAppServeApp(app *domain.AppServeApp) (string, } } - appId, taskId, err := u.repo.CreateAppServeApp(app) - if err != nil { - log.Error(err) - return "", "", errors.Wrap(err, "Failed to create app.") - } - - fmt.Printf("appId = %s, taskId = %s", appId, taskId) - extEnv := app.AppServeAppTasks[0].ExtraEnv if extEnv != "" { /* Preprocess extraEnv param */ log.Debug("extraEnv received: ", extEnv) tempMap := map[string]string{} - err = json.Unmarshal([]byte(extEnv), &tempMap) + err := json.Unmarshal([]byte(extEnv), &tempMap) if err != nil { log.Error(err) return "", "", errors.Wrap(err, "Failed to process extraEnv param.") @@ -122,6 +114,14 @@ func (u *AppServeAppUsecase) CreateAppServeApp(app *domain.AppServeApp) (string, log.Debug("After transform, extraEnv: ", extEnv) } + appId, taskId, err := u.repo.CreateAppServeApp(app) + if err != nil { + log.Error(err) + return "", "", errors.Wrap(err, "Failed to create app.") + } + + fmt.Printf("appId = %s, taskId = %s", appId, taskId) + // TODO: Validate PV params // Call argo workflow @@ -379,22 +379,6 @@ func (u *AppServeAppUsecase) UpdateAppServeApp(app *domain.AppServeApp, appTask } } - taskId, err := u.repo.CreateTask(appTask) - if err != nil { - log.Info("taskId = ", taskId) - return "", fmt.Errorf("failed to update app-serve application. Err: %s", err) - } - - // Sync new task status to the parent app - log.Info("Updating app status to 'PREPARING'..") - - err = u.repo.UpdateStatus(app.ID, taskId, "PREPARING", "") - if err != nil { - log.Debug("appId = ", app.ID) - log.Debug("taskId = ", taskId) - return "", fmt.Errorf("failed to update app status on UpdateAppServeApp. Err: %s", err) - } - extEnv := appTask.ExtraEnv if extEnv != "" { /* Preprocess extraEnv param */ @@ -421,6 +405,22 @@ func (u *AppServeAppUsecase) UpdateAppServeApp(app *domain.AppServeApp, appTask log.Debug("After transform, extraEnv: ", extEnv) } + taskId, err := u.repo.CreateTask(appTask) + if err != nil { + log.Info("taskId = ", taskId) + return "", fmt.Errorf("failed to update app-serve application. Err: %s", err) + } + + // Sync new task status to the parent app + log.Info("Updating app status to 'PREPARING'..") + + err = u.repo.UpdateStatus(app.ID, taskId, "PREPARING", "") + if err != nil { + log.Debug("appId = ", app.ID) + log.Debug("taskId = ", taskId) + return "", fmt.Errorf("failed to update app status on UpdateAppServeApp. Err: %s", err) + } + // Call argo workflow workflow := "serve-java-app" From 2dad91c2d2669d8308ca1756ac62e23922749706 Mon Sep 17 00:00:00 2001 From: Taekyu Date: Mon, 31 Jul 2023 19:19:18 +0900 Subject: [PATCH 45/54] bugfix. fix end date for dashboard ( pod calendar ) --- internal/usecase/dashboard.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/usecase/dashboard.go b/internal/usecase/dashboard.go index f91732ca..bc765f12 100644 --- a/internal/usecase/dashboard.go +++ b/internal/usecase/dashboard.go @@ -277,7 +277,7 @@ func (u *DashboardUsecase) getChartFromPrometheus(organizationId string, chartTy yearInt, _ := strconv.Atoi(year) monthInt, _ := strconv.Atoi(month) startDate := time.Date(yearInt, time.Month(monthInt), 1, 0, 0, 0, 0, time.UTC) - endDate := startDate.Add(time.Hour * 24 * 30) + endDate := time.Date(yearInt, time.Month(monthInt+1), 1, 0, 0, 0, 0, time.UTC) if now.Year() < yearInt { return res, fmt.Errorf("Invalid year") From 4e3e6a76122c58e60853b1210eadb693480ac3c4 Mon Sep 17 00:00:00 2001 From: Taekyu Date: Tue, 1 Aug 2023 15:16:51 +0900 Subject: [PATCH 46/54] bugfix. resource value change GB to GiB in dashboard. --- internal/usecase/dashboard.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/usecase/dashboard.go b/internal/usecase/dashboard.go index bc765f12..a9927cd8 100644 --- a/internal/usecase/dashboard.go +++ b/internal/usecase/dashboard.go @@ -185,36 +185,36 @@ func (u *DashboardUsecase) GetResources(ctx context.Context, organizationId stri if err != nil { return out, err } - memory := 0 + memory := float64(0) for _, val := range result.Data.Result { memoryVal, err := strconv.Atoi(val.Value[1].(string)) if err != nil { continue } if memoryVal > 0 { - memoryVal = memoryVal / 1024 / 1024 / 1024 - memory = memory + memoryVal + memory_ := float64(memoryVal) / float64(1024) / float64(1024) / float64(1024) + memory = memory + memory_ } } - out.Memory = fmt.Sprintf("%d GB", memory) + out.Memory = fmt.Sprintf("%v GiB", math.Round(memory)) // Storage result, err = thanosClient.Get("sum by (taco_cluster) (kubelet_volume_stats_capacity_bytes)") if err != nil { return out, err } - storage := 0 + storage := float64(0) for _, val := range result.Data.Result { storageVal, err := strconv.Atoi(val.Value[1].(string)) if err != nil { continue } if storageVal > 0 { - storageVal = storageVal / 1024 / 1024 / 1024 - storage = storage + storageVal + storage_ := float64(storageVal) / float64(1024) / float64(1024) / float64(1024) + storage = storage + storage_ } } - out.Storage = fmt.Sprintf("%d GB", storage) + out.Storage = fmt.Sprintf("%v GiB", math.Round(storage)) return } From c031a6e3fdc5cd8fa21ac96299313c7106c11152 Mon Sep 17 00:00:00 2001 From: Robert Choi Date: Tue, 1 Aug 2023 16:15:14 +0900 Subject: [PATCH 47/54] app-serving: validate name param --- internal/delivery/http/app-serve-app.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/internal/delivery/http/app-serve-app.go b/internal/delivery/http/app-serve-app.go index 06b8965f..0f81babc 100644 --- a/internal/delivery/http/app-serve-app.go +++ b/internal/delivery/http/app-serve-app.go @@ -3,6 +3,7 @@ package http import ( "fmt" "net/http" + "regexp" "strconv" "strings" "time" @@ -129,6 +130,13 @@ func (h *AppServeAppHandler) CreateAppServeApp(w http.ResponseWriter, r *http.Re app.AppServeAppTasks = append(app.AppServeAppTasks, task) + // Validate name param + re, _ := regexp.Compile("^[a-z][a-z0-9-]*$") + if !(re.MatchString(app.Name)) { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("error: name should consist of alphanumeric characters and hyphens only"), "", "")) + return + } + // Validate port param for springboot app if app.AppType == "springboot" { if task.Port == "" { From 9f9d0f01a88e76f007d5e514fbfedc680ff1b23d Mon Sep 17 00:00:00 2001 From: Robert Choi Date: Tue, 1 Aug 2023 17:16:03 +0900 Subject: [PATCH 48/54] app-serving: check if app name already exists --- internal/delivery/http/app-serve-app.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/internal/delivery/http/app-serve-app.go b/internal/delivery/http/app-serve-app.go index 0f81babc..f46b8c24 100644 --- a/internal/delivery/http/app-serve-app.go +++ b/internal/delivery/http/app-serve-app.go @@ -137,6 +137,16 @@ func (h *AppServeAppHandler) CreateAppServeApp(w http.ResponseWriter, r *http.Re return } + exist, err := h.usecase.IsAppServeAppNameExist(organizationId, app.Name) + if err != nil { + ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", "")) + return + } + if exist { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("error: name '%s' already exists.", app.Name), "", "")) + return + } + // Validate port param for springboot app if app.AppType == "springboot" { if task.Port == "" { From 3345db10b29a9f615dc1d596444af79f752a4983 Mon Sep 17 00:00:00 2001 From: Robert Choi Date: Wed, 2 Aug 2023 11:20:34 +0900 Subject: [PATCH 49/54] bugfix: assign transformed extraEnv to existing var --- internal/usecase/app-serve-app.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/usecase/app-serve-app.go b/internal/usecase/app-serve-app.go index 501b4580..63eaee7b 100644 --- a/internal/usecase/app-serve-app.go +++ b/internal/usecase/app-serve-app.go @@ -110,7 +110,7 @@ func (u *AppServeAppUsecase) CreateAppServeApp(app *domain.AppServeApp) (string, } mJson, _ := json.Marshal(newExtEnv) - extEnv := string(mJson) + extEnv = string(mJson) log.Debug("After transform, extraEnv: ", extEnv) } @@ -401,7 +401,6 @@ func (u *AppServeAppUsecase) UpdateAppServeApp(app *domain.AppServeApp, appTask mJson, _ := json.Marshal(newExtEnv) extEnv = string(mJson) - log.Debug("After transform, extraEnv: ", extEnv) } From 3546f8a41a0b481b9ebaafbfcf07401f970388a9 Mon Sep 17 00:00:00 2001 From: Taekyu Date: Tue, 1 Aug 2023 14:18:58 +0900 Subject: [PATCH 50/54] bugfix. fix filtering logic in users --- internal/delivery/http/user.go | 2 +- internal/pagination/pagination.go | 2 +- internal/repository/user.go | 57 +++++++++++++++++++------------ internal/usecase/auth.go | 8 ++--- internal/usecase/user.go | 26 +++++++++----- 5 files changed, 59 insertions(+), 36 deletions(-) diff --git a/internal/delivery/http/user.go b/internal/delivery/http/user.go index 135393ed..8443cec0 100644 --- a/internal/delivery/http/user.go +++ b/internal/delivery/http/user.go @@ -180,7 +180,7 @@ func (u UserHandler) List(w http.ResponseWriter, r *http.Request) { ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "", "")) return } - users, err := u.usecase.List(r.Context(), organizationId, pg) + users, err := u.usecase.ListWithPagination(r.Context(), organizationId, pg) if err != nil { if _, status := httpErrors.ErrorResponse(err); status == http.StatusNotFound { ResponseJSON(w, r, http.StatusNoContent, domain.ListUserResponse{}) diff --git a/internal/pagination/pagination.go b/internal/pagination/pagination.go index 01f8f513..40ed71ff 100644 --- a/internal/pagination/pagination.go +++ b/internal/pagination/pagination.go @@ -105,7 +105,7 @@ func NewPagination(urlParams *url.Values) (*Pagination, error) { //"combinedFilter=key1,key2:value" filterArray := strings.Split(value[0], ":") if len(filterArray) == 2 { - keys := strings.Split(filterArray[0], ",") + keys := strings.Split(helper.ToSnakeCase(strings.Replace(filterArray[0], "[]", "", -1)), ",") value := filterArray[1] pg.CombinedFilter = CombinedFilter{ diff --git a/internal/repository/user.go b/internal/repository/user.go index 5188c0d7..5403d81f 100644 --- a/internal/repository/user.go +++ b/internal/repository/user.go @@ -18,7 +18,8 @@ type IUserRepository interface { Create(accountId string, organizationId string, password string, name string) (domain.User, error) CreateWithUuid(uuid uuid.UUID, accountId string, name string, password string, email string, department string, description string, organizationId string, roleId uuid.UUID) (domain.User, error) - List(pg *pagination.Pagination, filters ...FilterFunc) (out *[]domain.User, err error) + List(filters ...FilterFunc) (out *[]domain.User, err error) + ListWithPagination(pg *pagination.Pagination, organizationId string) (out *[]domain.User, err error) Get(accountId string, organizationId string) (domain.User, error) GetByUuid(userId uuid.UUID) (domain.User, error) UpdateWithUuid(uuid uuid.UUID, accountId string, name string, password string, roleId uuid.UUID, email string, @@ -143,23 +144,11 @@ func (r *UserRepository) NameFilter(name string) FilterFunc { } } -func (r *UserRepository) List(pg *pagination.Pagination, filters ...FilterFunc) (*[]domain.User, error) { - var res *gorm.DB +func (r *UserRepository) List(filters ...FilterFunc) (*[]domain.User, error) { var users []User - var total int64 - - if pg == nil { - pg = pagination.NewDefaultPagination() - } - + var res *gorm.DB if filters == nil { - r.db.Model(&User{}).Count(&total) - - pg.TotalRows = total - pg.TotalPages = int(math.Ceil(float64(total) / float64(pg.Limit))) - orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) - res = r.db.Model(&User{}).Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery). - Preload("Organization").Preload("Role").Find(&users) + res = r.db.Model(&User{}).Preload("Organization").Preload("Role").Find(&users) } else { combinedFilter := func(filters ...FilterFunc) FilterFunc { return func(user *gorm.DB) *gorm.DB { @@ -170,15 +159,38 @@ func (r *UserRepository) List(pg *pagination.Pagination, filters ...FilterFunc) } } cFunc := combinedFilter(filters...) - cFunc(r.db.Model(&User{})).Count(&total) + res = cFunc(r.db.Model(&User{}).Preload("Organization").Preload("Role")).Find(&users) + } + if res.Error != nil { + log.Errorf("error is :%s(%T)", res.Error.Error(), res.Error) + return nil, res.Error + } + if res.RowsAffected == 0 { + return nil, httpErrors.NewNotFoundError(httpErrors.NotFound, "", "") + } + + var out []domain.User + for _, user := range users { + out = append(out, r.reflect(user)) + } - pg.TotalRows = total - pg.TotalPages = int(math.Ceil(float64(total) / float64(pg.Limit))) - orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) - res = cFunc(r.db.Model(&User{}).Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery). - Preload("Organization").Preload("Role")).Find(&users) + return &out, nil +} +func (r *UserRepository) ListWithPagination(pg *pagination.Pagination, organizationId string) (*[]domain.User, error) { + var users []User + + if pg == nil { + pg = pagination.NewDefaultPagination() } + + filterFunc := CombinedGormFilter("users", pg.GetFilters(), pg.CombinedFilter) + db := filterFunc(r.db.Model(&User{}).Where("organization_id = ?", organizationId)) + db.Count(&pg.TotalRows) + + pg.TotalPages = int(math.Ceil(float64(pg.TotalRows) / float64(pg.Limit))) + orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) + res := db.Preload("Organization").Preload("Role").Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery).Find(&users) if res.Error != nil { log.Errorf("error is :%s(%T)", res.Error.Error(), res.Error) return nil, res.Error @@ -194,6 +206,7 @@ func (r *UserRepository) List(pg *pagination.Pagination, filters ...FilterFunc) return &out, nil } + func (r *UserRepository) Get(accountId string, organizationId string) (domain.User, error) { user, err := r.getUserByAccountId(accountId, organizationId) if err != nil { diff --git a/internal/usecase/auth.go b/internal/usecase/auth.go index 668f665b..02b43103 100644 --- a/internal/usecase/auth.go +++ b/internal/usecase/auth.go @@ -104,7 +104,7 @@ func (u *AuthUsecase) Logout(accessToken string, organizationName string) error return nil } func (u *AuthUsecase) FindId(code string, email string, userName string, organizationId string) (string, error) { - users, err := u.userRepository.List(nil, u.userRepository.OrganizationFilter(organizationId), + users, err := u.userRepository.List(u.userRepository.OrganizationFilter(organizationId), u.userRepository.NameFilter(userName), u.userRepository.EmailFilter(email)) if err != nil && users == nil { return "", httpErrors.NewBadRequestError(err, "A_INVALID_ID", "") @@ -134,7 +134,7 @@ func (u *AuthUsecase) FindId(code string, email string, userName string, organiz } func (u *AuthUsecase) FindPassword(code string, accountId string, email string, userName string, organizationId string) error { - users, err := u.userRepository.List(nil, u.userRepository.OrganizationFilter(organizationId), + users, err := u.userRepository.List(u.userRepository.OrganizationFilter(organizationId), u.userRepository.AccountIdFilter(accountId), u.userRepository.NameFilter(userName), u.userRepository.EmailFilter(email)) if err != nil && users == nil { @@ -198,10 +198,10 @@ func (u *AuthUsecase) VerifyIdentity(accountId string, email string, userName st var err error if accountId == "" { - users, err = u.userRepository.List(nil, u.userRepository.OrganizationFilter(organizationId), + users, err = u.userRepository.List(u.userRepository.OrganizationFilter(organizationId), u.userRepository.NameFilter(userName), u.userRepository.EmailFilter(email)) } else { - users, err = u.userRepository.List(nil, u.userRepository.OrganizationFilter(organizationId), + users, err = u.userRepository.List(u.userRepository.OrganizationFilter(organizationId), u.userRepository.AccountIdFilter(accountId), u.userRepository.NameFilter(userName), u.userRepository.EmailFilter(email)) } diff --git a/internal/usecase/user.go b/internal/usecase/user.go index 41147aa2..a65b6649 100644 --- a/internal/usecase/user.go +++ b/internal/usecase/user.go @@ -24,7 +24,8 @@ type IUserUsecase interface { DeleteAdmin(organizationId string) error DeleteAll(ctx context.Context, organizationId string) error Create(ctx context.Context, user *domain.User) (*domain.User, error) - List(ctx context.Context, organizationId string, pg *pagination.Pagination) (*[]domain.User, error) + List(ctx context.Context, organizationId string) (*[]domain.User, error) + ListWithPagination(ctx context.Context, organizationId string, pg *pagination.Pagination) (*[]domain.User, error) Get(userId uuid.UUID) (*domain.User, error) Update(ctx context.Context, userId uuid.UUID, user *domain.User) (*domain.User, error) ResetPassword(userId uuid.UUID) error @@ -321,13 +322,22 @@ func (u *UserUsecase) UpdatePasswordByAccountId(ctx context.Context, accountId s return nil } -func (u *UserUsecase) List(ctx context.Context, organizationId string, pg *pagination.Pagination) (*[]domain.User, error) { - users, err := u.userRepository.List(pg, u.userRepository.OrganizationFilter(organizationId)) +func (u *UserUsecase) List(ctx context.Context, organizationId string) (users *[]domain.User, err error) { + users, err = u.userRepository.List(u.userRepository.OrganizationFilter(organizationId)) if err != nil { return nil, err } - return users, nil + return +} + +func (u *UserUsecase) ListWithPagination(ctx context.Context, organizationId string, pg *pagination.Pagination) (users *[]domain.User, err error) { + users, err = u.userRepository.ListWithPagination(pg, organizationId) + if err != nil { + return nil, err + } + + return } func (u *UserUsecase) Get(userId uuid.UUID) (*domain.User, error) { @@ -343,7 +353,7 @@ func (u *UserUsecase) Get(userId uuid.UUID) (*domain.User, error) { } func (u *UserUsecase) GetByAccountId(ctx context.Context, accountId string, organizationId string) (*domain.User, error) { - users, err := u.userRepository.List(nil, u.userRepository.OrganizationFilter(organizationId), + users, err := u.userRepository.List(u.userRepository.OrganizationFilter(organizationId), u.userRepository.AccountIdFilter(accountId)) if err != nil { return nil, err @@ -353,7 +363,7 @@ func (u *UserUsecase) GetByAccountId(ctx context.Context, accountId string, orga } func (u *UserUsecase) GetByEmail(ctx context.Context, email string, organizationId string) (*domain.User, error) { - users, err := u.userRepository.List(nil, u.userRepository.OrganizationFilter(organizationId), + users, err := u.userRepository.List(u.userRepository.OrganizationFilter(organizationId), u.userRepository.EmailFilter(email)) if err != nil { return nil, err @@ -395,7 +405,7 @@ func (u *UserUsecase) UpdateByAccountId(ctx context.Context, accountId string, u } } - users, err := u.userRepository.List(nil, u.userRepository.OrganizationFilter(userInfo.GetOrganizationId()), + users, err := u.userRepository.List(u.userRepository.OrganizationFilter(userInfo.GetOrganizationId()), u.userRepository.AccountIdFilter(accountId)) if err != nil { if _, code := httpErrors.ErrorResponse(err); code == http.StatusNotFound { @@ -551,7 +561,7 @@ func (u *UserUsecase) UpdateByAccountIdByAdmin(ctx context.Context, accountId st } } - users, err := u.userRepository.List(nil, u.userRepository.OrganizationFilter(userInfo.GetOrganizationId()), + users, err := u.userRepository.List(u.userRepository.OrganizationFilter(userInfo.GetOrganizationId()), u.userRepository.AccountIdFilter(accountId)) if err != nil { if _, code := httpErrors.ErrorResponse(err); code == http.StatusNotFound { From 8c83023692e987838610a774f803d4c32133ba3a Mon Sep 17 00:00:00 2001 From: Taekyu Date: Wed, 2 Aug 2023 14:45:38 +0900 Subject: [PATCH 51/54] bugfix. remove http status '204 empty' --- internal/delivery/http/user.go | 5 ----- internal/repository/user.go | 3 --- 2 files changed, 8 deletions(-) diff --git a/internal/delivery/http/user.go b/internal/delivery/http/user.go index 8443cec0..53797942 100644 --- a/internal/delivery/http/user.go +++ b/internal/delivery/http/user.go @@ -182,11 +182,6 @@ func (u UserHandler) List(w http.ResponseWriter, r *http.Request) { } users, err := u.usecase.ListWithPagination(r.Context(), organizationId, pg) if err != nil { - if _, status := httpErrors.ErrorResponse(err); status == http.StatusNotFound { - ResponseJSON(w, r, http.StatusNoContent, domain.ListUserResponse{}) - return - } - log.ErrorfWithContext(r.Context(), "error is :%s(%T)", err.Error(), err) ErrorJSON(w, r, err) return diff --git a/internal/repository/user.go b/internal/repository/user.go index 5403d81f..2571b1f6 100644 --- a/internal/repository/user.go +++ b/internal/repository/user.go @@ -195,9 +195,6 @@ func (r *UserRepository) ListWithPagination(pg *pagination.Pagination, organizat log.Errorf("error is :%s(%T)", res.Error.Error(), res.Error) return nil, res.Error } - if res.RowsAffected == 0 { - return nil, httpErrors.NewNotFoundError(httpErrors.NotFound, "", "") - } var out []domain.User for _, user := range users { From 9efd4887c48302d22aed4907695ac2ad548ea5d6 Mon Sep 17 00:00:00 2001 From: Taekyu Date: Wed, 2 Aug 2023 18:01:30 +0900 Subject: [PATCH 52/54] bugfix. change promQL query for "pod restart" in dashboard. --- internal/usecase/dashboard.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/usecase/dashboard.go b/internal/usecase/dashboard.go index a9927cd8..5938f0b5 100644 --- a/internal/usecase/dashboard.go +++ b/internal/usecase/dashboard.go @@ -267,7 +267,7 @@ func (u *DashboardUsecase) getChartFromPrometheus(organizationId string, chartTy query = "avg by (taco_cluster) (sum(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) by (taco_cluster) / sum(node_memory_MemTotal_bytes) by (taco_cluster))" case domain.ChartType_POD.String(): - query = "avg by (taco_cluster) (increase(kube_pod_container_status_restarts_total{namespace!=\"kube-system\"}[1h]))" + query = "sum by (taco_cluster) (changes(kube_pod_container_status_restarts_total{namespace!=\"kube-system\"}[1h]))" case domain.ChartType_TRAFFIC.String(): query = "avg by (taco_cluster) (rate(container_network_receive_bytes_total[1h]))" @@ -340,7 +340,7 @@ func (u *DashboardUsecase) getChartFromPrometheus(organizationId string, chartTy return domain.DashboardChart{}, fmt.Errorf("No data") } - result, err := thanosClient.FetchRange(query, int(now.Unix())-durationSec, int(now.Unix()), intervalSec) + result, err := thanosClient.FetchRange(query, int(now.Unix())-durationSec, int(now.Unix())+10000, intervalSec) if err != nil { return res, err } From b3241f7873e883d98ed22f90fe4523ba77056269 Mon Sep 17 00:00:00 2001 From: Taekyu Date: Thu, 3 Aug 2023 14:12:05 +0900 Subject: [PATCH 53/54] bugfix. update kubernetes version string v1.25 --- scripts/init_postgres.sql | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/init_postgres.sql b/scripts/init_postgres.sql index 2d1cb14d..6434a1d7 100644 --- a/scripts/init_postgres.sql +++ b/scripts/init_postgres.sql @@ -19,14 +19,14 @@ insert into cloud_accounts ( id, name, description, organization_id, cloud_servi values ( 'ce9e0387-01cb-4f37-a22a-fb91b6338434', 'aws', 'aws_description', 'master', 'AWS', 'result', now(), now() ); insert into stack_templates ( id, organization_id, name, description, version, cloud_service, platform, template, kube_version, kube_type, created_at, updated_at, services ) -values ( '49901092-be76-4d4f-94e9-b84525f560b5', 'master', 'AWS Standard (x86)', 'included LMA', 'v1', 'AWS', 'x86', 'aws-reference', 'v1.24', 'AWS', now(), now(), '[{"name": "Logging,Monitoring,Alerting", "type": "LMA", "applications": [{"name": "prometheus-stack", "version": "v.44.3.1", "description": "통계데이터 제공을 위한 backend 플랫폼"}, {"name": "elastic-system", "version": "v1.8.0", "description": "로그 데이터 적재를 위한 Storage"}, {"name": "alertmanager", "version": "v0.23.0", "description": "Alert 관리를 위한 backend 서비스"}, {"name": "grafana", "version": "v6.50.7", "description": "모니터링 통합 포탈"}]}]' ); +values ( '49901092-be76-4d4f-94e9-b84525f560b5', 'master', 'AWS Standard (x86)', 'included LMA', 'v1', 'AWS', 'x86', 'aws-reference', 'v1.25', 'AWS', now(), now(), '[{"name": "Logging,Monitoring,Alerting", "type": "LMA", "applications": [{"name": "prometheus-stack", "version": "v.44.3.1", "description": "통계데이터 제공을 위한 backend 플랫폼"}, {"name": "elastic-system", "version": "v1.8.0", "description": "로그 데이터 적재를 위한 Storage"}, {"name": "alertmanager", "version": "v0.23.0", "description": "Alert 관리를 위한 backend 서비스"}, {"name": "grafana", "version": "v6.50.7", "description": "모니터링 통합 포탈"}]}]' ); insert into stack_templates ( id, organization_id, name, description, version, cloud_service, platform, template, kube_version, kube_type, created_at, updated_at, services ) -values ( '44d5e76b-63db-4dd0-a16e-11bd3f6054cf', 'master', 'AWS MSA Standard (x86)', 'included LMA, SERVICE MESH', 'v1', 'AWS', 'x86', 'aws-msa-reference', 'v1.24', 'AWS', now(), now(), '[{"name": "Logging,Monitoring,Alerting", "type": "LMA", "applications": [{"name": "prometheus-stack", "version": "v.44.3.1", "description": "통계데이터 제공을 위한 backend 플랫폼"}, {"name": "elastic-system", "version": "v1.8.0", "description": "로그 데이터 적재를 위한 Storage"}, {"name": "alertmanager", "version": "v0.23.0", "description": "Alert 관리를 위한 backend 서비스"}, {"name": "grafana", "version": "v6.50.7", "description": "모니터링 통합 포탈"}]}, {"name": "MSA", "type": "SERVICE_MESH", "applications": [{"name": "istio", "version": "v1.13.1", "description": "MSA 플랫폼"}, {"name": "jagger", "version": "v2.27.1", "description": "분산 서비스간 트랜잭션 추적을 위한 로깅 플랫폼"}, {"name": "kiali", "version": "v1.45.1", "description": "MSA 통합 모니터링포탈"}]}]' ); +values ( '44d5e76b-63db-4dd0-a16e-11bd3f6054cf', 'master', 'AWS MSA Standard (x86)', 'included LMA, SERVICE MESH', 'v1', 'AWS', 'x86', 'aws-msa-reference', 'v1.25', 'AWS', now(), now(), '[{"name": "Logging,Monitoring,Alerting", "type": "LMA", "applications": [{"name": "prometheus-stack", "version": "v.44.3.1", "description": "통계데이터 제공을 위한 backend 플랫폼"}, {"name": "elastic-system", "version": "v1.8.0", "description": "로그 데이터 적재를 위한 Storage"}, {"name": "alertmanager", "version": "v0.23.0", "description": "Alert 관리를 위한 backend 서비스"}, {"name": "grafana", "version": "v6.50.7", "description": "모니터링 통합 포탈"}]}, {"name": "MSA", "type": "SERVICE_MESH", "applications": [{"name": "istio", "version": "v1.13.1", "description": "MSA 플랫폼"}, {"name": "jagger", "version": "v2.27.1", "description": "분산 서비스간 트랜잭션 추적을 위한 로깅 플랫폼"}, {"name": "kiali", "version": "v1.45.1", "description": "MSA 통합 모니터링포탈"}]}]' ); insert into stack_templates ( id, organization_id, name, description, version, cloud_service, platform, template, kube_version, kube_type, created_at, updated_at, services ) -values ( 'fe1d97e0-7428-4be6-9c69-310a88b4ff46', 'master', 'AWS Standard (arm)', 'included LMA', 'v2', 'AWS', 'arm', 'aws-arm-reference', 'v1.24', 'EKS', now(), now(), '[{"name": "Logging,Monitoring,Alerting", "type": "LMA", "applications": [{"name": "prometheus-stack", "version": "v.44.3.1", "description": "통계데이터 제공을 위한 backend 플랫폼"}, {"name": "elastic-system", "version": "v1.8.0", "description": "로그 데이터 적재를 위한 Storage"}, {"name": "alertmanager", "version": "v0.23.0", "description": "Alert 관리를 위한 backend 서비스"}, {"name": "grafana", "version": "v6.50.7", "description": "모니터링 통합 포탈"}]}]' ); +values ( 'fe1d97e0-7428-4be6-9c69-310a88b4ff46', 'master', 'AWS Standard (arm)', 'included LMA', 'v2', 'AWS', 'arm', 'aws-arm-reference', 'v1.25', 'EKS', now(), now(), '[{"name": "Logging,Monitoring,Alerting", "type": "LMA", "applications": [{"name": "prometheus-stack", "version": "v.44.3.1", "description": "통계데이터 제공을 위한 backend 플랫폼"}, {"name": "elastic-system", "version": "v1.8.0", "description": "로그 데이터 적재를 위한 Storage"}, {"name": "alertmanager", "version": "v0.23.0", "description": "Alert 관리를 위한 backend 서비스"}, {"name": "grafana", "version": "v6.50.7", "description": "모니터링 통합 포탈"}]}]' ); insert into stack_templates ( id, organization_id, name, description, version, cloud_service, platform, template, kube_version, kube_type, created_at, updated_at, services ) -values ( '3696cb38-4da0-4235-97eb-b6eb15962bd1', 'master', 'AWS Standard (arm)', 'included LMA, SERVICE_MESH', 'v2', 'AWS', 'arm', 'aws-arm-msa-reference', 'v1.24', 'EKS', now(), now(), '[{"name": "Logging,Monitoring,Alerting", "type": "LMA", "applications": [{"name": "prometheus-stack", "version": "v.44.3.1", "description": "통계데이터 제공을 위한 backend 플랫폼"}, {"name": "elastic-system", "version": "v1.8.0", "description": "로그 데이터 적재를 위한 Storage"}, {"name": "alertmanager", "version": "v0.23.0", "description": "Alert 관리를 위한 backend 서비스"}, {"name": "grafana", "version": "v6.50.7", "description": "모니터링 통합 포탈"}]}, {"name": "MSA", "type": "SERVICE_MESH", "applications": [{"name": "istio", "version": "v1.13.1", "description": "MSA 플랫폼"}, {"name": "jagger", "version": "v2.27.1", "description": "분산 서비스간 트랜잭션 추적을 위한 로깅 플랫폼"}, {"name": "kiali", "version": "v1.45.1", "description": "MSA 통합 모니터링포탈"}]}]' ); +values ( '3696cb38-4da0-4235-97eb-b6eb15962bd1', 'master', 'AWS Standard (arm)', 'included LMA, SERVICE_MESH', 'v2', 'AWS', 'arm', 'aws-arm-msa-reference', 'v1.25', 'EKS', now(), now(), '[{"name": "Logging,Monitoring,Alerting", "type": "LMA", "applications": [{"name": "prometheus-stack", "version": "v.44.3.1", "description": "통계데이터 제공을 위한 backend 플랫폼"}, {"name": "elastic-system", "version": "v1.8.0", "description": "로그 데이터 적재를 위한 Storage"}, {"name": "alertmanager", "version": "v0.23.0", "description": "Alert 관리를 위한 backend 서비스"}, {"name": "grafana", "version": "v6.50.7", "description": "모니터링 통합 포탈"}]}, {"name": "MSA", "type": "SERVICE_MESH", "applications": [{"name": "istio", "version": "v1.13.1", "description": "MSA 플랫폼"}, {"name": "jagger", "version": "v2.27.1", "description": "분산 서비스간 트랜잭션 추적을 위한 로깅 플랫폼"}, {"name": "kiali", "version": "v1.45.1", "description": "MSA 통합 모니터링포탈"}]}]' ); insert into stack_templates ( id, organization_id, name, description, version, cloud_service, platform, template, kube_version, kube_type, created_at, updated_at, services ) -values ( 'c8a4658d-d5a6-4191-8a91-e26f6aee007f', 'master', 'EKS Standard (x86)', 'included LMA', 'v1', 'AWS', 'x86', 'eks-reference', 'v1.24', 'AWS', now(), now(), '[{"name":"Logging,Monitoring,Alerting","type":"LMA","applications":[{"name":"thanos","version":"0.17.2","description":"다중클러스터의 모니터링 데이터 통합 질의처리"},{"name":"prometheus-stack","version":"v0.62.0","description":"모니터링 데이터 수집/저장 및 질의처리"},{"name":"alertmanager","version":"v0.23.0","description":"알람 처리를 위한 노티피케이션 서비스"},{"name":"loki","version":"2.6.1","description":"로그데이터 저장 및 질의처리"},{"name":"grafana","version":"9.3.6","description":"모니터링/로그 통합대시보드"}]}]' ); +values ( 'c8a4658d-d5a6-4191-8a91-e26f6aee007f', 'master', 'EKS Standard (x86)', 'included LMA', 'v1', 'AWS', 'x86', 'eks-reference', 'v1.25', 'AWS', now(), now(), '[{"name":"Logging,Monitoring,Alerting","type":"LMA","applications":[{"name":"thanos","version":"0.17.2","description":"다중클러스터의 모니터링 데이터 통합 질의처리"},{"name":"prometheus-stack","version":"v0.62.0","description":"모니터링 데이터 수집/저장 및 질의처리"},{"name":"alertmanager","version":"v0.23.0","description":"알람 처리를 위한 노티피케이션 서비스"},{"name":"loki","version":"2.6.1","description":"로그데이터 저장 및 질의처리"},{"name":"grafana","version":"9.3.6","description":"모니터링/로그 통합대시보드"}]}]' ); insert into stack_templates ( id, organization_id, name, description, version, cloud_service, platform, template, kube_version, kube_type, created_at, updated_at, services ) -values ( '39f18a09-5b94-4772-bdba-e4c32ee002f7', 'master', 'EKS MSA Standard (x86)', 'included LMA, SERVICE MESH', 'v1', 'AWS', 'x86', 'eks-msa-reference', 'v1.24', 'AWS', now(), now(), '[{"name":"Logging,Monitoring,Alerting","type":"LMA","applications":[{"name":"thanos","version":"0.17.2","description":"다중클러스터의 모니터링 데이터 통합 질의처리"},{"name":"prometheus-stack","version":"v0.62.0","description":"모니터링 데이터 수집/저장 및 질의처리"},{"name":"alertmanager","version":"v0.23.0","description":"알람 처리를 위한 노티피케이션 서비스"},{"name":"loki","version":"2.6.1","description":"로그데이터 저장 및 질의처리"},{"name":"grafana","version":"9.3.6","description":"모니터링/로그 통합대시보드"}]},{"name":"MSA","type":"SERVICE_MESH","applications":[{"name":"istio","version":"v1.17.2","description":"MSA 플랫폼"},{"name":"jagger","version":"1.35.0","description":"분산 서비스간 트랜잭션 추적을 위한 플랫폼"},{"name":"kiali","version":"v1.63.0","description":"MSA 구조 및 성능을 볼 수 있는 Dashboard"},{"name":"k8ssandra","version":"1.6.0","description":"분산 서비스간 호출 로그를 저장하는 스토리지"}]}]' ); +values ( '39f18a09-5b94-4772-bdba-e4c32ee002f7', 'master', 'EKS MSA Standard (x86)', 'included LMA, SERVICE MESH', 'v1', 'AWS', 'x86', 'eks-msa-reference', 'v1.25', 'AWS', now(), now(), '[{"name":"Logging,Monitoring,Alerting","type":"LMA","applications":[{"name":"thanos","version":"0.17.2","description":"다중클러스터의 모니터링 데이터 통합 질의처리"},{"name":"prometheus-stack","version":"v0.62.0","description":"모니터링 데이터 수집/저장 및 질의처리"},{"name":"alertmanager","version":"v0.23.0","description":"알람 처리를 위한 노티피케이션 서비스"},{"name":"loki","version":"2.6.1","description":"로그데이터 저장 및 질의처리"},{"name":"grafana","version":"9.3.6","description":"모니터링/로그 통합대시보드"}]},{"name":"MSA","type":"SERVICE_MESH","applications":[{"name":"istio","version":"v1.17.2","description":"MSA 플랫폼"},{"name":"jagger","version":"1.35.0","description":"분산 서비스간 트랜잭션 추적을 위한 플랫폼"},{"name":"kiali","version":"v1.63.0","description":"MSA 구조 및 성능을 볼 수 있는 Dashboard"},{"name":"k8ssandra","version":"1.6.0","description":"분산 서비스간 호출 로그를 저장하는 스토리지"}]}]' ); From 4b316df2693e7d33b0a2b6a3369f1f5fb196acfd Mon Sep 17 00:00:00 2001 From: Taekyu Date: Tue, 8 Aug 2023 09:57:54 +0900 Subject: [PATCH 54/54] trivial. add github action for prd --- .github/workflows/build-and-push.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-and-push.yml b/.github/workflows/build-and-push.yml index f943a8d4..84cf0540 100644 --- a/.github/workflows/build-and-push.yml +++ b/.github/workflows/build-and-push.yml @@ -51,6 +51,7 @@ jobs: ( cd cicd-manifests/${SERVICE}/overlay/ft && kustomize edit set image docker.io/sktcloud/${SERVICE}:${TAG} && git add kustomization.yaml ) elif [[ ${{github.ref}} == *"main"* ]]; then ( cd cicd-manifests/${SERVICE}/overlay/cicd && kustomize edit set image docker.io/sktcloud/${SERVICE}:${TAG} && git add kustomization.yaml ) + ( cd cicd-manifests/${SERVICE}/overlay/prd && kustomize edit set image docker.io/sktcloud/${SERVICE}:${TAG} && git add kustomization.yaml ) fi cd cicd-manifests