From 9142ea13a373e69787c11e9d246e4ae5e4d83b73 Mon Sep 17 00:00:00 2001 From: "taekyu.kang" Date: Wed, 18 Oct 2023 00:08:17 +0900 Subject: [PATCH] feature. add byoDomian parameter on creating byoh cluster --- api/swagger/docs.go | 37 +++++--- api/swagger/swagger.json | 37 +++++--- api/swagger/swagger.yaml | 26 ++++-- cmd/server/main.go | 2 +- internal/delivery/http/cluster.go | 4 + internal/repository/cluster.go | 109 +++++++++++----------- internal/usecase/app-group.go | 37 ++++---- internal/usecase/cloud-account.go | 13 +++ internal/usecase/cluster.go | 49 ++++++++-- internal/usecase/dashboard.go | 5 +- internal/usecase/stack.go | 55 +++++++----- pkg/domain/cluster.go | 145 +++++++++++++++--------------- pkg/domain/stack.go | 8 +- pkg/httpErrors/errorCode.go | 3 + 14 files changed, 322 insertions(+), 208 deletions(-) diff --git a/api/swagger/docs.go b/api/swagger/docs.go index 9275cc13..c1311530 100644 --- a/api/swagger/docs.go +++ b/api/swagger/docs.go @@ -4190,7 +4190,7 @@ const docTemplate = `{ "type": "object", "properties": { "expiration": { - "type": "string" + "type": "integer" } } }, @@ -4356,6 +4356,12 @@ const docTemplate = `{ "domain.Cluster": { "type": "object", "properties": { + "byoClusterEndpointHost": { + "type": "string" + }, + "byoClusterEndpointPort": { + "type": "integer" + }, "cloudAccount": { "$ref": "#/definitions/domain.CloudAccount" }, @@ -4365,9 +4371,6 @@ const docTemplate = `{ "cloudService": { "type": "string" }, - "clusterEndpoint": { - "type": "string" - }, "clusterType": { "type": "integer" }, @@ -4527,13 +4530,19 @@ const docTemplate = `{ "type": "string" }, "validity": { - "type": "string" + "type": "integer" } } }, "domain.ClusterResponse": { "type": "object", "properties": { + "byoClusterEndpointHost": { + "type": "string" + }, + "byoClusterEndpointPort": { + "type": "integer" + }, "cloudAccount": { "$ref": "#/definitions/domain.SimpleCloudAccountResponse" }, @@ -4581,15 +4590,18 @@ const docTemplate = `{ }, "updator": { "$ref": "#/definitions/domain.SimpleUserResponse" - }, - "userClusterEndpoint": { - "type": "string" } } }, "domain.ClusterSiteValuesResponse": { "type": "object", "properties": { + "byoClusterEndpointHost": { + "type": "string" + }, + "byoClusterEndpointPort": { + "type": "integer" + }, "clusterRegion": { "type": "string" }, @@ -4819,6 +4831,12 @@ const docTemplate = `{ "stackTemplateId" ], "properties": { + "byoClusterEndpointHost": { + "type": "string" + }, + "byoClusterEndpointPort": { + "type": "integer" + }, "cloudAccountId": { "type": "string" }, @@ -4873,9 +4891,6 @@ const docTemplate = `{ }, "tksUserNodeType": { "type": "string" - }, - "userClusterEndpoint": { - "type": "string" } } }, diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index 90f5baaa..454d384c 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -4183,7 +4183,7 @@ "type": "object", "properties": { "expiration": { - "type": "string" + "type": "integer" } } }, @@ -4349,6 +4349,12 @@ "domain.Cluster": { "type": "object", "properties": { + "byoClusterEndpointHost": { + "type": "string" + }, + "byoClusterEndpointPort": { + "type": "integer" + }, "cloudAccount": { "$ref": "#/definitions/domain.CloudAccount" }, @@ -4358,9 +4364,6 @@ "cloudService": { "type": "string" }, - "clusterEndpoint": { - "type": "string" - }, "clusterType": { "type": "integer" }, @@ -4520,13 +4523,19 @@ "type": "string" }, "validity": { - "type": "string" + "type": "integer" } } }, "domain.ClusterResponse": { "type": "object", "properties": { + "byoClusterEndpointHost": { + "type": "string" + }, + "byoClusterEndpointPort": { + "type": "integer" + }, "cloudAccount": { "$ref": "#/definitions/domain.SimpleCloudAccountResponse" }, @@ -4574,15 +4583,18 @@ }, "updator": { "$ref": "#/definitions/domain.SimpleUserResponse" - }, - "userClusterEndpoint": { - "type": "string" } } }, "domain.ClusterSiteValuesResponse": { "type": "object", "properties": { + "byoClusterEndpointHost": { + "type": "string" + }, + "byoClusterEndpointPort": { + "type": "integer" + }, "clusterRegion": { "type": "string" }, @@ -4812,6 +4824,12 @@ "stackTemplateId" ], "properties": { + "byoClusterEndpointHost": { + "type": "string" + }, + "byoClusterEndpointPort": { + "type": "integer" + }, "cloudAccountId": { "type": "string" }, @@ -4866,9 +4884,6 @@ }, "tksUserNodeType": { "type": "string" - }, - "userClusterEndpoint": { - "type": "string" } } }, diff --git a/api/swagger/swagger.yaml b/api/swagger/swagger.yaml index 45ba8b3a..6253a920 100644 --- a/api/swagger/swagger.yaml +++ b/api/swagger/swagger.yaml @@ -255,7 +255,7 @@ definitions: domain.BootstrapKubeconfig: properties: expiration: - type: string + type: integer type: object domain.ChartData: properties: @@ -363,14 +363,16 @@ definitions: type: object domain.Cluster: properties: + byoClusterEndpointHost: + type: string + byoClusterEndpointPort: + type: integer cloudAccount: $ref: '#/definitions/domain.CloudAccount' cloudAccountId: type: string cloudService: type: string - clusterEndpoint: - type: string clusterType: type: integer conf: @@ -476,10 +478,14 @@ definitions: type: type: string validity: - type: string + type: integer type: object domain.ClusterResponse: properties: + byoClusterEndpointHost: + type: string + byoClusterEndpointPort: + type: integer cloudAccount: $ref: '#/definitions/domain.SimpleCloudAccountResponse' cloudService: @@ -512,11 +518,13 @@ definitions: type: string updator: $ref: '#/definitions/domain.SimpleUserResponse' - userClusterEndpoint: - type: string type: object domain.ClusterSiteValuesResponse: properties: + byoClusterEndpointHost: + type: string + byoClusterEndpointPort: + type: integer clusterRegion: type: string sshKeyName: @@ -670,6 +678,10 @@ definitions: type: object domain.CreateClusterRequest: properties: + byoClusterEndpointHost: + type: string + byoClusterEndpointPort: + type: integer cloudAccountId: type: string cloudService: @@ -707,8 +719,6 @@ definitions: type: integer tksUserNodeType: type: string - userClusterEndpoint: - type: string required: - cloudService - name diff --git a/cmd/server/main.go b/cmd/server/main.go index 99508115..9c0d298d 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -33,7 +33,7 @@ func init() { flag.String("jwt-secret", "tks-api-secret", "secret value of jwt") flag.String("git-base-url", "https://github.com", "git base url") flag.String("git-account", "decapod10", "git account of admin cluster") - flag.String("external-gitea-url", "http://gitea-dev.taco-cat.xyz", "gitea url for byoh agent download") + flag.String("external-gitea-url", "http://ip-10-0-76-86.ap-northeast-2.compute.internal:30303", "gitea url for byoh agent download") flag.String("revision", "main", "revision") flag.String("aws-secret", "awsconfig-secret", "aws secret") flag.Int("migrate-db", 1, "If the values is true, enable db migration. recommend only development") diff --git a/internal/delivery/http/cluster.go b/internal/delivery/http/cluster.go index 7a2ebb09..cb8b8f6e 100644 --- a/internal/delivery/http/cluster.go +++ b/internal/delivery/http/cluster.go @@ -166,6 +166,10 @@ func (h *ClusterHandler) CreateCluster(w http.ResponseWriter, r *http.Request) { //txHandle := r.Context().Value("txHandle").(*gorm.DB) clusterId := domain.ClusterId("") if input.CloudService == domain.CloudService_BYOH { + if dto.ByoClusterEndpointHost == "" || dto.ByoClusterEndpointPort == 0 { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("Invalid byoh cluster endpoint"), "CL_INVALID_BYOH_CLUSTER_ENDPOINT", "")) + return + } clusterId, err = h.usecase.Bootstrap(r.Context(), dto) if err != nil { ErrorJSON(w, r, err) diff --git a/internal/repository/cluster.go b/internal/repository/cluster.go index a10d642d..570bc795 100644 --- a/internal/repository/cluster.go +++ b/internal/repository/cluster.go @@ -20,7 +20,7 @@ type IClusterRepository interface { WithTrx(*gorm.DB) IClusterRepository 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) + FetchByOrganizationId(organizationId string, userId uuid.UUID, 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) @@ -50,36 +50,37 @@ func NewClusterRepository(db *gorm.DB) IClusterRepository { type Cluster struct { gorm.Model - 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"` - WorkflowId string - Status domain.ClusterStatus - StatusDesc string - CloudAccountId *uuid.UUID - CloudAccount CloudAccount `gorm:"foreignKey:CloudAccountId"` - StackTemplateId uuid.UUID - StackTemplate StackTemplate `gorm:"foreignKey:StackTemplateId"` - Favorites *[]ClusterFavorite - ClusterType domain.ClusterType `gorm:"default:0"` - ClusterEndpoint string - IsStack bool `gorm:"default:false"` - TksCpNode int - TksCpNodeMax int - TksCpNodeType string - TksInfraNode int - TksInfraNodeMax int - TksInfraNodeType string - TksUserNode int - TksUserNodeMax int - TksUserNodeType string - CreatorId *uuid.UUID `gorm:"type:uuid"` - Creator User `gorm:"foreignKey:CreatorId"` - UpdatorId *uuid.UUID `gorm:"type:uuid"` - Updator User `gorm:"foreignKey:UpdatorId"` + 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"` + WorkflowId string + Status domain.ClusterStatus + StatusDesc string + CloudAccountId *uuid.UUID + CloudAccount CloudAccount `gorm:"foreignKey:CloudAccountId"` + StackTemplateId uuid.UUID + StackTemplate StackTemplate `gorm:"foreignKey:StackTemplateId"` + Favorites *[]ClusterFavorite + ClusterType domain.ClusterType `gorm:"default:0"` + ByoClusterEndpointHost string + ByoClusterEndpointPort int + IsStack bool `gorm:"default:false"` + TksCpNode int + TksCpNodeMax int + TksCpNodeType string + TksInfraNode int + TksInfraNodeMax int + TksInfraNodeType string + TksUserNode int + TksUserNodeMax int + TksUserNodeType string + CreatorId *uuid.UUID `gorm:"type:uuid"` + Creator User `gorm:"foreignKey:CreatorId"` + UpdatorId *uuid.UUID `gorm:"type:uuid"` + Updator User `gorm:"foreignKey:UpdatorId"` } func (c *Cluster) BeforeCreate(tx *gorm.DB) (err error) { @@ -135,8 +136,7 @@ func (r *ClusterRepository) Fetch(pg *pagination.Pagination) (out []domain.Clust return } -func (r *ClusterRepository) FetchByOrganizationId(organizationId string, pg *pagination.Pagination) (out []domain.Cluster, err error) { - userId := "79a404aa-7184-4d0f-9e73-2671e32f7da5" +func (r *ClusterRepository) FetchByOrganizationId(organizationId string, userId uuid.UUID, pg *pagination.Pagination) (out []domain.Cluster, err error) { var clusters []Cluster if pg == nil { pg = pagination.NewDefaultPagination() @@ -219,27 +219,28 @@ func (r *ClusterRepository) Create(dto domain.Cluster) (clusterId domain.Cluster cloudAccountId = nil } cluster := Cluster{ - OrganizationId: dto.OrganizationId, - Name: dto.Name, - Description: dto.Description, - CloudAccountId: cloudAccountId, - StackTemplateId: dto.StackTemplateId, - CreatorId: dto.CreatorId, - UpdatorId: nil, - Status: domain.ClusterStatus_PENDING, - ClusterType: dto.ClusterType, - CloudService: dto.CloudService, - ClusterEndpoint: dto.ClusterEndpoint, - IsStack: dto.IsStack, - TksCpNode: dto.Conf.TksCpNode, - TksCpNodeMax: dto.Conf.TksCpNodeMax, - TksCpNodeType: dto.Conf.TksCpNodeType, - TksInfraNode: dto.Conf.TksInfraNode, - TksInfraNodeMax: dto.Conf.TksInfraNodeMax, - TksInfraNodeType: dto.Conf.TksInfraNodeType, - TksUserNode: dto.Conf.TksUserNode, - TksUserNodeMax: dto.Conf.TksUserNodeMax, - TksUserNodeType: dto.Conf.TksUserNodeType, + OrganizationId: dto.OrganizationId, + Name: dto.Name, + Description: dto.Description, + CloudAccountId: cloudAccountId, + StackTemplateId: dto.StackTemplateId, + CreatorId: dto.CreatorId, + UpdatorId: nil, + Status: domain.ClusterStatus_PENDING, + ClusterType: dto.ClusterType, + CloudService: dto.CloudService, + ByoClusterEndpointHost: dto.ByoClusterEndpointHost, + ByoClusterEndpointPort: dto.ByoClusterEndpointPort, + IsStack: dto.IsStack, + TksCpNode: dto.Conf.TksCpNode, + TksCpNodeMax: dto.Conf.TksCpNodeMax, + TksCpNodeType: dto.Conf.TksCpNodeType, + TksInfraNode: dto.Conf.TksInfraNode, + TksInfraNodeMax: dto.Conf.TksInfraNodeMax, + TksInfraNodeType: dto.Conf.TksInfraNodeType, + TksUserNode: dto.Conf.TksUserNode, + TksUserNodeMax: dto.Conf.TksUserNodeMax, + TksUserNodeType: dto.Conf.TksUserNodeType, } res := r.db.Create(&cluster) if res.Error != nil { diff --git a/internal/usecase/app-group.go b/internal/usecase/app-group.go index e17fa685..3b8f9dcd 100644 --- a/internal/usecase/app-group.go +++ b/internal/usecase/app-group.go @@ -78,25 +78,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 = "" + tksCloudAccountId := "" + if cluster.CloudService != domain.CloudService_BYOH { + 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 } - isExist = true - break } - } - if !isExist { - return "", httpErrors.NewBadRequestError(fmt.Errorf("Not found cloudAccountId[%s] in organization[%s]", cluster.CloudAccountId, cluster.OrganizationId), "", "") + if !isExist { + return "", httpErrors.NewBadRequestError(fmt.Errorf("Not found cloudAccountId[%s] in organization[%s]", cluster.CloudAccountId, cluster.OrganizationId), "", "") + } } if dto.ID == "" { diff --git a/internal/usecase/cloud-account.go b/internal/usecase/cloud-account.go index 3d3f1be4..a938066f 100644 --- a/internal/usecase/cloud-account.go +++ b/internal/usecase/cloud-account.go @@ -456,3 +456,16 @@ func (u *CloudAccountUsecase) getClusterCnt(cloudAccountId uuid.UUID) (cnt int) return cnt } + +func getServiceQuota(client *servicequotas.Client, quotaCode string, serviceCode string) (res *servicequotas.GetServiceQuotaOutput, err error) { + res, err = client.GetServiceQuota(context.TODO(), &servicequotas.GetServiceQuotaInput{ + QuotaCode: "aCode, + ServiceCode: &serviceCode, + }, func(o *servicequotas.Options) { + o.Region = "ap-northeast-2" + }) + if err != nil { + return nil, err + } + return +} diff --git a/internal/usecase/cluster.go b/internal/usecase/cluster.go index 43097ef0..b4bbe3da 100644 --- a/internal/usecase/cluster.go +++ b/internal/usecase/cluster.go @@ -98,11 +98,16 @@ func (u *ClusterUsecase) WithTrx(trxHandle *gorm.DB) IClusterUsecase { } func (u *ClusterUsecase) Fetch(ctx context.Context, organizationId string, pg *pagination.Pagination) (out []domain.Cluster, err error) { + user, ok := request.UserFrom(ctx) + if !ok { + return out, httpErrors.NewBadRequestError(fmt.Errorf("Invalid token"), "", "") + } + if organizationId == "" { // [TODO] 사용자가 속한 organization 리스트 out, err = u.repo.Fetch(pg) } else { - out, err = u.repo.FetchByOrganizationId(organizationId, pg) + out, err = u.repo.FetchByOrganizationId(organizationId, user.GetUserId(), pg) } if err != nil { @@ -218,7 +223,7 @@ func (u *ClusterUsecase) Bootstrap(ctx context.Context, dto domain.Cluster) (clu if err != nil { return "", httpErrors.NewBadRequestError(errors.Wrap(err, "Invalid stackTemplateId"), "", "") } - log.Infof("%s %s", stackTemplate.CloudService, dto.CloudService) + log.InfofWithContext(ctx, "%s %s", stackTemplate.CloudService, dto.CloudService) if stackTemplate.CloudService != dto.CloudService { return "", httpErrors.NewBadRequestError(fmt.Errorf("Invalid cloudService for stackTemplate "), "", "") } @@ -379,6 +384,10 @@ func (u *ClusterUsecase) GetClusterSiteValues(ctx context.Context, clusterId dom log.ErrorWithContext(ctx, err) } + if err := serializer.Map(cluster, &out); err != nil { + log.ErrorWithContext(ctx, err) + } + /* // 기능 변경 : 20230614 : machine deployment 사용하지 않음. 단, aws-standard 는 사용할 여지가 있으므로 주석처리해둔다. const MAX_AZ_NUM = 4 @@ -466,7 +475,7 @@ func (u *ClusterUsecase) GetBootstrapKubeconfig(ctx context.Context, clusterId d return out, err } - log.Info(helper.ModelToJson(kubeconfig.Status.BootstrapKubeconfigData)) + log.DebugWithContext(ctx, helper.ModelToJson(kubeconfig.Status.BootstrapKubeconfigData)) type BootstrapKubeconfigUser struct { Users []struct { @@ -485,16 +494,28 @@ func (u *ClusterUsecase) GetBootstrapKubeconfig(ctx context.Context, clusterId d } token := kubeconfigData.Users[0].User.Token[:6] - //token = "5zg8tr" // FOR TEST - log.Info(token) + log.InfoWithContext(ctx, "token : ", token) secrets, err := client.CoreV1().Secrets("kube-system").Get(context.TODO(), "bootstrap-token-"+token, metav1.GetOptions{}) if err != nil { - log.Error(err) + log.ErrorWithContext(ctx, err) return out, err } - out.Expiration = string(secrets.Data["expiration"][:]) + log.Info(secrets.Data["expiration"][:]) + + // 2023-10-17T11:05:33Z + now := time.Now() + expiration, err := time.Parse(time.RFC3339, string(secrets.Data["expiration"][:])) + if err != nil { + return out, err + } + + period, err := time.ParseDuration(expiration.Sub(now).String()) + if err != nil { + return out, err + } + out.Expiration = int(period.Seconds()) return out, nil } @@ -553,7 +574,7 @@ func (u *ClusterUsecase) GetNodes(ctx context.Context, clusterId domain.ClusterI for _, host := range hosts.Items { label := host.Labels["role"] arr := strings.Split(host.Labels["role"], "-") - if len(arr) < 3 { + if len(arr) < 2 { continue } clusterId := arr[0] @@ -561,15 +582,25 @@ func (u *ClusterUsecase) GetNodes(ctx context.Context, clusterId domain.ClusterI if label[9] != '-' || clusterId != string(cluster.ID) { continue } + /* + if host.Name == "ip-10-0-12-87.ap-northeast-2.compute.internal" { + continue + } + + role := host.Labels["role"] // [FOR TEST] + */ hostStatus := host.Status.Conditions[0].Type registered, registering := 0, 0 - if hostStatus == "K8sNodeBootstrapSucceeded" { + // K8sComponentsInstallationSucceeded + if hostStatus == "K8sNodeBootstrapSucceeded" || hostStatus == "K8sComponentsInstallationSucceeded" { registered = 1 } else { registering = 1 } + log.Info(role) + switch role { case "control-plane": tksCpNodeRegistered = tksCpNodeRegistered + registered diff --git a/internal/usecase/dashboard.go b/internal/usecase/dashboard.go index b32c8ea1..c4a4252e 100644 --- a/internal/usecase/dashboard.go +++ b/internal/usecase/dashboard.go @@ -8,6 +8,7 @@ import ( "strconv" "time" + "github.com/google/uuid" "github.com/openinfradev/tks-api/internal/helper" "github.com/openinfradev/tks-api/internal/kubernetes" "github.com/openinfradev/tks-api/internal/repository" @@ -71,7 +72,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, nil) + clusters, err := u.clusterRepo.FetchByOrganizationId(organizationId, uuid.Nil, nil) if err != nil { return out, err } @@ -147,7 +148,7 @@ func (u *DashboardUsecase) GetResources(ctx context.Context, organizationId stri } // Stack - clusters, err := u.clusterRepo.FetchByOrganizationId(organizationId, nil) + clusters, err := u.clusterRepo.FetchByOrganizationId(organizationId, uuid.Nil, nil) if err != nil { return out, err } diff --git a/internal/usecase/stack.go b/internal/usecase/stack.go index 3604a593..7a3668de 100644 --- a/internal/usecase/stack.go +++ b/internal/usecase/stack.go @@ -3,10 +3,11 @@ package usecase import ( "context" "fmt" + "sort" "strings" "time" - "github.com/aws/aws-sdk-go-v2/service/servicequotas" + "github.com/google/uuid" "github.com/openinfradev/tks-api/internal/helper" "github.com/openinfradev/tks-api/internal/kubernetes" "github.com/openinfradev/tks-api/internal/middleware/auth/request" @@ -76,7 +77,7 @@ func (u *StackUsecase) Create(ctx context.Context, dto domain.Stack) (stackId do return "", httpErrors.NewInternalServerError(errors.Wrap(err, "Invalid stackTemplateId"), "S_INVALID_STACK_TEMPLATE", "") } - clusters, err := u.clusterRepo.FetchByOrganizationId(dto.OrganizationId, nil) + clusters, err := u.clusterRepo.FetchByOrganizationId(dto.OrganizationId, user.GetUserId(), nil) if err != nil { return "", httpErrors.NewInternalServerError(errors.Wrap(err, "Failed to get clusters"), "S_FAILED_GET_CLUSTERS", "") } @@ -88,7 +89,11 @@ func (u *StackUsecase) Create(ctx context.Context, dto domain.Stack) (stackId do if dto.CloudService == domain.CloudService_BYOH { if dto.ClusterEndpoint == "" { - return "", httpErrors.NewBadRequestError(fmt.Errorf("Invalid userClusterDomain"), "S_INVALID_ADMINCLUSTER_URL", "") + return "", httpErrors.NewBadRequestError(fmt.Errorf("Invalid clusterEndpoint"), "S_INVALID_ADMINCLUSTER_URL", "") + } + arr := strings.Split(dto.ClusterEndpoint, ":") + if len(arr) != 2 { + return "", httpErrors.NewBadRequestError(fmt.Errorf("Invalid clusterEndpoint"), "S_INVALID_ADMINCLUSTER_URL", "") } } else { if _, err = u.cloudAccountRepo.Get(dto.CloudAccountId); err != nil { @@ -115,6 +120,7 @@ func (u *StackUsecase) Create(ctx context.Context, dto domain.Stack) (stackId do "base_repo_branch=" + viper.GetString("revision"), "infra_conf=" + strings.Replace(helper.ModelToJson(stackConf), "\"", "\\\"", -1), "cloud_service=" + dto.CloudService, + "cluster_endpoint=" + dto.ClusterEndpoint, }, }) if err != nil { @@ -161,7 +167,7 @@ func (u *StackUsecase) Install(ctx context.Context, stackId domain.StackId) (err return httpErrors.NewInternalServerError(errors.Wrap(err, "Invalid stackTemplateId"), "S_INVALID_STACK_TEMPLATE", "") } - clusters, err := u.clusterRepo.FetchByOrganizationId(cluster.OrganizationId, nil) + clusters, err := u.clusterRepo.FetchByOrganizationId(cluster.OrganizationId, uuid.Nil, nil) if err != nil { return httpErrors.NewInternalServerError(errors.Wrap(err, "Failed to get clusters"), "S_FAILED_GET_CLUSTERS", "") } @@ -265,12 +271,17 @@ func (u *StackUsecase) GetByName(ctx context.Context, organizationId string, nam } func (u *StackUsecase) Fetch(ctx context.Context, organizationId string, pg *pagination.Pagination) (out []domain.Stack, err error) { + user, ok := request.UserFrom(ctx) + if !ok { + return out, httpErrors.NewUnauthorizedError(fmt.Errorf("Invalid token"), "A_INVALID_TOKEN", "") + } + 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, pg) + clusters, err := u.clusterRepo.FetchByOrganizationId(organizationId, user.GetUserId(), pg) if err != nil { return out, err } @@ -311,6 +322,10 @@ func (u *StackUsecase) Fetch(ctx context.Context, organizationId string, pg *pag out = append(out, outStack) } + sort.Slice(out, func(i, j int) bool { + return string(out[i].ID) == organization.PrimaryClusterId + }) + return } @@ -341,6 +356,11 @@ func (u *StackUsecase) Update(ctx context.Context, dto domain.Stack) (err error) } func (u *StackUsecase) Delete(ctx context.Context, dto domain.Stack) (err error) { + user, ok := request.UserFrom(ctx) + if !ok { + return httpErrors.NewBadRequestError(fmt.Errorf("Invalid token"), "", "") + } + cluster, err := u.clusterRepo.Get(domain.ClusterId(dto.ID)) if err != nil { return httpErrors.NewBadRequestError(errors.Wrap(err, "Failed to get cluster"), "S_FAILED_FETCH_CLUSTER", "") @@ -355,7 +375,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, nil) + clusters, err := u.clusterRepo.FetchByOrganizationId(organization.ID, user.GetUserId(), nil) if err != nil { return errors.Wrap(err, "Failed to get organizations") } @@ -473,7 +493,7 @@ func (u *StackUsecase) GetStepStatus(ctx context.Context, stackId domain.StackId out = append(out, clusterStepStatus) // make default appgroup status - if strings.Contains(cluster.StackTemplate.Template, "aws-reference") || strings.Contains(cluster.StackTemplate.Template, "eks-reference") { + if cluster.StackTemplate.TemplateType == "STANDARD" { // LMA out = append(out, domain.StackStepStatus{ Status: domain.AppGroupStatus_PENDING.String(), @@ -481,7 +501,7 @@ func (u *StackUsecase) GetStepStatus(ctx context.Context, stackId domain.StackId Step: 0, MaxStep: domain.MAX_STEP_LMA_CREATE_MEMBER, }) - } else if strings.Contains(cluster.StackTemplate.Template, "aws-msa-reference") || strings.Contains(cluster.StackTemplate.Template, "eks-msa-reference") { + } else { // LMA + SERVICE_MESH out = append(out, domain.StackStepStatus{ Status: domain.AppGroupStatus_PENDING.String(), @@ -639,6 +659,12 @@ func getStackStatus(cluster domain.Cluster, appGroups []domain.AppGroup) (domain } } + if cluster.Status == domain.ClusterStatus_BOOTSTRAPPING { + return domain.StackStatus_CLUSTER_BOOTSTRAPPING, cluster.StatusDesc + } + if cluster.Status == domain.ClusterStatus_BOOTSTRAPPED { + return domain.StackStatus_CLUSTER_BOOTSTRAPPED, cluster.StatusDesc + } if cluster.Status == domain.ClusterStatus_INSTALLING { return domain.StackStatus_CLUSTER_INSTALLING, cluster.StatusDesc } @@ -701,16 +727,3 @@ func parseStatusDescription(statusDesc string) (step int) { } return } - -func getServiceQuota(client *servicequotas.Client, quotaCode string, serviceCode string) (res *servicequotas.GetServiceQuotaOutput, err error) { - res, err = client.GetServiceQuota(context.TODO(), &servicequotas.GetServiceQuotaInput{ - QuotaCode: "aCode, - ServiceCode: &serviceCode, - }, func(o *servicequotas.Options) { - o.Region = "ap-northeast-2" - }) - if err != nil { - return nil, err - } - return -} diff --git a/pkg/domain/cluster.go b/pkg/domain/cluster.go index c5739a2e..99613c6e 100644 --- a/pkg/domain/cluster.go +++ b/pkg/domain/cluster.go @@ -84,28 +84,29 @@ func (m ClusterType) FromString(s string) ClusterType { // model type Cluster struct { - ID ClusterId - CloudService string - OrganizationId string - Name string - Description string - CloudAccountId uuid.UUID - CloudAccount CloudAccount - StackTemplateId uuid.UUID - StackTemplate StackTemplate - Status ClusterStatus - StatusDesc string - Conf ClusterConf - Favorited bool - CreatorId *uuid.UUID - Creator User - ClusterType ClusterType - UpdatorId *uuid.UUID - Updator User - CreatedAt time.Time - UpdatedAt time.Time - ClusterEndpoint string - IsStack bool + ID ClusterId + CloudService string + OrganizationId string + Name string + Description string + CloudAccountId uuid.UUID + CloudAccount CloudAccount + StackTemplateId uuid.UUID + StackTemplate StackTemplate + Status ClusterStatus + StatusDesc string + Conf ClusterConf + Favorited bool + CreatorId *uuid.UUID + Creator User + ClusterType ClusterType + UpdatorId *uuid.UUID + Updator User + CreatedAt time.Time + UpdatedAt time.Time + ByoClusterEndpointHost string + ByoClusterEndpointPort int + IsStack bool } type ClusterConf struct { @@ -132,12 +133,12 @@ type ClusterNode struct { Registering int `json:"registering"` Status string `json:"status"` Command string `json:"command"` - Validity string `json:"validity"` + Validity int `json:"validity"` Hosts []ClusterHost `json:"hosts"` } type BootstrapKubeconfig struct { - Expiration string `json:"expiration"` + Expiration int `json:"expiration"` } // [TODO] annotaion 으로 가능하려나? @@ -166,24 +167,25 @@ 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"` - ClusterType string `json:"clusterType"` - ClusterEndpoint string `json:"userClusterEndpoint,omitempty"` - IsStack bool `json:"isStack,omitempty"` - 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"` + 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"` + ClusterType string `json:"clusterType"` + ByoClusterEndpointHost string `json:"byoClusterEndpointHost,omitempty"` + ByoClusterEndpointPort int `json:"byoClusterEndpointPort,omitempty"` + IsStack bool `json:"isStack,omitempty"` + 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 CreateClusterResponse struct { @@ -203,23 +205,24 @@ 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"` - CloudAccount SimpleCloudAccountResponse `json:"cloudAccount"` - StackTemplate SimpleStackTemplateResponse `json:"stackTemplate"` - 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"` - UpdatedAt time.Time `json:"updatedAt"` - ClusterEndpoint string `json:"userClusterEndpoint,omitempty"` - IsStack bool `json:"isStack,omitempty"` + ID ClusterId `json:"id"` + CloudService string `json:"cloudService"` + OrganizationId string `json:"organizationId"` + Name string `json:"name"` + Description string `json:"description"` + CloudAccount SimpleCloudAccountResponse `json:"cloudAccount"` + StackTemplate SimpleStackTemplateResponse `json:"stackTemplate"` + 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"` + UpdatedAt time.Time `json:"updatedAt"` + ByoClusterEndpointHost string `json:"byoClusterEndpointHost,omitempty"` + ByoClusterEndpointInt int `json:"byoClusterEndpointPort,omitempty"` + IsStack bool `json:"isStack,omitempty"` } type SimpleClusterResponse struct { @@ -229,17 +232,19 @@ type SimpleClusterResponse struct { } type ClusterSiteValuesResponse struct { - SshKeyName string `json:"sshKeyName"` - ClusterRegion string `json:"clusterRegion"` - 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"` + SshKeyName string `json:"sshKeyName"` + ClusterRegion string `json:"clusterRegion"` + 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"` + ByoClusterEndpointHost string `json:"byoClusterEndpointHost,omitempty"` + ByoClusterEndpointPort int `json:"byoClusterEndpointPort,omitempty"` } type GetClustersResponse struct { diff --git a/pkg/domain/stack.go b/pkg/domain/stack.go index 8880c23f..07de89d8 100644 --- a/pkg/domain/stack.go +++ b/pkg/domain/stack.go @@ -36,8 +36,8 @@ const ( StackStatus_RUNNING - StackStatus_CLUSTER_BOOTSTRAPING - StackStatus_CLUSTER_BOOTSTRAED + StackStatus_CLUSTER_BOOTSTRAPPING + StackStatus_CLUSTER_BOOTSTRAPPED ) var stackStatus = [...]string{ @@ -52,8 +52,8 @@ var stackStatus = [...]string{ "CLUSTER_INSTALL_ERROR", "CLUSTER_DELETE_ERROR", "RUNNING", - "BOOTSTRAPING", - "BOOTSTRAPED", + "BOOTSTRAPPING", + "BOOTSTRAPPED", } func (m StackStatus) String() string { return stackStatus[(m)] } diff --git a/pkg/httpErrors/errorCode.go b/pkg/httpErrors/errorCode.go index 9c3a4974..ff6b05ae 100644 --- a/pkg/httpErrors/errorCode.go +++ b/pkg/httpErrors/errorCode.go @@ -44,6 +44,9 @@ var errorMap = map[ErrorCode]string{ // AppServeApp "D_NO_ASA": "요청한 앱아이디에 해당하는 어플리케이션이 없습니다.", + // Cluster + "CL_INVALID_BYOH_CLUSTER_ENDPOINT": "BYOH 타입의 클러스터 생성을 위한 cluster endpoint 가 유효하지 않습니다.", + // Stack "S_INVALID_STACK_TEMPLATE": "스택 템플릿을 가져올 수 없습니다.", "S_INVALID_CLOUD_ACCOUNT": "클라우드 계정설정을 가져올 수 없습니다.",