diff --git a/pkg/microservice/aslan/core/common/repository/models/env_svc_version.go b/pkg/microservice/aslan/core/common/repository/models/env_svc_version.go index 81160fa5f2..e9342d83ef 100644 --- a/pkg/microservice/aslan/core/common/repository/models/env_svc_version.go +++ b/pkg/microservice/aslan/core/common/repository/models/env_svc_version.go @@ -30,6 +30,7 @@ type EnvServiceVersion struct { ProductName string `bson:"product_name" json:"product_name"` EnvName string `bson:"env_name" json:"env_name"` Namespace string `bson:"namespace" json:"namespace"` + ClusterName string `bson:"cluster_name,omitempty" json:"cluster_name,omitempty"` Production bool `bson:"production" json:"production"` Revision int64 `bson:"revision" json:"revision"` Operation config.EnvOperation `bson:"operation" json:"operation"` diff --git a/pkg/microservice/aslan/core/common/service/helm/helm.go b/pkg/microservice/aslan/core/common/service/helm/helm.go index 340487b92f..8925648dfa 100644 --- a/pkg/microservice/aslan/core/common/service/helm/helm.go +++ b/pkg/microservice/aslan/core/common/service/helm/helm.go @@ -116,6 +116,12 @@ func CopyAndUploadService(projectName, serviceName, currentChartPath string, cop // Update Service and ServiceDeployStrategy for a single service in environment func UpdateServiceInEnv(product *commonmodels.Product, productSvc *commonmodels.ProductService, user string, operation config.EnvOperation, detail string) error { + return UpdateServiceInEnvWithClusterName(product, productSvc, user, operation, detail, "") +} + +// UpdateServiceInEnvWithClusterName keeps the created env service version snapshot aligned +// with the applied rollback target when cluster name should come from a historical version. +func UpdateServiceInEnvWithClusterName(product *commonmodels.Product, productSvc *commonmodels.ProductService, user string, operation config.EnvOperation, detail, clusterName string) error { session := mongo.Session() defer session.EndSession(context.TODO()) @@ -125,7 +131,7 @@ func UpdateServiceInEnv(product *commonmodels.Product, productSvc *commonmodels. } product.LintServices() - err = commonutil.CreateEnvServiceVersion(product, productSvc, user, operation, detail, session, log.SugaredLogger()) + err = commonutil.CreateEnvServiceVersionWithClusterName(product, productSvc, user, operation, detail, clusterName, session, log.SugaredLogger()) if err != nil { log.Errorf("failed to create helm service version, err: %v", err) } diff --git a/pkg/microservice/aslan/core/common/service/kube/parse.go b/pkg/microservice/aslan/core/common/service/kube/parse.go index 9c71df0edb..f60b34fb1f 100644 --- a/pkg/microservice/aslan/core/common/service/kube/parse.go +++ b/pkg/microservice/aslan/core/common/service/kube/parse.go @@ -30,6 +30,7 @@ const ( envRegexString = `\$EnvName\$` productRegexString = `\$Product\$` serviceRegexString = `\$Service\$` + clusterRegexString = `\$ClusterName\$` ) var ( @@ -41,13 +42,15 @@ var ( productRegex = regexp.MustCompile(productRegexString) envNameRegex = regexp.MustCompile(envRegexString) serviceRegex = regexp.MustCompile(serviceRegexString) + clusterRegex = regexp.MustCompile(clusterRegexString) ) // ParseSysKeys 渲染系统变量键值 -func ParseSysKeys(namespace, envName, productName, serviceName, ori string) string { +func ParseSysKeys(namespace, envName, productName, serviceName, clusterName, ori string) string { ori = envNameRegex.ReplaceAllLiteralString(ori, strings.ToLower(envName)) ori = namespaceRegex.ReplaceAllLiteralString(ori, strings.ToLower(namespace)) ori = productRegex.ReplaceAllLiteralString(ori, strings.ToLower(productName)) ori = serviceRegex.ReplaceAllLiteralString(ori, strings.ToLower(serviceName)) + ori = clusterRegex.ReplaceAllLiteralString(ori, strings.ToLower(clusterName)) return ori } diff --git a/pkg/microservice/aslan/core/common/service/kube/render.go b/pkg/microservice/aslan/core/common/service/kube/render.go index 939c8dadd0..b3b5ad689d 100644 --- a/pkg/microservice/aslan/core/common/service/kube/render.go +++ b/pkg/microservice/aslan/core/common/service/kube/render.go @@ -392,6 +392,11 @@ func FetchCurrentAppliedYaml(option *GeneSvcYamlOption) (string, int, error) { return "", 0, nil } + clusterName, err := resolveCurrentAppliedClusterName(productInfo, option.ServiceName) + if err != nil { + return "", 0, err + } + prodSvcTemplate, err := repository.QueryTemplateService(&commonrepo.ServiceFindOption{ ProductName: option.ProductName, ServiceName: option.ServiceName, @@ -402,7 +407,7 @@ func FetchCurrentAppliedYaml(option *GeneSvcYamlOption) (string, int, error) { } if option.IsImportToDeploy { - importedAllManifests, _, err := FetchImportedAllManifests(productInfo, prodSvcTemplate, curProductSvc.GetServiceRender()) + importedAllManifests, _, err := FetchImportedAllManifests(productInfo, prodSvcTemplate, curProductSvc.GetServiceRender(), clusterName) if err != nil { return "", 0, err } @@ -412,7 +417,7 @@ func FetchCurrentAppliedYaml(option *GeneSvcYamlOption) (string, int, error) { if err != nil { return "", 0, err } - fullRenderedYaml = ParseSysKeys(productInfo.Namespace, productInfo.EnvName, option.ProductName, option.ServiceName, fullRenderedYaml) + fullRenderedYaml = ParseSysKeys(productInfo.Namespace, productInfo.EnvName, option.ProductName, option.ServiceName, clusterName, fullRenderedYaml) mergedContainers := mergeContainers(prodSvcTemplate.Containers, curProductSvc.Containers) fullRenderedYaml, _, err = ReplaceWorkloadImages(fullRenderedYaml, mergedContainers) if err != nil { @@ -425,12 +430,42 @@ func FetchCurrentAppliedYaml(option *GeneSvcYamlOption) (string, int, error) { } } -func FetchImportedAllManifests(envInfo *models.Product, serviceTmp *models.Service, svcRender *template.ServiceRender) (string, []*WorkloadResource, error) { +func resolveCurrentAppliedClusterName(productInfo *models.Product, serviceName string) (string, error) { + + cluster, err := GetCluster(productInfo.ClusterID) + if err != nil { + return "", errors.Wrapf(err, "failed to get cluster name by cluster id %s", productInfo.ClusterID) + } + + // Use the latest stored service version as the source of truth for "current" preview yaml. + latestRevision, err := commonrepo.NewEnvServiceVersionColl().GetLatestRevision( + productInfo.ProductName, productInfo.EnvName, serviceName, false, productInfo.Production) + if err != nil { + return "", errors.Wrapf(err, "failed to find latest env service version for %s/%s/%s", productInfo.ProductName, productInfo.EnvName, serviceName) + } + if latestRevision == 0 { + return cluster.Name, nil + } + + envSvcVersion, err := commonrepo.NewEnvServiceVersionColl().Find( + productInfo.ProductName, productInfo.EnvName, serviceName, false, productInfo.Production, latestRevision) + if err != nil { + return "", errors.Wrapf(err, "failed to find env service version %s/%s/%s revision %d", productInfo.ProductName, productInfo.EnvName, serviceName, latestRevision) + } + // Older records may not have cluster_name populated, so keep a safe fallback. + if envSvcVersion.ClusterName != "" { + return envSvcVersion.ClusterName, nil + } + + return cluster.Name, nil +} + +func FetchImportedAllManifests(envInfo *models.Product, serviceTmp *models.Service, svcRender *template.ServiceRender, clusterName string) (string, []*WorkloadResource, error) { fullRenderedYaml, err := RenderServiceYaml(serviceTmp.Yaml, envInfo.ProductName, serviceTmp.ServiceName, svcRender) if err != nil { return "", nil, err } - fullRenderedYaml = ParseSysKeys(envInfo.Namespace, envInfo.EnvName, envInfo.ProductName, serviceTmp.ServiceName, fullRenderedYaml) + fullRenderedYaml = ParseSysKeys(envInfo.Namespace, envInfo.EnvName, envInfo.ProductName, serviceTmp.ServiceName, clusterName, fullRenderedYaml) manifests := util.SplitManifestsOrdered(fullRenderedYaml) @@ -686,7 +721,12 @@ func FetchImportedManifests(option *GeneSvcYamlOption, productInfo *models.Produ if err != nil { return "", nil, err } - fullRenderedYaml = ParseSysKeys(productInfo.Namespace, productInfo.EnvName, option.ProductName, option.ServiceName, fullRenderedYaml) + // get cluster name by id + cluster, err := GetCluster(productInfo.ClusterID) + if err != nil { + return "", nil, err + } + fullRenderedYaml = ParseSysKeys(productInfo.Namespace, productInfo.EnvName, option.ProductName, option.ServiceName, cluster.Name, fullRenderedYaml) manifests := releaseutil.SplitManifests(fullRenderedYaml) @@ -770,6 +810,12 @@ func GenerateRenderedYaml(option *GeneSvcYamlOption) (string, int, []*WorkloadRe return "", 0, nil, errors.Wrapf(err, "failed to find product %s", option.ProductName) } + // get cluster name by id + cluster, err := GetCluster(productInfo.ClusterID) + if err != nil { + return "", 0, nil, err + } + curProductSvc := productInfo.GetServiceMap()[option.ServiceName] // nothing to render when trying to uninstall a service which is not deployed @@ -831,7 +877,7 @@ func GenerateRenderedYaml(option *GeneSvcYamlOption) (string, int, []*WorkloadRe if renderErr != nil { return "", 0, nil, fmt.Errorf("failed to render current service yaml: %v", renderErr) } - currentRenderedYaml = ParseSysKeys(productInfo.Namespace, productInfo.EnvName, option.ProductName, option.ServiceName, currentRenderedYaml) + currentRenderedYaml = ParseSysKeys(productInfo.Namespace, productInfo.EnvName, option.ProductName, option.ServiceName, cluster.Name, currentRenderedYaml) currentBaseReplicaMap, err = ExtractWorkloadReplicas(currentRenderedYaml) if err != nil { return "", 0, nil, fmt.Errorf("failed to extract workload replicas: %v", err) @@ -860,7 +906,7 @@ func GenerateRenderedYaml(option *GeneSvcYamlOption) (string, int, []*WorkloadRe if err != nil { return "", 0, nil, fmt.Errorf("failed to render service yaml: %v", err) } - fullRenderedYaml = ParseSysKeys(productInfo.Namespace, productInfo.EnvName, option.ProductName, option.ServiceName, fullRenderedYaml) + fullRenderedYaml = ParseSysKeys(productInfo.Namespace, productInfo.EnvName, option.ProductName, option.ServiceName, cluster.Name, fullRenderedYaml) // service may not be deployed in environment, we need to extract containers again, since image related variables may be changed latestSvcTemplate.KubeYamls = util.SplitYaml(fullRenderedYaml) @@ -971,20 +1017,33 @@ func RenderEnvService(prod *commonmodels.Product, serviceRender *template.Servic return "", err } - return RenderEnvServiceWithTempl(prod, serviceRender, service, svcTmpl) + // get cluster name by cluster id + cluster, err := GetCluster(prod.ClusterID) + if err != nil { + return "", err + } + return RenderEnvServiceWithTempl(prod, serviceRender, service, svcTmpl, cluster.Name) } -func RenderEnvServiceWithTempl(prod *commonmodels.Product, serviceRender *template.ServiceRender, service *commonmodels.ProductService, svcTmpl *commonmodels.Service) (yaml string, err error) { +func RenderEnvServiceWithTempl(prod *commonmodels.Product, serviceRender *template.ServiceRender, service *commonmodels.ProductService, svcTmpl *commonmodels.Service, clusterName string) (yaml string, err error) { // Note only the keys in TemplateService.ServiceVar can work parsedYaml, err := RenderServiceYaml(svcTmpl.Yaml, prod.ProductName, svcTmpl.ServiceName, serviceRender) if err != nil { log.Errorf("failed to render service yaml, err: %s", err) return "", err } - parsedYaml = ParseSysKeys(prod.Namespace, prod.EnvName, prod.ProductName, service.ServiceName, parsedYaml) + parsedYaml = ParseSysKeys(prod.Namespace, prod.EnvName, prod.ProductName, service.ServiceName, clusterName, parsedYaml) parsedYaml, _, err = ReplaceWorkloadImages(parsedYaml, service.Containers) if err != nil { return "", err } return ApplyReplicaOverrides(parsedYaml, service.WorkLoads) } + +func GetCluster(clusterID string) (*commonmodels.K8SCluster, error) { + cluster, err := commonrepo.NewK8SClusterColl().FindByID(clusterID) + if err != nil { + return nil, errors.Wrapf(err, "failed to find cluster by id %s", clusterID) + } + return cluster, nil +} diff --git a/pkg/microservice/aslan/core/common/service/service.go b/pkg/microservice/aslan/core/common/service/service.go index 207da6640e..73e0da3faa 100644 --- a/pkg/microservice/aslan/core/common/service/service.go +++ b/pkg/microservice/aslan/core/common/service/service.go @@ -1361,6 +1361,12 @@ func GetServiceImpl(serviceName string, serviceTmpl *commonmodels.Service, workL err = nil namespace := env.Namespace + // get cluster name by id + cluster, err := kube.GetCluster(env.ClusterID) + if err != nil { + log.Errorf("", err) + return nil, err + } switch env.Source { case setting.SourceFromHelm: k8sServices, _ := getter.ListServicesWithCache(nil, inf) @@ -1421,8 +1427,9 @@ func GetServiceImpl(serviceName string, serviceTmpl *commonmodels.Service, workL log.Errorf("failed to render service yaml, err: %s", err) return nil, err } - // 渲染系统变量键值 - parsedYaml = kube.ParseSysKeys(namespace, envName, productName, service.ServiceName, parsedYaml) + + // render system kv value + parsedYaml = kube.ParseSysKeys(namespace, envName, productName, service.ServiceName, cluster.Name, parsedYaml) manifests := releaseutil.SplitManifests(parsedYaml) for _, item := range manifests { diff --git a/pkg/microservice/aslan/core/common/service/version.go b/pkg/microservice/aslan/core/common/service/version.go index 2829d42600..a66054e26f 100644 --- a/pkg/microservice/aslan/core/common/service/version.go +++ b/pkg/microservice/aslan/core/common/service/version.go @@ -139,14 +139,42 @@ func GetEnvServiceVersionYaml(ctx *internalhandler.Context, projectName, envName return resp, nil } + // for get clusterID + env, err := mongodb.NewProductColl().Find(&mongodb.ProductFindOptions{ + Name: projectName, + EnvName: envName, + Production: &isProduction, + }) + if err != nil { + return resp, fmt.Errorf("failed to find %s/%s env, isProduction %v, error: %v", projectName, envName, isProduction, err) + } + if envSvcRevision.Service.Type == setting.K8SDeployType { fakeEnv := &commonmodels.Product{ ProductName: envSvcRevision.ProductName, EnvName: envSvcRevision.EnvName, + ClusterID: env.ClusterID, Namespace: envSvcRevision.Namespace, Production: envSvcRevision.Production, } - parsedYaml, err := kube.RenderEnvService(fakeEnv, envSvcRevision.Service.GetServiceRender(), envSvcRevision.Service) + clusterName := envSvcRevision.ClusterName + if clusterName == "" { + cluster, err := kube.GetCluster(env.ClusterID) + if err != nil { + return resp, err + } + clusterName = cluster.Name + } + svcTmpl, err := repository.QueryTemplateService(&commonrepo.ServiceFindOption{ + ServiceName: envSvcRevision.Service.ServiceName, + ProductName: envSvcRevision.ProductName, + Type: envSvcRevision.Service.Type, + Revision: envSvcRevision.Service.Revision, + }, envSvcRevision.Production) + if err != nil { + return resp, fmt.Errorf("failed to find %s/%s/%d service template, isProduction %v, error: %v", envSvcRevision.ProductName, envSvcRevision.Service.ServiceName, envSvcRevision.Service.Revision, envSvcRevision.Production, err) + } + parsedYaml, err := kube.RenderEnvServiceWithTempl(fakeEnv, envSvcRevision.Service.GetServiceRender(), envSvcRevision.Service, svcTmpl, clusterName) if err != nil { err = fmt.Errorf("Failed to render env Service %s, error: %v", envSvcRevision.Service.ServiceName, err) return resp, err @@ -396,7 +424,8 @@ func RollbackEnvServiceVersion(ctx *internalhandler.Context, projectName, envNam VariableKVs: envSvcVersion.Service.GetServiceRender().OverrideYaml.RenderVariableKVs, Containers: envSvcVersion.Service.Containers, } - _, _, resources, err := kube.GenerateRenderedYaml(option) + var resources []*kube.WorkloadResource + _, _, resources, err = kube.GenerateRenderedYaml(option) if err != nil { return nil, e.ErrRollbackEnvServiceVersion.AddErr(fmt.Errorf("failed to generate service yaml, error: %v", err)) } @@ -419,10 +448,28 @@ func RollbackEnvServiceVersion(ctx *internalhandler.Context, projectName, envNam fakeEnv := &commonmodels.Product{ ProductName: envSvcVersion.ProductName, EnvName: envSvcVersion.EnvName, + ClusterID: env.ClusterID, Namespace: envSvcVersion.Namespace, Production: envSvcVersion.Production, } - parsedYaml, err := kube.RenderEnvService(fakeEnv, envSvcVersion.Service.GetServiceRender(), envSvcVersion.Service) + clusterName := envSvcVersion.ClusterName + if clusterName == "" { + cluster, err := kube.GetCluster(env.ClusterID) + if err != nil { + return nil, e.ErrRollbackEnvServiceVersion.AddErr(err) + } + clusterName = cluster.Name + } + svcTmpl, err := repository.QueryTemplateService(&commonrepo.ServiceFindOption{ + ServiceName: envSvcVersion.Service.ServiceName, + ProductName: envSvcVersion.ProductName, + Type: envSvcVersion.Service.Type, + Revision: envSvcVersion.Service.Revision, + }, envSvcVersion.Production) + if err != nil { + return nil, e.ErrRollbackEnvServiceVersion.AddErr(fmt.Errorf("failed to find %s/%s/%d service template, isProduction %v, error: %v", envSvcVersion.ProductName, envSvcVersion.Service.ServiceName, envSvcVersion.Service.Revision, envSvcVersion.Production, err)) + } + parsedYaml, err := kube.RenderEnvServiceWithTempl(fakeEnv, envSvcVersion.Service.GetServiceRender(), envSvcVersion.Service, svcTmpl, clusterName) if err != nil { err = fmt.Errorf("Failed to render env %s, service %s, revision %d, error: %v", envSvcVersion.EnvName, envSvcVersion.Service.ServiceName, envSvcVersion.Service.Revision, err) return nil, e.ErrRollbackEnvServiceVersion.AddErr(err) @@ -502,7 +549,7 @@ func RollbackEnvServiceVersion(ctx *internalhandler.Context, projectName, envNam } env.Services[groupIndex][svcIndex] = envSvcVersion.Service - err = helmservice.UpdateServiceInEnv(env, envSvcVersion.Service, ctx.UserName, config.EnvOperationRollback, detail) + err = helmservice.UpdateServiceInEnvWithClusterName(env, envSvcVersion.Service, ctx.UserName, config.EnvOperationRollback, detail, envSvcVersion.ClusterName) if err != nil { return nil, e.ErrRollbackEnvServiceVersion.AddErr(fmt.Errorf("failed to update service %s in env %s/%s, isProudction %v", envSvcVersion.Service.ServiceName, envSvcVersion.ProductName, envSvcVersion.EnvName, envSvcVersion.Production)) } diff --git a/pkg/microservice/aslan/core/common/util/version.go b/pkg/microservice/aslan/core/common/util/version.go index 206ffc15d1..eeda77b635 100644 --- a/pkg/microservice/aslan/core/common/util/version.go +++ b/pkg/microservice/aslan/core/common/util/version.go @@ -22,6 +22,10 @@ func GenerateEnvServiceNextRevision(projectName, envName, serviceName string, is } func CreateEnvServiceVersion(env *models.Product, prodSvc *models.ProductService, createBy string, operation config.EnvOperation, detail string, session mongo.Session, log *zap.SugaredLogger) error { + return CreateEnvServiceVersionWithClusterName(env, prodSvc, createBy, operation, detail, "", session, log) +} + +func CreateEnvServiceVersionWithClusterName(env *models.Product, prodSvc *models.ProductService, createBy string, operation config.EnvOperation, detail, clusterName string, session mongo.Session, log *zap.SugaredLogger) error { name := prodSvc.ServiceName isHelmChart := !prodSvc.FromZadig() if isHelmChart { @@ -50,11 +54,21 @@ func CreateEnvServiceVersion(env *models.Product, prodSvc *models.ProductService return fmt.Errorf("failed to find template product %s, error: %v", env.ProductName, err) } + var cluster *models.K8SCluster + if clusterName == "" && env.ClusterID != "" { + cluster, err = commonrepo.NewK8SClusterColl().FindByID(env.ClusterID) + if err != nil { + return fmt.Errorf("failed to find cluster by id %s, error: %v", env.ClusterID, err) + } + clusterName = cluster.Name + } + svcVersionColl := mongodb.NewEnvServiceVersionCollWithSession(session) version := &models.EnvServiceVersion{ ProductName: env.ProductName, EnvName: env.EnvName, Namespace: env.Namespace, + ClusterName: clusterName, Production: env.Production, Revision: revision, Service: prodSvc, diff --git a/pkg/microservice/aslan/core/environment/service/configmap.go b/pkg/microservice/aslan/core/environment/service/configmap.go index 2db490da57..1fd3bc66ba 100644 --- a/pkg/microservice/aslan/core/environment/service/configmap.go +++ b/pkg/microservice/aslan/core/environment/service/configmap.go @@ -204,6 +204,12 @@ func UpdateConfigMap(args *models.CreateUpdateCommonEnvCfgArgs, userName string, return e.ErrUpdateConfigMap.AddErr(err) } + // get clusterName by id + cluster, err := kube.GetCluster(product.ClusterID) + if err != nil { + return e.ErrUpdateConfigMap.AddErr(err) + } + namespace := product.Namespace for key, value := range cm.Data { @@ -211,7 +217,7 @@ func UpdateConfigMap(args *models.CreateUpdateCommonEnvCfgArgs, userName string, //for _, kv := range renderSet.KVs { // value = strings.Replace(value, kv.Alias, kv.Value, -1) //} - value = kube.ParseSysKeys(product.Namespace, product.EnvName, product.ProductName, args.ServiceName, value) + value = kube.ParseSysKeys(product.Namespace, product.EnvName, product.ProductName, args.ServiceName, cluster.Name, value) cm.Data[key] = value } diff --git a/pkg/microservice/aslan/core/environment/service/environment.go b/pkg/microservice/aslan/core/environment/service/environment.go index 850d55640f..fd153777c7 100644 --- a/pkg/microservice/aslan/core/environment/service/environment.go +++ b/pkg/microservice/aslan/core/environment/service/environment.go @@ -3034,8 +3034,20 @@ func upsertService(env *commonmodels.Product, newService *commonmodels.ProductSe func getOldSvcYaml(env *commonmodels.Product, oldService *commonmodels.ProductService, log *zap.SugaredLogger) (string, error) { + // Use the current applied yaml as the update baseline so resource patching stays + // consistent with preview/export behavior after cluster name changes. + parsedYaml, _, err := kube.FetchCurrentAppliedYaml(&kube.GeneSvcYamlOption{ + ProductName: env.ProductName, + EnvName: env.EnvName, + ServiceName: oldService.ServiceName, + IsImportToDeploy: env.ServiceDeployStrategy[oldService.ServiceName] == setting.ServiceDeployStrategyImport, + }) + if err == nil { + return parsedYaml, nil + } + log.Warnf("failed to fetch current applied yaml for %s/%s/%s, fallback to rendered service yaml, err: %v", env.ProductName, env.EnvName, oldService.ServiceName, err) - parsedYaml, err := kube.RenderEnvService(env, oldService.GetServiceRender(), oldService) + parsedYaml, err = kube.RenderEnvService(env, oldService.GetServiceRender(), oldService) if err != nil { log.Errorf("failed to find old service revision %s/%d", oldService.ServiceName, oldService.Revision) return "", err @@ -4310,6 +4322,13 @@ func EnvSleep(productName, envName string, isEnable, isProduction bool, log *zap log.Error(err) return e.ErrEnvSleep.AddErr(err) } + cluster, err := kube.GetCluster(prod.ClusterID) + if err != nil { + wrapErr := fmt.Errorf("failed to get cluster for cluster %s, err: %v", prod.ClusterID, err) + log.Error(wrapErr) + return e.ErrEnvSleep.AddErr(wrapErr) + } + if prod.Production != isProduction { err = fmt.Errorf("Insufficient permissions: %s/%s, is production %v", productName, envName, prod.Production) log.Error(err) @@ -4404,7 +4423,7 @@ func EnvSleep(productName, envName string, isEnable, isProduction bool, log *zap return e.ErrEnvSleep.AddErr(wrapErr) } - parsedYaml, err := kube.RenderEnvServiceWithTempl(prod, prodSvc.GetServiceRender(), prodSvc, svc) + parsedYaml, err := kube.RenderEnvServiceWithTempl(prod, prodSvc.GetServiceRender(), prodSvc, svc, cluster.Name) if err != nil { return e.ErrEnvSleep.AddErr(fmt.Errorf("failed to render service %s, err: %s", svc.ServiceName, err)) } diff --git a/pkg/microservice/aslan/core/environment/service/environment_creation.go b/pkg/microservice/aslan/core/environment/service/environment_creation.go index 5f3286a05e..92df6ed1b6 100644 --- a/pkg/microservice/aslan/core/environment/service/environment_creation.go +++ b/pkg/microservice/aslan/core/environment/service/environment_creation.go @@ -302,6 +302,7 @@ func prepareK8sProductCreation(templateProduct *templatemodels.Product, productO } func createSingleYamlProduct(templateProduct *templatemodels.Product, requestID, userName string, arg *CreateSingleProductArg, log *zap.SugaredLogger) error { + productObj := &commonmodels.Product{ ProductName: templateProduct.ProductName, Revision: templateProduct.Revision, diff --git a/pkg/microservice/aslan/core/environment/service/kube.go b/pkg/microservice/aslan/core/environment/service/kube.go index 78d7ffcbaa..40e208605a 100644 --- a/pkg/microservice/aslan/core/environment/service/kube.go +++ b/pkg/microservice/aslan/core/environment/service/kube.go @@ -934,6 +934,10 @@ func getWorkloadDetail(ns, resType, name string, kc client.Client, cs *kubernete func GetResourceDeployStatus(productName string, request *K8sDeployStatusCheckRequest, production bool, log *zap.SugaredLogger) ([]*ServiceDeployStatus, error) { clusterID, namespace := request.ClusterID, request.Namespace + cluster, err := kube.GetCluster(clusterID) + if err != nil { + return nil, e.ErrGetResourceDeployInfo.AddErr(fmt.Errorf("failed to get cluster by id: %s, err: %s", clusterID, err)) + } svcSet := sets.NewString() for _, svc := range request.Services { @@ -983,7 +987,7 @@ func GetResourceDeployStatus(productName string, request *K8sDeployStatusCheckRe if err != nil { return nil, e.ErrGetResourceDeployInfo.AddErr(fmt.Errorf("failed to render service yaml, serviceName:%s, err: %w", svc.ServiceName, err)) } - rederedYaml = kube.ParseSysKeys(request.Namespace, request.EnvName, productName, svc.ServiceName, rederedYaml) + rederedYaml = kube.ParseSysKeys(request.Namespace, request.EnvName, productName, svc.ServiceName, cluster.Name, rederedYaml) manifests := releaseutil.SplitManifests(rederedYaml) resources := make([]*ResourceDeployStatus, 0) diff --git a/pkg/microservice/aslan/core/environment/service/replica_sync.go b/pkg/microservice/aslan/core/environment/service/replica_sync.go index 19c41c3784..f154de52eb 100644 --- a/pkg/microservice/aslan/core/environment/service/replica_sync.go +++ b/pkg/microservice/aslan/core/environment/service/replica_sync.go @@ -96,7 +96,14 @@ func renderServiceWithOverrides(prod *commonmodels.Product, service *commonmodel return "", fmt.Errorf("service is nil") } serviceCopy.WorkLoads = cloneWorkLoads(overrides) - return kube.RenderEnvServiceWithTempl(prod, serviceCopy.GetServiceRender(), serviceCopy, tmpl) + + // get cluster + cluster, err := kube.GetCluster(prod.ClusterID) + if err != nil { + return "", fmt.Errorf("failed to get cluster for cluster %s: %w", prod.ClusterID, err) + } + + return kube.RenderEnvServiceWithTempl(prod, serviceCopy.GetServiceRender(), serviceCopy, tmpl, cluster.Name) } func serviceReplicaStateChanged(currentSvc, candidateSvc *commonmodels.ProductService) bool { diff --git a/pkg/microservice/aslan/core/environment/service/service.go b/pkg/microservice/aslan/core/environment/service/service.go index 8e40402b14..ddba143f78 100644 --- a/pkg/microservice/aslan/core/environment/service/service.go +++ b/pkg/microservice/aslan/core/environment/service/service.go @@ -179,6 +179,10 @@ func GetService(envName, productName, serviceName string, production bool, workL func GetServiceWorkloads(svcTmpl *commonmodels.Service, env *commonmodels.Product, inf informers.SharedInformerFactory, log *zap.SugaredLogger) ([]*commonservice.Workload, error) { ret := make([]*commonservice.Workload, 0) envName, productName, namespace := env.EnvName, env.ProductName, env.Namespace + cluster, err := kube.GetCluster(env.ClusterID) + if err != nil { + return nil, e.ErrGetService.AddErr(fmt.Errorf("failed to get cluster for cluster %s: %w", env.ClusterID, err)) + } svcRender := env.GetSvcRender(svcTmpl.ServiceName) parsedYaml, err := kube.RenderServiceYaml(svcTmpl.Yaml, productName, svcTmpl.ServiceName, svcRender) @@ -186,7 +190,7 @@ func GetServiceWorkloads(svcTmpl *commonmodels.Service, env *commonmodels.Produc log.Errorf("failed to render service yaml, err: %s", err) return nil, err } - parsedYaml = kube.ParseSysKeys(namespace, envName, productName, svcTmpl.ServiceName, parsedYaml) + parsedYaml = kube.ParseSysKeys(namespace, envName, productName, svcTmpl.ServiceName, cluster.Name, parsedYaml) manifests := releaseutil.SplitManifests(parsedYaml) for _, item := range manifests { diff --git a/pkg/microservice/aslan/core/service/service/environment.go b/pkg/microservice/aslan/core/service/service/environment.go index 576bb3005a..c818f8020c 100644 --- a/pkg/microservice/aslan/core/service/service/environment.go +++ b/pkg/microservice/aslan/core/service/service/environment.go @@ -44,6 +44,7 @@ type DeployableEnv struct { Alias string `json:"alias"` Namespace string `json:"namespace"` ClusterID string `json:"cluster_id"` + ClusterName string `json:"cluster_name"` Services []*types.ServiceWithVariable `json:"services"` GlobalVariableKVs []*commontypes.GlobalVariableKV `json:"global_variable_kvs"` } @@ -84,6 +85,32 @@ func GetDeployableEnvs(svcName, projectName string, production bool) (*Deployabl return resp, nil } +func getClusterNameMap() (map[string]string, error) { + clusters, err := commonrepo.NewK8SClusterColl().List(&commonrepo.ClusterListOpts{}) + if err != nil { + return nil, err + } + + clusterNameMap := make(map[string]string, len(clusters)) + for _, cluster := range clusters { + clusterNameMap[cluster.ID.Hex()] = cluster.Name + } + + return clusterNameMap, nil +} + +func newDeployableEnv(templateProduct *template.Product, env *commonmodels.Product, clusterNameMap map[string]string) *DeployableEnv { + return &DeployableEnv{ + EnvName: env.EnvName, + Alias: env.Alias, + Namespace: env.Namespace, + ClusterID: env.ClusterID, + ClusterName: clusterNameMap[env.ClusterID], + GlobalVariableKVs: env.GlobalVariables, + Services: getServiceVariables(templateProduct, env), + } +} + type GetKubeWorkloadsResp struct { WorkloadsMap map[string][]string `json:"workloads_map"` } @@ -356,20 +383,14 @@ func getAllGeneralEnvs(templateProduct *template.Product, production bool) ([]*D return nil, err } - ret := make([]*DeployableEnv, len(envs)) + clusterNameMap, err := getClusterNameMap() + if err != nil { + return nil, err + } - envNames := make([]string, len(envs)) + ret := make([]*DeployableEnv, len(envs)) for i, env := range envs { - - envNames[i] = env.EnvName - ret[i] = &DeployableEnv{ - EnvName: env.EnvName, - Alias: env.Alias, - Namespace: env.Namespace, - ClusterID: env.ClusterID, - GlobalVariableKVs: env.GlobalVariables, - Services: getServiceVariables(templateProduct, env), - } + ret[i] = newDeployableEnv(templateProduct, env, clusterNameMap) } return ret, nil @@ -388,23 +409,20 @@ func getDeployableShareEnvs(svcName string, templateProduct *template.Product, p return nil, err } + clusterNameMap, err := getClusterNameMap() + if err != nil { + return nil, err + } + ret := make([]*DeployableEnv, 0) for _, baseEnv := range baseEnvs { - - ret = append(ret, &DeployableEnv{ - EnvName: baseEnv.EnvName, - Alias: baseEnv.Alias, - Namespace: baseEnv.Namespace, - ClusterID: baseEnv.ClusterID, - GlobalVariableKVs: baseEnv.GlobalVariables, - Services: getServiceVariables(templateProduct, baseEnv), - }) + ret = append(ret, newDeployableEnv(templateProduct, baseEnv, clusterNameMap)) if !hasSvcInEnv(svcName, baseEnv) { continue } - subEnvs, err := getSubEnvs(baseEnv.EnvName, templateProduct) + subEnvs, err := getSubEnvs(baseEnv.EnvName, templateProduct, clusterNameMap) if err != nil { return nil, err } @@ -424,23 +442,20 @@ func getDeployableShareEnvs(svcName string, templateProduct *template.Product, p return nil, err } + clusterNameMap, err := getClusterNameMap() + if err != nil { + return nil, err + } + ret := make([]*DeployableEnv, 0) for _, baseEnv := range baseEnvs { - - ret = append(ret, &DeployableEnv{ - EnvName: baseEnv.EnvName, - Alias: baseEnv.Alias, - Namespace: baseEnv.Namespace, - ClusterID: baseEnv.ClusterID, - GlobalVariableKVs: baseEnv.GlobalVariables, - Services: getServiceVariables(templateProduct, baseEnv), - }) + ret = append(ret, newDeployableEnv(templateProduct, baseEnv, clusterNameMap)) if !hasSvcInEnv(svcName, baseEnv) { continue } - grayEnvs, err := getGrayEnvs(baseEnv.EnvName, baseEnv.ClusterID, templateProduct) + grayEnvs, err := getGrayEnvs(baseEnv.EnvName, baseEnv.ClusterID, templateProduct, clusterNameMap) if err != nil { return nil, err } @@ -452,7 +467,7 @@ func getDeployableShareEnvs(svcName string, templateProduct *template.Product, p } } -func getSubEnvs(baseEnvName string, templateProduct *template.Product) ([]*DeployableEnv, error) { +func getSubEnvs(baseEnvName string, templateProduct *template.Product, clusterNameMap map[string]string) ([]*DeployableEnv, error) { projectName := templateProduct.ProjectName envs, err := commonrepo.NewProductColl().List(&commonrepo.ProductListOptions{ Name: projectName, @@ -467,20 +482,13 @@ func getSubEnvs(baseEnvName string, templateProduct *template.Product) ([]*Deplo ret := make([]*DeployableEnv, len(envs)) for i, env := range envs { - ret[i] = &DeployableEnv{ - EnvName: env.EnvName, - Alias: env.Alias, - Namespace: env.Namespace, - ClusterID: env.ClusterID, - GlobalVariableKVs: env.GlobalVariables, - Services: getServiceVariables(templateProduct, env), - } + ret[i] = newDeployableEnv(templateProduct, env, clusterNameMap) } return ret, nil } -func getGrayEnvs(baseEnvName, clusterID string, templateProduct *template.Product) ([]*DeployableEnv, error) { +func getGrayEnvs(baseEnvName, clusterID string, templateProduct *template.Product, clusterNameMap map[string]string) ([]*DeployableEnv, error) { projectName := templateProduct.ProjectName envs, err := commonutil.FetchGrayEnvs(context.TODO(), projectName, clusterID, baseEnvName) if err != nil { @@ -489,14 +497,7 @@ func getGrayEnvs(baseEnvName, clusterID string, templateProduct *template.Produc ret := make([]*DeployableEnv, len(envs)) for i, env := range envs { - ret[i] = &DeployableEnv{ - EnvName: env.EnvName, - Alias: env.Alias, - Namespace: env.Namespace, - ClusterID: env.ClusterID, - GlobalVariableKVs: env.GlobalVariables, - Services: getServiceVariables(templateProduct, env), - } + ret[i] = newDeployableEnv(templateProduct, env, clusterNameMap) } return ret, nil diff --git a/pkg/microservice/aslan/core/service/service/service.go b/pkg/microservice/aslan/core/service/service/service.go index a0dd57faf3..99894dafe2 100644 --- a/pkg/microservice/aslan/core/service/service/service.go +++ b/pkg/microservice/aslan/core/service/service/service.go @@ -181,6 +181,9 @@ func GetServiceOption(args *commonmodels.Service, log *zap.SugaredLogger) (*Serv { Key: "$EnvName$", Value: ""}, + { + Key: "$ClusterName$", + Value: ""}, } serviceOption.VariableYaml = args.VariableYaml