Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand Down
8 changes: 7 additions & 1 deletion pkg/microservice/aslan/core/common/service/helm/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -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())

Expand All @@ -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)
}
Expand Down
5 changes: 4 additions & 1 deletion pkg/microservice/aslan/core/common/service/kube/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const (
envRegexString = `\$EnvName\$`
productRegexString = `\$Product\$`
serviceRegexString = `\$Service\$`
clusterRegexString = `\$ClusterName\$`
)

var (
Expand All @@ -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
}
79 changes: 69 additions & 10 deletions pkg/microservice/aslan/core/common/service/kube/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
}
Expand All @@ -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 {
Expand All @@ -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)

Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
}
11 changes: 9 additions & 2 deletions pkg/microservice/aslan/core/common/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 {
Expand Down
55 changes: 51 additions & 4 deletions pkg/microservice/aslan/core/common/service/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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))
}
Expand All @@ -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)
Expand Down Expand Up @@ -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))
}
Expand Down
14 changes: 14 additions & 0 deletions pkg/microservice/aslan/core/common/util/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down
8 changes: 7 additions & 1 deletion pkg/microservice/aslan/core/environment/service/configmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,14 +204,20 @@ 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 {
// TODO need fill variable yaml?
//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
}

Expand Down
Loading
Loading