From 3137278d320ea690291c9779917b27fc88a97419 Mon Sep 17 00:00:00 2001 From: "taekyu.kang" Date: Fri, 22 Sep 2023 14:27:59 +0900 Subject: [PATCH] rollback. rollback logic of infra conf on creating stack(cluster). --- api/swagger/docs.go | 170 ++++++++++++++++++++++++------ api/swagger/swagger.json | 170 ++++++++++++++++++++++++------ api/swagger/swagger.yaml | 112 ++++++++++++++++---- internal/database/database.go | 3 + internal/delivery/http/cluster.go | 1 + internal/delivery/http/stack.go | 54 ++++++++++ internal/repository/alert.go | 13 ++- internal/repository/cluster.go | 67 +++++++++++- internal/route/route.go | 2 + internal/serializer/serializer.go | 10 +- internal/usecase/stack.go | 37 ++++++- pkg/domain/cloud-account.go | 1 + pkg/domain/cluster.go | 28 +++++ pkg/domain/stack.go | 50 +++++---- 14 files changed, 592 insertions(+), 126 deletions(-) diff --git a/api/swagger/docs.go b/api/swagger/docs.go index 2ef5030a..b35f65c1 100644 --- a/api/swagger/docs.go +++ b/api/swagger/docs.go @@ -2879,6 +2879,86 @@ const docTemplate = `{ } } }, + "/organizations/{organizationId}/stacks/{stackId}/favorite": { + "post": { + "security": [ + { + "JWT": [] + } + ], + "description": "Set favorite stack", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Stacks" + ], + "summary": "Set favorite stack", + "parameters": [ + { + "type": "string", + "description": "organizationId", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "stackId", + "name": "stackId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "delete": { + "security": [ + { + "JWT": [] + } + ], + "description": "Delete favorite stack", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Stacks" + ], + "summary": "Delete favorite stack", + "parameters": [ + { + "type": "string", + "description": "organizationId", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "stackId", + "name": "stackId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, "/organizations/{organizationId}/stacks/{stackId}/kube-config": { "get": { "security": [ @@ -4118,6 +4198,12 @@ const docTemplate = `{ "cloudAccountId": { "type": "string" }, + "cloudService": { + "type": "string" + }, + "clusterType": { + "type": "integer" + }, "conf": { "$ref": "#/definitions/domain.ClusterConf" }, @@ -4235,6 +4321,12 @@ const docTemplate = `{ "cloudAccount": { "$ref": "#/definitions/domain.SimpleCloudAccountResponse" }, + "cloudService": { + "type": "string" + }, + "clusterType": { + "type": "string" + }, "conf": { "$ref": "#/definitions/domain.ClusterConfResponse" }, @@ -4492,6 +4584,7 @@ const docTemplate = `{ "type": "object", "required": [ "cloudAccountId", + "cloudService", "name", "organizationId", "stackTemplateId" @@ -4500,6 +4593,16 @@ const docTemplate = `{ "cloudAccountId": { "type": "string" }, + "cloudService": { + "type": "string", + "enum": [ + "AWS", + "BYOH" + ] + }, + "clusterType": { + "type": "string" + }, "description": { "type": "string" }, @@ -4576,25 +4679,56 @@ const docTemplate = `{ "type": "object", "required": [ "cloudAccountId", + "cloudService", "name", - "nodes", "stackTemplateId" ], "properties": { "cloudAccountId": { "type": "string" }, + "cloudService": { + "type": "string", + "enum": [ + "AWS", + "BYOH" + ] + }, "description": { "type": "string" }, "name": { "type": "string" }, - "nodes": { - "$ref": "#/definitions/domain.StackNodesIO" - }, "stackTemplateId": { "type": "string" + }, + "tksCpNode": { + "type": "integer" + }, + "tksCpNodeMax": { + "type": "integer" + }, + "tksCpNodeType": { + "type": "string" + }, + "tksInfraNode": { + "type": "integer" + }, + "tksInfraNodeMax": { + "type": "integer" + }, + "tksInfraNodeType": { + "type": "string" + }, + "tksUserNode": { + "type": "integer" + }, + "tksUserNodeMax": { + "type": "integer" + }, + "tksUserNodeType": { + "type": "string" } } }, @@ -5635,34 +5769,6 @@ const docTemplate = `{ } } }, - "domain.StackNodeIO": { - "type": "object", - "properties": { - "count": { - "type": "integer" - }, - "hostNames": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "domain.StackNodesIO": { - "type": "object", - "properties": { - "tksCpNode": { - "$ref": "#/definitions/domain.StackNodeIO" - }, - "tksInfraNode": { - "$ref": "#/definitions/domain.StackNodeIO" - }, - "tksUserNode": { - "$ref": "#/definitions/domain.StackNodeIO" - } - } - }, "domain.StackResponse": { "type": "object", "properties": { diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index 761169d4..ef7eb582 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -2872,6 +2872,86 @@ } } }, + "/organizations/{organizationId}/stacks/{stackId}/favorite": { + "post": { + "security": [ + { + "JWT": [] + } + ], + "description": "Set favorite stack", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Stacks" + ], + "summary": "Set favorite stack", + "parameters": [ + { + "type": "string", + "description": "organizationId", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "stackId", + "name": "stackId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "delete": { + "security": [ + { + "JWT": [] + } + ], + "description": "Delete favorite stack", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Stacks" + ], + "summary": "Delete favorite stack", + "parameters": [ + { + "type": "string", + "description": "organizationId", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "stackId", + "name": "stackId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, "/organizations/{organizationId}/stacks/{stackId}/kube-config": { "get": { "security": [ @@ -4111,6 +4191,12 @@ "cloudAccountId": { "type": "string" }, + "cloudService": { + "type": "string" + }, + "clusterType": { + "type": "integer" + }, "conf": { "$ref": "#/definitions/domain.ClusterConf" }, @@ -4228,6 +4314,12 @@ "cloudAccount": { "$ref": "#/definitions/domain.SimpleCloudAccountResponse" }, + "cloudService": { + "type": "string" + }, + "clusterType": { + "type": "string" + }, "conf": { "$ref": "#/definitions/domain.ClusterConfResponse" }, @@ -4485,6 +4577,7 @@ "type": "object", "required": [ "cloudAccountId", + "cloudService", "name", "organizationId", "stackTemplateId" @@ -4493,6 +4586,16 @@ "cloudAccountId": { "type": "string" }, + "cloudService": { + "type": "string", + "enum": [ + "AWS", + "BYOH" + ] + }, + "clusterType": { + "type": "string" + }, "description": { "type": "string" }, @@ -4569,25 +4672,56 @@ "type": "object", "required": [ "cloudAccountId", + "cloudService", "name", - "nodes", "stackTemplateId" ], "properties": { "cloudAccountId": { "type": "string" }, + "cloudService": { + "type": "string", + "enum": [ + "AWS", + "BYOH" + ] + }, "description": { "type": "string" }, "name": { "type": "string" }, - "nodes": { - "$ref": "#/definitions/domain.StackNodesIO" - }, "stackTemplateId": { "type": "string" + }, + "tksCpNode": { + "type": "integer" + }, + "tksCpNodeMax": { + "type": "integer" + }, + "tksCpNodeType": { + "type": "string" + }, + "tksInfraNode": { + "type": "integer" + }, + "tksInfraNodeMax": { + "type": "integer" + }, + "tksInfraNodeType": { + "type": "string" + }, + "tksUserNode": { + "type": "integer" + }, + "tksUserNodeMax": { + "type": "integer" + }, + "tksUserNodeType": { + "type": "string" } } }, @@ -5628,34 +5762,6 @@ } } }, - "domain.StackNodeIO": { - "type": "object", - "properties": { - "count": { - "type": "integer" - }, - "hostNames": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "domain.StackNodesIO": { - "type": "object", - "properties": { - "tksCpNode": { - "$ref": "#/definitions/domain.StackNodeIO" - }, - "tksInfraNode": { - "$ref": "#/definitions/domain.StackNodeIO" - }, - "tksUserNode": { - "$ref": "#/definitions/domain.StackNodeIO" - } - } - }, "domain.StackResponse": { "type": "object", "properties": { diff --git a/api/swagger/swagger.yaml b/api/swagger/swagger.yaml index f9dc2a40..4f484a0a 100644 --- a/api/swagger/swagger.yaml +++ b/api/swagger/swagger.yaml @@ -362,6 +362,10 @@ definitions: $ref: '#/definitions/domain.CloudAccount' cloudAccountId: type: string + cloudService: + type: string + clusterType: + type: integer conf: $ref: '#/definitions/domain.ClusterConf' createdAt: @@ -439,6 +443,10 @@ definitions: properties: cloudAccount: $ref: '#/definitions/domain.SimpleCloudAccountResponse' + cloudService: + type: string + clusterType: + type: string conf: $ref: '#/definitions/domain.ClusterConfResponse' createdAt: @@ -616,6 +624,13 @@ definitions: properties: cloudAccountId: type: string + cloudService: + enum: + - AWS + - BYOH + type: string + clusterType: + type: string description: type: string name: @@ -644,6 +659,7 @@ definitions: type: string required: - cloudAccountId + - cloudService - name - organizationId - stackTemplateId @@ -673,18 +689,39 @@ definitions: properties: cloudAccountId: type: string + cloudService: + enum: + - AWS + - BYOH + type: string description: type: string name: type: string - nodes: - $ref: '#/definitions/domain.StackNodesIO' stackTemplateId: type: string + tksCpNode: + type: integer + tksCpNodeMax: + type: integer + tksCpNodeType: + type: string + tksInfraNode: + type: integer + tksInfraNodeMax: + type: integer + tksInfraNodeType: + type: string + tksUserNode: + type: integer + tksUserNodeMax: + type: integer + tksUserNodeType: + type: string required: - cloudAccountId + - cloudService - name - - nodes - stackTemplateId type: object domain.CreateStackResponse: @@ -1370,24 +1407,6 @@ definitions: - tksInfraNode - tksUserNode type: object - domain.StackNodeIO: - properties: - count: - type: integer - hostNames: - items: - type: string - type: array - type: object - domain.StackNodesIO: - properties: - tksCpNode: - $ref: '#/definitions/domain.StackNodeIO' - tksInfraNode: - $ref: '#/definitions/domain.StackNodeIO' - tksUserNode: - $ref: '#/definitions/domain.StackNodeIO' - type: object domain.StackResponse: properties: cloudAccount: @@ -3639,6 +3658,57 @@ paths: summary: Update Stack tags: - Stacks + /organizations/{organizationId}/stacks/{stackId}/favorite: + delete: + consumes: + - application/json + description: Delete favorite stack + parameters: + - description: organizationId + in: path + name: organizationId + required: true + type: string + - description: stackId + in: path + name: stackId + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + security: + - JWT: [] + summary: Delete favorite stack + tags: + - Stacks + post: + consumes: + - application/json + description: Set favorite stack + parameters: + - description: organizationId + in: path + name: organizationId + required: true + type: string + - description: stackId + in: path + name: stackId + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + security: + - JWT: [] + summary: Set favorite stack + tags: + - Stacks /organizations/{organizationId}/stacks/{stackId}/kube-config: get: consumes: diff --git a/internal/database/database.go b/internal/database/database.go index 1442427d..7d7ff222 100644 --- a/internal/database/database.go +++ b/internal/database/database.go @@ -86,6 +86,9 @@ func migrateSchema(db *gorm.DB) error { if err := db.AutoMigrate(&repository.Cluster{}); err != nil { return err } + if err := db.AutoMigrate(&repository.ClusterFavorite{}); err != nil { + return err + } // Services if err := db.AutoMigrate(&repository.AppGroup{}); err != nil { diff --git a/internal/delivery/http/cluster.go b/internal/delivery/http/cluster.go index 1c7b3a54..62b51dca 100644 --- a/internal/delivery/http/cluster.go +++ b/internal/delivery/http/cluster.go @@ -159,6 +159,7 @@ func (h *ClusterHandler) CreateCluster(w http.ResponseWriter, r *http.Request) { } // [TODO] set default value + dto.ClusterType = domain.ClusterType_USER dto.Conf.SetDefault() log.InfoWithContext(r.Context(), dto.Conf) diff --git a/internal/delivery/http/stack.go b/internal/delivery/http/stack.go index 0b1f6e0e..d9ba89d7 100644 --- a/internal/delivery/http/stack.go +++ b/internal/delivery/http/stack.go @@ -368,3 +368,57 @@ func (h *StackHandler) GetStackKubeConfig(w http.ResponseWriter, r *http.Request ResponseJSON(w, r, http.StatusOK, out) } + +// SetFavorite godoc +// @Tags Stacks +// @Summary Set favorite stack +// @Description Set favorite stack +// @Accept json +// @Produce json +// @Param organizationId path string true "organizationId" +// @Param stackId path string true "stackId" +// @Success 200 {object} nil +// @Router /organizations/{organizationId}/stacks/{stackId}/favorite [post] +// @Security JWT +func (h *StackHandler) SetFavorite(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + strId, ok := vars["stackId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("Invalid stackId"), "C_INVALID_STACK_ID", "")) + return + } + + err := h.usecase.SetFavorite(r.Context(), domain.StackId(strId)) + if err != nil { + ErrorJSON(w, r, err) + return + } + ResponseJSON(w, r, http.StatusOK, nil) +} + +// DeleteFavorite godoc +// @Tags Stacks +// @Summary Delete favorite stack +// @Description Delete favorite stack +// @Accept json +// @Produce json +// @Param organizationId path string true "organizationId" +// @Param stackId path string true "stackId" +// @Success 200 {object} nil +// @Router /organizations/{organizationId}/stacks/{stackId}/favorite [delete] +// @Security JWT +func (h *StackHandler) DeleteFavorite(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + strId, ok := vars["stackId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("Invalid stackId"), "C_INVALID_STACK_ID", "")) + return + } + + err := h.usecase.DeleteFavorite(r.Context(), domain.StackId(strId)) + if err != nil { + ErrorJSON(w, r, err) + return + } + ResponseJSON(w, r, http.StatusOK, nil) +} diff --git a/internal/repository/alert.go b/internal/repository/alert.go index f983c304..f1ffd971 100644 --- a/internal/repository/alert.go +++ b/internal/repository/alert.go @@ -57,7 +57,7 @@ type Alert struct { CheckPoint string GrafanaUrl string Summary string - AlertActions []AlertAction `gorm:"foreignKey:AlertId"` + AlertActions []AlertAction RawData datatypes.JSON Status domain.AlertActionStatus `gorm:"index"` } @@ -222,8 +222,15 @@ func reflectAlert(alert Alert) (out domain.Alert) { } out.AlertActions = make([]domain.AlertAction, len(alert.AlertActions)) - if err := serializer.Map(alert.AlertActions, &out.AlertActions); err != nil { - log.Error(err) + for i, alertAction := range alert.AlertActions { + if err := serializer.Map(alertAction.Model, &out.AlertActions[i]); err != nil { + log.Error(err) + continue + } + if err := serializer.Map(alertAction, &out.AlertActions[i]); err != nil { + log.Error(err) + continue + } } return } diff --git a/internal/repository/cluster.go b/internal/repository/cluster.go index a3daa11c..649c18ce 100644 --- a/internal/repository/cluster.go +++ b/internal/repository/cluster.go @@ -28,6 +28,8 @@ type IClusterRepository interface { Delete(id domain.ClusterId) error InitWorkflow(clusterId domain.ClusterId, workflowId string, status domain.ClusterStatus) error InitWorkflowDescription(clusterId domain.ClusterId) error + SetFavorite(clusterId domain.ClusterId, userId uuid.UUID) error + DeleteFavorite(clusterId domain.ClusterId, userId uuid.UUID) error } type ClusterRepository struct { @@ -48,6 +50,7 @@ type Cluster struct { ID domain.ClusterId `gorm:"primarykey"` Name string `gorm:"index"` + CloudService string `gorm:"default:AWS"` OrganizationId string Organization Organization `gorm:"foreignKey:OrganizationId"` Description string `gorm:"index"` @@ -58,6 +61,8 @@ type Cluster struct { CloudAccount CloudAccount `gorm:"foreignKey:CloudAccountId"` StackTemplateId uuid.UUID StackTemplate StackTemplate `gorm:"foreignKey:StackTemplateId"` + Favorite *[]ClusterFavorite + ClusterType domain.ClusterType `gorm:"default:0"` TksCpNode int TksCpNodeMax int TksCpNodeType string @@ -78,6 +83,21 @@ func (c *Cluster) BeforeCreate(tx *gorm.DB) (err error) { return nil } +type ClusterFavorite struct { + gorm.Model + + ID uuid.UUID `gorm:"primarykey;type:uuid"` + ClusterId domain.ClusterId + Cluster Cluster `gorm:"foreignKey:ClusterId"` + UserId uuid.UUID `gorm:"type:uuid"` + User User `gorm:"foreignKey:UserId"` +} + +func (c *ClusterFavorite) BeforeCreate(tx *gorm.DB) (err error) { + c.ID = uuid.New() + return nil +} + // Logics func (r *ClusterRepository) WithTrx(trxHandle *gorm.DB) IClusterRepository { if trxHandle == nil { @@ -112,6 +132,7 @@ func (r *ClusterRepository) Fetch(pg *pagination.Pagination) (out []domain.Clust } func (r *ClusterRepository) FetchByOrganizationId(organizationId string, pg *pagination.Pagination) (out []domain.Cluster, err error) { + userId := "79a404aa-7184-4d0f-9e73-2671e32f7da5" var clusters []Cluster if pg == nil { pg = pagination.NewDefaultPagination() @@ -119,14 +140,16 @@ func (r *ClusterRepository) FetchByOrganizationId(organizationId string, pg *pag pg.SortColumn = "created_at" pg.SortOrder = "DESC" filterFunc := CombinedGormFilter("clusters", pg.GetFilters(), pg.CombinedFilter) - db := filterFunc(r.db.Model(&Cluster{}).Preload(clause.Associations). + db := filterFunc(r.db.Model(&Cluster{}). + Preload(clause.Associations). + Joins("left outer join cluster_favorites on clusters.id = cluster_favorites.cluster_id AND cluster_favorites.user_id = ?", userId). Where("organization_id = ? AND status != ?", organizationId, domain.ClusterStatus_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 := db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery).Find(&clusters) + res := db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order("cluster_favorites.cluster_id").Order(orderQuery).Find(&clusters) if res.Error != nil { return nil, res.Error } @@ -134,6 +157,8 @@ func (r *ClusterRepository) FetchByOrganizationId(organizationId string, pg *pag outCluster := reflectCluster(cluster) out = append(out, outCluster) } + + //log.Info(helper.ModelToJson(clusters)) return } @@ -193,6 +218,7 @@ func (r *ClusterRepository) Create(dto domain.Cluster) (clusterId domain.Cluster CreatorId: dto.CreatorId, UpdatorId: nil, Status: domain.ClusterStatus_PENDING, + ClusterType: dto.ClusterType, TksCpNode: dto.Conf.TksCpNode, TksCpNodeMax: dto.Conf.TksCpNodeMax, TksCpNodeType: dto.Conf.TksCpNodeType, @@ -254,10 +280,41 @@ func (r *ClusterRepository) InitWorkflowDescription(clusterId domain.ClusterId) return nil } -func reflectCluster(cluster Cluster) (out domain.Cluster) { - if err := serializer.Map(cluster.Model, &out); err != nil { - log.Error(err) +func (r *ClusterRepository) SetFavorite(clusterId domain.ClusterId, userId uuid.UUID) error { + var clusterFavorites []ClusterFavorite + res := r.db.Where("cluster_id = ? AND user_id = ?", clusterId, userId).Find(&clusterFavorites) + if res.Error != nil { + log.Info(res.Error) + return res.Error + } + + if len(clusterFavorites) > 0 { + return nil } + + clusterFavorite := ClusterFavorite{ + ClusterId: clusterId, + UserId: userId, + } + resCreate := r.db.Create(&clusterFavorite) + if resCreate.Error != nil { + log.Error(resCreate.Error) + return fmt.Errorf("could not create cluster favorite for clusterId %s, userId %s", clusterId, userId) + } + + return nil +} + +func (r *ClusterRepository) DeleteFavorite(clusterId domain.ClusterId, userId uuid.UUID) error { + res := r.db.Unscoped().Delete(&ClusterFavorite{}, "cluster_id = ? AND user_id = ?", clusterId, userId) + if res.Error != nil { + log.Error(res.Error) + return fmt.Errorf("could not delete cluster favorite for clusterId %s, userId %s", clusterId, userId) + } + return nil +} + +func reflectCluster(cluster Cluster) (out domain.Cluster) { if err := serializer.Map(cluster, &out); err != nil { log.Error(err) } diff --git a/internal/route/route.go b/internal/route/route.go index 1859de7e..4f1f01ca 100644 --- a/internal/route/route.go +++ b/internal/route/route.go @@ -166,6 +166,8 @@ func SetupRouter(db *gorm.DB, argoClient argowf.ArgoClient, kc keycloak.IKeycloa r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/stacks/{stackId}", authMiddleware.Handle(http.HandlerFunc(stackHandler.DeleteStack))).Methods(http.MethodDelete) r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/stacks/{stackId}/kube-config", authMiddleware.Handle(http.HandlerFunc(stackHandler.GetStackKubeConfig))).Methods(http.MethodGet) r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/stacks/{stackId}/status", authMiddleware.Handle(http.HandlerFunc(stackHandler.GetStackStatus))).Methods(http.MethodGet) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/stacks/{stackId}/favorite", authMiddleware.Handle(http.HandlerFunc(stackHandler.SetFavorite))).Methods(http.MethodPost) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/stacks/{stackId}/favorite", authMiddleware.Handle(http.HandlerFunc(stackHandler.DeleteFavorite))).Methods(http.MethodDelete) dashboardHandler := delivery.NewDashboardHandler(usecase.NewDashboardUsecase(repoFactory, cache)) r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/dashboard/charts", authMiddleware.Handle(http.HandlerFunc(dashboardHandler.GetCharts))).Methods(http.MethodGet) diff --git a/internal/serializer/serializer.go b/internal/serializer/serializer.go index 012f1abd..70e96552 100644 --- a/internal/serializer/serializer.go +++ b/internal/serializer/serializer.go @@ -7,7 +7,6 @@ import ( "github.com/google/uuid" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/log" - "gorm.io/datatypes" ) type ConverterMap map[compositeKey]func(interface{}) (interface{}, error) @@ -18,14 +17,13 @@ type compositeKey struct { } func recursiveMap(src interface{}, dst interface{}, converterMap ConverterMap) error { - // not support type - if _, ok := src.(datatypes.JSON); ok { - return nil - } - srcVal := reflect.ValueOf(src) srcType := srcVal.Type() + if srcType.Kind() == reflect.Slice { + return fmt.Errorf("not support src type (Slice)") + } + dstVal := reflect.ValueOf(dst) if dstVal.Kind() != reflect.Ptr || dstVal.IsNil() { return fmt.Errorf("dst must be a non-nil pointer") diff --git a/internal/usecase/stack.go b/internal/usecase/stack.go index 869c86b1..9576cd10 100644 --- a/internal/usecase/stack.go +++ b/internal/usecase/stack.go @@ -31,6 +31,8 @@ type IStackUsecase interface { Delete(ctx context.Context, dto domain.Stack) error GetKubeConfig(ctx context.Context, stackId domain.StackId) (kubeConfig string, err error) GetStepStatus(ctx context.Context, stackId domain.StackId) (out []domain.StackStepStatus, stackStatus string, err error) + SetFavorite(ctx context.Context, stackId domain.StackId) error + DeleteFavorite(ctx context.Context, stackId domain.StackId) error } type StackUsecase struct { @@ -87,10 +89,9 @@ func (u *StackUsecase) Create(ctx context.Context, dto domain.Stack) (stackId do log.DebugWithContext(ctx, "isPrimary ", isPrimary) // Make stack nodes - stackConf := domain.StackConfResponse{ - TksCpNode: dto.NodesIO.TksCpNode.Count, - TksInfraNode: dto.NodesIO.TksInfraNode.Count, - TksUserNode: dto.NodesIO.TksUserNode.Count, + var stackConf domain.StackConfResponse + if err = domain.Map(dto.Conf, &stackConf); err != nil { + log.InfoWithContext(ctx, err) } workflow := "" @@ -488,6 +489,34 @@ func (u *StackUsecase) GetStepStatus(ctx context.Context, stackId domain.StackId return } +func (u *StackUsecase) SetFavorite(ctx context.Context, stackId domain.StackId) error { + user, ok := request.UserFrom(ctx) + if !ok { + return httpErrors.NewUnauthorizedError(fmt.Errorf("Invalid token"), "A_INVALID_TOKEN", "") + } + + err := u.clusterRepo.SetFavorite(domain.ClusterId(stackId), user.GetUserId()) + if err != nil { + return err + } + + return nil +} + +func (u *StackUsecase) DeleteFavorite(ctx context.Context, stackId domain.StackId) error { + user, ok := request.UserFrom(ctx) + if !ok { + return httpErrors.NewUnauthorizedError(fmt.Errorf("Invalid token"), "A_INVALID_TOKEN", "") + } + + err := u.clusterRepo.DeleteFavorite(domain.ClusterId(stackId), user.GetUserId()) + if err != nil { + return err + } + + return nil +} + func reflectClusterToStack(cluster domain.Cluster, appGroups []domain.AppGroup) (out domain.Stack) { if err := serializer.Map(cluster, &out); err != nil { log.Error(err) diff --git a/pkg/domain/cloud-account.go b/pkg/domain/cloud-account.go index 65609b23..5e4720c8 100644 --- a/pkg/domain/cloud-account.go +++ b/pkg/domain/cloud-account.go @@ -13,6 +13,7 @@ const ( CloudService_AWS = "AWS" CloudService_AZURE = "AZZURE" CloudService_GCP = "GCP" + CloudService_BYOH = "BYOH" ) // enum diff --git a/pkg/domain/cluster.go b/pkg/domain/cluster.go index ea7df469..98ff1514 100644 --- a/pkg/domain/cluster.go +++ b/pkg/domain/cluster.go @@ -50,9 +50,32 @@ func (m ClusterStatus) FromString(s string) ClusterStatus { return ClusterStatus_PENDING } +type ClusterType int32 + +const ( + ClusterType_USER = iota + ClusterType_ADMIN +) + +var clusterType = [...]string{ + "USER", + "ADMIN", +} + +func (m ClusterType) String() string { return clusterType[(m)] } +func (m ClusterType) FromString(s string) ClusterType { + for i, v := range clusterType { + if v == s { + return ClusterType(i) + } + } + return ClusterType_USER +} + // model type Cluster struct { ID ClusterId + CloudService string OrganizationId string Name string Description string @@ -65,6 +88,7 @@ type Cluster struct { Conf ClusterConf CreatorId *uuid.UUID Creator User + ClusterType ClusterType UpdatorId *uuid.UUID Updator User CreatedAt time.Time @@ -110,10 +134,12 @@ func (m *ClusterConf) SetDefault() { type CreateClusterRequest struct { OrganizationId string `json:"organizationId" validate:"required"` + CloudService string `json:"cloudService" validate:"required,oneof=AWS BYOH"` StackTemplateId string `json:"stackTemplateId" validate:"required"` Name string `json:"name" validate:"required,name"` Description string `json:"description"` CloudAccountId string `json:"cloudAccountId" validate:"required"` + ClusterType string `json:"clusterType"` TksCpNode int `json:"tksCpNode"` TksCpNodeMax int `json:"tksCpNodeMax,omitempty"` TksCpNodeType string `json:"tksCpNodeType,omitempty"` @@ -143,6 +169,7 @@ type ClusterConfResponse struct { type ClusterResponse struct { ID ClusterId `json:"id"` + CloudService string `json:"cloudService"` OrganizationId string `json:"organizationId"` Name string `json:"name"` Description string `json:"description"` @@ -151,6 +178,7 @@ type ClusterResponse struct { Status string `json:"status"` StatusDesc string `json:"statusDesc"` Conf ClusterConfResponse `json:"conf"` + ClusterType string `json:"clusterType"` Creator SimpleUserResponse `json:"creator"` Updator SimpleUserResponse `json:"updator"` CreatedAt time.Time `json:"createdAt"` diff --git a/pkg/domain/stack.go b/pkg/domain/stack.go index 29afdad6..b8800f8d 100644 --- a/pkg/domain/stack.go +++ b/pkg/domain/stack.go @@ -75,14 +75,14 @@ type Stack = struct { Name string Description string OrganizationId string + CloudService string CloudAccountId uuid.UUID CloudAccount CloudAccount StackTemplateId uuid.UUID StackTemplate StackTemplate Status StackStatus StatusDesc string - Nodes []StackNode - NodesIO StackNodesIO + Conf StackConf PrimaryCluster bool GrafanaUrl string CreatorId *uuid.UUID @@ -93,6 +93,17 @@ type Stack = struct { UpdatedAt time.Time } +type StackConf struct { + TksCpNode int + TksCpNodeMax int + TksCpNodeType string + TksInfraNode int + TksInfraNodeMax int + TksInfraNodeType string + TksUserNode int + TksUserNodeMax int + TksUserNodeType string +} type StackStepStatus struct { Status string `json:"status"` Stage string `json:"stage"` @@ -100,28 +111,21 @@ type StackStepStatus struct { MaxStep int `json:"maxStep"` } -type StackNode struct { - StackNodeType string `json:"type" validate:"oneof=TKS_CP_NODE TKS_INFRA_NODE TKS_USER_NODE"` - HostName []string -} - -type StackNodeIO struct { - Count int `json:"count"` - HostName []string `json:"hostNames"` -} - -type StackNodesIO struct { - TksCpNode StackNodeIO `json:"tksCpNode"` - TksInfraNode StackNodeIO `json:"tksInfraNode"` - TksUserNode StackNodeIO `json:"tksUserNode"` -} - type CreateStackRequest struct { - Name string `json:"name" validate:"required,name,rfc1123"` - Description string `json:"description"` - StackTemplateId string `json:"stackTemplateId" validate:"required"` - CloudAccountId string `json:"cloudAccountId" validate:"required"` - NodesIO StackNodesIO `json:"nodes" validate:"required"` + Name string `json:"name" validate:"required,name,rfc1123"` + Description string `json:"description"` + CloudService string `json:"cloudService" validate:"required,oneof=AWS BYOH"` + StackTemplateId string `json:"stackTemplateId" validate:"required"` + CloudAccountId string `json:"cloudAccountId" validate:"required"` + TksCpNode int `json:"tksCpNode"` + TksCpNodeMax int `json:"tksCpNodeMax,omitempty"` + TksCpNodeType string `json:"tksCpNodeType,omitempty"` + TksInfraNode int `json:"tksInfraNode"` + TksInfraNodeMax int `json:"tksInfraNodeMax,omitempty"` + TksInfraNodeType string `json:"tksInfraNodeType,omitempty"` + TksUserNode int `json:"tksUserNode"` + TksUserNodeMax int `json:"tksUserNodeMax,omitempty"` + TksUserNodeType string `json:"tksUserNodeType,omitempty"` } type CreateStackResponse struct {