From 2bdc927e3e9dfd25cb3cff2d1bccdf875283db30 Mon Sep 17 00:00:00 2001 From: allenshen Date: Tue, 16 Nov 2021 22:24:04 +0800 Subject: [PATCH 001/134] update get chart version api logic Signed-off-by: allenshen --- pkg/microservice/aslan/config/config.go | 4 + .../repository/models/delivery_version.go | 1 + .../core/environment/handler/helm_release.go | 40 +++ .../aslan/core/environment/handler/router.go | 3 + .../aslan/core/environment/service/helm.go | 263 ++++++++++++++++++ .../aslan/core/service/handler/helm.go | 18 +- .../aslan/core/service/service/helm.go | 66 ++++- pkg/tool/errors/http_errors.go | 6 + 8 files changed, 387 insertions(+), 14 deletions(-) create mode 100644 pkg/microservice/aslan/core/environment/handler/helm_release.go create mode 100644 pkg/microservice/aslan/core/environment/service/helm.go diff --git a/pkg/microservice/aslan/config/config.go b/pkg/microservice/aslan/config/config.go index 02da935da..22fd8bfb6 100644 --- a/pkg/microservice/aslan/config/config.go +++ b/pkg/microservice/aslan/config/config.go @@ -230,6 +230,10 @@ func LocalServicePathWithRevision(project, service string, revision int64) strin return configbase.LocalServicePathWithRevision(project, service, fmt.Sprintf("%d", revision)) } +func LocalDeliveryChartPathWithRevision(project, service string, revision int64) string { + return configbase.LocalServicePathWithRevision(project, service, fmt.Sprintf("delivery/%d", revision)) +} + func ServiceNameWithRevision(serviceName string, revision int64) string { return fmt.Sprintf("%s-%d", serviceName, revision) } diff --git a/pkg/microservice/aslan/core/common/repository/models/delivery_version.go b/pkg/microservice/aslan/core/common/repository/models/delivery_version.go index 459d7f96f..7efeda7d4 100644 --- a/pkg/microservice/aslan/core/common/repository/models/delivery_version.go +++ b/pkg/microservice/aslan/core/common/repository/models/delivery_version.go @@ -25,6 +25,7 @@ type DeliveryVersion struct { Version string `bson:"version" json:"version"` ProductName string `bson:"product_name" json:"productName"` WorkflowName string `bson:"workflow_name" json:"workflowName"` + Type string `bson:"type" json:"type"` TaskID int `bson:"task_id" json:"taskId"` Desc string `bson:"desc" json:"desc"` Labels []string `bson:"labels" json:"labels"` diff --git a/pkg/microservice/aslan/core/environment/handler/helm_release.go b/pkg/microservice/aslan/core/environment/handler/helm_release.go new file mode 100644 index 000000000..d93e7a5e7 --- /dev/null +++ b/pkg/microservice/aslan/core/environment/handler/helm_release.go @@ -0,0 +1,40 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package handler + +import ( + "github.com/gin-gonic/gin" + "github.com/koderover/zadig/pkg/microservice/aslan/core/environment/service" + internalhandler "github.com/koderover/zadig/pkg/shared/handler" +) + +func ListReleases(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + envName := c.Query("envName") + productName := c.Param("productName") + ctx.Resp, ctx.Err = service.ListReleases(productName, envName, ctx.Logger) +} + +func GetChartInfos(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + envName := c.Query("envName") + servicesName := c.Query("serviceName") + productName := c.Param("productName") + ctx.Resp, ctx.Err = service.GetChartInfos(productName, envName, servicesName, ctx.Logger) +} diff --git a/pkg/microservice/aslan/core/environment/handler/router.go b/pkg/microservice/aslan/core/environment/handler/router.go index bc13c84ca..4b7b8529f 100644 --- a/pkg/microservice/aslan/core/environment/handler/router.go +++ b/pkg/microservice/aslan/core/environment/handler/router.go @@ -121,6 +121,9 @@ func (*Router) Inject(router *gin.RouterGroup) { environments.GET("/:productName/groups", ListGroups) environments.GET("/:productName/workloads", ListWorkloadsInEnv) + environments.GET("/:productName/helm/releases", ListReleases) + environments.GET("/:productName/helm/charts", GetChartInfos) + environments.GET("/:productName/services/:serviceName", GetService) environments.PUT("/:productName/services/:serviceName/:serviceType", gin2.UpdateOperationLogStatus, UpdateService) environments.POST("/:productName/services/:serviceName/restart", gin2.UpdateOperationLogStatus, RestartService) diff --git a/pkg/microservice/aslan/core/environment/service/helm.go b/pkg/microservice/aslan/core/environment/service/helm.go new file mode 100644 index 000000000..64fe4fb24 --- /dev/null +++ b/pkg/microservice/aslan/core/environment/service/helm.go @@ -0,0 +1,263 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package service + +import ( + "fmt" + "os" + "path/filepath" + "strings" + "sync" + + "github.com/otiai10/copy" + + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" + + "github.com/koderover/zadig/pkg/tool/log" + + "github.com/koderover/zadig/pkg/types" + + "github.com/hashicorp/go-multierror" + "github.com/koderover/zadig/pkg/setting" + "github.com/koderover/zadig/pkg/util" + + helmtool "github.com/koderover/zadig/pkg/tool/helmclient" + + "github.com/koderover/zadig/pkg/microservice/aslan/config" + commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" + commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" + e "github.com/koderover/zadig/pkg/tool/errors" + "go.uber.org/zap" +) + +type HelmReleaseResp struct { + ReleaseName string `json:"releaseName"` + ServiceName string `json:"serviceName"` + Revision int `json:"revision"` + Chart string `json:"chart"` + AppVersion string `json:"appVersion"` +} + +type ChartInfo struct { + ServiceName string `json:"serviceName"` + Revision int64 `json:"revision"` +} + +type HelmChartsResp struct { + ChartInfos []*ChartInfo `json:"chartInfos"` + FileInfos []*types.FileInfo `json:"fileInfos"` +} + +func ListReleases(productName, envName string, log *zap.SugaredLogger) ([]*HelmReleaseResp, error) { + opt := &commonrepo.ProductFindOptions{Name: productName, EnvName: envName} + prod, err := commonrepo.NewProductColl().Find(opt) + if err != nil { + return nil, e.ErrListHelmReleases.AddDesc(err.Error()) + } + + restConfig, err := kube.GetRESTConfig(prod.ClusterID) + if err != nil { + log.Errorf("GetRESTConfig error: %v", err) + return nil, e.ErrListHelmReleases.AddDesc(err.Error()) + } + helmClient, err := helmtool.NewClientFromRestConf(restConfig, prod.Namespace) + if err != nil { + log.Errorf("[%s][%s] NewClientFromRestConf error: %v", envName, productName, err) + return nil, e.ErrListHelmReleases.AddErr(err) + } + + releases, err := helmClient.ListDeployedReleases() + if err != nil { + return nil, e.ErrListHelmReleases.AddErr(err) + } + + ret := make([]*HelmReleaseResp, 0, len(releases)) + for _, release := range releases { + + for _, singleFile := range release.Chart.Files { + log.Infof("###### single file name is %s", singleFile.Name) + log.Infof("###### single file data is %s", string(singleFile.Data)) + } + + for _, singleFile := range release.Chart.Templates { + log.Infof("###### single file name is %s", singleFile.Name) + log.Infof("###### single file data is %s", string(singleFile.Data)) + } + + ret = append(ret, &HelmReleaseResp{ + ReleaseName: release.Name, + ServiceName: util.ExtraServiceName(release.Name, prod.Namespace), + Revision: release.Version, + Chart: release.Chart.Name(), + AppVersion: release.Chart.AppVersion(), + }) + } + return ret, nil +} + +func loadChartFilesInfo(productName, serviceName string, revision int64, dir string) ([]*types.FileInfo, error) { + base := config.LocalServicePathWithRevision(productName, serviceName, revision) + + var fis []*types.FileInfo + files, err := os.ReadDir(filepath.Join(base, serviceName, dir)) + if err != nil { + log.Warnf("failed to read chart info for service %s with revision %d", serviceName, revision) + base = config.LocalServicePath(productName, serviceName) + files, err = os.ReadDir(filepath.Join(base, serviceName, dir)) + if err != nil { + return nil, err + } + } + + for _, file := range files { + info, _ := file.Info() + if info == nil { + continue + } + fi := &types.FileInfo{ + Parent: dir, + Name: file.Name(), + Size: info.Size(), + Mode: file.Type(), + ModTime: info.ModTime().Unix(), + IsDir: file.IsDir(), + } + + fis = append(fis, fi) + } + return fis, nil +} + +//prepare chart version data +func prepareChartVersionData(productName string, serviceObj *models.Service) error { + serviceName, revision := serviceObj.ServiceName, serviceObj.Revision + base := config.LocalServicePathWithRevision(productName, serviceName, revision) + if err := commonservice.PreloadServiceManifestsByRevision(base, serviceObj); err != nil { + log.Warnf("failed to get chart of revision: %d for service: %s, use latest version", revision, serviceName) + // use the latest version when it fails to download the specific version + base = config.LocalServicePath(productName, serviceName) + if err = commonservice.PreLoadServiceManifests(base, serviceObj); err != nil { + log.Errorf("failed to load chart info for service %v", serviceObj.ServiceName) + return err + } + } + + fullPath := filepath.Join(base, serviceObj.ServiceName) + deliveryChartPath := filepath.Join(config.LocalDeliveryChartPathWithRevision(productName, serviceObj.ServiceName, serviceObj.Revision), serviceObj.ServiceName) + err := copy.Copy(fullPath, deliveryChartPath) + if err != nil { + return nil + } + + // write values.yaml + if err = os.WriteFile(filepath.Join(deliveryChartPath, setting.ValuesYaml), []byte("this is fake data"), 0644); err != nil { + return err + } + + return nil +} + +func GetChartInfos(productName, envName, serviceName string, log *zap.SugaredLogger) (*HelmChartsResp, error) { + opt := &commonrepo.ProductFindOptions{Name: productName, EnvName: envName} + prod, err := commonrepo.NewProductColl().Find(opt) + if err != nil { + return nil, e.ErrGetHelmCharts.AddErr(err) + } + + //restConfig, err := kube.GetRESTConfig(prod.ClusterID) + //if err != nil { + // log.Errorf("GetRESTConfig error: %v", err) + // return nil, e.ErrGetHelmCharts.AddDesc(err.Error()) + //} + //helmClient, err := helmtool.NewClientFromRestConf(restConfig, prod.Namespace) + //if err != nil { + // log.Errorf("[%s][%s] NewClientFromRestConf error: %v", envName, productName, err) + // return nil, e.ErrGetHelmCharts.AddErr(err) + //} + + allServiceMap := prod.GetServiceMap() + serviceMap := make(map[string]*models.ProductService) + if len(serviceName) > 0 { + serviceList := strings.Split(serviceName, ",") + // validate service exists in environment + for _, singleService := range serviceList { + if service, ok := allServiceMap[singleService]; ok { + serviceMap[service.ServiceName] = service + } else { + return nil, e.ErrGetHelmCharts.AddDesc(fmt.Sprintf("failed to find service %s in target namespace", singleService)) + } + } + } else { + serviceMap = allServiceMap + } + + if len(serviceMap) == 0 { + return nil, nil + } + + ret := &HelmChartsResp{ + ChartInfos: make([]*ChartInfo, 0), + FileInfos: make([]*types.FileInfo, 0), + } + + errList := new(multierror.Error) + wg := sync.WaitGroup{} + + for _, service := range serviceMap { + ret.ChartInfos = append(ret.ChartInfos, &ChartInfo{ + ServiceName: service.ServiceName, + Revision: service.Revision, + }) + wg.Add(1) + // download chart info with particular version + go func(serviceName string, revision int64) { + defer wg.Done() + serviceObj, err := commonrepo.NewServiceColl().Find(&commonrepo.ServiceFindOption{ + ServiceName: serviceName, + Revision: revision, + Type: setting.HelmDeployType, + }) + if err != nil { + log.Errorf("failed to query services name: %s, revision: %d, error: %s", serviceName, revision, err) + errList = multierror.Append(errList, fmt.Errorf("failed to query service, serviceName: %s, revision: %d", serviceName, revision)) + return + } + err = prepareChartVersionData(productName, serviceObj) + if err != nil { + errList = multierror.Append(errList, fmt.Errorf("failed to prepare chart info for service %s", serviceObj.ServiceName)) + return + } + }(service.ServiceName, service.Revision) + } + wg.Wait() + + if errList.ErrorOrNil() != nil { + return nil, errList.ErrorOrNil() + } + + // expand file info for first service + serviceToExpand := ret.ChartInfos[0].ServiceName + fis, err := loadChartFilesInfo(productName, serviceToExpand, serviceMap[serviceToExpand].Revision, "") + if err != nil { + log.Errorf("Failed to load service file info, err: %s", err) + return nil, e.ErrListTemplate.AddErr(err) + } + ret.FileInfos = fis + + return ret, nil +} diff --git a/pkg/microservice/aslan/core/service/handler/helm.go b/pkg/microservice/aslan/core/service/handler/helm.go index 0573b0989..b0fb475ba 100644 --- a/pkg/microservice/aslan/core/service/handler/helm.go +++ b/pkg/microservice/aslan/core/service/handler/helm.go @@ -46,13 +46,27 @@ func GetHelmServiceModule(c *gin.Context) { func GetFilePath(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Resp, ctx.Err = svcservice.GetFilePath(c.Param("serviceName"), c.Param("productName"), c.Query("dir"), ctx.Logger) + c.Query("revision") + revision, err := strconv.ParseInt(c.DefaultQuery("revision", "0"), 10, 64) + if err != nil { + ctx.Err = e.ErrInvalidParam.AddDesc("invalid revision number") + return + } + ctx.Resp, ctx.Err = svcservice.GetFilePath(c.Param("serviceName"), c.Param("productName"), revision, c.Query("dir"), ctx.Logger) } func GetFileContent(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Resp, ctx.Err = svcservice.GetFileContent(c.Param("serviceName"), c.Param("productName"), c.Query("filePath"), c.Query("fileName"), ctx.Logger) + + param := new(svcservice.GetFileContentParam) + err := c.ShouldBindQuery(param) + if err != nil { + ctx.Err = e.ErrInvalidParam.AddErr(err) + return + } + + ctx.Resp, ctx.Err = svcservice.GetFileContent(c.Param("serviceName"), c.Param("productName"), param, ctx.Logger) } func CreateOrUpdateHelmService(c *gin.Context) { diff --git a/pkg/microservice/aslan/core/service/service/helm.go b/pkg/microservice/aslan/core/service/service/helm.go index cc91441b3..a915bf295 100644 --- a/pkg/microservice/aslan/core/service/service/helm.go +++ b/pkg/microservice/aslan/core/service/service/helm.go @@ -113,6 +113,13 @@ type ChartTemplateData struct { DefaultValuesYAML []byte // content of values.yaml in template } +type GetFileContentParam struct { + FilePath string `json:"filePath" form:"filePath"` + FileName string `json:"fileName" form:"fileName"` + Revision int64 `json:"revision" form:"revision"` + DeliveryVersion bool `json:"deliveryVersion" form:"deliveryVersion"` +} + func ListHelmServices(productName string, log *zap.SugaredLogger) (*HelmService, error) { helmService := &HelmService{ ServiceInfos: []*models.Service{}, @@ -133,7 +140,7 @@ func ListHelmServices(productName string, log *zap.SugaredLogger) (*HelmService, helmService.ServiceInfos = services if len(services) > 0 { - fis, err := loadServiceFileInfos(services[0].ProductName, services[0].ServiceName, "") + fis, err := loadServiceFileInfos(services[0].ProductName, services[0].ServiceName, 0, "") if err != nil { log.Errorf("Failed to load service file info, err: %s", err) return nil, e.ErrListTemplate.AddErr(err) @@ -172,24 +179,45 @@ func GetHelmServiceModule(serviceName, productName string, revision int64, log * return helmServiceModule, err } -func GetFilePath(serviceName, productName, dir string, _ *zap.SugaredLogger) ([]*types.FileInfo, error) { - return loadServiceFileInfos(productName, serviceName, dir) +func GetFilePath(serviceName, productName string, revision int64, dir string, _ *zap.SugaredLogger) ([]*types.FileInfo, error) { + return loadServiceFileInfos(productName, serviceName, revision, dir) } -func GetFileContent(serviceName, productName, filePath, fileName string, log *zap.SugaredLogger) (string, error) { - base := config.LocalServicePath(productName, serviceName) - +func GetFileContent(serviceName, productName string, param *GetFileContentParam, log *zap.SugaredLogger) (string, error) { + filePath, fileName, revision, forDelivery := param.FilePath, param.FileName, param.Revision, param.DeliveryVersion svc, err := commonrepo.NewServiceColl().Find(&commonrepo.ServiceFindOption{ ProductName: productName, ServiceName: serviceName, + Revision: revision, }) if err != nil { return "", e.ErrFileContent.AddDesc(err.Error()) } - err = commonservice.PreLoadServiceManifests(base, svc) - if err != nil { - return "", e.ErrFileContent.AddDesc(err.Error()) + base := config.LocalServicePath(productName, serviceName) + if revision > 0 { + base = config.LocalServicePathWithRevision(productName, serviceName, revision) + if err = commonservice.PreloadServiceManifestsByRevision(base, svc); err != nil { + log.Warnf("failed to get chart of revision: %d for service: %s, use latest version", + svc.Revision, svc.ServiceName) + } + } + if err != nil || revision == 0 { + base = config.LocalServicePath(productName, serviceName) + err = commonservice.PreLoadServiceManifests(base, svc) + if err != nil { + return "", e.ErrFileContent.AddDesc(err.Error()) + } + } + + if forDelivery { + fullPath := filepath.Join(base, serviceName) + base = config.LocalDeliveryChartPathWithRevision(productName, serviceName, revision) + deliveryChartPath := filepath.Join(base, serviceName) + err := copy.Copy(fullPath, deliveryChartPath) + if err != nil { + return "", e.ErrFileContent.AddErr(err) + } } file := filepath.Join(base, serviceName, filePath, fileName) @@ -863,9 +891,7 @@ func createOrUpdateHelmService(fsTree fs.FS, args *helmServiceCreationArgs, logg return serviceObj, nil } -func loadServiceFileInfos(productName, serviceName, dir string) ([]*types.FileInfo, error) { - base := config.LocalServicePath(productName, serviceName) - +func loadServiceFileInfos(productName, serviceName string, revision int64, dir string) ([]*types.FileInfo, error) { svc, err := commonrepo.NewServiceColl().Find(&commonrepo.ServiceFindOption{ ProductName: productName, ServiceName: serviceName, @@ -874,6 +900,22 @@ func loadServiceFileInfos(productName, serviceName, dir string) ([]*types.FileIn return nil, e.ErrFilePath.AddDesc(err.Error()) } + base := config.LocalServicePath(productName, serviceName) + if revision > 0 { + base = config.LocalServicePathWithRevision(productName, serviceName, revision) + if err = commonservice.PreloadServiceManifestsByRevision(base, svc); err != nil { + log.Warnf("failed to get chart of revision: %d for service: %s, use latest version", + svc.Revision, svc.ServiceName) + } + } + if err != nil || revision == 0 { + base = config.LocalServicePath(productName, serviceName) + err = commonservice.PreLoadServiceManifests(base, svc) + if err != nil { + return nil, e.ErrFilePath.AddDesc(err.Error()) + } + } + err = commonservice.PreLoadServiceManifests(base, svc) if err != nil { return nil, e.ErrFilePath.AddDesc(err.Error()) diff --git a/pkg/tool/errors/http_errors.go b/pkg/tool/errors/http_errors.go index 45554ea76..e0ffc2eed 100644 --- a/pkg/tool/errors/http_errors.go +++ b/pkg/tool/errors/http_errors.go @@ -680,4 +680,10 @@ var ( ErrUpdateExternalLink = NewHTTPError(6842, "更新链接失败") ErrDeleteExternalLink = NewHTTPError(6843, "删除链接失败") ErrListExternalLink = NewHTTPError(6844, "获取链接列表失败") + + //----------------------------------------------------------------------------------------------- + // helm releated Error Range: 6850 - 6869 + //----------------------------------------------------------------------------------------------- + ErrListHelmReleases = NewHTTPError(6850, "获取release失败") + ErrGetHelmCharts = NewHTTPError(6851, "获取chart信息失败") ) -- Gitee From 96ab55829b11a1be68ba4b2514e70b58dcf8afc1 Mon Sep 17 00:00:00 2001 From: allenshen Date: Fri, 19 Nov 2021 11:42:46 +0800 Subject: [PATCH 002/134] make basic progress work Signed-off-by: allenshen --- go.mod | 1 + go.sum | 5 + pkg/config/config.go | 4 + .../repository/models/delivery_version.go | 10 + .../repository/mongodb/delivery_version.go | 28 ++ .../common/repository/mongodb/helm_repo.go | 32 +- .../aslan/core/delivery/handler/router.go | 2 + .../aslan/core/delivery/handler/version.go | 14 + .../aslan/core/delivery/service/version.go | 347 ++++++++++++++++++ .../aslan/core/environment/service/helm.go | 68 ++-- .../aslan/core/service/handler/helm.go | 7 +- .../aslan/core/system/handler/helm.go | 1 + pkg/setting/consts.go | 11 + 13 files changed, 496 insertions(+), 34 deletions(-) diff --git a/go.mod b/go.mod index 3c65dad55..ddc70b3dd 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/bugsnag/bugsnag-go v2.1.0+incompatible // indirect github.com/bugsnag/panicwrap v1.3.1 // indirect github.com/cenkalti/backoff/v4 v4.1.1 + github.com/chartmuseum/helm-push v0.10.1 github.com/coocood/freecache v1.1.0 github.com/coreos/go-oidc/v3 v3.0.0 github.com/dexidp/dex v0.0.0-20210802203454-3fac2ab6bc3b diff --git a/go.sum b/go.sum index 7fa362e8a..e7218b75a 100644 --- a/go.sum +++ b/go.sum @@ -286,6 +286,8 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= +github.com/chartmuseum/helm-push v0.10.1 h1:NqStAmarEy0GnrDCk0zubGKeRmkhOm/rRi5au8h76BA= +github.com/chartmuseum/helm-push v0.10.1/go.mod h1:s6xTICU31jKdLkOXS+GgaR61E+oU4h8TWb1yZcHq8OE= github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -536,6 +538,7 @@ github.com/garyburd/redigo v1.6.2 h1:yE/pwKCrbLpLpQICzYTeZ7JsTA/C53wFTJHaEtRqniM github.com/garyburd/redigo v1.6.2/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/gzip v0.0.1 h1:ezvKOL6jH+jlzdHNE4h9h8q8uMpDQjyl0NN0Jd7jozc= github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w= @@ -2349,6 +2352,8 @@ k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8 k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/helm v2.17.0+incompatible h1:Bpn6o1wKLYqKM3+Osh8e+1/K2g/GsQJ4F4yNF2+deao= +k8s.io/helm v2.17.0+incompatible/go.mod h1:LZzlS4LQBHfciFOurYBFkCMTaZ0D1l+p0teMg7TSULI= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= diff --git a/pkg/config/config.go b/pkg/config/config.go index 78ff45336..4f324676e 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -210,6 +210,10 @@ func ObjectStorageTemplatePath(name, kind string) string { return filepath.Join("templates", kind, name) } +func ObjectStorageDeliveryVersionPath(project string) string { + return filepath.Join(project, "delivery-versions") +} + func ObjectStorageChartTemplatePath(name string) string { return ObjectStorageTemplatePath(name, setting.ChartTemplatesPath) } diff --git a/pkg/microservice/aslan/core/common/repository/models/delivery_version.go b/pkg/microservice/aslan/core/common/repository/models/delivery_version.go index 7efeda7d4..8fcc93f86 100644 --- a/pkg/microservice/aslan/core/common/repository/models/delivery_version.go +++ b/pkg/microservice/aslan/core/common/repository/models/delivery_version.go @@ -20,6 +20,12 @@ import ( "go.mongodb.org/mongo-driver/bson/primitive" ) +type DeliveryChart struct { + Name string `bson:"name" json:"name"` + Version string `bson:"version" json:"version"` + Repo string `bson:"repo" json:"repo"` +} + type DeliveryVersion struct { ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` Version string `bson:"version" json:"version"` @@ -30,6 +36,10 @@ type DeliveryVersion struct { Desc string `bson:"desc" json:"desc"` Labels []string `bson:"labels" json:"labels"` ProductEnvInfo *Product `bson:"product_env_info" json:"productEnvInfo"` + Charts []*DeliveryChart `bson:"charts" json:"charts"` + Status string `bson:"status" json:"status"` + Error string `bson:"log" json:"log"` + CreateArgument interface{} `bson:"createArgument" json:"-"` CreatedBy string `bson:"created_by" json:"createdBy"` CreatedAt int64 `bson:"created_at" json:"created_at"` DeletedAt int64 `bson:"deleted_at" json:"deleted_at"` diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go b/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go index bae5fc668..355477683 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go @@ -190,6 +190,34 @@ func (c *DeliveryVersionColl) Insert(args *models.DeliveryVersion) error { return nil } +func (c *DeliveryVersionColl) UpdateStatusByName(versionName, status, errorStr string) error { + query := bson.M{"version": versionName, "deleted_at": 0} + change := bson.M{"$set": bson.M{ + "status": status, + "error": errorStr, + }} + _, err := c.UpdateOne(context.TODO(), query, change) + return err +} + +func (c *DeliveryVersionColl) AddDeliveryChart(versionName string, chartInfo *models.DeliveryChart) error { + query := bson.M{ + "version": versionName, + "deleted_at": 0, + "charts.name": bson.M{"$ne": chartInfo.Name}, + } + change := bson.M{ + "$push": bson.M{ + "charts": bson.M{ + "name": chartInfo.Name, + "version": chartInfo.Version, + "repo": chartInfo.Repo, + }, + }} + _, err := c.UpdateOne(context.TODO(), query, change) + return err +} + func (c *DeliveryVersionColl) Update(args *models.DeliveryVersion) error { if args == nil { return errors.New("nil delivery_version args") diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/helm_repo.go b/pkg/microservice/aslan/core/common/repository/mongodb/helm_repo.go index 6d7731676..86fff875e 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/helm_repo.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/helm_repo.go @@ -37,6 +37,11 @@ type HelmRepoColl struct { coll string } +type HelmRepoFindOption struct { + Id string + RepoName string +} + func NewHelmRepoColl() *HelmRepoColl { name := models.HelmRepo{}.TableName() coll := &HelmRepoColl{Collection: mongotool.Database(config.MongoDatabase()).Collection(name), coll: name} @@ -49,7 +54,12 @@ func (c *HelmRepoColl) GetCollectionName() string { } func (c *HelmRepoColl) EnsureIndex(ctx context.Context) error { - return nil + mod := mongo.IndexModel{ + Keys: bson.M{"repo_name": 1}, + Options: options.Index().SetUnique(false), + } + _, err := c.Indexes().CreateOne(ctx, mod) + return err } func (c *HelmRepoColl) Create(args *models.HelmRepo) error { @@ -64,6 +74,26 @@ func (c *HelmRepoColl) Create(args *models.HelmRepo) error { return err } +func (c *HelmRepoColl) Find(opt *HelmRepoFindOption) (*models.HelmRepo, error) { + query := bson.M{} + if len(opt.Id) > 0 { + oid, err := primitive.ObjectIDFromHex(opt.Id) + if err != nil { + return nil, err + } + query["_id"] = oid + } + if len(opt.RepoName) > 0 { + query["repo_name"] = opt.RepoName + } + ret := new(models.HelmRepo) + err := c.FindOne(context.TODO(), query).Decode(ret) + if err != nil { + return nil, err + } + return ret, nil +} + func (c *HelmRepoColl) Update(id string, args *models.HelmRepo) error { oid, err := primitive.ObjectIDFromHex(id) if err != nil { diff --git a/pkg/microservice/aslan/core/delivery/handler/router.go b/pkg/microservice/aslan/core/delivery/handler/router.go index 889b7e7aa..7b532a817 100644 --- a/pkg/microservice/aslan/core/delivery/handler/router.go +++ b/pkg/microservice/aslan/core/delivery/handler/router.go @@ -45,6 +45,8 @@ func (*Router) Inject(router *gin.RouterGroup) { deliveryRelease.GET("/:id", GetDeliveryVersion) deliveryRelease.GET("", ListDeliveryVersion) deliveryRelease.DELETE("/:id", GetProductNameByDelivery, gin2.UpdateOperationLogStatus, DeleteDeliveryVersion) + + deliveryRelease.POST("/helm", CreateHelmDeliveryVersion) } deliveryPackage := router.Group("packages") diff --git a/pkg/microservice/aslan/core/delivery/handler/version.go b/pkg/microservice/aslan/core/delivery/handler/version.go index 44ea5e998..4ac0900d1 100644 --- a/pkg/microservice/aslan/core/delivery/handler/version.go +++ b/pkg/microservice/aslan/core/delivery/handler/version.go @@ -326,6 +326,20 @@ func ListPackagesVersion(c *gin.Context) { ctx.Resp = fileInfoList } +func CreateHelmDeliveryVersion(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + args := new(deliveryservice.CreateHelmDeliveryVersionArgs) + err := c.ShouldBindJSON(args) + if err != nil { + ctx.Err = e.ErrInvalidParam.AddErr(err) + return + } + args.CreateBy = ctx.UserName + ctx.Err = deliveryservice.CreateHelmDeliveryVersion(args, ctx.Logger) +} + func DeleteDeliveryVersion(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() diff --git a/pkg/microservice/aslan/core/delivery/service/version.go b/pkg/microservice/aslan/core/delivery/service/version.go index 1c013f689..de24a038c 100644 --- a/pkg/microservice/aslan/core/delivery/service/version.go +++ b/pkg/microservice/aslan/core/delivery/service/version.go @@ -17,14 +17,77 @@ limitations under the License. package service import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "os" + "path/filepath" + "sync" + "time" + + "go.mongodb.org/mongo-driver/bson/primitive" + + fsservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/fs" + + fsutil "github.com/koderover/zadig/pkg/util/fs" + + "github.com/hashicorp/go-multierror" + + cm "github.com/chartmuseum/helm-push/pkg/chartmuseum" + "github.com/chartmuseum/helm-push/pkg/helm" + "github.com/otiai10/copy" + "github.com/pkg/errors" "go.uber.org/zap" + chartloader "helm.sh/helm/v3/pkg/chart/loader" "k8s.io/apimachinery/pkg/util/sets" + "sigs.k8s.io/yaml" + configbase "github.com/koderover/zadig/pkg/config" + "github.com/koderover/zadig/pkg/microservice/aslan/config" commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" + commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" + "github.com/koderover/zadig/pkg/setting" e "github.com/koderover/zadig/pkg/tool/errors" + "github.com/koderover/zadig/pkg/tool/log" ) +type CreateHelmDeliveryVersionOption struct { + EnableOfflineDist bool `json:"enableOfflineDist"` + S3StorageID string `json:"s3StorageID"` +} + +type CreateHelmDeliveryVersionChartData struct { + ServiceName string `json:"serviceName"` + Version string `json:"version"` + ValuesYamlContent string `json:"valuesYamlContent"` +} + +type CreateHelmDeliveryVersionArgs struct { + CreateBy string `json:"-"` + Version string `json:"version"` + Desc string `json:"desc"` + ProductName string `json:"productName"` + EnvName string `json:"envName"` + Labels []string `json:"labels"` + //ChartDatas []*CreateHelmDeliveryVersionChartData `json:"chartDatas"` + ChartRepoName string `json:"chartRepoName"` + //Options *CreateHelmDeliveryVersionOption `json:"options"` + *DeliveryVersionChartData +} + +type DeliveryVersionChartData struct { + ChartDatas []*CreateHelmDeliveryVersionChartData `json:"chartDatas"` + Options *CreateHelmDeliveryVersionOption `json:"options"` +} + +type ChartDeliveryData struct { + ChartData *CreateHelmDeliveryVersionChartData + ProductService *commonmodels.ProductService + ServiceObj *commonmodels.Service +} + func GetDeliveryVersion(args *commonrepo.DeliveryVersionArgs, log *zap.SugaredLogger) (*commonmodels.DeliveryVersion, error) { resp, err := commonrepo.NewDeliveryVersionColl().Get(args) if err != nil { @@ -52,6 +115,290 @@ func DeleteDeliveryVersion(args *commonrepo.DeliveryVersionArgs, log *zap.Sugare return nil } +func getProductEnvInfo(productName, envName string) (*commonmodels.Product, error) { + productInfo, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{ + Name: productName, + EnvName: envName, + }) + if err != nil { + log.Errorf("failed to query product info, productName: %s envName: %s err: %s", productName, envName, err) + return nil, fmt.Errorf("failed to query product info, productName: %s envName: %s", productName, envName) + } + return productInfo, nil +} + +func getChartRepoData(repoName string) (*commonmodels.HelmRepo, error) { + return commonrepo.NewHelmRepoColl().Find(&commonrepo.HelmRepoFindOption{RepoName: repoName}) +} + +func createChartRepoClient(repo *commonmodels.HelmRepo) (*cm.Client, error) { + client, err := cm.NewClient( + cm.URL(repo.URL), + cm.Username(repo.Username), + cm.Password(repo.Password), + // need support more auth types + ) + if err != nil { + return nil, errors.Wrapf(err, "failed to create chart repo client") + } + return client, nil +} + +func handleSingleChart(chartData *ChartDeliveryData, chartRepo *commonmodels.HelmRepo, dir string) error { + serviceObj := chartData.ServiceObj + serviceName, revision := serviceObj.ServiceName, serviceObj.Revision + base := config.LocalServicePathWithRevision(serviceObj.ProductName, serviceName, revision) + if err := commonservice.PreloadServiceManifestsByRevision(base, serviceObj); err != nil { + log.Warnf("failed to get chart of revision: %d for service: %s, use latest version", revision, serviceName) + // use the latest version when it fails to download the specific version + base = config.LocalServicePath(serviceObj.ProductName, serviceName) + if err = commonservice.PreLoadServiceManifests(base, serviceObj); err != nil { + log.Errorf("failed to load chart info for service %v", serviceObj.ServiceName) + return err + } + } + + fullPath := filepath.Join(base, serviceObj.ServiceName) + revisionBasePath := config.LocalDeliveryChartPathWithRevision(serviceObj.ProductName, serviceObj.ServiceName, serviceObj.Revision) + deliveryChartPath := filepath.Join(revisionBasePath, serviceObj.ServiceName) + err := copy.Copy(fullPath, deliveryChartPath) + if err != nil { + return nil + } + + //load chart info from local storage + chartRequested, err := chartloader.Load(deliveryChartPath) + if err != nil { + return errors.Wrapf(err, "failed to load chart info, path %s", deliveryChartPath) + } + + //set version and values.yaml content + chartRequested.Metadata.Name = chartData.ChartData.ServiceName + chartRequested.Metadata.Version = chartData.ChartData.Version + chartRequested.Metadata.AppVersion = chartData.ChartData.Version + if len(chartData.ChartData.ValuesYamlContent) > 0 { + valuesInfo := make(map[string]interface{}) + if err = yaml.Unmarshal([]byte(chartData.ChartData.ValuesYamlContent), map[string]interface{}{}); err != nil { + log.Errorf("invalid yaml content, serviceName: %s, yamlContent: %s", serviceObj.ServiceName, chartData.ChartData.ValuesYamlContent) + return errors.Wrapf(err, "invalid yaml content for service: %s", serviceObj.ServiceName) + } + chartRequested.Values = valuesInfo + } + + chartPackagePath, err := helm.CreateChartPackage(&helm.Chart{Chart: chartRequested}, dir) + if err != nil { + return err + } + + client, err := createChartRepoClient(chartRepo) + if err != nil { + return err + } + + log.Infof("pushing %s to %s...\n", filepath.Base(chartPackagePath), chartRepo.URL) + resp, err := client.UploadChartPackage(chartPackagePath, false) + if err != nil { + return errors.Wrapf(err, "failed to prepare pushing chart: %s", chartPackagePath) + } + err = handlePushResponse(resp) + if err != nil { + return errors.Wrapf(err, "failed to push chart: %s ", chartPackagePath) + } + return nil +} + +func handlePushResponse(resp *http.Response) error { + if resp.StatusCode != 201 && resp.StatusCode != 202 { + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + return getChartmuseumError(b, resp.StatusCode) + } + log.Infof("push chart to chart repo done") + return nil +} + +func getChartmuseumError(b []byte, code int) error { + var er struct { + Error string `json:"error"` + } + err := json.Unmarshal(b, &er) + if err != nil || er.Error == "" { + return errors.Errorf("%d: could not properly parse response JSON: %s", code, string(b)) + } + return errors.Errorf("%d: %s", code, er.Error) +} + +func mkChartTGZFileDir(versionName string) (string, error) { + tmpDir := os.TempDir() + path := filepath.Join(tmpDir, "chart-tgz", versionName) + if err := os.RemoveAll(path); err != nil { + if !os.IsExist(err) { + return "", errors.Wrapf(err, "failed to claer dir for chart tgz files") + } + } + err := os.MkdirAll(path, 0777) + if err != nil { + return "", errors.Wrapf(err, "failed to create chart tgz dir for version: %s", versionName) + } + return path, nil +} + +func CreateHelmDeliveryVersion(args *CreateHelmDeliveryVersionArgs, logger *zap.SugaredLogger) error { + // need appoint chart info + if len(args.ChartDatas) == 0 { + return e.ErrCreateDeliveryVersion.AddDesc("no chart info appointed") + } + + // prepare data + productInfo, err := getProductEnvInfo(args.ProductName, args.EnvName) + if err != nil { + log.Infof("failed to query product info, procutName: %s envName %s, err: %s", args.ProductName, args.EnvName, err) + return e.ErrCreateDeliveryVersion.AddDesc(fmt.Sprintf("failed to query product info, procutName: %s envName %s", args.ProductName, args.EnvName)) + } + repoInfo, err := getChartRepoData(args.ChartRepoName) + if err != nil { + log.Infof("failed to query chart-repo info, procutName: %s envName %s, err: %s", args.ProductName, args.EnvName, err) + return e.ErrCreateDeliveryVersion.AddDesc(fmt.Sprintf("failed to query chart-repo info, procutName: %s envName %s", args.ProductName, args.EnvName)) + } + + dir, err := mkChartTGZFileDir(args.Version) + if err != nil { + return e.ErrCreateDeliveryVersion.AddErr(err) + } + + // validate chartInfo, make sure service is in environment + // prepare data set for chart delivery + chartDataMap := make(map[string]*ChartDeliveryData) + serviceMap := productInfo.GetServiceMap() + for _, chartDta := range args.ChartDatas { + if productService, ok := serviceMap[chartDta.ServiceName]; ok { + serviceObj, err := commonrepo.NewServiceColl().Find(&commonrepo.ServiceFindOption{ + ServiceName: chartDta.ServiceName, + Revision: productService.Revision, + Type: setting.HelmDeployType, + ProductName: args.ProductName, + }) + if err != nil { + return e.ErrCreateDeliveryVersion.AddDesc(fmt.Sprintf("failed to query service: %s", chartDta.ServiceName)) + } + chartDataMap[chartDta.ServiceName] = &ChartDeliveryData{ + ChartData: chartDta, + ProductService: productService, + ServiceObj: serviceObj, + } + } else { + return e.ErrCreateDeliveryVersion.AddDesc(fmt.Sprintf("service %s not found in environment", chartDta.ServiceName)) + } + } + + productInfo.ID, _ = primitive.ObjectIDFromHex("") + + versionObj := &commonmodels.DeliveryVersion{ + Version: args.Version, + ProductName: args.ProductName, + Type: setting.DeliveryVersionTypeChart, + Desc: args.Desc, + Labels: args.Labels, + ProductEnvInfo: productInfo, + Status: setting.DeliveryVersionStatusCreating, + CreateArgument: args.DeliveryVersionChartData, + CreatedBy: args.CreateBy, + CreatedAt: time.Now().Unix(), + DeletedAt: 0, + } + + err = commonrepo.NewDeliveryVersionColl().Insert(versionObj) + if err != nil { + logger.Errorf("failed to insert version data, err: %s", err) + return fmt.Errorf("failed to insert delivery version: %s", versionObj.Version) + } + + go func() { + var err error + defer func() { + if err != nil { + versionObj.Status = setting.DeliveryVersionStatusFailed + versionObj.Error = err.Error() + } else { + versionObj.Status = setting.DeliveryVersionStatusSuccess + versionObj.Error = "" + } + err = commonrepo.NewDeliveryVersionColl().UpdateStatusByName(versionObj.Version, versionObj.Status, versionObj.Error) + if err != nil { + logger.Errorf("failed to update delivery version data, name: %s error: %s", versionObj.Version, err) + } + }() + + var errLock sync.Mutex + errorList := &multierror.Error{} + + appendError := func(err error) { + errLock.Lock() + defer errLock.Unlock() + errorList = multierror.Append(errorList, err) + } + + // push charts to repo + wg := sync.WaitGroup{} + for _, chartData := range chartDataMap { + wg.Add(1) + go func(cData *ChartDeliveryData) { + defer wg.Done() + err := handleSingleChart(cData, repoInfo, dir) + if err != nil { + logger.Errorf("failed to handle single chart data, serviceName: %s err: %s", cData.ChartData.ServiceName, err) + appendError(err) + } else { + err = commonrepo.NewDeliveryVersionColl().AddDeliveryChart(versionObj.Version, &commonmodels.DeliveryChart{ + Name: cData.ServiceObj.ServiceName, + Version: cData.ChartData.Version, + Repo: args.ChartRepoName, + }) + if err != nil { + appendError(errors.Wrapf(err, "failed to save delivery chart: %s", cData.ChartData.ServiceName)) + } + } + }(chartData) + } + wg.Wait() + + if errorList.ErrorOrNil() != nil { + err = errorList.ErrorOrNil() + return + } + + tmpDir, err := os.MkdirTemp("", "delivery-") + if err != nil { + logger.Errorf("failed to create temp dir, err: %s", err) + return + } + defer os.RemoveAll(tmpDir) + + //tar all chart files and send to s3 store + fsTree := os.DirFS(dir) + tarball := fmt.Sprintf("%s.tar.gz", versionObj.Version) + localPath := filepath.Join(tmpDir, tarball) + if err = fsutil.Tar(fsTree, localPath); err != nil { + logger.Errorf("failed to archive tarball %s, err: %s", localPath, err) + versionObj.Status = setting.DeliveryVersionStatusFailed + err = errors.Wrapf(err, "failed to archive chart files, path %s", localPath) + return + } + + ServiceS3Base := configbase.ObjectStorageDeliveryVersionPath(args.ProductName) + if err = fsservice.ArchiveAndUploadFilesToS3(fsTree, versionObj.Version, ServiceS3Base, nil, logger); err != nil { + logger.Errorf("failed to upload chart package files for project %s, err: %s", args.ProductName, err) + err = errors.Wrapf(err, "failed to upload package file") + return + } + + }() + + return nil +} + func ListDeliveryServiceNames(productName string, log *zap.SugaredLogger) ([]string, error) { serviceNames := sets.String{} diff --git a/pkg/microservice/aslan/core/environment/service/helm.go b/pkg/microservice/aslan/core/environment/service/helm.go index 64fe4fb24..b4087f30a 100644 --- a/pkg/microservice/aslan/core/environment/service/helm.go +++ b/pkg/microservice/aslan/core/environment/service/helm.go @@ -23,26 +23,23 @@ import ( "strings" "sync" - "github.com/otiai10/copy" - - "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" - - "github.com/koderover/zadig/pkg/tool/log" - - "github.com/koderover/zadig/pkg/types" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/template" "github.com/hashicorp/go-multierror" - "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/util" - - helmtool "github.com/koderover/zadig/pkg/tool/helmclient" + "github.com/otiai10/copy" + "go.uber.org/zap" "github.com/koderover/zadig/pkg/microservice/aslan/config" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" + "github.com/koderover/zadig/pkg/setting" e "github.com/koderover/zadig/pkg/tool/errors" - "go.uber.org/zap" + helmtool "github.com/koderover/zadig/pkg/tool/helmclient" + "github.com/koderover/zadig/pkg/tool/log" + "github.com/koderover/zadig/pkg/types" + "github.com/koderover/zadig/pkg/util" ) type HelmReleaseResp struct { @@ -67,23 +64,23 @@ func ListReleases(productName, envName string, log *zap.SugaredLogger) ([]*HelmR opt := &commonrepo.ProductFindOptions{Name: productName, EnvName: envName} prod, err := commonrepo.NewProductColl().Find(opt) if err != nil { - return nil, e.ErrListHelmReleases.AddDesc(err.Error()) + return nil, e.ErrCreateDeliveryVersion.AddDesc(err.Error()) } restConfig, err := kube.GetRESTConfig(prod.ClusterID) if err != nil { log.Errorf("GetRESTConfig error: %v", err) - return nil, e.ErrListHelmReleases.AddDesc(err.Error()) + return nil, e.ErrCreateDeliveryVersion.AddDesc(err.Error()) } helmClient, err := helmtool.NewClientFromRestConf(restConfig, prod.Namespace) if err != nil { log.Errorf("[%s][%s] NewClientFromRestConf error: %v", envName, productName, err) - return nil, e.ErrListHelmReleases.AddErr(err) + return nil, e.ErrCreateDeliveryVersion.AddErr(err) } releases, err := helmClient.ListDeployedReleases() if err != nil { - return nil, e.ErrListHelmReleases.AddErr(err) + return nil, e.ErrCreateDeliveryVersion.AddErr(err) } ret := make([]*HelmReleaseResp, 0, len(releases)) @@ -144,7 +141,7 @@ func loadChartFilesInfo(productName, serviceName string, revision int64, dir str } //prepare chart version data -func prepareChartVersionData(productName string, serviceObj *models.Service) error { +func prepareChartVersionData(productName string, serviceObj *models.Service, renderChart *template.RenderChart, renderset *models.RenderSet) error { serviceName, revision := serviceObj.ServiceName, serviceObj.Revision base := config.LocalServicePathWithRevision(productName, serviceName, revision) if err := commonservice.PreloadServiceManifestsByRevision(base, serviceObj); err != nil { @@ -161,11 +158,16 @@ func prepareChartVersionData(productName string, serviceObj *models.Service) err deliveryChartPath := filepath.Join(config.LocalDeliveryChartPathWithRevision(productName, serviceObj.ServiceName, serviceObj.Revision), serviceObj.ServiceName) err := copy.Copy(fullPath, deliveryChartPath) if err != nil { - return nil + return err + } + + mergedValuesYaml, err := helmtool.MergeOverrideValues(renderChart.ValuesYaml, renderset.DefaultValues, renderChart.GetOverrideYaml(), renderChart.OverrideValues) + if err != nil { + return err } // write values.yaml - if err = os.WriteFile(filepath.Join(deliveryChartPath, setting.ValuesYaml), []byte("this is fake data"), 0644); err != nil { + if err = os.WriteFile(filepath.Join(deliveryChartPath, setting.ValuesYaml), []byte(mergedValuesYaml), 0644); err != nil { return err } @@ -178,23 +180,22 @@ func GetChartInfos(productName, envName, serviceName string, log *zap.SugaredLog if err != nil { return nil, e.ErrGetHelmCharts.AddErr(err) } + renderSet, err := FindHelmRenderSet(productName, envName, log) + if err != nil { + log.Errorf("[%s][P:%s] find product renderset error: %v", envName, productName, err) + return nil, e.ErrGetHelmCharts.AddErr(err) + } - //restConfig, err := kube.GetRESTConfig(prod.ClusterID) - //if err != nil { - // log.Errorf("GetRESTConfig error: %v", err) - // return nil, e.ErrGetHelmCharts.AddDesc(err.Error()) - //} - //helmClient, err := helmtool.NewClientFromRestConf(restConfig, prod.Namespace) - //if err != nil { - // log.Errorf("[%s][%s] NewClientFromRestConf error: %v", envName, productName, err) - // return nil, e.ErrGetHelmCharts.AddErr(err) - //} + chartMap := make(map[string]*template.RenderChart) + for _, chart := range renderSet.ChartInfos { + chartMap[chart.ServiceName] = chart + } allServiceMap := prod.GetServiceMap() serviceMap := make(map[string]*models.ProductService) + //validate data, make sure service and chart info exists if len(serviceName) > 0 { serviceList := strings.Split(serviceName, ",") - // validate service exists in environment for _, singleService := range serviceList { if service, ok := allServiceMap[singleService]; ok { serviceMap[service.ServiceName] = service @@ -237,7 +238,12 @@ func GetChartInfos(productName, envName, serviceName string, log *zap.SugaredLog errList = multierror.Append(errList, fmt.Errorf("failed to query service, serviceName: %s, revision: %d", serviceName, revision)) return } - err = prepareChartVersionData(productName, serviceObj) + renderChart, ok := chartMap[serviceName] + if !ok { + errList = multierror.Append(errList, fmt.Errorf("failed to find render chart for service %s in target namespace", serviceName)) + return + } + err = prepareChartVersionData(productName, serviceObj, renderChart, renderSet) if err != nil { errList = multierror.Append(errList, fmt.Errorf("failed to prepare chart info for service %s", serviceObj.ServiceName)) return diff --git a/pkg/microservice/aslan/core/service/handler/helm.go b/pkg/microservice/aslan/core/service/handler/helm.go index b0fb475ba..d1462e369 100644 --- a/pkg/microservice/aslan/core/service/handler/helm.go +++ b/pkg/microservice/aslan/core/service/handler/helm.go @@ -46,8 +46,11 @@ func GetHelmServiceModule(c *gin.Context) { func GetFilePath(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - c.Query("revision") - revision, err := strconv.ParseInt(c.DefaultQuery("revision", "0"), 10, 64) + revision := int64(0) + var err error + if len(c.Query("revision")) > 0 { + revision, err = strconv.ParseInt(c.Query("revision"), 10, 64) + } if err != nil { ctx.Err = e.ErrInvalidParam.AddDesc("invalid revision number") return diff --git a/pkg/microservice/aslan/core/system/handler/helm.go b/pkg/microservice/aslan/core/system/handler/helm.go index 31a84a53d..7f92809e6 100644 --- a/pkg/microservice/aslan/core/system/handler/helm.go +++ b/pkg/microservice/aslan/core/system/handler/helm.go @@ -49,6 +49,7 @@ func CreateHelmRepo(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid url") return } + ctx.Err = service.CreateHelmRepo(args, ctx.Logger) } diff --git a/pkg/setting/consts.go b/pkg/setting/consts.go index c8c77099e..dd37e7018 100644 --- a/pkg/setting/consts.go +++ b/pkg/setting/consts.go @@ -271,6 +271,10 @@ const ( FunctionTestType = "function" ) +const ( + DeliveryVersionTypeChart = "HelmChart" +) + const ( AuthorizationHeader = "Authorization" ) @@ -322,6 +326,13 @@ const ( ProductStatusUnstable = "Unstable" ) +// DeliveryVersion status +const ( + DeliveryVersionStatusSuccess = "success" + DeliveryVersionStatusFailed = "failed" + DeliveryVersionStatusCreating = "creating" +) + const ( NormalModeProduct = "normal" ) -- Gitee From 9d0fea08e340b59b545dbf41e56a9e750777146b Mon Sep 17 00:00:00 2001 From: allenshen Date: Sun, 21 Nov 2021 16:44:21 +0800 Subject: [PATCH 003/134] add get chart data api Signed-off-by: allenshen --- .../repository/models/delivery_version.go | 2 +- .../repository/mongodb/delivery_version.go | 9 +- .../aslan/core/delivery/handler/router.go | 4 + .../aslan/core/delivery/handler/version.go | 27 +++ .../aslan/core/delivery/service/version.go | 210 +++++++++++++++--- 5 files changed, 221 insertions(+), 31 deletions(-) diff --git a/pkg/microservice/aslan/core/common/repository/models/delivery_version.go b/pkg/microservice/aslan/core/common/repository/models/delivery_version.go index 8fcc93f86..956070a35 100644 --- a/pkg/microservice/aslan/core/common/repository/models/delivery_version.go +++ b/pkg/microservice/aslan/core/common/repository/models/delivery_version.go @@ -38,7 +38,7 @@ type DeliveryVersion struct { ProductEnvInfo *Product `bson:"product_env_info" json:"productEnvInfo"` Charts []*DeliveryChart `bson:"charts" json:"charts"` Status string `bson:"status" json:"status"` - Error string `bson:"log" json:"log"` + Error string `bson:"error" json:"error"` CreateArgument interface{} `bson:"createArgument" json:"-"` CreatedBy string `bson:"created_by" json:"createdBy"` CreatedAt int64 `bson:"created_at" json:"created_at"` diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go b/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go index 355477683..ada39606b 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go @@ -34,6 +34,7 @@ import ( type DeliveryVersionArgs struct { ID string `json:"id"` ProductName string `json:"productName"` + Version string `json:"version"` WorkflowName string `json:"workflowName"` TaskID int `json:"taskId"` PerPage int `json:"perPage"` @@ -164,7 +165,13 @@ func (c *DeliveryVersionColl) Get(args *DeliveryVersionArgs) (*models.DeliveryVe resp := new(models.DeliveryVersion) var query map[string]interface{} if args.ID != "" { - query = bson.M{"_id": args.ID, "deleted_at": 0} + oid, err := primitive.ObjectIDFromHex(args.ID) + if err != nil { + return nil, err + } + query = bson.M{"_id": oid, "deleted_at": 0} + } else if len(args.Version) > 0 { + query = bson.M{"product_name": args.ProductName, "version": args.Version, "deleted_at": 0} } else { query = bson.M{"product_name": args.ProductName, "workflow_name": args.WorkflowName, "task_id": args.TaskID, "deleted_at": 0} } diff --git a/pkg/microservice/aslan/core/delivery/handler/router.go b/pkg/microservice/aslan/core/delivery/handler/router.go index 7b532a817..18ecc0de3 100644 --- a/pkg/microservice/aslan/core/delivery/handler/router.go +++ b/pkg/microservice/aslan/core/delivery/handler/router.go @@ -46,7 +46,11 @@ func (*Router) Inject(router *gin.RouterGroup) { deliveryRelease.GET("", ListDeliveryVersion) deliveryRelease.DELETE("/:id", GetProductNameByDelivery, gin2.UpdateOperationLogStatus, DeleteDeliveryVersion) + deliveryRelease.GET("/charts", DownloadDeliveryChart) + deliveryRelease.GET("/charts/preview", PreviewGetDeliveryChart) + deliveryRelease.POST("/helm", CreateHelmDeliveryVersion) + } deliveryPackage := router.Group("packages") diff --git a/pkg/microservice/aslan/core/delivery/handler/version.go b/pkg/microservice/aslan/core/delivery/handler/version.go index 4ac0900d1..f91c4ec0b 100644 --- a/pkg/microservice/aslan/core/delivery/handler/version.go +++ b/pkg/microservice/aslan/core/delivery/handler/version.go @@ -385,3 +385,30 @@ func ListDeliveryServiceNames(c *gin.Context) { productName := c.Query("projectName") ctx.Resp, ctx.Err = deliveryservice.ListDeliveryServiceNames(productName, ctx.Logger) } + +func DownloadDeliveryChart(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + versionName := c.Query("version") + chartName := c.Query("chartName") + projectName := c.Query("projectName") + + filePath, err := deliveryservice.DownloadDeliveryChart(projectName, versionName, chartName, ctx.Logger) + if err != nil { + ctx.Err = err + return + } + c.File(filePath) +} + +func PreviewGetDeliveryChart(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + versionName := c.Query("version") + chartName := c.Query("chartName") + projectName := c.Query("projectName") + + ctx.Resp, ctx.Err = deliveryservice.PreviewDeliveryChart(projectName, versionName, chartName, ctx.Logger) +} diff --git a/pkg/microservice/aslan/core/delivery/service/version.go b/pkg/microservice/aslan/core/delivery/service/version.go index de24a038c..9973e81df 100644 --- a/pkg/microservice/aslan/core/delivery/service/version.go +++ b/pkg/microservice/aslan/core/delivery/service/version.go @@ -23,23 +23,19 @@ import ( "net/http" "os" "path/filepath" + "strings" "sync" "time" - "go.mongodb.org/mongo-driver/bson/primitive" - - fsservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/fs" - - fsutil "github.com/koderover/zadig/pkg/util/fs" - - "github.com/hashicorp/go-multierror" - cm "github.com/chartmuseum/helm-push/pkg/chartmuseum" "github.com/chartmuseum/helm-push/pkg/helm" + "github.com/hashicorp/go-multierror" "github.com/otiai10/copy" "github.com/pkg/errors" + "go.mongodb.org/mongo-driver/bson/primitive" "go.uber.org/zap" chartloader "helm.sh/helm/v3/pkg/chart/loader" + "helm.sh/helm/v3/pkg/chartutil" "k8s.io/apimachinery/pkg/util/sets" "sigs.k8s.io/yaml" @@ -48,9 +44,12 @@ import ( commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" + fsservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/fs" "github.com/koderover/zadig/pkg/setting" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/log" + "github.com/koderover/zadig/pkg/types" + fsutil "github.com/koderover/zadig/pkg/util/fs" ) type CreateHelmDeliveryVersionOption struct { @@ -65,15 +64,13 @@ type CreateHelmDeliveryVersionChartData struct { } type CreateHelmDeliveryVersionArgs struct { - CreateBy string `json:"-"` - Version string `json:"version"` - Desc string `json:"desc"` - ProductName string `json:"productName"` - EnvName string `json:"envName"` - Labels []string `json:"labels"` - //ChartDatas []*CreateHelmDeliveryVersionChartData `json:"chartDatas"` - ChartRepoName string `json:"chartRepoName"` - //Options *CreateHelmDeliveryVersionOption `json:"options"` + CreateBy string `json:"-"` + Version string `json:"version"` + Desc string `json:"desc"` + ProductName string `json:"productName"` + EnvName string `json:"envName"` + Labels []string `json:"labels"` + ChartRepoName string `json:"chartRepoName"` *DeliveryVersionChartData } @@ -82,12 +79,16 @@ type DeliveryVersionChartData struct { Options *CreateHelmDeliveryVersionOption `json:"options"` } -type ChartDeliveryData struct { +type DeliveryChartData struct { ChartData *CreateHelmDeliveryVersionChartData ProductService *commonmodels.ProductService ServiceObj *commonmodels.Service } +type DeliveryChartResp struct { + FileInfos []*types.FileInfo `json:"fileInfos"` +} + func GetDeliveryVersion(args *commonrepo.DeliveryVersionArgs, log *zap.SugaredLogger) (*commonmodels.DeliveryVersion, error) { resp, err := commonrepo.NewDeliveryVersionColl().Get(args) if err != nil { @@ -115,6 +116,16 @@ func DeleteDeliveryVersion(args *commonrepo.DeliveryVersionArgs, log *zap.Sugare return nil } +func getChartTGZDir(productName, versionName string) string { + tmpDir := os.TempDir() + return filepath.Join(tmpDir, "chart-tgz", productName, versionName) +} + +func getChartExpandDir(productName, versionName string) string { + tmpDir := os.TempDir() + return filepath.Join(tmpDir, "chart", productName, versionName) +} + func getProductEnvInfo(productName, envName string) (*commonmodels.Product, error) { productInfo, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{ Name: productName, @@ -139,12 +150,12 @@ func createChartRepoClient(repo *commonmodels.HelmRepo) (*cm.Client, error) { // need support more auth types ) if err != nil { - return nil, errors.Wrapf(err, "failed to create chart repo client") + return nil, errors.Wrapf(err, "failed to create chart repo client, repoName: %s", repo.RepoName) } return client, nil } -func handleSingleChart(chartData *ChartDeliveryData, chartRepo *commonmodels.HelmRepo, dir string) error { +func handleSingleChart(chartData *DeliveryChartData, chartRepo *commonmodels.HelmRepo, dir string) error { serviceObj := chartData.ServiceObj serviceName, revision := serviceObj.ServiceName, serviceObj.Revision base := config.LocalServicePathWithRevision(serviceObj.ProductName, serviceName, revision) @@ -230,9 +241,8 @@ func getChartmuseumError(b []byte, code int) error { return errors.Errorf("%d: %s", code, er.Error) } -func mkChartTGZFileDir(versionName string) (string, error) { - tmpDir := os.TempDir() - path := filepath.Join(tmpDir, "chart-tgz", versionName) +func mkChartTGZFileDir(productName, versionName string) (string, error) { + path := getChartTGZDir(productName, versionName) if err := os.RemoveAll(path); err != nil { if !os.IsExist(err) { return "", errors.Wrapf(err, "failed to claer dir for chart tgz files") @@ -260,17 +270,17 @@ func CreateHelmDeliveryVersion(args *CreateHelmDeliveryVersionArgs, logger *zap. repoInfo, err := getChartRepoData(args.ChartRepoName) if err != nil { log.Infof("failed to query chart-repo info, procutName: %s envName %s, err: %s", args.ProductName, args.EnvName, err) - return e.ErrCreateDeliveryVersion.AddDesc(fmt.Sprintf("failed to query chart-repo info, procutName: %s envName %s", args.ProductName, args.EnvName)) + return e.ErrCreateDeliveryVersion.AddDesc(fmt.Sprintf("failed to query chart-repo info, procutName: %s, envName %s, repoName", args.ProductName, args.EnvName, args.ChartRepoName)) } - dir, err := mkChartTGZFileDir(args.Version) + dir, err := mkChartTGZFileDir(args.ProductName, args.Version) if err != nil { return e.ErrCreateDeliveryVersion.AddErr(err) } // validate chartInfo, make sure service is in environment // prepare data set for chart delivery - chartDataMap := make(map[string]*ChartDeliveryData) + chartDataMap := make(map[string]*DeliveryChartData) serviceMap := productInfo.GetServiceMap() for _, chartDta := range args.ChartDatas { if productService, ok := serviceMap[chartDta.ServiceName]; ok { @@ -283,7 +293,7 @@ func CreateHelmDeliveryVersion(args *CreateHelmDeliveryVersionArgs, logger *zap. if err != nil { return e.ErrCreateDeliveryVersion.AddDesc(fmt.Sprintf("failed to query service: %s", chartDta.ServiceName)) } - chartDataMap[chartDta.ServiceName] = &ChartDeliveryData{ + chartDataMap[chartDta.ServiceName] = &DeliveryChartData{ ChartData: chartDta, ProductService: productService, ServiceObj: serviceObj, @@ -344,7 +354,7 @@ func CreateHelmDeliveryVersion(args *CreateHelmDeliveryVersionArgs, logger *zap. wg := sync.WaitGroup{} for _, chartData := range chartDataMap { wg.Add(1) - go func(cData *ChartDeliveryData) { + go func(cData *DeliveryChartData) { defer wg.Done() err := handleSingleChart(cData, repoInfo, dir) if err != nil { @@ -374,7 +384,9 @@ func CreateHelmDeliveryVersion(args *CreateHelmDeliveryVersionArgs, logger *zap. logger.Errorf("failed to create temp dir, err: %s", err) return } - defer os.RemoveAll(tmpDir) + defer func(path string) { + _ = os.RemoveAll(path) + }(tmpDir) //tar all chart files and send to s3 store fsTree := os.DirFS(dir) @@ -425,3 +437,143 @@ func ListDeliveryServiceNames(productName string, log *zap.SugaredLogger) ([]str return serviceNames.UnsortedList(), nil } + +func downloadChart(version *commonmodels.DeliveryVersion, chartInfo *commonmodels.DeliveryChart) (string, error) { + chartTGZName := fmt.Sprintf("%s-%s.tgz", chartInfo.Name, chartInfo.Version) + chartTGZFileParent := getChartTGZDir(version.ProductName, version.Version) + chartTGZFilePath := filepath.Join(chartTGZFileParent, chartTGZName) + if _, err := os.Stat(chartTGZFilePath); err == nil { + // local cache exists + log.Infof("local cache exists, path %s", chartTGZFilePath) + return chartTGZFilePath, nil + } + + chartRepo, err := getChartRepoData(chartInfo.Repo) + if err != nil { + return "", fmt.Errorf("failed to query chart-repo info, repoName %s", chartInfo.Repo) + } + + client, err := createChartRepoClient(chartRepo) + if err != nil { + return "", err + } + + if err = os.MkdirAll(chartTGZFileParent, 0644); err != nil { + return "", errors.Wrapf(err, "failed to craete tgz parent dir") + } + + out, err := os.Create(chartTGZFilePath) + if err != nil { + os.RemoveAll(chartTGZFilePath) + return "", errors.Wrapf(err, "failed to create chart tgz file") + } + + response, err := client.DownloadFile(fmt.Sprintf("charts/%s", chartTGZName)) + if err != nil { + return "", errors.Wrapf(err, "failed to download file") + } + + //helm.CreateChartPackage() + + if response.StatusCode != 200 { + return "", errors.Wrapf(err, "download file failed %s", chartTGZName) + } + + b, err := ioutil.ReadAll(response.Body) + defer response.Body.Close() + if err != nil { + return "", errors.Wrapf(err, "failed to read response data") + } + + defer func(out *os.File) { + _ = out.Close() + }(out) + + err = ioutil.WriteFile(chartTGZFilePath, b, 0644) + if err != nil { + return "", err + } + return chartTGZFilePath, nil +} + +func DownloadDeliveryChart(projectName, version string, chartName string, log *zap.SugaredLogger) (string, error) { + deliveryVersion, err := GetDeliveryVersion(&commonrepo.DeliveryVersionArgs{ + ProductName: projectName, + Version: version, + }, log) + if err != nil { + return "", err + } + + var chartInfo *commonmodels.DeliveryChart + for _, singleChart := range deliveryVersion.Charts { + if singleChart.Name == chartName { + chartInfo = singleChart + } + } + + if chartInfo == nil { + return "", fmt.Errorf("can't find target chart: %s", chartName) + } + + // prepare chart data + filePath, err := downloadChart(deliveryVersion, chartInfo) + if err != nil { + return "", err + } + + return filePath, err +} + +func PreviewDeliveryChart(projectName, version string, chartName string, log *zap.SugaredLogger) (*DeliveryChartResp, error) { + filePath, err := DownloadDeliveryChart(projectName, version, chartName, log) + if err != nil { + return nil, err + } + fileName := filepath.Base(filePath) + dstDir := getChartExpandDir(projectName, version) + + fileName = strings.TrimSuffix(fileName, filepath.Ext(fileName)) + dstDir = filepath.Join(dstDir, fileName) + + file, err := os.Open(filePath) + if err != nil { + return nil, errors.Wrap(err, "unable to open tarball") + } + defer file.Close() + + err = chartutil.Expand(dstDir, file) + if err != nil { + log.Errorf("failed to uncompress file: %s", filePath) + return nil, errors.Wrapf(err, "failed to uncompress file") + } + + ret := &DeliveryChartResp{ + FileInfos: make([]*types.FileInfo, 0), + } + + var fis []*types.FileInfo + files, err := os.ReadDir(filepath.Join(dstDir, chartName)) + if err != nil { + return nil, err + } + + for _, file := range files { + info, _ := file.Info() + if info == nil { + continue + } + fi := &types.FileInfo{ + Parent: "", + Name: file.Name(), + Size: info.Size(), + Mode: file.Type(), + ModTime: info.ModTime().Unix(), + IsDir: file.IsDir(), + } + + fis = append(fis, fi) + } + ret.FileInfos = fis + return ret, nil +} -- Gitee From 7598070a35d288c8969e7145fe48ab95f4fbec1f Mon Sep 17 00:00:00 2001 From: allenshen Date: Tue, 23 Nov 2021 12:21:43 +0800 Subject: [PATCH 004/134] add retry api Signed-off-by: allenshen --- .../repository/models/delivery_version.go | 40 +- .../repository/mongodb/template/product.go | 37 +- .../aslan/core/common/service/fs/s3.go | 25 +- .../aslan/core/common/service/s3/s3.go | 19 + .../aslan/core/delivery/handler/router.go | 2 + .../aslan/core/delivery/handler/version.go | 29 + .../aslan/core/delivery/service/version.go | 547 +++++++++++++----- .../aslan/core/environment/service/helm.go | 3 +- .../aslan/core/project/service/project.go | 26 +- pkg/setting/consts.go | 8 + 10 files changed, 553 insertions(+), 183 deletions(-) diff --git a/pkg/microservice/aslan/core/common/repository/models/delivery_version.go b/pkg/microservice/aslan/core/common/repository/models/delivery_version.go index 956070a35..c221d1af8 100644 --- a/pkg/microservice/aslan/core/common/repository/models/delivery_version.go +++ b/pkg/microservice/aslan/core/common/repository/models/delivery_version.go @@ -26,23 +26,31 @@ type DeliveryChart struct { Repo string `bson:"repo" json:"repo"` } +type DeliveryVersionProgress struct { + SuccessChartCount int `json:"successChartCount"` + TotalChartCount int `json:"totalChartCount"` + PackageUploadStatus string `json:"packageStatus"` + Error string `json:"error"` +} + type DeliveryVersion struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - Version string `bson:"version" json:"version"` - ProductName string `bson:"product_name" json:"productName"` - WorkflowName string `bson:"workflow_name" json:"workflowName"` - Type string `bson:"type" json:"type"` - TaskID int `bson:"task_id" json:"taskId"` - Desc string `bson:"desc" json:"desc"` - Labels []string `bson:"labels" json:"labels"` - ProductEnvInfo *Product `bson:"product_env_info" json:"productEnvInfo"` - Charts []*DeliveryChart `bson:"charts" json:"charts"` - Status string `bson:"status" json:"status"` - Error string `bson:"error" json:"error"` - CreateArgument interface{} `bson:"createArgument" json:"-"` - CreatedBy string `bson:"created_by" json:"createdBy"` - CreatedAt int64 `bson:"created_at" json:"created_at"` - DeletedAt int64 `bson:"deleted_at" json:"deleted_at"` + ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + Version string `bson:"version" json:"version"` + ProductName string `bson:"product_name" json:"productName"` + WorkflowName string `bson:"workflow_name" json:"workflowName"` + Type string `bson:"type" json:"type"` + TaskID int `bson:"task_id" json:"taskId"` + Desc string `bson:"desc" json:"desc"` + Labels []string `bson:"labels" json:"labels"` + ProductEnvInfo *Product `bson:"product_env_info" json:"productEnvInfo"` + Charts []*DeliveryChart `bson:"charts" json:"charts"` + Status string `bson:"status" json:"status"` + Error string `bson:"error" json:"error"` + Progress *DeliveryVersionProgress `bson:"-" json:"progress"` + CreateArgument interface{} `bson:"createArgument" json:"-"` + CreatedBy string `bson:"created_by" json:"createdBy"` + CreatedAt int64 `bson:"created_at" json:"created_at"` + DeletedAt int64 `bson:"deleted_at" json:"deleted_at"` } func (DeliveryVersion) TableName() string { diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/template/product.go b/pkg/microservice/aslan/core/common/repository/mongodb/template/product.go index c5d232276..88f038446 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/template/product.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/template/product.go @@ -39,6 +39,7 @@ type ProjectInfo struct { UpdatedBy string `bson:"update_by"` OnboardStatus int `bson:"onboarding_status"` Public bool `bson:"public"` + DeployType string `bson:"deploy_type"` } type ProductColl struct { @@ -82,8 +83,8 @@ func (c *ProductColl) FindProjectName(project string) (*template.Product, error) } func (c *ProductColl) ListNames(inNames []string) ([]string, error) { - res, err := c.listProjects(inNames, bson.D{ - {"product_name", 1}, + res, err := c.listProjects(inNames, bson.M{ + "product_name": "$product_name", }) if err != nil { return nil, err @@ -98,29 +99,34 @@ func (c *ProductColl) ListNames(inNames []string) ([]string, error) { } func (c *ProductColl) ListProjectBriefs(inNames []string) ([]*ProjectInfo, error) { - return c.listProjects(inNames, bson.D{ - {"product_name", 1}, - {"project_name", 1}, - {"description", 1}, - {"update_time", 1}, - {"update_by", 1}, - {"onboarding_status", 1}, - {"public", 1}, + return c.listProjects(inNames, bson.M{ + "product_name": "$product_name", + "project_name": "$project_name", + "description": "$description", + "update_time": "$update_time", + "update_by": "$update_by", + "onboarding_status": "$onboarding_status", + "public": "$public", + "deploy_type": "$product_feature.deploy_type", }) } -func (c *ProductColl) listProjects(inNames []string, projection bson.D) ([]*ProjectInfo, error) { - opts := options.Find() +func (c *ProductColl) listProjects(inNames []string, projection bson.M) ([]*ProjectInfo, error) { filter := bson.M{} if len(inNames) > 0 { filter["product_name"] = bson.M{"$in": inNames} } - if len(projection) > 0 { - opts.SetProjection(projection) + pipeline := []bson.M{ + { + "$match": filter, + }, + { + "$project": projection, + }, } - cursor, err := c.Collection.Find(context.TODO(), filter, opts) + cursor, err := c.Collection.Aggregate(context.TODO(), pipeline) if err != nil { return nil, err } @@ -130,7 +136,6 @@ func (c *ProductColl) listProjects(inNames []string, projection bson.D) ([]*Proj if err != nil { return nil, err } - return res, nil } diff --git a/pkg/microservice/aslan/core/common/service/fs/s3.go b/pkg/microservice/aslan/core/common/service/fs/s3.go index 0680a4c28..e792f0f2c 100644 --- a/pkg/microservice/aslan/core/common/service/fs/s3.go +++ b/pkg/microservice/aslan/core/common/service/fs/s3.go @@ -24,13 +24,32 @@ import ( "go.uber.org/zap" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/s3" s3service "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/s3" "github.com/koderover/zadig/pkg/setting" s3tool "github.com/koderover/zadig/pkg/tool/s3" fsutil "github.com/koderover/zadig/pkg/util/fs" ) +func ArchiveAndUploadFilesToSpecifiedS3(fileTree fs.FS, name, s3Base string, copies []string, s3Id string, logger *zap.SugaredLogger) error { + s3Storage, err := s3service.FindS3ById(s3Id) + if err != nil { + logger.Errorf("Failed to find default s3, err:%v", err) + return err + } + return archiveAndUploadFiles(fileTree, name, s3Base, copies, s3Storage, logger) +} + func ArchiveAndUploadFilesToS3(fileTree fs.FS, name, s3Base string, copies []string, logger *zap.SugaredLogger) error { + s3Storage, err := s3service.FindDefaultS3() + if err != nil { + logger.Errorf("Failed to find default s3, err:%v", err) + return err + } + return archiveAndUploadFiles(fileTree, name, s3Base, copies, s3Storage, logger) +} + +func archiveAndUploadFiles(fileTree fs.FS, name, s3Base string, copies []string, s3Storage *s3.S3, logger *zap.SugaredLogger) error { tmpDir, err := os.MkdirTemp("", "") if err != nil { logger.Errorf("Failed to create temp dir, err: %s", err) @@ -44,11 +63,7 @@ func ArchiveAndUploadFilesToS3(fileTree fs.FS, name, s3Base string, copies []str logger.Errorf("Failed to archive tarball %s, err: %s", localPath, err) return err } - s3Storage, err := s3service.FindDefaultS3() - if err != nil { - logger.Errorf("Failed to find default s3, err:%v", err) - return err - } + forcedPathStyle := true if s3Storage.Provider == setting.ProviderSourceAli { forcedPathStyle = false diff --git a/pkg/microservice/aslan/core/common/service/s3/s3.go b/pkg/microservice/aslan/core/common/service/s3/s3.go index 24655148c..7a7f31a75 100644 --- a/pkg/microservice/aslan/core/common/service/s3/s3.go +++ b/pkg/microservice/aslan/core/common/service/s3/s3.go @@ -148,6 +148,25 @@ func FindDefaultS3() (*S3, error) { return &S3{S3Storage: storage}, nil } +func FindS3ById(id string) (*S3, error) { + storage, err := commonrepo.NewS3StorageColl().Find(id) + if err != nil { + log.Warnf("Failed to find default s3 in db, err: %s", err) + return &S3{ + S3Storage: &models.S3Storage{ + Ak: config.S3StorageAK(), + Sk: config.S3StorageSK(), + Endpoint: config.S3StorageEndpoint(), + Bucket: config.S3StorageBucket(), + Insecure: config.S3StorageProtocol() == "http", + Provider: setting.ProviderSourceSystemDefault, + }, + }, nil + } + + return &S3{S3Storage: storage}, nil +} + // 获取内置的s3 func FindInternalS3() *S3 { storage := &models.S3Storage{ diff --git a/pkg/microservice/aslan/core/delivery/handler/router.go b/pkg/microservice/aslan/core/delivery/handler/router.go index 18ecc0de3..69b26bb4b 100644 --- a/pkg/microservice/aslan/core/delivery/handler/router.go +++ b/pkg/microservice/aslan/core/delivery/handler/router.go @@ -48,6 +48,8 @@ func (*Router) Inject(router *gin.RouterGroup) { deliveryRelease.GET("/charts", DownloadDeliveryChart) deliveryRelease.GET("/charts/preview", PreviewGetDeliveryChart) + deliveryRelease.GET("/charts/filePath", GetDeliveryChartFilePath) + deliveryRelease.GET("/charts/fileContent", GetDeliveryChartFileContent) deliveryRelease.POST("/helm", CreateHelmDeliveryVersion) diff --git a/pkg/microservice/aslan/core/delivery/handler/version.go b/pkg/microservice/aslan/core/delivery/handler/version.go index f91c4ec0b..b750ab623 100644 --- a/pkg/microservice/aslan/core/delivery/handler/version.go +++ b/pkg/microservice/aslan/core/delivery/handler/version.go @@ -152,6 +152,7 @@ func ListDeliveryVersion(c *gin.Context) { for _, deliveryVersion := range deliveryVersions { releaseInfo := new(ReleaseInfo) //versionInfo + deliveryVersion.Progress = deliveryservice.FillDeliveryProgressInfo(deliveryVersion) releaseInfo.VersionInfo = deliveryVersion //deployInfo @@ -412,3 +413,31 @@ func PreviewGetDeliveryChart(c *gin.Context) { ctx.Resp, ctx.Err = deliveryservice.PreviewDeliveryChart(projectName, versionName, chartName, ctx.Logger) } + +func GetDeliveryChartFilePath(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + args := new(deliveryservice.DeliveryChartFilePathArgs) + err := c.BindQuery(args) + if err != nil { + ctx.Err = e.ErrInvalidParam.AddErr(err) + return + } + + ctx.Resp, ctx.Err = deliveryservice.GetDeliveryChartFilePath(args, ctx.Logger) +} + +func GetDeliveryChartFileContent(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + args := new(deliveryservice.DeliveryChartFileContentArgs) + err := c.BindQuery(args) + if err != nil { + ctx.Err = e.ErrInvalidParam.AddErr(err) + return + } + + ctx.Resp, ctx.Err = deliveryservice.GetDeliveryChartFileContent(args, ctx.Logger) +} diff --git a/pkg/microservice/aslan/core/delivery/service/version.go b/pkg/microservice/aslan/core/delivery/service/version.go index 9973e81df..88eca22fa 100644 --- a/pkg/microservice/aslan/core/delivery/service/version.go +++ b/pkg/microservice/aslan/core/delivery/service/version.go @@ -23,7 +23,6 @@ import ( "net/http" "os" "path/filepath" - "strings" "sync" "time" @@ -49,7 +48,6 @@ import ( e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/log" "github.com/koderover/zadig/pkg/types" - fsutil "github.com/koderover/zadig/pkg/util/fs" ) type CreateHelmDeliveryVersionOption struct { @@ -65,30 +63,47 @@ type CreateHelmDeliveryVersionChartData struct { type CreateHelmDeliveryVersionArgs struct { CreateBy string `json:"-"` + ProductName string `json:"productName"` + Retry bool `json:"retry"` Version string `json:"version"` Desc string `json:"desc"` - ProductName string `json:"productName"` EnvName string `json:"envName"` Labels []string `json:"labels"` - ChartRepoName string `json:"chartRepoName"` + ImageRepoName string `json:"imageRepoName"` *DeliveryVersionChartData } type DeliveryVersionChartData struct { - ChartDatas []*CreateHelmDeliveryVersionChartData `json:"chartDatas"` - Options *CreateHelmDeliveryVersionOption `json:"options"` + ChartRepoName string `json:"chartRepoName"` + ImageRegistryID string `json:"imageRegistryID"` + ChartDatas []*CreateHelmDeliveryVersionChartData `json:"chartDatas"` + Options *CreateHelmDeliveryVersionOption `json:"options"` } type DeliveryChartData struct { - ChartData *CreateHelmDeliveryVersionChartData - ProductService *commonmodels.ProductService - ServiceObj *commonmodels.Service + ChartData *CreateHelmDeliveryVersionChartData + ServiceObj *commonmodels.Service } type DeliveryChartResp struct { FileInfos []*types.FileInfo `json:"fileInfos"` } +type DeliveryChartFilePathArgs struct { + Dir string `json:"dir"` + ProjectName string `json:"projectName"` + ChartName string `json:"chartName"` + Version string `json:"version"` +} + +type DeliveryChartFileContentArgs struct { + FilePath string `json:"filePath"` + FileName string `json:"fileName"` + ProjectName string `json:"projectName"` + ChartName string `json:"chartName"` + Version string `json:"version"` +} + func GetDeliveryVersion(args *commonrepo.DeliveryVersionArgs, log *zap.SugaredLogger) (*commonmodels.DeliveryVersion, error) { resp, err := commonrepo.NewDeliveryVersionColl().Get(args) if err != nil { @@ -116,6 +131,53 @@ func DeleteDeliveryVersion(args *commonrepo.DeliveryVersionArgs, log *zap.Sugare return nil } +func FillDeliveryProgressInfo(deliveryVersion *commonmodels.DeliveryVersion) *commonmodels.DeliveryVersionProgress { + if deliveryVersion.Type != setting.DeliveryVersionTypeChart { + return nil + } + successfulChartCount := len(deliveryVersion.Charts) + + progress := &commonmodels.DeliveryVersionProgress{ + SuccessChartCount: successfulChartCount, + TotalChartCount: 0, + PackageUploadStatus: "", + Error: "", + } + if deliveryVersion.Status == setting.DeliveryVersionStatusSuccess { + progress.TotalChartCount = successfulChartCount + progress.PackageUploadStatus = setting.DeliveryVersionPackageStatusSuccess + return progress + } + + argsBytes, err := json.Marshal(deliveryVersion.CreateArgument) + if err != nil { + log.Errorf("failed to marshal arguments, versionName: %s err %s", deliveryVersion.Version, err) + return progress + } + createArgs := new(DeliveryVersionChartData) + err = json.Unmarshal(argsBytes, createArgs) + if err != nil { + log.Errorf("failed to unMarshal arguments, versionName: %s err %s", deliveryVersion.Version, err) + return progress + } + + progress.TotalChartCount = len(createArgs.ChartDatas) + + if deliveryVersion.Status == setting.DeliveryVersionStatusFailed { + progress.PackageUploadStatus = setting.DeliveryVersionPackageStatusFailed + return progress + } + + if len(createArgs.ChartDatas) > successfulChartCount { + progress.PackageUploadStatus = setting.DeliveryVersionPackageStatusWaiting + return progress + } + + progress.PackageUploadStatus = setting.DeliveryVersionPackageStatusUploading + return progress + +} + func getChartTGZDir(productName, versionName string) string { tmpDir := os.TempDir() return filepath.Join(tmpDir, "chart-tgz", productName, versionName) @@ -169,6 +231,9 @@ func handleSingleChart(chartData *DeliveryChartData, chartRepo *commonmodels.Hel } } + // push 镜像 + //commonrepo.NewRegistryNamespaceColl().Find(&commonrepo.FindRegOps{}) + fullPath := filepath.Join(base, serviceObj.ServiceName) revisionBasePath := config.LocalDeliveryChartPathWithRevision(serviceObj.ProductName, serviceObj.ServiceName, serviceObj.Revision) deliveryChartPath := filepath.Join(revisionBasePath, serviceObj.ServiceName) @@ -241,7 +306,7 @@ func getChartmuseumError(b []byte, code int) error { return errors.Errorf("%d: %s", code, er.Error) } -func mkChartTGZFileDir(productName, versionName string) (string, error) { +func makeChartTGZFileDir(productName, versionName string) (string, error) { path := getChartTGZDir(productName, versionName) if err := os.RemoveAll(path); err != nil { if !os.IsExist(err) { @@ -256,51 +321,136 @@ func mkChartTGZFileDir(productName, versionName string) (string, error) { } func CreateHelmDeliveryVersion(args *CreateHelmDeliveryVersionArgs, logger *zap.SugaredLogger) error { - // need appoint chart info - if len(args.ChartDatas) == 0 { - return e.ErrCreateDeliveryVersion.AddDesc("no chart info appointed") - } - - // prepare data - productInfo, err := getProductEnvInfo(args.ProductName, args.EnvName) - if err != nil { - log.Infof("failed to query product info, procutName: %s envName %s, err: %s", args.ProductName, args.EnvName, err) - return e.ErrCreateDeliveryVersion.AddDesc(fmt.Sprintf("failed to query product info, procutName: %s envName %s", args.ProductName, args.EnvName)) - } - repoInfo, err := getChartRepoData(args.ChartRepoName) - if err != nil { - log.Infof("failed to query chart-repo info, procutName: %s envName %s, err: %s", args.ProductName, args.EnvName, err) - return e.ErrCreateDeliveryVersion.AddDesc(fmt.Sprintf("failed to query chart-repo info, procutName: %s, envName %s, repoName", args.ProductName, args.EnvName, args.ChartRepoName)) - } - - dir, err := mkChartTGZFileDir(args.ProductName, args.Version) - if err != nil { - return e.ErrCreateDeliveryVersion.AddErr(err) + if args.Retry { + return RetryCreateHelmDeliveryVersion(args.ProductName, args.Version, logger) + } else { + return CreateNewHelmDeliveryVersion(args, logger) } +} - // validate chartInfo, make sure service is in environment - // prepare data set for chart delivery +// validate chartInfo, make sure service is in environment +// prepare data set for chart delivery +func prepareChartData(chartDatas []*CreateHelmDeliveryVersionChartData, productInfo *commonmodels.Product) (map[string]*DeliveryChartData, error) { chartDataMap := make(map[string]*DeliveryChartData) serviceMap := productInfo.GetServiceMap() - for _, chartDta := range args.ChartDatas { + for _, chartDta := range chartDatas { if productService, ok := serviceMap[chartDta.ServiceName]; ok { serviceObj, err := commonrepo.NewServiceColl().Find(&commonrepo.ServiceFindOption{ ServiceName: chartDta.ServiceName, Revision: productService.Revision, Type: setting.HelmDeployType, - ProductName: args.ProductName, + ProductName: productInfo.ProductName, }) if err != nil { - return e.ErrCreateDeliveryVersion.AddDesc(fmt.Sprintf("failed to query service: %s", chartDta.ServiceName)) + return nil, fmt.Errorf("failed to query service: %s", chartDta.ServiceName) } chartDataMap[chartDta.ServiceName] = &DeliveryChartData{ - ChartData: chartDta, - ProductService: productService, - ServiceObj: serviceObj, + ChartData: chartDta, + //ProductService: productService, + ServiceObj: serviceObj, } } else { - return e.ErrCreateDeliveryVersion.AddDesc(fmt.Sprintf("service %s not found in environment", chartDta.ServiceName)) + return nil, fmt.Errorf("service %s not found in environment", chartDta.ServiceName) + } + } + return chartDataMap, nil +} + +func buildDeliveryCharts(chartDataMap map[string]*DeliveryChartData, deliveryVersion *commonmodels.DeliveryVersion, args *DeliveryVersionChartData, logger *zap.SugaredLogger) (err error) { + defer func() { + if err != nil { + deliveryVersion.Status = setting.DeliveryVersionStatusFailed + deliveryVersion.Error = err.Error() + } else { + deliveryVersion.Status = setting.DeliveryVersionStatusSuccess + deliveryVersion.Error = "" + } + err = commonrepo.NewDeliveryVersionColl().UpdateStatusByName(deliveryVersion.Version, deliveryVersion.Status, deliveryVersion.Error) + if err != nil { + logger.Errorf("failed to update delivery version data, name: %s error: %s", deliveryVersion.Version, err) } + }() + + var errLock sync.Mutex + errorList := &multierror.Error{} + + appendError := func(err error) { + errLock.Lock() + defer errLock.Unlock() + errorList = multierror.Append(errorList, err) + } + + dir, err := makeChartTGZFileDir(deliveryVersion.ProductName, deliveryVersion.Version) + if err != nil { + return err + } + repoInfo, err := getChartRepoData(args.ChartRepoName) + if err != nil { + log.Infof("failed to query chart-repo info, productName: %s, err: %s", deliveryVersion.ProductName, err) + return fmt.Errorf("failed to query chart-repo info, productName: %s, repoName: %s", deliveryVersion.ProductName, args.ChartRepoName) + } + + // push charts to repo + wg := sync.WaitGroup{} + for _, chartData := range chartDataMap { + wg.Add(1) + go func(cData *DeliveryChartData) { + defer wg.Done() + err := handleSingleChart(cData, repoInfo, dir) + if err != nil { + logger.Errorf("failed to handle single chart data, serviceName: %s err: %s", cData.ChartData.ServiceName, err) + appendError(err) + } else { + err = commonrepo.NewDeliveryVersionColl().AddDeliveryChart(deliveryVersion.Version, &commonmodels.DeliveryChart{ + Name: cData.ChartData.ServiceName, + Version: cData.ChartData.Version, + Repo: args.ChartRepoName, + }) + if err != nil { + appendError(errors.Wrapf(err, "failed to save delivery chart: %s", cData.ChartData.ServiceName)) + } + } + }(chartData) + } + wg.Wait() + + if errorList.ErrorOrNil() != nil { + err = errorList.ErrorOrNil() + return + } + + // no need to upload chart packages + if args.Options == nil || !args.Options.EnableOfflineDist { + return + } + + //tar all chart files and send to s3 store + fsTree := os.DirFS(dir) + ServiceS3Base := configbase.ObjectStorageDeliveryVersionPath(deliveryVersion.ProductName) + if err = fsservice.ArchiveAndUploadFilesToSpecifiedS3(fsTree, deliveryVersion.Version, ServiceS3Base, nil, args.Options.S3StorageID, logger); err != nil { + logger.Errorf("failed to upload chart package files for project %s, err: %s", deliveryVersion.ProductName, err) + err = errors.Wrapf(err, "failed to upload package file") + return + } + return +} + +func CreateNewHelmDeliveryVersion(args *CreateHelmDeliveryVersionArgs, logger *zap.SugaredLogger) error { + // need appoint chart info + if len(args.ChartDatas) == 0 { + return e.ErrCreateDeliveryVersion.AddDesc("no chart info appointed") + } + + // prepare data + productInfo, err := getProductEnvInfo(args.ProductName, args.EnvName) + if err != nil { + log.Infof("failed to query product info, productName: %s envName %s, err: %s", args.ProductName, args.EnvName, err) + return e.ErrCreateDeliveryVersion.AddDesc(fmt.Sprintf("failed to query product info, procutName: %s envName %s", args.ProductName, args.EnvName)) + } + + chartDataMap, err := prepareChartData(args.ChartDatas, productInfo) + if err != nil { + return e.ErrCreateDeliveryVersion.AddErr(err) } productInfo.ID, _ = primitive.ObjectIDFromHex("") @@ -322,91 +472,149 @@ func CreateHelmDeliveryVersion(args *CreateHelmDeliveryVersionArgs, logger *zap. err = commonrepo.NewDeliveryVersionColl().Insert(versionObj) if err != nil { logger.Errorf("failed to insert version data, err: %s", err) - return fmt.Errorf("failed to insert delivery version: %s", versionObj.Version) + return e.ErrCreateDeliveryVersion.AddErr(fmt.Errorf("failed to insert delivery version: %s", versionObj.Version)) } - go func() { - var err error - defer func() { - if err != nil { - versionObj.Status = setting.DeliveryVersionStatusFailed - versionObj.Error = err.Error() - } else { - versionObj.Status = setting.DeliveryVersionStatusSuccess - versionObj.Error = "" - } - err = commonrepo.NewDeliveryVersionColl().UpdateStatusByName(versionObj.Version, versionObj.Status, versionObj.Error) - if err != nil { - logger.Errorf("failed to update delivery version data, name: %s error: %s", versionObj.Version, err) - } - }() + err = buildDeliveryCharts(chartDataMap, versionObj, args.DeliveryVersionChartData, logger) + if err != nil { + return err + } - var errLock sync.Mutex - errorList := &multierror.Error{} + //go func() { + // var err error + // defer func() { + // if err != nil { + // versionObj.Status = setting.DeliveryVersionStatusFailed + // versionObj.Error = err.Error() + // } else { + // versionObj.Status = setting.DeliveryVersionStatusSuccess + // versionObj.Error = "" + // } + // err = commonrepo.NewDeliveryVersionColl().UpdateStatusByName(versionObj.Version, versionObj.Status, versionObj.Error) + // if err != nil { + // logger.Errorf("failed to update delivery version data, name: %s error: %s", versionObj.Version, err) + // } + // }() + // + // var errLock sync.Mutex + // errorList := &multierror.Error{} + // + // appendError := func(err error) { + // errLock.Lock() + // defer errLock.Unlock() + // errorList = multierror.Append(errorList, err) + // } + // + // // push charts to repo + // wg := sync.WaitGroup{} + // for _, chartData := range chartDataMap { + // wg.Add(1) + // go func(cData *DeliveryChartData) { + // defer wg.Done() + // err := handleSingleChart(cData, repoInfo, dir) + // if err != nil { + // logger.Errorf("failed to handle single chart data, serviceName: %s err: %s", cData.ChartData.ServiceName, err) + // appendError(err) + // } else { + // err = commonrepo.NewDeliveryVersionColl().AddDeliveryChart(versionObj.Version, &commonmodels.DeliveryChart{ + // Name: cData.ChartData.ServiceName, + // Version: cData.ChartData.Version, + // Repo: args.ChartRepoName, + // }) + // if err != nil { + // appendError(errors.Wrapf(err, "failed to save delivery chart: %s", cData.ChartData.ServiceName)) + // } + // } + // }(chartData) + // } + // wg.Wait() + // + // if errorList.ErrorOrNil() != nil { + // err = errorList.ErrorOrNil() + // return + // } + // + // // no need to upload chart packages + // if args.Options == nil || !args.Options.EnableOfflineDist { + // return + // } + // + // //tar all chart files and send to s3 store + // fsTree := os.DirFS(dir) + // ServiceS3Base := configbase.ObjectStorageDeliveryVersionPath(args.ProductName) + // if err = fsservice.ArchiveAndUploadFilesToSpecifiedS3(fsTree, versionObj.Version, ServiceS3Base, nil, args.Options.S3StorageID, logger); err != nil { + // logger.Errorf("failed to upload chart package files for project %s, err: %s", args.ProductName, err) + // err = errors.Wrapf(err, "failed to upload package file") + // return + // } + //}() - appendError := func(err error) { - errLock.Lock() - defer errLock.Unlock() - errorList = multierror.Append(errorList, err) - } + return nil +} - // push charts to repo - wg := sync.WaitGroup{} - for _, chartData := range chartDataMap { - wg.Add(1) - go func(cData *DeliveryChartData) { - defer wg.Done() - err := handleSingleChart(cData, repoInfo, dir) - if err != nil { - logger.Errorf("failed to handle single chart data, serviceName: %s err: %s", cData.ChartData.ServiceName, err) - appendError(err) - } else { - err = commonrepo.NewDeliveryVersionColl().AddDeliveryChart(versionObj.Version, &commonmodels.DeliveryChart{ - Name: cData.ServiceObj.ServiceName, - Version: cData.ChartData.Version, - Repo: args.ChartRepoName, - }) - if err != nil { - appendError(errors.Wrapf(err, "failed to save delivery chart: %s", cData.ChartData.ServiceName)) - } - } - }(chartData) - } - wg.Wait() +func RetryCreateHelmDeliveryVersion(projectName, versionName string, logger *zap.SugaredLogger) error { + deliveryVersion, err := commonrepo.NewDeliveryVersionColl().Get(&commonrepo.DeliveryVersionArgs{ + ProductName: projectName, + Version: versionName, + }) + if err != nil { + logger.Errorf("failed to query delivery version data, verisonName: %s, error: %s", versionName, err) + return fmt.Errorf("failed to query delivery version data, verisonName: %s", versionName) + } - if errorList.ErrorOrNil() != nil { - err = errorList.ErrorOrNil() - return - } + if deliveryVersion.Status != setting.DeliveryVersionStatusFailed { + return fmt.Errorf("can't reCreate version with status:%s", deliveryVersion.Status) + } + + argsBytes, err := json.Marshal(deliveryVersion.CreateArgument) + if err != nil { + return errors.Wrapf(err, "failed to marshal arguments, versionName: %s err %s", deliveryVersion.Version) + } + createArgs := new(DeliveryVersionChartData) + err = json.Unmarshal(argsBytes, createArgs) + if err != nil { + return errors.Wrapf(err, "failed to unMarshal arguments, versionName: %s err %s", deliveryVersion.Version) + } + + productInfoSnap := deliveryVersion.ProductEnvInfo - tmpDir, err := os.MkdirTemp("", "delivery-") + // for charts has been successfully handled, download charts directly + successCharts := sets.NewString() + for _, singleChart := range deliveryVersion.Charts { + // prepare chart data + _, err := downloadChart(projectName, versionName, singleChart) if err != nil { - logger.Errorf("failed to create temp dir, err: %s", err) - return - } - defer func(path string) { - _ = os.RemoveAll(path) - }(tmpDir) - - //tar all chart files and send to s3 store - fsTree := os.DirFS(dir) - tarball := fmt.Sprintf("%s.tar.gz", versionObj.Version) - localPath := filepath.Join(tmpDir, tarball) - if err = fsutil.Tar(fsTree, localPath); err != nil { - logger.Errorf("failed to archive tarball %s, err: %s", localPath, err) - versionObj.Status = setting.DeliveryVersionStatusFailed - err = errors.Wrapf(err, "failed to archive chart files, path %s", localPath) - return + log.Errorf("failed to download chart from chart repo, chartName: %s, err: %s", singleChart.Name, err) + continue } + successCharts.Insert(singleChart.Name) + } - ServiceS3Base := configbase.ObjectStorageDeliveryVersionPath(args.ProductName) - if err = fsservice.ArchiveAndUploadFilesToS3(fsTree, versionObj.Version, ServiceS3Base, nil, logger); err != nil { - logger.Errorf("failed to upload chart package files for project %s, err: %s", args.ProductName, err) - err = errors.Wrapf(err, "failed to upload package file") - return + chartsToBeHandled := make([]*CreateHelmDeliveryVersionChartData, 0) + for _, chartConfig := range createArgs.ChartDatas { + if successCharts.Has(chartConfig.ServiceName) { + continue } + chartsToBeHandled = append(chartsToBeHandled, chartConfig) + } - }() + chartDataMap, err := prepareChartData(chartsToBeHandled, productInfoSnap) + if err != nil { + return e.ErrCreateDeliveryVersion.AddErr(err) + } + + err = buildDeliveryCharts(chartDataMap, deliveryVersion, createArgs, logger) + if err != nil { + return err + } + + // update status + deliveryVersion.Status = setting.DeliveryVersionStatusRetrying + err = commonrepo.NewDeliveryVersionColl().UpdateStatusByName(deliveryVersion.Version, deliveryVersion.Status, "") + if err != nil { + logger.Errorf("failed to update delivery status, name: %s, err: %s", deliveryVersion.Version, err) + return fmt.Errorf("failed to update delivery status, name: %s", deliveryVersion.Version) + } return nil } @@ -438,9 +646,9 @@ func ListDeliveryServiceNames(productName string, log *zap.SugaredLogger) ([]str return serviceNames.UnsortedList(), nil } -func downloadChart(version *commonmodels.DeliveryVersion, chartInfo *commonmodels.DeliveryChart) (string, error) { +func downloadChart(productName, versionName string, chartInfo *commonmodels.DeliveryChart) (string, error) { chartTGZName := fmt.Sprintf("%s-%s.tgz", chartInfo.Name, chartInfo.Version) - chartTGZFileParent := getChartTGZDir(version.ProductName, version.Version) + chartTGZFileParent := getChartTGZDir(productName, versionName) chartTGZFilePath := filepath.Join(chartTGZFileParent, chartTGZName) if _, err := os.Stat(chartTGZFilePath); err == nil { // local cache exists @@ -464,7 +672,7 @@ func downloadChart(version *commonmodels.DeliveryVersion, chartInfo *commonmodel out, err := os.Create(chartTGZFilePath) if err != nil { - os.RemoveAll(chartTGZFilePath) + _ = os.RemoveAll(chartTGZFilePath) return "", errors.Wrapf(err, "failed to create chart tgz file") } @@ -473,14 +681,12 @@ func downloadChart(version *commonmodels.DeliveryVersion, chartInfo *commonmodel return "", errors.Wrapf(err, "failed to download file") } - //helm.CreateChartPackage() - if response.StatusCode != 200 { return "", errors.Wrapf(err, "download file failed %s", chartTGZName) } + defer func() { _ = response.Body.Close() }() b, err := ioutil.ReadAll(response.Body) - defer response.Body.Close() if err != nil { return "", errors.Wrapf(err, "failed to read response data") } @@ -496,13 +702,13 @@ func downloadChart(version *commonmodels.DeliveryVersion, chartInfo *commonmodel return chartTGZFilePath, nil } -func DownloadDeliveryChart(projectName, version string, chartName string, log *zap.SugaredLogger) (string, error) { +func getChartConfigInfo(projectName, version string, chartName string, log *zap.SugaredLogger) (*commonmodels.DeliveryChart, error) { deliveryVersion, err := GetDeliveryVersion(&commonrepo.DeliveryVersionArgs{ ProductName: projectName, Version: version, }, log) if err != nil { - return "", err + return nil, err } var chartInfo *commonmodels.DeliveryChart @@ -513,39 +719,57 @@ func DownloadDeliveryChart(projectName, version string, chartName string, log *z } if chartInfo == nil { - return "", fmt.Errorf("can't find target chart: %s", chartName) + return nil, fmt.Errorf("can't find target chart: %s", chartName) } + return chartInfo, nil +} +func DownloadDeliveryChart(projectName, version string, chartName string, log *zap.SugaredLogger) (string, error) { + chartInfo, err := getChartConfigInfo(projectName, version, chartName, log) + if err != nil { + return "", err + } // prepare chart data - filePath, err := downloadChart(deliveryVersion, chartInfo) + filePath, err := downloadChart(projectName, version, chartInfo) if err != nil { return "", err } - return filePath, err } -func PreviewDeliveryChart(projectName, version string, chartName string, log *zap.SugaredLogger) (*DeliveryChartResp, error) { - filePath, err := DownloadDeliveryChart(projectName, version, chartName, log) +func preDownloadAndUncompressChart(projectName, versionName, chartName string, log *zap.SugaredLogger) (string, error) { + + chartInfo, err := getChartConfigInfo(projectName, versionName, chartName, log) if err != nil { - return nil, err + return "", err } - fileName := filepath.Base(filePath) - dstDir := getChartExpandDir(projectName, version) + dstDir := getChartExpandDir(projectName, versionName) + dstDir = filepath.Join(dstDir, fmt.Sprintf("%s-%s", chartInfo.Name, chartInfo.Version)) - fileName = strings.TrimSuffix(fileName, filepath.Ext(fileName)) - dstDir = filepath.Join(dstDir, fileName) + filePath, err := DownloadDeliveryChart(projectName, versionName, chartName, log) + if err != nil { + return "", err + } file, err := os.Open(filePath) if err != nil { - return nil, errors.Wrap(err, "unable to open tarball") + return "", errors.Wrap(err, "unable to open tarball") } - defer file.Close() + defer func() { _ = file.Close() }() err = chartutil.Expand(dstDir, file) if err != nil { log.Errorf("failed to uncompress file: %s", filePath) - return nil, errors.Wrapf(err, "failed to uncompress file") + return "", errors.Wrapf(err, "failed to uncompress file") + } + return dstDir, nil +} + +func PreviewDeliveryChart(projectName, version, chartName string, log *zap.SugaredLogger) (*DeliveryChartResp, error) { + + dstDir, err := preDownloadAndUncompressChart(projectName, version, chartName, log) + if err != nil { + return nil, err } ret := &DeliveryChartResp{ @@ -577,3 +801,60 @@ func PreviewDeliveryChart(projectName, version string, chartName string, log *za ret.FileInfos = fis return ret, nil } + +// load chart file infos +func loadChartFileInfos(fileDir, chartName string, dir string) ([]*types.FileInfo, error) { + var fis []*types.FileInfo + files, err := os.ReadDir(filepath.Join(fileDir, chartName, dir)) + if err != nil { + return nil, e.ErrFilePath.AddDesc(err.Error()) + } + + for _, file := range files { + info, _ := file.Info() + if info == nil { + continue + } + fi := &types.FileInfo{ + Parent: dir, + Name: file.Name(), + Size: info.Size(), + Mode: file.Type(), + ModTime: info.ModTime().Unix(), + IsDir: file.IsDir(), + } + fis = append(fis, fi) + } + return fis, nil +} + +func GetDeliveryChartFilePath(args *DeliveryChartFilePathArgs, log *zap.SugaredLogger) ([]*types.FileInfo, error) { + projectName, version, chartName := args.ProjectName, args.Version, args.ChartName + dstDir, err := preDownloadAndUncompressChart(projectName, version, chartName, log) + if err != nil { + return nil, nil + } + + fileInfos, err := loadChartFileInfos(dstDir, chartName, args.Dir) + if err != nil { + return nil, err + } + return fileInfos, nil +} + +func GetDeliveryChartFileContent(args *DeliveryChartFileContentArgs, log *zap.SugaredLogger) (string, error) { + projectName, version, chartName := args.ProjectName, args.Version, args.ChartName + dstDir, err := preDownloadAndUncompressChart(projectName, version, chartName, log) + if err != nil { + return "", nil + } + + file := filepath.Join(dstDir, chartName, args.FilePath, args.FileName) + fileContent, err := os.ReadFile(file) + if err != nil { + log.Errorf("Failed to read file %s, err: %s", file, err) + return "", e.ErrFileContent.AddDesc(err.Error()) + } + + return string(fileContent), nil +} diff --git a/pkg/microservice/aslan/core/environment/service/helm.go b/pkg/microservice/aslan/core/environment/service/helm.go index b4087f30a..98503c44f 100644 --- a/pkg/microservice/aslan/core/environment/service/helm.go +++ b/pkg/microservice/aslan/core/environment/service/helm.go @@ -180,7 +180,7 @@ func GetChartInfos(productName, envName, serviceName string, log *zap.SugaredLog if err != nil { return nil, e.ErrGetHelmCharts.AddErr(err) } - renderSet, err := FindHelmRenderSet(productName, envName, log) + renderSet, err := FindHelmRenderSet(productName, prod.Render.Name, log) if err != nil { log.Errorf("[%s][P:%s] find product renderset error: %v", envName, productName, err) return nil, e.ErrGetHelmCharts.AddErr(err) @@ -193,6 +193,7 @@ func GetChartInfos(productName, envName, serviceName string, log *zap.SugaredLog allServiceMap := prod.GetServiceMap() serviceMap := make(map[string]*models.ProductService) + //validate data, make sure service and chart info exists if len(serviceName) > 0 { serviceList := strings.Split(serviceName, ",") diff --git a/pkg/microservice/aslan/core/project/service/project.go b/pkg/microservice/aslan/core/project/service/project.go index 4c9e1fb92..196d63db0 100644 --- a/pkg/microservice/aslan/core/project/service/project.go +++ b/pkg/microservice/aslan/core/project/service/project.go @@ -41,12 +41,13 @@ type ProjectListOptions struct { type ProjectDetailedRepresentation struct { *ProjectBriefRepresentation - Alias string `json:"alias"` - Desc string `json:"desc"` - UpdatedAt int64 `json:"updatedAt"` - UpdatedBy string `json:"updatedBy"` - Onboard bool `json:"onboard"` - Public bool `json:"public"` + Alias string `json:"alias"` + Desc string `json:"desc"` + UpdatedAt int64 `json:"updatedAt"` + UpdatedBy string `json:"updatedBy"` + Onboard bool `json:"onboard"` + Public bool `json:"public"` + DeployType string `json:"deployType"` } type ProjectBriefRepresentation struct { @@ -98,12 +99,13 @@ func listDetailedProjectInfos(opts *ProjectListOptions, logger *zap.SugaredLogge ProjectMinimalRepresentation: &ProjectMinimalRepresentation{Name: name}, Envs: nameWithEnvMap[name], }, - Alias: info.Alias, - Desc: info.Desc, - UpdatedAt: info.UpdatedAt, - UpdatedBy: info.UpdatedBy, - Onboard: info.OnboardStatus != 0, - Public: info.Public, + Alias: info.Alias, + Desc: info.Desc, + UpdatedAt: info.UpdatedAt, + UpdatedBy: info.UpdatedBy, + Onboard: info.OnboardStatus != 0, + Public: info.Public, + DeployType: info.DeployType, }) } diff --git a/pkg/setting/consts.go b/pkg/setting/consts.go index dd37e7018..af9b8b8cd 100644 --- a/pkg/setting/consts.go +++ b/pkg/setting/consts.go @@ -331,6 +331,14 @@ const ( DeliveryVersionStatusSuccess = "success" DeliveryVersionStatusFailed = "failed" DeliveryVersionStatusCreating = "creating" + DeliveryVersionStatusRetrying = "retrying" +) + +const ( + DeliveryVersionPackageStatusSuccess = "success" + DeliveryVersionPackageStatusFailed = "failed" + DeliveryVersionPackageStatusWaiting = "waiting" + DeliveryVersionPackageStatusUploading = "uploading" ) const ( -- Gitee From 7e5d3c95db95b0b8da299b8ddc8769bbb2146bd4 Mon Sep 17 00:00:00 2001 From: allenshen Date: Tue, 23 Nov 2021 16:15:48 +0800 Subject: [PATCH 005/134] add apply global variable api Signed-off-by: allenshen --- .../aslan/core/delivery/handler/router.go | 11 +- .../aslan/core/delivery/handler/version.go | 14 ++- .../aslan/core/delivery/service/version.go | 111 ++++++------------ 3 files changed, 56 insertions(+), 80 deletions(-) diff --git a/pkg/microservice/aslan/core/delivery/handler/router.go b/pkg/microservice/aslan/core/delivery/handler/router.go index 69b26bb4b..7e9b1f480 100644 --- a/pkg/microservice/aslan/core/delivery/handler/router.go +++ b/pkg/microservice/aslan/core/delivery/handler/router.go @@ -46,13 +46,12 @@ func (*Router) Inject(router *gin.RouterGroup) { deliveryRelease.GET("", ListDeliveryVersion) deliveryRelease.DELETE("/:id", GetProductNameByDelivery, gin2.UpdateOperationLogStatus, DeleteDeliveryVersion) - deliveryRelease.GET("/charts", DownloadDeliveryChart) - deliveryRelease.GET("/charts/preview", PreviewGetDeliveryChart) - deliveryRelease.GET("/charts/filePath", GetDeliveryChartFilePath) - deliveryRelease.GET("/charts/fileContent", GetDeliveryChartFileContent) - deliveryRelease.POST("/helm", CreateHelmDeliveryVersion) - + deliveryRelease.POST("/helm/global-variables", ApplyDeliveryGlobalVariables) + deliveryRelease.GET("/helm/charts", DownloadDeliveryChart) + deliveryRelease.GET("/helm/charts/preview", PreviewGetDeliveryChart) + deliveryRelease.GET("/helm/charts/filePath", GetDeliveryChartFilePath) + deliveryRelease.GET("/helm/charts/fileContent", GetDeliveryChartFileContent) } deliveryPackage := router.Group("packages") diff --git a/pkg/microservice/aslan/core/delivery/handler/version.go b/pkg/microservice/aslan/core/delivery/handler/version.go index b750ab623..1d11d6350 100644 --- a/pkg/microservice/aslan/core/delivery/handler/version.go +++ b/pkg/microservice/aslan/core/delivery/handler/version.go @@ -438,6 +438,18 @@ func GetDeliveryChartFileContent(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddErr(err) return } - ctx.Resp, ctx.Err = deliveryservice.GetDeliveryChartFileContent(args, ctx.Logger) } + +func ApplyDeliveryGlobalVariables(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + args := new(deliveryservice.DeliveryVariablesApplyArgs) + err := c.BindJSON(args) + if err != nil { + ctx.Err = e.ErrInvalidParam.AddErr(err) + return + } + ctx.Resp, ctx.Err = deliveryservice.ApplyDeliveryGlobalVariables(args, ctx.Logger) +} diff --git a/pkg/microservice/aslan/core/delivery/service/version.go b/pkg/microservice/aslan/core/delivery/service/version.go index 88eca22fa..c764572b4 100644 --- a/pkg/microservice/aslan/core/delivery/service/version.go +++ b/pkg/microservice/aslan/core/delivery/service/version.go @@ -26,6 +26,8 @@ import ( "sync" "time" + yamlutil "github.com/koderover/zadig/pkg/util/yaml" + cm "github.com/chartmuseum/helm-push/pkg/chartmuseum" "github.com/chartmuseum/helm-push/pkg/helm" "github.com/hashicorp/go-multierror" @@ -57,7 +59,7 @@ type CreateHelmDeliveryVersionOption struct { type CreateHelmDeliveryVersionChartData struct { ServiceName string `json:"serviceName"` - Version string `json:"version"` + Version string `json:"version,omitempty"` ValuesYamlContent string `json:"valuesYamlContent"` } @@ -74,6 +76,7 @@ type CreateHelmDeliveryVersionArgs struct { } type DeliveryVersionChartData struct { + GlobalVariables string `json:"globalVariables"` ChartRepoName string `json:"chartRepoName"` ImageRegistryID string `json:"imageRegistryID"` ChartDatas []*CreateHelmDeliveryVersionChartData `json:"chartDatas"` @@ -104,6 +107,11 @@ type DeliveryChartFileContentArgs struct { Version string `json:"version"` } +type DeliveryVariablesApplyArgs struct { + GlobalVariables string `json:"globalVariables,omitempty"` + ChartDatas []*CreateHelmDeliveryVersionChartData `json:"chartDatas"` +} + func GetDeliveryVersion(args *commonrepo.DeliveryVersionArgs, log *zap.SugaredLogger) (*commonmodels.DeliveryVersion, error) { resp, err := commonrepo.NewDeliveryVersionColl().Get(args) if err != nil { @@ -217,7 +225,7 @@ func createChartRepoClient(repo *commonmodels.HelmRepo) (*cm.Client, error) { return client, nil } -func handleSingleChart(chartData *DeliveryChartData, chartRepo *commonmodels.HelmRepo, dir string) error { +func handleSingleChart(chartData *DeliveryChartData, chartRepo *commonmodels.HelmRepo, dir string, globalVariables string) error { serviceObj := chartData.ServiceObj serviceName, revision := serviceObj.ServiceName, serviceObj.Revision base := config.LocalServicePathWithRevision(serviceObj.ProductName, serviceName, revision) @@ -252,13 +260,23 @@ func handleSingleChart(chartData *DeliveryChartData, chartRepo *commonmodels.Hel chartRequested.Metadata.Name = chartData.ChartData.ServiceName chartRequested.Metadata.Version = chartData.ChartData.Version chartRequested.Metadata.AppVersion = chartData.ChartData.Version - if len(chartData.ChartData.ValuesYamlContent) > 0 { + + if len(chartData.ChartData.ValuesYamlContent) > 0 { // values.yaml was edited directly valuesInfo := make(map[string]interface{}) if err = yaml.Unmarshal([]byte(chartData.ChartData.ValuesYamlContent), map[string]interface{}{}); err != nil { log.Errorf("invalid yaml content, serviceName: %s, yamlContent: %s", serviceObj.ServiceName, chartData.ChartData.ValuesYamlContent) return errors.Wrapf(err, "invalid yaml content for service: %s", serviceObj.ServiceName) } chartRequested.Values = valuesInfo + } else if len(globalVariables) > 0 { // merge global variables + curValuesStr, err := yaml.Marshal(chartRequested.Values) + if err != nil { + return errors.Wrapf(err, "failed to marshal values.yaml for service: %s", serviceObj.ServiceName) + } + chartRequested.Values, err = yamlutil.MergeAndUnmarshal([][]byte{curValuesStr, []byte(globalVariables)}) + if err != nil { + return errors.Wrapf(err, "failed to merge global variables for service: %s", serviceObj.ServiceName) + } } chartPackagePath, err := helm.CreateChartPackage(&helm.Chart{Chart: chartRequested}, dir) @@ -286,6 +304,7 @@ func handleSingleChart(chartData *DeliveryChartData, chartRepo *commonmodels.Hel func handlePushResponse(resp *http.Response) error { if resp.StatusCode != 201 && resp.StatusCode != 202 { b, err := ioutil.ReadAll(resp.Body) + defer resp.Body.Close() if err != nil { return err } @@ -396,7 +415,7 @@ func buildDeliveryCharts(chartDataMap map[string]*DeliveryChartData, deliveryVer wg.Add(1) go func(cData *DeliveryChartData) { defer wg.Done() - err := handleSingleChart(cData, repoInfo, dir) + err := handleSingleChart(cData, repoInfo, dir, args.GlobalVariables) if err != nil { logger.Errorf("failed to handle single chart data, serviceName: %s err: %s", cData.ChartData.ServiceName, err) appendError(err) @@ -480,75 +499,6 @@ func CreateNewHelmDeliveryVersion(args *CreateHelmDeliveryVersionArgs, logger *z return err } - //go func() { - // var err error - // defer func() { - // if err != nil { - // versionObj.Status = setting.DeliveryVersionStatusFailed - // versionObj.Error = err.Error() - // } else { - // versionObj.Status = setting.DeliveryVersionStatusSuccess - // versionObj.Error = "" - // } - // err = commonrepo.NewDeliveryVersionColl().UpdateStatusByName(versionObj.Version, versionObj.Status, versionObj.Error) - // if err != nil { - // logger.Errorf("failed to update delivery version data, name: %s error: %s", versionObj.Version, err) - // } - // }() - // - // var errLock sync.Mutex - // errorList := &multierror.Error{} - // - // appendError := func(err error) { - // errLock.Lock() - // defer errLock.Unlock() - // errorList = multierror.Append(errorList, err) - // } - // - // // push charts to repo - // wg := sync.WaitGroup{} - // for _, chartData := range chartDataMap { - // wg.Add(1) - // go func(cData *DeliveryChartData) { - // defer wg.Done() - // err := handleSingleChart(cData, repoInfo, dir) - // if err != nil { - // logger.Errorf("failed to handle single chart data, serviceName: %s err: %s", cData.ChartData.ServiceName, err) - // appendError(err) - // } else { - // err = commonrepo.NewDeliveryVersionColl().AddDeliveryChart(versionObj.Version, &commonmodels.DeliveryChart{ - // Name: cData.ChartData.ServiceName, - // Version: cData.ChartData.Version, - // Repo: args.ChartRepoName, - // }) - // if err != nil { - // appendError(errors.Wrapf(err, "failed to save delivery chart: %s", cData.ChartData.ServiceName)) - // } - // } - // }(chartData) - // } - // wg.Wait() - // - // if errorList.ErrorOrNil() != nil { - // err = errorList.ErrorOrNil() - // return - // } - // - // // no need to upload chart packages - // if args.Options == nil || !args.Options.EnableOfflineDist { - // return - // } - // - // //tar all chart files and send to s3 store - // fsTree := os.DirFS(dir) - // ServiceS3Base := configbase.ObjectStorageDeliveryVersionPath(args.ProductName) - // if err = fsservice.ArchiveAndUploadFilesToSpecifiedS3(fsTree, versionObj.Version, ServiceS3Base, nil, args.Options.S3StorageID, logger); err != nil { - // logger.Errorf("failed to upload chart package files for project %s, err: %s", args.ProductName, err) - // err = errors.Wrapf(err, "failed to upload package file") - // return - // } - //}() - return nil } @@ -858,3 +808,18 @@ func GetDeliveryChartFileContent(args *DeliveryChartFileContentArgs, log *zap.Su return string(fileContent), nil } + +func ApplyDeliveryGlobalVariables(args *DeliveryVariablesApplyArgs, log *zap.SugaredLogger) (interface{}, error) { + ret := new(DeliveryVariablesApplyArgs) + for _, chartData := range args.ChartDatas { + mergedYaml, err := yamlutil.Merge([][]byte{[]byte(chartData.ValuesYamlContent), []byte(args.GlobalVariables)}) + if err != nil { + return nil, errors.Wrapf(err, "failed to merge global variable for service: %s", chartData.ServiceName) + } + ret.ChartDatas = append(ret.ChartDatas, &CreateHelmDeliveryVersionChartData{ + ServiceName: chartData.ServiceName, + ValuesYamlContent: string(mergedYaml), + }) + } + return ret, nil +} -- Gitee From 711066e2ac73bd47d4783a59eacb2d3166217e72 Mon Sep 17 00:00:00 2001 From: allenshen Date: Thu, 25 Nov 2021 11:18:38 +0800 Subject: [PATCH 006/134] fix compile error Signed-off-by: allenshen --- pkg/microservice/aslan/config/consts.go | 1 + .../repository/models/delivery_distribute.go | 2 + .../repository/models/delivery_version.go | 32 +- .../repository/mongodb/delivery_version.go | 32 +- .../aslan/core/common/service/service.go | 36 ++ .../aslan/core/delivery/handler/version.go | 190 +------ .../aslan/core/delivery/service/docker.go | 57 ++ .../aslan/core/delivery/service/version.go | 489 ++++++++++++++++-- .../aslan/core/environment/service/helm.go | 11 - pkg/setting/consts.go | 8 +- 10 files changed, 580 insertions(+), 278 deletions(-) create mode 100644 pkg/microservice/aslan/core/delivery/service/docker.go diff --git a/pkg/microservice/aslan/config/consts.go b/pkg/microservice/aslan/config/consts.go index 363760937..718b2bb4a 100644 --- a/pkg/microservice/aslan/config/consts.go +++ b/pkg/microservice/aslan/config/consts.go @@ -136,6 +136,7 @@ type DistributeType string const ( File DistributeType = "file" Image DistributeType = "image" + Chart DistributeType = "chart" ) type K8SClusterStatus string diff --git a/pkg/microservice/aslan/core/common/repository/models/delivery_distribute.go b/pkg/microservice/aslan/core/common/repository/models/delivery_distribute.go index db24294d6..24b87745f 100644 --- a/pkg/microservice/aslan/core/common/repository/models/delivery_distribute.go +++ b/pkg/microservice/aslan/core/common/repository/models/delivery_distribute.go @@ -28,6 +28,8 @@ type DeliveryDistribute struct { ServiceName string `bson:"service_name" json:"serviceName"` DistributeType config.DistributeType `bson:"distribute_type" json:"distributeType"` RegistryName string `bson:"registry_name" json:"registryName"` + Version string `bson:"version" json:"version"` + ChartRepoName string `bson:"chart_repo_name" json:"chartRepoName"` Namespace string `bson:"namespace" json:"namespace"` PackageFile string `bson:"package_file" json:"packageFile"` RemoteFileKey string `bson:"remote_file_key" json:"remoteFileKey"` diff --git a/pkg/microservice/aslan/core/common/repository/models/delivery_version.go b/pkg/microservice/aslan/core/common/repository/models/delivery_version.go index c221d1af8..8720ac8bc 100644 --- a/pkg/microservice/aslan/core/common/repository/models/delivery_version.go +++ b/pkg/microservice/aslan/core/common/repository/models/delivery_version.go @@ -20,11 +20,11 @@ import ( "go.mongodb.org/mongo-driver/bson/primitive" ) -type DeliveryChart struct { - Name string `bson:"name" json:"name"` - Version string `bson:"version" json:"version"` - Repo string `bson:"repo" json:"repo"` -} +//type DeliveryChart struct { +// Name string `bson:"name" json:"name"` +// Version string `bson:"version" json:"version"` +// Repo string `bson:"repo" json:"repo"` +//} type DeliveryVersionProgress struct { SuccessChartCount int `json:"successChartCount"` @@ -34,18 +34,18 @@ type DeliveryVersionProgress struct { } type DeliveryVersion struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - Version string `bson:"version" json:"version"` - ProductName string `bson:"product_name" json:"productName"` - WorkflowName string `bson:"workflow_name" json:"workflowName"` - Type string `bson:"type" json:"type"` - TaskID int `bson:"task_id" json:"taskId"` - Desc string `bson:"desc" json:"desc"` - Labels []string `bson:"labels" json:"labels"` - ProductEnvInfo *Product `bson:"product_env_info" json:"productEnvInfo"` - Charts []*DeliveryChart `bson:"charts" json:"charts"` + ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + Version string `bson:"version" json:"version"` + ProductName string `bson:"product_name" json:"productName"` + WorkflowName string `bson:"workflow_name" json:"workflowName"` + Type string `bson:"type" json:"type"` + TaskID int `bson:"task_id" json:"taskId"` + Desc string `bson:"desc" json:"desc"` + Labels []string `bson:"labels" json:"labels"` + ProductEnvInfo *Product `bson:"product_env_info" json:"productEnvInfo"` + //Charts []*DeliveryChart `bson:"charts" json:"charts"` Status string `bson:"status" json:"status"` - Error string `bson:"error" json:"error"` + Error string `bson:"error" json:"-"` Progress *DeliveryVersionProgress `bson:"-" json:"progress"` CreateArgument interface{} `bson:"createArgument" json:"-"` CreatedBy string `bson:"created_by" json:"createdBy"` diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go b/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go index ada39606b..05d7cb8bb 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go @@ -207,22 +207,22 @@ func (c *DeliveryVersionColl) UpdateStatusByName(versionName, status, errorStr s return err } -func (c *DeliveryVersionColl) AddDeliveryChart(versionName string, chartInfo *models.DeliveryChart) error { - query := bson.M{ - "version": versionName, - "deleted_at": 0, - "charts.name": bson.M{"$ne": chartInfo.Name}, - } - change := bson.M{ - "$push": bson.M{ - "charts": bson.M{ - "name": chartInfo.Name, - "version": chartInfo.Version, - "repo": chartInfo.Repo, - }, - }} - _, err := c.UpdateOne(context.TODO(), query, change) - return err +func (c *DeliveryVersionColl) AddDeliveryChart(versionName string, chartInfo *models.DeliveryDistribute) error { + //query := bson.M{ + // "version": versionName, + // "deleted_at": 0, + // "charts.name": bson.M{"$ne": chartInfo.Name}, + //} + //change := bson.M{ + // "$push": bson.M{ + // "charts": bson.M{ + // "name": chartInfo.Name, + // "version": chartInfo.Version, + // "repo": chartInfo.Repo, + // }, + // }} + //_, err := c.UpdateOne(context.TODO(), query, change) + return nil } func (c *DeliveryVersionColl) Update(args *models.DeliveryVersion) error { diff --git a/pkg/microservice/aslan/core/common/service/service.go b/pkg/microservice/aslan/core/common/service/service.go index 780409314..b5bb8a6b7 100644 --- a/pkg/microservice/aslan/core/common/service/service.go +++ b/pkg/microservice/aslan/core/common/service/service.go @@ -21,6 +21,7 @@ import ( "encoding/json" "errors" "fmt" + "net/url" "regexp" "strings" templ "text/template" @@ -614,6 +615,41 @@ func ExtractImageName(imageURI string) string { return "" } +// ExtractImageRegistry extract registry url from total image uri +func ExtractImageRegistry(imageURI string) (string, error) { + subMatchAll := imageParseRegex.FindStringSubmatch(imageURI) + exNames := imageParseRegex.SubexpNames() + for i, matchedStr := range subMatchAll { + if i != 0 && matchedStr != "" && matchedStr != ":" { + if exNames[i] == "repo" { + u, err := url.Parse(matchedStr) + if err != nil { + return "", err + } + if len(u.Scheme) > 0 { + matchedStr = strings.TrimPrefix(matchedStr, fmt.Sprintf("%s://", u.Scheme)) + } + return matchedStr, nil + } + } + } + return "", fmt.Errorf("failed to extract registry url") +} + +// ExtractImageTag extract image tag from total image uri +func ExtractImageTag(imageURI string) string { + subMatchAll := imageParseRegex.FindStringSubmatch(imageURI) + exNames := imageParseRegex.SubexpNames() + for i, matchedStr := range subMatchAll { + if i != 0 && matchedStr != "" && matchedStr != ":" { + if exNames[i] == "tag" { + return matchedStr + } + } + } + return "" +} + func parseImagesByPattern(nested map[string]interface{}, patterns []map[string]string) ([]*models.Container, error) { flatMap, err := converter.Flatten(nested) if err != nil { diff --git a/pkg/microservice/aslan/core/delivery/handler/version.go b/pkg/microservice/aslan/core/delivery/handler/version.go index 1d11d6350..10397ed47 100644 --- a/pkg/microservice/aslan/core/delivery/handler/version.go +++ b/pkg/microservice/aslan/core/delivery/handler/version.go @@ -17,19 +17,14 @@ limitations under the License. package handler import ( - "encoding/json" "fmt" - "strconv" "strings" "github.com/gin-gonic/gin" "github.com/koderover/zadig/pkg/microservice/aslan/config" - commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" - "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/base" deliveryservice "github.com/koderover/zadig/pkg/microservice/aslan/core/delivery/service" - workflowservice "github.com/koderover/zadig/pkg/microservice/aslan/core/workflow/service/workflow" internalhandler "github.com/koderover/zadig/pkg/shared/handler" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/log" @@ -65,190 +60,31 @@ func GetDeliveryVersion(c *gin.Context) { } version := new(commonrepo.DeliveryVersionArgs) version.ID = ID - ctx.Resp, ctx.Err = deliveryservice.GetDeliveryVersion(version, ctx.Logger) -} - -type ReleaseInfo struct { - VersionInfo *commonmodels.DeliveryVersion `json:"versionInfo"` - BuildInfo []*commonmodels.DeliveryBuild `json:"buildInfo"` - DeployInfo []*commonmodels.DeliveryDeploy `json:"deployInfo"` - TestInfo []*commonmodels.DeliveryTest `json:"testInfo"` - DistributeInfo []*commonmodels.DeliveryDistribute `json:"distributeInfo"` - SecurityInfo []*DeliverySecurityStats `json:"securityStatsInfo"` -} - -type DeliverySecurityStats struct { - ImageName string `json:"imageName"` - ImageID string `json:"imageId"` - DeliverySecurityStatsInfo DeliverySecurityStatsInfo `json:"deliverySecurityStatsInfo"` -} - -type DeliverySecurityStatsInfo struct { - Total int `json:"total"` - Unknown int `json:"unkown"` - Negligible int `json:"negligible"` - Low int `json:"low"` - Medium int `json:"medium"` - High int `json:"high"` - Critical int `json:"critical"` + ctx.Resp, ctx.Err = deliveryservice.GetDetailReleaseData(version, ctx.Logger) } func ListDeliveryVersion(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - taskIDStr := c.Query("taskId") - var taskID = 0 - var err error - if taskIDStr != "" { - taskID, err = strconv.Atoi(taskIDStr) - if err != nil { - ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) - return - } + args := new(deliveryservice.ListDeliveryVersionArgs) + err := c.BindQuery(args) + if err != nil { + ctx.Err = e.ErrInvalidParam.AddErr(err) + return } - perPageStr := c.Query("per_page") - pageStr := c.Query("page") - var ( - perPage int - page int - ) - if perPageStr == "" { - perPage = 20 - } else { - perPage, err = strconv.Atoi(perPageStr) - if err != nil { - ctx.Err = e.ErrInvalidParam.AddDesc(fmt.Sprintf("perPage args err :%s", err)) - return - } + if args.Page <= 0 { + args.Page = 1 } - - if pageStr == "" { - page = 1 - } else { - page, err = strconv.Atoi(pageStr) - if err != nil { - ctx.Err = e.ErrInvalidParam.AddDesc(fmt.Sprintf("page args err :%s", err)) - return - } + if args.PerPage <= 0 { + args.Page = 20 } - - serviceName := c.Query("serviceName") - - version := new(commonrepo.DeliveryVersionArgs) - version.ProductName = c.Query("projectName") - version.WorkflowName = c.Query("workflowName") - version.TaskID = taskID - version.PerPage = perPage - version.Page = page - deliveryVersions, err := deliveryservice.FindDeliveryVersion(version, ctx.Logger) - - if err != nil { - ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) - return + if len(args.Verbosity) == 0 { + args.Verbosity = deliveryservice.VerbosityDetailed } - releaseInfos := make([]*ReleaseInfo, 0) - for _, deliveryVersion := range deliveryVersions { - releaseInfo := new(ReleaseInfo) - //versionInfo - deliveryVersion.Progress = deliveryservice.FillDeliveryProgressInfo(deliveryVersion) - releaseInfo.VersionInfo = deliveryVersion - - //deployInfo - deliveryDeployArgs := new(commonrepo.DeliveryDeployArgs) - deliveryDeployArgs.ReleaseID = deliveryVersion.ID.Hex() - deliveryDeploys, err := deliveryservice.FindDeliveryDeploy(deliveryDeployArgs, ctx.Logger) - if err != nil { - ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) - } - // 查询条件serviceName - if serviceName != "" { - match := false - for _, deliveryDeploy := range deliveryDeploys { - if deliveryDeploy.ServiceName == serviceName { - match = true - break - } - } - if !match { - continue - } - } - // 将serviceName替换为服务名/服务组件的形式,用于前端展示 - for _, deliveryDeploy := range deliveryDeploys { - if deliveryDeploy.ContainerName != "" { - deliveryDeploy.ServiceName = deliveryDeploy.ServiceName + "/" + deliveryDeploy.ContainerName - } - } - releaseInfo.DeployInfo = deliveryDeploys - - //buildInfo - deliveryBuildArgs := new(commonrepo.DeliveryBuildArgs) - deliveryBuildArgs.ReleaseID = deliveryVersion.ID.Hex() - deliveryBuilds, err := deliveryservice.FindDeliveryBuild(deliveryBuildArgs, ctx.Logger) - if err != nil { - ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) - } - releaseInfo.BuildInfo = deliveryBuilds - - //testInfo - deliveryTestArgs := new(commonrepo.DeliveryTestArgs) - deliveryTestArgs.ReleaseID = deliveryVersion.ID.Hex() - deliveryTests, err := deliveryservice.FindDeliveryTest(deliveryTestArgs, ctx.Logger) - if err != nil { - ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) - } - releaseInfo.TestInfo = deliveryTests - - //securityStatsInfo - deliverySecurityStatss := make([]*DeliverySecurityStats, 0) - if pipelineTask, err := workflowservice.GetPipelineTaskV2(int64(deliveryVersion.TaskID), deliveryVersion.WorkflowName, config.WorkflowType, ctx.Logger); err == nil { - for _, subStage := range pipelineTask.Stages { - if subStage.TaskType == config.TaskSecurity { - subSecurityTaskMap := subStage.SubTasks - for _, subTask := range subSecurityTaskMap { - securityInfo, _ := base.ToSecurityTask(subTask) - - deliverySecurityStats := new(DeliverySecurityStats) - deliverySecurityStats.ImageName = securityInfo.ImageName - deliverySecurityStats.ImageID = securityInfo.ImageID - deliverySecurityStatsMap, err := deliveryservice.FindDeliverySecurityStatistics(securityInfo.ImageID, ctx.Logger) - if err != nil { - ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) - } - var transErr error - b, err := json.Marshal(deliverySecurityStatsMap) - if err != nil { - transErr = fmt.Errorf("marshal task error: %v", err) - } - - if err := json.Unmarshal(b, &deliverySecurityStats.DeliverySecurityStatsInfo); err != nil { - transErr = fmt.Errorf("unmarshal task error: %v", err) - } - if transErr != nil { - ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) - } - - deliverySecurityStatss = append(deliverySecurityStatss, deliverySecurityStats) - } - break - } - } - releaseInfo.SecurityInfo = deliverySecurityStatss - } - - //distributeInfo - deliveryDistributeArgs := new(commonrepo.DeliveryDistributeArgs) - deliveryDistributeArgs.ReleaseID = deliveryVersion.ID.Hex() - deliveryDistributes, _ := deliveryservice.FindDeliveryDistribute(deliveryDistributeArgs, ctx.Logger) - - releaseInfo.DistributeInfo = deliveryDistributes - releaseInfos = append(releaseInfos, releaseInfo) - } - ctx.Err = err - ctx.Resp = releaseInfos + ctx.Resp, ctx.Err = deliveryservice.ListDeliveryVersion(args, ctx.Logger) } func getFileName(fileName string) string { diff --git a/pkg/microservice/aslan/core/delivery/service/docker.go b/pkg/microservice/aslan/core/delivery/service/docker.go new file mode 100644 index 000000000..65a35941e --- /dev/null +++ b/pkg/microservice/aslan/core/delivery/service/docker.go @@ -0,0 +1,57 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package service + +import "os/exec" + +const dockerExe = "/usr/local/bin/docker" + +func dockerLogin(user, password, registry string) *exec.Cmd { + return exec.Command( + dockerExe, + "login", + "-u", user, + "-p", password, + registry, + ) +} + +func dockerInfo() *exec.Cmd { + return exec.Command(dockerExe, "info") +} + +func dockerPush(fullImage string) *exec.Cmd { + args := []string{ + "push", + fullImage, + } + return exec.Command(dockerExe, args...) +} + +func dockerPull(image string) *exec.Cmd { + args := []string{"pull", image} + return exec.Command(dockerExe, args...) +} + +func dockerTag(sourceFullImage, targetFullImage string) *exec.Cmd { + args := []string{ + "tag", + sourceFullImage, + targetFullImage, + } + return exec.Command(dockerExe, args...) +} diff --git a/pkg/microservice/aslan/core/delivery/service/version.go b/pkg/microservice/aslan/core/delivery/service/version.go index c764572b4..5524f87d8 100644 --- a/pkg/microservice/aslan/core/delivery/service/version.go +++ b/pkg/microservice/aslan/core/delivery/service/version.go @@ -17,16 +17,21 @@ limitations under the License. package service import ( + "bytes" "encoding/json" "fmt" + "io" "io/ioutil" "net/http" + "net/url" "os" + "os/exec" "path/filepath" + "strings" "sync" "time" - yamlutil "github.com/koderover/zadig/pkg/util/yaml" + workflowservice "github.com/koderover/zadig/pkg/microservice/aslan/core/workflow/service/workflow" cm "github.com/chartmuseum/helm-push/pkg/chartmuseum" "github.com/chartmuseum/helm-push/pkg/helm" @@ -43,15 +48,29 @@ import ( configbase "github.com/koderover/zadig/pkg/config" "github.com/koderover/zadig/pkg/microservice/aslan/config" commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/template" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/base" fsservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/fs" "github.com/koderover/zadig/pkg/setting" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/log" "github.com/koderover/zadig/pkg/types" + "github.com/koderover/zadig/pkg/util/converter" + yamlutil "github.com/koderover/zadig/pkg/util/yaml" ) +const ( + VerbosityBrief string = "brief" // brief delivery data + VerbosityDetailed string = "detailed" // detailed delivery version with total data +) + +type DeliveryVersionFilter struct { + ServiceName string +} + type CreateHelmDeliveryVersionOption struct { EnableOfflineDist bool `json:"enableOfflineDist"` S3StorageID string `json:"s3StorageID"` @@ -112,13 +131,57 @@ type DeliveryVariablesApplyArgs struct { ChartDatas []*CreateHelmDeliveryVersionChartData `json:"chartDatas"` } +type ListDeliveryVersionArgs struct { + Page int `form:"page"` + PerPage int `form:"per_page"` + TaskId int `form:"taskId"` + ServiceName string `form:"serviceName"` + Verbosity string `form:"verbosity"` + ProjectName string `form:"projectName"` + WorkflowName string `form:"workflowName"` +} + +type ReleaseInfo struct { + VersionInfo *commonmodels.DeliveryVersion `json:"versionInfo"` + BuildInfo []*commonmodels.DeliveryBuild `json:"buildInfo,omitempty"` + DeployInfo []*commonmodels.DeliveryDeploy `json:"deployInfo,omitempty"` + TestInfo []*commonmodels.DeliveryTest `json:"testInfo,omitempty"` + DistributeInfo []*commonmodels.DeliveryDistribute `json:"distributeInfo,omitempty"` + SecurityInfo []*DeliverySecurityStats `json:"securityStatsInfo,omitempty"` +} + +type DeliverySecurityStatsInfo struct { + Total int `json:"total"` + Unknown int `json:"unkown"` + Negligible int `json:"negligible"` + Low int `json:"low"` + Medium int `json:"medium"` + High int `json:"high"` + Critical int `json:"critical"` +} + +type DeliverySecurityStats struct { + ImageName string `json:"imageName"` + ImageID string `json:"imageId"` + DeliverySecurityStatsInfo DeliverySecurityStatsInfo `json:"deliverySecurityStatsInfo"` +} + func GetDeliveryVersion(args *commonrepo.DeliveryVersionArgs, log *zap.SugaredLogger) (*commonmodels.DeliveryVersion, error) { - resp, err := commonrepo.NewDeliveryVersionColl().Get(args) + versionData, err := commonrepo.NewDeliveryVersionColl().Get(args) if err != nil { log.Errorf("get deliveryVersion error: %v", err) return nil, e.ErrGetDeliveryVersion } - return resp, err + return versionData, err +} + +func GetDetailReleaseData(args *commonrepo.DeliveryVersionArgs, log *zap.SugaredLogger) (*ReleaseInfo, error) { + versionData, err := commonrepo.NewDeliveryVersionColl().Get(args) + if err != nil { + log.Errorf("get deliveryVersion error: %v", err) + return nil, e.ErrGetDeliveryVersion + } + return buildReleaseRespData(VerbosityDetailed, versionData, nil, log) } func FindDeliveryVersion(args *commonrepo.DeliveryVersionArgs, log *zap.SugaredLogger) ([]*commonmodels.DeliveryVersion, error) { @@ -139,11 +202,176 @@ func DeleteDeliveryVersion(args *commonrepo.DeliveryVersionArgs, log *zap.Sugare return nil } -func FillDeliveryProgressInfo(deliveryVersion *commonmodels.DeliveryVersion) *commonmodels.DeliveryVersionProgress { +func filterReleases(filter *DeliveryVersionFilter, deliveryVersion *commonmodels.DeliveryVersion, logger *zap.SugaredLogger) bool { + if filter == nil { + return true + } + if filter.ServiceName != "" { + deliveryDeployArgs := new(commonrepo.DeliveryDeployArgs) + deliveryDeployArgs.ReleaseID = deliveryVersion.ID.Hex() + deliveryDeploys, err := FindDeliveryDeploy(deliveryDeployArgs, logger) + if err != nil { + return true + } + match := false + for _, deliveryDeploy := range deliveryDeploys { + if deliveryDeploy.ServiceName == filter.ServiceName { + match = true + break + } + } + if !match { + return false + } + } + return true +} + +func buildBriefRelease(deliveryVersion *commonmodels.DeliveryVersion, _ *zap.SugaredLogger) (*ReleaseInfo, error) { + return &ReleaseInfo{ + VersionInfo: deliveryVersion, + }, nil +} + +func buildDetailedRelease(deliveryVersion *commonmodels.DeliveryVersion, filterOpt *DeliveryVersionFilter, logger *zap.SugaredLogger) (*ReleaseInfo, error) { + releaseInfo := new(ReleaseInfo) + //versionInfo + releaseInfo.VersionInfo = deliveryVersion + + //deployInfo + deliveryDeployArgs := new(commonrepo.DeliveryDeployArgs) + deliveryDeployArgs.ReleaseID = deliveryVersion.ID.Hex() + deliveryDeploys, err := FindDeliveryDeploy(deliveryDeployArgs, logger) + if err != nil { + return nil, err + } + if filterOpt != nil { + if !filterReleases(filterOpt, deliveryVersion, logger) { + return nil, nil + } + } + // 将serviceName替换为服务名/服务组件的形式,用于前端展示 + for _, deliveryDeploy := range deliveryDeploys { + if deliveryDeploy.ContainerName != "" { + deliveryDeploy.ServiceName = deliveryDeploy.ServiceName + "/" + deliveryDeploy.ContainerName + } + } + releaseInfo.DeployInfo = deliveryDeploys + + //buildInfo + deliveryBuildArgs := new(commonrepo.DeliveryBuildArgs) + deliveryBuildArgs.ReleaseID = deliveryVersion.ID.Hex() + deliveryBuilds, err := FindDeliveryBuild(deliveryBuildArgs, logger) + if err != nil { + return nil, err + } + releaseInfo.BuildInfo = deliveryBuilds + + //testInfo + deliveryTestArgs := new(commonrepo.DeliveryTestArgs) + deliveryTestArgs.ReleaseID = deliveryVersion.ID.Hex() + deliveryTests, err := FindDeliveryTest(deliveryTestArgs, logger) + if err != nil { + return nil, err + } + releaseInfo.TestInfo = deliveryTests + + //securityStatsInfo + deliverySecurityStatss := make([]*DeliverySecurityStats, 0) + if pipelineTask, err := workflowservice.GetPipelineTaskV2(int64(deliveryVersion.TaskID), deliveryVersion.WorkflowName, config.WorkflowType, logger); err == nil { + for _, subStage := range pipelineTask.Stages { + if subStage.TaskType == config.TaskSecurity { + subSecurityTaskMap := subStage.SubTasks + for _, subTask := range subSecurityTaskMap { + securityInfo, _ := base.ToSecurityTask(subTask) + + deliverySecurityStats := new(DeliverySecurityStats) + deliverySecurityStats.ImageName = securityInfo.ImageName + deliverySecurityStats.ImageID = securityInfo.ImageID + deliverySecurityStatsMap, err := FindDeliverySecurityStatistics(securityInfo.ImageID, logger) + if err != nil { + return nil, err + } + var transErr error + b, err := json.Marshal(deliverySecurityStatsMap) + if err != nil { + transErr = fmt.Errorf("marshal task error: %v", err) + } + if err := json.Unmarshal(b, &deliverySecurityStats.DeliverySecurityStatsInfo); err != nil { + transErr = fmt.Errorf("unmarshal task error: %v", err) + } + if transErr != nil { + return nil, transErr + } + + deliverySecurityStatss = append(deliverySecurityStatss, deliverySecurityStats) + } + break + } + } + releaseInfo.SecurityInfo = deliverySecurityStatss + } + + //distributeInfo + deliveryDistributeArgs := new(commonrepo.DeliveryDistributeArgs) + deliveryDistributeArgs.ReleaseID = deliveryVersion.ID.Hex() + deliveryDistributes, _ := FindDeliveryDistribute(deliveryDistributeArgs, logger) + + deliveryVersion.Progress = FillDeliveryProgressInfo(deliveryVersion, deliveryDistributes) + + releaseInfo.DistributeInfo = deliveryDistributes + return releaseInfo, nil +} + +func buildReleaseRespData(verbosity string, deliveryVersion *commonmodels.DeliveryVersion, filterOpt *DeliveryVersionFilter, logger *zap.SugaredLogger) (*ReleaseInfo, error) { + switch verbosity { + case VerbosityBrief: + return buildBriefRelease(deliveryVersion, logger) + case VerbosityDetailed: + return buildDetailedRelease(deliveryVersion, filterOpt, logger) + default: + return buildDetailedRelease(deliveryVersion, filterOpt, logger) + } +} + +func ListDeliveryVersion(args *ListDeliveryVersionArgs, logger *zap.SugaredLogger) ([]*ReleaseInfo, error) { + version := new(commonrepo.DeliveryVersionArgs) + version.ProductName = args.ProjectName + version.WorkflowName = args.WorkflowName + version.TaskID = args.TaskId + version.PerPage = args.PerPage + version.Page = args.Page + deliveryVersions, err := FindDeliveryVersion(version, logger) + if err != nil { + return nil, err + } + + log.Infof("###### the verbosity is %s, projectName is %s", args.Verbosity, args.ProjectName) + releaseInfos := make([]*ReleaseInfo, 0) + for _, deliveryVersion := range deliveryVersions { + releaseInfo, err := buildReleaseRespData(args.Verbosity, deliveryVersion, &DeliveryVersionFilter{ServiceName: args.ServiceName}, logger) + if err != nil { + return nil, err + } + if releaseInfo == nil { + continue + } + releaseInfos = append(releaseInfos, releaseInfo) + } + return releaseInfos, nil +} + +func FillDeliveryProgressInfo(deliveryVersion *commonmodels.DeliveryVersion, deliveryDistribute []*commonmodels.DeliveryDistribute) *commonmodels.DeliveryVersionProgress { if deliveryVersion.Type != setting.DeliveryVersionTypeChart { return nil } - successfulChartCount := len(deliveryVersion.Charts) + chartDeploys := make([]*commonmodels.DeliveryDistribute, 0) + for _, deliveryDistribute := range deliveryDistribute { + if deliveryDistribute.DistributeType == config.Chart { + chartDeploys = append(chartDeploys, deliveryDistribute) + } + } + successfulChartCount := len(chartDeploys) progress := &commonmodels.DeliveryVersionProgress{ SuccessChartCount: successfulChartCount, @@ -173,6 +401,7 @@ func FillDeliveryProgressInfo(deliveryVersion *commonmodels.DeliveryVersion) *co if deliveryVersion.Status == setting.DeliveryVersionStatusFailed { progress.PackageUploadStatus = setting.DeliveryVersionPackageStatusFailed + progress.Error = deliveryVersion.Error return progress } @@ -225,24 +454,109 @@ func createChartRepoClient(repo *commonmodels.HelmRepo) (*cm.Client, error) { return client, nil } -func handleSingleChart(chartData *DeliveryChartData, chartRepo *commonmodels.HelmRepo, dir string, globalVariables string) error { +func runDockerCommand(cmd *exec.Cmd) error { + var out bytes.Buffer + cmd.Stdout = &out + cmd.Stderr = &out + if err := cmd.Run(); err != nil { + return err + } + return nil +} + +// pull image from currently using registry and push to specified repo +func pushImages(serviceObj *commonmodels.Service, valuesMap map[string]interface{}, targetRegistry *commonmodels.RegistryNamespace, registryMap map[string]*commonmodels.RegistryNamespace) error { + + log.Infof("######## start pushing image #########") + + flatMap, err := converter.Flatten(valuesMap) + if err != nil { + return err + } + + imagePathSpecs := make([]map[string]string, 0) + for _, container := range serviceObj.Containers { + imageSearchRule := &template.ImageSearchingRule{ + Repo: container.ImagePath.Repo, + Image: container.ImagePath.Image, + Tag: container.ImagePath.Tag, + } + pattern := imageSearchRule.GetSearchingPattern() + imagePathSpecs = append(imagePathSpecs, pattern) + } + + // find full image uris from values.yaml + imageUris := make([]string, 0) + for _, spec := range imagePathSpecs { + imageUri, err := commonservice.GeneImageURI(spec, flatMap) + if err != nil { + return err + } + imageUris = append(imageUris, imageUri) + } + + // login to the target repo + err = runDockerCommand(dockerLogin(targetRegistry.AccessKey, targetRegistry.SecretKey, targetRegistry.RegAddr)) + if err != nil { + return errors.Wrapf(err, fmt.Sprintf("failed to login docker registry, url: %s", targetRegistry.RegAddr)) + } + + for _, imageUri := range imageUris { + log.Infof("##### handle single image uri %s ######", imageUri) + registryUrl, err := commonservice.ExtractImageRegistry(imageUri) + if err != nil { + return errors.Wrapf(err, "failed to parse registry from image uri: %s", imageUri) + } + registryUrl = strings.TrimSuffix(registryUrl, "/") + log.Infof("#### extract registry url %s ####", registryUrl) + if registry, ok := registryMap[registryUrl]; ok { + if registry.ID == targetRegistry.ID { + log.Infof("######## same registry, no need to push again ########") + continue + } + //TODO need optimize to avoid login to same repo multiple times + err := runDockerCommand(dockerLogin(registry.AccessKey, registry.SecretKey, registry.RegAddr)) + if err != nil { + return errors.Wrapf(err, fmt.Sprintf("failed to login docker registry, url: %s", registry.RegAddr)) + } + } + err = runDockerCommand(dockerPull(imageUri)) + if err != nil { + return errors.Wrapf(err, fmt.Sprintf("failed to pull docker image, source url: %s", imageUri)) + } + + imageName := commonservice.ExtractImageName(imageUri) + imageTag := commonservice.ExtractImageTag(imageUri) + + targetFullImageUri := fmt.Sprintf("%s/%s/%s:%s", targetRegistry.RegAddr, targetRegistry.Namespace, imageName, imageTag) + err = runDockerCommand(dockerTag(imageUri, targetFullImageUri)) + if err != nil { + return errors.Wrapf(err, "failed to tag image from: %s to : %s", imageUri, targetFullImageUri) + } + + err = runDockerCommand(dockerPush(targetFullImageUri)) + if err != nil { + return errors.Wrapf(err, "failed to push image: %s", targetFullImageUri) + } + } + return nil +} + +func handleSingleChart(chartData *DeliveryChartData, chartRepo *commonmodels.HelmRepo, dir string, globalVariables string, targetRegistry *commonmodels.RegistryNamespace, registryMap map[string]*commonmodels.RegistryNamespace) error { serviceObj := chartData.ServiceObj serviceName, revision := serviceObj.ServiceName, serviceObj.Revision - base := config.LocalServicePathWithRevision(serviceObj.ProductName, serviceName, revision) - if err := commonservice.PreloadServiceManifestsByRevision(base, serviceObj); err != nil { + basePath := config.LocalServicePathWithRevision(serviceObj.ProductName, serviceName, revision) + if err := commonservice.PreloadServiceManifestsByRevision(basePath, serviceObj); err != nil { log.Warnf("failed to get chart of revision: %d for service: %s, use latest version", revision, serviceName) // use the latest version when it fails to download the specific version - base = config.LocalServicePath(serviceObj.ProductName, serviceName) - if err = commonservice.PreLoadServiceManifests(base, serviceObj); err != nil { + basePath = config.LocalServicePath(serviceObj.ProductName, serviceName) + if err = commonservice.PreLoadServiceManifests(basePath, serviceObj); err != nil { log.Errorf("failed to load chart info for service %v", serviceObj.ServiceName) return err } } - // push 镜像 - //commonrepo.NewRegistryNamespaceColl().Find(&commonrepo.FindRegOps{}) - - fullPath := filepath.Join(base, serviceObj.ServiceName) + fullPath := filepath.Join(basePath, serviceObj.ServiceName) revisionBasePath := config.LocalDeliveryChartPathWithRevision(serviceObj.ProductName, serviceObj.ServiceName, serviceObj.Revision) deliveryChartPath := filepath.Join(revisionBasePath, serviceObj.ServiceName) err := copy.Copy(fullPath, deliveryChartPath) @@ -284,9 +598,15 @@ func handleSingleChart(chartData *DeliveryChartData, chartRepo *commonmodels.Hel return err } + // push docker image + err = pushImages(serviceObj, chartRequested.Values, targetRegistry, registryMap) + if err != nil { + return errors.Wrapf(err, "failed to handle image") + } + client, err := createChartRepoClient(chartRepo) if err != nil { - return err + return errors.Wrapf(err, "failed to create chart repo client, repoName: %s", chartRepo.RepoName) } log.Infof("pushing %s to %s...\n", filepath.Base(chartPackagePath), chartRepo.URL) @@ -304,7 +624,9 @@ func handleSingleChart(chartData *DeliveryChartData, chartRepo *commonmodels.Hel func handlePushResponse(resp *http.Response) error { if resp.StatusCode != 201 && resp.StatusCode != 202 { b, err := ioutil.ReadAll(resp.Body) - defer resp.Body.Close() + defer func(Body io.ReadCloser) { + _ = Body.Close() + }(resp.Body) if err != nil { return err } @@ -375,6 +697,24 @@ func prepareChartData(chartDatas []*CreateHelmDeliveryVersionChartData, productI return chartDataMap, nil } +func buildRegistryMap() (map[string]*commonmodels.RegistryNamespace, error) { + registries, err := commonrepo.NewRegistryNamespaceColl().FindAll(&mongodb.FindRegOps{}) + if err != nil { + return nil, fmt.Errorf("failed to query registries") + } + ret := make(map[string]*commonmodels.RegistryNamespace) + for _, singleRegistry := range registries { + fullUrl := fmt.Sprintf("%s/%s", singleRegistry.RegAddr, singleRegistry.Namespace) + fullUrl = strings.TrimSuffix(fullUrl, "/") + u, _ := url.Parse(fullUrl) + if len(u.Scheme) > 0 { + fullUrl = strings.TrimPrefix(fullUrl, fmt.Sprintf("%s://", u.Scheme)) + } + ret[fullUrl] = singleRegistry + } + return ret, nil +} + func buildDeliveryCharts(chartDataMap map[string]*DeliveryChartData, deliveryVersion *commonmodels.DeliveryVersion, args *DeliveryVersionChartData, logger *zap.SugaredLogger) (err error) { defer func() { if err != nil { @@ -405,29 +745,47 @@ func buildDeliveryCharts(chartDataMap map[string]*DeliveryChartData, deliveryVer } repoInfo, err := getChartRepoData(args.ChartRepoName) if err != nil { - log.Infof("failed to query chart-repo info, productName: %s, err: %s", deliveryVersion.ProductName, err) + log.Errorf("failed to query chart-repo info, productName: %s, err: %s", deliveryVersion.ProductName, err) return fmt.Errorf("failed to query chart-repo info, productName: %s, repoName: %s", deliveryVersion.ProductName, args.ChartRepoName) } + targetRegistry, err := commonrepo.NewRegistryNamespaceColl().Find(&mongodb.FindRegOps{ + ID: args.ImageRegistryID, + }) + if err != nil { + log.Errorf("failed to query target image registry with ID: %s, err %s", args.ImageRegistryID, err) + return fmt.Errorf("faild to query target registry namespace") + } + + registryMap, err := buildRegistryMap() + if err != nil { + return fmt.Errorf("failed to build registry map") + } + + err = runDockerCommand(dockerInfo()) + if err != nil { + return fmt.Errorf("failed to run docker deamon") + } + // push charts to repo wg := sync.WaitGroup{} for _, chartData := range chartDataMap { wg.Add(1) go func(cData *DeliveryChartData) { defer wg.Done() - err := handleSingleChart(cData, repoInfo, dir, args.GlobalVariables) + err := handleSingleChart(cData, repoInfo, dir, args.GlobalVariables, targetRegistry, registryMap) if err != nil { logger.Errorf("failed to handle single chart data, serviceName: %s err: %s", cData.ChartData.ServiceName, err) appendError(err) } else { - err = commonrepo.NewDeliveryVersionColl().AddDeliveryChart(deliveryVersion.Version, &commonmodels.DeliveryChart{ - Name: cData.ChartData.ServiceName, - Version: cData.ChartData.Version, - Repo: args.ChartRepoName, - }) - if err != nil { - appendError(errors.Wrapf(err, "failed to save delivery chart: %s", cData.ChartData.ServiceName)) - } + //err = commonrepo.NewDeliveryVersionColl().AddDeliveryChart(deliveryVersion.Version, &commonmodels.DeliveryChart{ + // Name: cData.ChartData.ServiceName, + // Version: cData.ChartData.Version, + // Repo: args.ChartRepoName, + //}) + //if err != nil { + // appendError(errors.Wrapf(err, "failed to save delivery chart: %s", cData.ChartData.ServiceName)) + //} } }(chartData) } @@ -467,6 +825,14 @@ func CreateNewHelmDeliveryVersion(args *CreateHelmDeliveryVersionArgs, logger *z return e.ErrCreateDeliveryVersion.AddDesc(fmt.Sprintf("failed to query product info, procutName: %s envName %s", args.ProductName, args.EnvName)) } + // validate necessary params + if len(args.ChartRepoName) == 0 { + return e.ErrCreateDeliveryVersion.AddDesc("chart repo not appointed") + } + if len(args.ImageRegistryID) == 0 { + return e.ErrCreateDeliveryVersion.AddDesc("image registry not appointed") + } + chartDataMap, err := prepareChartData(args.ChartDatas, productInfo) if err != nil { return e.ErrCreateDeliveryVersion.AddErr(err) @@ -518,27 +884,28 @@ func RetryCreateHelmDeliveryVersion(projectName, versionName string, logger *zap argsBytes, err := json.Marshal(deliveryVersion.CreateArgument) if err != nil { - return errors.Wrapf(err, "failed to marshal arguments, versionName: %s err %s", deliveryVersion.Version) + return errors.Wrapf(err, "failed to marshal arguments, versionName: %s err: %s", deliveryVersion.Version, err) } createArgs := new(DeliveryVersionChartData) err = json.Unmarshal(argsBytes, createArgs) if err != nil { - return errors.Wrapf(err, "failed to unMarshal arguments, versionName: %s err %s", deliveryVersion.Version) + return errors.Wrapf(err, "failed to unMarshal arguments, versionName: %s err: %s", deliveryVersion.Version, err) } productInfoSnap := deliveryVersion.ProductEnvInfo + //deploys := make + // for charts has been successfully handled, download charts directly successCharts := sets.NewString() - for _, singleChart := range deliveryVersion.Charts { - // prepare chart data - _, err := downloadChart(projectName, versionName, singleChart) - if err != nil { - log.Errorf("failed to download chart from chart repo, chartName: %s, err: %s", singleChart.Name, err) - continue - } - successCharts.Insert(singleChart.Name) - } + //for _, singleChart := range deliveryVersion.Charts { + // _, err := downloadChart(projectName, versionName, singleChart) + // if err != nil { + // log.Errorf("failed to download chart from chart repo, chartName: %s, err: %s", singleChart.Name, err) + // continue + // } + // successCharts.Insert(singleChart.Name) + //} chartsToBeHandled := make([]*CreateHelmDeliveryVersionChartData, 0) for _, chartConfig := range createArgs.ChartDatas { @@ -596,8 +963,8 @@ func ListDeliveryServiceNames(productName string, log *zap.SugaredLogger) ([]str return serviceNames.UnsortedList(), nil } -func downloadChart(productName, versionName string, chartInfo *commonmodels.DeliveryChart) (string, error) { - chartTGZName := fmt.Sprintf("%s-%s.tgz", chartInfo.Name, chartInfo.Version) +func downloadChart(productName, versionName string, chartInfo *commonmodels.DeliveryDistribute) (string, error) { + chartTGZName := fmt.Sprintf("%s-%s.tgz", chartInfo.ServiceName, chartInfo.Version) chartTGZFileParent := getChartTGZDir(productName, versionName) chartTGZFilePath := filepath.Join(chartTGZFileParent, chartTGZName) if _, err := os.Stat(chartTGZFilePath); err == nil { @@ -606,9 +973,9 @@ func downloadChart(productName, versionName string, chartInfo *commonmodels.Deli return chartTGZFilePath, nil } - chartRepo, err := getChartRepoData(chartInfo.Repo) + chartRepo, err := getChartRepoData(chartInfo.ChartRepoName) if err != nil { - return "", fmt.Errorf("failed to query chart-repo info, repoName %s", chartInfo.Repo) + return "", fmt.Errorf("failed to query chart-repo info, repoName %s", chartInfo.ChartRepoName) } client, err := createChartRepoClient(chartRepo) @@ -652,19 +1019,26 @@ func downloadChart(productName, versionName string, chartInfo *commonmodels.Deli return chartTGZFilePath, nil } -func getChartConfigInfo(projectName, version string, chartName string, log *zap.SugaredLogger) (*commonmodels.DeliveryChart, error) { - deliveryVersion, err := GetDeliveryVersion(&commonrepo.DeliveryVersionArgs{ - ProductName: projectName, - Version: version, +func getChartDistributeInfo(projectName, version string, chartName string, log *zap.SugaredLogger) (*commonmodels.DeliveryDistribute, error) { + //deliveryVersion, err := GetDeliveryVersion(&commonrepo.DeliveryVersionArgs{ + // ProductName: projectName, + // Version: version, + //}, log) + + //if err != nil { + // return nil, err + //} + + distributes, _ := FindDeliveryDistribute(&commonrepo.DeliveryDistributeArgs{ + ReleaseID: "", + ServiceName: chartName, + DistributeType: config.Chart, }, log) - if err != nil { - return nil, err - } - var chartInfo *commonmodels.DeliveryChart - for _, singleChart := range deliveryVersion.Charts { - if singleChart.Name == chartName { - chartInfo = singleChart + var chartInfo *commonmodels.DeliveryDistribute + for _, distribute := range distributes { + if distribute.ServiceName == chartName { + chartInfo = distribute } } @@ -675,7 +1049,7 @@ func getChartConfigInfo(projectName, version string, chartName string, log *zap. } func DownloadDeliveryChart(projectName, version string, chartName string, log *zap.SugaredLogger) (string, error) { - chartInfo, err := getChartConfigInfo(projectName, version, chartName, log) + chartInfo, err := getChartDistributeInfo(projectName, version, chartName, log) if err != nil { return "", err } @@ -689,12 +1063,12 @@ func DownloadDeliveryChart(projectName, version string, chartName string, log *z func preDownloadAndUncompressChart(projectName, versionName, chartName string, log *zap.SugaredLogger) (string, error) { - chartInfo, err := getChartConfigInfo(projectName, versionName, chartName, log) + chartDistribute, err := getChartDistributeInfo(projectName, versionName, chartName, log) if err != nil { return "", err } dstDir := getChartExpandDir(projectName, versionName) - dstDir = filepath.Join(dstDir, fmt.Sprintf("%s-%s", chartInfo.Name, chartInfo.Version)) + dstDir = filepath.Join(dstDir, fmt.Sprintf("%s-%s", chartDistribute.ServiceName, chartDistribute.Version)) filePath, err := DownloadDeliveryChart(projectName, versionName, chartName, log) if err != nil { @@ -809,12 +1183,13 @@ func GetDeliveryChartFileContent(args *DeliveryChartFileContentArgs, log *zap.Su return string(fileContent), nil } -func ApplyDeliveryGlobalVariables(args *DeliveryVariablesApplyArgs, log *zap.SugaredLogger) (interface{}, error) { +func ApplyDeliveryGlobalVariables(args *DeliveryVariablesApplyArgs, logger *zap.SugaredLogger) (interface{}, error) { ret := new(DeliveryVariablesApplyArgs) for _, chartData := range args.ChartDatas { mergedYaml, err := yamlutil.Merge([][]byte{[]byte(chartData.ValuesYamlContent), []byte(args.GlobalVariables)}) if err != nil { - return nil, errors.Wrapf(err, "failed to merge global variable for service: %s", chartData.ServiceName) + logger.Errorf("failed to merge gobal variables for service: %s", chartData.ServiceName) + return nil, errors.Wrapf(err, "failed to merge global variables for service: %s", chartData.ServiceName) } ret.ChartDatas = append(ret.ChartDatas, &CreateHelmDeliveryVersionChartData{ ServiceName: chartData.ServiceName, diff --git a/pkg/microservice/aslan/core/environment/service/helm.go b/pkg/microservice/aslan/core/environment/service/helm.go index 98503c44f..20f887383 100644 --- a/pkg/microservice/aslan/core/environment/service/helm.go +++ b/pkg/microservice/aslan/core/environment/service/helm.go @@ -85,17 +85,6 @@ func ListReleases(productName, envName string, log *zap.SugaredLogger) ([]*HelmR ret := make([]*HelmReleaseResp, 0, len(releases)) for _, release := range releases { - - for _, singleFile := range release.Chart.Files { - log.Infof("###### single file name is %s", singleFile.Name) - log.Infof("###### single file data is %s", string(singleFile.Data)) - } - - for _, singleFile := range release.Chart.Templates { - log.Infof("###### single file name is %s", singleFile.Name) - log.Infof("###### single file data is %s", string(singleFile.Data)) - } - ret = append(ret, &HelmReleaseResp{ ReleaseName: release.Name, ServiceName: util.ExtraServiceName(release.Name, prod.Namespace), diff --git a/pkg/setting/consts.go b/pkg/setting/consts.go index af9b8b8cd..9a6b00327 100644 --- a/pkg/setting/consts.go +++ b/pkg/setting/consts.go @@ -272,7 +272,13 @@ const ( ) const ( - DeliveryVersionTypeChart = "HelmChart" + DeliveryVersionTypeChart = "HelmChart" + DeliveryVersionTypeK8SWorkflow = "K8SWorkflow" +) + +const ( + DeliveryDeployTypeImage = "image" + DeliveryDeployTypeChart = "chart" ) const ( -- Gitee From aba139dbe27aebb2856b9daeab04a032104c9a07 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Fri, 26 Nov 2021 17:40:23 +0800 Subject: [PATCH 007/134] Workflow and test tasks support resource scheduling configuration Signed-off-by: liu deyi --- .../core/common/repository/models/build.go | 4 ++- .../core/common/repository/models/testing.go | 4 ++- .../aslan/core/environment/handler/kube.go | 7 ++++ .../aslan/core/environment/handler/router.go | 1 + .../aslan/core/environment/service/kube.go | 33 +++++++++++++++++++ pkg/shared/kube/resource/node.go | 6 ++++ 6 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 pkg/shared/kube/resource/node.go diff --git a/pkg/microservice/aslan/core/common/repository/models/build.go b/pkg/microservice/aslan/core/common/repository/models/build.go index c5288acc9..123fc7d95 100644 --- a/pkg/microservice/aslan/core/common/repository/models/build.go +++ b/pkg/microservice/aslan/core/common/repository/models/build.go @@ -65,7 +65,9 @@ type PreBuild struct { // Parameters Parameters []*Parameter `bson:"parameters,omitempty" json:"parameters"` // UploadPkg uploads package to s3 - UploadPkg bool `bson:"upload_pkg" json:"upload_pkg"` + UploadPkg bool `bson:"upload_pkg" json:"upload_pkg"` + ClusterID string `bson:"cluster_id" json:"cluster_id"` + Namespace string `bson:"namespace" json:"namespace"` } type BuildObj struct { diff --git a/pkg/microservice/aslan/core/common/repository/models/testing.go b/pkg/microservice/aslan/core/common/repository/models/testing.go index c42a6deb2..6b802cf30 100644 --- a/pkg/microservice/aslan/core/common/repository/models/testing.go +++ b/pkg/microservice/aslan/core/common/repository/models/testing.go @@ -78,7 +78,9 @@ type PreTest struct { // Envs stores user defined env key val for build Envs []*KeyVal `bson:"envs,omitempty" json:"envs"` // EnableProxy - EnableProxy bool `bson:"enable_proxy" json:"enable_proxy"` + EnableProxy bool `bson:"enable_proxy" json:"enable_proxy"` + ClusterID string `bson:"cluster_id" json:"cluster_id"` + Namespace string `bson:"namespace" json:"namespace"` } func (Testing) TableName() string { diff --git a/pkg/microservice/aslan/core/environment/handler/kube.go b/pkg/microservice/aslan/core/environment/handler/kube.go index 1e4c0c481..215d8237e 100644 --- a/pkg/microservice/aslan/core/environment/handler/kube.go +++ b/pkg/microservice/aslan/core/environment/handler/kube.go @@ -97,3 +97,10 @@ func ListPodEvents(c *gin.Context) { ctx.Resp, ctx.Err = service.ListPodEvents(envName, productName, podName, ctx.Logger) } + +func ListNodes(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + ctx.Resp, ctx.Err = service.ListAvailableNodes(c.Query("clusterId"), ctx.Logger) +} diff --git a/pkg/microservice/aslan/core/environment/handler/router.go b/pkg/microservice/aslan/core/environment/handler/router.go index bc13c84ca..d2eecee1c 100644 --- a/pkg/microservice/aslan/core/environment/handler/router.go +++ b/pkg/microservice/aslan/core/environment/handler/router.go @@ -86,6 +86,7 @@ func (*Router) Inject(router *gin.RouterGroup) { kube.DELETE("/pods/:podName", gin2.UpdateOperationLogStatus, DeletePod) kube.GET("/pods/:podName/events", ListPodEvents) kube.GET("/workloads", ListWorkloads) + kube.GET("/nodes", ListNodes) } // --------------------------------------------------------------------------------------- diff --git a/pkg/microservice/aslan/core/environment/service/kube.go b/pkg/microservice/aslan/core/environment/service/kube.go index 7c8e0fa39..0e403db3c 100644 --- a/pkg/microservice/aslan/core/environment/service/kube.go +++ b/pkg/microservice/aslan/core/environment/service/kube.go @@ -223,3 +223,36 @@ func getModifiedServiceFromObjectMeta(om metav1.Object) *serviceInfo { LastUpdateTime: t, } } + +func ListAvailableNodes(clusterID string, log *zap.SugaredLogger) ([]*resource.Node, error) { + resp := make([]*resource.Node, 0) + kubeClient, err := kube.GetKubeClient(clusterID) + if err != nil { + log.Errorf("ListAvailableNodes clusterID:%s err:%s", clusterID, err) + return resp, err + } + + nodes, err := getter.ListNodes(kubeClient) + if err != nil { + log.Errorf("ListNodes err:%s", err) + if apierrors.IsForbidden(err) { + return resp, nil + } + return resp, err + } + + for _, node := range nodes { + labelM := node.Labels + labels := make([]string, 0, len(labelM)) + for key, value := range labelM { + labels = append(labels, fmt.Sprintf("%s:%s", key, value)) + } + nodeResource := &resource.Node{ + Status: string(node.Status.Phase), + Labels: labels, + } + resp = append(resp, nodeResource) + } + + return resp, nil +} diff --git a/pkg/shared/kube/resource/node.go b/pkg/shared/kube/resource/node.go new file mode 100644 index 000000000..c54f3d362 --- /dev/null +++ b/pkg/shared/kube/resource/node.go @@ -0,0 +1,6 @@ +package resource + +type Node struct { + Labels []string `json:"node_labels"` + Status string `json:"node_status"` +} -- Gitee From 7d77438a3e325c4e0416b3e8fdf8c02bfd48c940 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Fri, 26 Nov 2021 18:46:11 +0800 Subject: [PATCH 008/134] optimize get node info Signed-off-by: liu deyi --- .../aslan/core/environment/service/kube.go | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/pkg/microservice/aslan/core/environment/service/kube.go b/pkg/microservice/aslan/core/environment/service/kube.go index 0e403db3c..684b534d8 100644 --- a/pkg/microservice/aslan/core/environment/service/kube.go +++ b/pkg/microservice/aslan/core/environment/service/kube.go @@ -20,6 +20,8 @@ import ( "fmt" "time" + corev1 "k8s.io/api/core/v1" + "go.uber.org/zap" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -242,17 +244,32 @@ func ListAvailableNodes(clusterID string, log *zap.SugaredLogger) ([]*resource.N } for _, node := range nodes { - labelM := node.Labels - labels := make([]string, 0, len(labelM)) - for key, value := range labelM { - labels = append(labels, fmt.Sprintf("%s:%s", key, value)) - } nodeResource := &resource.Node{ - Status: string(node.Status.Phase), - Labels: labels, + Status: nodeReady(node), + Labels: nodeLabel(node), } resp = append(resp, nodeResource) } return resp, nil } + +// Ready indicates that the node is ready for traffic. +func nodeReady(node *corev1.Node) string { + cs := node.Status.Conditions + for _, c := range cs { + if c.Type == corev1.NodeReady && c.Status == corev1.ConditionTrue { + return "ready" + } + } + return "not ready" +} + +func nodeLabel(node *corev1.Node) []string { + labels := make([]string, 0, len(node.Labels)) + labelM := node.Labels + for key, value := range labelM { + labels = append(labels, fmt.Sprintf("%s:%s", key, value)) + } + return labels +} -- Gitee From 0118ff8e9b4826d2750e1016e3a69fdfbac390f8 Mon Sep 17 00:00:00 2001 From: allenshen Date: Sun, 28 Nov 2021 19:20:16 +0800 Subject: [PATCH 009/134] update api logic | revier dockerfile changes Signed-off-by: allenshen --- docker/service/aslan.Dockerfile | 2 +- pkg/config/config.go | 2 +- .../repository/models/delivery_distribute.go | 25 +- .../repository/models/delivery_version.go | 25 +- .../repository/mongodb/delivery_distribute.go | 2 +- .../repository/mongodb/delivery_version.go | 20 +- .../aslan/core/common/service/s3/s3.go | 13 +- .../aslan/core/common/service/service.go | 18 +- .../aslan/core/delivery/handler/version.go | 9 +- .../aslan/core/delivery/service/version.go | 280 +++++++++++------- 10 files changed, 224 insertions(+), 172 deletions(-) diff --git a/docker/service/aslan.Dockerfile b/docker/service/aslan.Dockerfile index 434810faa..4384bb45d 100644 --- a/docker/service/aslan.Dockerfile +++ b/docker/service/aslan.Dockerfile @@ -2,7 +2,7 @@ RUN go build -v -o /aslan ./cmd/aslan/main.go -#alpine-git.Dockerfile +#alpine.Dockerfile WORKDIR /app diff --git a/pkg/config/config.go b/pkg/config/config.go index 4f324676e..e88d6736a 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -211,7 +211,7 @@ func ObjectStorageTemplatePath(name, kind string) string { } func ObjectStorageDeliveryVersionPath(project string) string { - return filepath.Join(project, "delivery-versions") + return filepath.Join("delivery-distributes", "files", project) } func ObjectStorageChartTemplatePath(name string) string { diff --git a/pkg/microservice/aslan/core/common/repository/models/delivery_distribute.go b/pkg/microservice/aslan/core/common/repository/models/delivery_distribute.go index 24b87745f..4365fa139 100644 --- a/pkg/microservice/aslan/core/common/repository/models/delivery_distribute.go +++ b/pkg/microservice/aslan/core/common/repository/models/delivery_distribute.go @@ -25,18 +25,23 @@ import ( type DeliveryDistribute struct { ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` ReleaseID primitive.ObjectID `bson:"release_id" json:"releaseId"` - ServiceName string `bson:"service_name" json:"serviceName"` + ServiceName string `bson:"service_name" json:"serviceName,omitempty"` DistributeType config.DistributeType `bson:"distribute_type" json:"distributeType"` RegistryName string `bson:"registry_name" json:"registryName"` - Version string `bson:"version" json:"version"` - ChartRepoName string `bson:"chart_repo_name" json:"chartRepoName"` - Namespace string `bson:"namespace" json:"namespace"` - PackageFile string `bson:"package_file" json:"packageFile"` - RemoteFileKey string `bson:"remote_file_key" json:"remoteFileKey"` - DestStorageURL string `bson:"dest_storage_url" json:"destStorageUrl"` - SrcStorageURL string `bson:"src_storage_url" json:"srcStorageUrl"` - StartTime int64 `bson:"start_time,omitempty" json:"start_time,omitempty"` - EndTime int64 `bson:"end_time,omitempty" json:"end_time,omitempty"` + ChartVersion string `bson:"chart_version" json:"chartVersion,omitempty"` + ChartName string `bson:"chart_name" json:"chartName,omitempty"` + ChartRepoName string `bson:"chart_repo_name" json:"chartRepoName,omitempty"` + SubDistributes []*DeliveryDistribute `bson:"-" json:"subDistributes,omitempty"` + Namespace string `bson:"namespace" json:"namespace,omitempty"` + PackageFile string `bson:"package_file" json:"packageFile,omitempty"` + RemoteFileKey string `bson:"remote_file_key" json:"remoteFileKey,omitempty"` + DestStorageURL string `bson:"dest_storage_url" json:"destStorageUrl,omitempty"` + S3StorageID string `bson:"s3_storage_id" json:"s3StorageID"` + StorageURL string `bson:"-" json:"storageUrl"` + StorageBucket string `bson:"-" json:"storageBucket"` + SrcStorageURL string `bson:"src_storage_url" json:"srcStorageUrl,omitempty"` + StartTime int64 `bson:"start_time,omitempty" json:"start_time,omitempty,omitempty"` + EndTime int64 `bson:"end_time,omitempty" json:"end_time,omitempty,omitempty"` CreatedAt int64 `bson:"created_at" json:"created_at"` DeletedAt int64 `bson:"deleted_at" json:"deleted_at"` } diff --git a/pkg/microservice/aslan/core/common/repository/models/delivery_version.go b/pkg/microservice/aslan/core/common/repository/models/delivery_version.go index 8720ac8bc..432d66156 100644 --- a/pkg/microservice/aslan/core/common/repository/models/delivery_version.go +++ b/pkg/microservice/aslan/core/common/repository/models/delivery_version.go @@ -20,12 +20,6 @@ import ( "go.mongodb.org/mongo-driver/bson/primitive" ) -//type DeliveryChart struct { -// Name string `bson:"name" json:"name"` -// Version string `bson:"version" json:"version"` -// Repo string `bson:"repo" json:"repo"` -//} - type DeliveryVersionProgress struct { SuccessChartCount int `json:"successChartCount"` TotalChartCount int `json:"totalChartCount"` @@ -34,16 +28,15 @@ type DeliveryVersionProgress struct { } type DeliveryVersion struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - Version string `bson:"version" json:"version"` - ProductName string `bson:"product_name" json:"productName"` - WorkflowName string `bson:"workflow_name" json:"workflowName"` - Type string `bson:"type" json:"type"` - TaskID int `bson:"task_id" json:"taskId"` - Desc string `bson:"desc" json:"desc"` - Labels []string `bson:"labels" json:"labels"` - ProductEnvInfo *Product `bson:"product_env_info" json:"productEnvInfo"` - //Charts []*DeliveryChart `bson:"charts" json:"charts"` + ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + Version string `bson:"version" json:"version"` + ProductName string `bson:"product_name" json:"productName"` + WorkflowName string `bson:"workflow_name" json:"workflowName"` + Type string `bson:"type" json:"type"` + TaskID int `bson:"task_id" json:"taskId"` + Desc string `bson:"desc" json:"desc"` + Labels []string `bson:"labels" json:"labels"` + ProductEnvInfo *Product `bson:"product_env_info" json:"productEnvInfo"` Status string `bson:"status" json:"status"` Error string `bson:"error" json:"-"` Progress *DeliveryVersionProgress `bson:"-" json:"progress"` diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/delivery_distribute.go b/pkg/microservice/aslan/core/common/repository/mongodb/delivery_distribute.go index 0b3ce01a7..21ef1dd5a 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/delivery_distribute.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/delivery_distribute.go @@ -116,7 +116,7 @@ func (c *DeliveryDistributeColl) Find(args *DeliveryDistributeArgs) ([]*models.D query := bson.M{"release_id": releaseID, "deleted_at": 0} if args.DistributeType != "" { - query["distribute_type"] = config.File + query["distribute_type"] = string(args.DistributeType) } cursor, err := c.Collection.Find(context.TODO(), query) if err != nil { diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go b/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go index 05d7cb8bb..e0adcfc8e 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go @@ -90,7 +90,6 @@ func (c *DeliveryVersionColl) Find(args *DeliveryVersionArgs) ([]*models.Deliver return nil, errors.New("nil delivery_version args") } - var resp []*models.DeliveryVersion query := bson.M{"deleted_at": 0} if args.ProductName != "" { query["product_name"] = args.ProductName @@ -114,6 +113,7 @@ func (c *DeliveryVersionColl) Find(args *DeliveryVersionArgs) ([]*models.Deliver return nil, err } + resp := make([]*models.DeliveryVersion, 0) err = cursor.All(ctx, &resp) if err != nil { return nil, err @@ -207,24 +207,6 @@ func (c *DeliveryVersionColl) UpdateStatusByName(versionName, status, errorStr s return err } -func (c *DeliveryVersionColl) AddDeliveryChart(versionName string, chartInfo *models.DeliveryDistribute) error { - //query := bson.M{ - // "version": versionName, - // "deleted_at": 0, - // "charts.name": bson.M{"$ne": chartInfo.Name}, - //} - //change := bson.M{ - // "$push": bson.M{ - // "charts": bson.M{ - // "name": chartInfo.Name, - // "version": chartInfo.Version, - // "repo": chartInfo.Repo, - // }, - // }} - //_, err := c.UpdateOne(context.TODO(), query, change) - return nil -} - func (c *DeliveryVersionColl) Update(args *models.DeliveryVersion) error { if args == nil { return errors.New("nil delivery_version args") diff --git a/pkg/microservice/aslan/core/common/service/s3/s3.go b/pkg/microservice/aslan/core/common/service/s3/s3.go index 7a7f31a75..fc363b616 100644 --- a/pkg/microservice/aslan/core/common/service/s3/s3.go +++ b/pkg/microservice/aslan/core/common/service/s3/s3.go @@ -151,17 +151,8 @@ func FindDefaultS3() (*S3, error) { func FindS3ById(id string) (*S3, error) { storage, err := commonrepo.NewS3StorageColl().Find(id) if err != nil { - log.Warnf("Failed to find default s3 in db, err: %s", err) - return &S3{ - S3Storage: &models.S3Storage{ - Ak: config.S3StorageAK(), - Sk: config.S3StorageSK(), - Endpoint: config.S3StorageEndpoint(), - Bucket: config.S3StorageBucket(), - Insecure: config.S3StorageProtocol() == "http", - Provider: setting.ProviderSourceSystemDefault, - }, - }, nil + log.Warnf("Failed to find s3 in db, err: %s", err) + return nil, err } return &S3{S3Storage: storage}, nil diff --git a/pkg/microservice/aslan/core/common/service/service.go b/pkg/microservice/aslan/core/common/service/service.go index b5bb8a6b7..fbcf8086c 100644 --- a/pkg/microservice/aslan/core/common/service/service.go +++ b/pkg/microservice/aslan/core/common/service/service.go @@ -91,8 +91,9 @@ type ServiceProductMap struct { } var ( - imageParseRegex = regexp.MustCompile(`(?P.+/)?(?P[^:]+){1}(:)?(?P.+)?`) - presetPatterns = []map[string]string{ + imageParseRegex = regexp.MustCompile(`(?P.+/)?(?P[^:]+){1}(:)?(?P.+)?`) + imageSpaceParseRegex = regexp.MustCompile(`\/(.*?)\/`) + presetPatterns = []map[string]string{ {setting.PathSearchComponentImage: "image.repository", setting.PathSearchComponentTag: "image.tag"}, {setting.PathSearchComponentImage: "image"}, } @@ -650,6 +651,19 @@ func ExtractImageTag(imageURI string) string { return "" } +// ExtractRegistryNamespace extract registry namespace form image uri +func ExtractRegistryNamespace(imageURI string) string { + imageURI = strings.TrimPrefix(imageURI, "http://") + imageURI = strings.TrimPrefix(imageURI, "https://") + + firstIndex := strings.Index(imageURI, "/") + lastIndex := strings.LastIndex(imageURI, "/") + if lastIndex == firstIndex { + return "" + } + return strings.TrimPrefix(imageURI[firstIndex:lastIndex], "/") +} + func parseImagesByPattern(nested map[string]interface{}, patterns []map[string]string) ([]*models.Container, error) { flatMap, err := converter.Flatten(nested) if err != nil { diff --git a/pkg/microservice/aslan/core/delivery/handler/version.go b/pkg/microservice/aslan/core/delivery/handler/version.go index 10397ed47..c943e5d3f 100644 --- a/pkg/microservice/aslan/core/delivery/handler/version.go +++ b/pkg/microservice/aslan/core/delivery/handler/version.go @@ -18,6 +18,7 @@ package handler import ( "fmt" + "net/http" "strings" "github.com/gin-gonic/gin" @@ -78,7 +79,7 @@ func ListDeliveryVersion(c *gin.Context) { args.Page = 1 } if args.PerPage <= 0 { - args.Page = 20 + args.PerPage = 20 } if len(args.Verbosity) == 0 { args.Verbosity = deliveryservice.VerbosityDetailed @@ -231,12 +232,14 @@ func DownloadDeliveryChart(c *gin.Context) { chartName := c.Query("chartName") projectName := c.Query("projectName") - filePath, err := deliveryservice.DownloadDeliveryChart(projectName, versionName, chartName, ctx.Logger) + fileBytes, fileName, err := deliveryservice.DownloadDeliveryChart(projectName, versionName, chartName, ctx.Logger) if err != nil { ctx.Err = err return } - c.File(filePath) + + c.Writer.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, fileName)) + c.Data(http.StatusOK, "application/octet-stream", fileBytes) } func PreviewGetDeliveryChart(c *gin.Context) { diff --git a/pkg/microservice/aslan/core/delivery/service/version.go b/pkg/microservice/aslan/core/delivery/service/version.go index 5524f87d8..e839a7ddf 100644 --- a/pkg/microservice/aslan/core/delivery/service/version.go +++ b/pkg/microservice/aslan/core/delivery/service/version.go @@ -17,7 +17,6 @@ limitations under the License. package service import ( - "bytes" "encoding/json" "fmt" "io" @@ -25,7 +24,6 @@ import ( "net/http" "net/url" "os" - "os/exec" "path/filepath" "strings" "sync" @@ -181,7 +179,7 @@ func GetDetailReleaseData(args *commonrepo.DeliveryVersionArgs, log *zap.Sugared log.Errorf("get deliveryVersion error: %v", err) return nil, e.ErrGetDeliveryVersion } - return buildReleaseRespData(VerbosityDetailed, versionData, nil, log) + return buildListReleaseResp(VerbosityDetailed, versionData, nil, log) } func FindDeliveryVersion(args *commonrepo.DeliveryVersionArgs, log *zap.SugaredLogger) ([]*commonmodels.DeliveryVersion, error) { @@ -316,14 +314,15 @@ func buildDetailedRelease(deliveryVersion *commonmodels.DeliveryVersion, filterO deliveryDistributeArgs := new(commonrepo.DeliveryDistributeArgs) deliveryDistributeArgs.ReleaseID = deliveryVersion.ID.Hex() deliveryDistributes, _ := FindDeliveryDistribute(deliveryDistributeArgs, logger) + releaseInfo.DistributeInfo = deliveryDistributes - deliveryVersion.Progress = FillDeliveryProgressInfo(deliveryVersion, deliveryDistributes) + // fill some data for helm delivery releases + processReleaseRespData(releaseInfo) - releaseInfo.DistributeInfo = deliveryDistributes return releaseInfo, nil } -func buildReleaseRespData(verbosity string, deliveryVersion *commonmodels.DeliveryVersion, filterOpt *DeliveryVersionFilter, logger *zap.SugaredLogger) (*ReleaseInfo, error) { +func buildListReleaseResp(verbosity string, deliveryVersion *commonmodels.DeliveryVersion, filterOpt *DeliveryVersionFilter, logger *zap.SugaredLogger) (*ReleaseInfo, error) { switch verbosity { case VerbosityBrief: return buildBriefRelease(deliveryVersion, logger) @@ -335,21 +334,20 @@ func buildReleaseRespData(verbosity string, deliveryVersion *commonmodels.Delive } func ListDeliveryVersion(args *ListDeliveryVersionArgs, logger *zap.SugaredLogger) ([]*ReleaseInfo, error) { - version := new(commonrepo.DeliveryVersionArgs) - version.ProductName = args.ProjectName - version.WorkflowName = args.WorkflowName - version.TaskID = args.TaskId - version.PerPage = args.PerPage - version.Page = args.Page - deliveryVersions, err := FindDeliveryVersion(version, logger) + versionListArgs := new(commonrepo.DeliveryVersionArgs) + versionListArgs.ProductName = args.ProjectName + versionListArgs.WorkflowName = args.WorkflowName + versionListArgs.TaskID = args.TaskId + versionListArgs.PerPage = args.PerPage + versionListArgs.Page = args.Page + deliveryVersions, err := FindDeliveryVersion(versionListArgs, logger) if err != nil { return nil, err } - log.Infof("###### the verbosity is %s, projectName is %s", args.Verbosity, args.ProjectName) releaseInfos := make([]*ReleaseInfo, 0) for _, deliveryVersion := range deliveryVersions { - releaseInfo, err := buildReleaseRespData(args.Verbosity, deliveryVersion, &DeliveryVersionFilter{ServiceName: args.ServiceName}, logger) + releaseInfo, err := buildListReleaseResp(args.Verbosity, deliveryVersion, &DeliveryVersionFilter{ServiceName: args.ServiceName}, logger) if err != nil { return nil, err } @@ -361,17 +359,50 @@ func ListDeliveryVersion(args *ListDeliveryVersionArgs, logger *zap.SugaredLogge return releaseInfos, nil } -func FillDeliveryProgressInfo(deliveryVersion *commonmodels.DeliveryVersion, deliveryDistribute []*commonmodels.DeliveryDistribute) *commonmodels.DeliveryVersionProgress { - if deliveryVersion.Type != setting.DeliveryVersionTypeChart { - return nil +// fill release +func processReleaseRespData(release *ReleaseInfo) { + if release.VersionInfo.Type != setting.DeliveryVersionTypeChart { + return } - chartDeploys := make([]*commonmodels.DeliveryDistribute, 0) - for _, deliveryDistribute := range deliveryDistribute { - if deliveryDistribute.DistributeType == config.Chart { - chartDeploys = append(chartDeploys, deliveryDistribute) + + distributeMap := make(map[string][]*commonmodels.DeliveryDistribute) + for _, distributeImage := range release.DistributeInfo { + if distributeImage.DistributeType != config.Image { + continue + } + distributeMap[distributeImage.ChartName] = append(distributeMap[distributeImage.ChartName], distributeImage) + } + + chartDistributeCount := 0 + distributes := make([]*commonmodels.DeliveryDistribute, 0) + for _, distribute := range release.DistributeInfo { + if distribute.DistributeType == config.Image { + continue } + switch distribute.DistributeType { + case config.Chart: + chartDistributeCount++ + distribute.SubDistributes = distributeMap[distribute.ChartName] + case config.File: + s3Storage, err := commonrepo.NewS3StorageColl().Find(distribute.S3StorageID) + if err != nil { + log.Errorf("failed to query s3 storageID: %s, err: %s", distribute.S3StorageID, err) + } else { + distribute.StorageURL = s3Storage.Endpoint + distribute.StorageBucket = s3Storage.Bucket + } + } + distributes = append(distributes, distribute) + } + release.DistributeInfo = distributes + + release.VersionInfo.Progress = buildDeliveryProgressInfo(release.VersionInfo, chartDistributeCount) +} + +func buildDeliveryProgressInfo(deliveryVersion *commonmodels.DeliveryVersion, successfulChartCount int) *commonmodels.DeliveryVersionProgress { + if deliveryVersion.Type != setting.DeliveryVersionTypeChart { + return nil } - successfulChartCount := len(chartDeploys) progress := &commonmodels.DeliveryVersionProgress{ SuccessChartCount: successfulChartCount, @@ -454,18 +485,8 @@ func createChartRepoClient(repo *commonmodels.HelmRepo) (*cm.Client, error) { return client, nil } -func runDockerCommand(cmd *exec.Cmd) error { - var out bytes.Buffer - cmd.Stdout = &out - cmd.Stderr = &out - if err := cmd.Run(); err != nil { - return err - } - return nil -} - // pull image from currently using registry and push to specified repo -func pushImages(serviceObj *commonmodels.Service, valuesMap map[string]interface{}, targetRegistry *commonmodels.RegistryNamespace, registryMap map[string]*commonmodels.RegistryNamespace) error { +func pushImages(deliveryVersion *commonmodels.DeliveryVersion, serviceObj *commonmodels.Service, valuesMap map[string]interface{}, targetRegistry *commonmodels.RegistryNamespace, registryMap map[string]*commonmodels.RegistryNamespace) error { log.Infof("######## start pushing image #########") @@ -495,12 +516,6 @@ func pushImages(serviceObj *commonmodels.Service, valuesMap map[string]interface imageUris = append(imageUris, imageUri) } - // login to the target repo - err = runDockerCommand(dockerLogin(targetRegistry.AccessKey, targetRegistry.SecretKey, targetRegistry.RegAddr)) - if err != nil { - return errors.Wrapf(err, fmt.Sprintf("failed to login docker registry, url: %s", targetRegistry.RegAddr)) - } - for _, imageUri := range imageUris { log.Infof("##### handle single image uri %s ######", imageUri) registryUrl, err := commonservice.ExtractImageRegistry(imageUri) @@ -509,40 +524,37 @@ func pushImages(serviceObj *commonmodels.Service, valuesMap map[string]interface } registryUrl = strings.TrimSuffix(registryUrl, "/") log.Infof("#### extract registry url %s ####", registryUrl) - if registry, ok := registryMap[registryUrl]; ok { - if registry.ID == targetRegistry.ID { - log.Infof("######## same registry, no need to push again ########") - continue - } - //TODO need optimize to avoid login to same repo multiple times - err := runDockerCommand(dockerLogin(registry.AccessKey, registry.SecretKey, registry.RegAddr)) - if err != nil { - return errors.Wrapf(err, fmt.Sprintf("failed to login docker registry, url: %s", registry.RegAddr)) - } - } - err = runDockerCommand(dockerPull(imageUri)) - if err != nil { - return errors.Wrapf(err, fmt.Sprintf("failed to pull docker image, source url: %s", imageUri)) - } imageName := commonservice.ExtractImageName(imageUri) imageTag := commonservice.ExtractImageTag(imageUri) + imageNamespace := commonservice.ExtractRegistryNamespace(imageUri) + targetFullImageUri := imageUri - targetFullImageUri := fmt.Sprintf("%s/%s/%s:%s", targetRegistry.RegAddr, targetRegistry.Namespace, imageName, imageTag) - err = runDockerCommand(dockerTag(imageUri, targetFullImageUri)) - if err != nil { - return errors.Wrapf(err, "failed to tag image from: %s to : %s", imageUri, targetFullImageUri) + if registry, ok := registryMap[registryUrl]; ok { + if registry.ID != targetRegistry.ID { + targetFullImageUri = fmt.Sprintf("%s/%s/%s:%s", targetRegistry.RegAddr, targetRegistry.Namespace, imageName, imageTag) + } } - err = runDockerCommand(dockerPush(targetFullImageUri)) + // add image distribution data + err = commonrepo.NewDeliveryDistributeColl().Insert(&commonmodels.DeliveryDistribute{ + ReleaseID: deliveryVersion.ID, + ServiceName: imageName, + ChartName: serviceObj.ServiceName, + DistributeType: config.Image, + RegistryName: targetFullImageUri, + Namespace: imageNamespace, + CreatedAt: time.Now().Unix(), + }) if err != nil { - return errors.Wrapf(err, "failed to push image: %s", targetFullImageUri) + log.Errorf("failed to insert image distribute data, version: %s, image: %s, err: %s", deliveryVersion.Version, targetFullImageUri, err) + return fmt.Errorf("failed to insert image distribute data") } } return nil } -func handleSingleChart(chartData *DeliveryChartData, chartRepo *commonmodels.HelmRepo, dir string, globalVariables string, targetRegistry *commonmodels.RegistryNamespace, registryMap map[string]*commonmodels.RegistryNamespace) error { +func handleSingleChart(deliveryVersion *commonmodels.DeliveryVersion, chartData *DeliveryChartData, chartRepo *commonmodels.HelmRepo, dir string, globalVariables string, targetRegistry *commonmodels.RegistryNamespace, registryMap map[string]*commonmodels.RegistryNamespace) error { serviceObj := chartData.ServiceObj serviceName, revision := serviceObj.ServiceName, serviceObj.Revision basePath := config.LocalServicePathWithRevision(serviceObj.ProductName, serviceName, revision) @@ -599,7 +611,7 @@ func handleSingleChart(chartData *DeliveryChartData, chartRepo *commonmodels.Hel } // push docker image - err = pushImages(serviceObj, chartRequested.Values, targetRegistry, registryMap) + err = pushImages(deliveryVersion, serviceObj, chartRequested.Values, targetRegistry, registryMap) if err != nil { return errors.Wrapf(err, "failed to handle image") } @@ -762,10 +774,10 @@ func buildDeliveryCharts(chartDataMap map[string]*DeliveryChartData, deliveryVer return fmt.Errorf("failed to build registry map") } - err = runDockerCommand(dockerInfo()) - if err != nil { - return fmt.Errorf("failed to run docker deamon") - } + //err = runDockerCommand(dockerInfo()) + //if err != nil { + // return fmt.Errorf("failed to run docker deamon") + //} // push charts to repo wg := sync.WaitGroup{} @@ -773,19 +785,24 @@ func buildDeliveryCharts(chartDataMap map[string]*DeliveryChartData, deliveryVer wg.Add(1) go func(cData *DeliveryChartData) { defer wg.Done() - err := handleSingleChart(cData, repoInfo, dir, args.GlobalVariables, targetRegistry, registryMap) + err := handleSingleChart(deliveryVersion, cData, repoInfo, dir, args.GlobalVariables, targetRegistry, registryMap) if err != nil { logger.Errorf("failed to handle single chart data, serviceName: %s err: %s", cData.ChartData.ServiceName, err) appendError(err) - } else { - //err = commonrepo.NewDeliveryVersionColl().AddDeliveryChart(deliveryVersion.Version, &commonmodels.DeliveryChart{ - // Name: cData.ChartData.ServiceName, - // Version: cData.ChartData.Version, - // Repo: args.ChartRepoName, - //}) - //if err != nil { - // appendError(errors.Wrapf(err, "failed to save delivery chart: %s", cData.ChartData.ServiceName)) - //} + return + } + err = commonrepo.NewDeliveryDistributeColl().Insert(&commonmodels.DeliveryDistribute{ + ReleaseID: deliveryVersion.ID, + DistributeType: config.Chart, + ChartName: cData.ChartData.ServiceName, + ChartVersion: cData.ChartData.Version, + ChartRepoName: args.ChartRepoName, + SubDistributes: nil, + CreatedAt: time.Now().Unix(), + }) + if err != nil { + logger.Errorf("failed to insert delivery distribute chart, serviceName: %s, err: %s", cData.ChartData.ServiceName, err) + appendError(err) } }(chartData) } @@ -801,14 +818,28 @@ func buildDeliveryCharts(chartDataMap map[string]*DeliveryChartData, deliveryVer return } - //tar all chart files and send to s3 store + //tar all chart files and image offline packages, send to s3 store fsTree := os.DirFS(dir) - ServiceS3Base := configbase.ObjectStorageDeliveryVersionPath(deliveryVersion.ProductName) - if err = fsservice.ArchiveAndUploadFilesToSpecifiedS3(fsTree, deliveryVersion.Version, ServiceS3Base, nil, args.Options.S3StorageID, logger); err != nil { + s3Base := configbase.ObjectStorageDeliveryVersionPath(deliveryVersion.ProductName) + if err = fsservice.ArchiveAndUploadFilesToSpecifiedS3(fsTree, deliveryVersion.Version, s3Base, nil, args.Options.S3StorageID, logger); err != nil { logger.Errorf("failed to upload chart package files for project %s, err: %s", deliveryVersion.ProductName, err) err = errors.Wrapf(err, "failed to upload package file") return } + + err = commonrepo.NewDeliveryDistributeColl().Insert(&commonmodels.DeliveryDistribute{ + ReleaseID: deliveryVersion.ID, + DistributeType: config.File, + PackageFile: fmt.Sprintf("%s.tar.gz", deliveryVersion.Version), + RemoteFileKey: filepath.Join(s3Base, fmt.Sprintf("%s.tar.gz", deliveryVersion.Version)), + S3StorageID: args.Options.S3StorageID, + CreatedAt: time.Now().Unix(), + }) + if err != nil { + logger.Errorf("failed to insert file distribute data, version: %s, err: %s", deliveryVersion.Version, err) + return fmt.Errorf("failed to insert file distribute data") + } + return } @@ -896,16 +927,26 @@ func RetryCreateHelmDeliveryVersion(projectName, versionName string, logger *zap //deploys := make + distributes, err := commonrepo.NewDeliveryDistributeColl().Find(&commonrepo.DeliveryDistributeArgs{ + ReleaseID: deliveryVersion.ID.Hex(), + }) + if err != nil { + return errors.Wrapf(err, "failed to query distrubutes, versionName: %s", deliveryVersion.Version) + } + // for charts has been successfully handled, download charts directly successCharts := sets.NewString() - //for _, singleChart := range deliveryVersion.Charts { - // _, err := downloadChart(projectName, versionName, singleChart) - // if err != nil { - // log.Errorf("failed to download chart from chart repo, chartName: %s, err: %s", singleChart.Name, err) - // continue - // } - // successCharts.Insert(singleChart.Name) - //} + for _, distribute := range distributes { + if distribute.DistributeType != config.Chart { + continue + } + _, err := downloadChart(deliveryVersion, distribute) + if err != nil { + log.Errorf("failed to download chart from chart repo, chartName: %s, err: %s", distribute.ChartName, err) + continue + } + successCharts.Insert(distribute.ChartName) + } chartsToBeHandled := make([]*CreateHelmDeliveryVersionChartData, 0) for _, chartConfig := range createArgs.ChartDatas { @@ -963,8 +1004,9 @@ func ListDeliveryServiceNames(productName string, log *zap.SugaredLogger) ([]str return serviceNames.UnsortedList(), nil } -func downloadChart(productName, versionName string, chartInfo *commonmodels.DeliveryDistribute) (string, error) { - chartTGZName := fmt.Sprintf("%s-%s.tgz", chartInfo.ServiceName, chartInfo.Version) +func downloadChart(deliveryVersion *commonmodels.DeliveryVersion, chartInfo *commonmodels.DeliveryDistribute) (string, error) { + productName, versionName := deliveryVersion.ProductName, deliveryVersion.Version + chartTGZName := fmt.Sprintf("%s-%s.tgz", chartInfo.ChartName, chartInfo.ChartVersion) chartTGZFileParent := getChartTGZDir(productName, versionName) chartTGZFilePath := filepath.Join(chartTGZFileParent, chartTGZName) if _, err := os.Stat(chartTGZFilePath); err == nil { @@ -1019,25 +1061,16 @@ func downloadChart(productName, versionName string, chartInfo *commonmodels.Deli return chartTGZFilePath, nil } -func getChartDistributeInfo(projectName, version string, chartName string, log *zap.SugaredLogger) (*commonmodels.DeliveryDistribute, error) { - //deliveryVersion, err := GetDeliveryVersion(&commonrepo.DeliveryVersionArgs{ - // ProductName: projectName, - // Version: version, - //}, log) - - //if err != nil { - // return nil, err - //} - +func getChartDistributeInfo(releaseID, chartName string, log *zap.SugaredLogger) (*commonmodels.DeliveryDistribute, error) { distributes, _ := FindDeliveryDistribute(&commonrepo.DeliveryDistributeArgs{ - ReleaseID: "", + ReleaseID: releaseID, ServiceName: chartName, DistributeType: config.Chart, }, log) var chartInfo *commonmodels.DeliveryDistribute for _, distribute := range distributes { - if distribute.ServiceName == chartName { + if distribute.ChartName == chartName { chartInfo = distribute } } @@ -1048,13 +1081,36 @@ func getChartDistributeInfo(projectName, version string, chartName string, log * return chartInfo, nil } -func DownloadDeliveryChart(projectName, version string, chartName string, log *zap.SugaredLogger) (string, error) { - chartInfo, err := getChartDistributeInfo(projectName, version, chartName, log) +func DownloadDeliveryChart(projectName, version string, chartName string, log *zap.SugaredLogger) ([]byte, string, error) { + + filePath, err := preDownloadChart(projectName, version, chartName, log) + if err != nil { + return nil, "", err + } + + fileBytes, err := os.ReadFile(filePath) + if err != nil { + return nil, "", err + } + + return fileBytes, filepath.Base(filePath), err +} + +func preDownloadChart(projectName, versionName, chartName string, log *zap.SugaredLogger) (string, error) { + deliveryInfo, err := GetDeliveryVersion(&commonrepo.DeliveryVersionArgs{ + ProductName: projectName, + Version: versionName, + }, log) + if err != nil { + return "", fmt.Errorf("failed to query delivery info") + } + + chartInfo, err := getChartDistributeInfo(deliveryInfo.ID.Hex(), chartName, log) if err != nil { return "", err } // prepare chart data - filePath, err := downloadChart(projectName, version, chartInfo) + filePath, err := downloadChart(deliveryInfo, chartInfo) if err != nil { return "", err } @@ -1063,14 +1119,22 @@ func DownloadDeliveryChart(projectName, version string, chartName string, log *z func preDownloadAndUncompressChart(projectName, versionName, chartName string, log *zap.SugaredLogger) (string, error) { - chartDistribute, err := getChartDistributeInfo(projectName, versionName, chartName, log) + deliveryInfo, err := GetDeliveryVersion(&commonrepo.DeliveryVersionArgs{ + ProductName: projectName, + Version: versionName, + }, log) + if err != nil { + return "", fmt.Errorf("failed to query delivery info") + } + + chartDistribute, err := getChartDistributeInfo(deliveryInfo.ID.Hex(), chartName, log) if err != nil { return "", err } dstDir := getChartExpandDir(projectName, versionName) - dstDir = filepath.Join(dstDir, fmt.Sprintf("%s-%s", chartDistribute.ServiceName, chartDistribute.Version)) + dstDir = filepath.Join(dstDir, fmt.Sprintf("%s-%s", chartDistribute.ChartName, chartDistribute.ChartVersion)) - filePath, err := DownloadDeliveryChart(projectName, versionName, chartName, log) + filePath, err := preDownloadChart(projectName, versionName, chartName, log) if err != nil { return "", err } -- Gitee From 9cc7c849cb101ce60fdb695e4dd6a6b3cce27721 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Mon, 29 Nov 2021 18:05:24 +0800 Subject: [PATCH 010/134] add cluster config Signed-off-by: liu deyi --- .../common/repository/models/k8s_cluster.go | 36 +++++++++++-------- .../core/common/repository/models/queue.go | 1 + .../common/repository/models/task/build.go | 1 + .../common/repository/models/task/testing.go | 2 ++ .../common/repository/mongodb/k8s_cluster.go | 17 +++++++++ .../core/common/service/config_payload.go | 4 +++ .../aslan/core/common/service/environment.go | 5 +-- .../aslan/core/common/service/kube/service.go | 4 --- .../aslan/core/common/service/product.go | 4 ++- .../core/environment/service/configmap.go | 8 +++-- .../core/environment/service/environment.go | 7 ++-- .../service/environment_creator.go | 5 +-- .../environment/service/environment_group.go | 4 ++- .../aslan/core/environment/service/export.go | 5 +-- .../aslan/core/environment/service/image.go | 4 ++- .../aslan/core/environment/service/k8s.go | 7 ++-- .../aslan/core/environment/service/kube.go | 13 +++---- .../aslan/core/environment/service/service.go | 14 ++++---- .../aslan/core/service/service/service.go | 6 ++-- .../aslan/core/system/service/registry.go | 7 ++-- .../service/workflow/pipeline_validation.go | 4 +-- .../service/workflow/workflow_task.go | 4 +++ .../core/service/taskplugin/build.go | 32 +++++++++++++---- .../core/service/taskplugin/testing.go | 14 ++++---- .../core/service/types/task/build.go | 1 + .../core/service/types/task/config_payload.go | 18 ++++++++++ .../core/service/types/task/testing.go | 2 ++ pkg/shared/kube/resource/namespace.go | 2 ++ pkg/shared/kube/wrapper/namespace.go | 10 +++--- 29 files changed, 166 insertions(+), 75 deletions(-) diff --git a/pkg/microservice/aslan/core/common/repository/models/k8s_cluster.go b/pkg/microservice/aslan/core/common/repository/models/k8s_cluster.go index f3f60b219..4ddf9fd9e 100644 --- a/pkg/microservice/aslan/core/common/repository/models/k8s_cluster.go +++ b/pkg/microservice/aslan/core/common/repository/models/k8s_cluster.go @@ -29,21 +29,22 @@ import ( var namePattern = regexp.MustCompile(`^[0-9a-zA-Z_.-]{1,32}$`) type K8SCluster struct { - ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` - Name string `json:"name" bson:"name"` - Tags []string `json:"tags" bson:"tags"` - Description string `json:"description" bson:"description"` - Namespace string `json:"namespace" bson:"namespace"` - Info *K8SClusterInfo `json:"info,omitempty" bson:"info,omitempty"` - Status config.K8SClusterStatus `json:"status" bson:"status"` - Error string `json:"error" bson:"error"` - Yaml string `json:"yaml" bson:"yaml"` - Production bool `json:"production" bson:"production"` - CreatedAt int64 `json:"createdAt" bson:"createdAt"` - CreatedBy string `json:"createdBy" bson:"createdBy"` - Disconnected bool `json:"-" bson:"disconnected"` - Token string `json:"token" bson:"-"` - Provider int8 `json:"provider" bson:"provider"` + ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` + Name string `json:"name" bson:"name"` + Tags []string `json:"tags" bson:"tags"` + Description string `json:"description" bson:"description"` + Namespace string `json:"namespace" bson:"namespace"` + Info *K8SClusterInfo `json:"info,omitempty" bson:"info,omitempty"` + ClusterConfig *ClusterConfig `json:"config,omitempty" bson:"config,omitempty"` + Status config.K8SClusterStatus `json:"status" bson:"status"` + Error string `json:"error" bson:"error"` + Yaml string `json:"yaml" bson:"yaml"` + Production bool `json:"production" bson:"production"` + CreatedAt int64 `json:"createdAt" bson:"createdAt"` + CreatedBy string `json:"createdBy" bson:"createdBy"` + Disconnected bool `json:"-" bson:"disconnected"` + Token string `json:"token" bson:"-"` + Provider int8 `json:"provider" bson:"provider"` } type K8SClusterInfo struct { @@ -53,6 +54,11 @@ type K8SClusterInfo struct { Memory string `json:"memory" bson:"memory"` } +type ClusterConfig struct { + Strategy string `json:"strategy,omitempty" bson:"strategy,omitempty"` + NodeLabels []string `json:"node_labels,omitempty" bson:"node_labels,omitempty"` +} + func (K8SCluster) TableName() string { return "k8s_cluster" } diff --git a/pkg/microservice/aslan/core/common/repository/models/queue.go b/pkg/microservice/aslan/core/common/repository/models/queue.go index 7801b2c46..b60f7e0f6 100644 --- a/pkg/microservice/aslan/core/common/repository/models/queue.go +++ b/pkg/microservice/aslan/core/common/repository/models/queue.go @@ -136,6 +136,7 @@ type ConfigPayload struct { ResetCache bool `json:"reset_cache"` JenkinsBuildConfig JenkinsBuildConfig `json:"jenkins_build_config"` PrivateKeys []*PrivateKey `json:"private_keys"` + K8SClusters []*K8SCluster `json:"k8s_cluster"` } type AslanConfig struct { diff --git a/pkg/microservice/aslan/core/common/repository/models/task/build.go b/pkg/microservice/aslan/core/common/repository/models/task/build.go index c82112975..bd75aa2bc 100644 --- a/pkg/microservice/aslan/core/common/repository/models/task/build.go +++ b/pkg/microservice/aslan/core/common/repository/models/task/build.go @@ -59,6 +59,7 @@ type Build struct { // Get the host bound to the environment of the cloud host service configuration EnvHostInfo map[string][]string `bson:"env_host_info,omitempty" json:"env_host_info,omitempty"` ArtifactInfo *ArtifactInfo `bson:"artifact_info,omitempty" json:"artifact_info,omitempty"` + ClusterID string `bson:"cluster_id,omitempty" json:"cluster_id,omitempty"` } type ArtifactInfo struct { diff --git a/pkg/microservice/aslan/core/common/repository/models/task/testing.go b/pkg/microservice/aslan/core/common/repository/models/task/testing.go index f6aaab8a3..d2c2c80e0 100644 --- a/pkg/microservice/aslan/core/common/repository/models/task/testing.go +++ b/pkg/microservice/aslan/core/common/repository/models/task/testing.go @@ -45,6 +45,8 @@ type Testing struct { ReportReady bool `bson:"report_ready" json:"report_ready"` IsRestart bool `bson:"is_restart" json:"is_restart"` Registries []*models.RegistryNamespace `bson:"-" json:"registries"` + ClusterID string `bson:"cluster_id,omitempty" json:"cluster_id,omitempty"` + Namespace string `bson:"namespace" json:"namespace"` } func (t *Testing) ToSubTask() (map[string]interface{}, error) { diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/k8s_cluster.go b/pkg/microservice/aslan/core/common/repository/mongodb/k8s_cluster.go index 31f5efc8d..7e05ce65e 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/k8s_cluster.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/k8s_cluster.go @@ -201,3 +201,20 @@ func (c *K8SClusterColl) GetByToken(token string) (*models.K8SCluster, error) { return c.Get(id) } + +func (c *K8SClusterColl) List() ([]*models.K8SCluster, error) { + resp := make([]*models.K8SCluster, 0) + ctx := context.Background() + + cursor, err := c.Collection.Find(ctx, bson.M{}) + if err != nil { + return nil, err + } + + err = cursor.All(ctx, &resp) + if err != nil { + return nil, err + } + + return resp, err +} diff --git a/pkg/microservice/aslan/core/common/service/config_payload.go b/pkg/microservice/aslan/core/common/service/config_payload.go index ac244fe38..b3c2808f3 100644 --- a/pkg/microservice/aslan/core/common/service/config_payload.go +++ b/pkg/microservice/aslan/core/common/service/config_payload.go @@ -89,5 +89,9 @@ func GetConfigPayload(codeHostID int) *models.ConfigPayload { payload.PrivateKeys = privateKeys } + k8sClusters, _ := mongodb.NewK8SClusterColl().List() + if len(k8sClusters) != 0 { + payload.K8SClusters = k8sClusters + } return payload } diff --git a/pkg/microservice/aslan/core/common/service/environment.go b/pkg/microservice/aslan/core/common/service/environment.go index 6212da278..61b2cddce 100644 --- a/pkg/microservice/aslan/core/common/service/environment.go +++ b/pkg/microservice/aslan/core/common/service/environment.go @@ -26,16 +26,17 @@ import ( "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/sets" + "github.com/koderover/zadig/pkg/microservice/aslan/config" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" templatemodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/template" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" templaterepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb/template" - "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/shared/kube/resource" "github.com/koderover/zadig/pkg/shared/kube/wrapper" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/kube/getter" + "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/util" jsonutil "github.com/koderover/zadig/pkg/util/json" ) @@ -208,7 +209,7 @@ func ListWorkloads(envName, clusterID, namespace, productName string, perPage, p log.Infof("Start to list workloads in namespace %s", namespace) var resp = make([]*ServiceResp, 0) - kubeClient, err := kube.GetKubeClient(clusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), clusterID) if err != nil { log.Errorf("[%s][%s] error: %v", envName, namespace, err) return 0, resp, e.ErrListGroups.AddDesc(err.Error()) diff --git a/pkg/microservice/aslan/core/common/service/kube/service.go b/pkg/microservice/aslan/core/common/service/kube/service.go index ee405bfef..8f092f71e 100644 --- a/pkg/microservice/aslan/core/common/service/kube/service.go +++ b/pkg/microservice/aslan/core/common/service/kube/service.go @@ -36,10 +36,6 @@ import ( "github.com/koderover/zadig/pkg/tool/kube/multicluster" ) -func GetKubeClient(clusterID string) (client.Client, error) { - return multicluster.GetKubeClient(config.HubServerAddress(), clusterID) -} - func GetKubeAPIReader(clusterID string) (client.Reader, error) { return multicluster.GetKubeAPIReader(config.HubServerAddress(), clusterID) } diff --git a/pkg/microservice/aslan/core/common/service/product.go b/pkg/microservice/aslan/core/common/service/product.go index 9986f3575..2a024a065 100644 --- a/pkg/microservice/aslan/core/common/service/product.go +++ b/pkg/microservice/aslan/core/common/service/product.go @@ -27,6 +27,7 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/koderover/zadig/pkg/microservice/aslan/config" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" @@ -36,6 +37,7 @@ import ( "github.com/koderover/zadig/pkg/setting" e "github.com/koderover/zadig/pkg/tool/errors" helmtool "github.com/koderover/zadig/pkg/tool/helmclient" + "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/kube/updater" ) @@ -51,7 +53,7 @@ func DeleteProduct(username, envName, productName, requestID string, log *zap.Su return e.ErrDeleteEnv.AddDesc("not found") } - kubeClient, err := kube.GetKubeClient(productInfo.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), productInfo.ClusterID) if err != nil { return e.ErrDeleteEnv.AddErr(err) } diff --git a/pkg/microservice/aslan/core/environment/service/configmap.go b/pkg/microservice/aslan/core/environment/service/configmap.go index bbb634c57..038b0f07f 100644 --- a/pkg/microservice/aslan/core/environment/service/configmap.go +++ b/pkg/microservice/aslan/core/environment/service/configmap.go @@ -28,6 +28,7 @@ import ( "k8s.io/apimachinery/pkg/labels" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/koderover/zadig/pkg/microservice/aslan/config" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" @@ -35,6 +36,7 @@ import ( "github.com/koderover/zadig/pkg/shared/kube/wrapper" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/kube/getter" + "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/kube/updater" "github.com/koderover/zadig/pkg/tool/kube/util" ) @@ -98,7 +100,7 @@ func ListConfigMaps(args *ListConfigMapArgs, log *zap.SugaredLogger) ([]*configM if err != nil { return nil, e.ErrListConfigMaps.AddErr(err) } - kubeClient, err := kube.GetKubeClient(product.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), product.ClusterID) if err != nil { return nil, e.ErrListConfigMaps.AddErr(err) } @@ -153,7 +155,7 @@ func UpdateConfigMap(envName string, args *UpdateConfigMapArgs, userName, userID if err != nil { return e.ErrUpdateConfigMap.AddErr(err) } - kubeClient, err := kube.GetKubeClient(product.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), product.ClusterID) if err != nil { return e.ErrUpdateConfigMap.AddErr(err) } @@ -230,7 +232,7 @@ func RollBackConfigMap(envName string, args *RollBackConfigMapArgs, userName, us if err != nil { return e.ErrUpdateConfigMap.AddErr(err) } - kubeClient, err := kube.GetKubeClient(product.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), product.ClusterID) if err != nil { return e.ErrUpdateConfigMap.AddErr(err) } diff --git a/pkg/microservice/aslan/core/environment/service/environment.go b/pkg/microservice/aslan/core/environment/service/environment.go index 57de424a1..f708a2ff0 100644 --- a/pkg/microservice/aslan/core/environment/service/environment.go +++ b/pkg/microservice/aslan/core/environment/service/environment.go @@ -58,6 +58,7 @@ import ( e "github.com/koderover/zadig/pkg/tool/errors" helmtool "github.com/koderover/zadig/pkg/tool/helmclient" "github.com/koderover/zadig/pkg/tool/kube/getter" + "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/kube/serializer" "github.com/koderover/zadig/pkg/tool/kube/updater" "github.com/koderover/zadig/pkg/tool/log" @@ -276,7 +277,7 @@ func AutoUpdateProduct(envNames []string, productName, requestID string, force b continue } - kubeClient, err := kube.GetKubeClient(p.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), p.ClusterID) if err != nil { log.Errorf("Failed to get kube client for %s, error: %v", productName, err) continue @@ -388,7 +389,7 @@ func UpdateProduct(existedProd, updateProd *commonmodels.Product, renderSet *com return } - kubeClient, err := kube.GetKubeClient(existedProd.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), existedProd.ClusterID) if err != nil { return e.ErrUpdateEnv.AddErr(err) } @@ -532,7 +533,7 @@ func UpdateProductV2(envName, productName, user, requestID string, force bool, k return e.ErrUpdateEnv.AddDesc(e.EnvNotFoundErrMsg) } - kubeClient, err := kube.GetKubeClient(exitedProd.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), exitedProd.ClusterID) if err != nil { return e.ErrUpdateEnv.AddErr(err) } diff --git a/pkg/microservice/aslan/core/environment/service/environment_creator.go b/pkg/microservice/aslan/core/environment/service/environment_creator.go index f8c5a8d64..b73b49e91 100644 --- a/pkg/microservice/aslan/core/environment/service/environment_creator.go +++ b/pkg/microservice/aslan/core/environment/service/environment_creator.go @@ -33,6 +33,7 @@ import ( e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/helmclient" "github.com/koderover/zadig/pkg/tool/kube/getter" + "github.com/koderover/zadig/pkg/tool/kube/multicluster" ) type CreateProductParam struct { @@ -120,7 +121,7 @@ func newHelmProductCreator() *HelmProductCreator { } func (creator *HelmProductCreator) Create(user, requestID string, args *models.Product, log *zap.SugaredLogger) error { - kubeClient, err := kube.GetKubeClient(args.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), args.ClusterID) if err != nil { log.Errorf("[%s][%s] GetKubeClient error: %v", args.EnvName, args.ProductName, err) return e.ErrCreateEnv.AddErr(err) @@ -277,7 +278,7 @@ func newDefaultProductCreator() *DefaultProductCreator { } func (creator *DefaultProductCreator) Create(user, requestID string, args *models.Product, log *zap.SugaredLogger) error { - kubeClient, err := kube.GetKubeClient(args.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), args.ClusterID) if err != nil { return e.ErrCreateEnv.AddErr(err) } diff --git a/pkg/microservice/aslan/core/environment/service/environment_group.go b/pkg/microservice/aslan/core/environment/service/environment_group.go index 70e8f6890..cb438525c 100644 --- a/pkg/microservice/aslan/core/environment/service/environment_group.go +++ b/pkg/microservice/aslan/core/environment/service/environment_group.go @@ -24,6 +24,7 @@ import ( "helm.sh/helm/v3/pkg/releaseutil" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/koderover/zadig/pkg/microservice/aslan/config" commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" @@ -32,6 +33,7 @@ import ( "github.com/koderover/zadig/pkg/shared/kube/resource" "github.com/koderover/zadig/pkg/shared/kube/wrapper" e "github.com/koderover/zadig/pkg/tool/errors" + "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/kube/serializer" "github.com/koderover/zadig/pkg/util" ) @@ -65,7 +67,7 @@ func ListGroups(serviceName, envName, productName string, perPage, page int, log //将获取到的所有服务按照名称进行排序 sort.SliceStable(allServices, func(i, j int) bool { return allServices[i].ServiceName < allServices[j].ServiceName }) - kubeClient, err := kube.GetKubeClient(productInfo.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), productInfo.ClusterID) if err != nil { log.Errorf("[%s][%s] error: %v", envName, productName, err) return resp, count, e.ErrListGroups.AddDesc(err.Error()) diff --git a/pkg/microservice/aslan/core/environment/service/export.go b/pkg/microservice/aslan/core/environment/service/export.go index 035c30d5b..775c62f6a 100644 --- a/pkg/microservice/aslan/core/environment/service/export.go +++ b/pkg/microservice/aslan/core/environment/service/export.go @@ -21,10 +21,11 @@ import ( "k8s.io/apimachinery/pkg/labels" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/koderover/zadig/pkg/microservice/aslan/config" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" - "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/tool/kube/getter" + "github.com/koderover/zadig/pkg/tool/kube/multicluster" ) // ExportYaml 查询使用到服务模板的服务组模板 @@ -39,7 +40,7 @@ func ExportYaml(envName, productName, serviceName string, log *zap.SugaredLogger } namespace := env.Namespace - kubeClient, err := kube.GetKubeClient(env.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), env.ClusterID) if err != nil { log.Errorf("cluster is not connected [%s][%s][%s]", env.EnvName, env.ProductName, env.ClusterID) return res diff --git a/pkg/microservice/aslan/core/environment/service/image.go b/pkg/microservice/aslan/core/environment/service/image.go index 4fd4bbf73..b1556b5bf 100644 --- a/pkg/microservice/aslan/core/environment/service/image.go +++ b/pkg/microservice/aslan/core/environment/service/image.go @@ -30,6 +30,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/yaml" + "github.com/koderover/zadig/pkg/microservice/aslan/config" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" templatemodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/template" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" @@ -39,6 +40,7 @@ import ( e "github.com/koderover/zadig/pkg/tool/errors" helmtool "github.com/koderover/zadig/pkg/tool/helmclient" "github.com/koderover/zadig/pkg/tool/kube/getter" + "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/kube/updater" "github.com/koderover/zadig/pkg/tool/log" "github.com/koderover/zadig/pkg/util" @@ -319,7 +321,7 @@ func UpdateContainerImage(requestID string, args *UpdateContainerImageArgs, log } namespace := product.Namespace - kubeClient, err := kube.GetKubeClient(product.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), product.ClusterID) if err != nil { return e.ErrUpdateConainterImage.AddErr(err) } diff --git a/pkg/microservice/aslan/core/environment/service/k8s.go b/pkg/microservice/aslan/core/environment/service/k8s.go index 3f922b06a..4606d4a28 100644 --- a/pkg/microservice/aslan/core/environment/service/k8s.go +++ b/pkg/microservice/aslan/core/environment/service/k8s.go @@ -25,18 +25,17 @@ import ( "github.com/hashicorp/go-multierror" "go.uber.org/zap" - "sigs.k8s.io/controller-runtime/pkg/client" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "sigs.k8s.io/controller-runtime/pkg/client" "github.com/koderover/zadig/pkg/microservice/aslan/config" commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" templaterepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb/template" commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" - "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" e "github.com/koderover/zadig/pkg/tool/errors" + "github.com/koderover/zadig/pkg/tool/kube/multicluster" ) type K8sService struct { @@ -84,7 +83,7 @@ func (k *K8sService) updateService(args *SvcOptArgs) error { return errors.New(e.UpsertServiceErrMsg) } - kubeClient, err := kube.GetKubeClient(exitedProd.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), exitedProd.ClusterID) if err != nil { return e.ErrUpdateEnv.AddErr(err) } diff --git a/pkg/microservice/aslan/core/environment/service/kube.go b/pkg/microservice/aslan/core/environment/service/kube.go index 684b534d8..c4ba3ff67 100644 --- a/pkg/microservice/aslan/core/environment/service/kube.go +++ b/pkg/microservice/aslan/core/environment/service/kube.go @@ -20,14 +20,14 @@ import ( "fmt" "time" - corev1 "k8s.io/api/core/v1" - "go.uber.org/zap" + corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" + "github.com/koderover/zadig/pkg/microservice/aslan/config" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" @@ -35,6 +35,7 @@ import ( "github.com/koderover/zadig/pkg/shared/kube/wrapper" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/kube/getter" + "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/kube/updater" "github.com/koderover/zadig/pkg/tool/kube/util" ) @@ -111,7 +112,7 @@ func ListPodEvents(envName, productName, podName string, log *zap.SugaredLogger) // ListAvailableNamespaces lists available namespaces created by non-koderover func ListAvailableNamespaces(clusterID string, log *zap.SugaredLogger) ([]*resource.Namespace, error) { resp := make([]*resource.Namespace, 0) - kubeClient, err := kube.GetKubeClient(clusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), clusterID) if err != nil { log.Errorf("ListNamespaces clusterID:%s err:%v", clusterID, err) return resp, err @@ -148,7 +149,7 @@ func ListServicePods(productName, envName string, serviceName string, log *zap.S if err != nil { return res, e.ErrListServicePod.AddErr(err) } - kubeClient, err := kube.GetKubeClient(product.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), product.ClusterID) if err != nil { return res, e.ErrListServicePod.AddErr(err) } @@ -175,7 +176,7 @@ func DeletePod(envName, productName, podName string, log *zap.SugaredLogger) err if err != nil { return e.ErrDeletePod.AddErr(err) } - kubeClient, err := kube.GetKubeClient(product.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), product.ClusterID) if err != nil { return e.ErrDeletePod.AddErr(err) } @@ -228,7 +229,7 @@ func getModifiedServiceFromObjectMeta(om metav1.Object) *serviceInfo { func ListAvailableNodes(clusterID string, log *zap.SugaredLogger) ([]*resource.Node, error) { resp := make([]*resource.Node, 0) - kubeClient, err := kube.GetKubeClient(clusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), clusterID) if err != nil { log.Errorf("ListAvailableNodes clusterID:%s err:%s", clusterID, err) return resp, err diff --git a/pkg/microservice/aslan/core/environment/service/service.go b/pkg/microservice/aslan/core/environment/service/service.go index 630d37647..d21d4e388 100644 --- a/pkg/microservice/aslan/core/environment/service/service.go +++ b/pkg/microservice/aslan/core/environment/service/service.go @@ -27,6 +27,7 @@ import ( "k8s.io/apimachinery/pkg/labels" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/koderover/zadig/pkg/microservice/aslan/config" commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" @@ -36,6 +37,7 @@ import ( "github.com/koderover/zadig/pkg/shared/kube/wrapper" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/kube/getter" + "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/kube/serializer" "github.com/koderover/zadig/pkg/tool/kube/updater" "github.com/koderover/zadig/pkg/tool/log" @@ -59,7 +61,7 @@ func ScaleService(envName, productName, serviceName string, number int, log *zap return e.ErrScaleService.AddErr(err) } - kubeClient, err := kube.GetKubeClient(prod.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), prod.ClusterID) if err != nil { return e.ErrScaleService.AddErr(err) } @@ -110,7 +112,7 @@ func Scale(args *ScaleArgs, logger *zap.SugaredLogger) error { return e.ErrScaleService.AddErr(err) } - kubeClient, err := kube.GetKubeClient(prod.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), prod.ClusterID) if err != nil { return e.ErrScaleService.AddErr(err) } @@ -140,7 +142,7 @@ func RestartScale(args *RestartScaleArgs, _ *zap.SugaredLogger) error { return err } - kubeClient, err := kube.GetKubeClient(prod.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), prod.ClusterID) if err != nil { return err } @@ -176,7 +178,7 @@ func GetService(envName, productName, serviceName string, workLoadType string, l return nil, e.ErrGetService.AddErr(err) } - kubeClient, err := kube.GetKubeClient(env.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), env.ClusterID) if err != nil { return nil, e.ErrGetService.AddErr(err) } @@ -322,7 +324,7 @@ func RestartService(envName string, args *SvcOptArgs, log *zap.SugaredLogger) (e if err != nil { return err } - kubeClient, err := kube.GetKubeClient(productObj.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), productObj.ClusterID) if err != nil { return err } @@ -421,7 +423,7 @@ func validateServiceContainer(envName, productName, serviceName, container strin return "", err } - kubeClient, err := kube.GetKubeClient(prod.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), prod.ClusterID) if err != nil { return "", err } diff --git a/pkg/microservice/aslan/core/service/service/service.go b/pkg/microservice/aslan/core/service/service/service.go index 73c3733f5..ab213cbd0 100644 --- a/pkg/microservice/aslan/core/service/service/service.go +++ b/pkg/microservice/aslan/core/service/service/service.go @@ -43,7 +43,6 @@ import ( commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/command" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/fs" - "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/microservice/aslan/core/environment/service" "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/shared/client/systemconfig" @@ -51,6 +50,7 @@ import ( "github.com/koderover/zadig/pkg/tool/gerrit" "github.com/koderover/zadig/pkg/tool/httpclient" "github.com/koderover/zadig/pkg/tool/kube/getter" + "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/log" "github.com/koderover/zadig/pkg/util" ) @@ -256,7 +256,7 @@ func GetServiceOption(args *commonmodels.Service, log *zap.SugaredLogger) (*Serv } func CreateK8sWorkLoads(ctx context.Context, requestID, username string, productName string, workLoads []models.Workload, clusterID, namespace string, envName string, log *zap.SugaredLogger) error { - kubeClient, err := kube.GetKubeClient(clusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), clusterID) if err != nil { log.Errorf("[%s] error: %v", namespace, err) return err @@ -385,7 +385,7 @@ type UpdateWorkloadsArgs struct { } func UpdateWorkloads(ctx context.Context, requestID, username, productName, envName string, args UpdateWorkloadsArgs, log *zap.SugaredLogger) error { - kubeClient, err := kube.GetKubeClient(args.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), args.ClusterID) if err != nil { log.Errorf("[%s] error: %s", args.Namespace, err) return err diff --git a/pkg/microservice/aslan/core/system/service/registry.go b/pkg/microservice/aslan/core/system/service/registry.go index 0aa8288ee..8df8afe05 100644 --- a/pkg/microservice/aslan/core/system/service/registry.go +++ b/pkg/microservice/aslan/core/system/service/registry.go @@ -22,13 +22,14 @@ import ( "go.uber.org/zap" + "github.com/koderover/zadig/pkg/microservice/aslan/config" commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" - "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/registry" "github.com/koderover/zadig/pkg/setting" e "github.com/koderover/zadig/pkg/tool/errors" + "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/util" ) @@ -86,7 +87,7 @@ func CreateRegistryNamespace(username string, args *commonmodels.RegistryNamespa } for _, env := range envs { go func(prod *commonmodels.Product) { - kubeClient, err := kube.GetKubeClient(prod.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), prod.ClusterID) if err != nil { log.Errorf("[updateRegistry] Failed to get kubecli for namespace: %s", prod.Namespace) return @@ -161,7 +162,7 @@ func UpdateRegistryNamespace(username, id string, args *commonmodels.RegistryNam } for _, env := range envs { go func(prod *commonmodels.Product) { - kubeClient, err := kube.GetKubeClient(prod.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), prod.ClusterID) if err != nil { log.Errorf("[updateRegistry] Failed to get kubecli for namespace: %s", prod.Namespace) return diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_validation.go b/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_validation.go index 580992490..af56f9a50 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_validation.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_validation.go @@ -43,12 +43,12 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/base" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/codehub" git "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/github" - "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/shared/client/systemconfig" "github.com/koderover/zadig/pkg/shared/kube/wrapper" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/kube/getter" + "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/log" "github.com/koderover/zadig/pkg/types" "github.com/koderover/zadig/pkg/util" @@ -688,7 +688,7 @@ func validateServiceContainer(envName, productName, serviceName, container strin return "", err } - kubeClient, err := kube.GetKubeClient(product.ClusterID) + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), product.ClusterID) if err != nil { return "", err } diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go index 368a43529..9872000bc 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go @@ -1212,6 +1212,8 @@ func testArgsToSubtask(args *commonmodels.WorkflowTaskArgs, pt *task.Task, log * testTask.ImageID = testModule.PreTest.ImageID testTask.BuildOS = testModule.PreTest.BuildOS testTask.ImageFrom = testModule.PreTest.ImageFrom + testTask.ClusterID = testModule.PreTest.ClusterID + testTask.Namespace = testModule.PreTest.Namespace // 自定义基础镜像的镜像名称可能会被更新,需要使用ID获取最新的镜像名称 if testModule.PreTest.ImageID != "" { basicImage, err := commonrepo.NewBasicImageColl().Find(testModule.PreTest.ImageID) @@ -1559,6 +1561,8 @@ func BuildModuleToSubTasks(args *commonmodels.BuildModuleArgs, log *zap.SugaredL Timeout: module.Timeout, Registries: registries, ProductName: args.ProductName, + Namespace: module.PreBuild.Namespace, + ClusterID: module.PreBuild.ClusterID, } if args.TaskType != "" { diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/build.go b/pkg/microservice/warpdrive/core/service/taskplugin/build.go index db5c7f078..95e334f3a 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/build.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/build.go @@ -24,6 +24,8 @@ import ( "strings" "time" + "github.com/koderover/zadig/pkg/tool/kube/multicluster" + "go.uber.org/zap" "gopkg.in/yaml.v3" "k8s.io/apimachinery/pkg/util/sets" @@ -106,6 +108,20 @@ func (p *BuildTaskPlugin) SetBuildStatusCompleted(status config.Status) { //TODO: Binded Archive File logic func (p *BuildTaskPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipelineCtx *task.PipelineCtx, serviceName string) { + p.KubeNamespace = pipelineTask.ConfigPayload.Build.KubeNamespace + if p.Task.Namespace != "" { + p.KubeNamespace = p.Task.Namespace + kubeClient, err := multicluster.GetKubeClient(pipelineTask.ConfigPayload.HubServerAddr, p.Task.ClusterID) + if err != nil { + msg := fmt.Sprintf("failed to get kube client: %s", err) + p.Log.Error(msg) + p.Task.TaskStatus = config.StatusFailed + p.Task.Error = msg + p.SetBuildStatusCompleted(config.StatusFailed) + return + } + p.kubeClient = kubeClient + } if pipelineTask.Type == config.WorkflowType { envName := pipelineTask.WorkflowArgs.Namespace envNameVar := &task.KeyVal{Key: "ENV_NAME", Value: envName, IsCredential: false} @@ -143,7 +159,6 @@ func (p *BuildTaskPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipe p.Task.JobCtx.EnvVars = append(p.Task.JobCtx.EnvVars, artifactKeysVar) } - p.KubeNamespace = pipelineTask.ConfigPayload.Build.KubeNamespace for _, repo := range p.Task.JobCtx.Builds { repoName := strings.Replace(repo.RepoName, "-", "_", -1) if len(repo.Branch) > 0 { @@ -313,13 +328,16 @@ func (p *BuildTaskPlugin) Complete(ctx context.Context, pipelineTask *task.Task, // 清理用户取消和超时的任务 defer func() { - if p.Task.TaskStatus == config.StatusCancelled || p.Task.TaskStatus == config.StatusTimeout { - if err := ensureDeleteJob(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { - p.Log.Error(err) - p.Task.Error = err.Error() - } - return + if err := ensureDeleteJob(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + p.Log.Error(err) + p.Task.Error = err.Error() } + + if err := ensureDeleteConfigMap(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + p.Log.Error(err) + p.Task.Error = err.Error() + } + return }() err := saveContainerLog(pipelineTask, p.KubeNamespace, p.FileName, jobLabel, p.kubeClient) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go index d61273c00..44348007e 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go @@ -257,13 +257,15 @@ func (p *TestPlugin) Complete(ctx context.Context, pipelineTask *task.Task, serv // 日志保存失败与否都清理job defer func() { - if p.Task.TaskStatus == config.StatusCancelled || p.Task.TaskStatus == config.StatusTimeout { - if err := ensureDeleteJob(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { - p.Log.Error(err) - p.Task.Error = err.Error() - } - return + if err := ensureDeleteJob(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + p.Log.Error(err) + p.Task.Error = err.Error() } + if err := ensureDeleteConfigMap(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + p.Log.Error(err) + p.Task.Error = err.Error() + } + return }() err := saveContainerLog(pipelineTask, p.KubeNamespace, p.FileName, jobLabel, p.kubeClient) diff --git a/pkg/microservice/warpdrive/core/service/types/task/build.go b/pkg/microservice/warpdrive/core/service/types/task/build.go index 4d6e55c3b..daa76bbc8 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/build.go +++ b/pkg/microservice/warpdrive/core/service/types/task/build.go @@ -57,6 +57,7 @@ type Build struct { // Get the host bound to the environment of the cloud host service configuration EnvHostInfo map[string][]string `bson:"env_host_info,omitempty" json:"env_host_info,omitempty"` ArtifactInfo *ArtifactInfo `bson:"artifact_info,omitempty" json:"artifact_info,omitempty"` + ClusterID string `bson:"cluster_id,omitempty" json:"cluster_id,omitempty"` } type ArtifactInfo struct { diff --git a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go index 3b3e6e0a8..d42d25ea4 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go +++ b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go @@ -18,6 +18,9 @@ package task import ( "fmt" + + "github.com/koderover/zadig/pkg/microservice/aslan/config" + "go.mongodb.org/mongo-driver/bson/primitive" ) type ConfigPayload struct { @@ -49,6 +52,7 @@ type ConfigPayload struct { // ResetCache means ignore workspace cache ResetCache bool `json:"reset_cache"` PrivateKeys []*PrivateKey `json:"private_keys"` + K8SClusters []*K8SCluster `json:"k8s_cluster"` } func (cp *ConfigPayload) GetGitKnownHost() string { @@ -148,3 +152,17 @@ type JenkinsBuildConfig struct { type PrivateKey struct { Name string `json:"name"` } + +type K8SCluster struct { + ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` + Name string `json:"name" bson:"name"` + Status config.K8SClusterStatus `json:"status" bson:"status"` + ClusterConfig *ClusterConfig `json:"config,omitempty" bson:"config,omitempty"` + Production bool `json:"production" bson:"production"` + Disconnected bool `json:"-" bson:"disconnected"` +} + +type ClusterConfig struct { + Strategy string `json:"strategy,omitempty" bson:"strategy,omitempty"` + NodeLabels []string `json:"node_labels,omitempty" bson:"node_labels,omitempty"` +} diff --git a/pkg/microservice/warpdrive/core/service/types/task/testing.go b/pkg/microservice/warpdrive/core/service/types/task/testing.go index fcbb0a0c0..dbef2b7c1 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/testing.go +++ b/pkg/microservice/warpdrive/core/service/types/task/testing.go @@ -45,6 +45,8 @@ type Testing struct { ReportReady bool `bson:"report_ready" json:"report_ready"` IsRestart bool `bson:"is_restart" json:"is_restart"` Registries []*RegistryNamespace `bson:"-" json:"registries"` + ClusterID string `bson:"cluster_id" json:"cluster_id"` + Namespace string `bson:"namespace" json:"namespace"` } func (t *Testing) ToSubTask() (map[string]interface{}, error) { diff --git a/pkg/shared/kube/resource/namespace.go b/pkg/shared/kube/resource/namespace.go index 7fad232c1..50fc6e1be 100644 --- a/pkg/shared/kube/resource/namespace.go +++ b/pkg/shared/kube/resource/namespace.go @@ -21,4 +21,6 @@ type Namespace struct { Status string `json:"status"` Age string `json:"age"` Labels map[string]string `json:"labels"` + // Whether it is the namespace currently installed by zadig + Current bool `json:"current"` } diff --git a/pkg/shared/kube/wrapper/namespace.go b/pkg/shared/kube/wrapper/namespace.go index 4faa5d727..0f7c84023 100644 --- a/pkg/shared/kube/wrapper/namespace.go +++ b/pkg/shared/kube/wrapper/namespace.go @@ -19,6 +19,7 @@ package wrapper import ( corev1 "k8s.io/api/core/v1" + "github.com/koderover/zadig/pkg/microservice/aslan/config" "github.com/koderover/zadig/pkg/shared/kube/resource" "github.com/koderover/zadig/pkg/util" ) @@ -53,9 +54,10 @@ func (w *namespace) Terminating() bool { func (w *namespace) Resource() *resource.Namespace { return &resource.Namespace{ - Name: w.Name, - Status: string(w.Status.Phase), - Age: util.Age(w.CreationTimestamp.Unix()), - Labels: w.Labels, + Name: w.Name, + Status: string(w.Status.Phase), + Age: util.Age(w.CreationTimestamp.Unix()), + Labels: w.Labels, + Current: w.Name == config.Namespace(), } } -- Gitee From c5280e6384faed526cd6fca78131c73aaa64b37a Mon Sep 17 00:00:00 2001 From: liu deyi Date: Mon, 29 Nov 2021 19:54:32 +0800 Subject: [PATCH 011/134] add affinity Signed-off-by: liu deyi --- .../service/taskplugin/artifact_deploy.go | 2 +- .../core/service/taskplugin/build.go | 2 +- .../core/service/taskplugin/docker_build.go | 2 +- .../core/service/taskplugin/jenkins_plugin.go | 2 +- .../warpdrive/core/service/taskplugin/job.go | 61 +++++++++++++++++-- .../core/service/taskplugin/release_image.go | 2 +- .../core/service/taskplugin/testing.go | 2 +- 7 files changed, 63 insertions(+), 10 deletions(-) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/artifact_deploy.go b/pkg/microservice/warpdrive/core/service/taskplugin/artifact_deploy.go index c3a06aafa..875da7a6d 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/artifact_deploy.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/artifact_deploy.go @@ -215,7 +215,7 @@ func (p *ArtifactDeployTaskPlugin) Run(ctx context.Context, pipelineTask *task.T } //Resource request default value is LOW - job, err := buildJob(p.Type(), jobImage, p.JobName, serviceName, p.Task.ResReq, pipelineCtx, pipelineTask, p.Task.Registries) + job, err := buildJob(p.Type(), jobImage, p.JobName, serviceName, "", p.Task.ResReq, pipelineCtx, pipelineTask, p.Task.Registries) if err != nil { msg := fmt.Sprintf("create build job context error: %v", err) p.Log.Error(msg) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/build.go b/pkg/microservice/warpdrive/core/service/taskplugin/build.go index 95e334f3a..75525a356 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/build.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/build.go @@ -245,7 +245,7 @@ func (p *BuildTaskPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipe } //Resource request default value is LOW - job, err := buildJob(p.Type(), jobImage, p.JobName, serviceName, p.Task.ResReq, pipelineCtx, pipelineTask, p.Task.Registries) + job, err := buildJob(p.Type(), jobImage, p.JobName, serviceName, p.Task.ClusterID, p.Task.ResReq, pipelineCtx, pipelineTask, p.Task.Registries) if err != nil { msg := fmt.Sprintf("create build job context error: %v", err) p.Log.Error(msg) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/docker_build.go b/pkg/microservice/warpdrive/core/service/taskplugin/docker_build.go index cc02d9cb8..53cfffa23 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/docker_build.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/docker_build.go @@ -196,7 +196,7 @@ func (p *DockerBuildPlugin) Run(ctx context.Context, pipelineTask *task.Task, pi return } - job, err := buildJob(p.Type(), pipelineTask.ConfigPayload.Release.PredatorImage, p.JobName, serviceName, setting.MinRequest, pipelineCtx, pipelineTask, []*task.RegistryNamespace{}) + job, err := buildJob(p.Type(), pipelineTask.ConfigPayload.Release.PredatorImage, p.JobName, serviceName, "", setting.MinRequest, pipelineCtx, pipelineTask, []*task.RegistryNamespace{}) if err != nil { msg := fmt.Sprintf("create build job context error: %v", err) p.Log.Error(msg) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/jenkins_plugin.go b/pkg/microservice/warpdrive/core/service/taskplugin/jenkins_plugin.go index 5e38031fa..eef51210b 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/jenkins_plugin.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/jenkins_plugin.go @@ -158,7 +158,7 @@ func (j *JenkinsBuildPlugin) Run(ctx context.Context, pipelineTask *task.Task, p j.Log.Infof("succeed to create cm for jenkins build job %s", j.JobName) j.Log.Infof("JenkinsBuildConfig : %+v", pipelineTask.ConfigPayload.JenkinsBuildConfig) - job, err := buildJob(j.Type(), pipelineTask.ConfigPayload.JenkinsBuildConfig.JenkinsBuildImage, j.JobName, serviceName, setting.MinRequest, pipelineCtx, pipelineTask, []*task.RegistryNamespace{}) + job, err := buildJob(j.Type(), pipelineTask.ConfigPayload.JenkinsBuildConfig.JenkinsBuildImage, j.JobName, serviceName, "", setting.MinRequest, pipelineCtx, pipelineTask, []*task.RegistryNamespace{}) if err != nil { msg := fmt.Sprintf("create jenkins build job context error: %v", err) j.Log.Error(msg) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/job.go b/pkg/microservice/warpdrive/core/service/taskplugin/job.go index 1d13553eb..72f5009b7 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/job.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/job.go @@ -57,9 +57,10 @@ const ( defaultSecretEmail = "bot@koderover.com" PredatorPlugin = "predator-plugin" JenkinsPlugin = "jenkins-plugin" -) + NormalSchedule = "normal" + RequiredSchedule = "required" + PreferredSchedule = "preferred" -const ( registrySecretSuffix = "-registry-secret" ) @@ -381,12 +382,13 @@ func createJobConfigMap(namespace, jobName string, jobLabel *JobLabel, jobCtx st //"s-job": pipelinename-taskid-tasktype-servicename, //"s-task": pipelinename-taskid, //"s-type": tasktype, -func buildJob(taskType config.TaskType, jobImage, jobName, serviceName string, resReq setting.Request, ctx *task.PipelineCtx, pipelineTask *task.Task, registries []*task.RegistryNamespace) (*batchv1.Job, error) { +func buildJob(taskType config.TaskType, jobImage, jobName, serviceName, clusterID string, resReq setting.Request, ctx *task.PipelineCtx, pipelineTask *task.Task, registries []*task.RegistryNamespace) (*batchv1.Job, error) { return buildJobWithLinkedNs( taskType, jobImage, jobName, serviceName, + clusterID, resReq, ctx, pipelineTask, @@ -396,7 +398,7 @@ func buildJob(taskType config.TaskType, jobImage, jobName, serviceName string, r ) } -func buildJobWithLinkedNs(taskType config.TaskType, jobImage, jobName, serviceName string, resReq setting.Request, ctx *task.PipelineCtx, pipelineTask *task.Task, registries []*task.RegistryNamespace, execNs, linkedNs string) (*batchv1.Job, error) { +func buildJobWithLinkedNs(taskType config.TaskType, jobImage, jobName, serviceName, clusterID string, resReq setting.Request, ctx *task.PipelineCtx, pipelineTask *task.Task, registries []*task.RegistryNamespace, execNs, linkedNs string) (*batchv1.Job, error) { var reaperBootingScript string if !strings.Contains(jobImage, PredatorPlugin) && !strings.Contains(jobImage, JenkinsPlugin) { @@ -805,3 +807,54 @@ func checkDogFoodExistsInContainer(namespace string, pod string, container strin return success, err } + +func addNodeAffinity(clusterID string, K8SClusters []*task.K8SCluster) *corev1.Affinity { + clusterConfig := findClusterConfig(clusterID, K8SClusters) + if clusterConfig == nil { + return nil + } + + switch clusterConfig.Strategy { + case NormalSchedule: + return nil + case RequiredSchedule: + if len(clusterConfig.NodeLabels) == 0 { + return nil + } + nodeSelectorTerms := make([]corev1.NodeSelectorTerm, 0) + for _, nodeLabel := range clusterConfig.NodeLabels { + if !strings.Contains(nodeLabel, ":") || len(strings.Split(nodeLabel, ":")) != 2 { + continue + } + matchExpressions := make([]corev1.NodeSelectorRequirement, 0) + matchExpressions = append(matchExpressions, corev1.NodeSelectorRequirement{ + Key: strings.Split(nodeLabel, ":")[0], + Operator: "in", + Values: []string{strings.Split(nodeLabel, ":")[1]}, + }) + nodeSelectorTerms = append(nodeSelectorTerms, corev1.NodeSelectorTerm{ + MatchExpressions: matchExpressions, + }) + } + affinity := &corev1.Affinity{ + NodeAffinity: &corev1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ + NodeSelectorTerms: nodeSelectorTerms, + }, + }, + } + return affinity + case PreferredSchedule: + + } + return nil +} + +func findClusterConfig(clusterID string, K8SClusters []*task.K8SCluster) *task.ClusterConfig { + for _, K8SCluster := range K8SClusters { + if K8SCluster.ID.Hex() == clusterID { + return K8SCluster.ClusterConfig + } + } + return nil +} diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/release_image.go b/pkg/microservice/warpdrive/core/service/taskplugin/release_image.go index 08495bea1..27dc3393f 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/release_image.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/release_image.go @@ -176,7 +176,7 @@ func (p *ReleaseImagePlugin) Run(ctx context.Context, pipelineTask *task.Task, p } p.Log.Infof("succeed to create cm for image job %s", p.JobName) - job, err := buildJob(p.Type(), pipelineTask.ConfigPayload.Release.PredatorImage, p.JobName, serviceName, setting.MinRequest, pipelineCtx, pipelineTask, []*task.RegistryNamespace{}) + job, err := buildJob(p.Type(), pipelineTask.ConfigPayload.Release.PredatorImage, p.JobName, serviceName, "", setting.MinRequest, pipelineCtx, pipelineTask, []*task.RegistryNamespace{}) if err != nil { msg := fmt.Sprintf("create release image job context error: %v", err) p.Log.Error(msg) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go index 44348007e..4107b6461 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go @@ -200,7 +200,7 @@ func (p *TestPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipelineC // search namespace should also include desired namespace job, err := buildJobWithLinkedNs( - p.Type(), jobImage, p.JobName, serviceName, p.Task.ResReq, pipelineCtx, pipelineTask, p.Task.Registries, + p.Type(), jobImage, p.JobName, serviceName, p.Task.ClusterID, p.Task.ResReq, pipelineCtx, pipelineTask, p.Task.Registries, p.KubeNamespace, linkedNamespace, ) -- Gitee From d9c3ae9605ea90d82cc36a71af3dd8a44c2665ad Mon Sep 17 00:00:00 2001 From: liu deyi Date: Wed, 1 Dec 2021 10:56:37 +0800 Subject: [PATCH 012/134] handler conflict Signed-off-by: liu deyi --- .../common/repository/mongodb/k8s_cluster.go | 17 ----------------- .../aslan/core/common/service/config_payload.go | 2 +- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/k8s_cluster.go b/pkg/microservice/aslan/core/common/repository/mongodb/k8s_cluster.go index 2139cab5a..80e349478 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/k8s_cluster.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/k8s_cluster.go @@ -238,20 +238,3 @@ func (c *K8SClusterColl) GetByToken(token string) (*models.K8SCluster, error) { return c.Get(id) } - -func (c *K8SClusterColl) List() ([]*models.K8SCluster, error) { - resp := make([]*models.K8SCluster, 0) - ctx := context.Background() - - cursor, err := c.Collection.Find(ctx, bson.M{}) - if err != nil { - return nil, err - } - - err = cursor.All(ctx, &resp) - if err != nil { - return nil, err - } - - return resp, err -} diff --git a/pkg/microservice/aslan/core/common/service/config_payload.go b/pkg/microservice/aslan/core/common/service/config_payload.go index b3c2808f3..1f3ed4259 100644 --- a/pkg/microservice/aslan/core/common/service/config_payload.go +++ b/pkg/microservice/aslan/core/common/service/config_payload.go @@ -89,7 +89,7 @@ func GetConfigPayload(codeHostID int) *models.ConfigPayload { payload.PrivateKeys = privateKeys } - k8sClusters, _ := mongodb.NewK8SClusterColl().List() + k8sClusters, _ := mongodb.NewK8SClusterColl().List(nil) if len(k8sClusters) != 0 { payload.K8SClusters = k8sClusters } -- Gitee From 35e3fa845d71934205f17b5ff3e84943425ae634 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Wed, 1 Dec 2021 11:25:10 +0800 Subject: [PATCH 013/134] modify node interface Signed-off-by: liu deyi --- .../aslan/core/environment/service/kube.go | 14 ++++++++++---- pkg/shared/kube/resource/node.go | 6 ++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/pkg/microservice/aslan/core/environment/service/kube.go b/pkg/microservice/aslan/core/environment/service/kube.go index c4ba3ff67..c64c4feac 100644 --- a/pkg/microservice/aslan/core/environment/service/kube.go +++ b/pkg/microservice/aslan/core/environment/service/kube.go @@ -26,6 +26,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/util/sets" "github.com/koderover/zadig/pkg/microservice/aslan/config" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" @@ -227,8 +228,8 @@ func getModifiedServiceFromObjectMeta(om metav1.Object) *serviceInfo { } } -func ListAvailableNodes(clusterID string, log *zap.SugaredLogger) ([]*resource.Node, error) { - resp := make([]*resource.Node, 0) +func ListAvailableNodes(clusterID string, log *zap.SugaredLogger) (*resource.NodeResp, error) { + resp := new(resource.NodeResp) kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), clusterID) if err != nil { log.Errorf("ListAvailableNodes clusterID:%s err:%s", clusterID, err) @@ -244,14 +245,19 @@ func ListAvailableNodes(clusterID string, log *zap.SugaredLogger) ([]*resource.N return resp, err } + nodeInfos := make([]*resource.Node, 0) + labels := sets.NewString() for _, node := range nodes { nodeResource := &resource.Node{ Status: nodeReady(node), Labels: nodeLabel(node), + IP: node.Name, } - resp = append(resp, nodeResource) + nodeInfos = append(nodeInfos, nodeResource) + labels.Insert(nodeResource.Labels...) } - + resp.Nodes = nodeInfos + resp.Labels = labels.List() return resp, nil } diff --git a/pkg/shared/kube/resource/node.go b/pkg/shared/kube/resource/node.go index c54f3d362..c76b5eb62 100644 --- a/pkg/shared/kube/resource/node.go +++ b/pkg/shared/kube/resource/node.go @@ -3,4 +3,10 @@ package resource type Node struct { Labels []string `json:"node_labels"` Status string `json:"node_status"` + IP string `json:"node_ip"` +} + +type NodeResp struct { + Nodes []*Node `json:"data"` + Labels []string `json:"labels"` } -- Gitee From 8c7903fee082d285cdbf11244c8efc93290920e1 Mon Sep 17 00:00:00 2001 From: allenshen Date: Wed, 1 Dec 2021 14:51:36 +0800 Subject: [PATCH 014/134] add basic logic to push images by running jobs Signed-off-by: allenshen --- Makefile | 2 +- cmd/packager/main.go | 29 ++ docker/service/packager-plugin.Dockerfile | 17 + pkg/microservice/aslan/config/config.go | 4 + pkg/microservice/aslan/config/consts.go | 31 +- .../core/common/repository/models/queue.go | 39 +- .../models/task/artifact_package.go | 50 +++ .../common/repository/models/task/model.go | 12 +- .../aslan/core/common/service/base/convert.go | 8 + .../core/common/service/config_payload.go | 1 + .../aslan/core/workflow/handler/router.go | 4 + .../aslan/core/workflow/handler/workflow.go | 22 + .../service/workflow/artifact_task.go | 140 ++++++ .../core/workflow/service/workflow/convert.go | 162 +++---- .../service/workflow/workflow_task.go | 2 + pkg/microservice/packager/config/config.go | 33 ++ .../packager/core/service/docker.go | 72 +++ .../packager/core/service/packager.go | 46 ++ .../packager/core/service/service.go | 215 +++++++++ .../packager/executor/executor.go | 51 +++ pkg/microservice/warpdrive/config/const.go | 31 +- .../service/taskcontroller/task_handler.go | 3 + .../service/taskcontroller/task_helper.go | 26 +- .../service/taskplugin/artifact_package.go | 421 ++++++++++++++++++ .../warpdrive/core/service/taskplugin/job.go | 15 +- .../core/service/taskplugin/utils.go | 38 +- .../warpdrive/core/service/types/packager.go | 27 ++ .../service/types/task/artifact_package.go | 50 +++ .../core/service/types/task/config_payload.go | 3 + .../core/service/types/task/model.go | 20 + pkg/setting/consts.go | 7 + 31 files changed, 1430 insertions(+), 151 deletions(-) create mode 100644 cmd/packager/main.go create mode 100644 docker/service/packager-plugin.Dockerfile create mode 100644 pkg/microservice/aslan/core/common/repository/models/task/artifact_package.go create mode 100644 pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go create mode 100644 pkg/microservice/packager/config/config.go create mode 100644 pkg/microservice/packager/core/service/docker.go create mode 100644 pkg/microservice/packager/core/service/packager.go create mode 100644 pkg/microservice/packager/core/service/service.go create mode 100644 pkg/microservice/packager/executor/executor.go create mode 100644 pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go create mode 100644 pkg/microservice/warpdrive/core/service/types/packager.go create mode 100644 pkg/microservice/warpdrive/core/service/types/task/artifact_package.go diff --git a/Makefile b/Makefile index 08428072a..224828be5 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ IMAGE_REPOSITORY = ccr.ccs.tencentyun.com/koderover-rc VERSION ?= $(shell date +'%Y%m%d%H%M%S') -TARGETS = aslan cron hub-agent hub-server jenkins-plugin podexec predator-plugin resource-server ua warpdrive policy user picket config init +TARGETS = aslan cron hub-agent hub-server jenkins-plugin podexec predator-plugin packager-plugin resource-server ua warpdrive policy user picket config init REAPER_OS= focal xenial bionic ALL_IMAGES=$(TARGETS:=.image) diff --git a/cmd/packager/main.go b/cmd/packager/main.go new file mode 100644 index 000000000..ba2938d98 --- /dev/null +++ b/cmd/packager/main.go @@ -0,0 +1,29 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "log" + + "github.com/koderover/zadig/pkg/microservice/packager/executor" +) + +func main() { + if err := executor.Execute(); err != nil { + log.Fatalf("Failed to run predator, the error is: %+v", err) + } +} diff --git a/docker/service/packager-plugin.Dockerfile b/docker/service/packager-plugin.Dockerfile new file mode 100644 index 000000000..d7074f6aa --- /dev/null +++ b/docker/service/packager-plugin.Dockerfile @@ -0,0 +1,17 @@ +#golang.Dockerfile + +RUN go build -v -o /packager-plugin ./cmd/packager/main.go + +#ubuntu-xenial.Dockerfile + +# 安装 docker client +RUN curl -fsSL "http://resources.koderover.com/docker-cli-v19.03.2.tar.gz" -o docker.tgz &&\ + tar -xvzf docker.tgz &&\ + mv docker/* /usr/local/bin &&\ + rm -rf docke* + +WORKDIR /app + +COPY --from=build /packager-plugin . + +ENTRYPOINT ["/app/packager-plugin"] diff --git a/pkg/microservice/aslan/config/config.go b/pkg/microservice/aslan/config/config.go index 818381138..7b1c3e4b5 100644 --- a/pkg/microservice/aslan/config/config.go +++ b/pkg/microservice/aslan/config/config.go @@ -190,6 +190,10 @@ func PredatorImage() string { return viper.GetString(setting.ENVPredatorImage) } +func PackagerImage() string { + return viper.GetString(setting.EnvPackagerImage) +} + func DockerHosts() []string { return strings.Split(viper.GetString(setting.ENVDockerHosts), ",") } diff --git a/pkg/microservice/aslan/config/consts.go b/pkg/microservice/aslan/config/consts.go index 363760937..b810ddd3a 100644 --- a/pkg/microservice/aslan/config/consts.go +++ b/pkg/microservice/aslan/config/consts.go @@ -81,6 +81,8 @@ const ( TestType PipelineType = "test" // ServiceType 服务 ServiceType PipelineType = "service" + // ArtifactPackageType package artifact + ArtifactType PipelineType = "artifact" ) type Status string @@ -115,20 +117,21 @@ const ( type TaskType string const ( - TaskPipeline TaskType = "pipeline" - TaskBuild TaskType = "buildv2" - TaskJenkinsBuild TaskType = "jenkins_build" - TaskArtifact TaskType = "artifact" - TaskArtifactDeploy TaskType = "artifact_deploy" - TaskDeploy TaskType = "deploy" - TaskTestingV2 TaskType = "testingv2" - TaskDistributeToS3 TaskType = "distribute2kodo" - TaskReleaseImage TaskType = "release_image" - TaskJira TaskType = "jira" - TaskDockerBuild TaskType = "docker_build" - TaskSecurity TaskType = "security" - TaskResetImage TaskType = "reset_image" - TaskDistribute TaskType = "distribute" + TaskPipeline TaskType = "pipeline" + TaskBuild TaskType = "buildv2" + TaskJenkinsBuild TaskType = "jenkins_build" + TaskArtifact TaskType = "artifact" + TaskArtifactDeploy TaskType = "artifact_deploy" + TaskDeploy TaskType = "deploy" + TaskTestingV2 TaskType = "testingv2" + TaskDistributeToS3 TaskType = "distribute2kodo" + TaskReleaseImage TaskType = "release_image" + TaskJira TaskType = "jira" + TaskDockerBuild TaskType = "docker_build" + TaskSecurity TaskType = "security" + TaskResetImage TaskType = "reset_image" + TaskDistribute TaskType = "distribute" + TaskArtifactPackage TaskType = "artifact_package" ) type DistributeType string diff --git a/pkg/microservice/aslan/core/common/repository/models/queue.go b/pkg/microservice/aslan/core/common/repository/models/queue.go index 7801b2c46..9d81c752c 100644 --- a/pkg/microservice/aslan/core/common/repository/models/queue.go +++ b/pkg/microservice/aslan/core/common/repository/models/queue.go @@ -19,9 +19,8 @@ package models import ( "sync" - "go.mongodb.org/mongo-driver/bson/primitive" - "github.com/koderover/zadig/pkg/microservice/aslan/config" + "go.mongodb.org/mongo-driver/bson/primitive" ) type Queue struct { @@ -64,12 +63,14 @@ type Queue struct { // TestArgs 测试任务参数 TestArgs *TestTaskArgs `bson:"test_args,omitempty" json:"test_args,omitempty"` // ServiceTaskArgs 脚本部署工作流任务参数 - ServiceTaskArgs *ServiceTaskArgs `bson:"service_args,omitempty" json:"service_args,omitempty"` - ConfigPayload *ConfigPayload `json:"config_payload,omitempty"` - Error string `bson:"error,omitempty" json:"error,omitempty"` - Services [][]*ProductService `bson:"services" json:"services"` - Render *RenderInfo `bson:"render" json:"render"` - StorageURI string `bson:"storage_uri,omitempty" json:"storage_uri,omitempty"` + ServiceTaskArgs *ServiceTaskArgs `bson:"service_args,omitempty" json:"service_args,omitempty"` + // ArtifactPackageTaskArgs arguments for artifact-package type tasks + ArtifactPackageTaskArgs *ArtifactPackageTaskArgs `bson:"artifact_package_args,omitempty" json:"artifact_package_args,omitempty"` + ConfigPayload *ConfigPayload `json:"config_payload,omitempty"` + Error string `bson:"error,omitempty" json:"error,omitempty"` + Services [][]*ProductService `bson:"services" json:"services"` + Render *RenderInfo `bson:"render" json:"render"` + StorageURI string `bson:"storage_uri,omitempty" json:"storage_uri,omitempty"` // interface{} 为types.TestReport TestReports map[string]interface{} `bson:"test_reports,omitempty" json:"test_reports,omitempty"` @@ -108,6 +109,25 @@ type ServiceTaskArgs struct { Updatable bool `bson:"updatable" json:"updatable"` } +type ImageData struct { + ImageUrl string `bson:"image_url" json:"image_url"` + ImageName string `bson:"image_name" json:"image_name"` + ImageTag string `bson:"image_tag" json:"image_tag"` +} + +type ImagesByService struct { + ServiceName string `bson:"service_name" json:"service_name"` + Images []*ImageData `bson:"images" json:"images"` +} + +type ArtifactPackageTaskArgs struct { + ProjectName string `bson:"project_name" json:"project_name"` + EnvName string `bson:"env_name" json:"env_name"` + Images []*ImagesByService `bson:"images" json:"images"` + SourceRegistries []string `json:"source_registries" json:"source_registries"` + TargetRegistries []string `json:"target_registries" json:"target_registries"` +} + type ConfigPayload struct { Proxy Proxy `json:"proxy"` S3Storage S3Config `json:"s3_storage"` @@ -208,6 +228,9 @@ type ReleaseConfig struct { // PredatorImage sets docker build image // e.g. xxx.com/resources/predator-plugin:v0.1.0 PredatorImage string + // PackagerImage sets docker build image + // e.g. xxx.com/resources/predator-plugin:v0.1.0 + PackagerImage string } type ImageReleaseConfig struct { diff --git a/pkg/microservice/aslan/core/common/repository/models/task/artifact_package.go b/pkg/microservice/aslan/core/common/repository/models/task/artifact_package.go new file mode 100644 index 000000000..8f578b62c --- /dev/null +++ b/pkg/microservice/aslan/core/common/repository/models/task/artifact_package.go @@ -0,0 +1,50 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package task + +import ( + "fmt" + + "github.com/koderover/zadig/pkg/microservice/aslan/config" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" +) + +type ArtifactPackage struct { + TaskType config.TaskType `bson:"type" json:"type"` + TaskStatus config.Status `bson:"status" json:"status"` + Enabled bool `bson:"enabled" json:"enabled"` + Timeout int `bson:"timeout,omitempty" json:"timeout,omitempty"` + Error string `bson:"error,omitempty" json:"error,omitempty"` + StartTime int64 `bson:"start_time,omitempty" json:"start_time,omitempty"` + EndTime int64 `bson:"end_time,omitempty" json:"end_time,omitempty"` + LogFile string `bson:"log_file" json:"log_file"` + + // source images + Images []*models.ImagesByService `bson:"images" json:"images"` + // source registries need auth to pull images + SourceRegistries []string `bson:"source_registries" json:"source_registries"` + // target registries to push images + TargetRegistries []string `bson:"target_registries" json:"target_registries"` +} + +func (ri *ArtifactPackage) ToSubTask() (map[string]interface{}, error) { + var task map[string]interface{} + if err := IToi(ri, &task); err != nil { + return nil, fmt.Errorf("convert ReleaseImageTask to interface error: %v", err) + } + return task, nil +} diff --git a/pkg/microservice/aslan/core/common/repository/models/task/model.go b/pkg/microservice/aslan/core/common/repository/models/task/model.go index c503d9c6f..746534f3e 100644 --- a/pkg/microservice/aslan/core/common/repository/models/task/model.go +++ b/pkg/microservice/aslan/core/common/repository/models/task/model.go @@ -67,12 +67,14 @@ type Task struct { TestArgs *models.TestTaskArgs `bson:"test_args,omitempty" json:"test_args,omitempty"` // ServiceTaskArgs 脚本部署工作流任务参数 ServiceTaskArgs *models.ServiceTaskArgs `bson:"service_args,omitempty" json:"service_args,omitempty"` + // ArtifactPackageTaskArgs arguments for artifact-package type tasks + ArtifactPackageTaskArgs *models.ArtifactPackageTaskArgs `bson:"artifact_package_args,omitempty" json:"artifact_package_args,omitempty"` // ConfigPayload 系统配置信息 - ConfigPayload *models.ConfigPayload `json:"config_payload,omitempty"` - Error string `bson:"error,omitempty" json:"error,omitempty"` - Services [][]*models.ProductService `bson:"services" json:"services"` - Render *models.RenderInfo `bson:"render" json:"render"` - StorageURI string `bson:"storage_uri,omitempty" json:"storage_uri,omitempty"` + ConfigPayload *models.ConfigPayload `json:"config_payload,omitempty"` + Error string `bson:"error,omitempty" json:"error,omitempty"` + Services [][]*models.ProductService `bson:"services" json:"services"` + Render *models.RenderInfo `bson:"render" json:"render"` + StorageURI string `bson:"storage_uri,omitempty" json:"storage_uri,omitempty"` // interface{} 为types.TestReport TestReports map[string]interface{} `bson:"test_reports,omitempty" json:"test_reports,omitempty"` diff --git a/pkg/microservice/aslan/core/common/service/base/convert.go b/pkg/microservice/aslan/core/common/service/base/convert.go index b69135480..95ae17408 100644 --- a/pkg/microservice/aslan/core/common/service/base/convert.go +++ b/pkg/microservice/aslan/core/common/service/base/convert.go @@ -92,6 +92,14 @@ func ToReleaseImageTask(sb map[string]interface{}) (*task.ReleaseImage, error) { return t, nil } +func ToArtifactPackageImageTask(sb map[string]interface{}) (*task.ArtifactPackage, error) { + var t *task.ArtifactPackage + if err := task.IToi(sb, &t); err != nil { + return nil, fmt.Errorf("convert interface to ReleaseImageTask error: %v", err) + } + return t, nil +} + func ToJiraTask(sb map[string]interface{}) (*task.Jira, error) { var t *task.Jira if err := task.IToi(sb, &t); err != nil { diff --git a/pkg/microservice/aslan/core/common/service/config_payload.go b/pkg/microservice/aslan/core/common/service/config_payload.go index ac244fe38..dcbb24ae6 100644 --- a/pkg/microservice/aslan/core/common/service/config_payload.go +++ b/pkg/microservice/aslan/core/common/service/config_payload.go @@ -54,6 +54,7 @@ func GetConfigPayload(codeHostID int) *models.ConfigPayload { ReaperImage: config.ReaperImage(), ReaperBinaryFile: config.ReaperBinaryFile(), PredatorImage: config.PredatorImage(), + PackagerImage: config.PackagerImage(), }, Docker: models.DockerConfig{ HostList: config.DockerHosts(), diff --git a/pkg/microservice/aslan/core/workflow/handler/router.go b/pkg/microservice/aslan/core/workflow/handler/router.go index 091767d45..b8fde441d 100644 --- a/pkg/microservice/aslan/core/workflow/handler/router.go +++ b/pkg/microservice/aslan/core/workflow/handler/router.go @@ -103,6 +103,10 @@ func (*Router) Inject(router *gin.RouterGroup) { { workflow.POST("/:productName/auto", AutoCreateWorkflow) workflow.POST("", GetWorkflowProductName, gin2.UpdateOperationLogStatus, CreateWorkflow) + + // test api need to delete + workflow.POST("airifactTask", GetWorkflowProductName, gin2.UpdateOperationLogStatus, CreateArtifactTask) + workflow.PUT("", GetWorkflowProductName, gin2.UpdateOperationLogStatus, UpdateWorkflow) workflow.GET("", ListWorkflows) workflow.GET("/testName/:testName", ListTestWorkflows) diff --git a/pkg/microservice/aslan/core/workflow/handler/workflow.go b/pkg/microservice/aslan/core/workflow/handler/workflow.go index c73934a41..d33f1a589 100644 --- a/pkg/microservice/aslan/core/workflow/handler/workflow.go +++ b/pkg/microservice/aslan/core/workflow/handler/workflow.go @@ -90,6 +90,28 @@ func CreateWorkflow(c *gin.Context) { ctx.Err = workflow.CreateWorkflow(args, ctx.Logger) } +// TODO test code need to delete +func CreateArtifactTask(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + args := new(commonmodels.ArtifactPackageTaskArgs) + data, err := c.GetRawData() + if err != nil { + log.Errorf("CreateWorkflow c.GetRawData() err : %v", err) + } + if err = json.Unmarshal(data, args); err != nil { + log.Errorf("CreateWorkflow json.Unmarshal err : %v", err) + } + c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) + if err := c.ShouldBindWith(&args, binding.JSON); err != nil { + ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) + return + } + + ctx.Err = workflow.CreateArtifactPackageTask(args, ctx.Logger) +} + // UpdateWorkflow update a workflow func UpdateWorkflow(c *gin.Context) { ctx := internalhandler.NewContext(c) diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go new file mode 100644 index 000000000..15c7b59fa --- /dev/null +++ b/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go @@ -0,0 +1,140 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package workflow + +import ( + "fmt" + "sort" + + "k8s.io/apimachinery/pkg/util/sets" + + "github.com/koderover/zadig/pkg/microservice/aslan/config" + commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/task" + taskmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/task" + commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" + commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/s3" + "github.com/koderover/zadig/pkg/setting" + e "github.com/koderover/zadig/pkg/tool/errors" + "github.com/koderover/zadig/pkg/util" + "go.uber.org/zap" +) + +func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, log *zap.SugaredLogger) error { + + // 获取全局configpayload + configPayload := commonservice.GetConfigPayload(0) + repos, err := commonrepo.NewRegistryNamespaceColl().FindAll(&commonrepo.FindRegOps{}) + + if err != nil { + log.Errorf("CreateArtifactPackageTask query registries failed, err: %s", err) + return fmt.Errorf("failed to query registries") + } + + registriesInvolved := sets.NewString() + registriesInvolved.Insert(args.SourceRegistries...) + registriesInvolved.Insert(args.TargetRegistries...) + + configPayload.RepoConfigs = make(map[string]*commonmodels.RegistryNamespace) + for _, repo := range repos { + if !registriesInvolved.Has(repo.ID.Hex()) { + continue + } + // if the registry is SWR, we need to modify ak/sk according to the rule + if repo.RegProvider == config.SWRProvider { + ak := fmt.Sprintf("%s@%s", repo.Region, repo.AccessKey) + sk := util.ComputeHmacSha256(repo.AccessKey, repo.SecretKey) + repo.AccessKey = ak + repo.SecretKey = sk + } + configPayload.RepoConfigs[repo.ID.Hex()] = repo + } + + defaultS3, err := s3.FindDefaultS3() + if err != nil { + err = e.ErrFindDefaultS3Storage.AddDesc("default storage is required by distribute task") + return err + } + + defaultURL, err := defaultS3.GetEncryptedURL() + if err != nil { + err = e.ErrS3Storage.AddErr(err) + return err + } + + task := &task.Task{ + Type: config.ArtifactType, + ProductName: args.ProjectName, + Status: config.StatusCreated, + ArtifactPackageTaskArgs: args, + ConfigPayload: configPayload, + StorageURI: defaultURL, + } + + subTask, err := (&taskmodels.ArtifactPackage{ + TaskType: config.TaskArtifactPackage, + Enabled: true, + TaskStatus: "", + Timeout: 0, + StartTime: 0, + EndTime: 0, + LogFile: "", + Images: args.Images, + SourceRegistries: args.SourceRegistries, + TargetRegistries: args.TargetRegistries, + }).ToSubTask() + + if err != nil { + return err + } + + task.SubTasks = []map[string]interface{}{subTask} + + if err := ensurePipelineTask(task, "", log); err != nil { + log.Errorf("CreateServiceTask ensurePipelineTask err : %v", err) + return err + } + + stages := make([]*commonmodels.Stage, 0) + for _, subTask := range task.SubTasks { + AddSubtaskToStage(&stages, subTask, args.EnvName) + } + sort.Sort(ByStageKind(stages)) + task.Stages = stages + if len(task.Stages) == 0 { + return e.ErrCreateTask.AddDesc(e.PipelineSubTaskNotFoundErrMsg) + } + + pipelineName := fmt.Sprintf("%s-%s-%s", args.ProjectName, args.EnvName, "artifact") + nextTaskID, err := commonrepo.NewCounterColl().GetNextSeq(fmt.Sprintf(setting.ServiceTaskFmt, pipelineName)) + if err != nil { + log.Errorf("CreateServiceTask Counter.GetNextSeq error: %v", err) + return e.ErrGetCounter.AddDesc(err.Error()) + } + + task.SubTasks = []map[string]interface{}{} + task.TaskID = nextTaskID + task.PipelineName = pipelineName + + if err := CreateTask(task); err != nil { + log.Error(err) + return e.ErrCreateTask + } + + return nil +} diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/convert.go b/pkg/microservice/aslan/core/workflow/service/workflow/convert.go index 7d98f8c95..1bd2649db 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/convert.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/convert.go @@ -31,91 +31,93 @@ import ( func ConvertQueueToTask(queueTask *commonmodels.Queue) *task.Task { return &task.Task{ - TaskID: queueTask.TaskID, - ProductName: queueTask.ProductName, - PipelineName: queueTask.PipelineName, - Type: queueTask.Type, - Status: queueTask.Status, - Description: queueTask.Description, - TaskCreator: queueTask.TaskCreator, - TaskRevoker: queueTask.TaskRevoker, - CreateTime: queueTask.CreateTime, - StartTime: queueTask.StartTime, - EndTime: queueTask.EndTime, - SubTasks: queueTask.SubTasks, - Stages: queueTask.Stages, - ReqID: queueTask.ReqID, - AgentHost: queueTask.AgentHost, - DockerHost: queueTask.DockerHost, - TeamName: queueTask.TeamName, - IsDeleted: queueTask.IsDeleted, - IsArchived: queueTask.IsArchived, - AgentID: queueTask.AgentID, - MultiRun: queueTask.MultiRun, - Target: queueTask.Target, - BuildModuleVer: queueTask.BuildModuleVer, - ServiceName: queueTask.ServiceName, - TaskArgs: queueTask.TaskArgs, - WorkflowArgs: queueTask.WorkflowArgs, - TestArgs: queueTask.TestArgs, - ServiceTaskArgs: queueTask.ServiceTaskArgs, - ConfigPayload: queueTask.ConfigPayload, - Error: queueTask.Error, - Services: queueTask.Services, - Render: queueTask.Render, - StorageURI: queueTask.StorageURI, - TestReports: queueTask.TestReports, - RwLock: queueTask.RwLock, - ResetImage: queueTask.ResetImage, - TriggerBy: queueTask.TriggerBy, - Features: queueTask.Features, - IsRestart: queueTask.IsRestart, - StorageEndpoint: queueTask.StorageEndpoint, + TaskID: queueTask.TaskID, + ProductName: queueTask.ProductName, + PipelineName: queueTask.PipelineName, + Type: queueTask.Type, + Status: queueTask.Status, + Description: queueTask.Description, + TaskCreator: queueTask.TaskCreator, + TaskRevoker: queueTask.TaskRevoker, + CreateTime: queueTask.CreateTime, + StartTime: queueTask.StartTime, + EndTime: queueTask.EndTime, + SubTasks: queueTask.SubTasks, + Stages: queueTask.Stages, + ReqID: queueTask.ReqID, + AgentHost: queueTask.AgentHost, + DockerHost: queueTask.DockerHost, + TeamName: queueTask.TeamName, + IsDeleted: queueTask.IsDeleted, + IsArchived: queueTask.IsArchived, + AgentID: queueTask.AgentID, + MultiRun: queueTask.MultiRun, + Target: queueTask.Target, + BuildModuleVer: queueTask.BuildModuleVer, + ServiceName: queueTask.ServiceName, + TaskArgs: queueTask.TaskArgs, + WorkflowArgs: queueTask.WorkflowArgs, + TestArgs: queueTask.TestArgs, + ServiceTaskArgs: queueTask.ServiceTaskArgs, + ArtifactPackageTaskArgs: queueTask.ArtifactPackageTaskArgs, + ConfigPayload: queueTask.ConfigPayload, + Error: queueTask.Error, + Services: queueTask.Services, + Render: queueTask.Render, + StorageURI: queueTask.StorageURI, + TestReports: queueTask.TestReports, + RwLock: queueTask.RwLock, + ResetImage: queueTask.ResetImage, + TriggerBy: queueTask.TriggerBy, + Features: queueTask.Features, + IsRestart: queueTask.IsRestart, + StorageEndpoint: queueTask.StorageEndpoint, } } func ConvertTaskToQueue(task *task.Task) *commonmodels.Queue { return &commonmodels.Queue{ - TaskID: task.TaskID, - ProductName: task.ProductName, - PipelineName: task.PipelineName, - Type: task.Type, - Status: task.Status, - Description: task.Description, - TaskCreator: task.TaskCreator, - TaskRevoker: task.TaskRevoker, - CreateTime: task.CreateTime, - StartTime: task.StartTime, - EndTime: task.EndTime, - SubTasks: task.SubTasks, - Stages: task.Stages, - ReqID: task.ReqID, - AgentHost: task.AgentHost, - DockerHost: task.DockerHost, - TeamName: task.TeamName, - IsDeleted: task.IsDeleted, - IsArchived: task.IsArchived, - AgentID: task.AgentID, - MultiRun: task.MultiRun, - Target: task.Target, - BuildModuleVer: task.BuildModuleVer, - ServiceName: task.ServiceName, - TaskArgs: task.TaskArgs, - WorkflowArgs: task.WorkflowArgs, - TestArgs: task.TestArgs, - ServiceTaskArgs: task.ServiceTaskArgs, - ConfigPayload: task.ConfigPayload, - Error: task.Error, - Services: task.Services, - Render: task.Render, - StorageURI: task.StorageURI, - TestReports: task.TestReports, - RwLock: task.RwLock, - ResetImage: task.ResetImage, - TriggerBy: task.TriggerBy, - Features: task.Features, - IsRestart: task.IsRestart, - StorageEndpoint: task.StorageEndpoint, + TaskID: task.TaskID, + ProductName: task.ProductName, + PipelineName: task.PipelineName, + Type: task.Type, + Status: task.Status, + Description: task.Description, + TaskCreator: task.TaskCreator, + TaskRevoker: task.TaskRevoker, + CreateTime: task.CreateTime, + StartTime: task.StartTime, + EndTime: task.EndTime, + SubTasks: task.SubTasks, + Stages: task.Stages, + ReqID: task.ReqID, + AgentHost: task.AgentHost, + DockerHost: task.DockerHost, + TeamName: task.TeamName, + IsDeleted: task.IsDeleted, + IsArchived: task.IsArchived, + AgentID: task.AgentID, + MultiRun: task.MultiRun, + Target: task.Target, + BuildModuleVer: task.BuildModuleVer, + ServiceName: task.ServiceName, + TaskArgs: task.TaskArgs, + WorkflowArgs: task.WorkflowArgs, + TestArgs: task.TestArgs, + ServiceTaskArgs: task.ServiceTaskArgs, + ArtifactPackageTaskArgs: task.ArtifactPackageTaskArgs, + ConfigPayload: task.ConfigPayload, + Error: task.Error, + Services: task.Services, + Render: task.Render, + StorageURI: task.StorageURI, + TestReports: task.TestReports, + RwLock: task.RwLock, + ResetImage: task.ResetImage, + TriggerBy: task.TriggerBy, + Features: task.Features, + IsRestart: task.IsRestart, + StorageEndpoint: task.StorageEndpoint, } } diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go index 368a43529..e7cd55885 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go @@ -2147,6 +2147,8 @@ func ensurePipelineTask(pt *task.Task, envName string, log *zap.SugaredLogger) e } case config.TaskDistribute: // 为了兼容历史数据类型,目前什么都不用做,避免出错 + case config.TaskArtifactPackage: + // do nothing default: return e.NewErrInvalidTaskType(string(pre.TaskType)) } diff --git a/pkg/microservice/packager/config/config.go b/pkg/microservice/packager/config/config.go new file mode 100644 index 000000000..76ed9e113 --- /dev/null +++ b/pkg/microservice/packager/config/config.go @@ -0,0 +1,33 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package config + +import ( + "github.com/spf13/viper" + + // init the config first + _ "github.com/koderover/zadig/pkg/config" + "github.com/koderover/zadig/pkg/setting" +) + +func JobConfigFile() string { + return viper.GetString(setting.JobConfigFile) +} + +func Home() string { + return viper.GetString(setting.Home) +} diff --git a/pkg/microservice/packager/core/service/docker.go b/pkg/microservice/packager/core/service/docker.go new file mode 100644 index 000000000..8cb0bce06 --- /dev/null +++ b/pkg/microservice/packager/core/service/docker.go @@ -0,0 +1,72 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package service + +import ( + "os/exec" + "strings" +) + +const dockerExe = "/usr/local/bin/docker" + +func dockerVersion() *exec.Cmd { + return exec.Command(dockerExe, "version") +} + +func dockerInfo() *exec.Cmd { + return exec.Command(dockerExe, "info") +} + +// Docker returns build command +// +// e.g. docker build --rm=true -t name:tag -f Dockerfile --build-arg APP_BIN=... . +func dockerBuild(dockerfile, fullImage, buildArgs string) *exec.Cmd { + + args := []string{"build", "--rm=true"} + if buildArgs != "" { + for _, val := range strings.Fields(buildArgs) { + if val != "" { + args = append(args, val) + } + } + + } + args = append(args, []string{"-t", fullImage, "-f", dockerfile, "."}...) + return exec.Command(dockerExe, args...) +} + +func dockerPull(image string) *exec.Cmd { + args := []string{"pull", image} + return exec.Command(dockerExe, args...) +} + +func dockerTag(sourceFullImage, targetFullImage string) *exec.Cmd { + args := []string{ + "tag", + sourceFullImage, + targetFullImage, + } + return exec.Command(dockerExe, args...) +} + +func dockerPush(fullImage string) *exec.Cmd { + args := []string{ + "push", + fullImage, + } + return exec.Command(dockerExe, args...) +} diff --git a/pkg/microservice/packager/core/service/packager.go b/pkg/microservice/packager/core/service/packager.go new file mode 100644 index 000000000..771d2f201 --- /dev/null +++ b/pkg/microservice/packager/core/service/packager.go @@ -0,0 +1,46 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package service + +type ImageData struct { + ImageUrl string `bson:"image_url" json:"image_url"` + ImageName string `bson:"image_name" json:"image_name"` + ImageTag string `bson:"image_tag" json:"image_tag"` +} + +// ImagesByService defines all images in a service +type ImagesByService struct { + ServiceName string `bson:"service_name" json:"service_name"` + Images []*ImageData `bson:"images" json:"images"` +} + +//DockerRegistry registry host/user/password +type DockerRegistry struct { + Host string `yaml:"host"` + UserName string `yaml:"username"` + Password string `yaml:"password"` + Namespace string `yaml:"namespace"` +} + +// Context ... +type Context struct { + JobType string `yaml:"job_type"` + ProgressFile string `yaml:"progress_file"` + Images []*ImagesByService `yaml:"images"` + SourceRegistries []*DockerRegistry `yaml:"source_registries"` + TargetRegistries []*DockerRegistry `yaml:"target_registries"` +} diff --git a/pkg/microservice/packager/core/service/service.go b/pkg/microservice/packager/core/service/service.go new file mode 100644 index 000000000..1f85dc7e5 --- /dev/null +++ b/pkg/microservice/packager/core/service/service.go @@ -0,0 +1,215 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package service + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path" + "path/filepath" + "strings" + "time" + + "github.com/pkg/errors" + + "gopkg.in/yaml.v3" + + "github.com/koderover/zadig/pkg/microservice/packager/config" + "github.com/koderover/zadig/pkg/setting" + "github.com/koderover/zadig/pkg/tool/log" +) + +// Packager ... +type Packager struct { + Ctx *Context +} + +type ServicePackageResult struct { + ServiceName string `json:"service_name"` + Result string `json:"result"` + ErrorMsg string `json:"error_msg"` +} + +func NewPackager() (*Packager, error) { + context, err := ioutil.ReadFile(config.JobConfigFile()) + if err != nil { + return nil, err + } + + var ctx *Context + if err := yaml.Unmarshal(context, &ctx); err != nil { + return nil, err + } + + packager := &Packager{ + Ctx: ctx, + } + + return packager, nil +} + +// BeforeExec ... +func (p *Packager) BeforeExec() error { + log.Info("wait for docker daemon to start") + for i := 0; i < 120; i++ { + err := dockerInfo().Run() + if err == nil { + break + } + time.Sleep(time.Second * 1) + } + + if len(p.Ctx.ProgressFile) == 0 { + return nil + } + + // create log file + if err := os.MkdirAll(filepath.Dir(p.Ctx.ProgressFile), 0770); err != nil { + return errors.Wrapf(err, "failed to create progress file dir") + } + file, err := os.Create(p.Ctx.ProgressFile) + if err != nil { + return errors.Wrapf(err, "failed to create progress file") + } + err = file.Close() + return errors.Wrapf(err, "failed to close progress file") +} + +// Exec ... +func (p *Packager) Exec() error { + + // add docker registry auths for all registries + allRegistries := make([]*DockerRegistry, 0) + allRegistries = append(allRegistries, p.Ctx.SourceRegistries...) + allRegistries = append(allRegistries, p.Ctx.TargetRegistries...) + err := writeDockerConfig(allRegistries) + if err != nil { + return err + } + + realTimeProgress := make([]*ServicePackageResult, 0) + + for _, image := range p.Ctx.Images { + cmds := p.dockerCommands(image) + var err error + for _, cmd := range cmds { + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + log.Info(strings.Join(cmd.Args, " ")) + if err = cmd.Run(); err != nil { + break + } + } + + result := &ServicePackageResult{ + ServiceName: image.ServiceName, + } + + if err != nil { + result.Result = "failed" + result.ErrorMsg = err.Error() + log.Infof("[result][fail][%s][%s]", image.ServiceName, err) + } else { + result.Result = "success" + log.Infof("[result][success][%s]", image.ServiceName) + } + + realTimeProgress = append(realTimeProgress, result) + + if len(p.Ctx.ProgressFile) > 0 { + bs, err := json.Marshal(realTimeProgress) + if err != nil { + log.Errorf("failed to marshal progress data %s", err) + continue + } + err = os.WriteFile(p.Ctx.ProgressFile, bs, 0644) + if err != nil { + log.Errorf("failed to write progress data %s", err) + continue + } + } + } + + time.Sleep(time.Second * 10) + return nil +} + +func writeDockerConfig(registries []*DockerRegistry) error { + + authMap := make(map[string]map[string]string) + //host string, username string, password string + for _, registry := range registries { + if registry.UserName == "" { + continue + } + authMap[registry.Host] = map[string]string{ + "auth": base64.StdEncoding.EncodeToString( + []byte(strings.Join([]string{registry.UserName, registry.Password}, ":")), + )} + } + + dir := path.Join(config.Home(), ".docker") + if err := os.MkdirAll(dir, 0600); err != nil { + return err + } + + cfg := map[string]map[string]map[string]string{ + "auths": authMap, + } + + data, err := json.Marshal(cfg) + + if err != nil { + return err + } + + return ioutil.WriteFile(path.Join(dir, "config.json"), data, 0600) +} + +func (p *Packager) dockerCommands(imageByService *ImagesByService) []*exec.Cmd { + cmds := make([]*exec.Cmd, 0) + //cmds = append(cmds, dockerVersion()) + + buildTargetImage := func(imageName, imageTag, host, nameSpace string) string { + ret := "" + if len(nameSpace) > 0 { + ret = fmt.Sprintf("%s/%s/%s:%s", host, nameSpace, imageName, imageTag) + } else { + ret = fmt.Sprintf("%s/%s:%s", host, imageName, imageTag) + } + ret = strings.TrimPrefix(ret, "http://") + ret = strings.TrimPrefix(ret, "https://") + return ret + } + + if p.Ctx.JobType == setting.BuildChartPackage { + for _, image := range imageByService.Images { + for _, registry := range p.Ctx.TargetRegistries { + cmds = append(cmds, dockerPull(image.ImageUrl)) + targetImage := buildTargetImage(image.ImageName, image.ImageTag, registry.Host, registry.Namespace) + cmds = append(cmds, dockerTag(image.ImageUrl, targetImage)) + cmds = append(cmds, dockerPush(targetImage)) + } + } + } + + return cmds +} diff --git a/pkg/microservice/packager/executor/executor.go b/pkg/microservice/packager/executor/executor.go new file mode 100644 index 000000000..13f757877 --- /dev/null +++ b/pkg/microservice/packager/executor/executor.go @@ -0,0 +1,51 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package executor + +import ( + commonconfig "github.com/koderover/zadig/pkg/config" + "github.com/koderover/zadig/pkg/microservice/packager/core/service" + "github.com/koderover/zadig/pkg/setting" + "github.com/koderover/zadig/pkg/tool/log" +) + +func Execute() error { + log.Init(&log.Config{ + Level: commonconfig.LogLevel(), + NoCaller: true, + NoLogLevel: true, + Development: commonconfig.Mode() != setting.ReleaseMode, + }) + + pred, err := service.NewPackager() + if err != nil { + log.Errorf("Failed to start packager, error: %s", err) + return err + } + + if err := pred.BeforeExec(); err != nil { + log.Errorf("Failed to run before exec step, error: %s", err) + return err + } + + if err := pred.Exec(); err != nil { + log.Errorf("Failed to run exec step, error: %s", err) + return err + } + + return nil +} diff --git a/pkg/microservice/warpdrive/config/const.go b/pkg/microservice/warpdrive/config/const.go index 6e4fcaca3..88c00a895 100644 --- a/pkg/microservice/warpdrive/config/const.go +++ b/pkg/microservice/warpdrive/config/const.go @@ -19,20 +19,21 @@ package config type TaskType string const ( - TaskPipeline TaskType = "pipeline" - TaskBuild TaskType = "buildv2" - TaskArtifactDeploy TaskType = "artifact_deploy" - TaskJenkinsBuild TaskType = "jenkins_build" - TaskArtifact TaskType = "artifact" - TaskDeploy TaskType = "deploy" - TaskTestingV2 TaskType = "testingv2" - TaskDistributeToS3 TaskType = "distribute2kodo" - TaskReleaseImage TaskType = "release_image" - TaskJira TaskType = "jira" - TaskDockerBuild TaskType = "docker_build" - TaskSecurity TaskType = "security" - TaskResetImage TaskType = "reset_image" - TaskDistribute TaskType = "distribute" + TaskPipeline TaskType = "pipeline" + TaskBuild TaskType = "buildv2" + TaskArtifactDeploy TaskType = "artifact_deploy" + TaskJenkinsBuild TaskType = "jenkins_build" + TaskArtifact TaskType = "artifact" + TaskDeploy TaskType = "deploy" + TaskTestingV2 TaskType = "testingv2" + TaskDistributeToS3 TaskType = "distribute2kodo" + TaskReleaseImage TaskType = "release_image" + TaskJira TaskType = "jira" + TaskDockerBuild TaskType = "docker_build" + TaskSecurity TaskType = "security" + TaskResetImage TaskType = "reset_image" + TaskDistribute TaskType = "distribute" + TaskArtifactPackage TaskType = "artifact_package" ) type Status string @@ -65,6 +66,8 @@ const ( TestType PipelineType = "test" // ServiceType 服务 ServiceType PipelineType = "service" + // ArtifactType 服务 + ArtifactType PipelineType = "artifact" ) type NotifyType int diff --git a/pkg/microservice/warpdrive/core/service/taskcontroller/task_handler.go b/pkg/microservice/warpdrive/core/service/taskcontroller/task_handler.go index 301be7bf6..db98e0842 100644 --- a/pkg/microservice/warpdrive/core/service/taskcontroller/task_handler.go +++ b/pkg/microservice/warpdrive/core/service/taskcontroller/task_handler.go @@ -411,6 +411,9 @@ func (h *ExecHandler) executeTask(taskCtx context.Context, plugin plugins.TaskPl } else if pipelineTask.Type == config.ServiceType { fileName = strings.Replace(strings.ToLower(fmt.Sprintf("%s-%s-%d-%s-%s", config.ServiceType, pipelineTask.PipelineName, pipelineTask.TaskID, plugin.Type(), servicename)), "_", "-", -1) + } else if pipelineTask.Type == config.ArtifactType { + fileName = strings.Replace(strings.ToLower(fmt.Sprintf("%s-%s-%d-%s", config.ArtifactType, pipelineTask.PipelineName, pipelineTask.TaskID, plugin.Type())), + "_", "-", -1) } plugin.Init(jobName, fileName, xl) diff --git a/pkg/microservice/warpdrive/core/service/taskcontroller/task_helper.go b/pkg/microservice/warpdrive/core/service/taskcontroller/task_helper.go index b0a13595e..f8b7a57ee 100644 --- a/pkg/microservice/warpdrive/core/service/taskcontroller/task_helper.go +++ b/pkg/microservice/warpdrive/core/service/taskcontroller/task_helper.go @@ -136,6 +136,9 @@ func updatePipelineSubTask(t interface{}, pipelineTask *task.Task, pos int, serv } else if pipelineTask.Type == config.ServiceType { xl.Info("pipeline type is service type: pipeline 3.0") pipelineTask.Stages[pos].SubTasks[servicename] = subTask + } else if pipelineTask.Type == config.ArtifactType { + xl.Info("pipeline type is artifact-package type: pipeline 3.0") + pipelineTask.Stages[pos].SubTasks[servicename] = subTask } } @@ -538,17 +541,18 @@ func getSubTaskTypeAndIsRestart(subTask map[string]interface{}) bool { func initTaskPlugins(execHandler *ExecHandler) { pluginConf := map[config.TaskType]plugins.Initiator{ - config.TaskJira: plugins.InitializeJiraTaskPlugin, - config.TaskBuild: plugins.InitializeBuildTaskPlugin, - config.TaskArtifactDeploy: plugins.InitializeArtifactTaskPlugin, - config.TaskJenkinsBuild: plugins.InitializeJenkinsBuildPlugin, - config.TaskDockerBuild: plugins.InitializeDockerBuildTaskPlugin, - config.TaskDeploy: plugins.InitializeDeployTaskPlugin, - config.TaskTestingV2: plugins.InitializeTestTaskPlugin, - config.TaskSecurity: plugins.InitializeSecurityPlugin, - config.TaskReleaseImage: plugins.InitializeReleaseImagePlugin, - config.TaskDistributeToS3: plugins.InitializeDistribute2S3TaskPlugin, - config.TaskResetImage: plugins.InitializeDeployTaskPlugin, + config.TaskJira: plugins.InitializeJiraTaskPlugin, + config.TaskBuild: plugins.InitializeBuildTaskPlugin, + config.TaskArtifactDeploy: plugins.InitializeArtifactTaskPlugin, + config.TaskJenkinsBuild: plugins.InitializeJenkinsBuildPlugin, + config.TaskDockerBuild: plugins.InitializeDockerBuildTaskPlugin, + config.TaskDeploy: plugins.InitializeDeployTaskPlugin, + config.TaskTestingV2: plugins.InitializeTestTaskPlugin, + config.TaskSecurity: plugins.InitializeSecurityPlugin, + config.TaskReleaseImage: plugins.InitializeReleaseImagePlugin, + config.TaskDistributeToS3: plugins.InitializeDistribute2S3TaskPlugin, + config.TaskResetImage: plugins.InitializeDeployTaskPlugin, + config.TaskArtifactPackage: plugins.InitializeArtifactPackagePlugin, } for name, pluginInitiator := range pluginConf { registerTaskPlugin(execHandler, name, pluginInitiator) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go b/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go new file mode 100644 index 000000000..2436728d6 --- /dev/null +++ b/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go @@ -0,0 +1,421 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package taskplugin + +import ( + "context" + "fmt" + "time" + + "github.com/koderover/zadig/pkg/shared/kube/wrapper" + "github.com/koderover/zadig/pkg/tool/kube/getter" + "github.com/koderover/zadig/pkg/tool/kube/podexec" + "k8s.io/apimachinery/pkg/labels" + + "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types" + "github.com/koderover/zadig/pkg/setting" + "gopkg.in/yaml.v3" + + "github.com/koderover/zadig/pkg/microservice/warpdrive/config" + "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types/task" + krkubeclient "github.com/koderover/zadig/pkg/tool/kube/client" + "github.com/koderover/zadig/pkg/tool/kube/updater" + "go.uber.org/zap" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// InitializeArtifactPackagePlugin to ini +func InitializeArtifactPackagePlugin(taskType config.TaskType) TaskPlugin { + return &ArtifactPackageTaskPlugin{ + Name: taskType, + kubeClient: krkubeclient.Client(), + } +} + +type ArtifactPackageTaskPlugin struct { + Name config.TaskType + KubeNamespace string + JobName string + FileName string + kubeClient client.Client + Task *task.ArtifactPackage + AckFunc func() + Log *zap.SugaredLogger + + RealTimeProgress string +} + +const ( + // ArtifactPackageBuildImageTaskTimeout ... + ArtifactPackageBuildImageTaskTimeout = 60 * 5 // 5 minutes +) + +// Init ... +func (p *ArtifactPackageTaskPlugin) Init(jobname, filename string, xl *zap.SugaredLogger) { + p.JobName = jobname + p.FileName = filename + // SetLogger ... + p.Log = xl +} + +func (p *ArtifactPackageTaskPlugin) SetAckFunc(f func()) { + p.AckFunc = f +} + +// Type ... +func (p *ArtifactPackageTaskPlugin) Type() config.TaskType { + return p.Name +} + +// Status ... +func (p *ArtifactPackageTaskPlugin) Status() config.Status { + return p.Task.TaskStatus +} + +// SetStatus ... +func (p *ArtifactPackageTaskPlugin) SetStatus(status config.Status) { + p.Task.TaskStatus = status +} + +func (p *ArtifactPackageTaskPlugin) SetProgress(progress string) { + p.Task.Progress = progress +} + +// TaskTimeout ... +func (p *ArtifactPackageTaskPlugin) TaskTimeout() int { + if p.Task.Timeout == 0 { + p.Task.Timeout = ArtifactPackageBuildImageTaskTimeout + } + return p.Task.Timeout +} + +func (p *ArtifactPackageTaskPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipelineCtx *task.PipelineCtx, serviceName string) { + p.KubeNamespace = pipelineTask.ConfigPayload.Build.KubeNamespace + + sourceRegistries := make([]*types.DockerRegistry, 0) + for _, registryID := range pipelineTask.ArtifactPackageTaskArgs.SourceRegistries { + if registry, ok := pipelineTask.ConfigPayload.RepoConfigs[registryID]; ok { + sourceRegistries = append(sourceRegistries, &types.DockerRegistry{ + Host: registry.RegAddr, + Namespace: registry.Namespace, + UserName: registry.AccessKey, + Password: registry.SecretKey, + }) + } + } + + targetRegistries := make([]*types.DockerRegistry, 0) + for _, registryID := range pipelineTask.ArtifactPackageTaskArgs.TargetRegistries { + if registry, ok := pipelineTask.ConfigPayload.RepoConfigs[registryID]; ok { + targetRegistries = append(targetRegistries, &types.DockerRegistry{ + Host: registry.RegAddr, + Namespace: registry.Namespace, + UserName: registry.AccessKey, + Password: registry.SecretKey, + }) + } + } + + jobCtx := &types.ArtifactPackagerContext{ + JobType: setting.BuildChartPackage, + ProgressFile: setting.ProgressFile, + Images: pipelineTask.ArtifactPackageTaskArgs.Images, + SourceRegistries: sourceRegistries, + TargetRegistries: targetRegistries, + } + + jobCtxBytes, err := yaml.Marshal(jobCtx) + if err != nil { + msg := fmt.Sprintf("cannot mashal predetor.Context data: %v", err) + p.Log.Error(msg) + p.Task.TaskStatus = config.StatusFailed + p.Task.Error = msg + return + } + + p.Task.Error = "" + + jobLabel := &JobLabel{ + PipelineName: pipelineTask.PipelineName, + TaskID: pipelineTask.TaskID, + TaskType: string(p.Type()), + PipelineType: string(pipelineTask.Type), + } + + if err := ensureDeleteConfigMap(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + msg := fmt.Sprintf("ensureDeleteConfigMap error: %v", err) + p.Log.Error(msg) + p.Task.TaskStatus = config.StatusFailed + p.Task.Error = msg + return + } + + if err := createJobConfigMap( + p.KubeNamespace, p.JobName, jobLabel, string(jobCtxBytes), p.kubeClient); err != nil { + msg := fmt.Sprintf("createJobConfigMap error: %v", err) + p.Log.Error(msg) + p.Task.TaskStatus = config.StatusFailed + p.Task.Error = msg + return + } + p.Log.Infof("succeed to create cm for artifact package job %s", p.JobName) + + job, err := buildJob(p.Type(), pipelineTask.ConfigPayload.Release.PackagerImage, p.JobName, serviceName, setting.MinRequest, pipelineCtx, pipelineTask, []*task.RegistryNamespace{}) + if err != nil { + msg := fmt.Sprintf("create release artifact package job context error: %v", err) + p.Log.Error(msg) + p.Task.TaskStatus = config.StatusFailed + p.Task.Error = msg + return + } + + if err := ensureDeleteJob(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + msg := fmt.Sprintf("delete release artifact package job error: %v", err) + p.Log.Error(msg) + p.Task.TaskStatus = config.StatusFailed + p.Task.Error = msg + return + } + + job.Namespace = p.KubeNamespace + if err := updater.CreateJob(job, p.kubeClient); err != nil { + msg := fmt.Sprintf("create release image job error: %v", err) + p.Log.Error(msg) + p.Task.TaskStatus = config.StatusFailed + p.Task.Error = msg + return + } + p.Log.Infof("succeed to create artifact package job %s", p.JobName) +} + +// SetTask ... +func (p *ArtifactPackageTaskPlugin) SetTask(t map[string]interface{}) error { + task, err := ToArtifactTask(t) + if err != nil { + return err + } + p.Task = task + return nil +} + +// GetTask ... +func (p *ArtifactPackageTaskPlugin) GetTask() interface{} { + return p.Task +} + +// Wait ... +func (p *ArtifactPackageTaskPlugin) Wait(ctx context.Context) { + + status := p.waitJobStart() + if status != config.StatusRunning { + p.SetStatus(status) + return + } + + status = p.waitJobEnd(ctx, p.TaskTimeout()) + p.SetProgress(p.RealTimeProgress) + p.SetStatus(status) +} + +func (p *ArtifactPackageTaskPlugin) waitJobStart() config.Status { + namespace, jobName, kubeClient, xl := p.KubeNamespace, p.JobName, p.kubeClient, p.Log + xl.Infof("wait job to start: %s/%s", namespace, jobName) + podTimeout := time.After(120 * time.Second) + var started bool + for { + select { + case <-podTimeout: + return config.StatusTimeout + default: + job, _, err := getter.GetJob(namespace, jobName, kubeClient) + if err != nil { + xl.Errorf("get job failed, namespace:%s, jobName:%s, err:%v", namespace, jobName, err) + } + if job != nil { + started = job.Status.Active > 0 + } + } + if started { + break + } + + time.Sleep(time.Second) + } + return config.StatusRunning +} + +func (p *ArtifactPackageTaskPlugin) waitJobEnd(ctx context.Context, taskTimeout int) (status config.Status) { + namespace, jobName, kubeClient, xl := p.KubeNamespace, p.JobName, p.kubeClient, p.Log + xl.Infof("wait job to start: %s/%s", namespace, jobName) + timeout := time.After(time.Duration(taskTimeout) * time.Second) + + // 等待job 运行结束 + xl.Infof("wait job to end: %s %s", namespace, jobName) + for { + select { + case <-ctx.Done(): + return config.StatusCancelled + + case <-timeout: + return config.StatusTimeout + + default: + job, found, err := getter.GetJob(namespace, jobName, kubeClient) + if err != nil || !found { + xl.Errorf("failed to get pod with label job-name=%s %v", jobName, err) + return config.StatusFailed + } + // pod is still running + if job.Status.Active != 0 { + + pods, err := getter.ListPods(namespace, labels.Set{"job-name": jobName}.AsSelector(), kubeClient) + if err != nil { + xl.Errorf("failed to find pod with label job-name=%s %v", jobName, err) + return config.StatusFailed + } + + var done bool + for _, pod := range pods { + ipod := wrapper.Pod(pod) + if ipod.Pending() { + continue + } + if ipod.Failed() { + return config.StatusFailed + } + + if !ipod.Finished() { + progressInfo, err := getProgressInfo(namespace, ipod.Name, ipod.ContainerNames()[0], setting.ProgressFile) + if err != nil { + xl.Infof("failed to check dog food file %s %v", pods[0].Name, err) + break + } + p.RealTimeProgress = progressInfo + xl.Infof("find progress info %s", progressInfo) + p.SetProgress(progressInfo) + p.SetStatus(config.StatusRunning) + + if p.AckFunc != nil { + p.AckFunc() + } + } else { + done = true + } + } + + if done { + return config.StatusPassed + } + } else if job.Status.Succeeded != 0 { + return config.StatusPassed + } else { + return config.StatusFailed + } + } + + time.Sleep(time.Second * 5) + } + +} + +// Complete ... +func (p *ArtifactPackageTaskPlugin) Complete(ctx context.Context, pipelineTask *task.Task, serviceName string) { + jobLabel := &JobLabel{ + PipelineName: pipelineTask.PipelineName, + ServiceName: serviceName, + TaskID: pipelineTask.TaskID, + TaskType: string(p.Type()), + PipelineType: string(pipelineTask.Type), + } + + // 清理用户取消和超时的任务 + defer func() { + if p.Task.TaskStatus == config.StatusCancelled || p.Task.TaskStatus == config.StatusTimeout { + if err := ensureDeleteJob(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + p.Log.Error(err) + p.Task.Error = err.Error() + } + return + } + }() + + // 保存实时日志到s3 + err := saveContainerLog(pipelineTask, p.KubeNamespace, p.FileName, jobLabel, p.kubeClient) + if err != nil { + p.Log.Error(err) + p.Task.Error = err.Error() + return + } + + p.Task.LogFile = p.JobName +} + +// IsTaskDone ... +func (p *ArtifactPackageTaskPlugin) IsTaskDone() bool { + if p.Task.TaskStatus != config.StatusCreated && p.Task.TaskStatus != config.StatusRunning { + return true + } + return false +} + +// IsTaskFailed ... +func (p *ArtifactPackageTaskPlugin) IsTaskFailed() bool { + if p.Task.TaskStatus == config.StatusFailed || p.Task.TaskStatus == config.StatusTimeout || p.Task.TaskStatus == config.StatusCancelled { + return true + } + return false +} + +// SetStartTime ... +func (p *ArtifactPackageTaskPlugin) SetStartTime() { + p.Task.StartTime = time.Now().Unix() +} + +// SetEndTime ... +func (p *ArtifactPackageTaskPlugin) SetEndTime() { + p.Task.EndTime = time.Now().Unix() +} + +// IsTaskEnabled ... +func (p *ArtifactPackageTaskPlugin) IsTaskEnabled() bool { + return p.Task.Enabled +} + +// ResetError ... +func (p *ArtifactPackageTaskPlugin) ResetError() { + p.Task.Error = "" +} + +func getProgressInfo(namespace string, pod string, container string, progressInfoFile string) (string, error) { + stdOut, stdErr, success, err := podexec.ExecWithOptions(podexec.ExecOptions{ + Command: []string{"cat", progressInfoFile}, + Namespace: namespace, + PodName: pod, + ContainerName: container, + }) + + if err != nil { + return "", err + } + if len(stdErr) != 0 { + return "", fmt.Errorf(stdErr) + } + if !success { + return "", fmt.Errorf("pod exec execute failed") + } + return stdOut, nil +} diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/job.go b/pkg/microservice/warpdrive/core/service/taskplugin/job.go index 1d13553eb..81c0dbcf4 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/job.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/job.go @@ -57,6 +57,7 @@ const ( defaultSecretEmail = "bot@koderover.com" PredatorPlugin = "predator-plugin" JenkinsPlugin = "jenkins-plugin" + PackagerPlugin = "packager-plugin" ) const ( @@ -106,6 +107,7 @@ func saveContainerLog(pipelineTask *task.Task, namespace, fileName string, jobLa if err = saveFile(buf, tempFileName); err == nil { var store *s3.S3 if store, err = s3.NewS3StorageFromEncryptedURI(pipelineTask.StorageURI); err != nil { + log.Errorf("failed to NewS3StorageFromEncryptedURI ") return err } if store.Subfolder != "" { @@ -351,12 +353,19 @@ const ( // getJobLabels get labels k-v map from JobLabel struct func getJobLabels(jobLabel *JobLabel) map[string]string { - return map[string]string{ + retMap := map[string]string{ jobLabelTaskKey: fmt.Sprintf("%s-%d", strings.ToLower(jobLabel.PipelineName), jobLabel.TaskID), jobLabelServiceKey: strings.ToLower(jobLabel.ServiceName), jobLabelSTypeKey: strings.Replace(jobLabel.TaskType, "_", "-", -1), jobLabelPTypeKey: jobLabel.PipelineType, } + // no need to add labels with empty value to a job + for k, v := range retMap { + if len(v) == 0 { + delete(retMap, k) + } + } + return retMap } func createJobConfigMap(namespace, jobName string, jobLabel *JobLabel, jobCtx string, kubeClient client.Client) error { @@ -399,7 +408,7 @@ func buildJob(taskType config.TaskType, jobImage, jobName, serviceName string, r func buildJobWithLinkedNs(taskType config.TaskType, jobImage, jobName, serviceName string, resReq setting.Request, ctx *task.PipelineCtx, pipelineTask *task.Task, registries []*task.RegistryNamespace, execNs, linkedNs string) (*batchv1.Job, error) { var reaperBootingScript string - if !strings.Contains(jobImage, PredatorPlugin) && !strings.Contains(jobImage, JenkinsPlugin) { + if !strings.Contains(jobImage, PredatorPlugin) && !strings.Contains(jobImage, JenkinsPlugin) && !strings.Contains(jobImage, PackagerPlugin) { reaperBootingScript = fmt.Sprintf("curl -m 60 --retry-delay 5 --retry 3 -sL %s -o reaper && chmod +x reaper && mv reaper /usr/local/bin && /usr/local/bin/reaper", pipelineTask.ConfigPayload.Release.ReaperBinaryFile) if pipelineTask.ConfigPayload.Proxy.EnableApplicationProxy && pipelineTask.ConfigPayload.Proxy.Type == "http" { reaperBootingScript = fmt.Sprintf("curl -m 60 --retry-delay 5 --retry 3 -sL --proxy %s %s -o reaper && chmod +x reaper && mv reaper /usr/local/bin && /usr/local/bin/reaper", @@ -480,7 +489,7 @@ func buildJobWithLinkedNs(taskType config.TaskType, jobImage, jobName, serviceNa }, } - if !strings.Contains(jobImage, PredatorPlugin) && !strings.Contains(jobImage, JenkinsPlugin) { + if !strings.Contains(jobImage, PredatorPlugin) && !strings.Contains(jobImage, JenkinsPlugin) && !strings.Contains(jobImage, PackagerPlugin) { job.Spec.Template.Spec.Containers[0].Command = []string{"/bin/sh", "-c"} job.Spec.Template.Spec.Containers[0].Args = []string{reaperBootingScript} } diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/utils.go b/pkg/microservice/warpdrive/core/service/taskplugin/utils.go index 6d4111015..35236b813 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/utils.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/utils.go @@ -98,7 +98,7 @@ type Preview struct { func ToPreview(sb map[string]interface{}) (*Preview, error) { var pre *Preview if err := IToi(sb, &pre); err != nil { - return nil, fmt.Errorf("convert interface to SubTaskPreview error: %v", err) + return nil, fmt.Errorf("convert interface to SubTaskPreview error: %s", err) } return pre, nil } @@ -106,15 +106,15 @@ func ToPreview(sb map[string]interface{}) (*Preview, error) { func ToBuildTask(sb map[string]interface{}) (*task.Build, error) { var t *task.Build if err := IToi(sb, &t); err != nil { - return nil, fmt.Errorf("convert interface to BuildTaskV2 error: %v", err) + return nil, fmt.Errorf("convert interface to BuildTaskV2 error: %s", err) } return t, nil } -func ToArtifactTask(sb map[string]interface{}) (*task.Artifact, error) { - var t *task.Artifact +func ToArtifactTask(sb map[string]interface{}) (*task.ArtifactPackage, error) { + var t *task.ArtifactPackage if err := IToi(sb, &t); err != nil { - return nil, fmt.Errorf("convert interface to ArtifactTask error: %v", err) + return nil, fmt.Errorf("convert interface to ArtifactTask error: %s", err) } return t, nil } @@ -122,7 +122,7 @@ func ToArtifactTask(sb map[string]interface{}) (*task.Artifact, error) { func ToDockerBuildTask(sb map[string]interface{}) (*task.DockerBuild, error) { var t *task.DockerBuild if err := IToi(sb, &t); err != nil { - return nil, fmt.Errorf("convert interface to DockerBuildTask error: %v", err) + return nil, fmt.Errorf("convert interface to DockerBuildTask error: %s", err) } return t, nil } @@ -130,7 +130,7 @@ func ToDockerBuildTask(sb map[string]interface{}) (*task.DockerBuild, error) { func ToDeployTask(sb map[string]interface{}) (*task.Deploy, error) { var t *task.Deploy if err := IToi(sb, &t); err != nil { - return nil, fmt.Errorf("convert interface to DeployTask error: %v", err) + return nil, fmt.Errorf("convert interface to DeployTask error: %s", err) } return t, nil } @@ -138,7 +138,7 @@ func ToDeployTask(sb map[string]interface{}) (*task.Deploy, error) { func ToTestingTask(sb map[string]interface{}) (*task.Testing, error) { var t *task.Testing if err := IToi(sb, &t); err != nil { - return nil, fmt.Errorf("convert interface to Testing error: %v", err) + return nil, fmt.Errorf("convert interface to Testing error: %s", err) } return t, nil } @@ -146,7 +146,7 @@ func ToTestingTask(sb map[string]interface{}) (*task.Testing, error) { func ToDistributeToS3Task(sb map[string]interface{}) (*task.DistributeToS3, error) { var t *task.DistributeToS3 if err := IToi(sb, &t); err != nil { - return nil, fmt.Errorf("convert interface to DistributeToS3Task error: %v", err) + return nil, fmt.Errorf("convert interface to DistributeToS3Task error: %s", err) } return t, nil } @@ -154,15 +154,23 @@ func ToDistributeToS3Task(sb map[string]interface{}) (*task.DistributeToS3, erro func ToReleaseImageTask(sb map[string]interface{}) (*task.ReleaseImage, error) { var t *task.ReleaseImage if err := IToi(sb, &t); err != nil { - return nil, fmt.Errorf("convert interface to ReleaseImageTask error: %v", err) + return nil, fmt.Errorf("convert interface to ReleaseImageTask error: %s", err) } return t, nil } +func ToArtifactPackageTask(sb map[string]interface{}) (*task.ArtifactPackageTaskArgs, error) { + var ret *task.ArtifactPackageTaskArgs + if err := IToi(sb, &ret); err != nil { + return nil, fmt.Errorf("convert interface to ArtifactPackageTaskArgs error: %s", err) + } + return ret, nil +} + func ToJiraTask(sb map[string]interface{}) (*task.Jira, error) { var t *task.Jira if err := IToi(sb, &t); err != nil { - return nil, fmt.Errorf("convert interface to JiraTask error: %v", err) + return nil, fmt.Errorf("convert interface to JiraTask error: %s", err) } return t, nil } @@ -170,7 +178,7 @@ func ToJiraTask(sb map[string]interface{}) (*task.Jira, error) { func ToSecurityTask(sb map[string]interface{}) (*task.Security, error) { var t *task.Security if err := IToi(sb, &t); err != nil { - return nil, fmt.Errorf("convert interface to securityTask error: %v", err) + return nil, fmt.Errorf("convert interface to securityTask error: %s", err) } return t, nil } @@ -178,7 +186,7 @@ func ToSecurityTask(sb map[string]interface{}) (*task.Security, error) { func ToJenkinsBuildTask(sb map[string]interface{}) (*task.JenkinsBuild, error) { var task *task.JenkinsBuild if err := IToi(sb, &task); err != nil { - return nil, fmt.Errorf("convert interface to JenkinsBuildTask error: %v", err) + return nil, fmt.Errorf("convert interface to JenkinsBuildTask error: %s", err) } return task, nil } @@ -186,11 +194,11 @@ func ToJenkinsBuildTask(sb map[string]interface{}) (*task.JenkinsBuild, error) { func IToi(before interface{}, after interface{}) error { b, err := json.Marshal(before) if err != nil { - return fmt.Errorf("marshal task error: %v", err) + return fmt.Errorf("marshal task error: %s", err) } if err := json.Unmarshal(b, &after); err != nil { - return fmt.Errorf("unmarshal task error: %v", err) + return fmt.Errorf("unmarshal task error: %s", err) } return nil diff --git a/pkg/microservice/warpdrive/core/service/types/packager.go b/pkg/microservice/warpdrive/core/service/types/packager.go new file mode 100644 index 000000000..19aac50ae --- /dev/null +++ b/pkg/microservice/warpdrive/core/service/types/packager.go @@ -0,0 +1,27 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package types + +import "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types/task" + +type ArtifactPackagerContext struct { + JobType string `yaml:"job_type"` + ProgressFile string `yaml:"progress_file"` + Images []*task.ImagesByService `yaml:"images"` + SourceRegistries []*DockerRegistry `yaml:"source_registries"` + TargetRegistries []*DockerRegistry `yaml:"target_registries"` +} diff --git a/pkg/microservice/warpdrive/core/service/types/task/artifact_package.go b/pkg/microservice/warpdrive/core/service/types/task/artifact_package.go new file mode 100644 index 000000000..9ac39d95a --- /dev/null +++ b/pkg/microservice/warpdrive/core/service/types/task/artifact_package.go @@ -0,0 +1,50 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package task + +import ( + "fmt" + + "github.com/koderover/zadig/pkg/microservice/warpdrive/config" +) + +type ArtifactPackage struct { + TaskType config.TaskType `bson:"type" json:"type"` + Enabled bool `bson:"enabled" json:"enabled"` + TaskStatus config.Status `bson:"status" json:"status"` + Progress string `bson:"progress" json:"progress"` + Timeout int `bson:"timeout,omitempty" json:"timeout,omitempty"` + Error string `bson:"error,omitempty" json:"error,omitempty"` + StartTime int64 `bson:"start_time,omitempty" json:"start_time,omitempty"` + EndTime int64 `bson:"end_time,omitempty" json:"end_time,omitempty"` + LogFile string `bson:"log_file" json:"log_file"` + + // source images + Images []*ImagesByService `bson:"images" json:"images"` + // target registries to push images + SourceRegistries []string `bson:"source_registries" json:"source_registries"` + // target registries to push images + TargetRegistries []string `bson:"target_registries" json:"target_registries"` +} + +func (ri *ArtifactPackage) ToSubTask() (map[string]interface{}, error) { + var task map[string]interface{} + if err := IToi(ri, &task); err != nil { + return nil, fmt.Errorf("convert ReleaseImageTask to interface error: %v", err) + } + return task, nil +} diff --git a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go index 3b3e6e0a8..fb5c696e1 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go +++ b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go @@ -129,6 +129,9 @@ type ReleaseConfig struct { // PredatorImage sets docker build image // e.g. xxx.com/resources/predator-plugin:v0.1.0 PredatorImage string + // PackagerImage sets docker build image + // e.g. xxx.com/resources/predator-plugin:v0.1.0 + PackagerImage string } type ImageReleaseConfig struct { diff --git a/pkg/microservice/warpdrive/core/service/types/task/model.go b/pkg/microservice/warpdrive/core/service/types/task/model.go index d6a0d9751..aa4ed2f16 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/model.go +++ b/pkg/microservice/warpdrive/core/service/types/task/model.go @@ -64,6 +64,8 @@ type Task struct { TestArgs *TestTaskArgs `bson:"test_args,omitempty" json:"test_args,omitempty"` // ServiceTaskArgs 脚本部署工作流任务参数 ServiceTaskArgs *ServiceTaskArgs `bson:"service_args,omitempty" json:"service_args,omitempty"` + // ArtifactPackageTaskArgs arguments for artifact-package type tasks + ArtifactPackageTaskArgs *ArtifactPackageTaskArgs `bson:"artifact_package_args,omitempty" json:"artifact_package_args,omitempty"` // ConfigPayload 系统配置信息 ConfigPayload *ConfigPayload `json:"config_payload,omitempty"` Error string `bson:"error,omitempty" json:"error,omitempty"` @@ -243,6 +245,24 @@ type ServiceTaskArgs struct { Updatable bool `bson:"updatable" json:"updatable"` } +type ImageData struct { + ImageUrl string `bson:"image_url" json:"image_url"` + ImageName string `bson:"image_name" json:"image_name"` + ImageTag string `bson:"image_tag" json:"image_tag"` +} + +type ImagesByService struct { + ServiceName string `bson:"service_name" json:"service_name"` + Images []*ImageData `bson:"images" json:"images"` +} + +type ArtifactPackageTaskArgs struct { + ProductName string `bson:"product_name" json:"product_name"` + Images []*ImagesByService `bson:"images" json:"images"` + SourceRegistries []string `bson:"source_registries" json:"source_registries"` + TargetRegistries []string `bson:"target_registries" json:"target_registries"` +} + type ProductService struct { ServiceName string `bson:"service_name" json:"service_name"` ProductName string `bson:"product_name" json:"product_name"` diff --git a/pkg/setting/consts.go b/pkg/setting/consts.go index c8c77099e..6aa3107e8 100644 --- a/pkg/setting/consts.go +++ b/pkg/setting/consts.go @@ -50,6 +50,7 @@ const ( ENVReaperImage = "REAPER_IMAGE" ENVReaperBinaryFile = "REAPER_BINARY_FILE" ENVPredatorImage = "PREDATOR_IMAGE" + EnvPackagerImage = "PACKAGER_IMAGE" ENVDockerHosts = "DOCKER_HOSTS" @@ -299,6 +300,10 @@ const ( ReleaseImageJob = "docker-release" ) +const ( + BuildChartPackage = "chart-package" +) + const ( JenkinsBuildJob = "jenkins-build" ) @@ -525,6 +530,8 @@ const MaxTries = 1 const DogFood = "/var/run/koderover-dog-food" +const ProgressFile = "/var/log/job-progress" + const ( ResponseError = "error" ResponseData = "response" -- Gitee From 2ea93701372e040d1b7376b668777317183024df Mon Sep 17 00:00:00 2001 From: liu deyi Date: Wed, 1 Dec 2021 16:47:08 +0800 Subject: [PATCH 015/134] add cluster init Signed-off-by: liu deyi --- pkg/cli/initconfig/cmd/init.go | 28 ++++++++++++- .../common/repository/models/k8s_cluster.go | 33 ++++++++------- .../core/multicluster/service/clusters.go | 12 +----- pkg/shared/client/aslan/multicluster.go | 42 +++++++++++++++++++ 4 files changed, 87 insertions(+), 28 deletions(-) create mode 100644 pkg/shared/client/aslan/multicluster.go diff --git a/pkg/cli/initconfig/cmd/init.go b/pkg/cli/initconfig/cmd/init.go index 1d0d67930..da0a70ff3 100644 --- a/pkg/cli/initconfig/cmd/init.go +++ b/pkg/cli/initconfig/cmd/init.go @@ -25,11 +25,11 @@ import ( "github.com/spf13/cobra" "golang.org/x/sync/errgroup" - "sigs.k8s.io/yaml" "github.com/koderover/zadig/pkg/config" "github.com/koderover/zadig/pkg/setting" + "github.com/koderover/zadig/pkg/shared/client/aslan" "github.com/koderover/zadig/pkg/shared/client/policy" "github.com/koderover/zadig/pkg/shared/client/user" "github.com/koderover/zadig/pkg/tool/httpclient" @@ -86,9 +86,15 @@ func initSystemConfig() error { } if err := presetRoleBinding(uid); err != nil { - log.Errorf("presetRoleBinding :%s", err) + log.Errorf("presetRoleBinding err:%s", err) + return err + } + + if err := createMultiCluster(); err != nil { + log.Errorf("createMultiCluster err:%s", err) return err } + return nil } @@ -184,3 +190,21 @@ func presetRole() error { } return nil } + +func createMultiCluster() error { + clusters, err := aslan.New(config.AslanServiceAddress()).ListMultiCluster() + if err != nil { + return err + } + var hasLocal bool + for _, cluster := range clusters { + if cluster.Local { + hasLocal = true + break + } + } + if !hasLocal { + return aslan.New(config.AslanServiceAddress()).AddMultiCluster() + } + return nil +} diff --git a/pkg/microservice/aslan/core/common/repository/models/k8s_cluster.go b/pkg/microservice/aslan/core/common/repository/models/k8s_cluster.go index b1768569e..bbc32146b 100644 --- a/pkg/microservice/aslan/core/common/repository/models/k8s_cluster.go +++ b/pkg/microservice/aslan/core/common/repository/models/k8s_cluster.go @@ -29,22 +29,23 @@ import ( var namePattern = regexp.MustCompile(`^[0-9a-zA-Z_.-]{1,32}$`) type K8SCluster struct { - ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` - Name string `json:"name" bson:"name"` - Tags []string `json:"tags" bson:"tags"` - Description string `json:"description" bson:"description"` - Namespace string `json:"namespace" bson:"namespace"` - Info *K8SClusterInfo `json:"info,omitempty" bson:"info,omitempty"` - Status setting.K8SClusterStatus `json:"status" bson:"status"` - Error string `json:"error" bson:"error"` - Yaml string `json:"yaml" bson:"yaml"` - Production bool `json:"production" bson:"production"` - CreatedAt int64 `json:"createdAt" bson:"createdAt"` - CreatedBy string `json:"createdBy" bson:"createdBy"` - Disconnected bool `json:"-" bson:"disconnected"` - Token string `json:"token" bson:"-"` - Provider int8 `json:"provider" bson:"provider"` - Local bool `json:"local" bson:"local"` + ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` + Name string `json:"name" bson:"name"` + Tags []string `json:"tags" bson:"tags"` + Description string `json:"description" bson:"description"` + Namespace string `json:"namespace" bson:"namespace"` + Info *K8SClusterInfo `json:"info,omitempty" bson:"info,omitempty"` + ClusterConfig *ClusterConfig `json:"config,omitempty" bson:"config,omitempty"` + Status setting.K8SClusterStatus `json:"status" bson:"status"` + Error string `json:"error" bson:"error"` + Yaml string `json:"yaml" bson:"yaml"` + Production bool `json:"production" bson:"production"` + CreatedAt int64 `json:"createdAt" bson:"createdAt"` + CreatedBy string `json:"createdBy" bson:"createdBy"` + Disconnected bool `json:"-" bson:"disconnected"` + Token string `json:"token" bson:"-"` + Provider int8 `json:"provider" bson:"provider"` + Local bool `json:"local" bson:"local"` } type K8SClusterInfo struct { diff --git a/pkg/microservice/aslan/core/multicluster/service/clusters.go b/pkg/microservice/aslan/core/multicluster/service/clusters.go index ddc196cb1..49386dd42 100644 --- a/pkg/microservice/aslan/core/multicluster/service/clusters.go +++ b/pkg/microservice/aslan/core/multicluster/service/clusters.go @@ -41,11 +41,11 @@ type K8SCluster struct { CreatedAt int64 `json:"createdAt"` CreatedBy string `json:"createdBy"` Provider int8 `json:"provider"` + Local bool `json:"local"` } func ListClusters(ids []string, logger *zap.SugaredLogger) ([]*K8SCluster, error) { idSet := sets.NewString(ids...) - localClusterIncluded := idSet.Has(setting.LocalClusterID) idSet = idSet.Delete(setting.LocalClusterID) cs, err := commonrepo.NewK8SClusterColl().List(&commonrepo.ClusterListOpts{IDs: idSet.UnsortedList()}) if err != nil { @@ -54,15 +54,6 @@ func ListClusters(ids []string, logger *zap.SugaredLogger) ([]*K8SCluster, error } var res []*K8SCluster - if len(ids) == 0 || localClusterIncluded { - res = append(res, &K8SCluster{ - ID: setting.LocalClusterID, - Name: setting.LocalClusterName, - Production: false, - Status: setting.Normal, - }) - } - for _, c := range cs { res = append(res, &K8SCluster{ ID: c.ID.Hex(), @@ -73,6 +64,7 @@ func ListClusters(ids []string, logger *zap.SugaredLogger) ([]*K8SCluster, error CreatedBy: c.CreatedBy, CreatedAt: c.CreatedAt, Provider: c.Provider, + Local: c.Local, }) } diff --git a/pkg/shared/client/aslan/multicluster.go b/pkg/shared/client/aslan/multicluster.go new file mode 100644 index 000000000..e74e9606b --- /dev/null +++ b/pkg/shared/client/aslan/multicluster.go @@ -0,0 +1,42 @@ +package aslan + +import ( + "fmt" + "time" + + "github.com/koderover/zadig/pkg/tool/httpclient" +) + +type cluster struct { + Name string `json:"name"` + Production bool `json:"production"` + Local bool `json:"local"` +} + +func (c *Client) AddMultiCluster() error { + timeStamp := time.Now().Format("20060102150405") + url := "/cluster/clusters" + req := cluster{ + Name: fmt.Sprintf("%s-%s", "local", timeStamp), + Local: true, + } + + _, err := c.Post(url, httpclient.SetBody(req)) + if err != nil { + return fmt.Errorf("Failed to add multi cluster, error: %s", err) + } + + return nil +} + +func (c *Client) ListMultiCluster() ([]*cluster, error) { + url := "/cluster/clusters" + + clusters := make([]*cluster, 0) + _, err := c.Get(url, httpclient.SetResult(clusters)) + if err != nil { + return nil, fmt.Errorf("Failed to list multi cluster, error: %s", err) + } + + return clusters, nil +} -- Gitee From 48868cc784c0c96014ce6c927bc3a32deb7ae5f5 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Wed, 1 Dec 2021 17:19:38 +0800 Subject: [PATCH 016/134] add cluster init Signed-off-by: liu deyi --- pkg/shared/client/aslan/multicluster.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/shared/client/aslan/multicluster.go b/pkg/shared/client/aslan/multicluster.go index e74e9606b..532a6b431 100644 --- a/pkg/shared/client/aslan/multicluster.go +++ b/pkg/shared/client/aslan/multicluster.go @@ -33,7 +33,7 @@ func (c *Client) ListMultiCluster() ([]*cluster, error) { url := "/cluster/clusters" clusters := make([]*cluster, 0) - _, err := c.Get(url, httpclient.SetResult(clusters)) + _, err := c.Get(url, httpclient.SetResult(&clusters)) if err != nil { return nil, fmt.Errorf("Failed to list multi cluster, error: %s", err) } -- Gitee From 8112c9c0d3fbd4f5c6b6e2f0c86d9795e2c4fab1 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Wed, 1 Dec 2021 17:28:07 +0800 Subject: [PATCH 017/134] modify local cluster status Signed-off-by: liu deyi --- pkg/shared/client/aslan/multicluster.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pkg/shared/client/aslan/multicluster.go b/pkg/shared/client/aslan/multicluster.go index 532a6b431..ba09c491f 100644 --- a/pkg/shared/client/aslan/multicluster.go +++ b/pkg/shared/client/aslan/multicluster.go @@ -4,21 +4,24 @@ import ( "fmt" "time" + "github.com/koderover/zadig/pkg/setting" + "github.com/koderover/zadig/pkg/tool/httpclient" ) type cluster struct { - Name string `json:"name"` - Production bool `json:"production"` - Local bool `json:"local"` + Name string `json:"name"` + Status setting.K8SClusterStatus `json:"status"` + Local bool `json:"local"` } func (c *Client) AddMultiCluster() error { timeStamp := time.Now().Format("20060102150405") url := "/cluster/clusters" req := cluster{ - Name: fmt.Sprintf("%s-%s", "local", timeStamp), - Local: true, + Name: fmt.Sprintf("%s-%s", "local", timeStamp), + Local: true, + Status: setting.Normal, } _, err := c.Post(url, httpclient.SetBody(req)) -- Gitee From 93f06ead02f5d938b36e4c19747bd8a923c4ac29 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Wed, 1 Dec 2021 17:45:59 +0800 Subject: [PATCH 018/134] add to determine if clusterid is a local cluster Signed-off-by: liu deyi --- .../aslan/core/common/service/kube/service.go | 4 +++- .../aslan/core/environment/service/kube.go | 22 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/pkg/microservice/aslan/core/common/service/kube/service.go b/pkg/microservice/aslan/core/common/service/kube/service.go index 8919f145b..e13a813a9 100644 --- a/pkg/microservice/aslan/core/common/service/kube/service.go +++ b/pkg/microservice/aslan/core/common/service/kube/service.go @@ -101,7 +101,9 @@ func (s *Service) CreateCluster(cluster *models.K8SCluster, logger *zap.SugaredL return nil, e.ErrCreateCluster.AddDesc(e.DuplicateClusterNameFound) } - cluster.Status = setting.Pending + if cluster.Status == "" { + cluster.Status = setting.Pending + } err = s.coll.Create(cluster) diff --git a/pkg/microservice/aslan/core/environment/service/kube.go b/pkg/microservice/aslan/core/environment/service/kube.go index c64c4feac..74484533b 100644 --- a/pkg/microservice/aslan/core/environment/service/kube.go +++ b/pkg/microservice/aslan/core/environment/service/kube.go @@ -113,6 +113,10 @@ func ListPodEvents(envName, productName, podName string, log *zap.SugaredLogger) // ListAvailableNamespaces lists available namespaces created by non-koderover func ListAvailableNamespaces(clusterID string, log *zap.SugaredLogger) ([]*resource.Namespace, error) { resp := make([]*resource.Namespace, 0) + isLocalCluster := isLocalCluster(clusterID, log) + if isLocalCluster { + clusterID = "" + } kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), clusterID) if err != nil { log.Errorf("ListNamespaces clusterID:%s err:%v", clusterID, err) @@ -230,6 +234,10 @@ func getModifiedServiceFromObjectMeta(om metav1.Object) *serviceInfo { func ListAvailableNodes(clusterID string, log *zap.SugaredLogger) (*resource.NodeResp, error) { resp := new(resource.NodeResp) + isLocalCluster := isLocalCluster(clusterID, log) + if isLocalCluster { + clusterID = "" + } kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), clusterID) if err != nil { log.Errorf("ListAvailableNodes clusterID:%s err:%s", clusterID, err) @@ -280,3 +288,17 @@ func nodeLabel(node *corev1.Node) []string { } return labels } + +func isLocalCluster(clusterID string, log *zap.SugaredLogger) bool { + clusters, err := commonrepo.NewK8SClusterColl().List(nil) + if err != nil { + log.Errorf("list k8s cluster err:%s", err) + return false + } + for _, cluster := range clusters { + if clusterID == cluster.ID.Hex() && cluster.Local { + return true + } + } + return false +} -- Gitee From 16119ee63978c876a39d3acbeaab49500a81dec9 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Wed, 1 Dec 2021 18:06:25 +0800 Subject: [PATCH 019/134] modify cluster status Signed-off-by: liu deyi --- pkg/microservice/hubserver/core/repository/models/models.go | 1 + pkg/microservice/hubserver/core/service/service.go | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/microservice/hubserver/core/repository/models/models.go b/pkg/microservice/hubserver/core/repository/models/models.go index 4bfefe013..04c47b98c 100644 --- a/pkg/microservice/hubserver/core/repository/models/models.go +++ b/pkg/microservice/hubserver/core/repository/models/models.go @@ -44,6 +44,7 @@ type K8SCluster struct { CreatedBy string `json:"createdBy" bson:"createdBy"` Disconnected bool `json:"-" bson:"disconnected"` Token string `json:"token" bson:"-"` + Local bool `json:"local" bson:"local"` } func (K8SCluster) TableName() string { diff --git a/pkg/microservice/hubserver/core/service/service.go b/pkg/microservice/hubserver/core/service/service.go index 2acae6b2e..9b84f2bc2 100644 --- a/pkg/microservice/hubserver/core/service/service.go +++ b/pkg/microservice/hubserver/core/service/service.go @@ -235,7 +235,7 @@ func Reset() { } for _, cluster := range clusters { - if cluster.Status == config.Normal { + if cluster.Status == config.Normal && !cluster.Local { cluster.Status = config.Abnormal err := mongodb.NewK8sClusterColl().UpdateStatus(cluster) if err != nil { @@ -271,7 +271,7 @@ func Sync(server *remotedialer.Server, stopCh <-chan struct{}) { statusChanged = true } } else { - if cluster.Status == config.Normal { + if cluster.Status == config.Normal && !cluster.Local { log.Infof( "cluster %s disconnected changed %s => %s", cluster.Name, cluster.Status, config.Abnormal, -- Gitee From c7a5012fcc6a615a0d7e0d7494dfdc32b7aa58e8 Mon Sep 17 00:00:00 2001 From: panxunying Date: Thu, 2 Dec 2021 10:19:16 +0800 Subject: [PATCH 020/134] update create product with new registry Signed-off-by: panxunying --- .../core/common/repository/models/product.go | 1 + .../aslan/core/common/service/registry.go | 18 ++++++++++++------ .../core/environment/service/environment.go | 11 ++++++----- .../aslan/core/system/service/registry.go | 4 ++-- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/pkg/microservice/aslan/core/common/repository/models/product.go b/pkg/microservice/aslan/core/common/repository/models/product.go index 5bfa65c97..2b290d888 100644 --- a/pkg/microservice/aslan/core/common/repository/models/product.go +++ b/pkg/microservice/aslan/core/common/repository/models/product.go @@ -50,6 +50,7 @@ type Product struct { RecycleDay int `bson:"recycle_day" json:"recycle_day"` Source string `bson:"source" json:"source"` IsOpenSource bool `bson:"is_opensource" json:"is_opensource"` + RegistryId string `bson:"registry_id" json:"registry_id"` // TODO: temp flag IsForkedProduct bool `bson:"-" json:"-"` } diff --git a/pkg/microservice/aslan/core/common/service/registry.go b/pkg/microservice/aslan/core/common/service/registry.go index ecf5a1c37..74ca6fc6a 100644 --- a/pkg/microservice/aslan/core/common/service/registry.go +++ b/pkg/microservice/aslan/core/common/service/registry.go @@ -30,11 +30,13 @@ import ( "github.com/koderover/zadig/pkg/util" ) -func FindDefaultRegistry(log *zap.SugaredLogger) (*models.RegistryNamespace, error) { +func FindRegistryById(registryId string, log *zap.SugaredLogger) (*models.RegistryNamespace, error) { + return FindRegisty(&mongodb.FindRegOps{ID: registryId}, log) +} + +func FindRegisty(regOps *mongodb.FindRegOps, log *zap.SugaredLogger) (*models.RegistryNamespace, error) { // TODO: 多租户适配 - resp, err := mongodb.NewRegistryNamespaceColl().Find(&mongodb.FindRegOps{ - IsDefault: true, - }) + resp, err := mongodb.NewRegistryNamespaceColl().Find(regOps) if err != nil { log.Warnf("RegistryNamespace.Find error: %v", err) @@ -58,6 +60,10 @@ func FindDefaultRegistry(log *zap.SugaredLogger) (*models.RegistryNamespace, err return resp, nil } +func FindDefaultRegistry(log *zap.SugaredLogger) (*models.RegistryNamespace, error) { + return FindRegisty(&mongodb.FindRegOps{IsDefault: true}, log) +} + func GetDefaultRegistryNamespace(log *zap.SugaredLogger) (*models.RegistryNamespace, error) { resp, err := mongodb.NewRegistryNamespaceColl().Find(&mongodb.FindRegOps{IsDefault: true}) if err != nil { @@ -76,8 +82,8 @@ func ListRegistryNamespaces(log *zap.SugaredLogger) ([]*models.RegistryNamespace return resp, nil } -func EnsureDefaultRegistrySecret(namespace string, kubeClient client.Client, log *zap.SugaredLogger) error { - reg, err := FindDefaultRegistry(log) +func EnsureDefaultRegistrySecret(namespace string, registryId string, kubeClient client.Client, log *zap.SugaredLogger) error { + reg, err := FindRegistryById(registryId, log) if err != nil { log.Errorf( "service.EnsureRegistrySecret: failed to find default candidate registry: %s %v", diff --git a/pkg/microservice/aslan/core/environment/service/environment.go b/pkg/microservice/aslan/core/environment/service/environment.go index 71e03bfd2..935967233 100644 --- a/pkg/microservice/aslan/core/environment/service/environment.go +++ b/pkg/microservice/aslan/core/environment/service/environment.go @@ -547,7 +547,7 @@ func UpdateProductV2(envName, productName, user, requestID string, force bool, k } } - err = ensureKubeEnv(exitedProd.Namespace, kubeClient, log) + err = ensureKubeEnv(exitedProd.Namespace, exitedProd.RegistryId, kubeClient, log) if err != nil { log.Errorf("[%s][P:%s] service.UpdateProductV2 create kubeEnv error: %v", envName, productName, err) @@ -1844,7 +1844,8 @@ func waitResourceRunning( }) } -func preCreateProduct(envName string, args *commonmodels.Product, kubeClient client.Client, log *zap.SugaredLogger) error { +func preCreateProduct(envName string, args *commonmodels.Product, kubeClient client.Client, + log *zap.SugaredLogger) error { var ( productTemplateName = args.ProductName renderSetName = commonservice.GetProductEnvNamespace(envName, args.ProductName, args.Namespace) @@ -1925,7 +1926,7 @@ func preCreateProduct(envName string, args *commonmodels.Product, kubeClient cli args.Render = tmpRenderInfo if preCreateNSAndSecret(productTmpl.ProductFeature) { - return ensureKubeEnv(args.Namespace, kubeClient, log) + return ensureKubeEnv(args.Namespace, args.ID.String(), kubeClient, log) } return nil } @@ -2037,7 +2038,7 @@ func applySystemImagePullSecrets(podSpec *corev1.PodSpec) { }) } -func ensureKubeEnv(namespace string, kubeClient client.Client, log *zap.SugaredLogger) error { +func ensureKubeEnv(namespace string, registryId string, kubeClient client.Client, log *zap.SugaredLogger) error { err := kube.CreateNamespace(namespace, kubeClient) if err != nil { log.Errorf("[%s] get or create namespace error: %v", namespace, err) @@ -2045,7 +2046,7 @@ func ensureKubeEnv(namespace string, kubeClient client.Client, log *zap.SugaredL } // 创建默认的镜像仓库secret - if err := commonservice.EnsureDefaultRegistrySecret(namespace, kubeClient, log); err != nil { + if err := commonservice.EnsureDefaultRegistrySecret(namespace, registryId, kubeClient, log); err != nil { log.Errorf("[%s] get or create namespace error: %v", namespace, err) return e.ErrCreateSecret.AddDesc(e.CreateDefaultRegistryErrMsg) } diff --git a/pkg/microservice/aslan/core/system/service/registry.go b/pkg/microservice/aslan/core/system/service/registry.go index 0aa8288ee..794e4710b 100644 --- a/pkg/microservice/aslan/core/system/service/registry.go +++ b/pkg/microservice/aslan/core/system/service/registry.go @@ -91,7 +91,7 @@ func CreateRegistryNamespace(username string, args *commonmodels.RegistryNamespa log.Errorf("[updateRegistry] Failed to get kubecli for namespace: %s", prod.Namespace) return } - err = commonservice.EnsureDefaultRegistrySecret(prod.Namespace, kubeClient, log) + err = commonservice.EnsureDefaultRegistrySecret(prod.Namespace, args.ID.String(), kubeClient, log) if err != nil { log.Errorf("[updateRegistry] Failed to update registry secret for namespace: %s, the error is: %+v", prod.Namespace, err) } @@ -166,7 +166,7 @@ func UpdateRegistryNamespace(username, id string, args *commonmodels.RegistryNam log.Errorf("[updateRegistry] Failed to get kubecli for namespace: %s", prod.Namespace) return } - err = commonservice.EnsureDefaultRegistrySecret(prod.Namespace, kubeClient, log) + err = commonservice.EnsureDefaultRegistrySecret(prod.Namespace, id, kubeClient, log) if err != nil { log.Errorf("[updateRegistry] Failed to update registry secret for namespace: %s, the error is: %+v", prod.Namespace, err) } -- Gitee From e308d97ff4a4564171d757c45ae618f4152774de Mon Sep 17 00:00:00 2001 From: liu deyi Date: Thu, 2 Dec 2021 11:07:18 +0800 Subject: [PATCH 021/134] optimize k8s schedule Signed-off-by: liu deyi --- .../core/environment/handler/environment.go | 8 ---- .../aslan/core/environment/handler/kube.go | 3 -- .../aslan/core/multicluster/service/bundle.go | 10 +---- .../aslan/core/service/handler/service.go | 3 -- .../warpdrive/core/service/taskplugin/job.go | 41 ++++++++++++++++--- pkg/setting/consts.go | 5 --- 6 files changed, 36 insertions(+), 34 deletions(-) diff --git a/pkg/microservice/aslan/core/environment/handler/environment.go b/pkg/microservice/aslan/core/environment/handler/environment.go index ad200efda..09efcf4de 100644 --- a/pkg/microservice/aslan/core/environment/handler/environment.go +++ b/pkg/microservice/aslan/core/environment/handler/environment.go @@ -205,10 +205,6 @@ func CreateProduct(c *gin.Context) { } args.UpdateBy = ctx.UserName - // don't save the local cluster id to db - if args.ClusterID == setting.LocalClusterID { - args.ClusterID = "" - } ctx.Err = service.CreateProduct( ctx.UserName, ctx.RequestID, args, ctx.Logger, ) @@ -488,10 +484,6 @@ func ListWorkloads(c *gin.Context) { return } - if args.ClusterID == setting.LocalClusterID { - args.ClusterID = "" - } - count, services, err := commonservice.ListWorkloads("", args.ClusterID, args.Namespace, "", args.PerPage, args.Page, ctx.Logger, func(workloads []*commonservice.Workload) []*commonservice.Workload { workloadStat, _ := mongodb.NewWorkLoadsStatColl().Find(args.ClusterID, args.Namespace) workloadM := map[string]commonmodels.Workload{} diff --git a/pkg/microservice/aslan/core/environment/handler/kube.go b/pkg/microservice/aslan/core/environment/handler/kube.go index 78a3e5dbd..869fae796 100644 --- a/pkg/microservice/aslan/core/environment/handler/kube.go +++ b/pkg/microservice/aslan/core/environment/handler/kube.go @@ -55,9 +55,6 @@ func ListAvailableNamespaces(c *gin.Context) { defer func() { internalhandler.JSONResponse(c, ctx) }() clusterID := c.Query("clusterId") - if clusterID == setting.LocalClusterID { - clusterID = "" - } ctx.Resp, ctx.Err = service.ListAvailableNamespaces(clusterID, ctx.Logger) } diff --git a/pkg/microservice/aslan/core/multicluster/service/bundle.go b/pkg/microservice/aslan/core/multicluster/service/bundle.go index 6a5d2084a..5eb49f164 100644 --- a/pkg/microservice/aslan/core/multicluster/service/bundle.go +++ b/pkg/microservice/aslan/core/multicluster/service/bundle.go @@ -20,7 +20,6 @@ import ( "strconv" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" - "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/tool/log" ) @@ -37,14 +36,7 @@ func GetBundleResources() ([]*resourceSpec, error) { return nil, err } - res := []*resourceSpec{ - { - ResourceID: setting.LocalClusterID, - Spec: map[string]interface{}{ - "production": "false", - }, - }, - } + var res []*resourceSpec for _, cluster := range clusters { res = append(res, &resourceSpec{ ResourceID: cluster.ID.Hex(), diff --git a/pkg/microservice/aslan/core/service/handler/service.go b/pkg/microservice/aslan/core/service/handler/service.go index bfa9de83f..495551d74 100644 --- a/pkg/microservice/aslan/core/service/handler/service.go +++ b/pkg/microservice/aslan/core/service/handler/service.go @@ -191,9 +191,6 @@ func CreateK8sWorkloads(c *gin.Context) { return } - if args.ClusterID == setting.LocalClusterID { - args.ClusterID = "" - } ctx.Err = svcservice.CreateK8sWorkLoads(c, ctx.RequestID, ctx.UserName, args.ProductName, args.WorkLoads, args.ClusterID, args.Namespace, args.EnvName, ctx.Logger) } diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/job.go b/pkg/microservice/warpdrive/core/service/taskplugin/job.go index 3fa456e98..7f25dfa97 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/job.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/job.go @@ -489,6 +489,10 @@ func buildJobWithLinkedNs(taskType config.TaskType, jobImage, jobName, serviceNa job.Spec.Template.Spec.Containers[0].Args = []string{reaperBootingScript} } + if affinity := addNodeAffinity(clusterID, pipelineTask.ConfigPayload.K8SClusters); affinity != nil { + job.Spec.Template.Spec.Affinity = affinity + } + if linkedNs != "" && execNs != "" && pipelineTask.ConfigPayload.CustomDNSSupported { job.Spec.Template.Spec.DNSConfig = &corev1.PodDNSConfig{ Searches: []string{ @@ -818,13 +822,12 @@ func addNodeAffinity(clusterID string, K8SClusters []*task.K8SCluster) *corev1.A return nil } - switch clusterConfig.Strategy { - case NormalSchedule: + if len(clusterConfig.NodeLabels) == 0 { return nil + } + + switch clusterConfig.Strategy { case RequiredSchedule: - if len(clusterConfig.NodeLabels) == 0 { - return nil - } nodeSelectorTerms := make([]corev1.NodeSelectorTerm, 0) for _, nodeLabel := range clusterConfig.NodeLabels { if !strings.Contains(nodeLabel, ":") || len(strings.Split(nodeLabel, ":")) != 2 { @@ -849,9 +852,35 @@ func addNodeAffinity(clusterID string, K8SClusters []*task.K8SCluster) *corev1.A } return affinity case PreferredSchedule: + preferredScheduleTerms := make([]corev1.PreferredSchedulingTerm, 0) + for _, nodeLabel := range clusterConfig.NodeLabels { + if !strings.Contains(nodeLabel, ":") || len(strings.Split(nodeLabel, ":")) != 2 { + continue + } + matchExpressions := make([]corev1.NodeSelectorRequirement, 0) + matchExpressions = append(matchExpressions, corev1.NodeSelectorRequirement{ + Key: strings.Split(nodeLabel, ":")[0], + Operator: "in", + Values: []string{strings.Split(nodeLabel, ":")[1]}, + }) + nodeSelectorTerm := corev1.NodeSelectorTerm{ + MatchExpressions: matchExpressions, + } + preferredScheduleTerms = append(preferredScheduleTerms, corev1.PreferredSchedulingTerm{ + Weight: 10, + Preference: nodeSelectorTerm, + }) + } + affinity := &corev1.Affinity{ + NodeAffinity: &corev1.NodeAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: preferredScheduleTerms, + }, + } + return affinity + default: + return nil } - return nil } func findClusterConfig(clusterID string, K8SClusters []*task.K8SCluster) *task.ClusterConfig { diff --git a/pkg/setting/consts.go b/pkg/setting/consts.go index 582fbe972..d49f52a3f 100644 --- a/pkg/setting/consts.go +++ b/pkg/setting/consts.go @@ -551,11 +551,6 @@ const ( ResourcesHeader = "Resources" ) -const ( - LocalClusterID = "local" // special(fake) id of the local cluster - LocalClusterName = "local" // special(fake) name of the local cluster -) - type K8SClusterStatus string const ( -- Gitee From 34f97a7e928e2e38e01a4136e1ceac180bb784a0 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Thu, 2 Dec 2021 14:07:10 +0800 Subject: [PATCH 022/134] modify cluster init Signed-off-by: liu deyi --- .../aslan/core/multicluster/service/clusters.go | 1 - pkg/setting/consts.go | 2 ++ pkg/shared/client/aslan/multicluster.go | 9 ++++++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/pkg/microservice/aslan/core/multicluster/service/clusters.go b/pkg/microservice/aslan/core/multicluster/service/clusters.go index 49386dd42..335eed3bd 100644 --- a/pkg/microservice/aslan/core/multicluster/service/clusters.go +++ b/pkg/microservice/aslan/core/multicluster/service/clusters.go @@ -46,7 +46,6 @@ type K8SCluster struct { func ListClusters(ids []string, logger *zap.SugaredLogger) ([]*K8SCluster, error) { idSet := sets.NewString(ids...) - idSet = idSet.Delete(setting.LocalClusterID) cs, err := commonrepo.NewK8SClusterColl().List(&commonrepo.ClusterListOpts{IDs: idSet.UnsortedList()}) if err != nil { logger.Errorf("Failed to list clusters, err: %s", err) diff --git a/pkg/setting/consts.go b/pkg/setting/consts.go index d49f52a3f..707822cca 100644 --- a/pkg/setting/consts.go +++ b/pkg/setting/consts.go @@ -559,3 +559,5 @@ const ( Normal K8SClusterStatus = "normal" Abnormal K8SClusterStatus = "abnormal" ) + +const LocalClusterID = "0123456789ABCDEF12345678" diff --git a/pkg/shared/client/aslan/multicluster.go b/pkg/shared/client/aslan/multicluster.go index ba09c491f..5db4d02f1 100644 --- a/pkg/shared/client/aslan/multicluster.go +++ b/pkg/shared/client/aslan/multicluster.go @@ -4,22 +4,25 @@ import ( "fmt" "time" - "github.com/koderover/zadig/pkg/setting" + "go.mongodb.org/mongo-driver/bson/primitive" + "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/tool/httpclient" ) type cluster struct { + ID primitive.ObjectID `json:"id,omitempty"` Name string `json:"name"` Status setting.K8SClusterStatus `json:"status"` Local bool `json:"local"` } func (c *Client) AddMultiCluster() error { - timeStamp := time.Now().Format("20060102150405") + oid, _ := primitive.ObjectIDFromHex(setting.LocalClusterID) url := "/cluster/clusters" req := cluster{ - Name: fmt.Sprintf("%s-%s", "local", timeStamp), + ID: oid, + Name: fmt.Sprintf("%s-%s", "local", time.Now().Format("20060102150405")), Local: true, Status: setting.Normal, } -- Gitee From 5a35014417267f3bbbfb39163539f56965c7e12c Mon Sep 17 00:00:00 2001 From: liu deyi Date: Thu, 2 Dec 2021 14:56:25 +0800 Subject: [PATCH 023/134] optimize local cluster Signed-off-by: liu deyi --- .../aslan/core/environment/service/kube.go | 22 ------------------- pkg/tool/kube/multicluster/service.go | 3 ++- 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/pkg/microservice/aslan/core/environment/service/kube.go b/pkg/microservice/aslan/core/environment/service/kube.go index 74484533b..c64c4feac 100644 --- a/pkg/microservice/aslan/core/environment/service/kube.go +++ b/pkg/microservice/aslan/core/environment/service/kube.go @@ -113,10 +113,6 @@ func ListPodEvents(envName, productName, podName string, log *zap.SugaredLogger) // ListAvailableNamespaces lists available namespaces created by non-koderover func ListAvailableNamespaces(clusterID string, log *zap.SugaredLogger) ([]*resource.Namespace, error) { resp := make([]*resource.Namespace, 0) - isLocalCluster := isLocalCluster(clusterID, log) - if isLocalCluster { - clusterID = "" - } kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), clusterID) if err != nil { log.Errorf("ListNamespaces clusterID:%s err:%v", clusterID, err) @@ -234,10 +230,6 @@ func getModifiedServiceFromObjectMeta(om metav1.Object) *serviceInfo { func ListAvailableNodes(clusterID string, log *zap.SugaredLogger) (*resource.NodeResp, error) { resp := new(resource.NodeResp) - isLocalCluster := isLocalCluster(clusterID, log) - if isLocalCluster { - clusterID = "" - } kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), clusterID) if err != nil { log.Errorf("ListAvailableNodes clusterID:%s err:%s", clusterID, err) @@ -288,17 +280,3 @@ func nodeLabel(node *corev1.Node) []string { } return labels } - -func isLocalCluster(clusterID string, log *zap.SugaredLogger) bool { - clusters, err := commonrepo.NewK8SClusterColl().List(nil) - if err != nil { - log.Errorf("list k8s cluster err:%s", err) - return false - } - for _, cluster := range clusters { - if clusterID == cluster.ID.Hex() && cluster.Local { - return true - } - } - return false -} diff --git a/pkg/tool/kube/multicluster/service.go b/pkg/tool/kube/multicluster/service.go index 067c8740f..3e0ad316f 100644 --- a/pkg/tool/kube/multicluster/service.go +++ b/pkg/tool/kube/multicluster/service.go @@ -28,11 +28,12 @@ import ( "k8s.io/client-go/tools/clientcmd/api" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/koderover/zadig/pkg/setting" krkubeclient "github.com/koderover/zadig/pkg/tool/kube/client" ) func GetKubeClient(hubServerAddr, clusterID string) (client.Client, error) { - if clusterID == "" { + if clusterID == "" || clusterID == setting.LocalClusterID { return krkubeclient.Client(), nil } -- Gitee From 49a217c28e19c6829cd1bcc42064d51e6d15eb70 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Thu, 2 Dec 2021 15:21:12 +0800 Subject: [PATCH 024/134] env add local field Signed-off-by: liu deyi --- pkg/microservice/aslan/core/environment/service/environment.go | 1 + pkg/microservice/aslan/core/environment/service/product.go | 1 + 2 files changed, 2 insertions(+) diff --git a/pkg/microservice/aslan/core/environment/service/environment.go b/pkg/microservice/aslan/core/environment/service/environment.go index 37250bd87..f9e9fc330 100644 --- a/pkg/microservice/aslan/core/environment/service/environment.go +++ b/pkg/microservice/aslan/core/environment/service/environment.go @@ -115,6 +115,7 @@ type ProductResp struct { ClusterName string `json:"cluster_name,omitempty"` RecycleDay int `json:"recycle_day"` IsProd bool `json:"is_prod"` + IsLocal bool `json:"is_local"` Source string `json:"source"` } diff --git a/pkg/microservice/aslan/core/environment/service/product.go b/pkg/microservice/aslan/core/environment/service/product.go index 88d38802c..e1c19f180 100644 --- a/pkg/microservice/aslan/core/environment/service/product.go +++ b/pkg/microservice/aslan/core/environment/service/product.go @@ -207,6 +207,7 @@ func buildProductResp(envName string, prod *commonmodels.Product, log *zap.Sugar } prodResp.IsProd = cluster.Production prodResp.ClusterName = cluster.Name + prodResp.IsLocal = cluster.Local if !clusterService.ClusterConnected(prod.ClusterID) { prodResp.Status = setting.ClusterDisconnected -- Gitee From f288b0beb517428a61128269a4de76df55f13c5b Mon Sep 17 00:00:00 2001 From: liu deyi Date: Thu, 2 Dec 2021 15:25:47 +0800 Subject: [PATCH 025/134] modify filed Signed-off-by: liu deyi --- .../core/service/types/task/config_payload.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go index d42d25ea4..6339fb94e 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go +++ b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go @@ -19,7 +19,8 @@ package task import ( "fmt" - "github.com/koderover/zadig/pkg/microservice/aslan/config" + "github.com/koderover/zadig/pkg/setting" + "go.mongodb.org/mongo-driver/bson/primitive" ) @@ -154,12 +155,12 @@ type PrivateKey struct { } type K8SCluster struct { - ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` - Name string `json:"name" bson:"name"` - Status config.K8SClusterStatus `json:"status" bson:"status"` - ClusterConfig *ClusterConfig `json:"config,omitempty" bson:"config,omitempty"` - Production bool `json:"production" bson:"production"` - Disconnected bool `json:"-" bson:"disconnected"` + ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` + Name string `json:"name" bson:"name"` + Status setting.K8SClusterStatus `json:"status" bson:"status"` + ClusterConfig *ClusterConfig `json:"config,omitempty" bson:"config,omitempty"` + Production bool `json:"production" bson:"production"` + Disconnected bool `json:"-" bson:"disconnected"` } type ClusterConfig struct { -- Gitee From 23d12508c36ca21819b394fd543c2c0d84f518ff Mon Sep 17 00:00:00 2001 From: liu deyi Date: Thu, 2 Dec 2021 15:37:27 +0800 Subject: [PATCH 026/134] modify const Signed-off-by: liu deyi --- pkg/setting/consts.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/setting/consts.go b/pkg/setting/consts.go index 707822cca..02085f398 100644 --- a/pkg/setting/consts.go +++ b/pkg/setting/consts.go @@ -560,4 +560,4 @@ const ( Abnormal K8SClusterStatus = "abnormal" ) -const LocalClusterID = "0123456789ABCDEF12345678" +const LocalClusterID = "0123456789abcdef12345678" -- Gitee From bef79054bfa04b0b933dc35cf7de15c757bb396e Mon Sep 17 00:00:00 2001 From: liu deyi Date: Thu, 2 Dec 2021 16:13:38 +0800 Subject: [PATCH 027/134] do not clean up the job temporarily, it is convenient for testing Signed-off-by: liu deyi --- .../warpdrive/core/service/taskplugin/build.go | 17 ++++++++++------- .../core/service/taskplugin/testing.go | 16 +++++++++------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/build.go b/pkg/microservice/warpdrive/core/service/taskplugin/build.go index 581d18356..039ecc9b9 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/build.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/build.go @@ -328,15 +328,18 @@ func (p *BuildTaskPlugin) Complete(ctx context.Context, pipelineTask *task.Task, // 清理用户取消和超时的任务 defer func() { - if err := ensureDeleteJob(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { - p.Log.Error(err) - p.Task.Error = err.Error() - } + if p.Task.TaskStatus == config.StatusCancelled || p.Task.TaskStatus == config.StatusTimeout { + if err := ensureDeleteJob(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + p.Log.Error(err) + p.Task.Error = err.Error() + } - if err := ensureDeleteConfigMap(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { - p.Log.Error(err) - p.Task.Error = err.Error() + if err := ensureDeleteConfigMap(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + p.Log.Error(err) + p.Task.Error = err.Error() + } } + return }() diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go index 4703b559a..88efe4513 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go @@ -257,13 +257,15 @@ func (p *TestPlugin) Complete(ctx context.Context, pipelineTask *task.Task, serv // 日志保存失败与否都清理job defer func() { - if err := ensureDeleteJob(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { - p.Log.Error(err) - p.Task.Error = err.Error() - } - if err := ensureDeleteConfigMap(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { - p.Log.Error(err) - p.Task.Error = err.Error() + if p.Task.TaskStatus == config.StatusCancelled || p.Task.TaskStatus == config.StatusTimeout { + if err := ensureDeleteJob(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + p.Log.Error(err) + p.Task.Error = err.Error() + } + if err := ensureDeleteConfigMap(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + p.Log.Error(err) + p.Task.Error = err.Error() + } } return }() -- Gitee From abe7432f34c1f082e85866a2a85430e90f22e445 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Thu, 2 Dec 2021 16:22:31 +0800 Subject: [PATCH 028/134] store cluster config Signed-off-by: liu deyi --- .../aslan/core/common/repository/mongodb/k8s_cluster.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/k8s_cluster.go b/pkg/microservice/aslan/core/common/repository/mongodb/k8s_cluster.go index f49abb0cd..8daf229f3 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/k8s_cluster.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/k8s_cluster.go @@ -185,6 +185,7 @@ func (c *K8SClusterColl) UpdateMutableFields(cluster *models.K8SCluster) error { "tags": cluster.Tags, "namespace": cluster.Namespace, "production": cluster.Production, + "config": cluster.ClusterConfig, }}, ) -- Gitee From 950468ddbca4a8895ab57823e7288447a1cb36e6 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Thu, 2 Dec 2021 16:42:31 +0800 Subject: [PATCH 029/134] optimize code Signed-off-by: liu deyi --- .../core/multicluster/service/clusters.go | 38 ++++++++++--------- .../warpdrive/core/service/taskplugin/job.go | 4 +- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/pkg/microservice/aslan/core/multicluster/service/clusters.go b/pkg/microservice/aslan/core/multicluster/service/clusters.go index 335eed3bd..8508224ce 100644 --- a/pkg/microservice/aslan/core/multicluster/service/clusters.go +++ b/pkg/microservice/aslan/core/multicluster/service/clusters.go @@ -33,15 +33,16 @@ import ( ) type K8SCluster struct { - ID string `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - Status setting.K8SClusterStatus `json:"status"` - Production bool `json:"production"` - CreatedAt int64 `json:"createdAt"` - CreatedBy string `json:"createdBy"` - Provider int8 `json:"provider"` - Local bool `json:"local"` + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Status setting.K8SClusterStatus `json:"status"` + Production bool `json:"production"` + CreatedAt int64 `json:"createdAt"` + CreatedBy string `json:"createdBy"` + Provider int8 `json:"provider"` + Local bool `json:"local"` + ClusterConfig *commonmodels.ClusterConfig `json:"config,omitempty"` } func ListClusters(ids []string, logger *zap.SugaredLogger) ([]*K8SCluster, error) { @@ -55,15 +56,16 @@ func ListClusters(ids []string, logger *zap.SugaredLogger) ([]*K8SCluster, error var res []*K8SCluster for _, c := range cs { res = append(res, &K8SCluster{ - ID: c.ID.Hex(), - Name: c.Name, - Description: c.Description, - Status: c.Status, - Production: c.Production, - CreatedBy: c.CreatedBy, - CreatedAt: c.CreatedAt, - Provider: c.Provider, - Local: c.Local, + ID: c.ID.Hex(), + Name: c.Name, + Description: c.Description, + Status: c.Status, + Production: c.Production, + CreatedBy: c.CreatedBy, + CreatedAt: c.CreatedAt, + Provider: c.Provider, + Local: c.Local, + ClusterConfig: c.ClusterConfig, }) } diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/job.go b/pkg/microservice/warpdrive/core/service/taskplugin/job.go index 7f25dfa97..b6060a9f1 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/job.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/job.go @@ -836,7 +836,7 @@ func addNodeAffinity(clusterID string, K8SClusters []*task.K8SCluster) *corev1.A matchExpressions := make([]corev1.NodeSelectorRequirement, 0) matchExpressions = append(matchExpressions, corev1.NodeSelectorRequirement{ Key: strings.Split(nodeLabel, ":")[0], - Operator: "in", + Operator: corev1.NodeSelectorOpIn, Values: []string{strings.Split(nodeLabel, ":")[1]}, }) nodeSelectorTerms = append(nodeSelectorTerms, corev1.NodeSelectorTerm{ @@ -860,7 +860,7 @@ func addNodeAffinity(clusterID string, K8SClusters []*task.K8SCluster) *corev1.A matchExpressions := make([]corev1.NodeSelectorRequirement, 0) matchExpressions = append(matchExpressions, corev1.NodeSelectorRequirement{ Key: strings.Split(nodeLabel, ":")[0], - Operator: "in", + Operator: corev1.NodeSelectorOpIn, Values: []string{strings.Split(nodeLabel, ":")[1]}, }) nodeSelectorTerm := corev1.NodeSelectorTerm{ -- Gitee From 9178d9a8a1fbc447c760b11c873c5db202bdac38 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Thu, 2 Dec 2021 20:11:45 +0800 Subject: [PATCH 030/134] optimize code Signed-off-by: liu deyi --- .../core/common/repository/models/queue.go | 1 + .../core/common/service/config_payload.go | 2 ++ .../core/service/archive/file_archive.go | 6 ++-- .../reaper/core/service/meta/types.go | 1 + .../reaper/core/service/reaper/archive.go | 6 ++-- .../reaper/core/service/reaper/artifact.go | 2 +- .../core/service/reaper/cachemanager.go | 6 ++-- .../reaper/core/service/reaper/reaper.go | 4 +-- .../reaper/core/service/reaper/script.go | 2 +- pkg/microservice/reaper/internal/s3/s3.go | 4 +-- .../warpdrive/core/service/taskplugin/job.go | 35 ++++++++++--------- .../warpdrive/core/service/types/reaper.go | 1 + .../core/service/types/task/config_payload.go | 1 + pkg/tool/crypto/aes.go | 16 +++++++-- 14 files changed, 55 insertions(+), 32 deletions(-) diff --git a/pkg/microservice/aslan/core/common/repository/models/queue.go b/pkg/microservice/aslan/core/common/repository/models/queue.go index b60f7e0f6..5edfa0b90 100644 --- a/pkg/microservice/aslan/core/common/repository/models/queue.go +++ b/pkg/microservice/aslan/core/common/repository/models/queue.go @@ -126,6 +126,7 @@ type ConfigPayload struct { CustomDNSSupported bool `json:"custom_dns_supported"` HubServerAddr string DeployClusterID string + AesKey string RepoConfigs map[string]*RegistryNamespace diff --git a/pkg/microservice/aslan/core/common/service/config_payload.go b/pkg/microservice/aslan/core/common/service/config_payload.go index 1f3ed4259..fb38f9edc 100644 --- a/pkg/microservice/aslan/core/common/service/config_payload.go +++ b/pkg/microservice/aslan/core/common/service/config_payload.go @@ -22,6 +22,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/shared/client/systemconfig" + "github.com/koderover/zadig/pkg/tool/crypto" ) func GetConfigPayload(codeHostID int) *models.ConfigPayload { @@ -64,6 +65,7 @@ func GetConfigPayload(codeHostID int) *models.ConfigPayload { JenkinsBuildConfig: models.JenkinsBuildConfig{ JenkinsBuildImage: config.JenkinsImage(), }, + AesKey: crypto.GetAesKey(), } githubApps, _ := mongodb.NewGithubAppColl().Find() diff --git a/pkg/microservice/reaper/core/service/archive/file_archive.go b/pkg/microservice/reaper/core/service/archive/file_archive.go index 96ee051c8..5857925a1 100644 --- a/pkg/microservice/reaper/core/service/archive/file_archive.go +++ b/pkg/microservice/reaper/core/service/archive/file_archive.go @@ -42,12 +42,14 @@ type WorkspaceAchiever struct { PipelineName string ServiceName string Envs []string + aesKey string } -func NewWorkspaceAchiever(storageURI, pipelineName, serviceName, wd string, caches, gitFolders, envs []string) *WorkspaceAchiever { +func NewWorkspaceAchiever(storageURI, pipelineName, serviceName, wd, aesKey string, caches, gitFolders, envs []string) *WorkspaceAchiever { return &WorkspaceAchiever{ paths: caches, wd: wd, + aesKey: aesKey, gitFolders: gitFolders, StorageURI: storageURI, PipelineName: pipelineName, @@ -224,7 +226,7 @@ func (c *WorkspaceAchiever) Achieve(target string) ([]string, error) { // return err //} - if store, err := s3.NewS3StorageFromEncryptedURI(c.StorageURI); err == nil { + if store, err := s3.NewS3StorageFromEncryptedURI(c.StorageURI, c.aesKey); err == nil { forcedPathStyle := true if store.Provider == setting.ProviderSourceAli { forcedPathStyle = false diff --git a/pkg/microservice/reaper/core/service/meta/types.go b/pkg/microservice/reaper/core/service/meta/types.go index 4a587d481..86d69329e 100644 --- a/pkg/microservice/reaper/core/service/meta/types.go +++ b/pkg/microservice/reaper/core/service/meta/types.go @@ -115,6 +115,7 @@ type Context struct { StorageBucket string `yaml:"storage_bucket"` StorageProvider int `yaml:"storage_provider"` ArtifactInfo *ArtifactInfo `yaml:"artifact_info"` + AesKey string `yaml:"aes_key"` } type ArtifactInfo struct { diff --git a/pkg/microservice/reaper/core/service/reaper/archive.go b/pkg/microservice/reaper/core/service/reaper/archive.go index b729ce665..c2c136bff 100644 --- a/pkg/microservice/reaper/core/service/reaper/archive.go +++ b/pkg/microservice/reaper/core/service/reaper/archive.go @@ -34,7 +34,7 @@ func (r *Reaper) archiveS3Files() (err error) { if r.Ctx.FileArchiveCtx != nil && r.Ctx.StorageURI != "" { var store *s3.S3 - if store, err = s3.NewS3StorageFromEncryptedURI(r.Ctx.StorageURI); err != nil { + if store, err = s3.NewS3StorageFromEncryptedURI(r.Ctx.StorageURI, r.Ctx.AesKey); err != nil { log.Errorf("failed to create s3 storage %s", r.Ctx.StorageURI) return } @@ -77,7 +77,7 @@ func (r *Reaper) archiveTestFiles() error { return nil } - store, err := s3.NewS3StorageFromEncryptedURI(r.Ctx.StorageURI) + store, err := s3.NewS3StorageFromEncryptedURI(r.Ctx.StorageURI, r.Ctx.AesKey) if err != nil { log.Errorf("failed to create s3 storage %s, err: %s", r.Ctx.StorageURI, err) return err @@ -130,7 +130,7 @@ func (r *Reaper) archiveHTMLTestReportFile() error { return nil } - store, err := s3.NewS3StorageFromEncryptedURI(r.Ctx.StorageURI) + store, err := s3.NewS3StorageFromEncryptedURI(r.Ctx.StorageURI, r.Ctx.AesKey) if err != nil { log.Errorf("failed to create s3 storage %s, err: %s", r.Ctx.StorageURI, err) return err diff --git a/pkg/microservice/reaper/core/service/reaper/artifact.go b/pkg/microservice/reaper/core/service/reaper/artifact.go index ff93b4ff8..09af436c7 100644 --- a/pkg/microservice/reaper/core/service/reaper/artifact.go +++ b/pkg/microservice/reaper/core/service/reaper/artifact.go @@ -38,7 +38,7 @@ func artifactsUpload(ctx *meta.Context, activeWorkspace string) error { ) if ctx.StorageURI != "" { - if store, err = s3.NewS3StorageFromEncryptedURI(ctx.StorageURI); err != nil { + if store, err = s3.NewS3StorageFromEncryptedURI(ctx.StorageURI, ctx.AesKey); err != nil { log.Errorf("artifactsUpload failed to create s3 storage err:%v", err) return err } diff --git a/pkg/microservice/reaper/core/service/reaper/cachemanager.go b/pkg/microservice/reaper/core/service/reaper/cachemanager.go index ae4eb5378..a4eba4d9a 100644 --- a/pkg/microservice/reaper/core/service/reaper/cachemanager.go +++ b/pkg/microservice/reaper/core/service/reaper/cachemanager.go @@ -80,13 +80,15 @@ type TarCacheManager struct { StorageURI string PipelineName string ServiceName string + aesKey string } -func NewTarCacheManager(storageURI, pipelineName, serviceName string) *TarCacheManager { +func NewTarCacheManager(storageURI, pipelineName, serviceName, aesKey string) *TarCacheManager { return &TarCacheManager{ StorageURI: storageURI, PipelineName: pipelineName, ServiceName: serviceName, + aesKey: aesKey, } } @@ -180,7 +182,7 @@ func (gcm *TarCacheManager) Unarchive(source, dest string) error { func (gcm *TarCacheManager) getS3Storage() (*s3.S3, error) { var err error var store *s3.S3 - if store, err = s3.NewS3StorageFromEncryptedURI(gcm.StorageURI); err != nil { + if store, err = s3.NewS3StorageFromEncryptedURI(gcm.StorageURI, gcm.aesKey); err != nil { log.Errorf("Archive failed to create s3 storage %s", gcm.StorageURI) return nil, err } diff --git a/pkg/microservice/reaper/core/service/reaper/reaper.go b/pkg/microservice/reaper/core/service/reaper/reaper.go index 136d0d394..d85d4a674 100644 --- a/pkg/microservice/reaper/core/service/reaper/reaper.go +++ b/pkg/microservice/reaper/core/service/reaper/reaper.go @@ -74,7 +74,7 @@ func NewReaper() (*Reaper, error) { reaper := &Reaper{ Ctx: ctx, - cm: NewTarCacheManager(ctx.StorageURI, ctx.PipelineName, ctx.ServiceName), + cm: NewTarCacheManager(ctx.StorageURI, ctx.PipelineName, ctx.ServiceName, ctx.AesKey), } return reaper, nil @@ -85,7 +85,7 @@ func (r *Reaper) GetCacheFile() string { } func (r *Reaper) archiveCustomCaches(wd, dest string, caches []string) ([]string, error) { - fileAchiever := archive.NewWorkspaceAchiever(r.Ctx.StorageURI, r.Ctx.PipelineName, r.Ctx.ServiceName, wd, caches, []string{}, r.getUserEnvs()) + fileAchiever := archive.NewWorkspaceAchiever(r.Ctx.StorageURI, r.Ctx.PipelineName, r.Ctx.ServiceName, wd, r.Ctx.AesKey, caches, []string{}, r.getUserEnvs()) // list files matches caches return fileAchiever.Achieve(dest) diff --git a/pkg/microservice/reaper/core/service/reaper/script.go b/pkg/microservice/reaper/core/service/reaper/script.go index 47cbf2409..3521273d8 100644 --- a/pkg/microservice/reaper/core/service/reaper/script.go +++ b/pkg/microservice/reaper/core/service/reaper/script.go @@ -377,7 +377,7 @@ func (r *Reaper) RunPMDeployScripts() error { func (r *Reaper) downloadArtifactFile() error { var err error var store *s3.S3 - if store, err = s3.NewS3StorageFromEncryptedURI(r.Ctx.ArtifactInfo.URL); err != nil { + if store, err = s3.NewS3StorageFromEncryptedURI(r.Ctx.ArtifactInfo.URL, r.Ctx.AesKey); err != nil { log.Errorf("Archive failed to create s3 storage %s", r.Ctx.ArtifactInfo.URL) return err } diff --git a/pkg/microservice/reaper/internal/s3/s3.go b/pkg/microservice/reaper/internal/s3/s3.go index 3c15cc4b8..ed87e9c7b 100644 --- a/pkg/microservice/reaper/internal/s3/s3.go +++ b/pkg/microservice/reaper/internal/s3/s3.go @@ -75,8 +75,8 @@ func NewS3StorageFromURL(uri string) (*S3, error) { return ret, nil } -func NewS3StorageFromEncryptedURI(encryptedURI string) (*S3, error) { - uri, err := crypto.AesDecrypt(encryptedURI) +func NewS3StorageFromEncryptedURI(encryptedURI, aesKey string) (*S3, error) { + uri, err := crypto.AesDecrypt(encryptedURI, aesKey) if err != nil { return nil, err } diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/job.go b/pkg/microservice/warpdrive/core/service/taskplugin/job.go index b6060a9f1..cdf6f4355 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/job.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/job.go @@ -211,6 +211,7 @@ func (b *JobCtxBuilder) BuildReaperContext(pipelineTask *task.Task, serviceName TaskID: pipelineTask.TaskID, ServiceName: serviceName, StorageEndpoint: pipelineTask.StorageEndpoint, + AesKey: pipelineTask.ConfigPayload.AesKey, } for _, install := range b.Installs { inst := &types.Install{ @@ -597,11 +598,11 @@ func getVolumeMounts(ctx *task.PipelineCtx) []corev1.VolumeMount { Name: "job-config", MountPath: ctx.ConfigMapMountDir, }) - resp = append(resp, corev1.VolumeMount{ - Name: "aes-key", - ReadOnly: true, - MountPath: "/etc/encryption", - }) + //resp = append(resp, corev1.VolumeMount{ + // Name: "aes-key", + // ReadOnly: true, + // MountPath: "/etc/encryption", + //}) return resp } @@ -618,18 +619,18 @@ func getVolumes(jobName string) []corev1.Volume { }, }, }) - resp = append(resp, corev1.Volume{ - Name: "aes-key", - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: "zadig-aes-key", - Items: []corev1.KeyToPath{{ - Key: "aesKey", - Path: "aes", - }}, - }, - }, - }) + //resp = append(resp, corev1.Volume{ + // Name: "aes-key", + // VolumeSource: corev1.VolumeSource{ + // Secret: &corev1.SecretVolumeSource{ + // SecretName: "zadig-aes-key", + // Items: []corev1.KeyToPath{{ + // Key: "aesKey", + // Path: "aes", + // }}, + // }, + // }, + //}) return resp } diff --git a/pkg/microservice/warpdrive/core/service/types/reaper.go b/pkg/microservice/warpdrive/core/service/types/reaper.go index 9ed4b2fdd..c3fa2fa75 100644 --- a/pkg/microservice/warpdrive/core/service/types/reaper.go +++ b/pkg/microservice/warpdrive/core/service/types/reaper.go @@ -113,6 +113,7 @@ type Context struct { StorageBucket string `yaml:"storage_bucket"` StorageProvider int8 `yaml:"storage_provider"` ArtifactInfo *ArtifactInfo `yaml:"artifact_info"` + AesKey string `yaml:"aes_key"` } type ArtifactInfo struct { diff --git a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go index 6339fb94e..313af2d79 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go +++ b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go @@ -44,6 +44,7 @@ type ConfigPayload struct { CustomDNSSupported bool `json:"custom_dns_supported"` HubServerAddr string DeployClusterID string + AesKey string RepoConfigs map[string]*RegistryNamespace diff --git a/pkg/tool/crypto/aes.go b/pkg/tool/crypto/aes.go index 65e69ce07..9889f609d 100644 --- a/pkg/tool/crypto/aes.go +++ b/pkg/tool/crypto/aes.go @@ -51,6 +51,10 @@ func getAESKey() string { return aesKey } +func GetAesKey() string { + return getAESKey() +} + func AesEncrypt(src string) (string, error) { client, err := NewAes(getAESKey()) if err != nil { @@ -63,8 +67,16 @@ func AesEncrypt(src string) (string, error) { return dest, nil } -func AesDecrypt(src string) (string, error) { - client, err := NewAes(getAESKey()) +func AesDecrypt(src string, aesKey ...string) (string, error) { + var ( + err error + client *Aes + ) + if len(aesKey) > 0 { + client, err = NewAes(aesKey[0]) + } else { + client, err = NewAes(getAESKey()) + } if err != nil { return "", err } -- Gitee From cc85b5d34c7c264891ecec10529e952c68ac52d1 Mon Sep 17 00:00:00 2001 From: allenshen Date: Thu, 2 Dec 2021 22:57:47 +0800 Subject: [PATCH 031/134] add more detail to progress data Signed-off-by: allenshen --- pkg/microservice/packager/core/service/service.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/pkg/microservice/packager/core/service/service.go b/pkg/microservice/packager/core/service/service.go index 1f85dc7e5..043ac8c6d 100644 --- a/pkg/microservice/packager/core/service/service.go +++ b/pkg/microservice/packager/core/service/service.go @@ -42,10 +42,11 @@ type Packager struct { Ctx *Context } -type ServicePackageResult struct { - ServiceName string `json:"service_name"` - Result string `json:"result"` - ErrorMsg string `json:"error_msg"` +type PackageResult struct { + ServiceName string `json:"service_name"` + Result string `json:"result"` + ErrorMsg string `json:"error_msg"` + ImageData []*ImageData `json:"image_data"` } func NewPackager() (*Packager, error) { @@ -105,7 +106,7 @@ func (p *Packager) Exec() error { return err } - realTimeProgress := make([]*ServicePackageResult, 0) + realTimeProgress := make([]*PackageResult, 0) for _, image := range p.Ctx.Images { cmds := p.dockerCommands(image) @@ -119,7 +120,7 @@ func (p *Packager) Exec() error { } } - result := &ServicePackageResult{ + result := &PackageResult{ ServiceName: image.ServiceName, } @@ -129,6 +130,7 @@ func (p *Packager) Exec() error { log.Infof("[result][fail][%s][%s]", image.ServiceName, err) } else { result.Result = "success" + result.ImageData = image.Images log.Infof("[result][success][%s]", image.ServiceName) } -- Gitee From 49699164b90d20f9574840b6e5019e47aaec72db Mon Sep 17 00:00:00 2001 From: allenshen Date: Sun, 5 Dec 2021 13:29:00 +0800 Subject: [PATCH 032/134] make build delivery version work Signed-off-by: allenshen --- .../models/task/artifact_package.go | 26 +- .../repository/mongodb/delivery_distribute.go | 7 +- .../aslan/core/delivery/service/version.go | 431 +++++++++++++----- .../handler/{helm_release.go => helm.go} | 12 +- .../aslan/core/environment/handler/router.go | 3 + .../aslan/core/workflow/handler/workflow.go | 2 +- .../service/workflow/artifact_task.go | 21 +- .../service/workflow/workflow_task.go | 2 +- .../packager/core/service/service.go | 2 + .../service/taskplugin/artifact_package.go | 2 +- .../core/service/taskplugin/deploy.go | 12 +- 11 files changed, 386 insertions(+), 134 deletions(-) rename pkg/microservice/aslan/core/environment/handler/{helm_release.go => helm.go} (80%) diff --git a/pkg/microservice/aslan/core/common/repository/models/task/artifact_package.go b/pkg/microservice/aslan/core/common/repository/models/task/artifact_package.go index 8f578b62c..0686b4615 100644 --- a/pkg/microservice/aslan/core/common/repository/models/task/artifact_package.go +++ b/pkg/microservice/aslan/core/common/repository/models/task/artifact_package.go @@ -17,12 +17,27 @@ limitations under the License. package task import ( + "encoding/json" "fmt" "github.com/koderover/zadig/pkg/microservice/aslan/config" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" ) +type ImageData struct { + ImageUrl string `bson:"image_url" json:"image_url"` + ImageName string `bson:"image_name" json:"image_name"` + ImageNamespace string `bson:"image_namespace" json:"image_namespace"` + ImageTag string `bson:"image_tag" json:"image_tag"` +} + +type ServicePackageResult struct { + ServiceName string `json:"service_name"` + Result string `json:"result"` + ErrorMsg string `json:"error_msg"` + ImageData []*ImageData `json:"image_data"` +} + type ArtifactPackage struct { TaskType config.TaskType `bson:"type" json:"type"` TaskStatus config.Status `bson:"status" json:"status"` @@ -32,7 +47,7 @@ type ArtifactPackage struct { StartTime int64 `bson:"start_time,omitempty" json:"start_time,omitempty"` EndTime int64 `bson:"end_time,omitempty" json:"end_time,omitempty"` LogFile string `bson:"log_file" json:"log_file"` - + Progress string `bson:"progress" json:"progress"` // source images Images []*models.ImagesByService `bson:"images" json:"images"` // source registries need auth to pull images @@ -48,3 +63,12 @@ func (ri *ArtifactPackage) ToSubTask() (map[string]interface{}, error) { } return task, nil } + +func (ri *ArtifactPackage) GetProgress() ([]*ServicePackageResult, error) { + if len(ri.Progress) == 0 { + return nil, nil + } + ret := make([]*ServicePackageResult, 0) + err := json.Unmarshal([]byte(ri.Progress), &ret) + return ret, err +} diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/delivery_distribute.go b/pkg/microservice/aslan/core/common/repository/mongodb/delivery_distribute.go index 21ef1dd5a..98a9c39ed 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/delivery_distribute.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/delivery_distribute.go @@ -35,6 +35,7 @@ type DeliveryDistributeArgs struct { ID string `json:"id"` ReleaseID string `json:"releaseId"` ServiceName string `json:"serviceName"` + ChartName string `json:"chartName"` DistributeType config.DistributeType `json:"distributeType"` } @@ -62,6 +63,7 @@ func (c *DeliveryDistributeColl) EnsureIndex(ctx context.Context) error { Keys: bson.D{ bson.E{Key: "release_id", Value: 1}, bson.E{Key: "service_name", Value: 1}, + bson.E{Key: "chart_name", Value: 1}, bson.E{Key: "deleted_at", Value: 1}, }, Options: options.Index().SetUnique(false), @@ -115,9 +117,12 @@ func (c *DeliveryDistributeColl) Find(args *DeliveryDistributeArgs) ([]*models.D } query := bson.M{"release_id": releaseID, "deleted_at": 0} - if args.DistributeType != "" { + if len(args.DistributeType) > 0 { query["distribute_type"] = string(args.DistributeType) } + if len(args.ChartName) > 0 { + query["chart_name"] = args.ChartName + } cursor, err := c.Collection.Find(context.TODO(), query) if err != nil { return nil, err diff --git a/pkg/microservice/aslan/core/delivery/service/version.go b/pkg/microservice/aslan/core/delivery/service/version.go index 1dcdf020c..90cd83e42 100644 --- a/pkg/microservice/aslan/core/delivery/service/version.go +++ b/pkg/microservice/aslan/core/delivery/service/version.go @@ -29,6 +29,8 @@ import ( "sync" "time" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/task" + workflowservice "github.com/koderover/zadig/pkg/microservice/aslan/core/workflow/service/workflow" cm "github.com/chartmuseum/helm-push/pkg/chartmuseum" @@ -43,7 +45,6 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "sigs.k8s.io/yaml" - configbase "github.com/koderover/zadig/pkg/config" "github.com/koderover/zadig/pkg/microservice/aslan/config" commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/template" @@ -51,7 +52,6 @@ import ( commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/base" - fsservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/fs" "github.com/koderover/zadig/pkg/setting" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/log" @@ -164,6 +164,19 @@ type DeliverySecurityStats struct { DeliverySecurityStatsInfo DeliverySecurityStatsInfo `json:"deliverySecurityStatsInfo"` } +type ImageUrlDetail struct { + ImageUrl string + Name string + Registry string + Tag string +} + +type ServiceImageDetails struct { + ServiceName string + Images []*ImageUrlDetail + Registries []string +} + func GetDeliveryVersion(args *commonrepo.DeliveryVersionArgs, log *zap.SugaredLogger) (*commonmodels.DeliveryVersion, error) { versionData, err := commonrepo.NewDeliveryVersionColl().Get(args) if err != nil { @@ -486,13 +499,12 @@ func createChartRepoClient(repo *commonmodels.HelmRepo) (*cm.Client, error) { } // pull image from currently using registry and push to specified repo -func pushImages(deliveryVersion *commonmodels.DeliveryVersion, serviceObj *commonmodels.Service, valuesMap map[string]interface{}, targetRegistry *commonmodels.RegistryNamespace, registryMap map[string]*commonmodels.RegistryNamespace) error { - - log.Infof("######## start pushing image #########") +func extractImages(deliveryVersion *commonmodels.DeliveryVersion, serviceObj *commonmodels.Service, valuesMap map[string]interface{}, + targetRegistry *commonmodels.RegistryNamespace, registryMap map[string]*commonmodels.RegistryNamespace) (*ServiceImageDetails, error) { flatMap, err := converter.Flatten(valuesMap) if err != nil { - return err + return nil, err } imagePathSpecs := make([]map[string]string, 0) @@ -507,54 +519,77 @@ func pushImages(deliveryVersion *commonmodels.DeliveryVersion, serviceObj *commo } // find full image uris from values.yaml - imageUris := make([]string, 0) + imageUrls := make([]string, 0) for _, spec := range imagePathSpecs { imageUri, err := commonservice.GeneImageURI(spec, flatMap) if err != nil { - return err + return nil, err } - imageUris = append(imageUris, imageUri) + + imageUrls = append(imageUrls, imageUri) + } + + ret := &ServiceImageDetails{ + ServiceName: serviceObj.ServiceName, + Images: make([]*ImageUrlDetail, 0), } - for _, imageUri := range imageUris { - log.Infof("##### handle single image uri %s ######", imageUri) - registryUrl, err := commonservice.ExtractImageRegistry(imageUri) + registrySet := sets.NewString() + + for _, imageUrl := range imageUrls { + + registryUrl, err := commonservice.ExtractImageRegistry(imageUrl) if err != nil { - return errors.Wrapf(err, "failed to parse registry from image uri: %s", imageUri) + return nil, errors.Wrapf(err, "failed to parse registry from image uri: %s", imageUrl) } registryUrl = strings.TrimSuffix(registryUrl, "/") - log.Infof("#### extract registry url %s ####", registryUrl) - imageName := commonservice.ExtractImageName(imageUri) - imageTag := commonservice.ExtractImageTag(imageUri) - imageNamespace := commonservice.ExtractRegistryNamespace(imageUri) - targetFullImageUri := imageUri + imageName := commonservice.ExtractImageName(imageUrl) + imageTag := commonservice.ExtractImageTag(imageUrl) + // used source registry if registry, ok := registryMap[registryUrl]; ok { - if registry.ID != targetRegistry.ID { - targetFullImageUri = fmt.Sprintf("%s/%s/%s:%s", targetRegistry.RegAddr, targetRegistry.Namespace, imageName, imageTag) - } + registrySet.Insert(registry.ID.Hex()) } - // add image distribution data - err = commonrepo.NewDeliveryDistributeColl().Insert(&commonmodels.DeliveryDistribute{ - ReleaseID: deliveryVersion.ID, - ServiceName: imageName, - ChartName: serviceObj.ServiceName, - DistributeType: config.Image, - RegistryName: targetFullImageUri, - Namespace: imageNamespace, - CreatedAt: time.Now().Unix(), + ret.Images = append(ret.Images, &ImageUrlDetail{ + ImageUrl: imageUrl, + Name: imageName, + Tag: imageTag, }) - if err != nil { - log.Errorf("failed to insert image distribute data, version: %s, image: %s, err: %s", deliveryVersion.Version, targetFullImageUri, err) - return fmt.Errorf("failed to insert image distribute data") - } } - return nil + + ret.Registries = registrySet.List() + return ret, nil + + //for _, imageUrl := range imageUrls { + // registryUrl, err := commonservice.ExtractImageRegistry(imageUrl) + // if err != nil { + // return nil, errors.Wrapf(err, "failed to parse registry from image uri: %s", imageUrl) + // } + // registryUrl = strings.TrimSuffix(registryUrl, "/") + // + // imageName := commonservice.ExtractImageName(imageUrl) + // imageTag := commonservice.ExtractImageTag(imageUrl) + // imageNamespace := commonservice.ExtractRegistryNamespace(imageUrl) + // targetFullImageUri := imageUrl + // + // if registry, ok := registryMap[registryUrl]; ok { + // if registry.ID != targetRegistry.ID { + // targetFullImageUri = fmt.Sprintf("%s/%s/%s:%s", targetRegistry.RegAddr, targetRegistry.Namespace, imageName, imageTag) + // } + // } + // + // if err != nil { + // log.Errorf("failed to insert image distribute data, version: %s, image: %s, err: %s", deliveryVersion.Version, targetFullImageUri, err) + // return nil, fmt.Errorf("failed to insert image distribute data") + // } + //} + //return nil, nil } -func handleSingleChart(deliveryVersion *commonmodels.DeliveryVersion, chartData *DeliveryChartData, chartRepo *commonmodels.HelmRepo, dir string, globalVariables string, targetRegistry *commonmodels.RegistryNamespace, registryMap map[string]*commonmodels.RegistryNamespace) error { +func handleSingleChart(deliveryVersion *commonmodels.DeliveryVersion, chartData *DeliveryChartData, chartRepo *commonmodels.HelmRepo, dir string, globalVariables string, + targetRegistry *commonmodels.RegistryNamespace, registryMap map[string]*commonmodels.RegistryNamespace) (*ServiceImageDetails, error) { serviceObj := chartData.ServiceObj serviceName, revision := serviceObj.ServiceName, serviceObj.Revision basePath := config.LocalServicePathWithRevision(serviceObj.ProductName, serviceName, revision) @@ -564,7 +599,7 @@ func handleSingleChart(deliveryVersion *commonmodels.DeliveryVersion, chartData basePath = config.LocalServicePath(serviceObj.ProductName, serviceName) if err = commonservice.PreLoadServiceManifests(basePath, serviceObj); err != nil { log.Errorf("failed to load chart info for service %v", serviceObj.ServiceName) - return err + return nil, err } } @@ -573,13 +608,13 @@ func handleSingleChart(deliveryVersion *commonmodels.DeliveryVersion, chartData deliveryChartPath := filepath.Join(revisionBasePath, serviceObj.ServiceName) err := copy.Copy(fullPath, deliveryChartPath) if err != nil { - return nil + return nil, err } //load chart info from local storage chartRequested, err := chartloader.Load(deliveryChartPath) if err != nil { - return errors.Wrapf(err, "failed to load chart info, path %s", deliveryChartPath) + return nil, errors.Wrapf(err, "failed to load chart info, path %s", deliveryChartPath) } //set version and values.yaml content @@ -591,46 +626,46 @@ func handleSingleChart(deliveryVersion *commonmodels.DeliveryVersion, chartData valuesInfo := make(map[string]interface{}) if err = yaml.Unmarshal([]byte(chartData.ChartData.ValuesYamlContent), map[string]interface{}{}); err != nil { log.Errorf("invalid yaml content, serviceName: %s, yamlContent: %s", serviceObj.ServiceName, chartData.ChartData.ValuesYamlContent) - return errors.Wrapf(err, "invalid yaml content for service: %s", serviceObj.ServiceName) + return nil, errors.Wrapf(err, "invalid yaml content for service: %s", serviceObj.ServiceName) } chartRequested.Values = valuesInfo } else if len(globalVariables) > 0 { // merge global variables curValuesStr, err := yaml.Marshal(chartRequested.Values) if err != nil { - return errors.Wrapf(err, "failed to marshal values.yaml for service: %s", serviceObj.ServiceName) + return nil, errors.Wrapf(err, "failed to marshal values.yaml for service: %s", serviceObj.ServiceName) } chartRequested.Values, err = yamlutil.MergeAndUnmarshal([][]byte{curValuesStr, []byte(globalVariables)}) if err != nil { - return errors.Wrapf(err, "failed to merge global variables for service: %s", serviceObj.ServiceName) + return nil, errors.Wrapf(err, "failed to merge global variables for service: %s", serviceObj.ServiceName) } } chartPackagePath, err := helm.CreateChartPackage(&helm.Chart{Chart: chartRequested}, dir) if err != nil { - return err + return nil, err } - // push docker image - err = pushImages(deliveryVersion, serviceObj, chartRequested.Values, targetRegistry, registryMap) + // parse docker image + imagesData, err := extractImages(deliveryVersion, serviceObj, chartRequested.Values, targetRegistry, registryMap) if err != nil { - return errors.Wrapf(err, "failed to handle image") + return nil, errors.Wrapf(err, "failed to handle image") } client, err := createChartRepoClient(chartRepo) if err != nil { - return errors.Wrapf(err, "failed to create chart repo client, repoName: %s", chartRepo.RepoName) + return nil, errors.Wrapf(err, "failed to create chart repo client, repoName: %s", chartRepo.RepoName) } log.Infof("pushing %s to %s...\n", filepath.Base(chartPackagePath), chartRepo.URL) resp, err := client.UploadChartPackage(chartPackagePath, false) if err != nil { - return errors.Wrapf(err, "failed to prepare pushing chart: %s", chartPackagePath) + return nil, errors.Wrapf(err, "failed to prepare pushing chart: %s", chartPackagePath) } err = handlePushResponse(resp) if err != nil { - return errors.Wrapf(err, "failed to push chart: %s ", chartPackagePath) + return nil, errors.Wrapf(err, "failed to push chart: %s ", chartPackagePath) } - return nil + return imagesData, nil } func handlePushResponse(resp *http.Response) error { @@ -727,14 +762,75 @@ func buildRegistryMap() (map[string]*commonmodels.RegistryNamespace, error) { return ret, nil } +func buildArtifactTaskArgs(projectName, envName string, imagesMap *sync.Map) *commonmodels.ArtifactPackageTaskArgs { + imageArgs := make([]*commonmodels.ImagesByService, 0) + sourceRegistry := sets.NewString() + imagesMap.Range(func(key, value interface{}) bool { + imageDetail := value.(*ServiceImageDetails) + imagesByService := &commonmodels.ImagesByService{ + ServiceName: imageDetail.ServiceName, + Images: make([]*commonmodels.ImageData, 0), + } + for _, image := range imageDetail.Images { + imagesByService.Images = append(imagesByService.Images, &commonmodels.ImageData{ + ImageUrl: image.ImageUrl, + ImageName: image.Name, + ImageTag: image.Tag, + }) + } + imageArgs = append(imageArgs, imagesByService) + sourceRegistry.Insert(imageDetail.Registries...) + return true + }) + + ret := &commonmodels.ArtifactPackageTaskArgs{ + ProjectName: projectName, + EnvName: envName, + Images: imageArgs, + SourceRegistries: sourceRegistry.List(), + } + return ret +} + +// insert delivery distribution data for single chart, include image and chart +func insertDeliveryDistributions(result *task.ServicePackageResult, chartVersion string, deliveryVersion *commonmodels.DeliveryVersion, args *DeliveryVersionChartData) error { + for _, image := range result.ImageData { + err := commonrepo.NewDeliveryDistributeColl().Insert(&commonmodels.DeliveryDistribute{ + ReleaseID: deliveryVersion.ID, + ServiceName: image.ImageName, // image name + ChartName: result.ServiceName, + DistributeType: config.Image, + RegistryName: image.ImageUrl, + Namespace: commonservice.ExtractRegistryNamespace(image.ImageUrl), + CreatedAt: time.Now().Unix(), + }) + if err != nil { + log.Errorf("failed to insert image distribute data, chartName: %s, err: %s", result.ServiceName, err) + return fmt.Errorf("failed to insert image distribute data, chartName: %s", result.ServiceName) + } + } + + err := commonrepo.NewDeliveryDistributeColl().Insert(&commonmodels.DeliveryDistribute{ + ReleaseID: deliveryVersion.ID, + DistributeType: config.Chart, + ChartName: result.ServiceName, + ChartVersion: chartVersion, + ChartRepoName: args.ChartRepoName, + SubDistributes: nil, + CreatedAt: time.Now().Unix(), + }) + if err != nil { + log.Errorf("failed to insert chart distribute data, chartName: %s, err: %s", result.ServiceName, err) + return fmt.Errorf("failed to insert chart distribute data, chartName: %s", result.ServiceName) + } + return nil +} + func buildDeliveryCharts(chartDataMap map[string]*DeliveryChartData, deliveryVersion *commonmodels.DeliveryVersion, args *DeliveryVersionChartData, logger *zap.SugaredLogger) (err error) { defer func() { if err != nil { deliveryVersion.Status = setting.DeliveryVersionStatusFailed deliveryVersion.Error = err.Error() - } else { - deliveryVersion.Status = setting.DeliveryVersionStatusSuccess - deliveryVersion.Error = "" } err = commonrepo.NewDeliveryVersionColl().UpdateStatusByName(deliveryVersion.Version, deliveryVersion.Status, deliveryVersion.Error) if err != nil { @@ -774,10 +870,7 @@ func buildDeliveryCharts(chartDataMap map[string]*DeliveryChartData, deliveryVer return fmt.Errorf("failed to build registry map") } - //err = runDockerCommand(dockerInfo()) - //if err != nil { - // return fmt.Errorf("failed to run docker deamon") - //} + imagesDataMap := &sync.Map{} // push charts to repo wg := sync.WaitGroup{} @@ -785,25 +878,14 @@ func buildDeliveryCharts(chartDataMap map[string]*DeliveryChartData, deliveryVer wg.Add(1) go func(cData *DeliveryChartData) { defer wg.Done() - err := handleSingleChart(deliveryVersion, cData, repoInfo, dir, args.GlobalVariables, targetRegistry, registryMap) + imagesData, err := handleSingleChart(deliveryVersion, cData, repoInfo, dir, args.GlobalVariables, targetRegistry, registryMap) if err != nil { logger.Errorf("failed to handle single chart data, serviceName: %s err: %s", cData.ChartData.ServiceName, err) appendError(err) return } - err = commonrepo.NewDeliveryDistributeColl().Insert(&commonmodels.DeliveryDistribute{ - ReleaseID: deliveryVersion.ID, - DistributeType: config.Chart, - ChartName: cData.ChartData.ServiceName, - ChartVersion: cData.ChartData.Version, - ChartRepoName: args.ChartRepoName, - SubDistributes: nil, - CreatedAt: time.Now().Unix(), - }) - if err != nil { - logger.Errorf("failed to insert delivery distribute chart, serviceName: %s, err: %s", cData.ChartData.ServiceName, err) - appendError(err) - } + imagesDataMap.Store(cData.ServiceObj.ServiceName, imagesData) + }(chartData) } wg.Wait() @@ -813,34 +895,174 @@ func buildDeliveryCharts(chartDataMap map[string]*DeliveryChartData, deliveryVer return } + // create task to deal with images + // offline docker images are not supported + taskArgs := buildArtifactTaskArgs(deliveryVersion.ProductName, deliveryVersion.ProductEnvInfo.EnvName, imagesDataMap) + taskArgs.TargetRegistries = []string{args.ImageRegistryID} + taskID, err := workflowservice.CreateArtifactPackageTask(taskArgs, deliveryVersion.Version, logger) + if err != nil { + return err + } + deliveryVersion.TaskID = int(taskID) + + // start a new routine to check task results + go waitVersionDone(deliveryVersion) + // no need to upload chart packages - if args.Options == nil || !args.Options.EnableOfflineDist { - return + //if args.Options == nil || !args.Options.EnableOfflineDist { + // return + //} + // + ////tar all chart files and image offline packages, send to s3 store + //fsTree := os.DirFS(dir) + //s3Base := configbase.ObjectStorageDeliveryVersionPath(deliveryVersion.ProductName) + //if err = fsservice.ArchiveAndUploadFilesToSpecifiedS3(fsTree, []string{deliveryVersion.Version}, s3Base, args.Options.S3StorageID, logger); err != nil { + // logger.Errorf("failed to upload chart package files for project %s, err: %s", deliveryVersion.ProductName, err) + // err = errors.Wrapf(err, "failed to upload package file") + // return + //} + + //err = commonrepo.NewDeliveryDistributeColl().Insert(&commonmodels.DeliveryDistribute{ + // ReleaseID: deliveryVersion.ID, + // DistributeType: config.File, + // PackageFile: fmt.Sprintf("%s.tar.gz", deliveryVersion.Version), + // //RemoteFileKey: filepath.Join(s3Base, fmt.Sprintf("%s.tar.gz", deliveryVersion.Version)), + // S3StorageID: args.Options.S3StorageID, + // CreatedAt: time.Now().Unix(), + //}) + //if err != nil { + // logger.Errorf("failed to insert file distribute data, version: %s, err: %s", deliveryVersion.Version, err) + // return fmt.Errorf("failed to insert file distribute data") + //} + + return +} + +func updateVersionStatus(versionName, status, errStr string) { + err := commonrepo.NewDeliveryVersionColl().UpdateStatusByName(versionName, status, errStr) + if err != nil { + log.Errorf("failed to update version status, name: %s, err: %s", versionName, err) } +} - //tar all chart files and image offline packages, send to s3 store - fsTree := os.DirFS(dir) - s3Base := configbase.ObjectStorageDeliveryVersionPath(deliveryVersion.ProductName) - if err = fsservice.ArchiveAndUploadFilesToSpecifiedS3(fsTree, []string{deliveryVersion.Version}, s3Base, args.Options.S3StorageID, logger); err != nil { - logger.Errorf("failed to upload chart package files for project %s, err: %s", deliveryVersion.ProductName, err) - err = errors.Wrapf(err, "failed to upload package file") - return +func taskFinished(status config.Status) bool { + return status == config.StatusPassed || status == config.StatusFailed || status == config.StatusTimeout || status == config.StatusCancelled +} + +func waitVersionDone(deliveryVersion *commonmodels.DeliveryVersion) { + waitTimeout := time.After(10 * time.Minute) + for { + select { + case <-waitTimeout: + updateVersionStatus(deliveryVersion.Version, setting.DeliveryVersionStatusFailed, "timeout") + return + default: + done, err := checkVersionStatus(deliveryVersion) + if err != nil { + updateVersionStatus(deliveryVersion.Version, setting.DeliveryVersionStatusFailed, err.Error()) + return + } + if done { + return + } + } + time.Sleep(time.Second * 5) } +} - err = commonrepo.NewDeliveryDistributeColl().Insert(&commonmodels.DeliveryDistribute{ - ReleaseID: deliveryVersion.ID, - DistributeType: config.File, - PackageFile: fmt.Sprintf("%s.tar.gz", deliveryVersion.Version), - RemoteFileKey: filepath.Join(s3Base, fmt.Sprintf("%s.tar.gz", deliveryVersion.Version)), - S3StorageID: args.Options.S3StorageID, - CreatedAt: time.Now().Unix(), +func checkVersionStatus(deliveryVersion *commonmodels.DeliveryVersion) (bool, error) { + if deliveryVersion.Status == setting.DeliveryVersionStatusSuccess || deliveryVersion.Status == setting.DeliveryVersionStatusFailed { + return true, nil + } + pipelineName := fmt.Sprintf("%s-%s-%s", deliveryVersion.ProductName, deliveryVersion.ProductEnvInfo.EnvName, "artifact") + taskData, err := commonrepo.NewTaskColl().Find(int64(deliveryVersion.TaskID), pipelineName, config.ArtifactType) + if err != nil { + return false, fmt.Errorf("failed to query taskData, id: %d, pipelineName: %s", deliveryVersion.TaskID) + } + + if len(taskData.Stages) != 1 { + return false, fmt.Errorf("invalid task data, stage length not leagal") + } + + argsBytes, err := json.Marshal(deliveryVersion.CreateArgument) + if err != nil { + return false, errors.Wrapf(err, "failed to marshal arguments, versionName: %s err: %s", deliveryVersion.Version, err) + } + createArgs := new(DeliveryVersionChartData) + err = json.Unmarshal(argsBytes, createArgs) + if err != nil { + return false, errors.Wrapf(err, "failed to unMarshal arguments, versionName: %s err: %s", deliveryVersion.Version, err) + } + + distributes, err := commonrepo.NewDeliveryDistributeColl().Find(&commonrepo.DeliveryDistributeArgs{ + DistributeType: config.Chart, + ReleaseID: deliveryVersion.ID.Hex(), }) if err != nil { - logger.Errorf("failed to insert file distribute data, version: %s, err: %s", deliveryVersion.Version, err) - return fmt.Errorf("failed to insert file distribute data") + return false, errors.Wrapf(err, "failed to query distrubutes, versionName: %s", deliveryVersion.Version) } - return + // for charts has been successfully handled, download charts directly + successCharts := sets.NewString() + for _, distribute := range distributes { + successCharts.Insert(distribute.ChartName) + } + + stage := taskData.Stages[0] + errorList := &multierror.Error{} + + allTaskDone := true + for _, taskData := range stage.SubTasks { + artifactPackageArgs, err := base.ToArtifactPackageImageTask(taskData) + if err != nil { + return false, errors.Wrapf(err, "failed to generate origin artifact task data") + } + + progressData, err := artifactPackageArgs.GetProgress() + if err != nil { + return false, errors.Wrapf(err, "failed to get progress data from data") + } + progressDataMap := make(map[string]*task.ServicePackageResult) + for _, singleResult := range progressData { + progressDataMap[singleResult.ServiceName] = singleResult + } + + for _, chartData := range createArgs.ChartDatas { + // service artifact has been marked as success + if successCharts.Has(chartData.ServiceName) { + continue + } + if singleResult, ok := progressDataMap[chartData.ServiceName]; ok { + if singleResult.Result != "success" { + errorList = multierror.Append(errorList, fmt.Errorf("failed to build image distribute for service:%s ", singleResult.ServiceName)) + continue + } + err = insertDeliveryDistributions(singleResult, chartData.Version, deliveryVersion, createArgs) + if err != nil { + errorList = multierror.Append(errorList, fmt.Errorf("failed to insert distribute data for service:%s ", singleResult.ServiceName)) + continue + } + successCharts.Insert(chartData.ServiceName) + } + } + + if !taskFinished(artifactPackageArgs.TaskStatus) { + allTaskDone = false + } + } + + if allTaskDone { + if successCharts.Len() == len(createArgs.ChartDatas) { + deliveryVersion.Status = setting.DeliveryVersionStatusSuccess + } else { + deliveryVersion.Status = setting.DeliveryVersionStatusFailed + } + } + if errorList.ErrorOrNil() != nil { + deliveryVersion.Error = errorList.Error() + } + updateVersionStatus(deliveryVersion.Version, deliveryVersion.Status, deliveryVersion.Error) + return allTaskDone, nil } func CreateNewHelmDeliveryVersion(args *CreateHelmDeliveryVersionArgs, logger *zap.SugaredLogger) error { @@ -885,15 +1107,15 @@ func CreateNewHelmDeliveryVersion(args *CreateHelmDeliveryVersionArgs, logger *z DeletedAt: 0, } - err = commonrepo.NewDeliveryVersionColl().Insert(versionObj) + err = buildDeliveryCharts(chartDataMap, versionObj, args.DeliveryVersionChartData, logger) if err != nil { - logger.Errorf("failed to insert version data, err: %s", err) - return e.ErrCreateDeliveryVersion.AddErr(fmt.Errorf("failed to insert delivery version: %s", versionObj.Version)) + return err } - err = buildDeliveryCharts(chartDataMap, versionObj, args.DeliveryVersionChartData, logger) + err = commonrepo.NewDeliveryVersionColl().Insert(versionObj) if err != nil { - return err + logger.Errorf("failed to insert version data, err: %s", err) + return e.ErrCreateDeliveryVersion.AddErr(fmt.Errorf("failed to insert delivery version: %s", versionObj.Version)) } return nil @@ -925,10 +1147,9 @@ func RetryCreateHelmDeliveryVersion(projectName, versionName string, logger *zap productInfoSnap := deliveryVersion.ProductEnvInfo - //deploys := make - distributes, err := commonrepo.NewDeliveryDistributeColl().Find(&commonrepo.DeliveryDistributeArgs{ - ReleaseID: deliveryVersion.ID.Hex(), + DistributeType: config.Chart, + ReleaseID: deliveryVersion.ID.Hex(), }) if err != nil { return errors.Wrapf(err, "failed to query distrubutes, versionName: %s", deliveryVersion.Version) @@ -1064,20 +1285,16 @@ func downloadChart(deliveryVersion *commonmodels.DeliveryVersion, chartInfo *com func getChartDistributeInfo(releaseID, chartName string, log *zap.SugaredLogger) (*commonmodels.DeliveryDistribute, error) { distributes, _ := FindDeliveryDistribute(&commonrepo.DeliveryDistributeArgs{ ReleaseID: releaseID, - ServiceName: chartName, + ChartName: chartName, DistributeType: config.Chart, }, log) - var chartInfo *commonmodels.DeliveryDistribute - for _, distribute := range distributes { - if distribute.ChartName == chartName { - chartInfo = distribute - } + if len(distributes) != 1 { + log.Warnf("find chart %s failed, expect count %d, found count %d, release_id: %s", chartName, 1, len(distributes), releaseID) + return nil, fmt.Errorf("can't find target charts") } - if chartInfo == nil { - return nil, fmt.Errorf("can't find target chart: %s", chartName) - } + chartInfo := distributes[0] return chartInfo, nil } diff --git a/pkg/microservice/aslan/core/environment/handler/helm_release.go b/pkg/microservice/aslan/core/environment/handler/helm.go similarity index 80% rename from pkg/microservice/aslan/core/environment/handler/helm_release.go rename to pkg/microservice/aslan/core/environment/handler/helm.go index d93e7a5e7..9e097cd91 100644 --- a/pkg/microservice/aslan/core/environment/handler/helm_release.go +++ b/pkg/microservice/aslan/core/environment/handler/helm.go @@ -25,16 +25,16 @@ import ( func ListReleases(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - envName := c.Query("envName") - productName := c.Param("productName") - ctx.Resp, ctx.Err = service.ListReleases(productName, envName, ctx.Logger) + envName := c.Param("name") + projectName := c.Query("projectName") + ctx.Resp, ctx.Err = service.ListReleases(projectName, envName, ctx.Logger) } func GetChartInfos(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - envName := c.Query("envName") + envName := c.Param("name") servicesName := c.Query("serviceName") - productName := c.Param("productName") - ctx.Resp, ctx.Err = service.GetChartInfos(productName, envName, servicesName, ctx.Logger) + projectName := c.Query("projectName") + ctx.Resp, ctx.Err = service.GetChartInfos(projectName, envName, servicesName, ctx.Logger) } diff --git a/pkg/microservice/aslan/core/environment/handler/router.go b/pkg/microservice/aslan/core/environment/handler/router.go index 03d649bc3..fcca81914 100644 --- a/pkg/microservice/aslan/core/environment/handler/router.go +++ b/pkg/microservice/aslan/core/environment/handler/router.go @@ -107,6 +107,9 @@ func (*Router) Inject(router *gin.RouterGroup) { environments.GET("/:name/groups", ListGroups) environments.GET("/:name/workloads", ListWorkloadsInEnv) + environments.GET("/:name/helm/releases", ListReleases) + environments.GET("/:name/helm/charts", GetChartInfos) + environments.GET("/:name/services/:serviceName", GetService) environments.PUT("/:name/services/:serviceName", gin2.UpdateOperationLogStatus, UpdateService) environments.POST("/:name/services/:serviceName/restart", gin2.UpdateOperationLogStatus, RestartService) diff --git a/pkg/microservice/aslan/core/workflow/handler/workflow.go b/pkg/microservice/aslan/core/workflow/handler/workflow.go index d33f1a589..3e4eca7b6 100644 --- a/pkg/microservice/aslan/core/workflow/handler/workflow.go +++ b/pkg/microservice/aslan/core/workflow/handler/workflow.go @@ -109,7 +109,7 @@ func CreateArtifactTask(c *gin.Context) { return } - ctx.Err = workflow.CreateArtifactPackageTask(args, ctx.Logger) + _, ctx.Err = workflow.CreateArtifactPackageTask(args, ctx.UserName, ctx.Logger) } // UpdateWorkflow update a workflow diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go index 15c7b59fa..abc795822 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go @@ -35,7 +35,7 @@ import ( "go.uber.org/zap" ) -func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, log *zap.SugaredLogger) error { +func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, taskCreator string, log *zap.SugaredLogger) (int64, error) { // 获取全局configpayload configPayload := commonservice.GetConfigPayload(0) @@ -43,7 +43,7 @@ func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, log * if err != nil { log.Errorf("CreateArtifactPackageTask query registries failed, err: %s", err) - return fmt.Errorf("failed to query registries") + return 0, fmt.Errorf("failed to query registries") } registriesInvolved := sets.NewString() @@ -68,13 +68,13 @@ func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, log * defaultS3, err := s3.FindDefaultS3() if err != nil { err = e.ErrFindDefaultS3Storage.AddDesc("default storage is required by distribute task") - return err + return 0, err } defaultURL, err := defaultS3.GetEncryptedURL() if err != nil { err = e.ErrS3Storage.AddErr(err) - return err + return 0, err } task := &task.Task{ @@ -82,6 +82,7 @@ func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, log * ProductName: args.ProjectName, Status: config.StatusCreated, ArtifactPackageTaskArgs: args, + TaskCreator: taskCreator, ConfigPayload: configPayload, StorageURI: defaultURL, } @@ -100,14 +101,14 @@ func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, log * }).ToSubTask() if err != nil { - return err + return 0, err } task.SubTasks = []map[string]interface{}{subTask} if err := ensurePipelineTask(task, "", log); err != nil { log.Errorf("CreateServiceTask ensurePipelineTask err : %v", err) - return err + return 0, err } stages := make([]*commonmodels.Stage, 0) @@ -117,14 +118,14 @@ func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, log * sort.Sort(ByStageKind(stages)) task.Stages = stages if len(task.Stages) == 0 { - return e.ErrCreateTask.AddDesc(e.PipelineSubTaskNotFoundErrMsg) + return 0, e.ErrCreateTask.AddDesc(e.PipelineSubTaskNotFoundErrMsg) } pipelineName := fmt.Sprintf("%s-%s-%s", args.ProjectName, args.EnvName, "artifact") nextTaskID, err := commonrepo.NewCounterColl().GetNextSeq(fmt.Sprintf(setting.ServiceTaskFmt, pipelineName)) if err != nil { log.Errorf("CreateServiceTask Counter.GetNextSeq error: %v", err) - return e.ErrGetCounter.AddDesc(err.Error()) + return 0, e.ErrGetCounter.AddDesc(err.Error()) } task.SubTasks = []map[string]interface{}{} @@ -133,8 +134,8 @@ func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, log * if err := CreateTask(task); err != nil { log.Error(err) - return e.ErrCreateTask + return 0, e.ErrCreateTask } - return nil + return nextTaskID, nil } diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go index deb423c19..896f3d0a2 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go @@ -1034,7 +1034,7 @@ func deployEnvToSubTasks(env commonmodels.DeployEnv, prodEnv *commonmodels.Produ func resetImageTaskToSubTask(env commonmodels.DeployEnv, prodEnv *commonmodels.Product) (map[string]interface{}, error) { switch env.Type { - case setting.K8SDeployType: + case setting.K8SDeployType, setting.HelmDeployType: deployTask := task.Deploy{TaskType: config.TaskResetImage, Enabled: true} deployTask.Namespace = prodEnv.Namespace deployTask.ProductName = prodEnv.ProductName diff --git a/pkg/microservice/packager/core/service/service.go b/pkg/microservice/packager/core/service/service.go index 043ac8c6d..17d2ba3cf 100644 --- a/pkg/microservice/packager/core/service/service.go +++ b/pkg/microservice/packager/core/service/service.go @@ -101,6 +101,7 @@ func (p *Packager) Exec() error { allRegistries := make([]*DockerRegistry, 0) allRegistries = append(allRegistries, p.Ctx.SourceRegistries...) allRegistries = append(allRegistries, p.Ctx.TargetRegistries...) + log.Infof("all registry count %v", len(allRegistries)) err := writeDockerConfig(allRegistries) if err != nil { return err @@ -209,6 +210,7 @@ func (p *Packager) dockerCommands(imageByService *ImagesByService) []*exec.Cmd { targetImage := buildTargetImage(image.ImageName, image.ImageTag, registry.Host, registry.Namespace) cmds = append(cmds, dockerTag(image.ImageUrl, targetImage)) cmds = append(cmds, dockerPush(targetImage)) + image.ImageUrl = targetImage } } } diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go b/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go index 2436728d6..693403be1 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go @@ -174,7 +174,7 @@ func (p *ArtifactPackageTaskPlugin) Run(ctx context.Context, pipelineTask *task. } p.Log.Infof("succeed to create cm for artifact package job %s", p.JobName) - job, err := buildJob(p.Type(), pipelineTask.ConfigPayload.Release.PackagerImage, p.JobName, serviceName, setting.MinRequest, pipelineCtx, pipelineTask, []*task.RegistryNamespace{}) + job, err := buildJob(p.Type(), pipelineTask.ConfigPayload.Release.PackagerImage, p.JobName, serviceName, setting.MinRequest, setting.MinRequestSpec, pipelineCtx, pipelineTask, []*task.RegistryNamespace{}) if err != nil { msg := fmt.Sprintf("create release artifact package job context error: %v", err) p.Log.Error(msg) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/deploy.go b/pkg/microservice/warpdrive/core/service/taskplugin/deploy.go index 6632789ba..3a69965ee 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/deploy.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/deploy.go @@ -366,15 +366,15 @@ func (p *DeployTaskPlugin) Run(ctx context.Context, pipelineTask *task.Task, _ * ) rcsList := make([]ResourceComponentSet, 0) - deployments, err := getter.ListDeployments(p.Task.Namespace, nil, p.kubeClient) - if err != nil { - p.Log.Errorf("failed to list deployments in namespace %s, productName %s, err %s", p.Task.Namespace, p.Task.ProductName, err) + deployments, errListDeploy := getter.ListDeployments(p.Task.Namespace, nil, p.kubeClient) + if errListDeploy != nil { + p.Log.Errorf("failed to list deployments in namespace %s, productName %s, err %s", p.Task.Namespace, p.Task.ProductName, errListDeploy) } else { rcsList = append(rcsList, RcsListFromDeployments(deployments)...) } - statefulSets, _ := getter.ListStatefulSets(p.Task.Namespace, nil, p.kubeClient) - if err != nil { - p.Log.Errorf("failed to list statefulsets in namespace %s, productName %s, err %s", p.Task.Namespace, p.Task.ProductName, err) + statefulSets, errListSts := getter.ListStatefulSets(p.Task.Namespace, nil, p.kubeClient) + if errListSts != nil { + p.Log.Errorf("failed to list statefulsets in namespace %s, productName %s, err %s", p.Task.Namespace, p.Task.ProductName, errListSts) } else { rcsList = append(rcsList, RcsListFromStatefulSets(statefulSets)...) } -- Gitee From af1f0ef55be7c6b9fe227008834bec6583fe46b2 Mon Sep 17 00:00:00 2001 From: allenshen Date: Mon, 6 Dec 2021 15:01:56 +0800 Subject: [PATCH 033/134] fix compile error Signed-off-by: allenshen --- .../aslan/core/workflow/service/workflow/workflow_task.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go index a2bd6c88d..4ce8e4c47 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go @@ -1034,7 +1034,7 @@ func deployEnvToSubTasks(env commonmodels.DeployEnv, prodEnv *commonmodels.Produ func resetImageTaskToSubTask(env commonmodels.DeployEnv, prodEnv *commonmodels.Product) (map[string]interface{}, error) { switch env.Type { - case setting.K8SDeployType, setting.HelmDeployType: + case setting.K8SDeployType: deployTask := task.Deploy{TaskType: config.TaskResetImage, Enabled: true} deployTask.Namespace = prodEnv.Namespace deployTask.ProductName = prodEnv.ProductName -- Gitee From 5c08446f042dfbbfd68c24cc018d811a7d08c23a Mon Sep 17 00:00:00 2001 From: panxunying Date: Mon, 6 Dec 2021 15:37:36 +0800 Subject: [PATCH 034/134] update create workflow task image with registryID Signed-off-by: panxunying --- .../core/workflow/service/workflow/workflow_task.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go index 45f27398d..946d79544 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go @@ -1778,13 +1778,20 @@ func ensurePipelineTask(pt *task.Task, envName string, log *zap.SugaredLogger) e setManunalBuilds(t.JobCtx.Builds, pt.TaskArgs.Builds, log) } + opt := &commonrepo.ProductFindOptions{Namespace: envName} + exitedProd, err := commonrepo.NewProductColl().Find(opt) + if err != nil { + log.Errorf("can't find product by namespace:%s error msg: %v", envName, err) + return e.ErrFindRegistry.AddDesc(err.Error()) + } + // 生成默认镜像tag后缀 //pt.TaskArgs.Deploy.Tag = releaseCandidate(t, pt.TaskID, pt.ProductName, pt.EnvName, "image") // 设置镜像名称 // 编译任务使用 t.JobCtx.Image // 注意: 其他任务从 pt.TaskArgs.Deploy.Image 获取, 必须要有编译任务 - reg, err := commonservice.FindDefaultRegistry(log) + reg, err := commonservice.FindRegistryById(exitedProd.RegistryId, log) if err != nil { log.Errorf("can't find default candidate registry: %v", err) return e.ErrFindRegistry.AddDesc(err.Error()) -- Gitee From 9c4ee32aeba7e052da20198e8efda7737f60fed2 Mon Sep 17 00:00:00 2001 From: panxunying Date: Mon, 6 Dec 2021 15:39:19 +0800 Subject: [PATCH 035/134] add GetRegistryNamespace and UpdateProductRegistry Signed-off-by: panxunying --- .../core/common/repository/mongodb/product.go | 18 +++++- .../aslan/core/common/service/product.go | 15 +++++ .../aslan/core/common/service/registry.go | 9 +++ .../core/environment/handler/environment.go | 60 +++++++++++++++---- .../aslan/core/environment/handler/router.go | 1 + .../core/environment/service/environment.go | 48 ++++++++++++--- .../service/environment_creator.go | 2 + .../aslan/core/system/handler/registry.go | 18 ++++++ .../aslan/core/system/handler/router.go | 1 + 9 files changed, 152 insertions(+), 20 deletions(-) diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/product.go b/pkg/microservice/aslan/core/common/repository/mongodb/product.go index ca490b5ba..023ba43f4 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/product.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/product.go @@ -33,8 +33,9 @@ import ( ) type ProductFindOptions struct { - Name string - EnvName string + Name string + EnvName string + Namespace string } // ClusterId is a primitive.ObjectID{}.Hex() @@ -130,6 +131,9 @@ func (c *ProductColl) Find(opt *ProductFindOptions) (*models.Product, error) { if opt.EnvName != "" { query["env_name"] = opt.EnvName } + if opt.Namespace != "" { + query["namespace"] = opt.Namespace + } err := c.FindOne(context.TODO(), query).Decode(res) return res, err @@ -241,6 +245,16 @@ func (c *ProductColl) UpdateErrors(owner, productName, errorMsg string) error { return err } +func (c *ProductColl) UpdateRegistry(namespace, registryId string) error { + query := bson.M{"namespace": namespace} + change := bson.M{"$set": bson.M{ + "registry_id": registryId, + }} + _, err := c.UpdateOne(context.TODO(), query, change) + + return err +} + func (c *ProductColl) UpdateRender(envName, productName string, render *models.RenderInfo) error { query := bson.M{"env_name": envName, "product_name": productName} change := bson.M{"$set": bson.M{ diff --git a/pkg/microservice/aslan/core/common/service/product.go b/pkg/microservice/aslan/core/common/service/product.go index 9986f3575..8c72170d8 100644 --- a/pkg/microservice/aslan/core/common/service/product.go +++ b/pkg/microservice/aslan/core/common/service/product.go @@ -352,3 +352,18 @@ func GetProductEnvNamespace(envName, productName, namespace string) string { } return product.Namespace } + +func GetProductEnv(envName, productName, namespace string) *models.Product { + if namespace != "" { + return nil + } + product, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{ + Name: productName, + EnvName: envName, + }) + if err != nil { + product = &commonmodels.Product{EnvName: envName, ProductName: productName} + return product + } + return product +} diff --git a/pkg/microservice/aslan/core/common/service/registry.go b/pkg/microservice/aslan/core/common/service/registry.go index 74ca6fc6a..08a963f16 100644 --- a/pkg/microservice/aslan/core/common/service/registry.go +++ b/pkg/microservice/aslan/core/common/service/registry.go @@ -73,6 +73,15 @@ func GetDefaultRegistryNamespace(log *zap.SugaredLogger) (*models.RegistryNamesp return resp, nil } +func GetRegistryNamespace(registryID string, log *zap.SugaredLogger) (*models.RegistryNamespace, error) { + resp, err := mongodb.NewRegistryNamespaceColl().Find(&mongodb.FindRegOps{ID: registryID}) + if err != nil { + log.Errorf("get default registry error: %v", err) + return resp, fmt.Errorf("get default registry error: %v", err) + } + return resp, nil +} + func ListRegistryNamespaces(log *zap.SugaredLogger) ([]*models.RegistryNamespace, error) { resp, err := mongodb.NewRegistryNamespaceColl().FindAll(&mongodb.FindRegOps{}) if err != nil { diff --git a/pkg/microservice/aslan/core/environment/handler/environment.go b/pkg/microservice/aslan/core/environment/handler/environment.go index ad200efda..6a1f5119a 100644 --- a/pkg/microservice/aslan/core/environment/handler/environment.go +++ b/pkg/microservice/aslan/core/environment/handler/environment.go @@ -130,7 +130,11 @@ func createHelmProduct(c *gin.Context, ctx *internalhandler.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("projectName can not be empty") return } - + registryID := c.Query("registryID") + if registryID == "" { + ctx.Err = e.ErrInvalidParam.AddDesc("registryID can not be empty") + return + } createArgs := make([]*service.CreateHelmProductArg, 0) data, err := c.GetRawData() if err != nil { @@ -156,7 +160,7 @@ func createHelmProduct(c *gin.Context, ctx *internalhandler.Context) { internalhandler.InsertOperationLog(c, ctx.UserName, projectName, "新增", "集成环境", strings.Join(envNameList, "-"), string(data), ctx.Logger) ctx.Err = service.CreateHelmProduct( - projectName, ctx.UserName, ctx.RequestID, createArgs, ctx.Logger, + projectName, ctx.UserName, ctx.RequestID, registryID, createArgs, ctx.Logger, ) } @@ -164,15 +168,6 @@ func CreateProduct(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - if c.Query("auto") == "true" { - ctx.Resp = service.AutoCreateProduct(c.Query("projectName"), c.Query("envType"), ctx.RequestID, ctx.Logger) - return - } - if c.Query("helm") == "true" { - createHelmProduct(c, ctx) - return - } - args := new(commonmodels.Product) data, err := c.GetRawData() if err != nil { @@ -182,6 +177,15 @@ func CreateProduct(c *gin.Context) { log.Errorf("CreateProduct json.Unmarshal err : %v", err) } + if c.Query("auto") == "true" { + ctx.Resp = service.AutoCreateProduct(c.Query("projectName"), c.Query("envType"), ctx.RequestID, ctx.Logger) + return + } + if c.Query("helm") == "true" { + createHelmProduct(c, ctx) + return + } + allowedClusters, found := internalhandler.GetResourcesInHeader(c) if found { allowedSet := sets.NewString(allowedClusters...) @@ -204,6 +208,11 @@ func CreateProduct(c *gin.Context) { return } + if args.RegistryId == "" { + ctx.Err = e.ErrInvalidParam.AddDesc("RegistryId can not be null!") + return + } + args.UpdateBy = ctx.UserName // don't save the local cluster id to db if args.ClusterID == setting.LocalClusterID { @@ -247,6 +256,35 @@ func UpdateProduct(c *gin.Context) { } } +func UpdateProductRegistry(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + namespace := c.Param("namespace") + projectName := c.Query("projectName") + args := new(commonmodels.Product) + data, err := c.GetRawData() + if err != nil { + log.Errorf("UpdateProduct c.GetRawData() err : %v", err) + } + if err = json.Unmarshal(data, args); err != nil { + log.Errorf("UpdateProduct json.Unmarshal err : %v", err) + ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) + return + } + internalhandler.InsertOperationLog(c, ctx.UserName, projectName, "更新", "集成环境", namespace, string(data), ctx.Logger) + c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) + + if err := c.BindJSON(args); err != nil { + ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) + return + } + ctx.Err = service.UpdateProductRegistry(namespace, args.RegistryId, ctx.Logger) + if ctx.Err != nil { + ctx.Logger.Errorf("failed to update product %s %s: %v", namespace, args.RegistryId, ctx.Err) + } +} + func UpdateProductRecycleDay(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() diff --git a/pkg/microservice/aslan/core/environment/handler/router.go b/pkg/microservice/aslan/core/environment/handler/router.go index f5bb3dd99..2dcb66cbc 100644 --- a/pkg/microservice/aslan/core/environment/handler/router.go +++ b/pkg/microservice/aslan/core/environment/handler/router.go @@ -95,6 +95,7 @@ func (*Router) Inject(router *gin.RouterGroup) { { environments.GET("", ListProducts) environments.PUT("/:name", gin2.UpdateOperationLogStatus, UpdateProduct) + environments.PUT("/:namespace/registry", gin2.UpdateOperationLogStatus, UpdateProductRegistry) environments.PUT("", gin2.UpdateOperationLogStatus, UpdateMultiProducts) environments.POST("", gin2.UpdateOperationLogStatus, CreateProduct) environments.GET("/:name", GetProduct) diff --git a/pkg/microservice/aslan/core/environment/service/environment.go b/pkg/microservice/aslan/core/environment/service/environment.go index 935967233..b5e4b8dd3 100644 --- a/pkg/microservice/aslan/core/environment/service/environment.go +++ b/pkg/microservice/aslan/core/environment/service/environment.go @@ -522,6 +522,31 @@ func UpdateProduct(existedProd, updateProd *commonmodels.Product, renderSet *com return nil } +func UpdateProductRegistry(namespace, registryID string, log *zap.SugaredLogger) (err error) { + opt := &commonrepo.ProductFindOptions{Namespace: namespace} + exitedProd, err := commonrepo.NewProductColl().Find(opt) + if err != nil { + log.Errorf("UpdateProductRegistry find product by namespace:%s,error: %v", namespace, err) + return e.ErrUpdateEnv.AddDesc(e.EnvNotFoundErrMsg) + } + err = commonrepo.NewProductColl().UpdateRegistry(namespace, registryID) + if err != nil { + log.Errorf("UpdateProductRegistry UpdateRegistry by namespace:%s registryID:%s error: %v", namespace, registryID, err) + return e.ErrUpdateEnv.AddErr(err) + } + kubeClient, err := kube.GetKubeClient(exitedProd.ClusterID) + if err != nil { + return e.ErrUpdateEnv.AddErr(err) + } + err = ensureKubeEnv(exitedProd.Namespace, exitedProd.RegistryId, kubeClient, log) + + if err != nil { + log.Errorf("UpdateProductRegistry ensureKubeEnv by namespace:%s,error: %v", namespace, err) + return err + } + return nil +} + func UpdateProductV2(envName, productName, user, requestID string, force bool, kvs []*template.RenderKV, log *zap.SugaredLogger) (err error) { // 根据产品名称和产品创建者到数据库中查找已有产品记录 opt := &commonrepo.ProductFindOptions{Name: productName, EnvName: envName} @@ -641,7 +666,7 @@ func UpdateProductV2(envName, productName, user, requestID string, force bool, k return nil } -func CreateHelmProduct(productName, userName, requestID string, args []*CreateHelmProductArg, log *zap.SugaredLogger) error { +func CreateHelmProduct(productName, userName, requestID, registryID string, args []*CreateHelmProductArg, log *zap.SugaredLogger) error { templateProduct, err := templaterepo.NewProductColl().Find(productName) if err != nil || templateProduct == nil { if err != nil { @@ -698,7 +723,7 @@ func CreateHelmProduct(productName, userName, requestID string, args []*CreateHe errList := new(multierror.Error) for _, arg := range args { - err = createSingleHelmProduct(templateProduct, serviceGroup, requestID, userName, arg, log) + err = createSingleHelmProduct(templateProduct, serviceGroup, requestID, userName, registryID, arg, log) if err != nil { errList = multierror.Append(errList, err) } @@ -706,7 +731,7 @@ func CreateHelmProduct(productName, userName, requestID string, args []*CreateHe return errList.ErrorOrNil() } -func createSingleHelmProduct(templateProduct *template.Product, serviceGroup [][]*commonmodels.ProductService, requestID, userName string, arg *CreateHelmProductArg, log *zap.SugaredLogger) error { +func createSingleHelmProduct(templateProduct *template.Product, serviceGroup [][]*commonmodels.ProductService, requestID, userName, registryID string, arg *CreateHelmProductArg, log *zap.SugaredLogger) error { productObj := &commonmodels.Product{ ProductName: templateProduct.ProductName, Revision: 1, @@ -721,6 +746,7 @@ func createSingleHelmProduct(templateProduct *template.Product, serviceGroup [][ IsOpenSource: templateProduct.IsOpensource, ChartInfos: templateProduct.ChartInfos, IsForkedProduct: false, + RegistryId: registryID, } customChartValueMap := make(map[string]*commonservice.RenderChartArg) @@ -927,9 +953,8 @@ func checkOverrideValuesChange(source *template.RenderChart, args *commonservice } func UpdateHelmProductRenderset(productName, envName, userName, requestID string, args *EnvRendersetArg, log *zap.SugaredLogger) error { - renderSetName := commonservice.GetProductEnvNamespace(envName, productName, "") - - opt := &commonrepo.RenderSetFindOption{Name: renderSetName} + product := commonservice.GetProductEnv(envName, productName, "") + opt := &commonrepo.RenderSetFindOption{Name: product.Namespace} productRenderset, _, err := commonrepo.NewRenderSetColl().FindRenderSet(opt) if err != nil || productRenderset == nil { if err != nil { @@ -969,7 +994,16 @@ func UpdateHelmProductRenderset(productName, envName, userName, requestID string updatedRcList = append(updatedRcList, updatedRc) } - return UpdateHelmProductVariable(productName, envName, userName, requestID, updatedRcList, productRenderset, log) + err = UpdateHelmProductVariable(productName, envName, userName, requestID, updatedRcList, productRenderset, log) + if err != nil { + return err + } + kubeClient, err := kube.GetKubeClient(product.ClusterID) + if err != nil { + log.Errorf("UpdateHelmProductRenderset GetKubeClient error, error msg:%s", err) + return err + } + return ensureKubeEnv(product.Namespace, product.RegistryId, kubeClient, log) } func UpdateHelmProductVariable(productName, envName, username, requestID string, updatedRcs []*template.RenderChart, renderset *commonmodels.RenderSet, log *zap.SugaredLogger) error { diff --git a/pkg/microservice/aslan/core/environment/service/environment_creator.go b/pkg/microservice/aslan/core/environment/service/environment_creator.go index f8c5a8d64..0abe50d1a 100644 --- a/pkg/microservice/aslan/core/environment/service/environment_creator.go +++ b/pkg/microservice/aslan/core/environment/service/environment_creator.go @@ -41,6 +41,7 @@ type CreateProductParam struct { ProductName string EnvType string log *zap.SugaredLogger + RegistryID string } type AutoCreator struct { @@ -84,6 +85,7 @@ func (autoCreator *AutoCreator) Create(envName string) (string, error) { productObject.Namespace = commonservice.GetProductEnvNamespace(envName, productName, "") productObject.UpdateBy = autoCreator.Param.UserName productObject.EnvName = envName + productObject.RegistryId = autoCreator.Param.RegistryID if autoCreator.Param.EnvType == setting.HelmDeployType { productObject.Source = setting.SourceFromHelm } diff --git a/pkg/microservice/aslan/core/system/handler/registry.go b/pkg/microservice/aslan/core/system/handler/registry.go index 7a419d0cb..14c0cd37d 100644 --- a/pkg/microservice/aslan/core/system/handler/registry.go +++ b/pkg/microservice/aslan/core/system/handler/registry.go @@ -60,6 +60,24 @@ func GetDefaultRegistryNamespace(c *gin.Context) { } } +func GetRegistryNamespace(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + reg, err := commonservice.GetRegistryNamespace(c.Param("id"), ctx.Logger) + if err != nil { + ctx.Err = err + return + } + + ctx.Resp = &Registry{ + ID: reg.ID.Hex(), + RegAddr: reg.RegAddr, + IsDefault: reg.IsDefault, + Namespace: reg.Namespace, + } +} + func ListRegistryNamespaces(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() diff --git a/pkg/microservice/aslan/core/system/handler/router.go b/pkg/microservice/aslan/core/system/handler/router.go index 9de790a64..bf356fe7b 100644 --- a/pkg/microservice/aslan/core/system/handler/router.go +++ b/pkg/microservice/aslan/core/system/handler/router.go @@ -61,6 +61,7 @@ func (*Router) Inject(router *gin.RouterGroup) { registry.GET("", ListRegistries) // 获取默认的镜像仓库配置,用于kodespace CLI调用 registry.GET("/namespaces/default", GetDefaultRegistryNamespace) + registry.GET("/namespaces/:id", GetRegistryNamespace) registry.GET("/namespaces", ListRegistryNamespaces) registry.POST("/namespaces", gin2.UpdateOperationLogStatus, CreateRegistryNamespace) registry.PUT("/namespaces/:id", gin2.UpdateOperationLogStatus, UpdateRegistryNamespace) -- Gitee From f88556afa8e8400039b54a4ea245bb7b1cc94d01 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Mon, 6 Dec 2021 16:52:02 +0800 Subject: [PATCH 036/134] optimize schdule code Signed-off-by: liu deyi --- .../warpdrive/core/service/taskplugin/job.go | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/job.go b/pkg/microservice/warpdrive/core/service/taskplugin/job.go index cdf6f4355..b34a3ce28 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/job.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/job.go @@ -829,21 +829,28 @@ func addNodeAffinity(clusterID string, K8SClusters []*task.K8SCluster) *corev1.A switch clusterConfig.Strategy { case RequiredSchedule: - nodeSelectorTerms := make([]corev1.NodeSelectorTerm, 0) + nodeLabelM := make(map[string][]string, 0) for _, nodeLabel := range clusterConfig.NodeLabels { if !strings.Contains(nodeLabel, ":") || len(strings.Split(nodeLabel, ":")) != 2 { continue } - matchExpressions := make([]corev1.NodeSelectorRequirement, 0) + key := strings.Split(nodeLabel, ":")[0] + value := strings.Split(nodeLabel, ":")[1] + nodeLabelM[key] = append(nodeLabelM[key], value) + } + nodeSelectorTerms := make([]corev1.NodeSelectorTerm, 0) + for key, value := range nodeLabelM { + var matchExpressions []corev1.NodeSelectorRequirement matchExpressions = append(matchExpressions, corev1.NodeSelectorRequirement{ - Key: strings.Split(nodeLabel, ":")[0], + Key: key, Operator: corev1.NodeSelectorOpIn, - Values: []string{strings.Split(nodeLabel, ":")[1]}, + Values: value, }) nodeSelectorTerms = append(nodeSelectorTerms, corev1.NodeSelectorTerm{ MatchExpressions: matchExpressions, }) } + affinity := &corev1.Affinity{ NodeAffinity: &corev1.NodeAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ @@ -853,16 +860,22 @@ func addNodeAffinity(clusterID string, K8SClusters []*task.K8SCluster) *corev1.A } return affinity case PreferredSchedule: - preferredScheduleTerms := make([]corev1.PreferredSchedulingTerm, 0) + nodeLabelM := make(map[string][]string, 0) for _, nodeLabel := range clusterConfig.NodeLabels { if !strings.Contains(nodeLabel, ":") || len(strings.Split(nodeLabel, ":")) != 2 { continue } - matchExpressions := make([]corev1.NodeSelectorRequirement, 0) + key := strings.Split(nodeLabel, ":")[0] + value := strings.Split(nodeLabel, ":")[1] + nodeLabelM[key] = append(nodeLabelM[key], value) + } + preferredScheduleTerms := make([]corev1.PreferredSchedulingTerm, 0) + for key, value := range nodeLabelM { + var matchExpressions []corev1.NodeSelectorRequirement matchExpressions = append(matchExpressions, corev1.NodeSelectorRequirement{ - Key: strings.Split(nodeLabel, ":")[0], + Key: key, Operator: corev1.NodeSelectorOpIn, - Values: []string{strings.Split(nodeLabel, ":")[1]}, + Values: value, }) nodeSelectorTerm := corev1.NodeSelectorTerm{ MatchExpressions: matchExpressions, @@ -872,7 +885,6 @@ func addNodeAffinity(clusterID string, K8SClusters []*task.K8SCluster) *corev1.A Preference: nodeSelectorTerm, }) } - affinity := &corev1.Affinity{ NodeAffinity: &corev1.NodeAffinity{ PreferredDuringSchedulingIgnoredDuringExecution: preferredScheduleTerms, -- Gitee From 7cdd11f384f293837b86854f88a8157f1dcd40ed Mon Sep 17 00:00:00 2001 From: panxunying Date: Mon, 6 Dec 2021 18:55:55 +0800 Subject: [PATCH 037/134] registry data compatibility Signed-off-by: panxunying --- .../aslan/core/common/service/registry.go | 27 ++++++++++++++----- .../aslan/core/environment/handler/router.go | 2 +- .../service/workflow/workflow_task.go | 18 ++++++++++--- 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/pkg/microservice/aslan/core/common/service/registry.go b/pkg/microservice/aslan/core/common/service/registry.go index 08a963f16..4c0323aac 100644 --- a/pkg/microservice/aslan/core/common/service/registry.go +++ b/pkg/microservice/aslan/core/common/service/registry.go @@ -92,13 +92,26 @@ func ListRegistryNamespaces(log *zap.SugaredLogger) ([]*models.RegistryNamespace } func EnsureDefaultRegistrySecret(namespace string, registryId string, kubeClient client.Client, log *zap.SugaredLogger) error { - reg, err := FindRegistryById(registryId, log) - if err != nil { - log.Errorf( - "service.EnsureRegistrySecret: failed to find default candidate registry: %s %v", - namespace, err, - ) - return err + var reg *models.RegistryNamespace + var err error + if len(registryId) > 0 { + reg, err = FindRegistryById(registryId, log) + if err != nil { + log.Errorf( + "service.EnsureRegistrySecret: failed to find registry: %s error msg:%v", + registryId, err, + ) + return err + } + } else { + reg, err = FindDefaultRegistry(log) + if err != nil { + log.Errorf( + "service.EnsureRegistrySecret: failed to find default candidate registry: %s %v", + namespace, err, + ) + return err + } } err = kube.CreateOrUpdateRegistrySecret(namespace, reg, kubeClient) diff --git a/pkg/microservice/aslan/core/environment/handler/router.go b/pkg/microservice/aslan/core/environment/handler/router.go index 2dcb66cbc..3b0cd996d 100644 --- a/pkg/microservice/aslan/core/environment/handler/router.go +++ b/pkg/microservice/aslan/core/environment/handler/router.go @@ -95,7 +95,7 @@ func (*Router) Inject(router *gin.RouterGroup) { { environments.GET("", ListProducts) environments.PUT("/:name", gin2.UpdateOperationLogStatus, UpdateProduct) - environments.PUT("/:namespace/registry", gin2.UpdateOperationLogStatus, UpdateProductRegistry) + environments.PUT("/registry", gin2.UpdateOperationLogStatus, UpdateProductRegistry) environments.PUT("", gin2.UpdateOperationLogStatus, UpdateMultiProducts) environments.POST("", gin2.UpdateOperationLogStatus, CreateProduct) environments.GET("/:name", GetProduct) diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go index 946d79544..28bd0f74e 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go @@ -1791,10 +1791,20 @@ func ensurePipelineTask(pt *task.Task, envName string, log *zap.SugaredLogger) e // 设置镜像名称 // 编译任务使用 t.JobCtx.Image // 注意: 其他任务从 pt.TaskArgs.Deploy.Image 获取, 必须要有编译任务 - reg, err := commonservice.FindRegistryById(exitedProd.RegistryId, log) - if err != nil { - log.Errorf("can't find default candidate registry: %v", err) - return e.ErrFindRegistry.AddDesc(err.Error()) + var reg *commonmodels.RegistryNamespace + if len(exitedProd.RegistryId) > 0 { + reg, err = commonservice.FindRegistryById(exitedProd.RegistryId, log) + if err != nil { + log.Errorf("service.EnsureRegistrySecret: failed to find registry: %s error msg:%v", + exitedProd.RegistryId, err) + return e.ErrFindRegistry.AddDesc(err.Error()) + } + } else { + reg, err = commonservice.FindDefaultRegistry(log) + if err != nil { + log.Errorf("can't find default candidate registry: %v", err) + return e.ErrFindRegistry.AddDesc(err.Error()) + } } t.JobCtx.Image = GetImage(reg, releaseCandidate(t, pt.TaskID, pt.ProductName, envName, "image")) -- Gitee From 6d5871b7626baa8e01a18e36f04d3a04a42e45cd Mon Sep 17 00:00:00 2001 From: liu deyi Date: Mon, 6 Dec 2021 18:59:36 +0800 Subject: [PATCH 038/134] optimize sse interface Signed-off-by: liu deyi --- .../aslan/core/log/service/sse.go | 42 ++++++++++++++++--- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/pkg/microservice/aslan/core/log/service/sse.go b/pkg/microservice/aslan/core/log/service/sse.go index eb7872dd3..5811f7434 100644 --- a/pkg/microservice/aslan/core/log/service/sse.go +++ b/pkg/microservice/aslan/core/log/service/sse.go @@ -32,9 +32,9 @@ import ( commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" - krkubeclient "github.com/koderover/zadig/pkg/tool/kube/client" "github.com/koderover/zadig/pkg/tool/kube/containerlog" "github.com/koderover/zadig/pkg/tool/kube/getter" + "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/kube/watcher" ) @@ -53,6 +53,7 @@ type GetContainerOptions struct { TestName string EnvName string ProductName string + ClusterID string } func ContainerLogStream(ctx context.Context, streamChan chan interface{}, envName, productName, podName, containerName string, follow bool, tailLines int64, log *zap.SugaredLogger) { @@ -127,6 +128,20 @@ func TaskContainerLogStream(ctx context.Context, streamChan chan interface{}, op options.TaskID = taskObj.TaskID } } + } else if options.ProductName != "" { + build, err := commonrepo.NewBuildColl().Find(&commonrepo.BuildFindOption{ + ProductName: options.ProductName, + Targets: []string{options.ServiceName}, + }) + if err != nil { + // Maybe this service is a shared service + build, err = commonrepo.NewBuildColl().Find(&commonrepo.BuildFindOption{ + Targets: []string{options.ServiceName}, + }) + } + if build != nil && build.PreBuild != nil { + options.ClusterID = build.PreBuild.ClusterID + } } if options.SubTask == "" { @@ -137,9 +152,14 @@ func TaskContainerLogStream(ctx context.Context, streamChan chan interface{}, op } func TestJobContainerLogStream(ctx context.Context, streamChan chan interface{}, options *GetContainerOptions, log *zap.SugaredLogger) { - options.SubTask = string(config.TaskTestingV2) selector := getPipelineSelector(options) + // get cluster ID + testName := strings.Replace(options.ServiceName, "-job", "", 1) + testing, _ := commonrepo.NewTestingColl().Find(testName, "") + if testing != nil && testing.PreTest != nil { + options.ClusterID = testing.PreTest.ClusterID + } waitAndGetLog(ctx, streamChan, selector, options, log) } @@ -149,12 +169,22 @@ func waitAndGetLog(ctx context.Context, streamChan chan interface{}, selector la defer cancel() log.Debugf("Waiting until pod is running before establishing the stream.") - err := watcher.WaitUntilPodRunning(PodCtx, options.Namespace, selector, krkubeclient.Clientset()) + clientSet, err := multicluster.GetClientset(config.HubServerAddress(), options.ClusterID) + if err != nil { + log.Errorf("GetContainerLogs, get client set error: %s", err) + return + } + err = watcher.WaitUntilPodRunning(PodCtx, options.Namespace, selector, clientSet) + if err != nil { + log.Errorf("GetContainerLogs, wait pod running error: %s", err) + return + } + kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), options.ClusterID) if err != nil { - log.Errorf("GetContainerLogs, wait pod running error: %+v", err) + log.Errorf("GetContainerLogs, get kube client error: %s", err) return } - pods, err := getter.ListPods(options.Namespace, selector, krkubeclient.Client()) + pods, err := getter.ListPods(options.Namespace, selector, kubeClient) if err != nil { log.Errorf("GetContainerLogs, get pod error: %+v", err) return @@ -169,7 +199,7 @@ func waitAndGetLog(ctx context.Context, streamChan chan interface{}, selector la pods[0].Name, options.SubTask, true, options.TailLines, - krkubeclient.Clientset(), + clientSet, log, ) } -- Gitee From f0198bea7b1a8ff70d04e21f9634cc017577a419 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Mon, 6 Dec 2021 19:11:40 +0800 Subject: [PATCH 039/134] optimize sse interface Signed-off-by: liu deyi --- pkg/microservice/aslan/core/log/service/sse.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/microservice/aslan/core/log/service/sse.go b/pkg/microservice/aslan/core/log/service/sse.go index 5811f7434..7ae80d0cb 100644 --- a/pkg/microservice/aslan/core/log/service/sse.go +++ b/pkg/microservice/aslan/core/log/service/sse.go @@ -141,6 +141,7 @@ func TaskContainerLogStream(ctx context.Context, streamChan chan interface{}, op } if build != nil && build.PreBuild != nil { options.ClusterID = build.PreBuild.ClusterID + options.Namespace = build.PreBuild.Namespace } } @@ -159,6 +160,7 @@ func TestJobContainerLogStream(ctx context.Context, streamChan chan interface{}, testing, _ := commonrepo.NewTestingColl().Find(testName, "") if testing != nil && testing.PreTest != nil { options.ClusterID = testing.PreTest.ClusterID + options.Namespace = testing.PreTest.Namespace } waitAndGetLog(ctx, streamChan, selector, options, log) -- Gitee From e85161bda2bea5ec6e22d220be6bbbc12829d160 Mon Sep 17 00:00:00 2001 From: panxunying Date: Mon, 6 Dec 2021 19:48:16 +0800 Subject: [PATCH 040/134] get env response add registryID Signed-off-by: panxunying --- .../aslan/core/environment/service/environment.go | 1 + .../aslan/core/environment/service/product.go | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/pkg/microservice/aslan/core/environment/service/environment.go b/pkg/microservice/aslan/core/environment/service/environment.go index b5e4b8dd3..8cf70deae 100644 --- a/pkg/microservice/aslan/core/environment/service/environment.go +++ b/pkg/microservice/aslan/core/environment/service/environment.go @@ -115,6 +115,7 @@ type ProductResp struct { RecycleDay int `json:"recycle_day"` IsProd bool `json:"is_prod"` Source string `json:"source"` + RegisterID string `json:"register_id"` } type ProductParams struct { diff --git a/pkg/microservice/aslan/core/environment/service/product.go b/pkg/microservice/aslan/core/environment/service/product.go index 88d38802c..44f637760 100644 --- a/pkg/microservice/aslan/core/environment/service/product.go +++ b/pkg/microservice/aslan/core/environment/service/product.go @@ -169,6 +169,14 @@ func GetProduct(username, envName, productName string, log *zap.SugaredLogger) ( } } + if len(prod.RegistryId) == 0 { + reg, err := commonservice.FindDefaultRegistry(log) + if err != nil { + log.Errorf("[User:%s][EnvName:%s][Product:%s] FindDefaultRegistry error: %v", username, envName, productName, err) + return nil, err + } + prod.RegistryId = reg.ID.String() + } resp := buildProductResp(prod.EnvName, prod, log) return resp, nil } @@ -190,6 +198,7 @@ func buildProductResp(envName string, prod *commonmodels.Product, log *zap.Sugar ClusterID: prod.ClusterID, RecycleDay: prod.RecycleDay, Source: prod.Source, + RegisterID: prod.RegistryId, } if prod.ClusterID != "" { -- Gitee From 7c06ff2623536f6d42e444289ec25603a8e9434f Mon Sep 17 00:00:00 2001 From: panxunying Date: Mon, 6 Dec 2021 20:02:29 +0800 Subject: [PATCH 041/134] list env response add registryID Signed-off-by: panxunying --- .../aslan/core/environment/service/environment.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pkg/microservice/aslan/core/environment/service/environment.go b/pkg/microservice/aslan/core/environment/service/environment.go index 8cf70deae..86db090cf 100644 --- a/pkg/microservice/aslan/core/environment/service/environment.go +++ b/pkg/microservice/aslan/core/environment/service/environment.go @@ -95,6 +95,7 @@ type EnvResp struct { ClusterName string `json:"clusterName"` Production bool `json:"production"` Source string `json:"source"` + RegistryID string `json:"registry_id"` } type ProductResp struct { @@ -181,11 +182,19 @@ func ListProducts(projectName string, envNames []string, log *zap.SugaredLogger) } var res []*EnvResp + reg, err := commonservice.FindDefaultRegistry(log) + if err != nil { + log.Errorf("FindDefaultRegistry error: %v", err) + return nil, err + } for _, env := range envs { clusterID := env.ClusterID production := false clusterName := "" cluster, ok := clusterMap[clusterID] + if len(env.RegistryId) == 0 { + env.RegistryId = reg.ID.String() + } if ok { production = cluster.Production clusterName = cluster.Name @@ -202,6 +211,7 @@ func ListProducts(projectName string, envNames []string, log *zap.SugaredLogger) Error: env.Error, UpdateTime: env.UpdateTime, UpdateBy: env.UpdateBy, + RegistryID: env.RegistryId, }) } -- Gitee From ed44a68aab95e8b0889cd26e424a76eee4248969 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Mon, 6 Dec 2021 20:52:37 +0800 Subject: [PATCH 042/134] optimize code Signed-off-by: liu deyi --- .../workflow/service/workflow/workflow_task.go | 1 - .../core/service/taskplugin/artifact_deploy.go | 2 +- .../warpdrive/core/service/taskplugin/build.go | 2 +- .../core/service/taskplugin/docker_build.go | 2 +- .../core/service/taskplugin/jenkins_plugin.go | 2 +- .../warpdrive/core/service/taskplugin/job.go | 13 ++++++++++--- .../core/service/taskplugin/release_image.go | 2 +- .../warpdrive/core/service/taskplugin/testing.go | 15 ++++++++++++++- pkg/tool/kube/multicluster/service.go | 6 +++--- 9 files changed, 32 insertions(+), 13 deletions(-) diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go index f7fe5165b..814f56819 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go @@ -1778,7 +1778,6 @@ func ensurePipelineTask(pt *task.Task, envName string, log *zap.SugaredLogger) e // } // } //} - // 设置Pipeline对应的服务名称 if t.ServiceName != "" { pt.ServiceName = t.ServiceName diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/artifact_deploy.go b/pkg/microservice/warpdrive/core/service/taskplugin/artifact_deploy.go index 37059967e..626e235c3 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/artifact_deploy.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/artifact_deploy.go @@ -307,7 +307,7 @@ func (p *ArtifactDeployTaskPlugin) Complete(ctx context.Context, pipelineTask *t } }() - err := saveContainerLog(pipelineTask, p.KubeNamespace, p.FileName, jobLabel, p.kubeClient) + err := saveContainerLog(pipelineTask, p.KubeNamespace, "", p.FileName, jobLabel, p.kubeClient) if err != nil { p.Log.Error(err) p.Task.Error = err.Error() diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/build.go b/pkg/microservice/warpdrive/core/service/taskplugin/build.go index 039ecc9b9..a5b68979f 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/build.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/build.go @@ -343,7 +343,7 @@ func (p *BuildTaskPlugin) Complete(ctx context.Context, pipelineTask *task.Task, return }() - err := saveContainerLog(pipelineTask, p.KubeNamespace, p.FileName, jobLabel, p.kubeClient) + err := saveContainerLog(pipelineTask, p.KubeNamespace, p.Task.ClusterID, p.FileName, jobLabel, p.kubeClient) if err != nil { p.Log.Error(err) p.Task.Error = err.Error() diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/docker_build.go b/pkg/microservice/warpdrive/core/service/taskplugin/docker_build.go index d8ab9b86f..bc358059c 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/docker_build.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/docker_build.go @@ -244,7 +244,7 @@ func (p *DockerBuildPlugin) Complete(ctx context.Context, pipelineTask *task.Tas }() // 保存实时日志到s3 - err := saveContainerLog(pipelineTask, p.KubeNamespace, p.FileName, jobLabel, p.kubeClient) + err := saveContainerLog(pipelineTask, p.KubeNamespace, "", p.FileName, jobLabel, p.kubeClient) if err != nil { p.Log.Error(err) p.Task.Error = err.Error() diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/jenkins_plugin.go b/pkg/microservice/warpdrive/core/service/taskplugin/jenkins_plugin.go index 279e8f52a..fbf8f15f0 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/jenkins_plugin.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/jenkins_plugin.go @@ -233,7 +233,7 @@ func (j *JenkinsBuildPlugin) Complete(ctx context.Context, pipelineTask *task.Ta }() // 保存实时日志到s3 - err := saveContainerLog(pipelineTask, j.KubeNamespace, j.FileName, jobLabel, j.kubeClient) + err := saveContainerLog(pipelineTask, j.KubeNamespace, "", j.FileName, jobLabel, j.kubeClient) if err != nil { j.Log.Error(err) j.Task.Error = err.Error() diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/job.go b/pkg/microservice/warpdrive/core/service/taskplugin/job.go index b34a3ce28..f5ef80a3e 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/job.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/job.go @@ -44,9 +44,9 @@ import ( "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types/task" "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/shared/kube/wrapper" - krkubeclient "github.com/koderover/zadig/pkg/tool/kube/client" "github.com/koderover/zadig/pkg/tool/kube/containerlog" "github.com/koderover/zadig/pkg/tool/kube/getter" + "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/kube/podexec" "github.com/koderover/zadig/pkg/tool/kube/updater" "github.com/koderover/zadig/pkg/tool/log" @@ -77,7 +77,7 @@ func saveFile(src io.Reader, localFile string) error { return err } -func saveContainerLog(pipelineTask *task.Task, namespace, fileName string, jobLabel *JobLabel, kubeClient client.Client) error { +func saveContainerLog(pipelineTask *task.Task, namespace, clusterID, fileName string, jobLabel *JobLabel, kubeClient client.Client) error { selector := labels.Set(getJobLabels(jobLabel)).AsSelector() pods, err := getter.ListPods(namespace, selector, kubeClient) if err != nil { @@ -97,7 +97,14 @@ func saveContainerLog(pipelineTask *task.Task, namespace, fileName string, jobLa sort.SliceStable(pods, func(i, j int) bool { return pods[i].CreationTimestamp.Before(&pods[j].CreationTimestamp) }) - if err := containerlog.GetContainerLogs(namespace, pods[0].Name, pods[0].Spec.Containers[0].Name, false, int64(0), buf, krkubeclient.Clientset()); err != nil { + + clientSet, err := multicluster.GetClientset(pipelineTask.ConfigPayload.HubServerAddr, clusterID) + if err != nil { + log.Errorf("saveContainerLog, get client set error: %s", err) + return err + } + + if err := containerlog.GetContainerLogs(namespace, pods[0].Name, pods[0].Spec.Containers[0].Name, false, int64(0), buf, clientSet); err != nil { return err } diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/release_image.go b/pkg/microservice/warpdrive/core/service/taskplugin/release_image.go index e8b76de5e..8cb98b582 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/release_image.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/release_image.go @@ -232,7 +232,7 @@ func (p *ReleaseImagePlugin) Complete(ctx context.Context, pipelineTask *task.Ta }() // 保存实时日志到s3 - err := saveContainerLog(pipelineTask, p.KubeNamespace, p.FileName, jobLabel, p.kubeClient) + err := saveContainerLog(pipelineTask, p.KubeNamespace, "", p.FileName, jobLabel, p.kubeClient) if err != nil { p.Log.Error(err) p.Task.Error = err.Error() diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go index 88efe4513..bba2c0da7 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go @@ -35,6 +35,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types/task" "github.com/koderover/zadig/pkg/setting" krkubeclient "github.com/koderover/zadig/pkg/tool/kube/client" + "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/kube/updater" s3tool "github.com/koderover/zadig/pkg/tool/s3" "github.com/koderover/zadig/pkg/util" @@ -104,6 +105,18 @@ func (p *TestPlugin) TaskTimeout() int { func (p *TestPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipelineCtx *task.PipelineCtx, serviceName string) { p.KubeNamespace = pipelineTask.ConfigPayload.Test.KubeNamespace + if p.Task.Namespace != "" { + p.KubeNamespace = p.Task.Namespace + kubeClient, err := multicluster.GetKubeClient(pipelineTask.ConfigPayload.HubServerAddr, p.Task.ClusterID) + if err != nil { + msg := fmt.Sprintf("failed to get kube client: %s", err) + p.Log.Error(msg) + p.Task.TaskStatus = config.StatusFailed + p.Task.Error = msg + return + } + p.kubeClient = kubeClient + } // 重置错误信息 p.Task.Error = "" // 获取测试相关的namespace @@ -270,7 +283,7 @@ func (p *TestPlugin) Complete(ctx context.Context, pipelineTask *task.Task, serv return }() - err := saveContainerLog(pipelineTask, p.KubeNamespace, p.FileName, jobLabel, p.kubeClient) + err := saveContainerLog(pipelineTask, p.KubeNamespace, p.Task.ClusterID, p.FileName, jobLabel, p.kubeClient) if err != nil { p.Log.Error(err) p.Task.Error = err.Error() diff --git a/pkg/tool/kube/multicluster/service.go b/pkg/tool/kube/multicluster/service.go index 3e0ad316f..eb6e6aeca 100644 --- a/pkg/tool/kube/multicluster/service.go +++ b/pkg/tool/kube/multicluster/service.go @@ -46,7 +46,7 @@ func GetKubeClient(hubServerAddr, clusterID string) (client.Client, error) { } func GetKubeAPIReader(hubServerAddr, clusterID string) (client.Reader, error) { - if clusterID == "" { + if clusterID == "" || clusterID == setting.LocalClusterID { return krkubeclient.APIReader(), nil } @@ -59,7 +59,7 @@ func GetKubeAPIReader(hubServerAddr, clusterID string) (client.Reader, error) { } func GetRESTConfig(hubServerAddr, clusterID string) (*rest.Config, error) { - if clusterID == "" { + if clusterID == "" || clusterID == setting.LocalClusterID { return krkubeclient.RESTConfig(), nil } @@ -68,7 +68,7 @@ func GetRESTConfig(hubServerAddr, clusterID string) (*rest.Config, error) { // GetClientset returns a client to interact with APIServer which implements kubernetes.Interface func GetClientset(hubServerAddr, clusterID string) (kubernetes.Interface, error) { - if clusterID == "" { + if clusterID == "" || clusterID == setting.LocalClusterID { return krkubeclient.Clientset(), nil } -- Gitee From f8b958b8d6891e8b765158fbe254852bb72d410b Mon Sep 17 00:00:00 2001 From: liu deyi Date: Mon, 6 Dec 2021 21:10:54 +0800 Subject: [PATCH 043/134] clean job Signed-off-by: liu deyi --- .../warpdrive/core/service/taskplugin/build.go | 16 +++++++--------- .../warpdrive/core/service/taskplugin/testing.go | 16 +++++++--------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/build.go b/pkg/microservice/warpdrive/core/service/taskplugin/build.go index a5b68979f..1f4e38866 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/build.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/build.go @@ -328,16 +328,14 @@ func (p *BuildTaskPlugin) Complete(ctx context.Context, pipelineTask *task.Task, // 清理用户取消和超时的任务 defer func() { - if p.Task.TaskStatus == config.StatusCancelled || p.Task.TaskStatus == config.StatusTimeout { - if err := ensureDeleteJob(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { - p.Log.Error(err) - p.Task.Error = err.Error() - } + if err := ensureDeleteJob(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + p.Log.Error(err) + p.Task.Error = err.Error() + } - if err := ensureDeleteConfigMap(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { - p.Log.Error(err) - p.Task.Error = err.Error() - } + if err := ensureDeleteConfigMap(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + p.Log.Error(err) + p.Task.Error = err.Error() } return diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go index bba2c0da7..325f7168b 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go @@ -270,15 +270,13 @@ func (p *TestPlugin) Complete(ctx context.Context, pipelineTask *task.Task, serv // 日志保存失败与否都清理job defer func() { - if p.Task.TaskStatus == config.StatusCancelled || p.Task.TaskStatus == config.StatusTimeout { - if err := ensureDeleteJob(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { - p.Log.Error(err) - p.Task.Error = err.Error() - } - if err := ensureDeleteConfigMap(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { - p.Log.Error(err) - p.Task.Error = err.Error() - } + if err := ensureDeleteJob(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + p.Log.Error(err) + p.Task.Error = err.Error() + } + if err := ensureDeleteConfigMap(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + p.Log.Error(err) + p.Task.Error = err.Error() } return }() -- Gitee From e17c125b9ff7826ac613e4f83d4cd0c6c07dcac2 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Mon, 6 Dec 2021 21:24:19 +0800 Subject: [PATCH 044/134] modify test task Signed-off-by: liu deyi --- .../aslan/core/workflow/service/workflow/pipeline_task.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_task.go index 31feb5d75..f60fea433 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_task.go @@ -567,6 +567,7 @@ func TestArgsToTestSubtask(args *commonmodels.TestTaskArgs, pt *task.Task, log * TestName: "test", Timeout: testModule.Timeout, } + testTask.TestModuleName = testModule.Name testTask.JobCtx.TestType = testModule.TestType testTask.JobCtx.Builds = testModule.Repos @@ -588,6 +589,8 @@ func TestArgsToTestSubtask(args *commonmodels.TestTaskArgs, pt *task.Task, log * testTask.InstallItems = testModule.PreTest.Installs testTask.JobCtx.CleanWorkspace = testModule.PreTest.CleanWorkspace testTask.JobCtx.EnableProxy = testModule.PreTest.EnableProxy + testTask.Namespace = testModule.PreTest.Namespace + testTask.ClusterID = testModule.PreTest.ClusterID envs := testModule.PreTest.Envs[:] -- Gitee From 4a998e66cdb8fed1ca3d48c84713856ba078e45e Mon Sep 17 00:00:00 2001 From: liu deyi Date: Mon, 6 Dec 2021 21:31:50 +0800 Subject: [PATCH 045/134] modify test task Signed-off-by: liu deyi --- .../aslan/core/workflow/service/workflow/workflow_task.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go index 814f56819..71f5f63a3 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go @@ -1211,6 +1211,8 @@ func testArgsToSubtask(args *commonmodels.WorkflowTaskArgs, pt *task.Task, log * testTask.InstallItems = testModule.PreTest.Installs testTask.JobCtx.CleanWorkspace = testModule.PreTest.CleanWorkspace testTask.JobCtx.EnableProxy = testModule.PreTest.EnableProxy + testTask.Namespace = testModule.PreTest.Namespace + testTask.ClusterID = testModule.PreTest.ClusterID envs := testModule.PreTest.Envs[:] -- Gitee From 9d2f1711abd64fc8e7256a13c0965e453024928d Mon Sep 17 00:00:00 2001 From: liu deyi Date: Tue, 7 Dec 2021 09:43:00 +0800 Subject: [PATCH 046/134] modify the import order of dependent packages Signed-off-by: liu deyi --- .../warpdrive/core/service/types/task/config_payload.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go index 313af2d79..a8827cfea 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go +++ b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go @@ -19,9 +19,9 @@ package task import ( "fmt" - "github.com/koderover/zadig/pkg/setting" - "go.mongodb.org/mongo-driver/bson/primitive" + + "github.com/koderover/zadig/pkg/setting" ) type ConfigPayload struct { -- Gitee From 2abdaa87c1ca7d9e65cb12e5c808a851565391d1 Mon Sep 17 00:00:00 2001 From: panxunying Date: Tue, 7 Dec 2021 10:24:33 +0800 Subject: [PATCH 047/134] optimize create helm product Signed-off-by: panxunying --- .../core/environment/handler/environment.go | 25 ++++++++----------- .../core/environment/service/environment.go | 5 ++-- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/pkg/microservice/aslan/core/environment/handler/environment.go b/pkg/microservice/aslan/core/environment/handler/environment.go index 6a1f5119a..6998191c8 100644 --- a/pkg/microservice/aslan/core/environment/handler/environment.go +++ b/pkg/microservice/aslan/core/environment/handler/environment.go @@ -130,11 +130,6 @@ func createHelmProduct(c *gin.Context, ctx *internalhandler.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("projectName can not be empty") return } - registryID := c.Query("registryID") - if registryID == "" { - ctx.Err = e.ErrInvalidParam.AddDesc("registryID can not be empty") - return - } createArgs := make([]*service.CreateHelmProductArg, 0) data, err := c.GetRawData() if err != nil { @@ -160,7 +155,7 @@ func createHelmProduct(c *gin.Context, ctx *internalhandler.Context) { internalhandler.InsertOperationLog(c, ctx.UserName, projectName, "新增", "集成环境", strings.Join(envNameList, "-"), string(data), ctx.Logger) ctx.Err = service.CreateHelmProduct( - projectName, ctx.UserName, ctx.RequestID, registryID, createArgs, ctx.Logger, + projectName, ctx.UserName, ctx.RequestID, createArgs, ctx.Logger, ) } @@ -168,15 +163,6 @@ func CreateProduct(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - args := new(commonmodels.Product) - data, err := c.GetRawData() - if err != nil { - log.Errorf("CreateProduct c.GetRawData() err : %v", err) - } - if err = json.Unmarshal(data, args); err != nil { - log.Errorf("CreateProduct json.Unmarshal err : %v", err) - } - if c.Query("auto") == "true" { ctx.Resp = service.AutoCreateProduct(c.Query("projectName"), c.Query("envType"), ctx.RequestID, ctx.Logger) return @@ -186,6 +172,15 @@ func CreateProduct(c *gin.Context) { return } + args := new(commonmodels.Product) + data, err := c.GetRawData() + if err != nil { + log.Errorf("CreateProduct c.GetRawData() err : %v", err) + } + if err = json.Unmarshal(data, args); err != nil { + log.Errorf("CreateProduct json.Unmarshal err : %v", err) + } + allowedClusters, found := internalhandler.GetResourcesInHeader(c) if found { allowedSet := sets.NewString(allowedClusters...) diff --git a/pkg/microservice/aslan/core/environment/service/environment.go b/pkg/microservice/aslan/core/environment/service/environment.go index 86db090cf..404fa3930 100644 --- a/pkg/microservice/aslan/core/environment/service/environment.go +++ b/pkg/microservice/aslan/core/environment/service/environment.go @@ -147,6 +147,7 @@ type CreateHelmProductArg struct { Namespace string `json:"namespace"` ClusterID string `json:"clusterID"` DefaultValues string `json:"defaultValues"` + RegistryID string `json:"registry_id"` ChartValues []*commonservice.RenderChartArg `json:"chartValues"` } @@ -677,7 +678,7 @@ func UpdateProductV2(envName, productName, user, requestID string, force bool, k return nil } -func CreateHelmProduct(productName, userName, requestID, registryID string, args []*CreateHelmProductArg, log *zap.SugaredLogger) error { +func CreateHelmProduct(productName, userName, requestID string, args []*CreateHelmProductArg, log *zap.SugaredLogger) error { templateProduct, err := templaterepo.NewProductColl().Find(productName) if err != nil || templateProduct == nil { if err != nil { @@ -734,7 +735,7 @@ func CreateHelmProduct(productName, userName, requestID, registryID string, args errList := new(multierror.Error) for _, arg := range args { - err = createSingleHelmProduct(templateProduct, serviceGroup, requestID, userName, registryID, arg, log) + err = createSingleHelmProduct(templateProduct, serviceGroup, requestID, userName, arg.RegistryID, arg, log) if err != nil { errList = multierror.Append(errList, err) } -- Gitee From 7b41d9a9785a2cec3b888cf287bb3bb284369a52 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Tue, 7 Dec 2021 13:47:23 +0800 Subject: [PATCH 048/134] modify the import order of dependent packages Signed-off-by: liu deyi --- pkg/microservice/warpdrive/core/service/taskplugin/build.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/build.go b/pkg/microservice/warpdrive/core/service/taskplugin/build.go index 1f4e38866..941be3e30 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/build.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/build.go @@ -24,8 +24,6 @@ import ( "strings" "time" - "github.com/koderover/zadig/pkg/tool/kube/multicluster" - "go.uber.org/zap" "gopkg.in/yaml.v3" "k8s.io/apimachinery/pkg/util/sets" @@ -35,6 +33,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types/task" "github.com/koderover/zadig/pkg/setting" krkubeclient "github.com/koderover/zadig/pkg/tool/kube/client" + "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/kube/updater" ) -- Gitee From 0d74a7eb5b2e63e0a700d93f4bc2e4b6298c5bf3 Mon Sep 17 00:00:00 2001 From: panxunying Date: Tue, 7 Dec 2021 14:01:28 +0800 Subject: [PATCH 049/134] fix worflow cant find registry Signed-off-by: panxunying --- .../aslan/core/workflow/service/workflow/workflow_task.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go index 28bd0f74e..b0f58e477 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go @@ -1778,10 +1778,10 @@ func ensurePipelineTask(pt *task.Task, envName string, log *zap.SugaredLogger) e setManunalBuilds(t.JobCtx.Builds, pt.TaskArgs.Builds, log) } - opt := &commonrepo.ProductFindOptions{Namespace: envName} + opt := &commonrepo.ProductFindOptions{Name: pt.ProductName} exitedProd, err := commonrepo.NewProductColl().Find(opt) if err != nil { - log.Errorf("can't find product by namespace:%s error msg: %v", envName, err) + log.Errorf("can't find product by name:%s error msg: %v", pt.ProductName, err) return e.ErrFindRegistry.AddDesc(err.Error()) } @@ -1794,6 +1794,7 @@ func ensurePipelineTask(pt *task.Task, envName string, log *zap.SugaredLogger) e var reg *commonmodels.RegistryNamespace if len(exitedProd.RegistryId) > 0 { reg, err = commonservice.FindRegistryById(exitedProd.RegistryId, log) + log.Infof("FindRegistryById %s", exitedProd.RegistryId) if err != nil { log.Errorf("service.EnsureRegistrySecret: failed to find registry: %s error msg:%v", exitedProd.RegistryId, err) -- Gitee From ded40ff6f238c6bb4c7bea99f50ef609bb19ab9d Mon Sep 17 00:00:00 2001 From: liu deyi Date: Tue, 7 Dec 2021 14:25:06 +0800 Subject: [PATCH 050/134] optimize the way to obtain reaper Signed-off-by: liu deyi --- .../warpdrive/core/service/taskplugin/job.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/job.go b/pkg/microservice/warpdrive/core/service/taskplugin/job.go index f5ef80a3e..0f10d1ebb 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/job.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/job.go @@ -409,14 +409,21 @@ func buildJob(taskType config.TaskType, jobImage, jobName, serviceName, clusterI } func buildJobWithLinkedNs(taskType config.TaskType, jobImage, jobName, serviceName, clusterID string, resReq setting.Request, resReqSpec setting.RequestSpec, ctx *task.PipelineCtx, pipelineTask *task.Task, registries []*task.RegistryNamespace, execNs, linkedNs string) (*batchv1.Job, error) { - var reaperBootingScript string + var ( + reaperBootingScript string + reaperBinaryFile = pipelineTask.ConfigPayload.Release.ReaperBinaryFile + ) + // not local cluster + if clusterID != "" && clusterID != setting.LocalClusterID { + reaperBinaryFile = strings.Replace(reaperBinaryFile, "resource-server", "resource-server.koderover-agent", -1) + } if !strings.Contains(jobImage, PredatorPlugin) && !strings.Contains(jobImage, JenkinsPlugin) { - reaperBootingScript = fmt.Sprintf("curl -m 60 --retry-delay 5 --retry 3 -sL %s -o reaper && chmod +x reaper && mv reaper /usr/local/bin && /usr/local/bin/reaper", pipelineTask.ConfigPayload.Release.ReaperBinaryFile) + reaperBootingScript = fmt.Sprintf("curl -m 60 --retry-delay 5 --retry 3 -sL %s -o reaper && chmod +x reaper && mv reaper /usr/local/bin && /usr/local/bin/reaper", reaperBinaryFile) if pipelineTask.ConfigPayload.Proxy.EnableApplicationProxy && pipelineTask.ConfigPayload.Proxy.Type == "http" { reaperBootingScript = fmt.Sprintf("curl -m 60 --retry-delay 5 --retry 3 -sL --proxy %s %s -o reaper && chmod +x reaper && mv reaper /usr/local/bin && /usr/local/bin/reaper", pipelineTask.ConfigPayload.Proxy.GetProxyURL(), - pipelineTask.ConfigPayload.Release.ReaperBinaryFile, + reaperBinaryFile, ) } } -- Gitee From 969ddcd64cbb2653997d9aa12ff44eb35735b72d Mon Sep 17 00:00:00 2001 From: liu deyi Date: Tue, 7 Dec 2021 14:42:13 +0800 Subject: [PATCH 051/134] optimize code Signed-off-by: liu deyi --- .../warpdrive/core/service/taskplugin/job.go | 28 +++++++------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/job.go b/pkg/microservice/warpdrive/core/service/taskplugin/job.go index 0f10d1ebb..72c578d1f 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/job.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/job.go @@ -841,17 +841,18 @@ func addNodeAffinity(clusterID string, K8SClusters []*task.K8SCluster) *corev1.A return nil } + nodeLabelM := make(map[string][]string, 0) + for _, nodeLabel := range clusterConfig.NodeLabels { + if !strings.Contains(nodeLabel, ":") || len(strings.Split(nodeLabel, ":")) != 2 { + continue + } + key := strings.Split(nodeLabel, ":")[0] + value := strings.Split(nodeLabel, ":")[1] + nodeLabelM[key] = append(nodeLabelM[key], value) + } + switch clusterConfig.Strategy { case RequiredSchedule: - nodeLabelM := make(map[string][]string, 0) - for _, nodeLabel := range clusterConfig.NodeLabels { - if !strings.Contains(nodeLabel, ":") || len(strings.Split(nodeLabel, ":")) != 2 { - continue - } - key := strings.Split(nodeLabel, ":")[0] - value := strings.Split(nodeLabel, ":")[1] - nodeLabelM[key] = append(nodeLabelM[key], value) - } nodeSelectorTerms := make([]corev1.NodeSelectorTerm, 0) for key, value := range nodeLabelM { var matchExpressions []corev1.NodeSelectorRequirement @@ -874,15 +875,6 @@ func addNodeAffinity(clusterID string, K8SClusters []*task.K8SCluster) *corev1.A } return affinity case PreferredSchedule: - nodeLabelM := make(map[string][]string, 0) - for _, nodeLabel := range clusterConfig.NodeLabels { - if !strings.Contains(nodeLabel, ":") || len(strings.Split(nodeLabel, ":")) != 2 { - continue - } - key := strings.Split(nodeLabel, ":")[0] - value := strings.Split(nodeLabel, ":")[1] - nodeLabelM[key] = append(nodeLabelM[key], value) - } preferredScheduleTerms := make([]corev1.PreferredSchedulingTerm, 0) for key, value := range nodeLabelM { var matchExpressions []corev1.NodeSelectorRequirement -- Gitee From 768ef571601b2dfec8d9ca00949086f07da19079 Mon Sep 17 00:00:00 2001 From: panxunying Date: Tue, 7 Dec 2021 14:51:28 +0800 Subject: [PATCH 052/134] optimize Signed-off-by: panxunying --- .../aslan/core/environment/handler/environment.go | 9 +++++---- .../aslan/core/environment/service/environment.go | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/pkg/microservice/aslan/core/environment/handler/environment.go b/pkg/microservice/aslan/core/environment/handler/environment.go index 6998191c8..ef9f41c3c 100644 --- a/pkg/microservice/aslan/core/environment/handler/environment.go +++ b/pkg/microservice/aslan/core/environment/handler/environment.go @@ -255,28 +255,29 @@ func UpdateProductRegistry(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - namespace := c.Param("namespace") projectName := c.Query("projectName") args := new(commonmodels.Product) data, err := c.GetRawData() if err != nil { log.Errorf("UpdateProduct c.GetRawData() err : %v", err) + ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) + return } if err = json.Unmarshal(data, args); err != nil { log.Errorf("UpdateProduct json.Unmarshal err : %v", err) ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) return } - internalhandler.InsertOperationLog(c, ctx.UserName, projectName, "更新", "集成环境", namespace, string(data), ctx.Logger) + internalhandler.InsertOperationLog(c, ctx.UserName, projectName, "更新", "集成环境", args.Namespace, string(data), ctx.Logger) c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) if err := c.BindJSON(args); err != nil { ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) return } - ctx.Err = service.UpdateProductRegistry(namespace, args.RegistryId, ctx.Logger) + ctx.Err = service.UpdateProductRegistry(args.Namespace, args.RegistryId, ctx.Logger) if ctx.Err != nil { - ctx.Logger.Errorf("failed to update product %s %s: %v", namespace, args.RegistryId, ctx.Err) + ctx.Logger.Errorf("failed to update product %s %s: %v", args.Namespace, args.RegistryId, ctx.Err) } } diff --git a/pkg/microservice/aslan/core/environment/service/environment.go b/pkg/microservice/aslan/core/environment/service/environment.go index 404fa3930..597af6ded 100644 --- a/pkg/microservice/aslan/core/environment/service/environment.go +++ b/pkg/microservice/aslan/core/environment/service/environment.go @@ -116,7 +116,7 @@ type ProductResp struct { RecycleDay int `json:"recycle_day"` IsProd bool `json:"is_prod"` Source string `json:"source"` - RegisterID string `json:"register_id"` + RegisterID string `json:"registry_id"` } type ProductParams struct { -- Gitee From f88b65c284f45f6cb84d236652667896651fed88 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Tue, 7 Dec 2021 20:55:55 +0800 Subject: [PATCH 053/134] optimize Signed-off-by: liu deyi --- pkg/microservice/aslan/core/log/service/sse.go | 12 ++++++------ pkg/shared/kube/client/client.go | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) create mode 100644 pkg/shared/kube/client/client.go diff --git a/pkg/microservice/aslan/core/log/service/sse.go b/pkg/microservice/aslan/core/log/service/sse.go index 7ae80d0cb..af913bd6c 100644 --- a/pkg/microservice/aslan/core/log/service/sse.go +++ b/pkg/microservice/aslan/core/log/service/sse.go @@ -120,14 +120,14 @@ func TaskContainerLogStream(ctx context.Context, streamChan chan interface{}, op return } log.Debugf("Start to get task container log.") - if options.EnvName != "" && options.ProductName != "" { + // Cloud host scenario reads real-time logs from the environment, so pipelineName is empty + if options.EnvName != "" && options.ProductName != "" && options.PipelineName == "" { //修改pipelineName,判断pipelineName是否为空,为空代表是来自环境里面请求,不为空代表是来自工作流任务的请求 - if options.PipelineName == "" { - options.PipelineName = fmt.Sprintf("%s-%s-%s", options.ServiceName, options.EnvName, "job") - if taskObj, err := commonrepo.NewTaskColl().FindTask(options.PipelineName, config.ServiceType); err == nil { - options.TaskID = taskObj.TaskID - } + options.PipelineName = fmt.Sprintf("%s-%s-%s", options.ServiceName, options.EnvName, "job") + if taskObj, err := commonrepo.NewTaskColl().FindTask(options.PipelineName, config.ServiceType); err == nil { + options.TaskID = taskObj.TaskID } + // Need to get build info based on the project name and service component name, then get clusterID and namespace } else if options.ProductName != "" { build, err := commonrepo.NewBuildColl().Find(&commonrepo.BuildFindOption{ ProductName: options.ProductName, diff --git a/pkg/shared/kube/client/client.go b/pkg/shared/kube/client/client.go new file mode 100644 index 000000000..f84e1e4e1 --- /dev/null +++ b/pkg/shared/kube/client/client.go @@ -0,0 +1 @@ +package kube -- Gitee From 831601955ebb641b4e595230fba4734e0b52ff41 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Tue, 7 Dec 2021 20:59:03 +0800 Subject: [PATCH 054/134] optimize code Signed-off-by: liu deyi --- pkg/cli/initconfig/cmd/init.go | 24 +-- pkg/config/config.go | 4 + .../common/repository/models/k8s_cluster.go | 79 ++++----- .../core/common/repository/models/queue.go | 4 +- .../common/repository/mongodb/k8s_cluster.go | 2 +- .../core/common/service/config_payload.go | 10 +- .../aslan/core/common/service/environment.go | 4 +- .../aslan/core/common/service/kube/service.go | 7 +- .../aslan/core/common/service/product.go | 4 +- .../core/environment/service/configmap.go | 8 +- .../core/environment/service/environment.go | 8 +- .../service/environment_creator.go | 6 +- .../environment/service/environment_group.go | 4 +- .../aslan/core/environment/service/export.go | 4 +- .../aslan/core/environment/service/image.go | 4 +- .../aslan/core/environment/service/k8s.go | 4 +- .../aslan/core/environment/service/kube.go | 18 +-- .../aslan/core/environment/service/service.go | 14 +- .../aslan/core/log/service/sse.go | 14 +- .../core/multicluster/handler/clusters.go | 5 +- .../core/multicluster/service/clusters.go | 152 +++++++++++++++--- .../aslan/core/service/service/service.go | 6 +- .../aslan/core/system/service/registry.go | 6 +- .../service/workflow/pipeline_validation.go | 4 +- .../core/service/taskplugin/build.go | 4 +- .../core/service/taskplugin/deploy.go | 6 +- .../warpdrive/core/service/taskplugin/job.go | 36 ++--- .../core/service/taskplugin/testing.go | 4 +- .../core/service/types/task/config_payload.go | 27 ++-- pkg/shared/client/aslan/multicluster.go | 21 ++- pkg/shared/kube/client/client.go | 40 ++++- pkg/shared/kube/resource/node.go | 2 +- pkg/shared/kube/wrapper/namespace.go | 2 +- pkg/tool/kube/multicluster/service.go | 9 +- 34 files changed, 334 insertions(+), 212 deletions(-) diff --git a/pkg/cli/initconfig/cmd/init.go b/pkg/cli/initconfig/cmd/init.go index 8d85e22ce..00add4ae7 100644 --- a/pkg/cli/initconfig/cmd/init.go +++ b/pkg/cli/initconfig/cmd/init.go @@ -102,8 +102,8 @@ func initSystemConfig() error { return err } - if err := createMultiCluster(); err != nil { - log.Errorf("createMultiCluster err:%s", err) + if err := createLocalCluster(); err != nil { + log.Errorf("createLocalCluster err:%s", err) return err } @@ -203,20 +203,10 @@ func presetRole() error { return nil } -func createMultiCluster() error { - clusters, err := aslan.New(config.AslanServiceAddress()).ListMultiCluster() - if err != nil { - return err +func createLocalCluster() error { + cluster, _ := aslan.New(config.AslanServiceAddress()).GetCluster() + if cluster != nil { + return nil } - var hasLocal bool - for _, cluster := range clusters { - if cluster.Local { - hasLocal = true - break - } - } - if !hasLocal { - return aslan.New(config.AslanServiceAddress()).AddMultiCluster() - } - return nil + return aslan.New(config.AslanServiceAddress()).AddLocalCluster() } diff --git a/pkg/config/config.go b/pkg/config/config.go index 78ff45336..593eff9c1 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -257,3 +257,7 @@ func AdminEmail() string { func AdminPassword() string { return viper.GetString(setting.ENVAdminPassword) } + +func Namespace() string { + return viper.GetString(setting.ENVNamespace) +} diff --git a/pkg/microservice/aslan/core/common/repository/models/k8s_cluster.go b/pkg/microservice/aslan/core/common/repository/models/k8s_cluster.go index bbc32146b..767d94490 100644 --- a/pkg/microservice/aslan/core/common/repository/models/k8s_cluster.go +++ b/pkg/microservice/aslan/core/common/repository/models/k8s_cluster.go @@ -17,35 +17,36 @@ limitations under the License. package models import ( - "fmt" - "regexp" - "strings" - "go.mongodb.org/mongo-driver/bson/primitive" + corev1 "k8s.io/api/core/v1" "github.com/koderover/zadig/pkg/setting" ) -var namePattern = regexp.MustCompile(`^[0-9a-zA-Z_.-]{1,32}$`) - type K8SCluster struct { - ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` - Name string `json:"name" bson:"name"` - Tags []string `json:"tags" bson:"tags"` - Description string `json:"description" bson:"description"` - Namespace string `json:"namespace" bson:"namespace"` - Info *K8SClusterInfo `json:"info,omitempty" bson:"info,omitempty"` - ClusterConfig *ClusterConfig `json:"config,omitempty" bson:"config,omitempty"` - Status setting.K8SClusterStatus `json:"status" bson:"status"` - Error string `json:"error" bson:"error"` - Yaml string `json:"yaml" bson:"yaml"` - Production bool `json:"production" bson:"production"` - CreatedAt int64 `json:"createdAt" bson:"createdAt"` - CreatedBy string `json:"createdBy" bson:"createdBy"` - Disconnected bool `json:"-" bson:"disconnected"` - Token string `json:"token" bson:"-"` - Provider int8 `json:"provider" bson:"provider"` - Local bool `json:"local" bson:"local"` + ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` + Name string `json:"name" bson:"name"` + Tags []string `json:"tags" bson:"tags"` + Description string `json:"description" bson:"description"` + Namespace string `json:"namespace" bson:"namespace"` + Info *K8SClusterInfo `json:"info,omitempty" bson:"info,omitempty"` + AdvancedConfig *AdvancedConfig `json:"config,omitempty" bson:"config,omitempty"` + Status setting.K8SClusterStatus `json:"status" bson:"status"` + Error string `json:"error" bson:"error"` + Yaml string `json:"yaml" bson:"yaml"` + Production bool `json:"production" bson:"production"` + CreatedAt int64 `json:"createdAt" bson:"createdAt"` + CreatedBy string `json:"createdBy" bson:"createdBy"` + Disconnected bool `json:"-" bson:"disconnected"` + Token string `json:"token" bson:"-"` + Provider int8 `json:"provider" bson:"provider"` + Local bool `json:"local" bson:"local"` +} + +type K8SClusterResp struct { + ID string `json:"id,omitempty" bson:"_id,omitempty"` + Name string `json:"name" bson:"name"` + AdvancedConfig *AdvancedConfig `json:"config,omitempty" bson:"config,omitempty"` } type K8SClusterInfo struct { @@ -55,31 +56,17 @@ type K8SClusterInfo struct { Memory string `json:"memory" bson:"memory"` } -type ClusterConfig struct { - Strategy string `json:"strategy,omitempty" bson:"strategy,omitempty"` - NodeLabels []string `json:"node_labels,omitempty" bson:"node_labels,omitempty"` +type AdvancedConfig struct { + Strategy string `json:"strategy,omitempty" bson:"strategy,omitempty"` + NodeLabels []*NodeSelectorRequirement `json:"node_labels,omitempty" bson:"node_labels,omitempty"` } -func (K8SCluster) TableName() string { - return "k8s_cluster" +type NodeSelectorRequirement struct { + Key string `json:"key"` + Value []string `json:"value"` + Operator corev1.NodeSelectorOperator `json:"operator"` } -func (k *K8SCluster) Clean() error { - k.Name = strings.TrimSpace(k.Name) - tags := k.Tags - k.Tags = []string{} - for _, tag := range tags { - tag = strings.TrimSpace(tag) - if tag != "" { - k.Tags = append(k.Tags, tag) - } - } - - k.Description = strings.TrimSpace(k.Description) - - if !namePattern.MatchString(k.Name) { - return fmt.Errorf("集群名称不符合规则") - } - - return nil +func (K8SCluster) TableName() string { + return "k8s_cluster" } diff --git a/pkg/microservice/aslan/core/common/repository/models/queue.go b/pkg/microservice/aslan/core/common/repository/models/queue.go index 5edfa0b90..973097c9b 100644 --- a/pkg/microservice/aslan/core/common/repository/models/queue.go +++ b/pkg/microservice/aslan/core/common/repository/models/queue.go @@ -126,7 +126,7 @@ type ConfigPayload struct { CustomDNSSupported bool `json:"custom_dns_supported"` HubServerAddr string DeployClusterID string - AesKey string + AesKey string `bson:"-" json:"aes_key"` RepoConfigs map[string]*RegistryNamespace @@ -137,7 +137,7 @@ type ConfigPayload struct { ResetCache bool `json:"reset_cache"` JenkinsBuildConfig JenkinsBuildConfig `json:"jenkins_build_config"` PrivateKeys []*PrivateKey `json:"private_keys"` - K8SClusters []*K8SCluster `json:"k8s_cluster"` + K8SClusters []*K8SClusterResp `bson:"-" json:"k8s_cluster"` } type AslanConfig struct { diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/k8s_cluster.go b/pkg/microservice/aslan/core/common/repository/mongodb/k8s_cluster.go index 8daf229f3..207d8c2a7 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/k8s_cluster.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/k8s_cluster.go @@ -185,7 +185,7 @@ func (c *K8SClusterColl) UpdateMutableFields(cluster *models.K8SCluster) error { "tags": cluster.Tags, "namespace": cluster.Namespace, "production": cluster.Production, - "config": cluster.ClusterConfig, + "config": cluster.AdvancedConfig, }}, ) diff --git a/pkg/microservice/aslan/core/common/service/config_payload.go b/pkg/microservice/aslan/core/common/service/config_payload.go index fb38f9edc..c4981fd53 100644 --- a/pkg/microservice/aslan/core/common/service/config_payload.go +++ b/pkg/microservice/aslan/core/common/service/config_payload.go @@ -93,7 +93,15 @@ func GetConfigPayload(codeHostID int) *models.ConfigPayload { k8sClusters, _ := mongodb.NewK8SClusterColl().List(nil) if len(k8sClusters) != 0 { - payload.K8SClusters = k8sClusters + var K8SClusterResp []*models.K8SClusterResp + for _, k8sCluster := range k8sClusters { + K8SClusterResp = append(K8SClusterResp, &models.K8SClusterResp{ + ID: k8sCluster.ID.Hex(), + Name: k8sCluster.Name, + AdvancedConfig: k8sCluster.AdvancedConfig, + }) + } + payload.K8SClusters = K8SClusterResp } return payload } diff --git a/pkg/microservice/aslan/core/common/service/environment.go b/pkg/microservice/aslan/core/common/service/environment.go index 61b2cddce..f2b50cf28 100644 --- a/pkg/microservice/aslan/core/common/service/environment.go +++ b/pkg/microservice/aslan/core/common/service/environment.go @@ -32,11 +32,11 @@ import ( commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" templaterepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb/template" "github.com/koderover/zadig/pkg/setting" + "github.com/koderover/zadig/pkg/shared/kube/client" "github.com/koderover/zadig/pkg/shared/kube/resource" "github.com/koderover/zadig/pkg/shared/kube/wrapper" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/kube/getter" - "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/util" jsonutil "github.com/koderover/zadig/pkg/util/json" ) @@ -209,7 +209,7 @@ func ListWorkloads(envName, clusterID, namespace, productName string, perPage, p log.Infof("Start to list workloads in namespace %s", namespace) var resp = make([]*ServiceResp, 0) - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), clusterID) + kubeClient, err := client.GetKubeClient(config.HubServerAddress(), clusterID) if err != nil { log.Errorf("[%s][%s] error: %v", envName, namespace, err) return 0, resp, e.ErrListGroups.AddDesc(err.Error()) diff --git a/pkg/microservice/aslan/core/common/service/kube/service.go b/pkg/microservice/aslan/core/common/service/kube/service.go index e13a813a9..1b650fa52 100644 --- a/pkg/microservice/aslan/core/common/service/kube/service.go +++ b/pkg/microservice/aslan/core/common/service/kube/service.go @@ -32,22 +32,23 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" "github.com/koderover/zadig/pkg/setting" + client2 "github.com/koderover/zadig/pkg/shared/kube/client" "github.com/koderover/zadig/pkg/tool/crypto" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/kube/multicluster" ) func GetKubeAPIReader(clusterID string) (client.Reader, error) { - return multicluster.GetKubeAPIReader(config.HubServerAddress(), clusterID) + return client2.GetKubeAPIReader(config.HubServerAddress(), clusterID) } func GetRESTConfig(clusterID string) (*rest.Config, error) { - return multicluster.GetRESTConfig(config.HubServerAddress(), clusterID) + return client2.GetRESTConfig(config.HubServerAddress(), clusterID) } // GetClientset returns a client to interact with APIServer which implements kubernetes.Interface func GetClientset(clusterID string) (kubernetes.Interface, error) { - return multicluster.GetClientset(config.HubServerAddress(), clusterID) + return client2.GetClientset(config.HubServerAddress(), clusterID) } type Service struct { diff --git a/pkg/microservice/aslan/core/common/service/product.go b/pkg/microservice/aslan/core/common/service/product.go index 2a024a065..e336b30d2 100644 --- a/pkg/microservice/aslan/core/common/service/product.go +++ b/pkg/microservice/aslan/core/common/service/product.go @@ -21,6 +21,7 @@ import ( "time" "github.com/hashicorp/go-multierror" + client2 "github.com/koderover/zadig/pkg/shared/kube/client" helmclient "github.com/mittwald/go-helm-client" "go.uber.org/zap" "k8s.io/apimachinery/pkg/labels" @@ -37,7 +38,6 @@ import ( "github.com/koderover/zadig/pkg/setting" e "github.com/koderover/zadig/pkg/tool/errors" helmtool "github.com/koderover/zadig/pkg/tool/helmclient" - "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/kube/updater" ) @@ -53,7 +53,7 @@ func DeleteProduct(username, envName, productName, requestID string, log *zap.Su return e.ErrDeleteEnv.AddDesc("not found") } - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), productInfo.ClusterID) + kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), productInfo.ClusterID) if err != nil { return e.ErrDeleteEnv.AddErr(err) } diff --git a/pkg/microservice/aslan/core/environment/service/configmap.go b/pkg/microservice/aslan/core/environment/service/configmap.go index 038b0f07f..a3d634019 100644 --- a/pkg/microservice/aslan/core/environment/service/configmap.go +++ b/pkg/microservice/aslan/core/environment/service/configmap.go @@ -33,10 +33,10 @@ import ( commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" + client2 "github.com/koderover/zadig/pkg/shared/kube/client" "github.com/koderover/zadig/pkg/shared/kube/wrapper" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/kube/getter" - "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/kube/updater" "github.com/koderover/zadig/pkg/tool/kube/util" ) @@ -100,7 +100,7 @@ func ListConfigMaps(args *ListConfigMapArgs, log *zap.SugaredLogger) ([]*configM if err != nil { return nil, e.ErrListConfigMaps.AddErr(err) } - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), product.ClusterID) + kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), product.ClusterID) if err != nil { return nil, e.ErrListConfigMaps.AddErr(err) } @@ -155,7 +155,7 @@ func UpdateConfigMap(envName string, args *UpdateConfigMapArgs, userName, userID if err != nil { return e.ErrUpdateConfigMap.AddErr(err) } - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), product.ClusterID) + kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), product.ClusterID) if err != nil { return e.ErrUpdateConfigMap.AddErr(err) } @@ -232,7 +232,7 @@ func RollBackConfigMap(envName string, args *RollBackConfigMapArgs, userName, us if err != nil { return e.ErrUpdateConfigMap.AddErr(err) } - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), product.ClusterID) + kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), product.ClusterID) if err != nil { return e.ErrUpdateConfigMap.AddErr(err) } diff --git a/pkg/microservice/aslan/core/environment/service/environment.go b/pkg/microservice/aslan/core/environment/service/environment.go index f9e9fc330..822e93fec 100644 --- a/pkg/microservice/aslan/core/environment/service/environment.go +++ b/pkg/microservice/aslan/core/environment/service/environment.go @@ -54,11 +54,11 @@ import ( commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" + client2 "github.com/koderover/zadig/pkg/shared/kube/client" "github.com/koderover/zadig/pkg/shared/kube/wrapper" e "github.com/koderover/zadig/pkg/tool/errors" helmtool "github.com/koderover/zadig/pkg/tool/helmclient" "github.com/koderover/zadig/pkg/tool/kube/getter" - "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/kube/serializer" "github.com/koderover/zadig/pkg/tool/kube/updater" "github.com/koderover/zadig/pkg/tool/log" @@ -277,7 +277,7 @@ func AutoUpdateProduct(envNames []string, productName, requestID string, force b continue } - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), p.ClusterID) + kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), p.ClusterID) if err != nil { log.Errorf("Failed to get kube client for %s, error: %v", productName, err) continue @@ -389,7 +389,7 @@ func UpdateProduct(existedProd, updateProd *commonmodels.Product, renderSet *com return } - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), existedProd.ClusterID) + kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), existedProd.ClusterID) if err != nil { return e.ErrUpdateEnv.AddErr(err) } @@ -533,7 +533,7 @@ func UpdateProductV2(envName, productName, user, requestID string, force bool, k return e.ErrUpdateEnv.AddDesc(e.EnvNotFoundErrMsg) } - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), exitedProd.ClusterID) + kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), exitedProd.ClusterID) if err != nil { return e.ErrUpdateEnv.AddErr(err) } diff --git a/pkg/microservice/aslan/core/environment/service/environment_creator.go b/pkg/microservice/aslan/core/environment/service/environment_creator.go index b73b49e91..62d508075 100644 --- a/pkg/microservice/aslan/core/environment/service/environment_creator.go +++ b/pkg/microservice/aslan/core/environment/service/environment_creator.go @@ -30,10 +30,10 @@ import ( commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" + "github.com/koderover/zadig/pkg/shared/kube/client" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/helmclient" "github.com/koderover/zadig/pkg/tool/kube/getter" - "github.com/koderover/zadig/pkg/tool/kube/multicluster" ) type CreateProductParam struct { @@ -121,7 +121,7 @@ func newHelmProductCreator() *HelmProductCreator { } func (creator *HelmProductCreator) Create(user, requestID string, args *models.Product, log *zap.SugaredLogger) error { - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), args.ClusterID) + kubeClient, err := client.GetKubeClient(config.HubServerAddress(), args.ClusterID) if err != nil { log.Errorf("[%s][%s] GetKubeClient error: %v", args.EnvName, args.ProductName, err) return e.ErrCreateEnv.AddErr(err) @@ -278,7 +278,7 @@ func newDefaultProductCreator() *DefaultProductCreator { } func (creator *DefaultProductCreator) Create(user, requestID string, args *models.Product, log *zap.SugaredLogger) error { - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), args.ClusterID) + kubeClient, err := client.GetKubeClient(config.HubServerAddress(), args.ClusterID) if err != nil { return e.ErrCreateEnv.AddErr(err) } diff --git a/pkg/microservice/aslan/core/environment/service/environment_group.go b/pkg/microservice/aslan/core/environment/service/environment_group.go index cb438525c..ab8fa01cb 100644 --- a/pkg/microservice/aslan/core/environment/service/environment_group.go +++ b/pkg/microservice/aslan/core/environment/service/environment_group.go @@ -30,10 +30,10 @@ import ( commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" + client2 "github.com/koderover/zadig/pkg/shared/kube/client" "github.com/koderover/zadig/pkg/shared/kube/resource" "github.com/koderover/zadig/pkg/shared/kube/wrapper" e "github.com/koderover/zadig/pkg/tool/errors" - "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/kube/serializer" "github.com/koderover/zadig/pkg/util" ) @@ -67,7 +67,7 @@ func ListGroups(serviceName, envName, productName string, perPage, page int, log //将获取到的所有服务按照名称进行排序 sort.SliceStable(allServices, func(i, j int) bool { return allServices[i].ServiceName < allServices[j].ServiceName }) - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), productInfo.ClusterID) + kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), productInfo.ClusterID) if err != nil { log.Errorf("[%s][%s] error: %v", envName, productName, err) return resp, count, e.ErrListGroups.AddDesc(err.Error()) diff --git a/pkg/microservice/aslan/core/environment/service/export.go b/pkg/microservice/aslan/core/environment/service/export.go index 775c62f6a..29d6589b2 100644 --- a/pkg/microservice/aslan/core/environment/service/export.go +++ b/pkg/microservice/aslan/core/environment/service/export.go @@ -24,8 +24,8 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/config" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" "github.com/koderover/zadig/pkg/setting" + client2 "github.com/koderover/zadig/pkg/shared/kube/client" "github.com/koderover/zadig/pkg/tool/kube/getter" - "github.com/koderover/zadig/pkg/tool/kube/multicluster" ) // ExportYaml 查询使用到服务模板的服务组模板 @@ -40,7 +40,7 @@ func ExportYaml(envName, productName, serviceName string, log *zap.SugaredLogger } namespace := env.Namespace - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), env.ClusterID) + kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), env.ClusterID) if err != nil { log.Errorf("cluster is not connected [%s][%s][%s]", env.EnvName, env.ProductName, env.ClusterID) return res diff --git a/pkg/microservice/aslan/core/environment/service/image.go b/pkg/microservice/aslan/core/environment/service/image.go index b1556b5bf..df062a828 100644 --- a/pkg/microservice/aslan/core/environment/service/image.go +++ b/pkg/microservice/aslan/core/environment/service/image.go @@ -37,10 +37,10 @@ import ( commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" + client2 "github.com/koderover/zadig/pkg/shared/kube/client" e "github.com/koderover/zadig/pkg/tool/errors" helmtool "github.com/koderover/zadig/pkg/tool/helmclient" "github.com/koderover/zadig/pkg/tool/kube/getter" - "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/kube/updater" "github.com/koderover/zadig/pkg/tool/log" "github.com/koderover/zadig/pkg/util" @@ -321,7 +321,7 @@ func UpdateContainerImage(requestID string, args *UpdateContainerImageArgs, log } namespace := product.Namespace - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), product.ClusterID) + kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), product.ClusterID) if err != nil { return e.ErrUpdateConainterImage.AddErr(err) } diff --git a/pkg/microservice/aslan/core/environment/service/k8s.go b/pkg/microservice/aslan/core/environment/service/k8s.go index 4606d4a28..5b6e998ef 100644 --- a/pkg/microservice/aslan/core/environment/service/k8s.go +++ b/pkg/microservice/aslan/core/environment/service/k8s.go @@ -34,8 +34,8 @@ import ( templaterepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb/template" commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/setting" + client2 "github.com/koderover/zadig/pkg/shared/kube/client" e "github.com/koderover/zadig/pkg/tool/errors" - "github.com/koderover/zadig/pkg/tool/kube/multicluster" ) type K8sService struct { @@ -83,7 +83,7 @@ func (k *K8sService) updateService(args *SvcOptArgs) error { return errors.New(e.UpsertServiceErrMsg) } - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), exitedProd.ClusterID) + kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), exitedProd.ClusterID) if err != nil { return e.ErrUpdateEnv.AddErr(err) } diff --git a/pkg/microservice/aslan/core/environment/service/kube.go b/pkg/microservice/aslan/core/environment/service/kube.go index c64c4feac..bfdc4c13f 100644 --- a/pkg/microservice/aslan/core/environment/service/kube.go +++ b/pkg/microservice/aslan/core/environment/service/kube.go @@ -32,11 +32,11 @@ import ( commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" + "github.com/koderover/zadig/pkg/shared/kube/client" "github.com/koderover/zadig/pkg/shared/kube/resource" "github.com/koderover/zadig/pkg/shared/kube/wrapper" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/kube/getter" - "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/kube/updater" "github.com/koderover/zadig/pkg/tool/kube/util" ) @@ -113,7 +113,7 @@ func ListPodEvents(envName, productName, podName string, log *zap.SugaredLogger) // ListAvailableNamespaces lists available namespaces created by non-koderover func ListAvailableNamespaces(clusterID string, log *zap.SugaredLogger) ([]*resource.Namespace, error) { resp := make([]*resource.Namespace, 0) - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), clusterID) + kubeClient, err := client.GetKubeClient(config.HubServerAddress(), clusterID) if err != nil { log.Errorf("ListNamespaces clusterID:%s err:%v", clusterID, err) return resp, err @@ -150,7 +150,7 @@ func ListServicePods(productName, envName string, serviceName string, log *zap.S if err != nil { return res, e.ErrListServicePod.AddErr(err) } - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), product.ClusterID) + kubeClient, err := client.GetKubeClient(config.HubServerAddress(), product.ClusterID) if err != nil { return res, e.ErrListServicePod.AddErr(err) } @@ -177,7 +177,7 @@ func DeletePod(envName, productName, podName string, log *zap.SugaredLogger) err if err != nil { return e.ErrDeletePod.AddErr(err) } - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), product.ClusterID) + kubeClient, err := client.GetKubeClient(config.HubServerAddress(), product.ClusterID) if err != nil { return e.ErrDeletePod.AddErr(err) } @@ -230,7 +230,7 @@ func getModifiedServiceFromObjectMeta(om metav1.Object) *serviceInfo { func ListAvailableNodes(clusterID string, log *zap.SugaredLogger) (*resource.NodeResp, error) { resp := new(resource.NodeResp) - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), clusterID) + kubeClient, err := client.GetKubeClient(config.HubServerAddress(), clusterID) if err != nil { log.Errorf("ListAvailableNodes clusterID:%s err:%s", clusterID, err) return resp, err @@ -249,7 +249,7 @@ func ListAvailableNodes(clusterID string, log *zap.SugaredLogger) (*resource.Nod labels := sets.NewString() for _, node := range nodes { nodeResource := &resource.Node{ - Status: nodeReady(node), + Ready: nodeReady(node), Labels: nodeLabel(node), IP: node.Name, } @@ -262,14 +262,14 @@ func ListAvailableNodes(clusterID string, log *zap.SugaredLogger) (*resource.Nod } // Ready indicates that the node is ready for traffic. -func nodeReady(node *corev1.Node) string { +func nodeReady(node *corev1.Node) bool { cs := node.Status.Conditions for _, c := range cs { if c.Type == corev1.NodeReady && c.Status == corev1.ConditionTrue { - return "ready" + return true } } - return "not ready" + return false } func nodeLabel(node *corev1.Node) []string { diff --git a/pkg/microservice/aslan/core/environment/service/service.go b/pkg/microservice/aslan/core/environment/service/service.go index d21d4e388..705930378 100644 --- a/pkg/microservice/aslan/core/environment/service/service.go +++ b/pkg/microservice/aslan/core/environment/service/service.go @@ -33,11 +33,11 @@ import ( commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" + client2 "github.com/koderover/zadig/pkg/shared/kube/client" internalresource "github.com/koderover/zadig/pkg/shared/kube/resource" "github.com/koderover/zadig/pkg/shared/kube/wrapper" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/kube/getter" - "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/kube/serializer" "github.com/koderover/zadig/pkg/tool/kube/updater" "github.com/koderover/zadig/pkg/tool/log" @@ -61,7 +61,7 @@ func ScaleService(envName, productName, serviceName string, number int, log *zap return e.ErrScaleService.AddErr(err) } - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), prod.ClusterID) + kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), prod.ClusterID) if err != nil { return e.ErrScaleService.AddErr(err) } @@ -112,7 +112,7 @@ func Scale(args *ScaleArgs, logger *zap.SugaredLogger) error { return e.ErrScaleService.AddErr(err) } - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), prod.ClusterID) + kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), prod.ClusterID) if err != nil { return e.ErrScaleService.AddErr(err) } @@ -142,7 +142,7 @@ func RestartScale(args *RestartScaleArgs, _ *zap.SugaredLogger) error { return err } - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), prod.ClusterID) + kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), prod.ClusterID) if err != nil { return err } @@ -178,7 +178,7 @@ func GetService(envName, productName, serviceName string, workLoadType string, l return nil, e.ErrGetService.AddErr(err) } - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), env.ClusterID) + kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), env.ClusterID) if err != nil { return nil, e.ErrGetService.AddErr(err) } @@ -324,7 +324,7 @@ func RestartService(envName string, args *SvcOptArgs, log *zap.SugaredLogger) (e if err != nil { return err } - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), productObj.ClusterID) + kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), productObj.ClusterID) if err != nil { return err } @@ -423,7 +423,7 @@ func validateServiceContainer(envName, productName, serviceName, container strin return "", err } - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), prod.ClusterID) + kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), prod.ClusterID) if err != nil { return "", err } diff --git a/pkg/microservice/aslan/core/log/service/sse.go b/pkg/microservice/aslan/core/log/service/sse.go index af913bd6c..f66547d70 100644 --- a/pkg/microservice/aslan/core/log/service/sse.go +++ b/pkg/microservice/aslan/core/log/service/sse.go @@ -32,9 +32,9 @@ import ( commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" + "github.com/koderover/zadig/pkg/shared/kube/client" "github.com/koderover/zadig/pkg/tool/kube/containerlog" "github.com/koderover/zadig/pkg/tool/kube/getter" - "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/kube/watcher" ) @@ -156,8 +156,7 @@ func TestJobContainerLogStream(ctx context.Context, streamChan chan interface{}, options.SubTask = string(config.TaskTestingV2) selector := getPipelineSelector(options) // get cluster ID - testName := strings.Replace(options.ServiceName, "-job", "", 1) - testing, _ := commonrepo.NewTestingColl().Find(testName, "") + testing, _ := commonrepo.NewTestingColl().Find(getTestName(options.ServiceName), "") if testing != nil && testing.PreTest != nil { options.ClusterID = testing.PreTest.ClusterID options.Namespace = testing.PreTest.Namespace @@ -166,12 +165,17 @@ func TestJobContainerLogStream(ctx context.Context, streamChan chan interface{}, waitAndGetLog(ctx, streamChan, selector, options, log) } +func getTestName(serviceName string) string { + testName := strings.TrimRight(serviceName, "-job") + return testName +} + func waitAndGetLog(ctx context.Context, streamChan chan interface{}, selector labels.Selector, options *GetContainerOptions, log *zap.SugaredLogger) { PodCtx, cancel := context.WithTimeout(ctx, timeout) defer cancel() log.Debugf("Waiting until pod is running before establishing the stream.") - clientSet, err := multicluster.GetClientset(config.HubServerAddress(), options.ClusterID) + clientSet, err := client.GetClientset(config.HubServerAddress(), options.ClusterID) if err != nil { log.Errorf("GetContainerLogs, get client set error: %s", err) return @@ -181,7 +185,7 @@ func waitAndGetLog(ctx context.Context, streamChan chan interface{}, selector la log.Errorf("GetContainerLogs, wait pod running error: %s", err) return } - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), options.ClusterID) + kubeClient, err := client.GetKubeClient(config.HubServerAddress(), options.ClusterID) if err != nil { log.Errorf("GetContainerLogs, get kube client error: %s", err) return diff --git a/pkg/microservice/aslan/core/multicluster/handler/clusters.go b/pkg/microservice/aslan/core/multicluster/handler/clusters.go index 42617c979..ca1ed7448 100644 --- a/pkg/microservice/aslan/core/multicluster/handler/clusters.go +++ b/pkg/microservice/aslan/core/multicluster/handler/clusters.go @@ -22,7 +22,6 @@ import ( "github.com/gin-gonic/gin" - commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" "github.com/koderover/zadig/pkg/microservice/aslan/core/multicluster/service" internalhandler "github.com/koderover/zadig/pkg/shared/handler" e "github.com/koderover/zadig/pkg/tool/errors" @@ -52,7 +51,7 @@ func CreateCluster(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - args := new(commonmodels.K8SCluster) + args := new(service.K8SCluster) if err := c.BindJSON(args); err != nil { ctx.Err = e.ErrInvalidParam.AddErr(err) return @@ -73,7 +72,7 @@ func UpdateCluster(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - args := new(commonmodels.K8SCluster) + args := new(service.K8SCluster) if err := c.BindJSON(args); err != nil { ctx.Err = e.ErrInvalidParam.AddErr(err) return diff --git a/pkg/microservice/aslan/core/multicluster/service/clusters.go b/pkg/microservice/aslan/core/multicluster/service/clusters.go index 8508224ce..cb315872c 100644 --- a/pkg/microservice/aslan/core/multicluster/service/clusters.go +++ b/pkg/microservice/aslan/core/multicluster/service/clusters.go @@ -17,10 +17,14 @@ limitations under the License. package service import ( + "fmt" "net/http" + "regexp" + "strings" "github.com/gin-gonic/gin" "go.uber.org/zap" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/sets" configbase "github.com/koderover/zadig/pkg/config" @@ -32,17 +36,51 @@ import ( e "github.com/koderover/zadig/pkg/tool/errors" ) +var namePattern = regexp.MustCompile(`^[0-9a-zA-Z_.-]{1,32}$`) + type K8SCluster struct { - ID string `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - Status setting.K8SClusterStatus `json:"status"` - Production bool `json:"production"` - CreatedAt int64 `json:"createdAt"` - CreatedBy string `json:"createdBy"` - Provider int8 `json:"provider"` - Local bool `json:"local"` - ClusterConfig *commonmodels.ClusterConfig `json:"config,omitempty"` + ID string `json:"id,omitempty"` + Name string `json:"name"` + Tags []string `json:"tags"` + Description string `json:"description"` + Namespace string `json:"namespace"` + Info *commonmodels.K8SClusterInfo `json:"info,omitempty"` + AdvancedConfig *AdvancedConfig `json:"config,omitempty"` + Status setting.K8SClusterStatus `json:"status"` + Error string `json:"error"` + Yaml string `json:"yaml"` + Production bool `json:"production"` + CreatedAt int64 `json:"createdAt"` + CreatedBy string `json:"createdBy"` + Disconnected bool `json:"-"` + Token string `json:"token"` + Provider int8 `json:"provider"` + Local bool `json:"local"` +} + +type AdvancedConfig struct { + Strategy string `json:"strategy,omitempty" bson:"strategy,omitempty"` + NodeLabels []string `json:"node_labels,omitempty" bson:"node_labels,omitempty"` +} + +func (k *K8SCluster) Clean() error { + k.Name = strings.TrimSpace(k.Name) + tags := k.Tags + k.Tags = []string{} + for _, tag := range tags { + tag = strings.TrimSpace(tag) + if tag != "" { + k.Tags = append(k.Tags, tag) + } + } + + k.Description = strings.TrimSpace(k.Description) + + if !namePattern.MatchString(k.Name) { + return fmt.Errorf("集群名称不符合规则") + } + + return nil } func ListClusters(ids []string, logger *zap.SugaredLogger) ([]*K8SCluster, error) { @@ -55,17 +93,28 @@ func ListClusters(ids []string, logger *zap.SugaredLogger) ([]*K8SCluster, error var res []*K8SCluster for _, c := range cs { + advancedConfig := new(AdvancedConfig) + if c.AdvancedConfig != nil { + advancedConfig.Strategy = c.AdvancedConfig.Strategy + var nodeLabels []string + for _, nodeSelectorRequirement := range c.AdvancedConfig.NodeLabels { + for _, labelValue := range nodeSelectorRequirement.Value { + nodeLabels = append(nodeLabels, fmt.Sprintf("%s:%s", nodeSelectorRequirement.Key, labelValue)) + } + } + advancedConfig.NodeLabels = nodeLabels + } res = append(res, &K8SCluster{ - ID: c.ID.Hex(), - Name: c.Name, - Description: c.Description, - Status: c.Status, - Production: c.Production, - CreatedBy: c.CreatedBy, - CreatedAt: c.CreatedAt, - Provider: c.Provider, - Local: c.Local, - ClusterConfig: c.ClusterConfig, + ID: c.ID.Hex(), + Name: c.Name, + Description: c.Description, + Status: c.Status, + Production: c.Production, + CreatedBy: c.CreatedBy, + CreatedAt: c.CreatedAt, + Provider: c.Provider, + Local: c.Local, + AdvancedConfig: advancedConfig, }) } @@ -78,15 +127,70 @@ func GetCluster(id string, logger *zap.SugaredLogger) (*commonmodels.K8SCluster, return s.GetCluster(id, logger) } -func CreateCluster(cluster *commonmodels.K8SCluster, logger *zap.SugaredLogger) (*commonmodels.K8SCluster, error) { - s, _ := kube.NewService("") +func convertToNodeSelectorRequirements(args *K8SCluster) []*commonmodels.NodeSelectorRequirement { + var nodeSelectorRequirements []*commonmodels.NodeSelectorRequirement + nodeLabelM := make(map[string][]string) + for _, nodeLabel := range args.AdvancedConfig.NodeLabels { + if !strings.Contains(nodeLabel, ":") || len(strings.Split(nodeLabel, ":")) != 2 { + continue + } + key := strings.Split(nodeLabel, ":")[0] + value := strings.Split(nodeLabel, ":")[1] + nodeLabelM[key] = append(nodeLabelM[key], value) + } + for key, value := range nodeLabelM { + nodeSelectorRequirements = append(nodeSelectorRequirements, &commonmodels.NodeSelectorRequirement{ + Key: key, + Value: value, + Operator: corev1.NodeSelectorOpIn, + }) + } + return nodeSelectorRequirements +} +func CreateCluster(args *K8SCluster, logger *zap.SugaredLogger) (*commonmodels.K8SCluster, error) { + s, _ := kube.NewService("") + advancedConfig := new(commonmodels.AdvancedConfig) + if args.AdvancedConfig != nil { + advancedConfig.Strategy = args.AdvancedConfig.Strategy + advancedConfig.NodeLabels = convertToNodeSelectorRequirements(args) + } + cluster := &commonmodels.K8SCluster{ + Name: args.Name, + Tags: args.Tags, + Description: args.Description, + Namespace: args.Namespace, + Info: args.Info, + AdvancedConfig: advancedConfig, + Status: args.Status, + Error: args.Error, + Yaml: args.Yaml, + Production: args.Production, + Disconnected: args.Disconnected, + Token: args.Token, + Provider: args.Provider, + Local: args.Local, + CreatedAt: args.CreatedAt, + CreatedBy: args.CreatedBy, + } return s.CreateCluster(cluster, logger) } -func UpdateCluster(id string, cluster *commonmodels.K8SCluster, logger *zap.SugaredLogger) (*commonmodels.K8SCluster, error) { +func UpdateCluster(id string, args *K8SCluster, logger *zap.SugaredLogger) (*commonmodels.K8SCluster, error) { s, _ := kube.NewService("") - + advancedConfig := new(commonmodels.AdvancedConfig) + if args.AdvancedConfig != nil { + advancedConfig.Strategy = args.AdvancedConfig.Strategy + advancedConfig.NodeLabels = convertToNodeSelectorRequirements(args) + } + cluster := &commonmodels.K8SCluster{ + Name: args.Name, + Tags: args.Tags, + Description: args.Description, + Namespace: args.Namespace, + AdvancedConfig: advancedConfig, + Production: args.Production, + } return s.UpdateCluster(id, cluster, logger) } diff --git a/pkg/microservice/aslan/core/service/service/service.go b/pkg/microservice/aslan/core/service/service/service.go index e5904d3c0..39cadff56 100644 --- a/pkg/microservice/aslan/core/service/service/service.go +++ b/pkg/microservice/aslan/core/service/service/service.go @@ -46,11 +46,11 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/environment/service" "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/shared/client/systemconfig" + "github.com/koderover/zadig/pkg/shared/kube/client" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/gerrit" "github.com/koderover/zadig/pkg/tool/httpclient" "github.com/koderover/zadig/pkg/tool/kube/getter" - "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/log" "github.com/koderover/zadig/pkg/util" ) @@ -256,7 +256,7 @@ func GetServiceOption(args *commonmodels.Service, log *zap.SugaredLogger) (*Serv } func CreateK8sWorkLoads(ctx context.Context, requestID, username string, productName string, workLoads []models.Workload, clusterID, namespace string, envName string, log *zap.SugaredLogger) error { - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), clusterID) + kubeClient, err := client.GetKubeClient(config.HubServerAddress(), clusterID) if err != nil { log.Errorf("[%s] error: %v", namespace, err) return err @@ -385,7 +385,7 @@ type UpdateWorkloadsArgs struct { } func UpdateWorkloads(ctx context.Context, requestID, username, productName, envName string, args UpdateWorkloadsArgs, log *zap.SugaredLogger) error { - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), args.ClusterID) + kubeClient, err := client.GetKubeClient(config.HubServerAddress(), args.ClusterID) if err != nil { log.Errorf("[%s] error: %s", args.Namespace, err) return err diff --git a/pkg/microservice/aslan/core/system/service/registry.go b/pkg/microservice/aslan/core/system/service/registry.go index 8df8afe05..3ab20ad32 100644 --- a/pkg/microservice/aslan/core/system/service/registry.go +++ b/pkg/microservice/aslan/core/system/service/registry.go @@ -28,8 +28,8 @@ import ( commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/registry" "github.com/koderover/zadig/pkg/setting" + "github.com/koderover/zadig/pkg/shared/kube/client" e "github.com/koderover/zadig/pkg/tool/errors" - "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/util" ) @@ -87,7 +87,7 @@ func CreateRegistryNamespace(username string, args *commonmodels.RegistryNamespa } for _, env := range envs { go func(prod *commonmodels.Product) { - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), prod.ClusterID) + kubeClient, err := client.GetKubeClient(config.HubServerAddress(), prod.ClusterID) if err != nil { log.Errorf("[updateRegistry] Failed to get kubecli for namespace: %s", prod.Namespace) return @@ -162,7 +162,7 @@ func UpdateRegistryNamespace(username, id string, args *commonmodels.RegistryNam } for _, env := range envs { go func(prod *commonmodels.Product) { - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), prod.ClusterID) + kubeClient, err := client.GetKubeClient(config.HubServerAddress(), prod.ClusterID) if err != nil { log.Errorf("[updateRegistry] Failed to get kubecli for namespace: %s", prod.Namespace) return diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_validation.go b/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_validation.go index 27210e24d..a8e90a08d 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_validation.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_validation.go @@ -45,10 +45,10 @@ import ( git "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/github" "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/shared/client/systemconfig" + client2 "github.com/koderover/zadig/pkg/shared/kube/client" "github.com/koderover/zadig/pkg/shared/kube/wrapper" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/kube/getter" - "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/log" "github.com/koderover/zadig/pkg/types" "github.com/koderover/zadig/pkg/util" @@ -688,7 +688,7 @@ func validateServiceContainer(envName, productName, serviceName, container strin return "", err } - kubeClient, err := multicluster.GetKubeClient(config.HubServerAddress(), product.ClusterID) + kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), product.ClusterID) if err != nil { return "", err } diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/build.go b/pkg/microservice/warpdrive/core/service/taskplugin/build.go index 941be3e30..687c471fa 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/build.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/build.go @@ -32,8 +32,8 @@ import ( "github.com/koderover/zadig/pkg/microservice/warpdrive/config" "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types/task" "github.com/koderover/zadig/pkg/setting" + client2 "github.com/koderover/zadig/pkg/shared/kube/client" krkubeclient "github.com/koderover/zadig/pkg/tool/kube/client" - "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/kube/updater" ) @@ -110,7 +110,7 @@ func (p *BuildTaskPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipe p.KubeNamespace = pipelineTask.ConfigPayload.Build.KubeNamespace if p.Task.Namespace != "" { p.KubeNamespace = p.Task.Namespace - kubeClient, err := multicluster.GetKubeClient(pipelineTask.ConfigPayload.HubServerAddr, p.Task.ClusterID) + kubeClient, err := client2.GetKubeClient(pipelineTask.ConfigPayload.HubServerAddr, p.Task.ClusterID) if err != nil { msg := fmt.Sprintf("failed to get kube client: %s", err) p.Log.Error(msg) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/deploy.go b/pkg/microservice/warpdrive/core/service/taskplugin/deploy.go index 34b72acab..e65e5f06d 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/deploy.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/deploy.go @@ -39,13 +39,13 @@ import ( "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types" "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types/task" "github.com/koderover/zadig/pkg/setting" + client2 "github.com/koderover/zadig/pkg/shared/kube/client" "github.com/koderover/zadig/pkg/shared/kube/resource" "github.com/koderover/zadig/pkg/shared/kube/wrapper" helmtool "github.com/koderover/zadig/pkg/tool/helmclient" "github.com/koderover/zadig/pkg/tool/httpclient" krkubeclient "github.com/koderover/zadig/pkg/tool/kube/client" "github.com/koderover/zadig/pkg/tool/kube/getter" - "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/kube/updater" s3tool "github.com/koderover/zadig/pkg/tool/s3" "github.com/koderover/zadig/pkg/util" @@ -202,13 +202,13 @@ func (p *DeployTaskPlugin) Run(ctx context.Context, pipelineTask *task.Task, _ * }() if pipelineTask.ConfigPayload.DeployClusterID != "" { - p.restConfig, err = multicluster.GetRESTConfig(pipelineTask.ConfigPayload.HubServerAddr, pipelineTask.ConfigPayload.DeployClusterID) + p.restConfig, err = client2.GetRESTConfig(pipelineTask.ConfigPayload.HubServerAddr, pipelineTask.ConfigPayload.DeployClusterID) if err != nil { err = errors.WithMessage(err, "can't get k8s rest config") return } - p.kubeClient, err = multicluster.GetKubeClient(pipelineTask.ConfigPayload.HubServerAddr, pipelineTask.ConfigPayload.DeployClusterID) + p.kubeClient, err = client2.GetKubeClient(pipelineTask.ConfigPayload.HubServerAddr, pipelineTask.ConfigPayload.DeployClusterID) if err != nil { err = errors.WithMessage(err, "can't init k8s client") return diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/job.go b/pkg/microservice/warpdrive/core/service/taskplugin/job.go index 72c578d1f..4fd3c6a9d 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/job.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/job.go @@ -43,10 +43,10 @@ import ( "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types" "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types/task" "github.com/koderover/zadig/pkg/setting" + client2 "github.com/koderover/zadig/pkg/shared/kube/client" "github.com/koderover/zadig/pkg/shared/kube/wrapper" "github.com/koderover/zadig/pkg/tool/kube/containerlog" "github.com/koderover/zadig/pkg/tool/kube/getter" - "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/kube/podexec" "github.com/koderover/zadig/pkg/tool/kube/updater" "github.com/koderover/zadig/pkg/tool/log" @@ -98,7 +98,7 @@ func saveContainerLog(pipelineTask *task.Task, namespace, clusterID, fileName st return pods[i].CreationTimestamp.Before(&pods[j].CreationTimestamp) }) - clientSet, err := multicluster.GetClientset(pipelineTask.ConfigPayload.HubServerAddr, clusterID) + clientSet, err := client2.GetClientset(pipelineTask.ConfigPayload.HubServerAddr, clusterID) if err != nil { log.Errorf("saveContainerLog, get client set error: %s", err) return err @@ -841,25 +841,15 @@ func addNodeAffinity(clusterID string, K8SClusters []*task.K8SCluster) *corev1.A return nil } - nodeLabelM := make(map[string][]string, 0) - for _, nodeLabel := range clusterConfig.NodeLabels { - if !strings.Contains(nodeLabel, ":") || len(strings.Split(nodeLabel, ":")) != 2 { - continue - } - key := strings.Split(nodeLabel, ":")[0] - value := strings.Split(nodeLabel, ":")[1] - nodeLabelM[key] = append(nodeLabelM[key], value) - } - switch clusterConfig.Strategy { case RequiredSchedule: nodeSelectorTerms := make([]corev1.NodeSelectorTerm, 0) - for key, value := range nodeLabelM { + for _, nodeLabel := range clusterConfig.NodeLabels { var matchExpressions []corev1.NodeSelectorRequirement matchExpressions = append(matchExpressions, corev1.NodeSelectorRequirement{ - Key: key, - Operator: corev1.NodeSelectorOpIn, - Values: value, + Key: nodeLabel.Key, + Operator: nodeLabel.Operator, + Values: nodeLabel.Value, }) nodeSelectorTerms = append(nodeSelectorTerms, corev1.NodeSelectorTerm{ MatchExpressions: matchExpressions, @@ -876,12 +866,12 @@ func addNodeAffinity(clusterID string, K8SClusters []*task.K8SCluster) *corev1.A return affinity case PreferredSchedule: preferredScheduleTerms := make([]corev1.PreferredSchedulingTerm, 0) - for key, value := range nodeLabelM { + for _, nodeLabel := range clusterConfig.NodeLabels { var matchExpressions []corev1.NodeSelectorRequirement matchExpressions = append(matchExpressions, corev1.NodeSelectorRequirement{ - Key: key, - Operator: corev1.NodeSelectorOpIn, - Values: value, + Key: nodeLabel.Key, + Operator: nodeLabel.Operator, + Values: nodeLabel.Value, }) nodeSelectorTerm := corev1.NodeSelectorTerm{ MatchExpressions: matchExpressions, @@ -902,10 +892,10 @@ func addNodeAffinity(clusterID string, K8SClusters []*task.K8SCluster) *corev1.A } } -func findClusterConfig(clusterID string, K8SClusters []*task.K8SCluster) *task.ClusterConfig { +func findClusterConfig(clusterID string, K8SClusters []*task.K8SCluster) *task.AdvancedConfig { for _, K8SCluster := range K8SClusters { - if K8SCluster.ID.Hex() == clusterID { - return K8SCluster.ClusterConfig + if K8SCluster.ID == clusterID { + return K8SCluster.AdvancedConfig } } return nil diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go index 325f7168b..76406a7d3 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go @@ -34,8 +34,8 @@ import ( "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types" "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types/task" "github.com/koderover/zadig/pkg/setting" + client2 "github.com/koderover/zadig/pkg/shared/kube/client" krkubeclient "github.com/koderover/zadig/pkg/tool/kube/client" - "github.com/koderover/zadig/pkg/tool/kube/multicluster" "github.com/koderover/zadig/pkg/tool/kube/updater" s3tool "github.com/koderover/zadig/pkg/tool/s3" "github.com/koderover/zadig/pkg/util" @@ -107,7 +107,7 @@ func (p *TestPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipelineC p.KubeNamespace = pipelineTask.ConfigPayload.Test.KubeNamespace if p.Task.Namespace != "" { p.KubeNamespace = p.Task.Namespace - kubeClient, err := multicluster.GetKubeClient(pipelineTask.ConfigPayload.HubServerAddr, p.Task.ClusterID) + kubeClient, err := client2.GetKubeClient(pipelineTask.ConfigPayload.HubServerAddr, p.Task.ClusterID) if err != nil { msg := fmt.Sprintf("failed to get kube client: %s", err) p.Log.Error(msg) diff --git a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go index a8827cfea..10b763847 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go +++ b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go @@ -19,9 +19,7 @@ package task import ( "fmt" - "go.mongodb.org/mongo-driver/bson/primitive" - - "github.com/koderover/zadig/pkg/setting" + corev1 "k8s.io/api/core/v1" ) type ConfigPayload struct { @@ -44,7 +42,7 @@ type ConfigPayload struct { CustomDNSSupported bool `json:"custom_dns_supported"` HubServerAddr string DeployClusterID string - AesKey string + AesKey string `json:"aes_key"` RepoConfigs map[string]*RegistryNamespace @@ -156,15 +154,18 @@ type PrivateKey struct { } type K8SCluster struct { - ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` - Name string `json:"name" bson:"name"` - Status setting.K8SClusterStatus `json:"status" bson:"status"` - ClusterConfig *ClusterConfig `json:"config,omitempty" bson:"config,omitempty"` - Production bool `json:"production" bson:"production"` - Disconnected bool `json:"-" bson:"disconnected"` + ID string `json:"id,omitempty" bson:"_id,omitempty"` + Name string `json:"name" bson:"name"` + AdvancedConfig *AdvancedConfig `json:"config,omitempty" bson:"config,omitempty"` +} + +type AdvancedConfig struct { + Strategy string `json:"strategy,omitempty" bson:"strategy,omitempty"` + NodeLabels []*NodeSelectorRequirement `json:"node_labels,omitempty" bson:"node_labels,omitempty"` } -type ClusterConfig struct { - Strategy string `json:"strategy,omitempty" bson:"strategy,omitempty"` - NodeLabels []string `json:"node_labels,omitempty" bson:"node_labels,omitempty"` +type NodeSelectorRequirement struct { + Key string `json:"key"` + Value []string `json:"value"` + Operator corev1.NodeSelectorOperator `json:"operator"` } diff --git a/pkg/shared/client/aslan/multicluster.go b/pkg/shared/client/aslan/multicluster.go index 5db4d02f1..e555ead64 100644 --- a/pkg/shared/client/aslan/multicluster.go +++ b/pkg/shared/client/aslan/multicluster.go @@ -4,24 +4,21 @@ import ( "fmt" "time" - "go.mongodb.org/mongo-driver/bson/primitive" - "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/tool/httpclient" ) type cluster struct { - ID primitive.ObjectID `json:"id,omitempty"` + ID string `json:"id"` Name string `json:"name"` Status setting.K8SClusterStatus `json:"status"` Local bool `json:"local"` } -func (c *Client) AddMultiCluster() error { - oid, _ := primitive.ObjectIDFromHex(setting.LocalClusterID) +func (c *Client) AddLocalCluster() error { url := "/cluster/clusters" req := cluster{ - ID: oid, + ID: setting.LocalClusterID, Name: fmt.Sprintf("%s-%s", "local", time.Now().Format("20060102150405")), Local: true, Status: setting.Normal, @@ -35,14 +32,14 @@ func (c *Client) AddMultiCluster() error { return nil } -func (c *Client) ListMultiCluster() ([]*cluster, error) { - url := "/cluster/clusters" +func (c *Client) GetCluster() (*cluster, error) { + url := "/cluster/clusters/" + setting.LocalClusterID - clusters := make([]*cluster, 0) - _, err := c.Get(url, httpclient.SetResult(&clusters)) + var cluster *cluster + _, err := c.Get(url, httpclient.SetResult(&cluster)) if err != nil { - return nil, fmt.Errorf("Failed to list multi cluster, error: %s", err) + return nil, fmt.Errorf("Failed to get cluster, error: %s", err) } - return clusters, nil + return cluster, nil } diff --git a/pkg/shared/kube/client/client.go b/pkg/shared/kube/client/client.go index f84e1e4e1..dfb984b13 100644 --- a/pkg/shared/kube/client/client.go +++ b/pkg/shared/kube/client/client.go @@ -1 +1,39 @@ -package kube +package client + +import ( + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/koderover/zadig/pkg/setting" + "github.com/koderover/zadig/pkg/tool/kube/multicluster" +) + +func GetKubeClient(hubServerAddr, clusterID string) (client.Client, error) { + if clusterID == setting.LocalClusterID { + clusterID = "" + } + + return multicluster.GetKubeClient(hubServerAddr, clusterID) +} + +func GetKubeAPIReader(hubServerAddr, clusterID string) (client.Reader, error) { + if clusterID == setting.LocalClusterID { + clusterID = "" + } + return multicluster.GetKubeAPIReader(hubServerAddr, clusterID) +} +func GetRESTConfig(hubServerAddr, clusterID string) (*rest.Config, error) { + if clusterID == setting.LocalClusterID { + clusterID = "" + } + return multicluster.GetRESTConfig(hubServerAddr, clusterID) +} + +func GetClientset(hubServerAddr, clusterID string) (kubernetes.Interface, error) { + if clusterID == setting.LocalClusterID { + clusterID = "" + } + + return multicluster.GetClientset(hubServerAddr, clusterID) +} diff --git a/pkg/shared/kube/resource/node.go b/pkg/shared/kube/resource/node.go index c76b5eb62..a78564c2f 100644 --- a/pkg/shared/kube/resource/node.go +++ b/pkg/shared/kube/resource/node.go @@ -2,7 +2,7 @@ package resource type Node struct { Labels []string `json:"node_labels"` - Status string `json:"node_status"` + Ready bool `json:"ready"` IP string `json:"node_ip"` } diff --git a/pkg/shared/kube/wrapper/namespace.go b/pkg/shared/kube/wrapper/namespace.go index 0f7c84023..3fd58ef1e 100644 --- a/pkg/shared/kube/wrapper/namespace.go +++ b/pkg/shared/kube/wrapper/namespace.go @@ -19,7 +19,7 @@ package wrapper import ( corev1 "k8s.io/api/core/v1" - "github.com/koderover/zadig/pkg/microservice/aslan/config" + "github.com/koderover/zadig/pkg/config" "github.com/koderover/zadig/pkg/shared/kube/resource" "github.com/koderover/zadig/pkg/util" ) diff --git a/pkg/tool/kube/multicluster/service.go b/pkg/tool/kube/multicluster/service.go index eb6e6aeca..067c8740f 100644 --- a/pkg/tool/kube/multicluster/service.go +++ b/pkg/tool/kube/multicluster/service.go @@ -28,12 +28,11 @@ import ( "k8s.io/client-go/tools/clientcmd/api" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/koderover/zadig/pkg/setting" krkubeclient "github.com/koderover/zadig/pkg/tool/kube/client" ) func GetKubeClient(hubServerAddr, clusterID string) (client.Client, error) { - if clusterID == "" || clusterID == setting.LocalClusterID { + if clusterID == "" { return krkubeclient.Client(), nil } @@ -46,7 +45,7 @@ func GetKubeClient(hubServerAddr, clusterID string) (client.Client, error) { } func GetKubeAPIReader(hubServerAddr, clusterID string) (client.Reader, error) { - if clusterID == "" || clusterID == setting.LocalClusterID { + if clusterID == "" { return krkubeclient.APIReader(), nil } @@ -59,7 +58,7 @@ func GetKubeAPIReader(hubServerAddr, clusterID string) (client.Reader, error) { } func GetRESTConfig(hubServerAddr, clusterID string) (*rest.Config, error) { - if clusterID == "" || clusterID == setting.LocalClusterID { + if clusterID == "" { return krkubeclient.RESTConfig(), nil } @@ -68,7 +67,7 @@ func GetRESTConfig(hubServerAddr, clusterID string) (*rest.Config, error) { // GetClientset returns a client to interact with APIServer which implements kubernetes.Interface func GetClientset(hubServerAddr, clusterID string) (kubernetes.Interface, error) { - if clusterID == "" || clusterID == setting.LocalClusterID { + if clusterID == "" { return krkubeclient.Clientset(), nil } -- Gitee From 690aaff7963ec1373c9e07454ef21d6b988a33cb Mon Sep 17 00:00:00 2001 From: liu deyi Date: Tue, 7 Dec 2021 21:12:34 +0800 Subject: [PATCH 055/134] optimize code Signed-off-by: liu deyi --- pkg/microservice/aslan/core/common/service/environment.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/microservice/aslan/core/common/service/environment.go b/pkg/microservice/aslan/core/common/service/environment.go index 8729b55df..ae4c0198f 100644 --- a/pkg/microservice/aslan/core/common/service/environment.go +++ b/pkg/microservice/aslan/core/common/service/environment.go @@ -36,7 +36,7 @@ import ( commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" templaterepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb/template" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/kube/client" + client2 "github.com/koderover/zadig/pkg/shared/kube/client" "github.com/koderover/zadig/pkg/shared/kube/resource" "github.com/koderover/zadig/pkg/shared/kube/wrapper" e "github.com/koderover/zadig/pkg/tool/errors" @@ -213,7 +213,7 @@ func ListWorkloads(envName, clusterID, namespace, productName string, perPage, p log.Infof("Start to list workloads in namespace %s", namespace) var resp = make([]*ServiceResp, 0) - kubeClient, err := client.GetKubeClient(config.HubServerAddress(), clusterID) + kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), clusterID) if err != nil { log.Errorf("[%s][%s] error: %v", envName, namespace, err) return 0, resp, e.ErrListGroups.AddDesc(err.Error()) -- Gitee From ac80b52bf738cad8485f9bb2f57c51e1072de557 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Tue, 7 Dec 2021 21:34:00 +0800 Subject: [PATCH 056/134] optimize code Signed-off-by: liu deyi --- pkg/shared/client/aslan/multicluster.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/pkg/shared/client/aslan/multicluster.go b/pkg/shared/client/aslan/multicluster.go index e555ead64..5790f5b15 100644 --- a/pkg/shared/client/aslan/multicluster.go +++ b/pkg/shared/client/aslan/multicluster.go @@ -32,14 +32,20 @@ func (c *Client) AddLocalCluster() error { return nil } -func (c *Client) GetCluster() (*cluster, error) { +type clusterResp struct { + Name string `json:"name"` + Status setting.K8SClusterStatus `json:"status"` + Local bool `json:"local"` +} + +func (c *Client) GetCluster() (*clusterResp, error) { url := "/cluster/clusters/" + setting.LocalClusterID - var cluster *cluster - _, err := c.Get(url, httpclient.SetResult(&cluster)) + var clusterResp *clusterResp + _, err := c.Get(url, httpclient.SetResult(&clusterResp)) if err != nil { return nil, fmt.Errorf("Failed to get cluster, error: %s", err) } - return cluster, nil + return clusterResp, nil } -- Gitee From c18ddd99c26d797636fab3eb5f450c97faba9657 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Tue, 7 Dec 2021 21:37:56 +0800 Subject: [PATCH 057/134] optimize code Signed-off-by: liu deyi --- pkg/shared/client/aslan/multicluster.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/shared/client/aslan/multicluster.go b/pkg/shared/client/aslan/multicluster.go index 5790f5b15..356a711f7 100644 --- a/pkg/shared/client/aslan/multicluster.go +++ b/pkg/shared/client/aslan/multicluster.go @@ -39,11 +39,12 @@ type clusterResp struct { } func (c *Client) GetCluster() (*clusterResp, error) { - url := "/cluster/clusters/" + setting.LocalClusterID + url := fmt.Sprintf("/cluster/clusters/%s", setting.LocalClusterID) - var clusterResp *clusterResp + clusterResp := new(clusterResp) _, err := c.Get(url, httpclient.SetResult(&clusterResp)) if err != nil { + fmt.Println(fmt.Sprintf("err:%+v", err)) return nil, fmt.Errorf("Failed to get cluster, error: %s", err) } -- Gitee From c1636c2d4f3d6aaa568a50d0c43ca7ff08fed0e7 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Tue, 7 Dec 2021 21:59:56 +0800 Subject: [PATCH 058/134] optimize code Signed-off-by: liu deyi --- pkg/cli/initconfig/cmd/init.go | 5 ++++- pkg/shared/client/aslan/multicluster.go | 9 ++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pkg/cli/initconfig/cmd/init.go b/pkg/cli/initconfig/cmd/init.go index 00add4ae7..aa2377636 100644 --- a/pkg/cli/initconfig/cmd/init.go +++ b/pkg/cli/initconfig/cmd/init.go @@ -204,7 +204,10 @@ func presetRole() error { } func createLocalCluster() error { - cluster, _ := aslan.New(config.AslanServiceAddress()).GetCluster() + cluster, err := aslan.New(config.AslanServiceAddress()).GetCluster() + if err != nil { + fmt.Println("err:", err) + } if cluster != nil { return nil } diff --git a/pkg/shared/client/aslan/multicluster.go b/pkg/shared/client/aslan/multicluster.go index 356a711f7..a29c709e7 100644 --- a/pkg/shared/client/aslan/multicluster.go +++ b/pkg/shared/client/aslan/multicluster.go @@ -33,16 +33,15 @@ func (c *Client) AddLocalCluster() error { } type clusterResp struct { - Name string `json:"name"` - Status setting.K8SClusterStatus `json:"status"` - Local bool `json:"local"` + Name string `json:"name"` + Local bool `json:"local"` } func (c *Client) GetCluster() (*clusterResp, error) { url := fmt.Sprintf("/cluster/clusters/%s", setting.LocalClusterID) - clusterResp := new(clusterResp) - _, err := c.Get(url, httpclient.SetResult(&clusterResp)) + clusterResp := &clusterResp{} + _, err := c.Get(url, httpclient.SetResult(clusterResp)) if err != nil { fmt.Println(fmt.Sprintf("err:%+v", err)) return nil, fmt.Errorf("Failed to get cluster, error: %s", err) -- Gitee From d6ff5f40e5b641d2e271f7f86cc95ff797c32be5 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Tue, 7 Dec 2021 22:04:39 +0800 Subject: [PATCH 059/134] optimize code Signed-off-by: liu deyi --- pkg/cli/initconfig/cmd/init.go | 5 +---- pkg/shared/client/aslan/multicluster.go | 8 +++++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/pkg/cli/initconfig/cmd/init.go b/pkg/cli/initconfig/cmd/init.go index aa2377636..00add4ae7 100644 --- a/pkg/cli/initconfig/cmd/init.go +++ b/pkg/cli/initconfig/cmd/init.go @@ -204,10 +204,7 @@ func presetRole() error { } func createLocalCluster() error { - cluster, err := aslan.New(config.AslanServiceAddress()).GetCluster() - if err != nil { - fmt.Println("err:", err) - } + cluster, _ := aslan.New(config.AslanServiceAddress()).GetCluster() if cluster != nil { return nil } diff --git a/pkg/shared/client/aslan/multicluster.go b/pkg/shared/client/aslan/multicluster.go index a29c709e7..fa18e6730 100644 --- a/pkg/shared/client/aslan/multicluster.go +++ b/pkg/shared/client/aslan/multicluster.go @@ -4,21 +4,24 @@ import ( "fmt" "time" + "go.mongodb.org/mongo-driver/bson/primitive" + "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/tool/httpclient" ) type cluster struct { - ID string `json:"id"` + ID primitive.ObjectID `json:"id,omitempty"` Name string `json:"name"` Status setting.K8SClusterStatus `json:"status"` Local bool `json:"local"` } func (c *Client) AddLocalCluster() error { + oid, _ := primitive.ObjectIDFromHex(setting.LocalClusterID) url := "/cluster/clusters" req := cluster{ - ID: setting.LocalClusterID, + ID: oid, Name: fmt.Sprintf("%s-%s", "local", time.Now().Format("20060102150405")), Local: true, Status: setting.Normal, @@ -43,7 +46,6 @@ func (c *Client) GetCluster() (*clusterResp, error) { clusterResp := &clusterResp{} _, err := c.Get(url, httpclient.SetResult(clusterResp)) if err != nil { - fmt.Println(fmt.Sprintf("err:%+v", err)) return nil, fmt.Errorf("Failed to get cluster, error: %s", err) } -- Gitee From 5ca61a8ad3d5e5b3297d38c3d4e991a9d23eef4c Mon Sep 17 00:00:00 2001 From: liu deyi Date: Tue, 7 Dec 2021 22:09:19 +0800 Subject: [PATCH 060/134] optimize code Signed-off-by: liu deyi --- .../aslan/core/multicluster/service/clusters.go | 5 +++++ pkg/shared/client/aslan/multicluster.go | 7 ++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/pkg/microservice/aslan/core/multicluster/service/clusters.go b/pkg/microservice/aslan/core/multicluster/service/clusters.go index cb315872c..928b7e612 100644 --- a/pkg/microservice/aslan/core/multicluster/service/clusters.go +++ b/pkg/microservice/aslan/core/multicluster/service/clusters.go @@ -22,6 +22,8 @@ import ( "regexp" "strings" + "go.mongodb.org/mongo-driver/bson/primitive" + "github.com/gin-gonic/gin" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" @@ -173,6 +175,9 @@ func CreateCluster(args *K8SCluster, logger *zap.SugaredLogger) (*commonmodels.K CreatedAt: args.CreatedAt, CreatedBy: args.CreatedBy, } + if args.ID != "" { + cluster.ID, _ = primitive.ObjectIDFromHex(args.ID) + } return s.CreateCluster(cluster, logger) } diff --git a/pkg/shared/client/aslan/multicluster.go b/pkg/shared/client/aslan/multicluster.go index fa18e6730..9904bcfea 100644 --- a/pkg/shared/client/aslan/multicluster.go +++ b/pkg/shared/client/aslan/multicluster.go @@ -4,24 +4,21 @@ import ( "fmt" "time" - "go.mongodb.org/mongo-driver/bson/primitive" - "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/tool/httpclient" ) type cluster struct { - ID primitive.ObjectID `json:"id,omitempty"` + ID string `json:"id,omitempty"` Name string `json:"name"` Status setting.K8SClusterStatus `json:"status"` Local bool `json:"local"` } func (c *Client) AddLocalCluster() error { - oid, _ := primitive.ObjectIDFromHex(setting.LocalClusterID) url := "/cluster/clusters" req := cluster{ - ID: oid, + ID: setting.LocalClusterID, Name: fmt.Sprintf("%s-%s", "local", time.Now().Format("20060102150405")), Local: true, Status: setting.Normal, -- Gitee From ed1c347edac750fa473297aef19dd36fcc6e2cc1 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Tue, 7 Dec 2021 22:17:08 +0800 Subject: [PATCH 061/134] optimize code Signed-off-by: liu deyi --- pkg/microservice/aslan/core/common/repository/models/queue.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/microservice/aslan/core/common/repository/models/queue.go b/pkg/microservice/aslan/core/common/repository/models/queue.go index 973097c9b..1ea52e5f3 100644 --- a/pkg/microservice/aslan/core/common/repository/models/queue.go +++ b/pkg/microservice/aslan/core/common/repository/models/queue.go @@ -126,7 +126,7 @@ type ConfigPayload struct { CustomDNSSupported bool `json:"custom_dns_supported"` HubServerAddr string DeployClusterID string - AesKey string `bson:"-" json:"aes_key"` + AesKey string `json:"aes_key"` RepoConfigs map[string]*RegistryNamespace @@ -137,7 +137,7 @@ type ConfigPayload struct { ResetCache bool `json:"reset_cache"` JenkinsBuildConfig JenkinsBuildConfig `json:"jenkins_build_config"` PrivateKeys []*PrivateKey `json:"private_keys"` - K8SClusters []*K8SClusterResp `bson:"-" json:"k8s_cluster"` + K8SClusters []*K8SClusterResp `json:"k8s_cluster"` } type AslanConfig struct { -- Gitee From 1b8ff0eb9b5a8345b625c60facf0cfdbb265107c Mon Sep 17 00:00:00 2001 From: liu deyi Date: Tue, 7 Dec 2021 22:34:04 +0800 Subject: [PATCH 062/134] optimize code Signed-off-by: liu deyi --- .../aslan/core/common/repository/models/k8s_cluster.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/microservice/aslan/core/common/repository/models/k8s_cluster.go b/pkg/microservice/aslan/core/common/repository/models/k8s_cluster.go index 767d94490..59fc65c9a 100644 --- a/pkg/microservice/aslan/core/common/repository/models/k8s_cluster.go +++ b/pkg/microservice/aslan/core/common/repository/models/k8s_cluster.go @@ -62,9 +62,9 @@ type AdvancedConfig struct { } type NodeSelectorRequirement struct { - Key string `json:"key"` - Value []string `json:"value"` - Operator corev1.NodeSelectorOperator `json:"operator"` + Key string `json:"key" bson:"key"` + Value []string `json:"value" bson:"value"` + Operator corev1.NodeSelectorOperator `json:"operator" bson:"operator"` } func (K8SCluster) TableName() string { -- Gitee From 861f82db23c19343289d7f24b081e0640ee639ef Mon Sep 17 00:00:00 2001 From: liu deyi Date: Tue, 7 Dec 2021 22:46:18 +0800 Subject: [PATCH 063/134] optimize code Signed-off-by: liu deyi --- pkg/microservice/aslan/core/multicluster/service/clusters.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/microservice/aslan/core/multicluster/service/clusters.go b/pkg/microservice/aslan/core/multicluster/service/clusters.go index 928b7e612..756e68cd2 100644 --- a/pkg/microservice/aslan/core/multicluster/service/clusters.go +++ b/pkg/microservice/aslan/core/multicluster/service/clusters.go @@ -196,6 +196,7 @@ func UpdateCluster(id string, args *K8SCluster, logger *zap.SugaredLogger) (*com AdvancedConfig: advancedConfig, Production: args.Production, } + logger.Infof("advancedConfig:%+v", cluster.AdvancedConfig) return s.UpdateCluster(id, cluster, logger) } -- Gitee From d8241665d1f9c955830db66ea5b6a15eca5c8ed8 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Tue, 7 Dec 2021 22:52:35 +0800 Subject: [PATCH 064/134] optimize code Signed-off-by: liu deyi --- pkg/microservice/aslan/core/common/service/kube/service.go | 4 +++- pkg/microservice/aslan/core/multicluster/service/clusters.go | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/microservice/aslan/core/common/service/kube/service.go b/pkg/microservice/aslan/core/common/service/kube/service.go index 1b650fa52..97180eb03 100644 --- a/pkg/microservice/aslan/core/common/service/kube/service.go +++ b/pkg/microservice/aslan/core/common/service/kube/service.go @@ -23,6 +23,8 @@ import ( "strings" "text/template" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.uber.org/zap" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" @@ -134,7 +136,7 @@ func (s *Service) UpdateCluster(id string, cluster *models.K8SCluster, logger *z return nil, e.ErrUpdateCluster.AddDesc(e.DuplicateClusterNameFound) } - + cluster.ID, _ = primitive.ObjectIDFromHex(id) err = s.coll.UpdateMutableFields(cluster) if err != nil { logger.Errorf("failed to update mutable fields %v", err) diff --git a/pkg/microservice/aslan/core/multicluster/service/clusters.go b/pkg/microservice/aslan/core/multicluster/service/clusters.go index 756e68cd2..928b7e612 100644 --- a/pkg/microservice/aslan/core/multicluster/service/clusters.go +++ b/pkg/microservice/aslan/core/multicluster/service/clusters.go @@ -196,7 +196,6 @@ func UpdateCluster(id string, args *K8SCluster, logger *zap.SugaredLogger) (*com AdvancedConfig: advancedConfig, Production: args.Production, } - logger.Infof("advancedConfig:%+v", cluster.AdvancedConfig) return s.UpdateCluster(id, cluster, logger) } -- Gitee From 24c8f2b0dd8a237d79b0449d2ef54ef928cf50b6 Mon Sep 17 00:00:00 2001 From: allenshen Date: Wed, 8 Dec 2021 10:33:30 +0800 Subject: [PATCH 065/134] add previous chart version api Signed-off-by: allenshen --- .../aslan/core/delivery/handler/router.go | 1 + .../aslan/core/delivery/handler/version.go | 10 + .../aslan/core/delivery/service/version.go | 319 +++++++++++------- .../aslan/core/environment/service/helm.go | 1 + .../aslan/core/service/service/helm.go | 6 - 5 files changed, 216 insertions(+), 121 deletions(-) diff --git a/pkg/microservice/aslan/core/delivery/handler/router.go b/pkg/microservice/aslan/core/delivery/handler/router.go index 7e9b1f480..7b58bcade 100644 --- a/pkg/microservice/aslan/core/delivery/handler/router.go +++ b/pkg/microservice/aslan/core/delivery/handler/router.go @@ -49,6 +49,7 @@ func (*Router) Inject(router *gin.RouterGroup) { deliveryRelease.POST("/helm", CreateHelmDeliveryVersion) deliveryRelease.POST("/helm/global-variables", ApplyDeliveryGlobalVariables) deliveryRelease.GET("/helm/charts", DownloadDeliveryChart) + deliveryRelease.GET("/helm/charts/version", GetChartVersionFromRepo) deliveryRelease.GET("/helm/charts/preview", PreviewGetDeliveryChart) deliveryRelease.GET("/helm/charts/filePath", GetDeliveryChartFilePath) deliveryRelease.GET("/helm/charts/fileContent", GetDeliveryChartFileContent) diff --git a/pkg/microservice/aslan/core/delivery/handler/version.go b/pkg/microservice/aslan/core/delivery/handler/version.go index c943e5d3f..39a4e5519 100644 --- a/pkg/microservice/aslan/core/delivery/handler/version.go +++ b/pkg/microservice/aslan/core/delivery/handler/version.go @@ -242,6 +242,16 @@ func DownloadDeliveryChart(c *gin.Context) { c.Data(http.StatusOK, "application/octet-stream", fileBytes) } +func GetChartVersionFromRepo(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + chartName := c.Query("chartName") + chartRepoName := c.Query("chartRepoName") + + ctx.Resp, ctx.Err = deliveryservice.GetChartVersions(chartName, chartRepoName) +} + func PreviewGetDeliveryChart(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() diff --git a/pkg/microservice/aslan/core/delivery/service/version.go b/pkg/microservice/aslan/core/delivery/service/version.go index 90cd83e42..7db6b6e75 100644 --- a/pkg/microservice/aslan/core/delivery/service/version.go +++ b/pkg/microservice/aslan/core/delivery/service/version.go @@ -29,10 +29,6 @@ import ( "sync" "time" - "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/task" - - workflowservice "github.com/koderover/zadig/pkg/microservice/aslan/core/workflow/service/workflow" - cm "github.com/chartmuseum/helm-push/pkg/chartmuseum" "github.com/chartmuseum/helm-push/pkg/helm" "github.com/hashicorp/go-multierror" @@ -47,16 +43,19 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/config" commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/task" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/template" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/base" + workflowservice "github.com/koderover/zadig/pkg/microservice/aslan/core/workflow/service/workflow" "github.com/koderover/zadig/pkg/setting" e "github.com/koderover/zadig/pkg/tool/errors" + helmtool "github.com/koderover/zadig/pkg/tool/helmclient" "github.com/koderover/zadig/pkg/tool/log" "github.com/koderover/zadig/pkg/types" - "github.com/koderover/zadig/pkg/util/converter" + fsutil "github.com/koderover/zadig/pkg/util/fs" yamlutil "github.com/koderover/zadig/pkg/util/yaml" ) @@ -101,8 +100,11 @@ type DeliveryVersionChartData struct { } type DeliveryChartData struct { - ChartData *CreateHelmDeliveryVersionChartData - ServiceObj *commonmodels.Service + ChartData *CreateHelmDeliveryVersionChartData + ServiceObj *commonmodels.Service + ProductService *commonmodels.ProductService + RenderChart *template.RenderChart + RenderSet *commonmodels.RenderSet } type DeliveryChartResp struct { @@ -177,6 +179,11 @@ type ServiceImageDetails struct { Registries []string } +type ChartVersionResp struct { + ChartName string `json:"chartName"` + ChartVersion string `json:"chartVersion"` +} + func GetDeliveryVersion(args *commonrepo.DeliveryVersionArgs, log *zap.SugaredLogger) (*commonmodels.DeliveryVersion, error) { versionData, err := commonrepo.NewDeliveryVersionColl().Get(args) if err != nil { @@ -499,44 +506,22 @@ func createChartRepoClient(repo *commonmodels.HelmRepo) (*cm.Client, error) { } // pull image from currently using registry and push to specified repo -func extractImages(deliveryVersion *commonmodels.DeliveryVersion, serviceObj *commonmodels.Service, valuesMap map[string]interface{}, - targetRegistry *commonmodels.RegistryNamespace, registryMap map[string]*commonmodels.RegistryNamespace) (*ServiceImageDetails, error) { - - flatMap, err := converter.Flatten(valuesMap) - if err != nil { - return nil, err - } - - imagePathSpecs := make([]map[string]string, 0) - for _, container := range serviceObj.Containers { - imageSearchRule := &template.ImageSearchingRule{ - Repo: container.ImagePath.Repo, - Image: container.ImagePath.Image, - Tag: container.ImagePath.Tag, - } - pattern := imageSearchRule.GetSearchingPattern() - imagePathSpecs = append(imagePathSpecs, pattern) - } - - // find full image uris from values.yaml - imageUrls := make([]string, 0) - for _, spec := range imagePathSpecs { - imageUri, err := commonservice.GeneImageURI(spec, flatMap) - if err != nil { - return nil, err - } +func extractImages(productService *commonmodels.ProductService, registryMap map[string]*commonmodels.RegistryNamespace) (*ServiceImageDetails, error) { - imageUrls = append(imageUrls, imageUri) + // find all images in one single chart + imageUrlsSet := sets.NewString() + for _, container := range productService.Containers { + imageUrlsSet.Insert(container.Image) } ret := &ServiceImageDetails{ - ServiceName: serviceObj.ServiceName, + ServiceName: productService.ServiceName, Images: make([]*ImageUrlDetail, 0), } registrySet := sets.NewString() - for _, imageUrl := range imageUrls { + for _, imageUrl := range imageUrlsSet.List() { registryUrl, err := commonservice.ExtractImageRegistry(imageUrl) if err != nil { @@ -561,36 +546,17 @@ func extractImages(deliveryVersion *commonmodels.DeliveryVersion, serviceObj *co ret.Registries = registrySet.List() return ret, nil - - //for _, imageUrl := range imageUrls { - // registryUrl, err := commonservice.ExtractImageRegistry(imageUrl) - // if err != nil { - // return nil, errors.Wrapf(err, "failed to parse registry from image uri: %s", imageUrl) - // } - // registryUrl = strings.TrimSuffix(registryUrl, "/") - // - // imageName := commonservice.ExtractImageName(imageUrl) - // imageTag := commonservice.ExtractImageTag(imageUrl) - // imageNamespace := commonservice.ExtractRegistryNamespace(imageUrl) - // targetFullImageUri := imageUrl - // - // if registry, ok := registryMap[registryUrl]; ok { - // if registry.ID != targetRegistry.ID { - // targetFullImageUri = fmt.Sprintf("%s/%s/%s:%s", targetRegistry.RegAddr, targetRegistry.Namespace, imageName, imageTag) - // } - // } - // - // if err != nil { - // log.Errorf("failed to insert image distribute data, version: %s, image: %s, err: %s", deliveryVersion.Version, targetFullImageUri, err) - // return nil, fmt.Errorf("failed to insert image distribute data") - // } - //} - //return nil, nil } -func handleSingleChart(deliveryVersion *commonmodels.DeliveryVersion, chartData *DeliveryChartData, chartRepo *commonmodels.HelmRepo, dir string, globalVariables string, - targetRegistry *commonmodels.RegistryNamespace, registryMap map[string]*commonmodels.RegistryNamespace) (*ServiceImageDetails, error) { +// ensure chart files exist +func ensureChartFiles(chartData *DeliveryChartData) (string, error) { serviceObj := chartData.ServiceObj + revisionBasePath := config.LocalDeliveryChartPathWithRevision(serviceObj.ProductName, serviceObj.ServiceName, serviceObj.Revision) + deliveryChartPath := filepath.Join(revisionBasePath, serviceObj.ServiceName) + if exists, _ := fsutil.DirExists(deliveryChartPath); exists { + return deliveryChartPath, nil + } + serviceName, revision := serviceObj.ServiceName, serviceObj.Revision basePath := config.LocalServicePathWithRevision(serviceObj.ProductName, serviceName, revision) if err := commonservice.PreloadServiceManifestsByRevision(basePath, serviceObj); err != nil { @@ -599,73 +565,97 @@ func handleSingleChart(deliveryVersion *commonmodels.DeliveryVersion, chartData basePath = config.LocalServicePath(serviceObj.ProductName, serviceName) if err = commonservice.PreLoadServiceManifests(basePath, serviceObj); err != nil { log.Errorf("failed to load chart info for service %v", serviceObj.ServiceName) - return nil, err + return "", err } } fullPath := filepath.Join(basePath, serviceObj.ServiceName) - revisionBasePath := config.LocalDeliveryChartPathWithRevision(serviceObj.ProductName, serviceObj.ServiceName, serviceObj.Revision) - deliveryChartPath := filepath.Join(revisionBasePath, serviceObj.ServiceName) err := copy.Copy(fullPath, deliveryChartPath) if err != nil { - return nil, err + return "", err } - //load chart info from local storage - chartRequested, err := chartloader.Load(deliveryChartPath) + mergedValuesYaml, err := helmtool.MergeOverrideValues(chartData.RenderChart.ValuesYaml, chartData.RenderSet.DefaultValues, chartData.RenderChart.GetOverrideYaml(), chartData.RenderChart.OverrideValues) if err != nil { - return nil, errors.Wrapf(err, "failed to load chart info, path %s", deliveryChartPath) + return "", err + } + err = os.WriteFile(filepath.Join(deliveryChartPath, setting.ValuesYaml), []byte(mergedValuesYaml), 0644) + if err != nil { + return "", errors.Wrapf(err, "failed to write values.yaml") } - //set version and values.yaml content - chartRequested.Metadata.Name = chartData.ChartData.ServiceName - chartRequested.Metadata.Version = chartData.ChartData.Version - chartRequested.Metadata.AppVersion = chartData.ChartData.Version + return deliveryChartPath, nil +} +func buildChartPackage(chartData *DeliveryChartData, chartRepo *commonmodels.HelmRepo, dir string, globalVariables string, registryMap map[string]*commonmodels.RegistryNamespace) error { + serviceObj := chartData.ServiceObj + + deliveryChartPath, err := ensureChartFiles(chartData) + if err != nil { + return err + } + + valuesYamlData := make(map[string]interface{}) + valuesFilePath := filepath.Join(deliveryChartPath, setting.ValuesYaml) + valueYamlContent, err := os.ReadFile(valuesFilePath) + if err != nil { + return errors.Wrapf(err, "failed to read values.yaml for service %s", serviceObj.ServiceName) + } + err = yaml.Unmarshal(valueYamlContent, &valuesYamlData) + if err != nil { + return errors.Wrapf(err, "failed to unmarshal values.yaml for service %s", serviceObj.ServiceName) + } + + // write values.yaml file before load if len(chartData.ChartData.ValuesYamlContent) > 0 { // values.yaml was edited directly - valuesInfo := make(map[string]interface{}) if err = yaml.Unmarshal([]byte(chartData.ChartData.ValuesYamlContent), map[string]interface{}{}); err != nil { log.Errorf("invalid yaml content, serviceName: %s, yamlContent: %s", serviceObj.ServiceName, chartData.ChartData.ValuesYamlContent) - return nil, errors.Wrapf(err, "invalid yaml content for service: %s", serviceObj.ServiceName) + return errors.Wrapf(err, "invalid yaml content for service: %s", serviceObj.ServiceName) } - chartRequested.Values = valuesInfo + valueYamlContent = []byte(chartData.ChartData.ValuesYamlContent) } else if len(globalVariables) > 0 { // merge global variables - curValuesStr, err := yaml.Marshal(chartRequested.Values) - if err != nil { - return nil, errors.Wrapf(err, "failed to marshal values.yaml for service: %s", serviceObj.ServiceName) - } - chartRequested.Values, err = yamlutil.MergeAndUnmarshal([][]byte{curValuesStr, []byte(globalVariables)}) + valueYamlContent, err = yamlutil.Merge([][]byte{valueYamlContent, []byte(globalVariables)}) if err != nil { - return nil, errors.Wrapf(err, "failed to merge global variables for service: %s", serviceObj.ServiceName) + return errors.Wrapf(err, "failed to merge global variables for service: %s", serviceObj.ServiceName) } } + err = os.WriteFile(valuesFilePath, valueYamlContent, 0644) + if err != nil { + return errors.Wrapf(err, "failed to write values.yaml file for service %s", serviceObj.ServiceName) + } - chartPackagePath, err := helm.CreateChartPackage(&helm.Chart{Chart: chartRequested}, dir) + //load chart info from local storage + chartRequested, err := chartloader.Load(deliveryChartPath) if err != nil { - return nil, err + return errors.Wrapf(err, "failed to load chart info, path %s", deliveryChartPath) } - // parse docker image - imagesData, err := extractImages(deliveryVersion, serviceObj, chartRequested.Values, targetRegistry, registryMap) + //set metadata + chartRequested.Metadata.Name = chartData.ChartData.ServiceName + chartRequested.Metadata.Version = chartData.ChartData.Version + chartRequested.Metadata.AppVersion = chartData.ChartData.Version + + //create local chart package + chartPackagePath, err := helm.CreateChartPackage(&helm.Chart{Chart: chartRequested}, dir) if err != nil { - return nil, errors.Wrapf(err, "failed to handle image") + return err } client, err := createChartRepoClient(chartRepo) if err != nil { - return nil, errors.Wrapf(err, "failed to create chart repo client, repoName: %s", chartRepo.RepoName) + return errors.Wrapf(err, "failed to create chart repo client, repoName: %s", chartRepo.RepoName) } - log.Infof("pushing %s to %s...\n", filepath.Base(chartPackagePath), chartRepo.URL) + log.Infof("pushing chart %s to %s...", filepath.Base(chartPackagePath), chartRepo.URL) resp, err := client.UploadChartPackage(chartPackagePath, false) if err != nil { - return nil, errors.Wrapf(err, "failed to prepare pushing chart: %s", chartPackagePath) + return errors.Wrapf(err, "failed to prepare pushing chart: %s", chartPackagePath) } err = handlePushResponse(resp) if err != nil { - return nil, errors.Wrapf(err, "failed to push chart: %s ", chartPackagePath) + return errors.Wrapf(err, "failed to push chart: %s ", chartPackagePath) } - return imagesData, nil + return nil } func handlePushResponse(resp *http.Response) error { @@ -719,26 +709,45 @@ func CreateHelmDeliveryVersion(args *CreateHelmDeliveryVersionArgs, logger *zap. // validate chartInfo, make sure service is in environment // prepare data set for chart delivery func prepareChartData(chartDatas []*CreateHelmDeliveryVersionChartData, productInfo *commonmodels.Product) (map[string]*DeliveryChartData, error) { + + renderSet, err := commonrepo.NewRenderSetColl().Find(&commonrepo.RenderSetFindOption{ + Revision: productInfo.Render.Revision, + Name: productInfo.Render.Name, + }) + if err != nil { + return nil, fmt.Errorf("failed to find renderSet: %s, revision: %d", productInfo.Render.Name, productInfo.Render.Revision) + } + chartMap := make(map[string]*template.RenderChart) + for _, rChart := range renderSet.ChartInfos { + chartMap[rChart.ServiceName] = rChart + } + chartDataMap := make(map[string]*DeliveryChartData) serviceMap := productInfo.GetServiceMap() - for _, chartDta := range chartDatas { - if productService, ok := serviceMap[chartDta.ServiceName]; ok { + for _, chartData := range chartDatas { + if productService, ok := serviceMap[chartData.ServiceName]; ok { serviceObj, err := commonrepo.NewServiceColl().Find(&commonrepo.ServiceFindOption{ - ServiceName: chartDta.ServiceName, + ServiceName: chartData.ServiceName, Revision: productService.Revision, Type: setting.HelmDeployType, ProductName: productInfo.ProductName, }) if err != nil { - return nil, fmt.Errorf("failed to query service: %s", chartDta.ServiceName) + return nil, fmt.Errorf("failed to query service: %s", chartData.ServiceName) } - chartDataMap[chartDta.ServiceName] = &DeliveryChartData{ - ChartData: chartDta, - //ProductService: productService, - ServiceObj: serviceObj, + renderChart, ok := chartMap[chartData.ServiceName] + if !ok { + return nil, fmt.Errorf("can't find renderChart for service: %s", chartData.ServiceName) + } + chartDataMap[chartData.ServiceName] = &DeliveryChartData{ + ChartData: chartData, + RenderChart: renderChart, + ServiceObj: serviceObj, + ProductService: productService, + RenderSet: renderSet, } } else { - return nil, fmt.Errorf("service %s not found in environment", chartDta.ServiceName) + return nil, fmt.Errorf("service %s not found in environment", chartData.ServiceName) } } return chartDataMap, nil @@ -857,14 +866,6 @@ func buildDeliveryCharts(chartDataMap map[string]*DeliveryChartData, deliveryVer return fmt.Errorf("failed to query chart-repo info, productName: %s, repoName: %s", deliveryVersion.ProductName, args.ChartRepoName) } - targetRegistry, err := commonrepo.NewRegistryNamespaceColl().Find(&mongodb.FindRegOps{ - ID: args.ImageRegistryID, - }) - if err != nil { - log.Errorf("failed to query target image registry with ID: %s, err %s", args.ImageRegistryID, err) - return fmt.Errorf("faild to query target registry namespace") - } - registryMap, err := buildRegistryMap() if err != nil { return fmt.Errorf("failed to build registry map") @@ -878,14 +879,19 @@ func buildDeliveryCharts(chartDataMap map[string]*DeliveryChartData, deliveryVer wg.Add(1) go func(cData *DeliveryChartData) { defer wg.Done() - imagesData, err := handleSingleChart(deliveryVersion, cData, repoInfo, dir, args.GlobalVariables, targetRegistry, registryMap) + err := buildChartPackage(cData, repoInfo, dir, args.GlobalVariables, registryMap) if err != nil { - logger.Errorf("failed to handle single chart data, serviceName: %s err: %s", cData.ChartData.ServiceName, err) + logger.Errorf("failed to build chart package, serviceName: %s err: %s", cData.ChartData.ServiceName, err) appendError(err) return } - imagesDataMap.Store(cData.ServiceObj.ServiceName, imagesData) - + imageData, err := extractImages(cData.ProductService, registryMap) + if err != nil { + logger.Errorf("failed to extract image data, serviceName: %s err: %s", cData.ChartData.ServiceName, err) + appendError(err) + return + } + imagesDataMap.Store(cData.ServiceObj.ServiceName, imageData) }(chartData) } wg.Wait() @@ -950,7 +956,7 @@ func taskFinished(status config.Status) bool { } func waitVersionDone(deliveryVersion *commonmodels.DeliveryVersion) { - waitTimeout := time.After(10 * time.Minute) + waitTimeout := time.After(60 * time.Minute * 2) for { select { case <-waitTimeout: @@ -1049,6 +1055,9 @@ func checkVersionStatus(deliveryVersion *commonmodels.DeliveryVersion) (bool, er if !taskFinished(artifactPackageArgs.TaskStatus) { allTaskDone = false } + if len(artifactPackageArgs.Error) > 0 { + errorList = multierror.Append(errorList, fmt.Errorf(artifactPackageArgs.Error)) + } } if allTaskDone { @@ -1334,6 +1343,86 @@ func preDownloadChart(projectName, versionName, chartName string, log *zap.Sugar return filePath, err } +func getIndexDownloader(client *cm.Client) helm.IndexDownloader { + return func() ([]byte, error) { + resp, err := client.DownloadFile("index.yaml") + if err != nil { + return nil, err + } + defer func(Body io.ReadCloser) { + _ = Body.Close() + }(resp.Body) + + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + if resp.StatusCode != 200 { + return nil, getChartmuseumError(b, resp.StatusCode) + } + return b, nil + } +} + +func GetChartVersions(chartName, chartRepoName string) ([]*ChartVersionResp, error) { + + chartRepo, err := getChartRepoData(chartRepoName) + if err != nil { + return nil, fmt.Errorf("failed to query chart-repo info, repoName %s", chartRepoName) + } + + client, err := createChartRepoClient(chartRepo) + if err != nil { + return nil, errors.Wrapf(err, "failed to create chart repo client") + } + + resp, err := client.DownloadFile("index.yaml") + if err != nil { + return nil, errors.Wrapf(err, "failed to download index.yaml") + } + + defer func(Body io.ReadCloser) { + _ = Body.Close() + }(resp.Body) + + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + return nil, errors.Wrapf(getChartmuseumError(b, resp.StatusCode), "failed to download index.yaml") + } + + log.Infof("###### the raw data is %s", string(b)) + + index, err := helm.LoadIndex(b) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse index.yaml") + } + + chartNameList := strings.Split(chartName, ",") + chartNameSet := sets.NewString(chartNameList...) + + ret := make([]*ChartVersionResp, 0) + + for name, entry := range index.Entries { + if !chartNameSet.Has(name) { + continue + } + if len(entry) == 0 { + continue + } + latestEntry := entry[0] + ret = append(ret, &ChartVersionResp{ + ChartName: name, + ChartVersion: latestEntry.Version, + }) + } + + return ret, nil +} + func preDownloadAndUncompressChart(projectName, versionName, chartName string, log *zap.SugaredLogger) (string, error) { deliveryInfo, err := GetDeliveryVersion(&commonrepo.DeliveryVersionArgs{ diff --git a/pkg/microservice/aslan/core/environment/service/helm.go b/pkg/microservice/aslan/core/environment/service/helm.go index 20f887383..8a2ea6097 100644 --- a/pkg/microservice/aslan/core/environment/service/helm.go +++ b/pkg/microservice/aslan/core/environment/service/helm.go @@ -219,6 +219,7 @@ func GetChartInfos(productName, envName, serviceName string, log *zap.SugaredLog go func(serviceName string, revision int64) { defer wg.Done() serviceObj, err := commonrepo.NewServiceColl().Find(&commonrepo.ServiceFindOption{ + ProductName: productName, ServiceName: serviceName, Revision: revision, Type: setting.HelmDeployType, diff --git a/pkg/microservice/aslan/core/service/service/helm.go b/pkg/microservice/aslan/core/service/service/helm.go index 7d0c214ee..931bfa21c 100644 --- a/pkg/microservice/aslan/core/service/service/helm.go +++ b/pkg/microservice/aslan/core/service/service/helm.go @@ -211,13 +211,7 @@ func GetFileContent(serviceName, productName string, param *GetFileContentParam, } if forDelivery { - fullPath := filepath.Join(base, serviceName) base = config.LocalDeliveryChartPathWithRevision(productName, serviceName, revision) - deliveryChartPath := filepath.Join(base, serviceName) - err := copy.Copy(fullPath, deliveryChartPath) - if err != nil { - return "", e.ErrFileContent.AddErr(err) - } } file := filepath.Join(base, serviceName, filePath, fileName) -- Gitee From 00efc07a79df64f9ba13ac33cab955d8914391ea Mon Sep 17 00:00:00 2001 From: allenshen Date: Wed, 8 Dec 2021 10:49:53 +0800 Subject: [PATCH 066/134] optimize code Signed-off-by: allenshen --- .../core/common/repository/models/queue.go | 3 ++- .../aslan/core/workflow/handler/router.go | 4 ---- .../aslan/core/workflow/handler/workflow.go | 22 ------------------- .../service/workflow/artifact_task.go | 2 +- .../packager/core/service/service.go | 1 - .../service/taskplugin/artifact_package.go | 17 +++++++------- 6 files changed, 11 insertions(+), 38 deletions(-) diff --git a/pkg/microservice/aslan/core/common/repository/models/queue.go b/pkg/microservice/aslan/core/common/repository/models/queue.go index 9d81c752c..bda3be278 100644 --- a/pkg/microservice/aslan/core/common/repository/models/queue.go +++ b/pkg/microservice/aslan/core/common/repository/models/queue.go @@ -19,8 +19,9 @@ package models import ( "sync" - "github.com/koderover/zadig/pkg/microservice/aslan/config" "go.mongodb.org/mongo-driver/bson/primitive" + + "github.com/koderover/zadig/pkg/microservice/aslan/config" ) type Queue struct { diff --git a/pkg/microservice/aslan/core/workflow/handler/router.go b/pkg/microservice/aslan/core/workflow/handler/router.go index b8fde441d..091767d45 100644 --- a/pkg/microservice/aslan/core/workflow/handler/router.go +++ b/pkg/microservice/aslan/core/workflow/handler/router.go @@ -103,10 +103,6 @@ func (*Router) Inject(router *gin.RouterGroup) { { workflow.POST("/:productName/auto", AutoCreateWorkflow) workflow.POST("", GetWorkflowProductName, gin2.UpdateOperationLogStatus, CreateWorkflow) - - // test api need to delete - workflow.POST("airifactTask", GetWorkflowProductName, gin2.UpdateOperationLogStatus, CreateArtifactTask) - workflow.PUT("", GetWorkflowProductName, gin2.UpdateOperationLogStatus, UpdateWorkflow) workflow.GET("", ListWorkflows) workflow.GET("/testName/:testName", ListTestWorkflows) diff --git a/pkg/microservice/aslan/core/workflow/handler/workflow.go b/pkg/microservice/aslan/core/workflow/handler/workflow.go index d33f1a589..c73934a41 100644 --- a/pkg/microservice/aslan/core/workflow/handler/workflow.go +++ b/pkg/microservice/aslan/core/workflow/handler/workflow.go @@ -90,28 +90,6 @@ func CreateWorkflow(c *gin.Context) { ctx.Err = workflow.CreateWorkflow(args, ctx.Logger) } -// TODO test code need to delete -func CreateArtifactTask(c *gin.Context) { - ctx := internalhandler.NewContext(c) - defer func() { internalhandler.JSONResponse(c, ctx) }() - - args := new(commonmodels.ArtifactPackageTaskArgs) - data, err := c.GetRawData() - if err != nil { - log.Errorf("CreateWorkflow c.GetRawData() err : %v", err) - } - if err = json.Unmarshal(data, args); err != nil { - log.Errorf("CreateWorkflow json.Unmarshal err : %v", err) - } - c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) - if err := c.ShouldBindWith(&args, binding.JSON); err != nil { - ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) - return - } - - ctx.Err = workflow.CreateArtifactPackageTask(args, ctx.Logger) -} - // UpdateWorkflow update a workflow func UpdateWorkflow(c *gin.Context) { ctx := internalhandler.NewContext(c) diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go index 15c7b59fa..00ca9b6c0 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go @@ -20,6 +20,7 @@ import ( "fmt" "sort" + "go.uber.org/zap" "k8s.io/apimachinery/pkg/util/sets" "github.com/koderover/zadig/pkg/microservice/aslan/config" @@ -32,7 +33,6 @@ import ( "github.com/koderover/zadig/pkg/setting" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/util" - "go.uber.org/zap" ) func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, log *zap.SugaredLogger) error { diff --git a/pkg/microservice/packager/core/service/service.go b/pkg/microservice/packager/core/service/service.go index 043ac8c6d..c35301fd1 100644 --- a/pkg/microservice/packager/core/service/service.go +++ b/pkg/microservice/packager/core/service/service.go @@ -29,7 +29,6 @@ import ( "time" "github.com/pkg/errors" - "gopkg.in/yaml.v3" "github.com/koderover/zadig/pkg/microservice/packager/config" diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go b/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go index 2436728d6..24fcb3832 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go @@ -21,21 +21,20 @@ import ( "fmt" "time" - "github.com/koderover/zadig/pkg/shared/kube/wrapper" - "github.com/koderover/zadig/pkg/tool/kube/getter" - "github.com/koderover/zadig/pkg/tool/kube/podexec" - "k8s.io/apimachinery/pkg/labels" - - "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types" - "github.com/koderover/zadig/pkg/setting" + "go.uber.org/zap" "gopkg.in/yaml.v3" + "k8s.io/apimachinery/pkg/labels" + "sigs.k8s.io/controller-runtime/pkg/client" "github.com/koderover/zadig/pkg/microservice/warpdrive/config" + "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types" "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types/task" + "github.com/koderover/zadig/pkg/setting" + "github.com/koderover/zadig/pkg/shared/kube/wrapper" krkubeclient "github.com/koderover/zadig/pkg/tool/kube/client" + "github.com/koderover/zadig/pkg/tool/kube/getter" + "github.com/koderover/zadig/pkg/tool/kube/podexec" "github.com/koderover/zadig/pkg/tool/kube/updater" - "go.uber.org/zap" - "sigs.k8s.io/controller-runtime/pkg/client" ) // InitializeArtifactPackagePlugin to ini -- Gitee From 8c79d67723e15114d9ed8b519b19510e7525306e Mon Sep 17 00:00:00 2001 From: mouuii <49775493+mouuii@users.noreply.github.com> Date: Wed, 8 Dec 2021 10:54:07 +0800 Subject: [PATCH 067/134] workflow (#693) Signed-off-by: mouuii --- .../aslan/core/workflow/service/workflow/workflow.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow.go index d87e15cff..a2f167ff8 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow.go @@ -60,6 +60,7 @@ type Workflow struct { RecentFailedTask *TaskInfo `json:"recentFailedTask"` AverageExecutionTime float64 `json:"averageExecutionTime"` SuccessRate float64 `json:"successRate"` + Description string `json:"description,omitempty"` } type TaskInfo struct { @@ -538,6 +539,7 @@ func ListWorkflows(projects []string, userID string, log *zap.SugaredLogger) ([] SchedulerEnabled: w.ScheduleEnabled, Schedules: w.Schedules, EnabledStages: stages, + Description: w.Description, }) workflowNames = append(workflowNames, w.Name) -- Gitee From 04def52a8f17cb1a1b8329876c11a70870c3e81b Mon Sep 17 00:00:00 2001 From: liu deyi Date: Wed, 8 Dec 2021 14:01:27 +0800 Subject: [PATCH 068/134] optimize code Signed-off-by: liu deyi --- pkg/microservice/aslan/core/common/service/kube/service.go | 1 - pkg/microservice/aslan/core/common/service/product.go | 2 +- pkg/microservice/aslan/core/multicluster/service/clusters.go | 3 +-- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/pkg/microservice/aslan/core/common/service/kube/service.go b/pkg/microservice/aslan/core/common/service/kube/service.go index 97180eb03..47aca9353 100644 --- a/pkg/microservice/aslan/core/common/service/kube/service.go +++ b/pkg/microservice/aslan/core/common/service/kube/service.go @@ -24,7 +24,6 @@ import ( "text/template" "go.mongodb.org/mongo-driver/bson/primitive" - "go.uber.org/zap" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" diff --git a/pkg/microservice/aslan/core/common/service/product.go b/pkg/microservice/aslan/core/common/service/product.go index e336b30d2..b18548d79 100644 --- a/pkg/microservice/aslan/core/common/service/product.go +++ b/pkg/microservice/aslan/core/common/service/product.go @@ -21,7 +21,6 @@ import ( "time" "github.com/hashicorp/go-multierror" - client2 "github.com/koderover/zadig/pkg/shared/kube/client" helmclient "github.com/mittwald/go-helm-client" "go.uber.org/zap" "k8s.io/apimachinery/pkg/labels" @@ -36,6 +35,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb/template" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" + client2 "github.com/koderover/zadig/pkg/shared/kube/client" e "github.com/koderover/zadig/pkg/tool/errors" helmtool "github.com/koderover/zadig/pkg/tool/helmclient" "github.com/koderover/zadig/pkg/tool/kube/updater" diff --git a/pkg/microservice/aslan/core/multicluster/service/clusters.go b/pkg/microservice/aslan/core/multicluster/service/clusters.go index 928b7e612..6a9bed6d3 100644 --- a/pkg/microservice/aslan/core/multicluster/service/clusters.go +++ b/pkg/microservice/aslan/core/multicluster/service/clusters.go @@ -22,9 +22,8 @@ import ( "regexp" "strings" - "go.mongodb.org/mongo-driver/bson/primitive" - "github.com/gin-gonic/gin" + "go.mongodb.org/mongo-driver/bson/primitive" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/sets" -- Gitee From e3e70705146e2ae7c498d682d194af860af28812 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Wed, 8 Dec 2021 14:05:02 +0800 Subject: [PATCH 069/134] optimize code Signed-off-by: liu deyi --- .../aslan/core/multicluster/service/clusters.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pkg/microservice/aslan/core/multicluster/service/clusters.go b/pkg/microservice/aslan/core/multicluster/service/clusters.go index 6a9bed6d3..a8380b37f 100644 --- a/pkg/microservice/aslan/core/multicluster/service/clusters.go +++ b/pkg/microservice/aslan/core/multicluster/service/clusters.go @@ -94,16 +94,18 @@ func ListClusters(ids []string, logger *zap.SugaredLogger) ([]*K8SCluster, error var res []*K8SCluster for _, c := range cs { - advancedConfig := new(AdvancedConfig) + var advancedConfig *AdvancedConfig if c.AdvancedConfig != nil { - advancedConfig.Strategy = c.AdvancedConfig.Strategy var nodeLabels []string for _, nodeSelectorRequirement := range c.AdvancedConfig.NodeLabels { for _, labelValue := range nodeSelectorRequirement.Value { nodeLabels = append(nodeLabels, fmt.Sprintf("%s:%s", nodeSelectorRequirement.Key, labelValue)) } } - advancedConfig.NodeLabels = nodeLabels + advancedConfig = &AdvancedConfig{ + Strategy: c.AdvancedConfig.Strategy, + NodeLabels: nodeLabels, + } } res = append(res, &K8SCluster{ ID: c.ID.Hex(), -- Gitee From 614ebc504bdd674fa7e7db3ac19929e770e0e0c8 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Wed, 8 Dec 2021 14:32:54 +0800 Subject: [PATCH 070/134] optimize code Signed-off-by: liu deyi --- .../core/multicluster/service/clusters.go | 80 +++++++------------ 1 file changed, 30 insertions(+), 50 deletions(-) diff --git a/pkg/microservice/aslan/core/multicluster/service/clusters.go b/pkg/microservice/aslan/core/multicluster/service/clusters.go index a8380b37f..1c615c6db 100644 --- a/pkg/microservice/aslan/core/multicluster/service/clusters.go +++ b/pkg/microservice/aslan/core/multicluster/service/clusters.go @@ -40,23 +40,16 @@ import ( var namePattern = regexp.MustCompile(`^[0-9a-zA-Z_.-]{1,32}$`) type K8SCluster struct { - ID string `json:"id,omitempty"` - Name string `json:"name"` - Tags []string `json:"tags"` - Description string `json:"description"` - Namespace string `json:"namespace"` - Info *commonmodels.K8SClusterInfo `json:"info,omitempty"` - AdvancedConfig *AdvancedConfig `json:"config,omitempty"` - Status setting.K8SClusterStatus `json:"status"` - Error string `json:"error"` - Yaml string `json:"yaml"` - Production bool `json:"production"` - CreatedAt int64 `json:"createdAt"` - CreatedBy string `json:"createdBy"` - Disconnected bool `json:"-"` - Token string `json:"token"` - Provider int8 `json:"provider"` - Local bool `json:"local"` + ID string `json:"id,omitempty"` + Name string `json:"name"` + Description string `json:"description"` + AdvancedConfig *AdvancedConfig `json:"config,omitempty"` + Status setting.K8SClusterStatus `json:"status"` + Production bool `json:"production"` + CreatedAt int64 `json:"createdAt"` + CreatedBy string `json:"createdBy"` + Provider int8 `json:"provider"` + Local bool `json:"local"` } type AdvancedConfig struct { @@ -64,17 +57,8 @@ type AdvancedConfig struct { NodeLabels []string `json:"node_labels,omitempty" bson:"node_labels,omitempty"` } -func (k *K8SCluster) Clean() error { +func (k *K8SCluster) Validate() error { k.Name = strings.TrimSpace(k.Name) - tags := k.Tags - k.Tags = []string{} - for _, tag := range tags { - tag = strings.TrimSpace(tag) - if tag != "" { - k.Tags = append(k.Tags, tag) - } - } - k.Description = strings.TrimSpace(k.Description) if !namePattern.MatchString(k.Name) { @@ -96,16 +80,8 @@ func ListClusters(ids []string, logger *zap.SugaredLogger) ([]*K8SCluster, error for _, c := range cs { var advancedConfig *AdvancedConfig if c.AdvancedConfig != nil { - var nodeLabels []string - for _, nodeSelectorRequirement := range c.AdvancedConfig.NodeLabels { - for _, labelValue := range nodeSelectorRequirement.Value { - nodeLabels = append(nodeLabels, fmt.Sprintf("%s:%s", nodeSelectorRequirement.Key, labelValue)) - } - } - advancedConfig = &AdvancedConfig{ - Strategy: c.AdvancedConfig.Strategy, - NodeLabels: nodeLabels, - } + advancedConfig = convertToAdvancedConfig(c.AdvancedConfig.NodeLabels) + advancedConfig.Strategy = c.AdvancedConfig.Strategy } res = append(res, &K8SCluster{ ID: c.ID.Hex(), @@ -130,10 +106,23 @@ func GetCluster(id string, logger *zap.SugaredLogger) (*commonmodels.K8SCluster, return s.GetCluster(id, logger) } -func convertToNodeSelectorRequirements(args *K8SCluster) []*commonmodels.NodeSelectorRequirement { +func convertToAdvancedConfig(nodeSelectorRequirements []*commonmodels.NodeSelectorRequirement) *AdvancedConfig { + var nodeLabels []string + for _, nodeSelectorRequirement := range nodeSelectorRequirements { + for _, labelValue := range nodeSelectorRequirement.Value { + nodeLabels = append(nodeLabels, fmt.Sprintf("%s:%s", nodeSelectorRequirement.Key, labelValue)) + } + } + advancedConfig := &AdvancedConfig{ + NodeLabels: nodeLabels, + } + return advancedConfig +} + +func convertToNodeSelectorRequirements(args *AdvancedConfig) []*commonmodels.NodeSelectorRequirement { var nodeSelectorRequirements []*commonmodels.NodeSelectorRequirement nodeLabelM := make(map[string][]string) - for _, nodeLabel := range args.AdvancedConfig.NodeLabels { + for _, nodeLabel := range args.NodeLabels { if !strings.Contains(nodeLabel, ":") || len(strings.Split(nodeLabel, ":")) != 2 { continue } @@ -156,21 +145,14 @@ func CreateCluster(args *K8SCluster, logger *zap.SugaredLogger) (*commonmodels.K advancedConfig := new(commonmodels.AdvancedConfig) if args.AdvancedConfig != nil { advancedConfig.Strategy = args.AdvancedConfig.Strategy - advancedConfig.NodeLabels = convertToNodeSelectorRequirements(args) + advancedConfig.NodeLabels = convertToNodeSelectorRequirements(args.AdvancedConfig) } cluster := &commonmodels.K8SCluster{ Name: args.Name, - Tags: args.Tags, Description: args.Description, - Namespace: args.Namespace, - Info: args.Info, AdvancedConfig: advancedConfig, Status: args.Status, - Error: args.Error, - Yaml: args.Yaml, Production: args.Production, - Disconnected: args.Disconnected, - Token: args.Token, Provider: args.Provider, Local: args.Local, CreatedAt: args.CreatedAt, @@ -187,13 +169,11 @@ func UpdateCluster(id string, args *K8SCluster, logger *zap.SugaredLogger) (*com advancedConfig := new(commonmodels.AdvancedConfig) if args.AdvancedConfig != nil { advancedConfig.Strategy = args.AdvancedConfig.Strategy - advancedConfig.NodeLabels = convertToNodeSelectorRequirements(args) + advancedConfig.NodeLabels = convertToNodeSelectorRequirements(args.AdvancedConfig) } cluster := &commonmodels.K8SCluster{ Name: args.Name, - Tags: args.Tags, Description: args.Description, - Namespace: args.Namespace, AdvancedConfig: advancedConfig, Production: args.Production, } -- Gitee From ca118a4c3e7a8877e3d266686912f55556d09e95 Mon Sep 17 00:00:00 2001 From: landylee007 Date: Wed, 8 Dec 2021 14:35:22 +0800 Subject: [PATCH 071/134] add links for api gateway component gloo,opa,dex --- System-Architecture-Overview-zh-CN.md | 6 +++--- System-Architecture-Overview.md | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/System-Architecture-Overview-zh-CN.md b/System-Architecture-Overview-zh-CN.md index 4f10c078a..dcef018df 100644 --- a/System-Architecture-Overview-zh-CN.md +++ b/System-Architecture-Overview-zh-CN.md @@ -12,10 +12,10 @@ - Zadig Toolkit:vscode 开发者插件 API 网关: -- Gloo Edge:Zadig 的 API 网关组件 -- OPA:认证和授权组件 +- [Gloo Edge](https://github.com/solo-io/gloo):Zadig 的 API 网关组件 +- [OPA](https://github.com/open-policy-agent/opa):认证和授权组件 +- [Dex](https://github.com/dexidp/dex):Zadig 的身份认证服务,用于连接其他第三方认证系统,比如 AD / LDAP / OAuth2 / GitHub / .. - User:用户管理,Token 生成 -- Dex:Zadig 的身份认证服务,用于连接其他第三方认证系统,比如 AD / LDAP / OAuth2 / GitHub / .. Zadig 核心业务: - Picket:数据聚合服务 diff --git a/System-Architecture-Overview.md b/System-Architecture-Overview.md index 61e059779..9c9414992 100644 --- a/System-Architecture-Overview.md +++ b/System-Architecture-Overview.md @@ -12,10 +12,10 @@ User Interface: - Zadig Toolkit:vscode plugin API Gateway: -- Gloo Edge:Zadig API gateway -- OPA:Authentication and authorization +- [Gloo Edge](https://github.com/solo-io/gloo):Zadig API gateway +- [OPA](https://github.com/open-policy-agent/opa):Authentication and authorization +- [Dex](https://github.com/dexidp/dex):Identity service for Zadig, acts as a portal to other identity providers like AD / LDAP / OAuth2 / GitHub / .. - User:User management, token generation -- Dex:Identity service for Zadig, acts as a portal to other identity providers like AD / LDAP / OAuth2 / GitHub / .. Zadig Core: - Picket:backend for frontend service. -- Gitee From ef6fd727f85748d1e90ddcd952f27c256aeecea8 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Wed, 8 Dec 2021 14:47:29 +0800 Subject: [PATCH 072/134] optimize code Signed-off-by: liu deyi --- .../core/multicluster/service/clusters.go | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/pkg/microservice/aslan/core/multicluster/service/clusters.go b/pkg/microservice/aslan/core/multicluster/service/clusters.go index 1c615c6db..6e606700c 100644 --- a/pkg/microservice/aslan/core/multicluster/service/clusters.go +++ b/pkg/microservice/aslan/core/multicluster/service/clusters.go @@ -57,7 +57,7 @@ type AdvancedConfig struct { NodeLabels []string `json:"node_labels,omitempty" bson:"node_labels,omitempty"` } -func (k *K8SCluster) Validate() error { +func (k *K8SCluster) Clean() error { k.Name = strings.TrimSpace(k.Name) k.Description = strings.TrimSpace(k.Description) @@ -80,8 +80,10 @@ func ListClusters(ids []string, logger *zap.SugaredLogger) ([]*K8SCluster, error for _, c := range cs { var advancedConfig *AdvancedConfig if c.AdvancedConfig != nil { - advancedConfig = convertToAdvancedConfig(c.AdvancedConfig.NodeLabels) - advancedConfig.Strategy = c.AdvancedConfig.Strategy + advancedConfig = &AdvancedConfig{ + Strategy: c.AdvancedConfig.Strategy, + NodeLabels: convertToNodeLabels(c.AdvancedConfig.NodeLabels), + } } res = append(res, &K8SCluster{ ID: c.ID.Hex(), @@ -106,23 +108,21 @@ func GetCluster(id string, logger *zap.SugaredLogger) (*commonmodels.K8SCluster, return s.GetCluster(id, logger) } -func convertToAdvancedConfig(nodeSelectorRequirements []*commonmodels.NodeSelectorRequirement) *AdvancedConfig { +func convertToNodeLabels(nodeSelectorRequirements []*commonmodels.NodeSelectorRequirement) []string { var nodeLabels []string for _, nodeSelectorRequirement := range nodeSelectorRequirements { for _, labelValue := range nodeSelectorRequirement.Value { nodeLabels = append(nodeLabels, fmt.Sprintf("%s:%s", nodeSelectorRequirement.Key, labelValue)) } } - advancedConfig := &AdvancedConfig{ - NodeLabels: nodeLabels, - } - return advancedConfig + + return nodeLabels } -func convertToNodeSelectorRequirements(args *AdvancedConfig) []*commonmodels.NodeSelectorRequirement { +func convertToNodeSelectorRequirements(nodeLabels []string) []*commonmodels.NodeSelectorRequirement { var nodeSelectorRequirements []*commonmodels.NodeSelectorRequirement nodeLabelM := make(map[string][]string) - for _, nodeLabel := range args.NodeLabels { + for _, nodeLabel := range nodeLabels { if !strings.Contains(nodeLabel, ":") || len(strings.Split(nodeLabel, ":")) != 2 { continue } @@ -145,7 +145,7 @@ func CreateCluster(args *K8SCluster, logger *zap.SugaredLogger) (*commonmodels.K advancedConfig := new(commonmodels.AdvancedConfig) if args.AdvancedConfig != nil { advancedConfig.Strategy = args.AdvancedConfig.Strategy - advancedConfig.NodeLabels = convertToNodeSelectorRequirements(args.AdvancedConfig) + advancedConfig.NodeLabels = convertToNodeSelectorRequirements(args.AdvancedConfig.NodeLabels) } cluster := &commonmodels.K8SCluster{ Name: args.Name, @@ -169,7 +169,7 @@ func UpdateCluster(id string, args *K8SCluster, logger *zap.SugaredLogger) (*com advancedConfig := new(commonmodels.AdvancedConfig) if args.AdvancedConfig != nil { advancedConfig.Strategy = args.AdvancedConfig.Strategy - advancedConfig.NodeLabels = convertToNodeSelectorRequirements(args.AdvancedConfig) + advancedConfig.NodeLabels = convertToNodeSelectorRequirements(args.AdvancedConfig.NodeLabels) } cluster := &commonmodels.K8SCluster{ Name: args.Name, -- Gitee From 437297aecf6a0f0ed4f2e467b07e5051b0f51e3c Mon Sep 17 00:00:00 2001 From: shendongdong Date: Wed, 8 Dec 2021 15:54:42 +0800 Subject: [PATCH 073/134] add 1.7.1 version define (#701) Signed-off-by: allenshen --- pkg/cli/upgradeassistant/internal/upgradepath/versions.go | 2 ++ version/version.go | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/cli/upgradeassistant/internal/upgradepath/versions.go b/pkg/cli/upgradeassistant/internal/upgradepath/versions.go index 0304cee03..cdc712339 100644 --- a/pkg/cli/upgradeassistant/internal/upgradepath/versions.go +++ b/pkg/cli/upgradeassistant/internal/upgradepath/versions.go @@ -30,6 +30,7 @@ const ( V150 V160 V170 + V171 ) var versionMap versions = map[string]int{ @@ -39,6 +40,7 @@ var versionMap versions = map[string]int{ "1.5.0": V150, "1.6.0": V160, "1.7.0": V170, + "1.7.1": V171, } type versions map[string]int diff --git a/version/version.go b/version/version.go index 90ad69753..1faa9cfcd 100644 --- a/version/version.go +++ b/version/version.go @@ -17,7 +17,7 @@ limitations under the License. package version var ( - Version = "1.7.0" + Version = "1.7.1" BuildNumber = "0" GitCommit = "" ) -- Gitee From 0d951dfcbfd323e13f0cc7753856143b16e09cb3 Mon Sep 17 00:00:00 2001 From: lou Date: Wed, 8 Dec 2021 16:22:55 +0800 Subject: [PATCH 074/134] do not panic for remote cluster Signed-off-by: lou --- pkg/tool/kube/client/cluster.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/pkg/tool/kube/client/cluster.go b/pkg/tool/kube/client/cluster.go index 927cd4115..d4b70be03 100644 --- a/pkg/tool/kube/client/cluster.go +++ b/pkg/tool/kube/client/cluster.go @@ -38,7 +38,11 @@ var c cluster.Cluster // Cluster is a singleton, it will be initialized only once. func Cluster() cluster.Cluster { once.Do(func() { - c = initCluster(ctrl.GetConfigOrDie()) + var err error + c, err = initCluster(ctrl.GetConfigOrDie()) + if err != nil { + panic(err) + } }) return c @@ -77,7 +81,10 @@ func NewClientFromAPIConfig(cfg *api.Config) (client.Client, error) { return nil, err } - cls := initCluster(restConfig) + cls, err := initCluster(restConfig) + if err != nil { + return nil, err + } return newAPIClient(cls.GetClient(), cls.GetAPIReader()), nil } @@ -105,7 +112,7 @@ func (c *apiClient) List(ctx context.Context, list client.ObjectList, opts ...cl return c.apiReader.List(ctx, list, opts...) } -func initCluster(restConfig *rest.Config) cluster.Cluster { +func initCluster(restConfig *rest.Config) (cluster.Cluster, error) { scheme := runtime.NewScheme() // add all known types @@ -116,8 +123,8 @@ func initCluster(restConfig *rest.Config) cluster.Cluster { clusterOptions.Scheme = scheme }) if err != nil { - panic(errors.Wrap(err, "unable to init client")) + return nil, errors.Wrap(err, "unable to init client") } - return c + return c, nil } -- Gitee From 3a90e9af8ccff41a76847a8990080d9d0bad686b Mon Sep 17 00:00:00 2001 From: liu deyi Date: Wed, 8 Dec 2021 16:24:19 +0800 Subject: [PATCH 075/134] optimize code Signed-off-by: liu deyi --- pkg/cli/initconfig/cmd/init.go | 5 +++- .../common/repository/models/k8s_cluster.go | 2 +- .../common/repository/mongodb/k8s_cluster.go | 14 +++++++--- .../aslan/core/common/service/environment.go | 4 +-- .../aslan/core/common/service/kube/service.go | 27 +++++++++---------- .../aslan/core/common/service/product.go | 4 +-- .../core/environment/service/configmap.go | 8 +++--- .../core/environment/service/environment.go | 8 +++--- .../service/environment_creator.go | 6 ++--- .../environment/service/environment_group.go | 4 +-- .../aslan/core/environment/service/export.go | 4 +-- .../aslan/core/environment/service/image.go | 4 +-- .../aslan/core/environment/service/k8s.go | 4 +-- .../aslan/core/environment/service/kube.go | 14 +++++----- .../aslan/core/environment/service/service.go | 14 +++++----- .../aslan/core/environment/service/types.go | 5 ++++ .../aslan/core/log/service/sse.go | 6 ++--- .../core/multicluster/service/clusters.go | 8 ++---- .../aslan/core/service/service/service.go | 6 ++--- .../aslan/core/system/service/registry.go | 6 ++--- .../service/workflow/pipeline_validation.go | 4 +-- .../core/service/taskplugin/build.go | 4 +-- .../core/service/taskplugin/deploy.go | 6 ++--- .../warpdrive/core/service/taskplugin/job.go | 4 +-- .../core/service/taskplugin/testing.go | 4 +-- pkg/shared/client/aslan/multicluster.go | 11 ++++---- pkg/shared/kube/resource/node.go | 5 ---- 27 files changed, 98 insertions(+), 93 deletions(-) diff --git a/pkg/cli/initconfig/cmd/init.go b/pkg/cli/initconfig/cmd/init.go index 00add4ae7..b27f0ed81 100644 --- a/pkg/cli/initconfig/cmd/init.go +++ b/pkg/cli/initconfig/cmd/init.go @@ -204,7 +204,10 @@ func presetRole() error { } func createLocalCluster() error { - cluster, _ := aslan.New(config.AslanServiceAddress()).GetCluster() + cluster, err := aslan.New(config.AslanServiceAddress()).GetLocalCluster() + if err != nil { + return err + } if cluster != nil { return nil } diff --git a/pkg/microservice/aslan/core/common/repository/models/k8s_cluster.go b/pkg/microservice/aslan/core/common/repository/models/k8s_cluster.go index 59fc65c9a..309ead9ac 100644 --- a/pkg/microservice/aslan/core/common/repository/models/k8s_cluster.go +++ b/pkg/microservice/aslan/core/common/repository/models/k8s_cluster.go @@ -44,7 +44,7 @@ type K8SCluster struct { } type K8SClusterResp struct { - ID string `json:"id,omitempty" bson:"_id,omitempty"` + ID string `json:"id" bson:"_id,omitempty"` Name string `json:"name" bson:"name"` AdvancedConfig *AdvancedConfig `json:"config,omitempty" bson:"config,omitempty"` } diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/k8s_cluster.go b/pkg/microservice/aslan/core/common/repository/mongodb/k8s_cluster.go index 207d8c2a7..8d6c5acd7 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/k8s_cluster.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/k8s_cluster.go @@ -67,7 +67,10 @@ func (c *K8SClusterColl) Delete(id string) error { return err } -func (c *K8SClusterColl) Create(cluster *models.K8SCluster) error { +func (c *K8SClusterColl) Create(cluster *models.K8SCluster, id string) error { + if id != "" { + cluster.ID, _ = primitive.ObjectIDFromHex(id) + } res, err := c.InsertOne(context.TODO(), cluster) if oid, ok := res.InsertedID.(primitive.ObjectID); ok { cluster.ID = oid @@ -177,8 +180,13 @@ func (c *K8SClusterColl) FindByName(name string) (*models.K8SCluster, error) { return res, err } -func (c *K8SClusterColl) UpdateMutableFields(cluster *models.K8SCluster) error { - _, err := c.UpdateOne(context.TODO(), +func (c *K8SClusterColl) UpdateMutableFields(cluster *models.K8SCluster, id string) error { + var err error + cluster.ID, err = primitive.ObjectIDFromHex(id) + if err != nil { + return err + } + _, err = c.UpdateOne(context.TODO(), bson.M{"_id": cluster.ID}, bson.M{"$set": bson.M{ "name": cluster.Name, "description": cluster.Description, diff --git a/pkg/microservice/aslan/core/common/service/environment.go b/pkg/microservice/aslan/core/common/service/environment.go index ae4c0198f..3d4a41eac 100644 --- a/pkg/microservice/aslan/core/common/service/environment.go +++ b/pkg/microservice/aslan/core/common/service/environment.go @@ -36,7 +36,7 @@ import ( commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" templaterepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb/template" "github.com/koderover/zadig/pkg/setting" - client2 "github.com/koderover/zadig/pkg/shared/kube/client" + kubeclient "github.com/koderover/zadig/pkg/shared/kube/client" "github.com/koderover/zadig/pkg/shared/kube/resource" "github.com/koderover/zadig/pkg/shared/kube/wrapper" e "github.com/koderover/zadig/pkg/tool/errors" @@ -213,7 +213,7 @@ func ListWorkloads(envName, clusterID, namespace, productName string, perPage, p log.Infof("Start to list workloads in namespace %s", namespace) var resp = make([]*ServiceResp, 0) - kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), clusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), clusterID) if err != nil { log.Errorf("[%s][%s] error: %v", envName, namespace, err) return 0, resp, e.ErrListGroups.AddDesc(err.Error()) diff --git a/pkg/microservice/aslan/core/common/service/kube/service.go b/pkg/microservice/aslan/core/common/service/kube/service.go index 47aca9353..d31ee8770 100644 --- a/pkg/microservice/aslan/core/common/service/kube/service.go +++ b/pkg/microservice/aslan/core/common/service/kube/service.go @@ -23,7 +23,6 @@ import ( "strings" "text/template" - "go.mongodb.org/mongo-driver/bson/primitive" "go.uber.org/zap" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" @@ -33,23 +32,23 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" "github.com/koderover/zadig/pkg/setting" - client2 "github.com/koderover/zadig/pkg/shared/kube/client" + kubeclient "github.com/koderover/zadig/pkg/shared/kube/client" "github.com/koderover/zadig/pkg/tool/crypto" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/kube/multicluster" ) func GetKubeAPIReader(clusterID string) (client.Reader, error) { - return client2.GetKubeAPIReader(config.HubServerAddress(), clusterID) + return kubeclient.GetKubeAPIReader(config.HubServerAddress(), clusterID) } func GetRESTConfig(clusterID string) (*rest.Config, error) { - return client2.GetRESTConfig(config.HubServerAddress(), clusterID) + return kubeclient.GetRESTConfig(config.HubServerAddress(), clusterID) } // GetClientset returns a client to interact with APIServer which implements kubernetes.Interface func GetClientset(clusterID string) (kubernetes.Interface, error) { - return client2.GetClientset(config.HubServerAddress(), clusterID) + return kubeclient.GetClientset(config.HubServerAddress(), clusterID) } type Service struct { @@ -95,20 +94,18 @@ func (s *Service) ListClusters(clusterType string, logger *zap.SugaredLogger) ([ return clusters, nil } -func (s *Service) CreateCluster(cluster *models.K8SCluster, logger *zap.SugaredLogger) (*models.K8SCluster, error) { +func (s *Service) CreateCluster(cluster *models.K8SCluster, id string, logger *zap.SugaredLogger) (*models.K8SCluster, error) { _, err := s.coll.FindByName(cluster.Name) - if err == nil { logger.Errorf("failed to create cluster %s %v", cluster.Name, err) return nil, e.ErrCreateCluster.AddDesc(e.DuplicateClusterNameFound) } - - if cluster.Status == "" { - cluster.Status = setting.Pending + cluster.Status = setting.Pending + if id == setting.LocalClusterID { + cluster.Status = setting.Normal + cluster.Local = true } - - err = s.coll.Create(cluster) - + err = s.coll.Create(cluster, id) if err != nil { return nil, e.ErrCreateCluster.AddErr(err) } @@ -135,8 +132,8 @@ func (s *Service) UpdateCluster(id string, cluster *models.K8SCluster, logger *z return nil, e.ErrUpdateCluster.AddDesc(e.DuplicateClusterNameFound) } - cluster.ID, _ = primitive.ObjectIDFromHex(id) - err = s.coll.UpdateMutableFields(cluster) + + err = s.coll.UpdateMutableFields(cluster, id) if err != nil { logger.Errorf("failed to update mutable fields %v", err) return nil, e.ErrUpdateCluster.AddErr(err) diff --git a/pkg/microservice/aslan/core/common/service/product.go b/pkg/microservice/aslan/core/common/service/product.go index b18548d79..4e4249b94 100644 --- a/pkg/microservice/aslan/core/common/service/product.go +++ b/pkg/microservice/aslan/core/common/service/product.go @@ -35,7 +35,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb/template" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" - client2 "github.com/koderover/zadig/pkg/shared/kube/client" + kubeclient "github.com/koderover/zadig/pkg/shared/kube/client" e "github.com/koderover/zadig/pkg/tool/errors" helmtool "github.com/koderover/zadig/pkg/tool/helmclient" "github.com/koderover/zadig/pkg/tool/kube/updater" @@ -53,7 +53,7 @@ func DeleteProduct(username, envName, productName, requestID string, log *zap.Su return e.ErrDeleteEnv.AddDesc("not found") } - kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), productInfo.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), productInfo.ClusterID) if err != nil { return e.ErrDeleteEnv.AddErr(err) } diff --git a/pkg/microservice/aslan/core/environment/service/configmap.go b/pkg/microservice/aslan/core/environment/service/configmap.go index a3d634019..1982dea07 100644 --- a/pkg/microservice/aslan/core/environment/service/configmap.go +++ b/pkg/microservice/aslan/core/environment/service/configmap.go @@ -33,7 +33,7 @@ import ( commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" - client2 "github.com/koderover/zadig/pkg/shared/kube/client" + kubeclient "github.com/koderover/zadig/pkg/shared/kube/client" "github.com/koderover/zadig/pkg/shared/kube/wrapper" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/kube/getter" @@ -100,7 +100,7 @@ func ListConfigMaps(args *ListConfigMapArgs, log *zap.SugaredLogger) ([]*configM if err != nil { return nil, e.ErrListConfigMaps.AddErr(err) } - kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), product.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), product.ClusterID) if err != nil { return nil, e.ErrListConfigMaps.AddErr(err) } @@ -155,7 +155,7 @@ func UpdateConfigMap(envName string, args *UpdateConfigMapArgs, userName, userID if err != nil { return e.ErrUpdateConfigMap.AddErr(err) } - kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), product.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), product.ClusterID) if err != nil { return e.ErrUpdateConfigMap.AddErr(err) } @@ -232,7 +232,7 @@ func RollBackConfigMap(envName string, args *RollBackConfigMapArgs, userName, us if err != nil { return e.ErrUpdateConfigMap.AddErr(err) } - kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), product.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), product.ClusterID) if err != nil { return e.ErrUpdateConfigMap.AddErr(err) } diff --git a/pkg/microservice/aslan/core/environment/service/environment.go b/pkg/microservice/aslan/core/environment/service/environment.go index 822e93fec..64e26f006 100644 --- a/pkg/microservice/aslan/core/environment/service/environment.go +++ b/pkg/microservice/aslan/core/environment/service/environment.go @@ -54,7 +54,7 @@ import ( commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" - client2 "github.com/koderover/zadig/pkg/shared/kube/client" + kubeclient "github.com/koderover/zadig/pkg/shared/kube/client" "github.com/koderover/zadig/pkg/shared/kube/wrapper" e "github.com/koderover/zadig/pkg/tool/errors" helmtool "github.com/koderover/zadig/pkg/tool/helmclient" @@ -277,7 +277,7 @@ func AutoUpdateProduct(envNames []string, productName, requestID string, force b continue } - kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), p.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), p.ClusterID) if err != nil { log.Errorf("Failed to get kube client for %s, error: %v", productName, err) continue @@ -389,7 +389,7 @@ func UpdateProduct(existedProd, updateProd *commonmodels.Product, renderSet *com return } - kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), existedProd.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), existedProd.ClusterID) if err != nil { return e.ErrUpdateEnv.AddErr(err) } @@ -533,7 +533,7 @@ func UpdateProductV2(envName, productName, user, requestID string, force bool, k return e.ErrUpdateEnv.AddDesc(e.EnvNotFoundErrMsg) } - kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), exitedProd.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), exitedProd.ClusterID) if err != nil { return e.ErrUpdateEnv.AddErr(err) } diff --git a/pkg/microservice/aslan/core/environment/service/environment_creator.go b/pkg/microservice/aslan/core/environment/service/environment_creator.go index 62d508075..15c6b1556 100644 --- a/pkg/microservice/aslan/core/environment/service/environment_creator.go +++ b/pkg/microservice/aslan/core/environment/service/environment_creator.go @@ -30,7 +30,7 @@ import ( commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/kube/client" + kubeclient "github.com/koderover/zadig/pkg/shared/kube/client" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/helmclient" "github.com/koderover/zadig/pkg/tool/kube/getter" @@ -121,7 +121,7 @@ func newHelmProductCreator() *HelmProductCreator { } func (creator *HelmProductCreator) Create(user, requestID string, args *models.Product, log *zap.SugaredLogger) error { - kubeClient, err := client.GetKubeClient(config.HubServerAddress(), args.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), args.ClusterID) if err != nil { log.Errorf("[%s][%s] GetKubeClient error: %v", args.EnvName, args.ProductName, err) return e.ErrCreateEnv.AddErr(err) @@ -278,7 +278,7 @@ func newDefaultProductCreator() *DefaultProductCreator { } func (creator *DefaultProductCreator) Create(user, requestID string, args *models.Product, log *zap.SugaredLogger) error { - kubeClient, err := client.GetKubeClient(config.HubServerAddress(), args.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), args.ClusterID) if err != nil { return e.ErrCreateEnv.AddErr(err) } diff --git a/pkg/microservice/aslan/core/environment/service/environment_group.go b/pkg/microservice/aslan/core/environment/service/environment_group.go index ab8fa01cb..ac0fabe6a 100644 --- a/pkg/microservice/aslan/core/environment/service/environment_group.go +++ b/pkg/microservice/aslan/core/environment/service/environment_group.go @@ -30,7 +30,7 @@ import ( commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" - client2 "github.com/koderover/zadig/pkg/shared/kube/client" + kubeclient "github.com/koderover/zadig/pkg/shared/kube/client" "github.com/koderover/zadig/pkg/shared/kube/resource" "github.com/koderover/zadig/pkg/shared/kube/wrapper" e "github.com/koderover/zadig/pkg/tool/errors" @@ -67,7 +67,7 @@ func ListGroups(serviceName, envName, productName string, perPage, page int, log //将获取到的所有服务按照名称进行排序 sort.SliceStable(allServices, func(i, j int) bool { return allServices[i].ServiceName < allServices[j].ServiceName }) - kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), productInfo.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), productInfo.ClusterID) if err != nil { log.Errorf("[%s][%s] error: %v", envName, productName, err) return resp, count, e.ErrListGroups.AddDesc(err.Error()) diff --git a/pkg/microservice/aslan/core/environment/service/export.go b/pkg/microservice/aslan/core/environment/service/export.go index 29d6589b2..acf9aa6b0 100644 --- a/pkg/microservice/aslan/core/environment/service/export.go +++ b/pkg/microservice/aslan/core/environment/service/export.go @@ -24,7 +24,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/config" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" "github.com/koderover/zadig/pkg/setting" - client2 "github.com/koderover/zadig/pkg/shared/kube/client" + kubeclient "github.com/koderover/zadig/pkg/shared/kube/client" "github.com/koderover/zadig/pkg/tool/kube/getter" ) @@ -40,7 +40,7 @@ func ExportYaml(envName, productName, serviceName string, log *zap.SugaredLogger } namespace := env.Namespace - kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), env.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), env.ClusterID) if err != nil { log.Errorf("cluster is not connected [%s][%s][%s]", env.EnvName, env.ProductName, env.ClusterID) return res diff --git a/pkg/microservice/aslan/core/environment/service/image.go b/pkg/microservice/aslan/core/environment/service/image.go index 44f61a716..e6d344b0b 100644 --- a/pkg/microservice/aslan/core/environment/service/image.go +++ b/pkg/microservice/aslan/core/environment/service/image.go @@ -34,7 +34,7 @@ import ( commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" - client2 "github.com/koderover/zadig/pkg/shared/kube/client" + kubeclient "github.com/koderover/zadig/pkg/shared/kube/client" e "github.com/koderover/zadig/pkg/tool/errors" helmtool "github.com/koderover/zadig/pkg/tool/helmclient" "github.com/koderover/zadig/pkg/tool/kube/updater" @@ -293,7 +293,7 @@ func UpdateContainerImage(requestID string, args *UpdateContainerImageArgs, log } namespace := product.Namespace - kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), product.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), product.ClusterID) if err != nil { return e.ErrUpdateConainterImage.AddErr(err) } diff --git a/pkg/microservice/aslan/core/environment/service/k8s.go b/pkg/microservice/aslan/core/environment/service/k8s.go index 5b6e998ef..24e4f5a12 100644 --- a/pkg/microservice/aslan/core/environment/service/k8s.go +++ b/pkg/microservice/aslan/core/environment/service/k8s.go @@ -34,7 +34,7 @@ import ( templaterepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb/template" commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/setting" - client2 "github.com/koderover/zadig/pkg/shared/kube/client" + kubeclient "github.com/koderover/zadig/pkg/shared/kube/client" e "github.com/koderover/zadig/pkg/tool/errors" ) @@ -83,7 +83,7 @@ func (k *K8sService) updateService(args *SvcOptArgs) error { return errors.New(e.UpsertServiceErrMsg) } - kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), exitedProd.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), exitedProd.ClusterID) if err != nil { return e.ErrUpdateEnv.AddErr(err) } diff --git a/pkg/microservice/aslan/core/environment/service/kube.go b/pkg/microservice/aslan/core/environment/service/kube.go index bfdc4c13f..bae1bc9d5 100644 --- a/pkg/microservice/aslan/core/environment/service/kube.go +++ b/pkg/microservice/aslan/core/environment/service/kube.go @@ -32,7 +32,7 @@ import ( commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/kube/client" + kubeclient "github.com/koderover/zadig/pkg/shared/kube/client" "github.com/koderover/zadig/pkg/shared/kube/resource" "github.com/koderover/zadig/pkg/shared/kube/wrapper" e "github.com/koderover/zadig/pkg/tool/errors" @@ -113,7 +113,7 @@ func ListPodEvents(envName, productName, podName string, log *zap.SugaredLogger) // ListAvailableNamespaces lists available namespaces created by non-koderover func ListAvailableNamespaces(clusterID string, log *zap.SugaredLogger) ([]*resource.Namespace, error) { resp := make([]*resource.Namespace, 0) - kubeClient, err := client.GetKubeClient(config.HubServerAddress(), clusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), clusterID) if err != nil { log.Errorf("ListNamespaces clusterID:%s err:%v", clusterID, err) return resp, err @@ -150,7 +150,7 @@ func ListServicePods(productName, envName string, serviceName string, log *zap.S if err != nil { return res, e.ErrListServicePod.AddErr(err) } - kubeClient, err := client.GetKubeClient(config.HubServerAddress(), product.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), product.ClusterID) if err != nil { return res, e.ErrListServicePod.AddErr(err) } @@ -177,7 +177,7 @@ func DeletePod(envName, productName, podName string, log *zap.SugaredLogger) err if err != nil { return e.ErrDeletePod.AddErr(err) } - kubeClient, err := client.GetKubeClient(config.HubServerAddress(), product.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), product.ClusterID) if err != nil { return e.ErrDeletePod.AddErr(err) } @@ -228,9 +228,9 @@ func getModifiedServiceFromObjectMeta(om metav1.Object) *serviceInfo { } } -func ListAvailableNodes(clusterID string, log *zap.SugaredLogger) (*resource.NodeResp, error) { - resp := new(resource.NodeResp) - kubeClient, err := client.GetKubeClient(config.HubServerAddress(), clusterID) +func ListAvailableNodes(clusterID string, log *zap.SugaredLogger) (*NodeResp, error) { + resp := new(NodeResp) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), clusterID) if err != nil { log.Errorf("ListAvailableNodes clusterID:%s err:%s", clusterID, err) return resp, err diff --git a/pkg/microservice/aslan/core/environment/service/service.go b/pkg/microservice/aslan/core/environment/service/service.go index 705930378..572d6d878 100644 --- a/pkg/microservice/aslan/core/environment/service/service.go +++ b/pkg/microservice/aslan/core/environment/service/service.go @@ -33,7 +33,7 @@ import ( commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" - client2 "github.com/koderover/zadig/pkg/shared/kube/client" + kubeclient "github.com/koderover/zadig/pkg/shared/kube/client" internalresource "github.com/koderover/zadig/pkg/shared/kube/resource" "github.com/koderover/zadig/pkg/shared/kube/wrapper" e "github.com/koderover/zadig/pkg/tool/errors" @@ -61,7 +61,7 @@ func ScaleService(envName, productName, serviceName string, number int, log *zap return e.ErrScaleService.AddErr(err) } - kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), prod.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), prod.ClusterID) if err != nil { return e.ErrScaleService.AddErr(err) } @@ -112,7 +112,7 @@ func Scale(args *ScaleArgs, logger *zap.SugaredLogger) error { return e.ErrScaleService.AddErr(err) } - kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), prod.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), prod.ClusterID) if err != nil { return e.ErrScaleService.AddErr(err) } @@ -142,7 +142,7 @@ func RestartScale(args *RestartScaleArgs, _ *zap.SugaredLogger) error { return err } - kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), prod.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), prod.ClusterID) if err != nil { return err } @@ -178,7 +178,7 @@ func GetService(envName, productName, serviceName string, workLoadType string, l return nil, e.ErrGetService.AddErr(err) } - kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), env.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), env.ClusterID) if err != nil { return nil, e.ErrGetService.AddErr(err) } @@ -324,7 +324,7 @@ func RestartService(envName string, args *SvcOptArgs, log *zap.SugaredLogger) (e if err != nil { return err } - kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), productObj.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), productObj.ClusterID) if err != nil { return err } @@ -423,7 +423,7 @@ func validateServiceContainer(envName, productName, serviceName, container strin return "", err } - kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), prod.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), prod.ClusterID) if err != nil { return "", err } diff --git a/pkg/microservice/aslan/core/environment/service/types.go b/pkg/microservice/aslan/core/environment/service/types.go index 60942bf80..f3c0af942 100644 --- a/pkg/microservice/aslan/core/environment/service/types.go +++ b/pkg/microservice/aslan/core/environment/service/types.go @@ -115,3 +115,8 @@ type ContainerNotFound struct { func (c *ContainerNotFound) Error() string { return fmt.Sprintf("serviceName:%s,container:%s", c.ServiceName, c.Container) } + +type NodeResp struct { + Nodes []*internalresource.Node `json:"data"` + Labels []string `json:"labels"` +} diff --git a/pkg/microservice/aslan/core/log/service/sse.go b/pkg/microservice/aslan/core/log/service/sse.go index f66547d70..384a27d5b 100644 --- a/pkg/microservice/aslan/core/log/service/sse.go +++ b/pkg/microservice/aslan/core/log/service/sse.go @@ -32,7 +32,7 @@ import ( commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/kube/client" + kubeclient "github.com/koderover/zadig/pkg/shared/kube/client" "github.com/koderover/zadig/pkg/tool/kube/containerlog" "github.com/koderover/zadig/pkg/tool/kube/getter" "github.com/koderover/zadig/pkg/tool/kube/watcher" @@ -175,7 +175,7 @@ func waitAndGetLog(ctx context.Context, streamChan chan interface{}, selector la defer cancel() log.Debugf("Waiting until pod is running before establishing the stream.") - clientSet, err := client.GetClientset(config.HubServerAddress(), options.ClusterID) + clientSet, err := kubeclient.GetClientset(config.HubServerAddress(), options.ClusterID) if err != nil { log.Errorf("GetContainerLogs, get client set error: %s", err) return @@ -185,7 +185,7 @@ func waitAndGetLog(ctx context.Context, streamChan chan interface{}, selector la log.Errorf("GetContainerLogs, wait pod running error: %s", err) return } - kubeClient, err := client.GetKubeClient(config.HubServerAddress(), options.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), options.ClusterID) if err != nil { log.Errorf("GetContainerLogs, get kube client error: %s", err) return diff --git a/pkg/microservice/aslan/core/multicluster/service/clusters.go b/pkg/microservice/aslan/core/multicluster/service/clusters.go index 6e606700c..f9815cf38 100644 --- a/pkg/microservice/aslan/core/multicluster/service/clusters.go +++ b/pkg/microservice/aslan/core/multicluster/service/clusters.go @@ -23,7 +23,6 @@ import ( "strings" "github.com/gin-gonic/gin" - "go.mongodb.org/mongo-driver/bson/primitive" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/sets" @@ -154,14 +153,11 @@ func CreateCluster(args *K8SCluster, logger *zap.SugaredLogger) (*commonmodels.K Status: args.Status, Production: args.Production, Provider: args.Provider, - Local: args.Local, CreatedAt: args.CreatedAt, CreatedBy: args.CreatedBy, } - if args.ID != "" { - cluster.ID, _ = primitive.ObjectIDFromHex(args.ID) - } - return s.CreateCluster(cluster, logger) + + return s.CreateCluster(cluster, args.ID, logger) } func UpdateCluster(id string, args *K8SCluster, logger *zap.SugaredLogger) (*commonmodels.K8SCluster, error) { diff --git a/pkg/microservice/aslan/core/service/service/service.go b/pkg/microservice/aslan/core/service/service/service.go index 39cadff56..1bd83639e 100644 --- a/pkg/microservice/aslan/core/service/service/service.go +++ b/pkg/microservice/aslan/core/service/service/service.go @@ -46,7 +46,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/aslan/core/environment/service" "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/shared/client/systemconfig" - "github.com/koderover/zadig/pkg/shared/kube/client" + kubeclient "github.com/koderover/zadig/pkg/shared/kube/client" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/gerrit" "github.com/koderover/zadig/pkg/tool/httpclient" @@ -256,7 +256,7 @@ func GetServiceOption(args *commonmodels.Service, log *zap.SugaredLogger) (*Serv } func CreateK8sWorkLoads(ctx context.Context, requestID, username string, productName string, workLoads []models.Workload, clusterID, namespace string, envName string, log *zap.SugaredLogger) error { - kubeClient, err := client.GetKubeClient(config.HubServerAddress(), clusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), clusterID) if err != nil { log.Errorf("[%s] error: %v", namespace, err) return err @@ -385,7 +385,7 @@ type UpdateWorkloadsArgs struct { } func UpdateWorkloads(ctx context.Context, requestID, username, productName, envName string, args UpdateWorkloadsArgs, log *zap.SugaredLogger) error { - kubeClient, err := client.GetKubeClient(config.HubServerAddress(), args.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), args.ClusterID) if err != nil { log.Errorf("[%s] error: %s", args.Namespace, err) return err diff --git a/pkg/microservice/aslan/core/system/service/registry.go b/pkg/microservice/aslan/core/system/service/registry.go index 3ab20ad32..a4c226096 100644 --- a/pkg/microservice/aslan/core/system/service/registry.go +++ b/pkg/microservice/aslan/core/system/service/registry.go @@ -28,7 +28,7 @@ import ( commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/registry" "github.com/koderover/zadig/pkg/setting" - "github.com/koderover/zadig/pkg/shared/kube/client" + kubeclient "github.com/koderover/zadig/pkg/shared/kube/client" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/util" ) @@ -87,7 +87,7 @@ func CreateRegistryNamespace(username string, args *commonmodels.RegistryNamespa } for _, env := range envs { go func(prod *commonmodels.Product) { - kubeClient, err := client.GetKubeClient(config.HubServerAddress(), prod.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), prod.ClusterID) if err != nil { log.Errorf("[updateRegistry] Failed to get kubecli for namespace: %s", prod.Namespace) return @@ -162,7 +162,7 @@ func UpdateRegistryNamespace(username, id string, args *commonmodels.RegistryNam } for _, env := range envs { go func(prod *commonmodels.Product) { - kubeClient, err := client.GetKubeClient(config.HubServerAddress(), prod.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), prod.ClusterID) if err != nil { log.Errorf("[updateRegistry] Failed to get kubecli for namespace: %s", prod.Namespace) return diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_validation.go b/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_validation.go index 183580ed9..1c33ddcc4 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_validation.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/pipeline_validation.go @@ -45,7 +45,7 @@ import ( git "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/github" "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/shared/client/systemconfig" - client2 "github.com/koderover/zadig/pkg/shared/kube/client" + kubeclient "github.com/koderover/zadig/pkg/shared/kube/client" "github.com/koderover/zadig/pkg/shared/kube/wrapper" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/kube/getter" @@ -688,7 +688,7 @@ func validateServiceContainer(envName, productName, serviceName, container strin return "", err } - kubeClient, err := client2.GetKubeClient(config.HubServerAddress(), product.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), product.ClusterID) if err != nil { return "", err } diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/build.go b/pkg/microservice/warpdrive/core/service/taskplugin/build.go index 687c471fa..0649e215a 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/build.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/build.go @@ -32,7 +32,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/warpdrive/config" "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types/task" "github.com/koderover/zadig/pkg/setting" - client2 "github.com/koderover/zadig/pkg/shared/kube/client" + kubeclient "github.com/koderover/zadig/pkg/shared/kube/client" krkubeclient "github.com/koderover/zadig/pkg/tool/kube/client" "github.com/koderover/zadig/pkg/tool/kube/updater" ) @@ -110,7 +110,7 @@ func (p *BuildTaskPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipe p.KubeNamespace = pipelineTask.ConfigPayload.Build.KubeNamespace if p.Task.Namespace != "" { p.KubeNamespace = p.Task.Namespace - kubeClient, err := client2.GetKubeClient(pipelineTask.ConfigPayload.HubServerAddr, p.Task.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(pipelineTask.ConfigPayload.HubServerAddr, p.Task.ClusterID) if err != nil { msg := fmt.Sprintf("failed to get kube client: %s", err) p.Log.Error(msg) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/deploy.go b/pkg/microservice/warpdrive/core/service/taskplugin/deploy.go index e65e5f06d..3c5d364d7 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/deploy.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/deploy.go @@ -39,7 +39,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types" "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types/task" "github.com/koderover/zadig/pkg/setting" - client2 "github.com/koderover/zadig/pkg/shared/kube/client" + kubeclient "github.com/koderover/zadig/pkg/shared/kube/client" "github.com/koderover/zadig/pkg/shared/kube/resource" "github.com/koderover/zadig/pkg/shared/kube/wrapper" helmtool "github.com/koderover/zadig/pkg/tool/helmclient" @@ -202,13 +202,13 @@ func (p *DeployTaskPlugin) Run(ctx context.Context, pipelineTask *task.Task, _ * }() if pipelineTask.ConfigPayload.DeployClusterID != "" { - p.restConfig, err = client2.GetRESTConfig(pipelineTask.ConfigPayload.HubServerAddr, pipelineTask.ConfigPayload.DeployClusterID) + p.restConfig, err = kubeclient.GetRESTConfig(pipelineTask.ConfigPayload.HubServerAddr, pipelineTask.ConfigPayload.DeployClusterID) if err != nil { err = errors.WithMessage(err, "can't get k8s rest config") return } - p.kubeClient, err = client2.GetKubeClient(pipelineTask.ConfigPayload.HubServerAddr, pipelineTask.ConfigPayload.DeployClusterID) + p.kubeClient, err = kubeclient.GetKubeClient(pipelineTask.ConfigPayload.HubServerAddr, pipelineTask.ConfigPayload.DeployClusterID) if err != nil { err = errors.WithMessage(err, "can't init k8s client") return diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/job.go b/pkg/microservice/warpdrive/core/service/taskplugin/job.go index 4fd3c6a9d..b41d87fbd 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/job.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/job.go @@ -43,7 +43,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types" "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types/task" "github.com/koderover/zadig/pkg/setting" - client2 "github.com/koderover/zadig/pkg/shared/kube/client" + kubeclient "github.com/koderover/zadig/pkg/shared/kube/client" "github.com/koderover/zadig/pkg/shared/kube/wrapper" "github.com/koderover/zadig/pkg/tool/kube/containerlog" "github.com/koderover/zadig/pkg/tool/kube/getter" @@ -98,7 +98,7 @@ func saveContainerLog(pipelineTask *task.Task, namespace, clusterID, fileName st return pods[i].CreationTimestamp.Before(&pods[j].CreationTimestamp) }) - clientSet, err := client2.GetClientset(pipelineTask.ConfigPayload.HubServerAddr, clusterID) + clientSet, err := kubeclient.GetClientset(pipelineTask.ConfigPayload.HubServerAddr, clusterID) if err != nil { log.Errorf("saveContainerLog, get client set error: %s", err) return err diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go index 76406a7d3..8edc85268 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go @@ -34,7 +34,7 @@ import ( "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types" "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types/task" "github.com/koderover/zadig/pkg/setting" - client2 "github.com/koderover/zadig/pkg/shared/kube/client" + kubeclient "github.com/koderover/zadig/pkg/shared/kube/client" krkubeclient "github.com/koderover/zadig/pkg/tool/kube/client" "github.com/koderover/zadig/pkg/tool/kube/updater" s3tool "github.com/koderover/zadig/pkg/tool/s3" @@ -107,7 +107,7 @@ func (p *TestPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipelineC p.KubeNamespace = pipelineTask.ConfigPayload.Test.KubeNamespace if p.Task.Namespace != "" { p.KubeNamespace = p.Task.Namespace - kubeClient, err := client2.GetKubeClient(pipelineTask.ConfigPayload.HubServerAddr, p.Task.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(pipelineTask.ConfigPayload.HubServerAddr, p.Task.ClusterID) if err != nil { msg := fmt.Sprintf("failed to get kube client: %s", err) p.Log.Error(msg) diff --git a/pkg/shared/client/aslan/multicluster.go b/pkg/shared/client/aslan/multicluster.go index 9904bcfea..89ab4871f 100644 --- a/pkg/shared/client/aslan/multicluster.go +++ b/pkg/shared/client/aslan/multicluster.go @@ -18,10 +18,8 @@ type cluster struct { func (c *Client) AddLocalCluster() error { url := "/cluster/clusters" req := cluster{ - ID: setting.LocalClusterID, - Name: fmt.Sprintf("%s-%s", "local", time.Now().Format("20060102150405")), - Local: true, - Status: setting.Normal, + ID: setting.LocalClusterID, + Name: fmt.Sprintf("%s-%s", "local", time.Now().Format("20060102150405")), } _, err := c.Post(url, httpclient.SetBody(req)) @@ -37,12 +35,15 @@ type clusterResp struct { Local bool `json:"local"` } -func (c *Client) GetCluster() (*clusterResp, error) { +func (c *Client) GetLocalCluster() (*clusterResp, error) { url := fmt.Sprintf("/cluster/clusters/%s", setting.LocalClusterID) clusterResp := &clusterResp{} _, err := c.Get(url, httpclient.SetResult(clusterResp)) if err != nil { + if httpclient.IsNotFound(err) { + return nil, nil + } return nil, fmt.Errorf("Failed to get cluster, error: %s", err) } diff --git a/pkg/shared/kube/resource/node.go b/pkg/shared/kube/resource/node.go index a78564c2f..a0fb402d7 100644 --- a/pkg/shared/kube/resource/node.go +++ b/pkg/shared/kube/resource/node.go @@ -5,8 +5,3 @@ type Node struct { Ready bool `json:"ready"` IP string `json:"node_ip"` } - -type NodeResp struct { - Nodes []*Node `json:"data"` - Labels []string `json:"labels"` -} -- Gitee From 9e80ed62ffd924f4374768beaa8eadff5c7b912c Mon Sep 17 00:00:00 2001 From: liu deyi Date: Wed, 8 Dec 2021 16:50:10 +0800 Subject: [PATCH 076/134] optimize code Signed-off-by: liu deyi --- pkg/shared/client/aslan/multicluster.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/shared/client/aslan/multicluster.go b/pkg/shared/client/aslan/multicluster.go index 89ab4871f..6b73fa982 100644 --- a/pkg/shared/client/aslan/multicluster.go +++ b/pkg/shared/client/aslan/multicluster.go @@ -2,6 +2,7 @@ package aslan import ( "fmt" + "strings" "time" "github.com/koderover/zadig/pkg/setting" @@ -41,7 +42,7 @@ func (c *Client) GetLocalCluster() (*clusterResp, error) { clusterResp := &clusterResp{} _, err := c.Get(url, httpclient.SetResult(clusterResp)) if err != nil { - if httpclient.IsNotFound(err) { + if strings.Contains(err.Error(), "\"code\":6643") { return nil, nil } return nil, fmt.Errorf("Failed to get cluster, error: %s", err) -- Gitee From f035d45a0c6bc00c6a12432e81138dcd296a0240 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Wed, 8 Dec 2021 16:55:00 +0800 Subject: [PATCH 077/134] optimize code Signed-off-by: liu deyi --- .../aslan/core/multicluster/service/clusters.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pkg/microservice/aslan/core/multicluster/service/clusters.go b/pkg/microservice/aslan/core/multicluster/service/clusters.go index f9815cf38..047cb9dc4 100644 --- a/pkg/microservice/aslan/core/multicluster/service/clusters.go +++ b/pkg/microservice/aslan/core/multicluster/service/clusters.go @@ -141,10 +141,12 @@ func convertToNodeSelectorRequirements(nodeLabels []string) []*commonmodels.Node func CreateCluster(args *K8SCluster, logger *zap.SugaredLogger) (*commonmodels.K8SCluster, error) { s, _ := kube.NewService("") - advancedConfig := new(commonmodels.AdvancedConfig) + var advancedConfig *commonmodels.AdvancedConfig if args.AdvancedConfig != nil { - advancedConfig.Strategy = args.AdvancedConfig.Strategy - advancedConfig.NodeLabels = convertToNodeSelectorRequirements(args.AdvancedConfig.NodeLabels) + advancedConfig = &commonmodels.AdvancedConfig{ + Strategy: args.AdvancedConfig.Strategy, + NodeLabels: convertToNodeSelectorRequirements(args.AdvancedConfig.NodeLabels), + } } cluster := &commonmodels.K8SCluster{ Name: args.Name, -- Gitee From eed7e5aa9b7b8eb89e281e665691e0de4bed4b1f Mon Sep 17 00:00:00 2001 From: liu deyi Date: Wed, 8 Dec 2021 17:26:54 +0800 Subject: [PATCH 078/134] debug code Signed-off-by: liu deyi --- pkg/shared/client/aslan/multicluster.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/shared/client/aslan/multicluster.go b/pkg/shared/client/aslan/multicluster.go index 6b73fa982..1acdb464a 100644 --- a/pkg/shared/client/aslan/multicluster.go +++ b/pkg/shared/client/aslan/multicluster.go @@ -40,8 +40,9 @@ func (c *Client) GetLocalCluster() (*clusterResp, error) { url := fmt.Sprintf("/cluster/clusters/%s", setting.LocalClusterID) clusterResp := &clusterResp{} - _, err := c.Get(url, httpclient.SetResult(clusterResp)) + resp, err := c.Get(url, httpclient.SetResult(clusterResp)) if err != nil { + fmt.Println(fmt.Sprintf("resp.body:%s", string(resp.Body()))) if strings.Contains(err.Error(), "\"code\":6643") { return nil, nil } -- Gitee From 7563dfee59049f85de506806bef344ea7959cf92 Mon Sep 17 00:00:00 2001 From: panxunying Date: Wed, 8 Dec 2021 17:30:20 +0800 Subject: [PATCH 079/134] update wd registry Signed-off-by: panxunying --- .../aslan/core/common/repository/models/queue.go | 2 ++ .../aslan/core/environment/service/environment.go | 4 +++- .../aslan/core/environment/service/product.go | 2 +- .../core/workflow/service/workflow/workflow_task.go | 12 ++++++++++++ .../core/service/taskplugin/artifact_deploy.go | 2 +- .../warpdrive/core/service/taskplugin/build.go | 2 +- .../warpdrive/core/service/taskplugin/job.go | 11 ++--------- .../warpdrive/core/service/taskplugin/testing.go | 2 +- .../warpdrive/core/service/types/task/build.go | 1 + .../core/service/types/task/config_payload.go | 2 ++ 10 files changed, 26 insertions(+), 14 deletions(-) diff --git a/pkg/microservice/aslan/core/common/repository/models/queue.go b/pkg/microservice/aslan/core/common/repository/models/queue.go index 7801b2c46..edd8a89a4 100644 --- a/pkg/microservice/aslan/core/common/repository/models/queue.go +++ b/pkg/microservice/aslan/core/common/repository/models/queue.go @@ -136,6 +136,8 @@ type ConfigPayload struct { ResetCache bool `json:"reset_cache"` JenkinsBuildConfig JenkinsBuildConfig `json:"jenkins_build_config"` PrivateKeys []*PrivateKey `json:"private_keys"` + + RegistryID string `json:"registry_id"` } type AslanConfig struct { diff --git a/pkg/microservice/aslan/core/environment/service/environment.go b/pkg/microservice/aslan/core/environment/service/environment.go index 597af6ded..dcecd7cce 100644 --- a/pkg/microservice/aslan/core/environment/service/environment.go +++ b/pkg/microservice/aslan/core/environment/service/environment.go @@ -93,6 +93,7 @@ type EnvResp struct { UpdateTime int64 `json:"updateTime"` IsPublic bool `json:"isPublic"` ClusterName string `json:"clusterName"` + ClusterID string `json:"cluster_id"` Production bool `json:"production"` Source string `json:"source"` RegistryID string `json:"registry_id"` @@ -213,6 +214,7 @@ func ListProducts(projectName string, envNames []string, log *zap.SugaredLogger) UpdateTime: env.UpdateTime, UpdateBy: env.UpdateBy, RegistryID: env.RegistryId, + ClusterID: env.ClusterID, }) } @@ -550,7 +552,7 @@ func UpdateProductRegistry(namespace, registryID string, log *zap.SugaredLogger) if err != nil { return e.ErrUpdateEnv.AddErr(err) } - err = ensureKubeEnv(exitedProd.Namespace, exitedProd.RegistryId, kubeClient, log) + err = ensureKubeEnv(exitedProd.Namespace, registryID, kubeClient, log) if err != nil { log.Errorf("UpdateProductRegistry ensureKubeEnv by namespace:%s,error: %v", namespace, err) diff --git a/pkg/microservice/aslan/core/environment/service/product.go b/pkg/microservice/aslan/core/environment/service/product.go index 44f637760..1429229a0 100644 --- a/pkg/microservice/aslan/core/environment/service/product.go +++ b/pkg/microservice/aslan/core/environment/service/product.go @@ -175,7 +175,7 @@ func GetProduct(username, envName, productName string, log *zap.SugaredLogger) ( log.Errorf("[User:%s][EnvName:%s][Product:%s] FindDefaultRegistry error: %v", username, envName, productName, err) return nil, err } - prod.RegistryId = reg.ID.String() + prod.RegistryId = reg.ID.Hex() } resp := buildProductResp(prod.EnvName, prod, log) return resp, nil diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go index b0f58e477..c0284a022 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go @@ -494,6 +494,18 @@ func CreateWorkflowTask(args *commonmodels.WorkflowTaskArgs, taskCreator string, // 获取全局configpayload configPayload := commonservice.GetConfigPayload(args.CodehostID) + if len(env.RegistryId) == 0 { + op := &commonrepo.FindRegOps{ + IsDefault: true, + } + reg, err := commonrepo.NewRegistryNamespaceColl().Find(op) + if err != nil { + log.Errorf("get default registry error: %v", err) + return nil, e.ErrGetCounter.AddDesc(err.Error()) + } + env.RegistryId = reg.ID.String() + } + configPayload.RegistryID = env.RegistryId repos, err := commonrepo.NewRegistryNamespaceColl().FindAll(&commonrepo.FindRegOps{}) if err == nil { configPayload.RepoConfigs = make(map[string]*commonmodels.RegistryNamespace) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/artifact_deploy.go b/pkg/microservice/warpdrive/core/service/taskplugin/artifact_deploy.go index b37306e70..e2dda26be 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/artifact_deploy.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/artifact_deploy.go @@ -237,7 +237,7 @@ func (p *ArtifactDeployTaskPlugin) Run(ctx context.Context, pipelineTask *task.T } // 将集成到KodeRover的私有镜像仓库的访问权限设置到namespace中 - if err := createOrUpdateRegistrySecrets(p.KubeNamespace, p.Task.Registries, p.kubeClient); err != nil { + if err := createOrUpdateRegistrySecrets(p.KubeNamespace, pipelineTask.ConfigPayload.RegistryID, p.Task.Registries, p.kubeClient); err != nil { msg := fmt.Sprintf("create secret error: %v", err) p.Log.Error(msg) p.Task.TaskStatus = config.StatusFailed diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/build.go b/pkg/microservice/warpdrive/core/service/taskplugin/build.go index 8374fdb03..ce9b2048d 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/build.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/build.go @@ -252,7 +252,7 @@ func (p *BuildTaskPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipe } // 将集成到KodeRover的私有镜像仓库的访问权限设置到namespace中 - if err := createOrUpdateRegistrySecrets(p.KubeNamespace, p.Task.Registries, p.kubeClient); err != nil { + if err := createOrUpdateRegistrySecrets(p.KubeNamespace, pipelineTask.ConfigPayload.RegistryID, p.Task.Registries, p.kubeClient); err != nil { msg := fmt.Sprintf("create secret error: %v", err) p.Log.Error(msg) p.Task.TaskStatus = config.StatusFailed diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/job.go b/pkg/microservice/warpdrive/core/service/taskplugin/job.go index 4835fa818..6ac361c32 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/job.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/job.go @@ -514,14 +514,7 @@ func buildJobWithLinkedNs(taskType config.TaskType, jobImage, jobName, serviceNa return job, nil } -func createOrUpdateRegistrySecrets(namespace string, registries []*task.RegistryNamespace, kubeClient client.Client) error { - defaultRegistry := &task.RegistryNamespace{ - RegAddr: config.DefaultRegistryAddr(), - AccessKey: config.DefaultRegistryAK(), - SecretKey: config.DefaultRegistrySK(), - } - registries = append(registries, defaultRegistry) - +func createOrUpdateRegistrySecrets(namespace, registryID string, registries []*task.RegistryNamespace, kubeClient client.Client) error { for _, reg := range registries { if reg.AccessKey == "" { continue @@ -533,7 +526,7 @@ func createOrUpdateRegistrySecrets(namespace string, registries []*task.Registry if reg.RegType != "" { secretName = namespaceInRegistry + "-" + reg.RegType + registrySecretSuffix } - if reg.RegAddr == config.DefaultRegistryAddr() { + if reg.ID == registryID { secretName = setting.DefaultImagePullSecret } diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go index 07ab9732c..7736b08f0 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go @@ -224,7 +224,7 @@ func (p *TestPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipelineC } // 将集成到KodeRover的私有镜像仓库的访问权限设置到namespace中 - if err := createOrUpdateRegistrySecrets(p.KubeNamespace, p.Task.Registries, p.kubeClient); err != nil { + if err := createOrUpdateRegistrySecrets(p.KubeNamespace, pipelineTask.ConfigPayload.RegistryID, p.Task.Registries, p.kubeClient); err != nil { p.Log.Errorf("create secret error: %v", err) } if err := updater.CreateJob(job, p.kubeClient); err != nil { diff --git a/pkg/microservice/warpdrive/core/service/types/task/build.go b/pkg/microservice/warpdrive/core/service/types/task/build.go index 42a36ee6e..d3242050e 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/build.go +++ b/pkg/microservice/warpdrive/core/service/types/task/build.go @@ -86,6 +86,7 @@ type Install struct { } type RegistryNamespace struct { + ID string `bson:"_id,omitempty" json:"id,omitempty"` RegAddr string `bson:"reg_addr" json:"reg_addr"` RegType string `bson:"reg_type" json:"reg_type"` RegProvider string `bson:"reg_provider" json:"reg_provider"` diff --git a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go index 3b3e6e0a8..b310c6be9 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go +++ b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go @@ -49,6 +49,8 @@ type ConfigPayload struct { // ResetCache means ignore workspace cache ResetCache bool `json:"reset_cache"` PrivateKeys []*PrivateKey `json:"private_keys"` + + RegistryID string `json:"registry_id"` } func (cp *ConfigPayload) GetGitKnownHost() string { -- Gitee From 33b6c4cae7dfbf7413cc401dcb97e2ae3ab6c1e6 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Wed, 8 Dec 2021 17:40:45 +0800 Subject: [PATCH 080/134] optimize code Signed-off-by: liu deyi --- pkg/shared/client/aslan/multicluster.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/pkg/shared/client/aslan/multicluster.go b/pkg/shared/client/aslan/multicluster.go index 1acdb464a..4e2f24da4 100644 --- a/pkg/shared/client/aslan/multicluster.go +++ b/pkg/shared/client/aslan/multicluster.go @@ -1,8 +1,8 @@ package aslan import ( + "encoding/json" "fmt" - "strings" "time" "github.com/koderover/zadig/pkg/setting" @@ -36,14 +36,23 @@ type clusterResp struct { Local bool `json:"local"` } +type ErrorMessage struct { + Type string `json:"type"` + Code int `json:"code"` +} + func (c *Client) GetLocalCluster() (*clusterResp, error) { url := fmt.Sprintf("/cluster/clusters/%s", setting.LocalClusterID) clusterResp := &clusterResp{} resp, err := c.Get(url, httpclient.SetResult(clusterResp)) if err != nil { - fmt.Println(fmt.Sprintf("resp.body:%s", string(resp.Body()))) - if strings.Contains(err.Error(), "\"code\":6643") { + errorMessage := new(ErrorMessage) + err := json.Unmarshal(resp.Body(), errorMessage) + if err != nil { + return nil, fmt.Errorf("Failed to get cluster, error: %s", err) + } + if errorMessage.Code == 6643 { return nil, nil } return nil, fmt.Errorf("Failed to get cluster, error: %s", err) -- Gitee From 08b9346c2f55cda39cacce8fa2876b89e678d8c7 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Wed, 8 Dec 2021 18:16:12 +0800 Subject: [PATCH 081/134] debug code Signed-off-by: liu deyi --- .../warpdrive/core/service/taskplugin/build.go | 18 +++++++++--------- .../core/service/taskplugin/testing.go | 16 ++++++++-------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/build.go b/pkg/microservice/warpdrive/core/service/taskplugin/build.go index 0649e215a..8c5d48ca9 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/build.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/build.go @@ -327,15 +327,15 @@ func (p *BuildTaskPlugin) Complete(ctx context.Context, pipelineTask *task.Task, // 清理用户取消和超时的任务 defer func() { - if err := ensureDeleteJob(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { - p.Log.Error(err) - p.Task.Error = err.Error() - } - - if err := ensureDeleteConfigMap(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { - p.Log.Error(err) - p.Task.Error = err.Error() - } + //if err := ensureDeleteJob(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + // p.Log.Error(err) + // p.Task.Error = err.Error() + //} + // + //if err := ensureDeleteConfigMap(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + // p.Log.Error(err) + // p.Task.Error = err.Error() + //} return }() diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go index 8edc85268..424b8a5c1 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go @@ -270,14 +270,14 @@ func (p *TestPlugin) Complete(ctx context.Context, pipelineTask *task.Task, serv // 日志保存失败与否都清理job defer func() { - if err := ensureDeleteJob(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { - p.Log.Error(err) - p.Task.Error = err.Error() - } - if err := ensureDeleteConfigMap(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { - p.Log.Error(err) - p.Task.Error = err.Error() - } + //if err := ensureDeleteJob(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + // p.Log.Error(err) + // p.Task.Error = err.Error() + //} + //if err := ensureDeleteConfigMap(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + // p.Log.Error(err) + // p.Task.Error = err.Error() + //} return }() -- Gitee From 3c7cf7701aadf3ff1d7e622b46028f2402c0820c Mon Sep 17 00:00:00 2001 From: huangzexiong Date: Wed, 8 Dec 2021 18:46:56 +0800 Subject: [PATCH 082/134] test add $SERVICES params Signed-off-by: huangzexiong --- .../workflow/service/workflow/workflow_task.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go index 062320492..d849ead7c 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go @@ -1158,6 +1158,8 @@ func workFlowArgsToTaskArgs(target string, workflowArgs *commonmodels.WorkflowTa // TODO 和validation中转化testsubtask合并为一个方法 func testArgsToSubtask(args *commonmodels.WorkflowTaskArgs, pt *task.Task, log *zap.SugaredLogger) ([]*task.Testing, error) { var resp []*task.Testing + var servicesArray []string + var services string // 创建任务的测试参数为脱敏数据,需要转换为实际数据 for _, test := range args.Tests { @@ -1167,6 +1169,15 @@ func testArgsToSubtask(args *commonmodels.WorkflowTaskArgs, pt *task.Task, log * } } + // 获取本次任务执行的服务,按照逗号分隔,service1,service2... + if len(args.Target) > 0 { + for _, service := range args.Target { + servicesArray = append(servicesArray, service.ServiceName) + } + services = strings.Replace(strings.Trim(fmt.Sprint(servicesArray), "[]"), " ", ",", -1) + log.Info("获取本次任务执行的服务services:%v", services) + } + testArgs := args.Tests testCreator := args.WorkflowTaskCreator @@ -1224,6 +1235,9 @@ func testArgsToSubtask(args *commonmodels.WorkflowTaskArgs, pt *task.Task, log * } } envs = append(envs, &commonmodels.KeyVal{Key: "TEST_URL", Value: GetLink(pt, configbase.SystemAddress(), config.WorkflowType)}) + envs = append(envs, &commonmodels.KeyVal{Key: "SERVICES", Value: services}) + log.Info("test envs:%v", envs) + testTask.JobCtx.EnvVars = envs testTask.ImageID = testModule.PreTest.ImageID testTask.BuildOS = testModule.PreTest.BuildOS -- Gitee From d35d2210491bd38ecdf5f55df6bee0e258e9715c Mon Sep 17 00:00:00 2001 From: liu deyi Date: Wed, 8 Dec 2021 18:57:08 +0800 Subject: [PATCH 083/134] optimize code Signed-off-by: liu deyi --- pkg/microservice/aslan/core/environment/service/product.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/microservice/aslan/core/environment/service/product.go b/pkg/microservice/aslan/core/environment/service/product.go index e1c19f180..b43e62a95 100644 --- a/pkg/microservice/aslan/core/environment/service/product.go +++ b/pkg/microservice/aslan/core/environment/service/product.go @@ -209,7 +209,7 @@ func buildProductResp(envName string, prod *commonmodels.Product, log *zap.Sugar prodResp.ClusterName = cluster.Name prodResp.IsLocal = cluster.Local - if !clusterService.ClusterConnected(prod.ClusterID) { + if !prodResp.IsLocal && !clusterService.ClusterConnected(prod.ClusterID) { prodResp.Status = setting.ClusterDisconnected prodResp.Error = "集群未连接" return prodResp -- Gitee From 9cf0667075757fd30e53f4b3bf80abb02085eee6 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Wed, 8 Dec 2021 19:14:38 +0800 Subject: [PATCH 084/134] remove debug code Signed-off-by: liu deyi --- .../warpdrive/core/service/taskplugin/build.go | 18 +++++++++--------- .../core/service/taskplugin/testing.go | 16 ++++++++-------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/build.go b/pkg/microservice/warpdrive/core/service/taskplugin/build.go index 8c5d48ca9..0649e215a 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/build.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/build.go @@ -327,15 +327,15 @@ func (p *BuildTaskPlugin) Complete(ctx context.Context, pipelineTask *task.Task, // 清理用户取消和超时的任务 defer func() { - //if err := ensureDeleteJob(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { - // p.Log.Error(err) - // p.Task.Error = err.Error() - //} - // - //if err := ensureDeleteConfigMap(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { - // p.Log.Error(err) - // p.Task.Error = err.Error() - //} + if err := ensureDeleteJob(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + p.Log.Error(err) + p.Task.Error = err.Error() + } + + if err := ensureDeleteConfigMap(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + p.Log.Error(err) + p.Task.Error = err.Error() + } return }() diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go index 424b8a5c1..8edc85268 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go @@ -270,14 +270,14 @@ func (p *TestPlugin) Complete(ctx context.Context, pipelineTask *task.Task, serv // 日志保存失败与否都清理job defer func() { - //if err := ensureDeleteJob(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { - // p.Log.Error(err) - // p.Task.Error = err.Error() - //} - //if err := ensureDeleteConfigMap(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { - // p.Log.Error(err) - // p.Task.Error = err.Error() - //} + if err := ensureDeleteJob(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + p.Log.Error(err) + p.Task.Error = err.Error() + } + if err := ensureDeleteConfigMap(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + p.Log.Error(err) + p.Task.Error = err.Error() + } return }() -- Gitee From 2b3c2a140c52d6092ae8da952acea3ba4283dfe3 Mon Sep 17 00:00:00 2001 From: huangzexiong Date: Wed, 8 Dec 2021 19:20:55 +0800 Subject: [PATCH 085/134] test add $SERVICES params Signed-off-by: huangzexiong --- .../aslan/core/workflow/service/workflow/workflow_task.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go index d849ead7c..01c72c37a 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go @@ -1174,7 +1174,7 @@ func testArgsToSubtask(args *commonmodels.WorkflowTaskArgs, pt *task.Task, log * for _, service := range args.Target { servicesArray = append(servicesArray, service.ServiceName) } - services = strings.Replace(strings.Trim(fmt.Sprint(servicesArray), "[]"), " ", ",", -1) + services = strings.Join(servicesArray,",") log.Info("获取本次任务执行的服务services:%v", services) } -- Gitee From a4ee227286d5df36d7e9a607fbfa7335a2512d36 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Thu, 9 Dec 2021 10:08:30 +0800 Subject: [PATCH 086/134] optimize code Signed-off-by: liu deyi --- .../common/repository/models/k8s_cluster.go | 34 +++++++++---------- .../core/common/repository/models/queue.go | 2 +- .../aslan/core/environment/service/kube.go | 4 +-- .../core/multicluster/service/clusters.go | 4 +-- .../picket/client/aslan/kubeconfig.go | 16 +++++++++ pkg/microservice/picket/config/consts.go | 16 +++++++++ .../picket/core/filter/handler/kubeconfig.go | 16 +++++++++ .../picket/core/filter/service/kubeconfig.go | 16 +++++++++ .../warpdrive/core/service/taskplugin/job.go | 17 ---------- .../core/service/types/task/config_payload.go | 4 +-- pkg/shared/client/aslan/multicluster.go | 16 +++++++++ pkg/shared/kube/client/client.go | 17 ++++++++++ pkg/shared/kube/resource/node.go | 20 +++++++++-- 13 files changed, 139 insertions(+), 43 deletions(-) diff --git a/pkg/microservice/aslan/core/common/repository/models/k8s_cluster.go b/pkg/microservice/aslan/core/common/repository/models/k8s_cluster.go index 309ead9ac..816689683 100644 --- a/pkg/microservice/aslan/core/common/repository/models/k8s_cluster.go +++ b/pkg/microservice/aslan/core/common/repository/models/k8s_cluster.go @@ -24,23 +24,23 @@ import ( ) type K8SCluster struct { - ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` - Name string `json:"name" bson:"name"` - Tags []string `json:"tags" bson:"tags"` - Description string `json:"description" bson:"description"` - Namespace string `json:"namespace" bson:"namespace"` - Info *K8SClusterInfo `json:"info,omitempty" bson:"info,omitempty"` - AdvancedConfig *AdvancedConfig `json:"config,omitempty" bson:"config,omitempty"` - Status setting.K8SClusterStatus `json:"status" bson:"status"` - Error string `json:"error" bson:"error"` - Yaml string `json:"yaml" bson:"yaml"` - Production bool `json:"production" bson:"production"` - CreatedAt int64 `json:"createdAt" bson:"createdAt"` - CreatedBy string `json:"createdBy" bson:"createdBy"` - Disconnected bool `json:"-" bson:"disconnected"` - Token string `json:"token" bson:"-"` - Provider int8 `json:"provider" bson:"provider"` - Local bool `json:"local" bson:"local"` + ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` + Name string `json:"name" bson:"name"` + Tags []string `json:"tags" bson:"tags"` + Description string `json:"description" bson:"description"` + Namespace string `json:"namespace" bson:"namespace"` + Info *K8SClusterInfo `json:"info,omitempty" bson:"info,omitempty"` + AdvancedConfig *AdvancedConfig `json:"advanced_config,omitempty" bson:"advanced_config,omitempty"` + Status setting.K8SClusterStatus `json:"status" bson:"status"` + Error string `json:"error" bson:"error"` + Yaml string `json:"yaml" bson:"yaml"` + Production bool `json:"production" bson:"production"` + CreatedAt int64 `json:"createdAt" bson:"createdAt"` + CreatedBy string `json:"createdBy" bson:"createdBy"` + Disconnected bool `json:"-" bson:"disconnected"` + Token string `json:"token" bson:"-"` + Provider int8 `json:"provider" bson:"provider"` + Local bool `json:"local" bson:"local"` } type K8SClusterResp struct { diff --git a/pkg/microservice/aslan/core/common/repository/models/queue.go b/pkg/microservice/aslan/core/common/repository/models/queue.go index 1ea52e5f3..2286fb79a 100644 --- a/pkg/microservice/aslan/core/common/repository/models/queue.go +++ b/pkg/microservice/aslan/core/common/repository/models/queue.go @@ -137,7 +137,7 @@ type ConfigPayload struct { ResetCache bool `json:"reset_cache"` JenkinsBuildConfig JenkinsBuildConfig `json:"jenkins_build_config"` PrivateKeys []*PrivateKey `json:"private_keys"` - K8SClusters []*K8SClusterResp `json:"k8s_cluster"` + K8SClusters []*K8SClusterResp `json:"k8s_clusters"` } type AslanConfig struct { diff --git a/pkg/microservice/aslan/core/environment/service/kube.go b/pkg/microservice/aslan/core/environment/service/kube.go index bae1bc9d5..103d1c433 100644 --- a/pkg/microservice/aslan/core/environment/service/kube.go +++ b/pkg/microservice/aslan/core/environment/service/kube.go @@ -122,7 +122,7 @@ func ListAvailableNamespaces(clusterID string, log *zap.SugaredLogger) ([]*resou if err != nil { log.Errorf("ListNamespaces err:%v", err) if apierrors.IsForbidden(err) { - return resp, nil + return resp, err } return resp, err } @@ -240,7 +240,7 @@ func ListAvailableNodes(clusterID string, log *zap.SugaredLogger) (*NodeResp, er if err != nil { log.Errorf("ListNodes err:%s", err) if apierrors.IsForbidden(err) { - return resp, nil + return resp, err } return resp, err } diff --git a/pkg/microservice/aslan/core/multicluster/service/clusters.go b/pkg/microservice/aslan/core/multicluster/service/clusters.go index 047cb9dc4..dc7f954a3 100644 --- a/pkg/microservice/aslan/core/multicluster/service/clusters.go +++ b/pkg/microservice/aslan/core/multicluster/service/clusters.go @@ -42,7 +42,7 @@ type K8SCluster struct { ID string `json:"id,omitempty"` Name string `json:"name"` Description string `json:"description"` - AdvancedConfig *AdvancedConfig `json:"config,omitempty"` + AdvancedConfig *AdvancedConfig `json:"advanced_config,omitempty"` Status setting.K8SClusterStatus `json:"status"` Production bool `json:"production"` CreatedAt int64 `json:"createdAt"` @@ -61,7 +61,7 @@ func (k *K8SCluster) Clean() error { k.Description = strings.TrimSpace(k.Description) if !namePattern.MatchString(k.Name) { - return fmt.Errorf("集群名称不符合规则") + return fmt.Errorf("The cluster name does not meet the rules") } return nil diff --git a/pkg/microservice/picket/client/aslan/kubeconfig.go b/pkg/microservice/picket/client/aslan/kubeconfig.go index b463271b3..6373970ad 100644 --- a/pkg/microservice/picket/client/aslan/kubeconfig.go +++ b/pkg/microservice/picket/client/aslan/kubeconfig.go @@ -1,3 +1,19 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package aslan import ( diff --git a/pkg/microservice/picket/config/consts.go b/pkg/microservice/picket/config/consts.go index 06e1924e5..944103019 100644 --- a/pkg/microservice/picket/config/consts.go +++ b/pkg/microservice/picket/config/consts.go @@ -1,3 +1,19 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package config type RulesLogicalOperator string diff --git a/pkg/microservice/picket/core/filter/handler/kubeconfig.go b/pkg/microservice/picket/core/filter/handler/kubeconfig.go index 5cac861fa..365e75e5f 100644 --- a/pkg/microservice/picket/core/filter/handler/kubeconfig.go +++ b/pkg/microservice/picket/core/filter/handler/kubeconfig.go @@ -1,3 +1,19 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package handler import ( diff --git a/pkg/microservice/picket/core/filter/service/kubeconfig.go b/pkg/microservice/picket/core/filter/service/kubeconfig.go index 773fc8cb4..b020f9707 100644 --- a/pkg/microservice/picket/core/filter/service/kubeconfig.go +++ b/pkg/microservice/picket/core/filter/service/kubeconfig.go @@ -1,3 +1,19 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package service import ( diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/job.go b/pkg/microservice/warpdrive/core/service/taskplugin/job.go index b41d87fbd..318f44547 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/job.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/job.go @@ -612,11 +612,6 @@ func getVolumeMounts(ctx *task.PipelineCtx) []corev1.VolumeMount { Name: "job-config", MountPath: ctx.ConfigMapMountDir, }) - //resp = append(resp, corev1.VolumeMount{ - // Name: "aes-key", - // ReadOnly: true, - // MountPath: "/etc/encryption", - //}) return resp } @@ -633,18 +628,6 @@ func getVolumes(jobName string) []corev1.Volume { }, }, }) - //resp = append(resp, corev1.Volume{ - // Name: "aes-key", - // VolumeSource: corev1.VolumeSource{ - // Secret: &corev1.SecretVolumeSource{ - // SecretName: "zadig-aes-key", - // Items: []corev1.KeyToPath{{ - // Key: "aesKey", - // Path: "aes", - // }}, - // }, - // }, - //}) return resp } diff --git a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go index 10b763847..cd6fb6267 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go +++ b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go @@ -52,7 +52,7 @@ type ConfigPayload struct { // ResetCache means ignore workspace cache ResetCache bool `json:"reset_cache"` PrivateKeys []*PrivateKey `json:"private_keys"` - K8SClusters []*K8SCluster `json:"k8s_cluster"` + K8SClusters []*K8SCluster `json:"k8s_clusters"` } func (cp *ConfigPayload) GetGitKnownHost() string { @@ -156,7 +156,7 @@ type PrivateKey struct { type K8SCluster struct { ID string `json:"id,omitempty" bson:"_id,omitempty"` Name string `json:"name" bson:"name"` - AdvancedConfig *AdvancedConfig `json:"config,omitempty" bson:"config,omitempty"` + AdvancedConfig *AdvancedConfig `json:"advanced_config,omitempty" bson:"advanced_config,omitempty"` } type AdvancedConfig struct { diff --git a/pkg/shared/client/aslan/multicluster.go b/pkg/shared/client/aslan/multicluster.go index 4e2f24da4..0611bcd85 100644 --- a/pkg/shared/client/aslan/multicluster.go +++ b/pkg/shared/client/aslan/multicluster.go @@ -1,3 +1,19 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package aslan import ( diff --git a/pkg/shared/kube/client/client.go b/pkg/shared/kube/client/client.go index dfb984b13..8374adb51 100644 --- a/pkg/shared/kube/client/client.go +++ b/pkg/shared/kube/client/client.go @@ -1,3 +1,19 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package client import ( @@ -23,6 +39,7 @@ func GetKubeAPIReader(hubServerAddr, clusterID string) (client.Reader, error) { } return multicluster.GetKubeAPIReader(hubServerAddr, clusterID) } + func GetRESTConfig(hubServerAddr, clusterID string) (*rest.Config, error) { if clusterID == setting.LocalClusterID { clusterID = "" diff --git a/pkg/shared/kube/resource/node.go b/pkg/shared/kube/resource/node.go index a0fb402d7..733ef4204 100644 --- a/pkg/shared/kube/resource/node.go +++ b/pkg/shared/kube/resource/node.go @@ -1,7 +1,23 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package resource type Node struct { - Labels []string `json:"node_labels"` + Labels []string `json:"labels"` Ready bool `json:"ready"` - IP string `json:"node_ip"` + IP string `json:"ip"` } -- Gitee From ee82522296b079e25aef49693d30101e35c59b50 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Thu, 9 Dec 2021 11:01:35 +0800 Subject: [PATCH 087/134] optimize code Signed-off-by: liu deyi --- .../core/common/repository/mongodb/k8s_cluster.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/k8s_cluster.go b/pkg/microservice/aslan/core/common/repository/mongodb/k8s_cluster.go index 8d6c5acd7..a9464a013 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/k8s_cluster.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/k8s_cluster.go @@ -188,12 +188,12 @@ func (c *K8SClusterColl) UpdateMutableFields(cluster *models.K8SCluster, id stri } _, err = c.UpdateOne(context.TODO(), bson.M{"_id": cluster.ID}, bson.M{"$set": bson.M{ - "name": cluster.Name, - "description": cluster.Description, - "tags": cluster.Tags, - "namespace": cluster.Namespace, - "production": cluster.Production, - "config": cluster.AdvancedConfig, + "name": cluster.Name, + "description": cluster.Description, + "tags": cluster.Tags, + "namespace": cluster.Namespace, + "production": cluster.Production, + "advanced_config": cluster.AdvancedConfig, }}, ) -- Gitee From ec592a79b66677b1388c2c7f8b141086160a39fb Mon Sep 17 00:00:00 2001 From: YuanPei Li Date: Thu, 9 Dec 2021 11:55:39 +0800 Subject: [PATCH 088/134] fix the quick start link Signed-off-by: Ryan Li --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7ba402d46..b004e68e7 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ The Highlighted Features: ### How to use? -Please follow [Quick Start](https://docs.koderover.com/zadig/quick-start/try-out-install) +Please follow [Quick Start](https://docs.koderover.com/zadig/quick-start/try-out-install/) ### Bootcamps -- Gitee From d4a5c17a3b04765e6d2606403a241457c3049526 Mon Sep 17 00:00:00 2001 From: YuanPei Li Date: Thu, 9 Dec 2021 12:01:06 +0800 Subject: [PATCH 089/134] fix quick start link in zh-cn doc Signed-off-by: Ryan Li --- README-zh-CN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README-zh-CN.md b/README-zh-CN.md index 3bd629bac..cbfb90056 100644 --- a/README-zh-CN.md +++ b/README-zh-CN.md @@ -75,7 +75,7 @@ Zadig 是一款面向开发者设计的云原生持续交付(Continuous Delivery ### 快速使用 -请参阅 [快速入门](https://docs.koderover.com/zadig/quick-start/try-out-install) +请参阅 [快速入门](https://docs.koderover.com/zadig/quick-start/try-out-install/) ### 训练营 -- Gitee From 55513efc6ac52902288b1036f364be072c03471f Mon Sep 17 00:00:00 2001 From: panxunying Date: Thu, 9 Dec 2021 14:46:36 +0800 Subject: [PATCH 090/134] optimize Signed-off-by: panxunying --- .../aslan/core/common/repository/models/queue.go | 1 + pkg/microservice/aslan/core/common/service/product.go | 9 +++------ pkg/microservice/aslan/core/common/service/registry.go | 9 --------- .../aslan/core/environment/handler/environment.go | 7 ++++++- .../aslan/core/environment/service/environment.go | 8 ++++++-- .../aslan/core/environment/service/product.go | 4 ++-- pkg/microservice/aslan/core/system/handler/registry.go | 2 +- pkg/microservice/aslan/core/system/service/registry.go | 2 +- .../core/workflow/service/workflow/workflow_task.go | 3 +-- 9 files changed, 21 insertions(+), 24 deletions(-) diff --git a/pkg/microservice/aslan/core/common/repository/models/queue.go b/pkg/microservice/aslan/core/common/repository/models/queue.go index edd8a89a4..f0d33f1e6 100644 --- a/pkg/microservice/aslan/core/common/repository/models/queue.go +++ b/pkg/microservice/aslan/core/common/repository/models/queue.go @@ -137,6 +137,7 @@ type ConfigPayload struct { JenkinsBuildConfig JenkinsBuildConfig `json:"jenkins_build_config"` PrivateKeys []*PrivateKey `json:"private_keys"` + // RegistryID is the id of product registry RegistryID string `json:"registry_id"` } diff --git a/pkg/microservice/aslan/core/common/service/product.go b/pkg/microservice/aslan/core/common/service/product.go index 8c72170d8..6eed899ef 100644 --- a/pkg/microservice/aslan/core/common/service/product.go +++ b/pkg/microservice/aslan/core/common/service/product.go @@ -353,17 +353,14 @@ func GetProductEnvNamespace(envName, productName, namespace string) string { return product.Namespace } -func GetProductEnv(envName, productName, namespace string) *models.Product { - if namespace != "" { - return nil - } +func GetProductEnv(envName, productName string) (*models.Product, error) { product, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{ Name: productName, EnvName: envName, }) if err != nil { product = &commonmodels.Product{EnvName: envName, ProductName: productName} - return product + return nil, err } - return product + return product, nil } diff --git a/pkg/microservice/aslan/core/common/service/registry.go b/pkg/microservice/aslan/core/common/service/registry.go index 4c0323aac..0c8d7dec3 100644 --- a/pkg/microservice/aslan/core/common/service/registry.go +++ b/pkg/microservice/aslan/core/common/service/registry.go @@ -73,15 +73,6 @@ func GetDefaultRegistryNamespace(log *zap.SugaredLogger) (*models.RegistryNamesp return resp, nil } -func GetRegistryNamespace(registryID string, log *zap.SugaredLogger) (*models.RegistryNamespace, error) { - resp, err := mongodb.NewRegistryNamespaceColl().Find(&mongodb.FindRegOps{ID: registryID}) - if err != nil { - log.Errorf("get default registry error: %v", err) - return resp, fmt.Errorf("get default registry error: %v", err) - } - return resp, nil -} - func ListRegistryNamespaces(log *zap.SugaredLogger) ([]*models.RegistryNamespace, error) { resp, err := mongodb.NewRegistryNamespaceColl().FindAll(&mongodb.FindRegOps{}) if err != nil { diff --git a/pkg/microservice/aslan/core/environment/handler/environment.go b/pkg/microservice/aslan/core/environment/handler/environment.go index ef9f41c3c..414b549f5 100644 --- a/pkg/microservice/aslan/core/environment/handler/environment.go +++ b/pkg/microservice/aslan/core/environment/handler/environment.go @@ -54,6 +54,11 @@ type NamespaceResource struct { Ingresses []resource.Ingress `json:"ingresses"` } +type UpdateProductRegistryRequest struct { + RegistryId string `json:"registry_id"` + Namespace string `json:"namespace"` +} + func ListProducts(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() @@ -256,7 +261,7 @@ func UpdateProductRegistry(c *gin.Context) { defer func() { internalhandler.JSONResponse(c, ctx) }() projectName := c.Query("projectName") - args := new(commonmodels.Product) + args := new(UpdateProductRegistryRequest) data, err := c.GetRawData() if err != nil { log.Errorf("UpdateProduct c.GetRawData() err : %v", err) diff --git a/pkg/microservice/aslan/core/environment/service/environment.go b/pkg/microservice/aslan/core/environment/service/environment.go index dcecd7cce..3030a6b3d 100644 --- a/pkg/microservice/aslan/core/environment/service/environment.go +++ b/pkg/microservice/aslan/core/environment/service/environment.go @@ -967,7 +967,11 @@ func checkOverrideValuesChange(source *template.RenderChart, args *commonservice } func UpdateHelmProductRenderset(productName, envName, userName, requestID string, args *EnvRendersetArg, log *zap.SugaredLogger) error { - product := commonservice.GetProductEnv(envName, productName, "") + product, err := commonservice.GetProductEnv(envName, productName) + if err != nil { + log.Errorf("UpdateHelmProductRenderset GetProductEnv envName:%s productName: %s error, error msg:%s", envName, productName, err) + return err + } opt := &commonrepo.RenderSetFindOption{Name: product.Namespace} productRenderset, _, err := commonrepo.NewRenderSetColl().FindRenderSet(opt) if err != nil || productRenderset == nil { @@ -1974,7 +1978,7 @@ func preCreateProduct(envName string, args *commonmodels.Product, kubeClient cli args.Render = tmpRenderInfo if preCreateNSAndSecret(productTmpl.ProductFeature) { - return ensureKubeEnv(args.Namespace, args.ID.String(), kubeClient, log) + return ensureKubeEnv(args.Namespace, args.RegistryId, kubeClient, log) } return nil } diff --git a/pkg/microservice/aslan/core/environment/service/product.go b/pkg/microservice/aslan/core/environment/service/product.go index 1429229a0..be1f97388 100644 --- a/pkg/microservice/aslan/core/environment/service/product.go +++ b/pkg/microservice/aslan/core/environment/service/product.go @@ -158,7 +158,7 @@ func GetProduct(username, envName, productName string, log *zap.SugaredLogger) ( opt := &commonrepo.ProductFindOptions{Name: productName, EnvName: envName} prod, err := commonrepo.NewProductColl().Find(opt) if err != nil { - log.Errorf("[User:%s][EnvName:%s][Product:%s] Product.FindByOwner error: %v", username, envName, productName, err) + log.Errorf("[User:%s][EnvName:%s][Product:%s] Product.FindByOwner error: %s", username, envName, productName, err) return nil, e.ErrGetEnv } @@ -172,7 +172,7 @@ func GetProduct(username, envName, productName string, log *zap.SugaredLogger) ( if len(prod.RegistryId) == 0 { reg, err := commonservice.FindDefaultRegistry(log) if err != nil { - log.Errorf("[User:%s][EnvName:%s][Product:%s] FindDefaultRegistry error: %v", username, envName, productName, err) + log.Errorf("[User:%s][EnvName:%s][Product:%s] FindDefaultRegistry error: %s", username, envName, productName, err) return nil, err } prod.RegistryId = reg.ID.Hex() diff --git a/pkg/microservice/aslan/core/system/handler/registry.go b/pkg/microservice/aslan/core/system/handler/registry.go index 14c0cd37d..b9a77ed8b 100644 --- a/pkg/microservice/aslan/core/system/handler/registry.go +++ b/pkg/microservice/aslan/core/system/handler/registry.go @@ -64,7 +64,7 @@ func GetRegistryNamespace(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - reg, err := commonservice.GetRegistryNamespace(c.Param("id"), ctx.Logger) + reg, err := commonservice.FindRegistryById(c.Param("id"), ctx.Logger) if err != nil { ctx.Err = err return diff --git a/pkg/microservice/aslan/core/system/service/registry.go b/pkg/microservice/aslan/core/system/service/registry.go index 794e4710b..42babe6ba 100644 --- a/pkg/microservice/aslan/core/system/service/registry.go +++ b/pkg/microservice/aslan/core/system/service/registry.go @@ -91,7 +91,7 @@ func CreateRegistryNamespace(username string, args *commonmodels.RegistryNamespa log.Errorf("[updateRegistry] Failed to get kubecli for namespace: %s", prod.Namespace) return } - err = commonservice.EnsureDefaultRegistrySecret(prod.Namespace, args.ID.String(), kubeClient, log) + err = commonservice.EnsureDefaultRegistrySecret(prod.Namespace, args.ID.Hex(), kubeClient, log) if err != nil { log.Errorf("[updateRegistry] Failed to update registry secret for namespace: %s, the error is: %+v", prod.Namespace, err) } diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go index c0284a022..b1f9aa72d 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go @@ -503,7 +503,7 @@ func CreateWorkflowTask(args *commonmodels.WorkflowTaskArgs, taskCreator string, log.Errorf("get default registry error: %v", err) return nil, e.ErrGetCounter.AddDesc(err.Error()) } - env.RegistryId = reg.ID.String() + env.RegistryId = reg.ID.Hex() } configPayload.RegistryID = env.RegistryId repos, err := commonrepo.NewRegistryNamespaceColl().FindAll(&commonrepo.FindRegOps{}) @@ -1806,7 +1806,6 @@ func ensurePipelineTask(pt *task.Task, envName string, log *zap.SugaredLogger) e var reg *commonmodels.RegistryNamespace if len(exitedProd.RegistryId) > 0 { reg, err = commonservice.FindRegistryById(exitedProd.RegistryId, log) - log.Infof("FindRegistryById %s", exitedProd.RegistryId) if err != nil { log.Errorf("service.EnsureRegistrySecret: failed to find registry: %s error msg:%v", exitedProd.RegistryId, err) -- Gitee From edf055925d7a07eaa62e7ecabd94239ffcb699d1 Mon Sep 17 00:00:00 2001 From: panxunying Date: Thu, 9 Dec 2021 15:42:37 +0800 Subject: [PATCH 091/134] optimize Signed-off-by: panxunying --- .../aslan/core/common/service/product.go | 12 ------------ .../aslan/core/environment/service/environment.go | 5 ++++- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/pkg/microservice/aslan/core/common/service/product.go b/pkg/microservice/aslan/core/common/service/product.go index 6eed899ef..9986f3575 100644 --- a/pkg/microservice/aslan/core/common/service/product.go +++ b/pkg/microservice/aslan/core/common/service/product.go @@ -352,15 +352,3 @@ func GetProductEnvNamespace(envName, productName, namespace string) string { } return product.Namespace } - -func GetProductEnv(envName, productName string) (*models.Product, error) { - product, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{ - Name: productName, - EnvName: envName, - }) - if err != nil { - product = &commonmodels.Product{EnvName: envName, ProductName: productName} - return nil, err - } - return product, nil -} diff --git a/pkg/microservice/aslan/core/environment/service/environment.go b/pkg/microservice/aslan/core/environment/service/environment.go index 3030a6b3d..b4ab56ca2 100644 --- a/pkg/microservice/aslan/core/environment/service/environment.go +++ b/pkg/microservice/aslan/core/environment/service/environment.go @@ -967,7 +967,10 @@ func checkOverrideValuesChange(source *template.RenderChart, args *commonservice } func UpdateHelmProductRenderset(productName, envName, userName, requestID string, args *EnvRendersetArg, log *zap.SugaredLogger) error { - product, err := commonservice.GetProductEnv(envName, productName) + product, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{ + Name: productName, + EnvName: envName, + }) if err != nil { log.Errorf("UpdateHelmProductRenderset GetProductEnv envName:%s productName: %s error, error msg:%s", envName, productName, err) return err -- Gitee From 4e51c86e8ab01dcdb2ca9b67fa3ff8b9164dac16 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Thu, 9 Dec 2021 16:10:59 +0800 Subject: [PATCH 092/134] optimize code Signed-off-by: liu deyi --- pkg/microservice/aslan/core/environment/service/product.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/microservice/aslan/core/environment/service/product.go b/pkg/microservice/aslan/core/environment/service/product.go index b43e62a95..db2108572 100644 --- a/pkg/microservice/aslan/core/environment/service/product.go +++ b/pkg/microservice/aslan/core/environment/service/product.go @@ -214,6 +214,8 @@ func buildProductResp(envName string, prod *commonmodels.Product, log *zap.Sugar prodResp.Error = "集群未连接" return prodResp } + } else { + prodResp.IsLocal = true } if prod.Status == setting.ProductStatusCreating { -- Gitee From 1d6f5ba7c508c9ee188fce91e713932900f91494 Mon Sep 17 00:00:00 2001 From: panxunying Date: Thu, 9 Dec 2021 17:14:56 +0800 Subject: [PATCH 093/134] optimize Signed-off-by: panxunying --- .../aslan/core/common/repository/models/product.go | 2 +- .../aslan/core/common/service/registry.go | 6 +++--- .../aslan/core/environment/handler/environment.go | 8 ++++---- .../aslan/core/environment/handler/router.go | 2 +- .../aslan/core/environment/service/environment.go | 14 +++++++------- .../environment/service/environment_creator.go | 2 +- .../aslan/core/environment/service/product.go | 6 +++--- .../aslan/core/system/handler/router.go | 2 +- .../workflow/service/workflow/workflow_task.go | 12 ++++++------ 9 files changed, 27 insertions(+), 27 deletions(-) diff --git a/pkg/microservice/aslan/core/common/repository/models/product.go b/pkg/microservice/aslan/core/common/repository/models/product.go index 2b290d888..af7ecc6b0 100644 --- a/pkg/microservice/aslan/core/common/repository/models/product.go +++ b/pkg/microservice/aslan/core/common/repository/models/product.go @@ -50,7 +50,7 @@ type Product struct { RecycleDay int `bson:"recycle_day" json:"recycle_day"` Source string `bson:"source" json:"source"` IsOpenSource bool `bson:"is_opensource" json:"is_opensource"` - RegistryId string `bson:"registry_id" json:"registry_id"` + RegistryID string `bson:"registry_id" json:"registry_id"` // TODO: temp flag IsForkedProduct bool `bson:"-" json:"-"` } diff --git a/pkg/microservice/aslan/core/common/service/registry.go b/pkg/microservice/aslan/core/common/service/registry.go index 0c8d7dec3..301e02245 100644 --- a/pkg/microservice/aslan/core/common/service/registry.go +++ b/pkg/microservice/aslan/core/common/service/registry.go @@ -31,10 +31,10 @@ import ( ) func FindRegistryById(registryId string, log *zap.SugaredLogger) (*models.RegistryNamespace, error) { - return FindRegisty(&mongodb.FindRegOps{ID: registryId}, log) + return findRegisty(&mongodb.FindRegOps{ID: registryId}, log) } -func FindRegisty(regOps *mongodb.FindRegOps, log *zap.SugaredLogger) (*models.RegistryNamespace, error) { +func findRegisty(regOps *mongodb.FindRegOps, log *zap.SugaredLogger) (*models.RegistryNamespace, error) { // TODO: 多租户适配 resp, err := mongodb.NewRegistryNamespaceColl().Find(regOps) @@ -61,7 +61,7 @@ func FindRegisty(regOps *mongodb.FindRegOps, log *zap.SugaredLogger) (*models.Re } func FindDefaultRegistry(log *zap.SugaredLogger) (*models.RegistryNamespace, error) { - return FindRegisty(&mongodb.FindRegOps{IsDefault: true}, log) + return findRegisty(&mongodb.FindRegOps{IsDefault: true}, log) } func GetDefaultRegistryNamespace(log *zap.SugaredLogger) (*models.RegistryNamespace, error) { diff --git a/pkg/microservice/aslan/core/environment/handler/environment.go b/pkg/microservice/aslan/core/environment/handler/environment.go index 414b549f5..c3ad692f5 100644 --- a/pkg/microservice/aslan/core/environment/handler/environment.go +++ b/pkg/microservice/aslan/core/environment/handler/environment.go @@ -55,7 +55,7 @@ type NamespaceResource struct { } type UpdateProductRegistryRequest struct { - RegistryId string `json:"registry_id"` + RegistryID string `json:"registry_id"` Namespace string `json:"namespace"` } @@ -208,7 +208,7 @@ func CreateProduct(c *gin.Context) { return } - if args.RegistryId == "" { + if args.RegistryID == "" { ctx.Err = e.ErrInvalidParam.AddDesc("RegistryId can not be null!") return } @@ -280,9 +280,9 @@ func UpdateProductRegistry(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) return } - ctx.Err = service.UpdateProductRegistry(args.Namespace, args.RegistryId, ctx.Logger) + ctx.Err = service.UpdateProductRegistry(args.Namespace, args.RegistryID, ctx.Logger) if ctx.Err != nil { - ctx.Logger.Errorf("failed to update product %s %s: %v", args.Namespace, args.RegistryId, ctx.Err) + ctx.Logger.Errorf("failed to update product %s %s: %v", args.Namespace, args.RegistryID, ctx.Err) } } diff --git a/pkg/microservice/aslan/core/environment/handler/router.go b/pkg/microservice/aslan/core/environment/handler/router.go index 3b0cd996d..bf4044349 100644 --- a/pkg/microservice/aslan/core/environment/handler/router.go +++ b/pkg/microservice/aslan/core/environment/handler/router.go @@ -95,7 +95,7 @@ func (*Router) Inject(router *gin.RouterGroup) { { environments.GET("", ListProducts) environments.PUT("/:name", gin2.UpdateOperationLogStatus, UpdateProduct) - environments.PUT("/registry", gin2.UpdateOperationLogStatus, UpdateProductRegistry) + environments.PUT("/:name/registry", gin2.UpdateOperationLogStatus, UpdateProductRegistry) environments.PUT("", gin2.UpdateOperationLogStatus, UpdateMultiProducts) environments.POST("", gin2.UpdateOperationLogStatus, CreateProduct) environments.GET("/:name", GetProduct) diff --git a/pkg/microservice/aslan/core/environment/service/environment.go b/pkg/microservice/aslan/core/environment/service/environment.go index b4ab56ca2..4e8caa243 100644 --- a/pkg/microservice/aslan/core/environment/service/environment.go +++ b/pkg/microservice/aslan/core/environment/service/environment.go @@ -194,8 +194,8 @@ func ListProducts(projectName string, envNames []string, log *zap.SugaredLogger) production := false clusterName := "" cluster, ok := clusterMap[clusterID] - if len(env.RegistryId) == 0 { - env.RegistryId = reg.ID.String() + if len(env.RegistryID) == 0 { + env.RegistryID = reg.ID.Hex() } if ok { production = cluster.Production @@ -213,7 +213,7 @@ func ListProducts(projectName string, envNames []string, log *zap.SugaredLogger) Error: env.Error, UpdateTime: env.UpdateTime, UpdateBy: env.UpdateBy, - RegistryID: env.RegistryId, + RegistryID: env.RegistryID, ClusterID: env.ClusterID, }) } @@ -586,7 +586,7 @@ func UpdateProductV2(envName, productName, user, requestID string, force bool, k } } - err = ensureKubeEnv(exitedProd.Namespace, exitedProd.RegistryId, kubeClient, log) + err = ensureKubeEnv(exitedProd.Namespace, exitedProd.RegistryID, kubeClient, log) if err != nil { log.Errorf("[%s][P:%s] service.UpdateProductV2 create kubeEnv error: %v", envName, productName, err) @@ -760,7 +760,7 @@ func createSingleHelmProduct(templateProduct *template.Product, serviceGroup [][ IsOpenSource: templateProduct.IsOpensource, ChartInfos: templateProduct.ChartInfos, IsForkedProduct: false, - RegistryId: registryID, + RegistryID: registryID, } customChartValueMap := make(map[string]*commonservice.RenderChartArg) @@ -1024,7 +1024,7 @@ func UpdateHelmProductRenderset(productName, envName, userName, requestID string log.Errorf("UpdateHelmProductRenderset GetKubeClient error, error msg:%s", err) return err } - return ensureKubeEnv(product.Namespace, product.RegistryId, kubeClient, log) + return ensureKubeEnv(product.Namespace, product.RegistryID, kubeClient, log) } func UpdateHelmProductVariable(productName, envName, username, requestID string, updatedRcs []*template.RenderChart, renderset *commonmodels.RenderSet, log *zap.SugaredLogger) error { @@ -1981,7 +1981,7 @@ func preCreateProduct(envName string, args *commonmodels.Product, kubeClient cli args.Render = tmpRenderInfo if preCreateNSAndSecret(productTmpl.ProductFeature) { - return ensureKubeEnv(args.Namespace, args.RegistryId, kubeClient, log) + return ensureKubeEnv(args.Namespace, args.RegistryID, kubeClient, log) } return nil } diff --git a/pkg/microservice/aslan/core/environment/service/environment_creator.go b/pkg/microservice/aslan/core/environment/service/environment_creator.go index 0abe50d1a..1d8896d12 100644 --- a/pkg/microservice/aslan/core/environment/service/environment_creator.go +++ b/pkg/microservice/aslan/core/environment/service/environment_creator.go @@ -85,7 +85,7 @@ func (autoCreator *AutoCreator) Create(envName string) (string, error) { productObject.Namespace = commonservice.GetProductEnvNamespace(envName, productName, "") productObject.UpdateBy = autoCreator.Param.UserName productObject.EnvName = envName - productObject.RegistryId = autoCreator.Param.RegistryID + productObject.RegistryID = autoCreator.Param.RegistryID if autoCreator.Param.EnvType == setting.HelmDeployType { productObject.Source = setting.SourceFromHelm } diff --git a/pkg/microservice/aslan/core/environment/service/product.go b/pkg/microservice/aslan/core/environment/service/product.go index be1f97388..b1a077906 100644 --- a/pkg/microservice/aslan/core/environment/service/product.go +++ b/pkg/microservice/aslan/core/environment/service/product.go @@ -169,13 +169,13 @@ func GetProduct(username, envName, productName string, log *zap.SugaredLogger) ( } } - if len(prod.RegistryId) == 0 { + if len(prod.RegistryID) == 0 { reg, err := commonservice.FindDefaultRegistry(log) if err != nil { log.Errorf("[User:%s][EnvName:%s][Product:%s] FindDefaultRegistry error: %s", username, envName, productName, err) return nil, err } - prod.RegistryId = reg.ID.Hex() + prod.RegistryID = reg.ID.Hex() } resp := buildProductResp(prod.EnvName, prod, log) return resp, nil @@ -198,7 +198,7 @@ func buildProductResp(envName string, prod *commonmodels.Product, log *zap.Sugar ClusterID: prod.ClusterID, RecycleDay: prod.RecycleDay, Source: prod.Source, - RegisterID: prod.RegistryId, + RegisterID: prod.RegistryID, } if prod.ClusterID != "" { diff --git a/pkg/microservice/aslan/core/system/handler/router.go b/pkg/microservice/aslan/core/system/handler/router.go index bf356fe7b..253728546 100644 --- a/pkg/microservice/aslan/core/system/handler/router.go +++ b/pkg/microservice/aslan/core/system/handler/router.go @@ -61,7 +61,7 @@ func (*Router) Inject(router *gin.RouterGroup) { registry.GET("", ListRegistries) // 获取默认的镜像仓库配置,用于kodespace CLI调用 registry.GET("/namespaces/default", GetDefaultRegistryNamespace) - registry.GET("/namespaces/:id", GetRegistryNamespace) + registry.GET("/namespaces/specific/:id", GetRegistryNamespace) registry.GET("/namespaces", ListRegistryNamespaces) registry.POST("/namespaces", gin2.UpdateOperationLogStatus, CreateRegistryNamespace) registry.PUT("/namespaces/:id", gin2.UpdateOperationLogStatus, UpdateRegistryNamespace) diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go index b1f9aa72d..35eb6beac 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go @@ -494,7 +494,7 @@ func CreateWorkflowTask(args *commonmodels.WorkflowTaskArgs, taskCreator string, // 获取全局configpayload configPayload := commonservice.GetConfigPayload(args.CodehostID) - if len(env.RegistryId) == 0 { + if len(env.RegistryID) == 0 { op := &commonrepo.FindRegOps{ IsDefault: true, } @@ -503,9 +503,9 @@ func CreateWorkflowTask(args *commonmodels.WorkflowTaskArgs, taskCreator string, log.Errorf("get default registry error: %v", err) return nil, e.ErrGetCounter.AddDesc(err.Error()) } - env.RegistryId = reg.ID.Hex() + env.RegistryID = reg.ID.Hex() } - configPayload.RegistryID = env.RegistryId + configPayload.RegistryID = env.RegistryID repos, err := commonrepo.NewRegistryNamespaceColl().FindAll(&commonrepo.FindRegOps{}) if err == nil { configPayload.RepoConfigs = make(map[string]*commonmodels.RegistryNamespace) @@ -1804,11 +1804,11 @@ func ensurePipelineTask(pt *task.Task, envName string, log *zap.SugaredLogger) e // 编译任务使用 t.JobCtx.Image // 注意: 其他任务从 pt.TaskArgs.Deploy.Image 获取, 必须要有编译任务 var reg *commonmodels.RegistryNamespace - if len(exitedProd.RegistryId) > 0 { - reg, err = commonservice.FindRegistryById(exitedProd.RegistryId, log) + if len(exitedProd.RegistryID) > 0 { + reg, err = commonservice.FindRegistryById(exitedProd.RegistryID, log) if err != nil { log.Errorf("service.EnsureRegistrySecret: failed to find registry: %s error msg:%v", - exitedProd.RegistryId, err) + exitedProd.RegistryID, err) return e.ErrFindRegistry.AddDesc(err.Error()) } } else { -- Gitee From d231cb5940e26841925320cb7b4f2193ac7919ff Mon Sep 17 00:00:00 2001 From: huangzexiong Date: Thu, 9 Dec 2021 17:38:06 +0800 Subject: [PATCH 094/134] fix code smell Signed-off-by: huangzexiong --- .../aslan/core/workflow/service/workflow/workflow_task.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go index 01c72c37a..f5bcbe4c1 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go @@ -1174,8 +1174,7 @@ func testArgsToSubtask(args *commonmodels.WorkflowTaskArgs, pt *task.Task, log * for _, service := range args.Target { servicesArray = append(servicesArray, service.ServiceName) } - services = strings.Join(servicesArray,",") - log.Info("获取本次任务执行的服务services:%v", services) + services = strings.Join(servicesArray, ",") } testArgs := args.Tests @@ -1236,7 +1235,6 @@ func testArgsToSubtask(args *commonmodels.WorkflowTaskArgs, pt *task.Task, log * } envs = append(envs, &commonmodels.KeyVal{Key: "TEST_URL", Value: GetLink(pt, configbase.SystemAddress(), config.WorkflowType)}) envs = append(envs, &commonmodels.KeyVal{Key: "SERVICES", Value: services}) - log.Info("test envs:%v", envs) testTask.JobCtx.EnvVars = envs testTask.ImageID = testModule.PreTest.ImageID -- Gitee From 9db9984fbf6655afb0b67c849300231ae95ca940 Mon Sep 17 00:00:00 2001 From: huangzexiong Date: Thu, 9 Dec 2021 18:53:02 +0800 Subject: [PATCH 095/134] test add $SERVICES params Signed-off-by: huangzexiong --- .../core/workflow/service/workflow/workflow_task.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go index f5bcbe4c1..7b36bbfa4 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go @@ -1169,13 +1169,11 @@ func testArgsToSubtask(args *commonmodels.WorkflowTaskArgs, pt *task.Task, log * } } - // 获取本次任务执行的服务,按照逗号分隔,service1,service2... - if len(args.Target) > 0 { - for _, service := range args.Target { - servicesArray = append(servicesArray, service.ServiceName) - } - services = strings.Join(servicesArray, ",") + // services env + for _, service := range args.Target { + servicesArray = append(servicesArray, service.ServiceName) } + services = strings.Join(servicesArray, ",") testArgs := args.Tests testCreator := args.WorkflowTaskCreator -- Gitee From d0898416245d9c0e12f85bbceebec2976eeab68d Mon Sep 17 00:00:00 2001 From: liu deyi Date: Thu, 9 Dec 2021 18:53:29 +0800 Subject: [PATCH 096/134] optimize code Signed-off-by: liu deyi --- .../warpdrive/core/service/taskplugin/artifact_deploy.go | 2 +- .../warpdrive/core/service/taskplugin/build.go | 4 +++- .../warpdrive/core/service/taskplugin/docker_build.go | 2 +- .../warpdrive/core/service/taskplugin/jenkins_plugin.go | 2 +- pkg/microservice/warpdrive/core/service/taskplugin/job.go | 7 +++++-- .../warpdrive/core/service/taskplugin/release_image.go | 2 +- .../warpdrive/core/service/taskplugin/testing.go | 4 +++- 7 files changed, 15 insertions(+), 8 deletions(-) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/artifact_deploy.go b/pkg/microservice/warpdrive/core/service/taskplugin/artifact_deploy.go index 626e235c3..c2c1e9683 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/artifact_deploy.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/artifact_deploy.go @@ -215,7 +215,7 @@ func (p *ArtifactDeployTaskPlugin) Run(ctx context.Context, pipelineTask *task.T } //Resource request default value is LOW - job, err := buildJob(p.Type(), jobImage, p.JobName, serviceName, "", p.Task.ResReq, p.Task.ResReqSpec, pipelineCtx, pipelineTask, p.Task.Registries) + job, err := buildJob(p.Type(), jobImage, p.JobName, serviceName, "", pipelineTask.ConfigPayload.Build.KubeNamespace, p.Task.ResReq, p.Task.ResReqSpec, pipelineCtx, pipelineTask, p.Task.Registries) if err != nil { msg := fmt.Sprintf("create build job context error: %v", err) p.Log.Error(msg) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/build.go b/pkg/microservice/warpdrive/core/service/taskplugin/build.go index 0649e215a..0cee599e1 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/build.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/build.go @@ -120,6 +120,8 @@ func (p *BuildTaskPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipe return } p.kubeClient = kubeClient + // replace docker host + pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, fmt.Sprintf(".%s", pipelineTask.ConfigPayload.Build.KubeNamespace), fmt.Sprintf(".%s", p.Task.Namespace), 1) } if pipelineTask.Type == config.WorkflowType { envName := pipelineTask.WorkflowArgs.Namespace @@ -244,7 +246,7 @@ func (p *BuildTaskPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipe } //Resource request default value is LOW - job, err := buildJob(p.Type(), jobImage, p.JobName, serviceName, p.Task.ClusterID, p.Task.ResReq, p.Task.ResReqSpec, pipelineCtx, pipelineTask, p.Task.Registries) + job, err := buildJob(p.Type(), jobImage, p.JobName, serviceName, p.Task.ClusterID, pipelineTask.ConfigPayload.Build.KubeNamespace, p.Task.ResReq, p.Task.ResReqSpec, pipelineCtx, pipelineTask, p.Task.Registries) if err != nil { msg := fmt.Sprintf("create build job context error: %v", err) p.Log.Error(msg) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/docker_build.go b/pkg/microservice/warpdrive/core/service/taskplugin/docker_build.go index bc358059c..d9abed532 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/docker_build.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/docker_build.go @@ -196,7 +196,7 @@ func (p *DockerBuildPlugin) Run(ctx context.Context, pipelineTask *task.Task, pi return } - job, err := buildJob(p.Type(), pipelineTask.ConfigPayload.Release.PredatorImage, p.JobName, serviceName, "", setting.MinRequest, setting.MinRequestSpec, pipelineCtx, pipelineTask, []*task.RegistryNamespace{}) + job, err := buildJob(p.Type(), pipelineTask.ConfigPayload.Release.PredatorImage, p.JobName, serviceName, "", pipelineTask.ConfigPayload.Build.KubeNamespace, setting.MinRequest, setting.MinRequestSpec, pipelineCtx, pipelineTask, []*task.RegistryNamespace{}) if err != nil { msg := fmt.Sprintf("create build job context error: %v", err) p.Log.Error(msg) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/jenkins_plugin.go b/pkg/microservice/warpdrive/core/service/taskplugin/jenkins_plugin.go index fbf8f15f0..1879bb0a9 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/jenkins_plugin.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/jenkins_plugin.go @@ -157,7 +157,7 @@ func (j *JenkinsBuildPlugin) Run(ctx context.Context, pipelineTask *task.Task, p } j.Log.Infof("succeed to create cm for jenkins build job %s", j.JobName) - job, err := buildJob(j.Type(), pipelineTask.ConfigPayload.JenkinsBuildConfig.JenkinsBuildImage, j.JobName, serviceName, "", setting.MinRequest, setting.MinRequestSpec, pipelineCtx, pipelineTask, []*task.RegistryNamespace{}) + job, err := buildJob(j.Type(), pipelineTask.ConfigPayload.JenkinsBuildConfig.JenkinsBuildImage, j.JobName, serviceName, "", pipelineTask.ConfigPayload.Build.KubeNamespace, setting.MinRequest, setting.MinRequestSpec, pipelineCtx, pipelineTask, []*task.RegistryNamespace{}) if err != nil { msg := fmt.Sprintf("create jenkins build job context error: %v", err) j.Log.Error(msg) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/job.go b/pkg/microservice/warpdrive/core/service/taskplugin/job.go index 318f44547..0b8b6b1c9 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/job.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/job.go @@ -391,13 +391,14 @@ func createJobConfigMap(namespace, jobName string, jobLabel *JobLabel, jobCtx st //"s-job": pipelinename-taskid-tasktype-servicename, //"s-task": pipelinename-taskid, //"s-type": tasktype, -func buildJob(taskType config.TaskType, jobImage, jobName, serviceName, clusterID string, resReq setting.Request, resReqSpec setting.RequestSpec, ctx *task.PipelineCtx, pipelineTask *task.Task, registries []*task.RegistryNamespace) (*batchv1.Job, error) { +func buildJob(taskType config.TaskType, jobImage, jobName, serviceName, clusterID, currentNamespace string, resReq setting.Request, resReqSpec setting.RequestSpec, ctx *task.PipelineCtx, pipelineTask *task.Task, registries []*task.RegistryNamespace) (*batchv1.Job, error) { return buildJobWithLinkedNs( taskType, jobImage, jobName, serviceName, clusterID, + currentNamespace, resReq, resReqSpec, ctx, @@ -408,7 +409,7 @@ func buildJob(taskType config.TaskType, jobImage, jobName, serviceName, clusterI ) } -func buildJobWithLinkedNs(taskType config.TaskType, jobImage, jobName, serviceName, clusterID string, resReq setting.Request, resReqSpec setting.RequestSpec, ctx *task.PipelineCtx, pipelineTask *task.Task, registries []*task.RegistryNamespace, execNs, linkedNs string) (*batchv1.Job, error) { +func buildJobWithLinkedNs(taskType config.TaskType, jobImage, jobName, serviceName, clusterID, currentNamespace string, resReq setting.Request, resReqSpec setting.RequestSpec, ctx *task.PipelineCtx, pipelineTask *task.Task, registries []*task.RegistryNamespace, execNs, linkedNs string) (*batchv1.Job, error) { var ( reaperBootingScript string reaperBinaryFile = pipelineTask.ConfigPayload.Release.ReaperBinaryFile @@ -416,6 +417,8 @@ func buildJobWithLinkedNs(taskType config.TaskType, jobImage, jobName, serviceNa // not local cluster if clusterID != "" && clusterID != setting.LocalClusterID { reaperBinaryFile = strings.Replace(reaperBinaryFile, "resource-server", "resource-server.koderover-agent", -1) + } else { + reaperBinaryFile = strings.Replace(reaperBinaryFile, "resource-server", "resource-server."+currentNamespace, -1) } if !strings.Contains(jobImage, PredatorPlugin) && !strings.Contains(jobImage, JenkinsPlugin) { diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/release_image.go b/pkg/microservice/warpdrive/core/service/taskplugin/release_image.go index 8cb98b582..fd34f27bd 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/release_image.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/release_image.go @@ -176,7 +176,7 @@ func (p *ReleaseImagePlugin) Run(ctx context.Context, pipelineTask *task.Task, p } p.Log.Infof("succeed to create cm for image job %s", p.JobName) - job, err := buildJob(p.Type(), pipelineTask.ConfigPayload.Release.PredatorImage, p.JobName, serviceName, "", setting.MinRequest, setting.MinRequestSpec, pipelineCtx, pipelineTask, []*task.RegistryNamespace{}) + job, err := buildJob(p.Type(), pipelineTask.ConfigPayload.Release.PredatorImage, p.JobName, serviceName, "", pipelineTask.ConfigPayload.Build.KubeNamespace, setting.MinRequest, setting.MinRequestSpec, pipelineCtx, pipelineTask, []*task.RegistryNamespace{}) if err != nil { msg := fmt.Sprintf("create release image job context error: %v", err) p.Log.Error(msg) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go index 8edc85268..17c442512 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go @@ -116,6 +116,8 @@ func (p *TestPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipelineC return } p.kubeClient = kubeClient + // replace docker host + pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, fmt.Sprintf(".%s", pipelineTask.ConfigPayload.Build.KubeNamespace), fmt.Sprintf(".%s", p.Task.Namespace), 1) } // 重置错误信息 p.Task.Error = "" @@ -213,7 +215,7 @@ func (p *TestPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipelineC // search namespace should also include desired namespace job, err := buildJobWithLinkedNs( - p.Type(), jobImage, p.JobName, serviceName, p.Task.ClusterID, p.Task.ResReq, p.Task.ResReqSpec, pipelineCtx, pipelineTask, p.Task.Registries, + p.Type(), jobImage, p.JobName, serviceName, p.Task.ClusterID, pipelineTask.ConfigPayload.Test.KubeNamespace, p.Task.ResReq, p.Task.ResReqSpec, pipelineCtx, pipelineTask, p.Task.Registries, p.KubeNamespace, linkedNamespace, ) -- Gitee From dfc6dd9f11039eced695ae08b309e759833aacc0 Mon Sep 17 00:00:00 2001 From: huangzexiong Date: Thu, 9 Dec 2021 18:55:02 +0800 Subject: [PATCH 097/134] test add $SERVICES params Signed-off-by: huangzexiong --- .../aslan/core/workflow/service/workflow/workflow_task.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go index 7b36bbfa4..8d4df9b28 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go @@ -1169,7 +1169,6 @@ func testArgsToSubtask(args *commonmodels.WorkflowTaskArgs, pt *task.Task, log * } } - // services env for _, service := range args.Target { servicesArray = append(servicesArray, service.ServiceName) } -- Gitee From 13b9b52f64cfe6d7204b93bbd66db0d0d73d0889 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Thu, 9 Dec 2021 19:01:49 +0800 Subject: [PATCH 098/134] debug code Signed-off-by: liu deyi --- pkg/microservice/warpdrive/core/service/taskplugin/build.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/build.go b/pkg/microservice/warpdrive/core/service/taskplugin/build.go index 0cee599e1..2808787d7 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/build.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/build.go @@ -121,6 +121,7 @@ func (p *BuildTaskPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipe } p.kubeClient = kubeClient // replace docker host + p.Log.Infof("pipelineTask.DockerHost:%s", pipelineTask.DockerHost) pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, fmt.Sprintf(".%s", pipelineTask.ConfigPayload.Build.KubeNamespace), fmt.Sprintf(".%s", p.Task.Namespace), 1) } if pipelineTask.Type == config.WorkflowType { -- Gitee From 9f7052b91c879d4c4cf88077b8348325b83aabd0 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Thu, 9 Dec 2021 19:20:12 +0800 Subject: [PATCH 099/134] debug code Signed-off-by: liu deyi --- .../core/service/taskplugin/build.go | 20 ++++++++++++++++--- .../core/service/taskplugin/testing.go | 17 ++++++++++++++-- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/build.go b/pkg/microservice/warpdrive/core/service/taskplugin/build.go index 2808787d7..94e2e9907 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/build.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/build.go @@ -120,10 +120,24 @@ func (p *BuildTaskPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipe return } p.kubeClient = kubeClient - // replace docker host - p.Log.Infof("pipelineTask.DockerHost:%s", pipelineTask.DockerHost) - pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, fmt.Sprintf(".%s", pipelineTask.ConfigPayload.Build.KubeNamespace), fmt.Sprintf(".%s", p.Task.Namespace), 1) } + + // not local cluster + if p.Task.ClusterID != "" && p.Task.ClusterID != setting.LocalClusterID { + if strings.Contains(pipelineTask.DockerHost, pipelineTask.ConfigPayload.Build.KubeNamespace) { + // replace namespace only + pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, fmt.Sprintf(".%s", pipelineTask.ConfigPayload.Build.KubeNamespace), ".koderover-agent", 1) + } else { + // add namespace + pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, ".dind", ".dind.koderover-agent", 1) + } + } else if p.Task.ClusterID == "" || p.Task.ClusterID == setting.LocalClusterID { + if !strings.Contains(pipelineTask.DockerHost, pipelineTask.ConfigPayload.Build.KubeNamespace) { + // add namespace + pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, ".dind", ".dind."+pipelineTask.ConfigPayload.Build.KubeNamespace, 1) + } + } + if pipelineTask.Type == config.WorkflowType { envName := pipelineTask.WorkflowArgs.Namespace envNameVar := &task.KeyVal{Key: "ENV_NAME", Value: envName, IsCredential: false} diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go index 17c442512..c8beb03e1 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go @@ -116,8 +116,21 @@ func (p *TestPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipelineC return } p.kubeClient = kubeClient - // replace docker host - pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, fmt.Sprintf(".%s", pipelineTask.ConfigPayload.Build.KubeNamespace), fmt.Sprintf(".%s", p.Task.Namespace), 1) + } + // not local cluster + if p.Task.ClusterID != "" && p.Task.ClusterID != setting.LocalClusterID { + if strings.Contains(pipelineTask.DockerHost, pipelineTask.ConfigPayload.Test.KubeNamespace) { + // replace namespace only + pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, fmt.Sprintf(".%s", pipelineTask.ConfigPayload.Test.KubeNamespace), ".koderover-agent", 1) + } else { + // add namespace + pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, ".dind", ".dind.koderover-agent", 1) + } + } else if p.Task.ClusterID == "" || p.Task.ClusterID == setting.LocalClusterID { + if !strings.Contains(pipelineTask.DockerHost, pipelineTask.ConfigPayload.Test.KubeNamespace) { + // add namespace + pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, ".dind", ".dind."+pipelineTask.ConfigPayload.Test.KubeNamespace, 1) + } } // 重置错误信息 p.Task.Error = "" -- Gitee From 043ed52a5c8362111e999e1baa110e6c61d465a5 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Thu, 9 Dec 2021 19:32:34 +0800 Subject: [PATCH 100/134] optimize code Signed-off-by: liu deyi --- pkg/microservice/warpdrive/core/service/taskplugin/build.go | 1 + pkg/microservice/warpdrive/core/service/taskplugin/testing.go | 1 + 2 files changed, 2 insertions(+) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/build.go b/pkg/microservice/warpdrive/core/service/taskplugin/build.go index 94e2e9907..2c9d0fedf 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/build.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/build.go @@ -137,6 +137,7 @@ func (p *BuildTaskPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipe pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, ".dind", ".dind."+pipelineTask.ConfigPayload.Build.KubeNamespace, 1) } } + pipelineCtx.DockerHost = pipelineTask.DockerHost if pipelineTask.Type == config.WorkflowType { envName := pipelineTask.WorkflowArgs.Namespace diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go index c8beb03e1..c97e5e52b 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go @@ -132,6 +132,7 @@ func (p *TestPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipelineC pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, ".dind", ".dind."+pipelineTask.ConfigPayload.Test.KubeNamespace, 1) } } + pipelineCtx.DockerHost = pipelineTask.DockerHost // 重置错误信息 p.Task.Error = "" // 获取测试相关的namespace -- Gitee From e18dbe0066c29b798407061f356ebf5fb18c6742 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Thu, 9 Dec 2021 20:29:25 +0800 Subject: [PATCH 101/134] optimize code Signed-off-by: liu deyi --- pkg/microservice/warpdrive/core/service/taskplugin/build.go | 4 ++-- pkg/microservice/warpdrive/core/service/taskplugin/job.go | 6 ++++-- .../warpdrive/core/service/taskplugin/testing.go | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/build.go b/pkg/microservice/warpdrive/core/service/taskplugin/build.go index 2c9d0fedf..f7abcd8ba 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/build.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/build.go @@ -129,12 +129,12 @@ func (p *BuildTaskPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipe pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, fmt.Sprintf(".%s", pipelineTask.ConfigPayload.Build.KubeNamespace), ".koderover-agent", 1) } else { // add namespace - pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, ".dind", ".dind.koderover-agent", 1) + pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, "."+DindServer, ".dind.koderover-agent", 1) } } else if p.Task.ClusterID == "" || p.Task.ClusterID == setting.LocalClusterID { if !strings.Contains(pipelineTask.DockerHost, pipelineTask.ConfigPayload.Build.KubeNamespace) { // add namespace - pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, ".dind", ".dind."+pipelineTask.ConfigPayload.Build.KubeNamespace, 1) + pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, "."+DindServer, ".dind."+pipelineTask.ConfigPayload.Build.KubeNamespace, 1) } } pipelineCtx.DockerHost = pipelineTask.DockerHost diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/job.go b/pkg/microservice/warpdrive/core/service/taskplugin/job.go index 0b8b6b1c9..0eb8310a3 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/job.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/job.go @@ -63,6 +63,8 @@ const ( PreferredSchedule = "preferred" registrySecretSuffix = "-registry-secret" + ResourceServer = "resource-server" + DindServer = "dind" ) func saveFile(src io.Reader, localFile string) error { @@ -416,9 +418,9 @@ func buildJobWithLinkedNs(taskType config.TaskType, jobImage, jobName, serviceNa ) // not local cluster if clusterID != "" && clusterID != setting.LocalClusterID { - reaperBinaryFile = strings.Replace(reaperBinaryFile, "resource-server", "resource-server.koderover-agent", -1) + reaperBinaryFile = strings.Replace(reaperBinaryFile, ResourceServer, ResourceServer+".koderover-agent", -1) } else { - reaperBinaryFile = strings.Replace(reaperBinaryFile, "resource-server", "resource-server."+currentNamespace, -1) + reaperBinaryFile = strings.Replace(reaperBinaryFile, ResourceServer, ResourceServer+"."+currentNamespace, -1) } if !strings.Contains(jobImage, PredatorPlugin) && !strings.Contains(jobImage, JenkinsPlugin) { diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go index c97e5e52b..baea2f747 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go @@ -124,12 +124,12 @@ func (p *TestPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipelineC pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, fmt.Sprintf(".%s", pipelineTask.ConfigPayload.Test.KubeNamespace), ".koderover-agent", 1) } else { // add namespace - pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, ".dind", ".dind.koderover-agent", 1) + pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, "."+DindServer, ".dind.koderover-agent", 1) } } else if p.Task.ClusterID == "" || p.Task.ClusterID == setting.LocalClusterID { if !strings.Contains(pipelineTask.DockerHost, pipelineTask.ConfigPayload.Test.KubeNamespace) { // add namespace - pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, ".dind", ".dind."+pipelineTask.ConfigPayload.Test.KubeNamespace, 1) + pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, "."+DindServer, ".dind."+pipelineTask.ConfigPayload.Test.KubeNamespace, 1) } } pipelineCtx.DockerHost = pipelineTask.DockerHost -- Gitee From b5b3be97c4f29e5a37157bb5a336033459938e97 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Thu, 9 Dec 2021 20:59:08 +0800 Subject: [PATCH 102/134] optimize code Signed-off-by: liu deyi --- .../warpdrive/core/service/taskplugin/build.go | 6 +++--- pkg/microservice/warpdrive/core/service/taskplugin/job.go | 7 ++++--- .../warpdrive/core/service/taskplugin/testing.go | 6 +++--- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/build.go b/pkg/microservice/warpdrive/core/service/taskplugin/build.go index f7abcd8ba..002f3acfc 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/build.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/build.go @@ -126,15 +126,15 @@ func (p *BuildTaskPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipe if p.Task.ClusterID != "" && p.Task.ClusterID != setting.LocalClusterID { if strings.Contains(pipelineTask.DockerHost, pipelineTask.ConfigPayload.Build.KubeNamespace) { // replace namespace only - pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, fmt.Sprintf(".%s", pipelineTask.ConfigPayload.Build.KubeNamespace), ".koderover-agent", 1) + pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, pipelineTask.ConfigPayload.Build.KubeNamespace, KoderoverAgentNamespace, 1) } else { // add namespace - pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, "."+DindServer, ".dind.koderover-agent", 1) + pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, DindServer, DindServer+"."+KoderoverAgentNamespace, 1) } } else if p.Task.ClusterID == "" || p.Task.ClusterID == setting.LocalClusterID { if !strings.Contains(pipelineTask.DockerHost, pipelineTask.ConfigPayload.Build.KubeNamespace) { // add namespace - pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, "."+DindServer, ".dind."+pipelineTask.ConfigPayload.Build.KubeNamespace, 1) + pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, DindServer, DindServer+"."+pipelineTask.ConfigPayload.Build.KubeNamespace, 1) } } pipelineCtx.DockerHost = pipelineTask.DockerHost diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/job.go b/pkg/microservice/warpdrive/core/service/taskplugin/job.go index 0eb8310a3..1d889e59f 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/job.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/job.go @@ -62,9 +62,10 @@ const ( RequiredSchedule = "required" PreferredSchedule = "preferred" - registrySecretSuffix = "-registry-secret" - ResourceServer = "resource-server" - DindServer = "dind" + registrySecretSuffix = "-registry-secret" + ResourceServer = "resource-server" + DindServer = "dind" + KoderoverAgentNamespace = "koderover-agent" ) func saveFile(src io.Reader, localFile string) error { diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go index baea2f747..fa3008e43 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go @@ -121,15 +121,15 @@ func (p *TestPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipelineC if p.Task.ClusterID != "" && p.Task.ClusterID != setting.LocalClusterID { if strings.Contains(pipelineTask.DockerHost, pipelineTask.ConfigPayload.Test.KubeNamespace) { // replace namespace only - pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, fmt.Sprintf(".%s", pipelineTask.ConfigPayload.Test.KubeNamespace), ".koderover-agent", 1) + pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, pipelineTask.ConfigPayload.Test.KubeNamespace, KoderoverAgentNamespace, 1) } else { // add namespace - pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, "."+DindServer, ".dind.koderover-agent", 1) + pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, DindServer, DindServer+"."+KoderoverAgentNamespace, 1) } } else if p.Task.ClusterID == "" || p.Task.ClusterID == setting.LocalClusterID { if !strings.Contains(pipelineTask.DockerHost, pipelineTask.ConfigPayload.Test.KubeNamespace) { // add namespace - pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, "."+DindServer, ".dind."+pipelineTask.ConfigPayload.Test.KubeNamespace, 1) + pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, DindServer, DindServer+"."+pipelineTask.ConfigPayload.Test.KubeNamespace, 1) } } pipelineCtx.DockerHost = pipelineTask.DockerHost -- Gitee From ad3fd6b7d0b02e61d5838d157220ffe771b9d2a7 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Thu, 9 Dec 2021 21:15:41 +0800 Subject: [PATCH 103/134] optimize code Signed-off-by: liu deyi --- .../warpdrive/core/service/taskplugin/build.go | 5 +++-- .../warpdrive/core/service/taskplugin/testing.go | 11 ++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/build.go b/pkg/microservice/warpdrive/core/service/taskplugin/build.go index 002f3acfc..10ee14631 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/build.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/build.go @@ -123,18 +123,19 @@ func (p *BuildTaskPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipe } // not local cluster + replaceDindServer := "." + DindServer if p.Task.ClusterID != "" && p.Task.ClusterID != setting.LocalClusterID { if strings.Contains(pipelineTask.DockerHost, pipelineTask.ConfigPayload.Build.KubeNamespace) { // replace namespace only pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, pipelineTask.ConfigPayload.Build.KubeNamespace, KoderoverAgentNamespace, 1) } else { // add namespace - pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, DindServer, DindServer+"."+KoderoverAgentNamespace, 1) + pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, replaceDindServer, replaceDindServer+"."+KoderoverAgentNamespace, 1) } } else if p.Task.ClusterID == "" || p.Task.ClusterID == setting.LocalClusterID { if !strings.Contains(pipelineTask.DockerHost, pipelineTask.ConfigPayload.Build.KubeNamespace) { // add namespace - pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, DindServer, DindServer+"."+pipelineTask.ConfigPayload.Build.KubeNamespace, 1) + pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, replaceDindServer, replaceDindServer+"."+pipelineTask.ConfigPayload.Build.KubeNamespace, 1) } } pipelineCtx.DockerHost = pipelineTask.DockerHost diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go index fa3008e43..3a935cb90 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/testing.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/testing.go @@ -118,18 +118,19 @@ func (p *TestPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipelineC p.kubeClient = kubeClient } // not local cluster + replaceDindServer := "." + DindServer if p.Task.ClusterID != "" && p.Task.ClusterID != setting.LocalClusterID { - if strings.Contains(pipelineTask.DockerHost, pipelineTask.ConfigPayload.Test.KubeNamespace) { + if strings.Contains(pipelineTask.DockerHost, pipelineTask.ConfigPayload.Build.KubeNamespace) { // replace namespace only - pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, pipelineTask.ConfigPayload.Test.KubeNamespace, KoderoverAgentNamespace, 1) + pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, pipelineTask.ConfigPayload.Build.KubeNamespace, KoderoverAgentNamespace, 1) } else { // add namespace - pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, DindServer, DindServer+"."+KoderoverAgentNamespace, 1) + pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, replaceDindServer, replaceDindServer+"."+KoderoverAgentNamespace, 1) } } else if p.Task.ClusterID == "" || p.Task.ClusterID == setting.LocalClusterID { - if !strings.Contains(pipelineTask.DockerHost, pipelineTask.ConfigPayload.Test.KubeNamespace) { + if !strings.Contains(pipelineTask.DockerHost, pipelineTask.ConfigPayload.Build.KubeNamespace) { // add namespace - pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, DindServer, DindServer+"."+pipelineTask.ConfigPayload.Test.KubeNamespace, 1) + pipelineTask.DockerHost = strings.Replace(pipelineTask.DockerHost, replaceDindServer, replaceDindServer+"."+pipelineTask.ConfigPayload.Build.KubeNamespace, 1) } } pipelineCtx.DockerHost = pipelineTask.DockerHost -- Gitee From d08e90520a5f2af84a36ae53b6d804576668a75b Mon Sep 17 00:00:00 2001 From: allenshen Date: Thu, 9 Dec 2021 21:19:31 +0800 Subject: [PATCH 104/134] fix comments Signed-off-by: allenshen --- cmd/packager/main.go | 2 +- docker/service/packager-plugin.Dockerfile | 8 +- .../core/common/repository/models/queue.go | 103 ++++---- .../common/repository/models/task/model.go | 33 ++- .../packager/core/service/docker.go | 72 ------ .../packager/core/service/packager.go | 22 +- .../packager/core/service/service.go | 230 +++++++++--------- .../packager/executor/executor.go | 9 +- .../service/taskplugin/artifact_package.go | 31 ++- .../warpdrive/core/service/types/reaper.go | 9 +- .../core/service/types/task/model.go | 11 +- 11 files changed, 232 insertions(+), 298 deletions(-) delete mode 100644 pkg/microservice/packager/core/service/docker.go diff --git a/cmd/packager/main.go b/cmd/packager/main.go index ba2938d98..bd2fa8bc1 100644 --- a/cmd/packager/main.go +++ b/cmd/packager/main.go @@ -24,6 +24,6 @@ import ( func main() { if err := executor.Execute(); err != nil { - log.Fatalf("Failed to run predator, the error is: %+v", err) + log.Fatalf("Failed to run packager, the error is: %+v", err) } } diff --git a/docker/service/packager-plugin.Dockerfile b/docker/service/packager-plugin.Dockerfile index d7074f6aa..2ae89592a 100644 --- a/docker/service/packager-plugin.Dockerfile +++ b/docker/service/packager-plugin.Dockerfile @@ -2,10 +2,12 @@ RUN go build -v -o /packager-plugin ./cmd/packager/main.go -#ubuntu-xenial.Dockerfile +#alpine.Dockerfile -# 安装 docker client -RUN curl -fsSL "http://resources.koderover.com/docker-cli-v19.03.2.tar.gz" -o docker.tgz &&\ +RUN apk --no-cache add curl +# install docker client +RUN apk --no-cache add curl && \ + curl -fsSL "http://resources.koderover.com/docker-cli-v19.03.2.tar.gz" -o docker.tgz &&\ tar -xvzf docker.tgz &&\ mv docker/* /usr/local/bin &&\ rm -rf docke* diff --git a/pkg/microservice/aslan/core/common/repository/models/queue.go b/pkg/microservice/aslan/core/common/repository/models/queue.go index bda3be278..a122e6fa5 100644 --- a/pkg/microservice/aslan/core/common/repository/models/queue.go +++ b/pkg/microservice/aslan/core/common/repository/models/queue.go @@ -25,65 +25,50 @@ import ( ) type Queue struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - TaskID int64 `bson:"task_id" json:"task_id"` - ProductName string `bson:"product_name" json:"product_name"` - PipelineName string `bson:"pipeline_name" json:"pipeline_name"` - Namespace string `bson:"namespace,omitempty" json:"namespace,omitempty"` - Type config.PipelineType `bson:"type" json:"type"` - Status config.Status `bson:"status" json:"status,omitempty"` - Description string `bson:"description,omitempty" json:"description,omitempty"` - TaskCreator string `bson:"task_creator" json:"task_creator,omitempty"` - TaskRevoker string `bson:"task_revoker,omitempty" json:"task_revoker,omitempty"` - CreateTime int64 `bson:"create_time" json:"create_time,omitempty"` - StartTime int64 `bson:"start_time" json:"start_time,omitempty"` - EndTime int64 `bson:"end_time" json:"end_time,omitempty"` - SubTasks []map[string]interface{} `bson:"sub_tasks" json:"sub_tasks"` - Stages []*Stage `bson:"stages" json:"stages"` - ReqID string `bson:"req_id,omitempty" json:"req_id,omitempty"` - AgentHost string `bson:"agent_host,omitempty" json:"agent_host,omitempty"` - DockerHost string `bson:"-" json:"docker_host,omitempty"` - TeamID int `bson:"team_id,omitempty" json:"team_id,omitempty"` - TeamName string `bson:"team,omitempty" json:"team,omitempty"` - IsDeleted bool `bson:"is_deleted" json:"is_deleted"` - IsArchived bool `bson:"is_archived" json:"is_archived"` - AgentID string `bson:"agent_id" json:"agent_id"` - // 是否允许同时运行多次 - MultiRun bool `bson:"multi_run" json:"multi_run"` - // target 服务名称, k8s为容器名称, 物理机为服务名 - Target string `bson:"target,omitempty" json:"target"` - // 使用预定义编译管理模块中的内容生成SubTasks, - // 查询条件为 服务模板名称: ServiceTmpl, 版本: BuildModuleVer - // 如果为空,则使用pipeline自定义SubTasks - BuildModuleVer string `bson:"build_module_ver,omitempty" json:"build_module_ver"` - ServiceName string `bson:"service_name,omitempty" json:"service_name,omitempty"` - // TaskArgs 单服务工作流任务参数 - TaskArgs *TaskArgs `bson:"task_args,omitempty" json:"task_args,omitempty"` - // WorkflowArgs 多服务工作流任务参数 - WorkflowArgs *WorkflowTaskArgs `bson:"workflow_args" json:"workflow_args,omitempty"` - // TestArgs 测试任务参数 - TestArgs *TestTaskArgs `bson:"test_args,omitempty" json:"test_args,omitempty"` - // ServiceTaskArgs 脚本部署工作流任务参数 - ServiceTaskArgs *ServiceTaskArgs `bson:"service_args,omitempty" json:"service_args,omitempty"` - // ArtifactPackageTaskArgs arguments for artifact-package type tasks - ArtifactPackageTaskArgs *ArtifactPackageTaskArgs `bson:"artifact_package_args,omitempty" json:"artifact_package_args,omitempty"` - ConfigPayload *ConfigPayload `json:"config_payload,omitempty"` - Error string `bson:"error,omitempty" json:"error,omitempty"` - Services [][]*ProductService `bson:"services" json:"services"` - Render *RenderInfo `bson:"render" json:"render"` - StorageURI string `bson:"storage_uri,omitempty" json:"storage_uri,omitempty"` - // interface{} 为types.TestReport - TestReports map[string]interface{} `bson:"test_reports,omitempty" json:"test_reports,omitempty"` - - RwLock sync.Mutex `bson:"-" json:"-"` - - ResetImage bool `json:"resetImage" bson:"resetImage"` - - TriggerBy *TriggerBy `json:"trigger_by,omitempty" bson:"trigger_by,omitempty"` - - Features []string `bson:"features" json:"features"` - IsRestart bool `bson:"is_restart" json:"is_restart"` - StorageEndpoint string `bson:"storage_endpoint" json:"storage_endpoint"` + ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + TaskID int64 `bson:"task_id" json:"task_id"` + ProductName string `bson:"product_name" json:"product_name"` + PipelineName string `bson:"pipeline_name" json:"pipeline_name"` + Namespace string `bson:"namespace,omitempty" json:"namespace,omitempty"` + Type config.PipelineType `bson:"type" json:"type"` + Status config.Status `bson:"status" json:"status,omitempty"` + Description string `bson:"description,omitempty" json:"description,omitempty"` + TaskCreator string `bson:"task_creator" json:"task_creator,omitempty"` + TaskRevoker string `bson:"task_revoker,omitempty" json:"task_revoker,omitempty"` + CreateTime int64 `bson:"create_time" json:"create_time,omitempty"` + StartTime int64 `bson:"start_time" json:"start_time,omitempty"` + EndTime int64 `bson:"end_time" json:"end_time,omitempty"` + SubTasks []map[string]interface{} `bson:"sub_tasks" json:"sub_tasks"` + Stages []*Stage `bson:"stages" json:"stages"` + ReqID string `bson:"req_id,omitempty" json:"req_id,omitempty"` + AgentHost string `bson:"agent_host,omitempty" json:"agent_host,omitempty"` + DockerHost string `bson:"-" json:"docker_host,omitempty"` + TeamID int `bson:"team_id,omitempty" json:"team_id,omitempty"` + TeamName string `bson:"team,omitempty" json:"team,omitempty"` + IsDeleted bool `bson:"is_deleted" json:"is_deleted"` + IsArchived bool `bson:"is_archived" json:"is_archived"` + AgentID string `bson:"agent_id" json:"agent_id"` + MultiRun bool `bson:"multi_run" json:"multi_run"` + Target string `bson:"target,omitempty" json:"target"` // target 服务名称, k8s为容器名称, 物理机为服务名 + BuildModuleVer string `bson:"build_module_ver,omitempty" json:"build_module_ver"` // 使用预定义编译管理模块中的内容生成SubTasks, 查询条件为 服务模板名称: ServiceTmpl, 版本: BuildModuleVer 如果为空,则使用pipeline自定义SubTasks + ServiceName string `bson:"service_name,omitempty" json:"service_name,omitempty"` + TaskArgs *TaskArgs `bson:"task_args,omitempty" json:"task_args,omitempty"` // TaskArgs 单服务工作流任务参数 + WorkflowArgs *WorkflowTaskArgs `bson:"workflow_args" json:"workflow_args,omitempty"` // WorkflowArgs 多服务工作流任务参数 + TestArgs *TestTaskArgs `bson:"test_args,omitempty" json:"test_args,omitempty"` // TestArgs 测试任务参数 + ServiceTaskArgs *ServiceTaskArgs `bson:"service_args,omitempty" json:"service_args,omitempty"` // ServiceTaskArgs 脚本部署工作流任务参数 + ArtifactPackageTaskArgs *ArtifactPackageTaskArgs `bson:"artifact_package_args,omitempty" json:"artifact_package_args,omitempty"` + ConfigPayload *ConfigPayload `bson:"configpayload,omitempty" json:"config_payload"` + Error string `bson:"error,omitempty" json:"error,omitempty"` + Services [][]*ProductService `bson:"services" json:"services"` + Render *RenderInfo `bson:"render" json:"render"` + StorageURI string `bson:"storage_uri,omitempty" json:"storage_uri,omitempty"` + TestReports map[string]interface{} `bson:"test_reports,omitempty" json:"test_reports,omitempty"` + RwLock sync.Mutex `bson:"-" json:"-"` + ResetImage bool `bson:"resetImage" json:"resetImage"` + TriggerBy *TriggerBy `bson:"trigger_by,omitempty" json:"trigger_by,omitempty"` + Features []string `bson:"features" json:"features"` + IsRestart bool `bson:"is_restart" json:"is_restart"` + StorageEndpoint string `bson:"storage_endpoint" json:"storage_endpoint"` } type TriggerBy struct { diff --git a/pkg/microservice/aslan/core/common/repository/models/task/model.go b/pkg/microservice/aslan/core/common/repository/models/task/model.go index 746534f3e..d1d23f200 100644 --- a/pkg/microservice/aslan/core/common/repository/models/task/model.go +++ b/pkg/microservice/aslan/core/common/repository/models/task/model.go @@ -28,7 +28,7 @@ import ( ) type Task struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` TaskID int64 `bson:"task_id" json:"task_id"` ProductName string `bson:"product_name" json:"product_name"` PipelineName string `bson:"pipeline_name" json:"pipeline_name"` @@ -48,7 +48,7 @@ type Task struct { TeamName string `bson:"team,omitempty" json:"team,omitempty"` IsDeleted bool `bson:"is_deleted" json:"is_deleted"` IsArchived bool `bson:"is_archived" json:"is_archived"` - AgentID string `bson:"agent_id" json:"agent_id"` + AgentID string `bson:"agent_id" json:"agent_id"` // 是否允许同时运行多次 MultiRun bool `bson:"multi_run" json:"multi_run"` // target 服务名称, k8s为容器名称, 物理机为服务名 @@ -57,8 +57,7 @@ type Task struct { // 查询条件为 服务模板名称: ServiceTmpl, 版本: BuildModuleVer // 如果为空,则使用pipeline自定义SubTasks BuildModuleVer string `bson:"build_module_ver,omitempty" json:"build_module_ver"` - - ServiceName string `bson:"service_name,omitempty" json:"service_name,omitempty"` + ServiceName string `bson:"service_name,omitempty" json:"service_name,omitempty"` // TaskArgs 单服务工作流任务参数 TaskArgs *models.TaskArgs `bson:"task_args,omitempty" json:"task_args,omitempty"` // WorkflowArgs 多服务工作流任务参数 @@ -70,23 +69,19 @@ type Task struct { // ArtifactPackageTaskArgs arguments for artifact-package type tasks ArtifactPackageTaskArgs *models.ArtifactPackageTaskArgs `bson:"artifact_package_args,omitempty" json:"artifact_package_args,omitempty"` // ConfigPayload 系统配置信息 - ConfigPayload *models.ConfigPayload `json:"config_payload,omitempty"` + ConfigPayload *models.ConfigPayload `bson:"configpayload" json:"config_payload,omitempty"` Error string `bson:"error,omitempty" json:"error,omitempty"` - Services [][]*models.ProductService `bson:"services" json:"services"` - Render *models.RenderInfo `bson:"render" json:"render"` - StorageURI string `bson:"storage_uri,omitempty" json:"storage_uri,omitempty"` + Services [][]*models.ProductService `bson:"services" json:"services"` + Render *models.RenderInfo `bson:"render" json:"render"` + StorageURI string `bson:"storage_uri,omitempty" json:"storage_uri,omitempty"` // interface{} 为types.TestReport - TestReports map[string]interface{} `bson:"test_reports,omitempty" json:"test_reports,omitempty"` - - RwLock sync.Mutex `bson:"-" json:"-"` - - ResetImage bool `json:"resetImage" bson:"resetImage"` - - TriggerBy *models.TriggerBy `json:"trigger_by,omitempty" bson:"trigger_by,omitempty"` - - Features []string `bson:"features" json:"features"` - IsRestart bool `bson:"is_restart" json:"is_restart"` - StorageEndpoint string `bson:"storage_endpoint" json:"storage_endpoint"` + TestReports map[string]interface{} `bson:"test_reports,omitempty" json:"test_reports,omitempty"` + RwLock sync.Mutex `bson:"-" json:"-"` + ResetImage bool `json:"resetImage" bson:"resetImage"` + TriggerBy *models.TriggerBy `json:"trigger_by,omitempty" bson:"trigger_by,omitempty"` + Features []string `bson:"features" json:"features"` + IsRestart bool `bson:"is_restart" json:"is_restart"` + StorageEndpoint string `bson:"storage_endpoint" json:"storage_endpoint"` } //type RenderInfo struct { diff --git a/pkg/microservice/packager/core/service/docker.go b/pkg/microservice/packager/core/service/docker.go deleted file mode 100644 index 8cb0bce06..000000000 --- a/pkg/microservice/packager/core/service/docker.go +++ /dev/null @@ -1,72 +0,0 @@ -/* -Copyright 2021 The KodeRover Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package service - -import ( - "os/exec" - "strings" -) - -const dockerExe = "/usr/local/bin/docker" - -func dockerVersion() *exec.Cmd { - return exec.Command(dockerExe, "version") -} - -func dockerInfo() *exec.Cmd { - return exec.Command(dockerExe, "info") -} - -// Docker returns build command -// -// e.g. docker build --rm=true -t name:tag -f Dockerfile --build-arg APP_BIN=... . -func dockerBuild(dockerfile, fullImage, buildArgs string) *exec.Cmd { - - args := []string{"build", "--rm=true"} - if buildArgs != "" { - for _, val := range strings.Fields(buildArgs) { - if val != "" { - args = append(args, val) - } - } - - } - args = append(args, []string{"-t", fullImage, "-f", dockerfile, "."}...) - return exec.Command(dockerExe, args...) -} - -func dockerPull(image string) *exec.Cmd { - args := []string{"pull", image} - return exec.Command(dockerExe, args...) -} - -func dockerTag(sourceFullImage, targetFullImage string) *exec.Cmd { - args := []string{ - "tag", - sourceFullImage, - targetFullImage, - } - return exec.Command(dockerExe, args...) -} - -func dockerPush(fullImage string) *exec.Cmd { - args := []string{ - "push", - fullImage, - } - return exec.Command(dockerExe, args...) -} diff --git a/pkg/microservice/packager/core/service/packager.go b/pkg/microservice/packager/core/service/packager.go index 771d2f201..d58b587bc 100644 --- a/pkg/microservice/packager/core/service/packager.go +++ b/pkg/microservice/packager/core/service/packager.go @@ -17,26 +17,28 @@ limitations under the License. package service type ImageData struct { - ImageUrl string `bson:"image_url" json:"image_url"` - ImageName string `bson:"image_name" json:"image_name"` - ImageTag string `bson:"image_tag" json:"image_tag"` + ImageUrl string `yaml:"image_url"` + ImageName string `yaml:"image_name"` + ImageTag string `yaml:"image_tag"` + RegistryID string `yaml:"registry_id,omitempty"` } // ImagesByService defines all images in a service type ImagesByService struct { - ServiceName string `bson:"service_name" json:"service_name"` - Images []*ImageData `bson:"images" json:"images"` + ServiceName string `yaml:"service_name"` + Images []*ImageData `yaml:"images"` } //DockerRegistry registry host/user/password type DockerRegistry struct { - Host string `yaml:"host"` - UserName string `yaml:"username"` - Password string `yaml:"password"` - Namespace string `yaml:"namespace"` + RegistryID string `yaml:"registry_id"` + Host string `yaml:"host"` + UserName string `yaml:"username"` + Password string `yaml:"password"` + Namespace string `yaml:"namespace"` } -// Context ... +// Context parameters for job to run with type Context struct { JobType string `yaml:"job_type"` ProgressFile string `yaml:"progress_file"` diff --git a/pkg/microservice/packager/core/service/service.go b/pkg/microservice/packager/core/service/service.go index c35301fd1..192196021 100644 --- a/pkg/microservice/packager/core/service/service.go +++ b/pkg/microservice/packager/core/service/service.go @@ -17,26 +17,25 @@ limitations under the License. package service import ( + "bytes" + "context" "encoding/base64" "encoding/json" "fmt" - "io/ioutil" "os" - "os/exec" - "path" "path/filepath" "strings" "time" + "github.com/docker/docker/api/types" + "github.com/docker/docker/client" "github.com/pkg/errors" "gopkg.in/yaml.v3" "github.com/koderover/zadig/pkg/microservice/packager/config" - "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/tool/log" ) -// Packager ... type Packager struct { Ctx *Context } @@ -49,7 +48,7 @@ type PackageResult struct { } func NewPackager() (*Packager, error) { - context, err := ioutil.ReadFile(config.JobConfigFile()) + context, err := os.ReadFile(config.JobConfigFile()) if err != nil { return nil, err } @@ -66,71 +65,144 @@ func NewPackager() (*Packager, error) { return packager, nil } -// BeforeExec ... -func (p *Packager) BeforeExec() error { - log.Info("wait for docker daemon to start") - for i := 0; i < 120; i++ { - err := dockerInfo().Run() - if err == nil { - break - } - time.Sleep(time.Second * 1) +func buildRegistryMap(registries []*DockerRegistry) map[string]*DockerRegistry { + ret := make(map[string]*DockerRegistry) + for _, registry := range registries { + ret[registry.RegistryID] = registry } + return ret +} - if len(p.Ctx.ProgressFile) == 0 { - return nil +func base64EncodeAuth(auth *types.AuthConfig) (string, error) { + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(auth); err != nil { + return "", err } + return base64.URLEncoding.EncodeToString(buf.Bytes()), nil +} - // create log file - if err := os.MkdirAll(filepath.Dir(p.Ctx.ProgressFile), 0770); err != nil { - return errors.Wrapf(err, "failed to create progress file dir") +func buildTargetImage(imageName, imageTag, host, nameSpace string) string { + ret := "" + if len(nameSpace) > 0 { + ret = fmt.Sprintf("%s/%s/%s:%s", host, nameSpace, imageName, imageTag) + } else { + ret = fmt.Sprintf("%s/%s:%s", host, imageName, imageTag) } - file, err := os.Create(p.Ctx.ProgressFile) - if err != nil { - return errors.Wrapf(err, "failed to create progress file") + ret = strings.TrimPrefix(ret, "http://") + ret = strings.TrimPrefix(ret, "https://") + return ret +} + +func handleSingleService(imageByService *ImagesByService, allRegistries map[string]*DockerRegistry, targetRegistries []*DockerRegistry, dockerClient *client.Client) error { + targetImageUrlByRepo := make(map[string][]string) + for _, singleImage := range imageByService.Images { + options := types.ImagePullOptions{} + // for images from public repo,registryID won't be appointed + if len(singleImage.RegistryID) > 0 { + registryInfo, ok := allRegistries[singleImage.RegistryID] + if !ok { + return fmt.Errorf("failed to find source registry for image: %s", singleImage.ImageUrl) + } + encodedAuth, err := base64EncodeAuth(&types.AuthConfig{ + Username: registryInfo.UserName, + Password: registryInfo.Password, + ServerAddress: registryInfo.Host, + }) + if err != nil { + return errors.Wrapf(err, "faied to create docker pull auth data") + } + options.RegistryAuth = encodedAuth + } + + // pull image + _, err := dockerClient.ImagePull(context.TODO(), singleImage.ImageUrl, options) + if err != nil { + return errors.Wrapf(err, "failed to pull image: %s", singleImage.ImageUrl) + } + + // tag image + for _, registry := range targetRegistries { + targetImage := buildTargetImage(singleImage.ImageName, singleImage.ImageTag, registry.Host, registry.Namespace) + err = dockerClient.ImageTag(context.TODO(), singleImage.ImageUrl, targetImage) + if err != nil { + return errors.Wrapf(err, "failed to tag image from: %s to: %s", singleImage.ImageUrl, targetImage) + } + targetImageUrlByRepo[registry.RegistryID] = append(targetImageUrlByRepo[registry.RegistryID], targetImage) + } + } + + // push image + for _, registry := range targetRegistries { + encodedAuth, err := base64EncodeAuth(&types.AuthConfig{ + Username: registry.UserName, + Password: registry.Password, + ServerAddress: registry.Host, + }) + if err != nil { + return errors.Wrapf(err, "faied to create docker push auth data") + } + options := types.ImagePushOptions{ + RegistryAuth: encodedAuth, + } + for _, targetImageUrl := range targetImageUrlByRepo[registry.RegistryID] { + _, err = dockerClient.ImagePush(context.TODO(), targetImageUrl, options) + if err != nil { + return errors.Wrapf(err, "failed to push image: %s", targetImageUrl) + } + } } - err = file.Close() - return errors.Wrapf(err, "failed to close progress file") + return nil } -// Exec ... func (p *Packager) Exec() error { - // add docker registry auths for all registries - allRegistries := make([]*DockerRegistry, 0) - allRegistries = append(allRegistries, p.Ctx.SourceRegistries...) - allRegistries = append(allRegistries, p.Ctx.TargetRegistries...) - err := writeDockerConfig(allRegistries) + // init docker client + cli, err := client.NewClientWithOpts(client.FromEnv) if err != nil { - return err + log.Errorf("failed to init docker client %s", err) } - realTimeProgress := make([]*PackageResult, 0) + // run docker info to ensure docker daemon connection + for i := 0; i < 120; i++ { + _, err := cli.Info(context.TODO()) + if err == nil { + break + } + log.Errorf("failed tor run docker info, try index: %d, err: %s", i, err) + time.Sleep(time.Second * 1) + } - for _, image := range p.Ctx.Images { - cmds := p.dockerCommands(image) - var err error - for _, cmd := range cmds { - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - log.Info(strings.Join(cmd.Args, " ")) - if err = cmd.Run(); err != nil { - break - } + // create log file + if len(p.Ctx.ProgressFile) >= 0 { + if err := os.MkdirAll(filepath.Dir(p.Ctx.ProgressFile), 0770); err != nil { + return errors.Wrapf(err, "failed to create progress file dir") } + file, err := os.Create(p.Ctx.ProgressFile) + if err != nil { + return errors.Wrapf(err, "failed to create progress file") + } + if err = file.Close(); err != nil { + return errors.Wrapf(err, "failed to close progress file") + } + } + + allRegistries := append(p.Ctx.SourceRegistries, p.Ctx.TargetRegistries...) + realTimeProgress := make([]*PackageResult, 0) + for _, imageByService := range p.Ctx.Images { result := &PackageResult{ - ServiceName: image.ServiceName, + ServiceName: imageByService.ServiceName, } + err = handleSingleService(imageByService, buildRegistryMap(allRegistries), p.Ctx.TargetRegistries, cli) if err != nil { result.Result = "failed" result.ErrorMsg = err.Error() - log.Infof("[result][fail][%s][%s]", image.ServiceName, err) + log.Errorf("[result][fail][%s][%s]", imageByService.ServiceName, err) } else { result.Result = "success" - result.ImageData = image.Images - log.Infof("[result][success][%s]", image.ServiceName) + result.ImageData = imageByService.Images + log.Infof("[result][success][%s]", imageByService.ServiceName) } realTimeProgress = append(realTimeProgress, result) @@ -149,68 +221,8 @@ func (p *Packager) Exec() error { } } + // keep job alive for extra 10 seconds to make the runner be able to catch all progress info + // TODO need optimize time.Sleep(time.Second * 10) return nil } - -func writeDockerConfig(registries []*DockerRegistry) error { - - authMap := make(map[string]map[string]string) - //host string, username string, password string - for _, registry := range registries { - if registry.UserName == "" { - continue - } - authMap[registry.Host] = map[string]string{ - "auth": base64.StdEncoding.EncodeToString( - []byte(strings.Join([]string{registry.UserName, registry.Password}, ":")), - )} - } - - dir := path.Join(config.Home(), ".docker") - if err := os.MkdirAll(dir, 0600); err != nil { - return err - } - - cfg := map[string]map[string]map[string]string{ - "auths": authMap, - } - - data, err := json.Marshal(cfg) - - if err != nil { - return err - } - - return ioutil.WriteFile(path.Join(dir, "config.json"), data, 0600) -} - -func (p *Packager) dockerCommands(imageByService *ImagesByService) []*exec.Cmd { - cmds := make([]*exec.Cmd, 0) - //cmds = append(cmds, dockerVersion()) - - buildTargetImage := func(imageName, imageTag, host, nameSpace string) string { - ret := "" - if len(nameSpace) > 0 { - ret = fmt.Sprintf("%s/%s/%s:%s", host, nameSpace, imageName, imageTag) - } else { - ret = fmt.Sprintf("%s/%s:%s", host, imageName, imageTag) - } - ret = strings.TrimPrefix(ret, "http://") - ret = strings.TrimPrefix(ret, "https://") - return ret - } - - if p.Ctx.JobType == setting.BuildChartPackage { - for _, image := range imageByService.Images { - for _, registry := range p.Ctx.TargetRegistries { - cmds = append(cmds, dockerPull(image.ImageUrl)) - targetImage := buildTargetImage(image.ImageName, image.ImageTag, registry.Host, registry.Namespace) - cmds = append(cmds, dockerTag(image.ImageUrl, targetImage)) - cmds = append(cmds, dockerPush(targetImage)) - } - } - } - - return cmds -} diff --git a/pkg/microservice/packager/executor/executor.go b/pkg/microservice/packager/executor/executor.go index 13f757877..f4d1c0aa2 100644 --- a/pkg/microservice/packager/executor/executor.go +++ b/pkg/microservice/packager/executor/executor.go @@ -31,18 +31,13 @@ func Execute() error { Development: commonconfig.Mode() != setting.ReleaseMode, }) - pred, err := service.NewPackager() + packager, err := service.NewPackager() if err != nil { log.Errorf("Failed to start packager, error: %s", err) return err } - if err := pred.BeforeExec(); err != nil { - log.Errorf("Failed to run before exec step, error: %s", err) - return err - } - - if err := pred.Exec(); err != nil { + if err := packager.Exec(); err != nil { log.Errorf("Failed to run exec step, error: %s", err) return err } diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go b/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go index 24fcb3832..f8e8f2de0 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go @@ -35,6 +35,7 @@ import ( "github.com/koderover/zadig/pkg/tool/kube/getter" "github.com/koderover/zadig/pkg/tool/kube/podexec" "github.com/koderover/zadig/pkg/tool/kube/updater" + "github.com/koderover/zadig/pkg/tool/log" ) // InitializeArtifactPackagePlugin to ini @@ -109,10 +110,11 @@ func (p *ArtifactPackageTaskPlugin) Run(ctx context.Context, pipelineTask *task. for _, registryID := range pipelineTask.ArtifactPackageTaskArgs.SourceRegistries { if registry, ok := pipelineTask.ConfigPayload.RepoConfigs[registryID]; ok { sourceRegistries = append(sourceRegistries, &types.DockerRegistry{ - Host: registry.RegAddr, - Namespace: registry.Namespace, - UserName: registry.AccessKey, - Password: registry.SecretKey, + RegistryID: registryID, + Host: registry.RegAddr, + Namespace: registry.Namespace, + UserName: registry.AccessKey, + Password: registry.SecretKey, }) } } @@ -121,14 +123,25 @@ func (p *ArtifactPackageTaskPlugin) Run(ctx context.Context, pipelineTask *task. for _, registryID := range pipelineTask.ArtifactPackageTaskArgs.TargetRegistries { if registry, ok := pipelineTask.ConfigPayload.RepoConfigs[registryID]; ok { targetRegistries = append(targetRegistries, &types.DockerRegistry{ - Host: registry.RegAddr, - Namespace: registry.Namespace, - UserName: registry.AccessKey, - Password: registry.SecretKey, + RegistryID: registryID, + Host: registry.RegAddr, + Namespace: registry.Namespace, + UserName: registry.AccessKey, + Password: registry.SecretKey, }) } } + log.Infof("######## source registry is %v", sourceRegistries) + log.Infof("######## targetRegistries registry is %+v", targetRegistries) + for _, singleImage := range pipelineTask.ArtifactPackageTaskArgs.Images { + log.Infof("##### the image service name is %s", singleImage.ServiceName) + log.Infof("##### the image service is %v", singleImage.Images) + for _, image := range singleImage.Images { + log.Infof("######## single image %+v", *image) + } + } + jobCtx := &types.ArtifactPackagerContext{ JobType: setting.BuildChartPackage, ProgressFile: setting.ProgressFile, @@ -173,7 +186,7 @@ func (p *ArtifactPackageTaskPlugin) Run(ctx context.Context, pipelineTask *task. } p.Log.Infof("succeed to create cm for artifact package job %s", p.JobName) - job, err := buildJob(p.Type(), pipelineTask.ConfigPayload.Release.PackagerImage, p.JobName, serviceName, setting.MinRequest, pipelineCtx, pipelineTask, []*task.RegistryNamespace{}) + job, err := buildJob(p.Type(), pipelineTask.ConfigPayload.Release.PackagerImage, p.JobName, serviceName, setting.MinRequest, setting.LowRequestSpec, pipelineCtx, pipelineTask, []*task.RegistryNamespace{}) if err != nil { msg := fmt.Sprintf("create release artifact package job context error: %v", err) p.Log.Error(msg) diff --git a/pkg/microservice/warpdrive/core/service/types/reaper.go b/pkg/microservice/warpdrive/core/service/types/reaper.go index 9ed4b2fdd..881479760 100644 --- a/pkg/microservice/warpdrive/core/service/types/reaper.go +++ b/pkg/microservice/warpdrive/core/service/types/reaper.go @@ -269,10 +269,11 @@ type GinkgoTest struct { // DockerRegistry 推送镜像到 docker registry 配置 type DockerRegistry struct { - Host string `yaml:"host"` - Namespace string `yaml:"namespace"` - UserName string `yaml:"username"` - Password string `yaml:"password"` + RegistryID string `yaml:"registry_id"` + Host string `yaml:"host"` + Namespace string `yaml:"namespace"` + UserName string `yaml:"username"` + Password string `yaml:"password"` } // Git ... diff --git a/pkg/microservice/warpdrive/core/service/types/task/model.go b/pkg/microservice/warpdrive/core/service/types/task/model.go index aa4ed2f16..a7bd4e9d8 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/model.go +++ b/pkg/microservice/warpdrive/core/service/types/task/model.go @@ -246,14 +246,15 @@ type ServiceTaskArgs struct { } type ImageData struct { - ImageUrl string `bson:"image_url" json:"image_url"` - ImageName string `bson:"image_name" json:"image_name"` - ImageTag string `bson:"image_tag" json:"image_tag"` + ImageUrl string `bson:"image_url" yaml:"image_url" json:"image_url"` + ImageName string `bson:"image_name" yaml:"image_name" json:"image_name"` + ImageTag string `bson:"image_tag" yaml:"image_tag" json:"image_tag"` + RegistryID string `bson:"registry_id,omitempty" yaml:"registry_id,omitempty" json:"registry_id,omitempty"` } type ImagesByService struct { - ServiceName string `bson:"service_name" json:"service_name"` - Images []*ImageData `bson:"images" json:"images"` + ServiceName string `bson:"service_name" json:"service_name" yaml:"service_name"` + Images []*ImageData `bson:"images" json:"images" yaml:"images"` } type ArtifactPackageTaskArgs struct { -- Gitee From 58aef56b727f082f818640a583744a35f06d788c Mon Sep 17 00:00:00 2001 From: allenshen Date: Thu, 9 Dec 2021 21:43:55 +0800 Subject: [PATCH 105/134] optimize code Signed-off-by: allenshen --- docker/service/aslan.Dockerfile | 2 +- .../aslan/core/delivery/service/version.go | 52 +------------------ .../aslan/core/environment/handler/router.go | 2 +- .../aslan/core/environment/service/helm.go | 3 +- .../core/service/types/task/config_payload.go | 2 +- 5 files changed, 5 insertions(+), 56 deletions(-) diff --git a/docker/service/aslan.Dockerfile b/docker/service/aslan.Dockerfile index 4384bb45d..434810faa 100644 --- a/docker/service/aslan.Dockerfile +++ b/docker/service/aslan.Dockerfile @@ -2,7 +2,7 @@ RUN go build -v -o /aslan ./cmd/aslan/main.go -#alpine.Dockerfile +#alpine-git.Dockerfile WORKDIR /app diff --git a/pkg/microservice/aslan/core/delivery/service/version.go b/pkg/microservice/aslan/core/delivery/service/version.go index 7db6b6e75..030209254 100644 --- a/pkg/microservice/aslan/core/delivery/service/version.go +++ b/pkg/microservice/aslan/core/delivery/service/version.go @@ -505,10 +505,8 @@ func createChartRepoClient(repo *commonmodels.HelmRepo) (*cm.Client, error) { return client, nil } -// pull image from currently using registry and push to specified repo +// find all images in one single chart func extractImages(productService *commonmodels.ProductService, registryMap map[string]*commonmodels.RegistryNamespace) (*ServiceImageDetails, error) { - - // find all images in one single chart imageUrlsSet := sets.NewString() for _, container := range productService.Containers { imageUrlsSet.Insert(container.Image) @@ -914,33 +912,6 @@ func buildDeliveryCharts(chartDataMap map[string]*DeliveryChartData, deliveryVer // start a new routine to check task results go waitVersionDone(deliveryVersion) - // no need to upload chart packages - //if args.Options == nil || !args.Options.EnableOfflineDist { - // return - //} - // - ////tar all chart files and image offline packages, send to s3 store - //fsTree := os.DirFS(dir) - //s3Base := configbase.ObjectStorageDeliveryVersionPath(deliveryVersion.ProductName) - //if err = fsservice.ArchiveAndUploadFilesToSpecifiedS3(fsTree, []string{deliveryVersion.Version}, s3Base, args.Options.S3StorageID, logger); err != nil { - // logger.Errorf("failed to upload chart package files for project %s, err: %s", deliveryVersion.ProductName, err) - // err = errors.Wrapf(err, "failed to upload package file") - // return - //} - - //err = commonrepo.NewDeliveryDistributeColl().Insert(&commonmodels.DeliveryDistribute{ - // ReleaseID: deliveryVersion.ID, - // DistributeType: config.File, - // PackageFile: fmt.Sprintf("%s.tar.gz", deliveryVersion.Version), - // //RemoteFileKey: filepath.Join(s3Base, fmt.Sprintf("%s.tar.gz", deliveryVersion.Version)), - // S3StorageID: args.Options.S3StorageID, - // CreatedAt: time.Now().Unix(), - //}) - //if err != nil { - // logger.Errorf("failed to insert file distribute data, version: %s, err: %s", deliveryVersion.Version, err) - // return fmt.Errorf("failed to insert file distribute data") - //} - return } @@ -1343,27 +1314,6 @@ func preDownloadChart(projectName, versionName, chartName string, log *zap.Sugar return filePath, err } -func getIndexDownloader(client *cm.Client) helm.IndexDownloader { - return func() ([]byte, error) { - resp, err := client.DownloadFile("index.yaml") - if err != nil { - return nil, err - } - defer func(Body io.ReadCloser) { - _ = Body.Close() - }(resp.Body) - - b, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, err - } - if resp.StatusCode != 200 { - return nil, getChartmuseumError(b, resp.StatusCode) - } - return b, nil - } -} - func GetChartVersions(chartName, chartRepoName string) ([]*ChartVersionResp, error) { chartRepo, err := getChartRepoData(chartRepoName) diff --git a/pkg/microservice/aslan/core/environment/handler/router.go b/pkg/microservice/aslan/core/environment/handler/router.go index fcca81914..741f70102 100644 --- a/pkg/microservice/aslan/core/environment/handler/router.go +++ b/pkg/microservice/aslan/core/environment/handler/router.go @@ -116,7 +116,7 @@ func (*Router) Inject(router *gin.RouterGroup) { environments.POST("/:name/services/:serviceName/restartNew", gin2.UpdateOperationLogStatus, RestartNewService) environments.POST("/:name/services/:serviceName/scale", gin2.UpdateOperationLogStatus, ScaleService) environments.POST("/:name/services/:serviceName/scaleNew", gin2.UpdateOperationLogStatus, ScaleNewService) - environments.GET("/:name/service/:serviceName/containers/:container", GetServiceContainer) + environments.GET("/:name/services/:serviceName/containers/:container", GetServiceContainer) environments.GET("/:name/estimated-renderchart", GetEstimatedRenderCharts) } diff --git a/pkg/microservice/aslan/core/environment/service/helm.go b/pkg/microservice/aslan/core/environment/service/helm.go index 8a2ea6097..255a2ba7d 100644 --- a/pkg/microservice/aslan/core/environment/service/helm.go +++ b/pkg/microservice/aslan/core/environment/service/helm.go @@ -23,14 +23,13 @@ import ( "strings" "sync" - "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/template" - "github.com/hashicorp/go-multierror" "github.com/otiai10/copy" "go.uber.org/zap" "github.com/koderover/zadig/pkg/microservice/aslan/config" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/template" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" diff --git a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go index fb5c696e1..6892f10e4 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go +++ b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go @@ -130,7 +130,7 @@ type ReleaseConfig struct { // e.g. xxx.com/resources/predator-plugin:v0.1.0 PredatorImage string // PackagerImage sets docker build image - // e.g. xxx.com/resources/predator-plugin:v0.1.0 + // e.g. xxx.com/resources/packager-plugin:v0.1.0 PackagerImage string } -- Gitee From 0da4739d24c73b5e20c0bb54b3662e28a5f256f9 Mon Sep 17 00:00:00 2001 From: allenshen Date: Thu, 9 Dec 2021 21:49:50 +0800 Subject: [PATCH 106/134] update tag align Signed-off-by: allenshen --- .../core/common/repository/models/task/model.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/microservice/aslan/core/common/repository/models/task/model.go b/pkg/microservice/aslan/core/common/repository/models/task/model.go index d1d23f200..d4783d2e6 100644 --- a/pkg/microservice/aslan/core/common/repository/models/task/model.go +++ b/pkg/microservice/aslan/core/common/repository/models/task/model.go @@ -76,12 +76,12 @@ type Task struct { StorageURI string `bson:"storage_uri,omitempty" json:"storage_uri,omitempty"` // interface{} 为types.TestReport TestReports map[string]interface{} `bson:"test_reports,omitempty" json:"test_reports,omitempty"` - RwLock sync.Mutex `bson:"-" json:"-"` - ResetImage bool `json:"resetImage" bson:"resetImage"` - TriggerBy *models.TriggerBy `json:"trigger_by,omitempty" bson:"trigger_by,omitempty"` - Features []string `bson:"features" json:"features"` - IsRestart bool `bson:"is_restart" json:"is_restart"` - StorageEndpoint string `bson:"storage_endpoint" json:"storage_endpoint"` + RwLock sync.Mutex `bson:"-" json:"-"` + ResetImage bool `bson:"resetImage" json:"resetImage"` + TriggerBy *models.TriggerBy `bson:"trigger_by,omitempty" json:"trigger_by,omitempty"` + Features []string `bson:"features" json:"features"` + IsRestart bool `bson:"is_restart" json:"is_restart"` + StorageEndpoint string `bson:"storage_endpoint" json:"storage_endpoint"` } //type RenderInfo struct { -- Gitee From cd5330a3d9ed27ec676dcd5e2bca6215f83de06b Mon Sep 17 00:00:00 2001 From: shendongdong Date: Fri, 10 Dec 2021 08:40:35 +0800 Subject: [PATCH 107/134] fix get estimate renderset error bug (#705) Signed-off-by: allenshen --- .../core/environment/service/environment.go | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/pkg/microservice/aslan/core/environment/service/environment.go b/pkg/microservice/aslan/core/environment/service/environment.go index 71e03bfd2..dfc388c6f 100644 --- a/pkg/microservice/aslan/core/environment/service/environment.go +++ b/pkg/microservice/aslan/core/environment/service/environment.go @@ -859,6 +859,7 @@ func prepareEstimatedData(productName, envName, serviceName, usageScenario, defa return "", "", fmt.Errorf("failed to query renderset info, name %s", productInfo.Render.Name) } + // find target render chart from render set var targetChart *templatemodels.RenderChart for _, chart := range renderSet.ChartInfos { if chart.ServiceName == serviceName { @@ -867,27 +868,30 @@ func prepareEstimatedData(productName, envName, serviceName, usageScenario, defa } } - if targetChart == nil { - return "", "", fmt.Errorf("failed to find chart info, name: %s", serviceName) - } - switch usageScenario { case usageScenarioUpdateEnv: imageRelatedKey := sets.NewString() - if templateService != nil { - for _, container := range templateService.Containers { - if container.ImagePath != nil { - imageRelatedKey.Insert(container.ImagePath.Image, container.ImagePath.Repo, container.ImagePath.Tag) - } + for _, container := range templateService.Containers { + if container.ImagePath != nil { + imageRelatedKey.Insert(container.ImagePath.Image, container.ImagePath.Repo, container.ImagePath.Tag) } } + + curValuesYaml := "" + if targetChart != nil { // service has been applied into environment, use current values.yaml + curValuesYaml = targetChart.ValuesYaml + } + // merge environment values - mergedBs, err := overrideValues([]byte(targetChart.ValuesYaml), []byte(templateService.HelmChart.ValuesYaml), imageRelatedKey) + mergedBs, err := overrideValues([]byte(curValuesYaml), []byte(templateService.HelmChart.ValuesYaml), imageRelatedKey) if err != nil { return "", "", errors.Wrapf(err, "failed to override values") } return string(mergedBs), renderSet.DefaultValues, nil case usageScenarioUpdateRenderSet: + if targetChart == nil { + return "", "", fmt.Errorf("failed to find chart info, name: %s", serviceName) + } return targetChart.ValuesYaml, renderSet.DefaultValues, nil default: return "", "", fmt.Errorf("unrecognized usageScenario:%s", usageScenario) @@ -2577,7 +2581,7 @@ func overrideValues(currentValuesYaml, latestValuesYaml []byte, imageRelatedKey } if len(replaceMap) == 0 { - return nil, nil + return latestValuesYaml, nil } var replaceKV []string -- Gitee From d599b1858eeca39be3c82d5bfbcb869b2ea0b82b Mon Sep 17 00:00:00 2001 From: allenshen Date: Fri, 10 Dec 2021 09:54:23 +0800 Subject: [PATCH 108/134] add registry id Signed-off-by: allenshen --- .../aslan/core/common/repository/models/queue.go | 7 ++++--- .../aslan/core/delivery/service/version.go | 12 ++++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/pkg/microservice/aslan/core/common/repository/models/queue.go b/pkg/microservice/aslan/core/common/repository/models/queue.go index a122e6fa5..2259f9dc3 100644 --- a/pkg/microservice/aslan/core/common/repository/models/queue.go +++ b/pkg/microservice/aslan/core/common/repository/models/queue.go @@ -96,9 +96,10 @@ type ServiceTaskArgs struct { } type ImageData struct { - ImageUrl string `bson:"image_url" json:"image_url"` - ImageName string `bson:"image_name" json:"image_name"` - ImageTag string `bson:"image_tag" json:"image_tag"` + ImageUrl string `bson:"image_url" json:"image_url"` + ImageName string `bson:"image_name" json:"image_name"` + ImageTag string `bson:"image_tag" json:"image_tag"` + RegistryID string `bson:"registry_id" json:"registry_id"` } type ImagesByService struct { diff --git a/pkg/microservice/aslan/core/delivery/service/version.go b/pkg/microservice/aslan/core/delivery/service/version.go index 030209254..961cdcfb7 100644 --- a/pkg/microservice/aslan/core/delivery/service/version.go +++ b/pkg/microservice/aslan/core/delivery/service/version.go @@ -530,15 +530,18 @@ func extractImages(productService *commonmodels.ProductService, registryMap map[ imageName := commonservice.ExtractImageName(imageUrl) imageTag := commonservice.ExtractImageTag(imageUrl) + registryID := "" // used source registry if registry, ok := registryMap[registryUrl]; ok { - registrySet.Insert(registry.ID.Hex()) + registryID = registry.ID.Hex() + registrySet.Insert(registryID) } ret.Images = append(ret.Images, &ImageUrlDetail{ ImageUrl: imageUrl, Name: imageName, Tag: imageTag, + Registry: registryID, }) } @@ -780,9 +783,10 @@ func buildArtifactTaskArgs(projectName, envName string, imagesMap *sync.Map) *co } for _, image := range imageDetail.Images { imagesByService.Images = append(imagesByService.Images, &commonmodels.ImageData{ - ImageUrl: image.ImageUrl, - ImageName: image.Name, - ImageTag: image.Tag, + ImageUrl: image.ImageUrl, + ImageName: image.Name, + ImageTag: image.Tag, + RegistryID: image.Registry, }) } imageArgs = append(imageArgs, imagesByService) -- Gitee From 86c08af2a666a88a918ed8d795c931d97336a52e Mon Sep 17 00:00:00 2001 From: allenshen Date: Fri, 10 Dec 2021 10:36:08 +0800 Subject: [PATCH 109/134] fix comments Signed-off-by: allenshen --- .../repository/models/delivery_version.go | 8 +++--- .../core/common/repository/models/queue.go | 26 +++++++++---------- .../aslan/core/service/service/helm.go | 6 ++--- .../service/workflow/artifact_task.go | 2 +- .../service/types/task/artifact_package.go | 2 +- .../core/service/types/task/model.go | 14 +++++----- 6 files changed, 29 insertions(+), 29 deletions(-) diff --git a/pkg/microservice/aslan/core/common/repository/models/delivery_version.go b/pkg/microservice/aslan/core/common/repository/models/delivery_version.go index 432d66156..ed851379d 100644 --- a/pkg/microservice/aslan/core/common/repository/models/delivery_version.go +++ b/pkg/microservice/aslan/core/common/repository/models/delivery_version.go @@ -32,14 +32,14 @@ type DeliveryVersion struct { Version string `bson:"version" json:"version"` ProductName string `bson:"product_name" json:"productName"` WorkflowName string `bson:"workflow_name" json:"workflowName"` - Type string `bson:"type" json:"type"` + Type string `bson:"type" json:"type"` TaskID int `bson:"task_id" json:"taskId"` Desc string `bson:"desc" json:"desc"` Labels []string `bson:"labels" json:"labels"` ProductEnvInfo *Product `bson:"product_env_info" json:"productEnvInfo"` - Status string `bson:"status" json:"status"` - Error string `bson:"error" json:"-"` - Progress *DeliveryVersionProgress `bson:"-" json:"progress"` + Status string `bson:"status" json:"status"` + Error string `bson:"error" json:"-"` + Progress *DeliveryVersionProgress `bson:"-" json:"progress"` CreateArgument interface{} `bson:"createArgument" json:"-"` CreatedBy string `bson:"created_by" json:"createdBy"` CreatedAt int64 `bson:"created_at" json:"created_at"` diff --git a/pkg/microservice/aslan/core/common/repository/models/queue.go b/pkg/microservice/aslan/core/common/repository/models/queue.go index 2259f9dc3..f87c728de 100644 --- a/pkg/microservice/aslan/core/common/repository/models/queue.go +++ b/pkg/microservice/aslan/core/common/repository/models/queue.go @@ -49,13 +49,13 @@ type Queue struct { IsArchived bool `bson:"is_archived" json:"is_archived"` AgentID string `bson:"agent_id" json:"agent_id"` MultiRun bool `bson:"multi_run" json:"multi_run"` - Target string `bson:"target,omitempty" json:"target"` // target 服务名称, k8s为容器名称, 物理机为服务名 - BuildModuleVer string `bson:"build_module_ver,omitempty" json:"build_module_ver"` // 使用预定义编译管理模块中的内容生成SubTasks, 查询条件为 服务模板名称: ServiceTmpl, 版本: BuildModuleVer 如果为空,则使用pipeline自定义SubTasks + Target string `bson:"target,omitempty" json:"target"` // target service name, for k8s: containerName, for pm: serviceName + BuildModuleVer string `bson:"build_module_ver,omitempty" json:"build_module_ver"` ServiceName string `bson:"service_name,omitempty" json:"service_name,omitempty"` - TaskArgs *TaskArgs `bson:"task_args,omitempty" json:"task_args,omitempty"` // TaskArgs 单服务工作流任务参数 - WorkflowArgs *WorkflowTaskArgs `bson:"workflow_args" json:"workflow_args,omitempty"` // WorkflowArgs 多服务工作流任务参数 - TestArgs *TestTaskArgs `bson:"test_args,omitempty" json:"test_args,omitempty"` // TestArgs 测试任务参数 - ServiceTaskArgs *ServiceTaskArgs `bson:"service_args,omitempty" json:"service_args,omitempty"` // ServiceTaskArgs 脚本部署工作流任务参数 + TaskArgs *TaskArgs `bson:"task_args,omitempty" json:"task_args,omitempty"` // TaskArgs job parameters for single-service workflow + WorkflowArgs *WorkflowTaskArgs `bson:"workflow_args" json:"workflow_args,omitempty"` // WorkflowArgs job parameters for multi-service workflow + TestArgs *TestTaskArgs `bson:"test_args,omitempty" json:"test_args,omitempty"` // TestArgs parameters for testing + ServiceTaskArgs *ServiceTaskArgs `bson:"service_args,omitempty" json:"service_args,omitempty"` // ServiceTaskArgs parameters for script-deployed workflows ArtifactPackageTaskArgs *ArtifactPackageTaskArgs `bson:"artifact_package_args,omitempty" json:"artifact_package_args,omitempty"` ConfigPayload *ConfigPayload `bson:"configpayload,omitempty" json:"config_payload"` Error string `bson:"error,omitempty" json:"error,omitempty"` @@ -96,9 +96,9 @@ type ServiceTaskArgs struct { } type ImageData struct { - ImageUrl string `bson:"image_url" json:"image_url"` - ImageName string `bson:"image_name" json:"image_name"` - ImageTag string `bson:"image_tag" json:"image_tag"` + ImageUrl string `bson:"image_url" json:"image_url"` + ImageName string `bson:"image_name" json:"image_name"` + ImageTag string `bson:"image_tag" json:"image_tag"` RegistryID string `bson:"registry_id" json:"registry_id"` } @@ -109,10 +109,10 @@ type ImagesByService struct { type ArtifactPackageTaskArgs struct { ProjectName string `bson:"project_name" json:"project_name"` - EnvName string `bson:"env_name" json:"env_name"` - Images []*ImagesByService `bson:"images" json:"images"` - SourceRegistries []string `json:"source_registries" json:"source_registries"` - TargetRegistries []string `json:"target_registries" json:"target_registries"` + EnvName string `bson:"env_name" json:"env_name"` + Images []*ImagesByService `bson:"images" json:"images"` + SourceRegistries []string `json:"source_registries" json:"source_registries"` + TargetRegistries []string `json:"target_registries" json:"target_registries"` } type ConfigPayload struct { diff --git a/pkg/microservice/aslan/core/service/service/helm.go b/pkg/microservice/aslan/core/service/service/helm.go index 931bfa21c..a9d2dec2c 100644 --- a/pkg/microservice/aslan/core/service/service/helm.go +++ b/pkg/microservice/aslan/core/service/service/helm.go @@ -114,9 +114,9 @@ type ChartTemplateData struct { } type GetFileContentParam struct { - FilePath string `json:"filePath" form:"filePath"` - FileName string `json:"fileName" form:"fileName"` - Revision int64 `json:"revision" form:"revision"` + FilePath string `json:"filePath" form:"filePath"` + FileName string `json:"fileName" form:"fileName"` + Revision int64 `json:"revision" form:"revision"` DeliveryVersion bool `json:"deliveryVersion" form:"deliveryVersion"` } diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go index 512cdc59c..d69d7c4be 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go @@ -37,7 +37,7 @@ import ( func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, taskCreator string, log *zap.SugaredLogger) (int64, error) { - // 获取全局configpayload + // get global config payload configPayload := commonservice.GetConfigPayload(0) repos, err := commonrepo.NewRegistryNamespaceColl().FindAll(&commonrepo.FindRegOps{}) diff --git a/pkg/microservice/warpdrive/core/service/types/task/artifact_package.go b/pkg/microservice/warpdrive/core/service/types/task/artifact_package.go index 9ac39d95a..5ebe24fb0 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/artifact_package.go +++ b/pkg/microservice/warpdrive/core/service/types/task/artifact_package.go @@ -26,7 +26,7 @@ type ArtifactPackage struct { TaskType config.TaskType `bson:"type" json:"type"` Enabled bool `bson:"enabled" json:"enabled"` TaskStatus config.Status `bson:"status" json:"status"` - Progress string `bson:"progress" json:"progress"` + Progress string `bson:"progress" json:"progress"` Timeout int `bson:"timeout,omitempty" json:"timeout,omitempty"` Error string `bson:"error,omitempty" json:"error,omitempty"` StartTime int64 `bson:"start_time,omitempty" json:"start_time,omitempty"` diff --git a/pkg/microservice/warpdrive/core/service/types/task/model.go b/pkg/microservice/warpdrive/core/service/types/task/model.go index a7bd4e9d8..d8588c9dc 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/model.go +++ b/pkg/microservice/warpdrive/core/service/types/task/model.go @@ -246,20 +246,20 @@ type ServiceTaskArgs struct { } type ImageData struct { - ImageUrl string `bson:"image_url" yaml:"image_url" json:"image_url"` - ImageName string `bson:"image_name" yaml:"image_name" json:"image_name"` - ImageTag string `bson:"image_tag" yaml:"image_tag" json:"image_tag"` - RegistryID string `bson:"registry_id,omitempty" yaml:"registry_id,omitempty" json:"registry_id,omitempty"` + ImageUrl string `bson:"image_url" json:"image_url" yaml:"image_url"` + ImageName string `bson:"image_name" json:"image_name" yaml:"image_name"` + ImageTag string `bson:"image_tag" json:"image_tag" yaml:"image_tag"` + RegistryID string `bson:"registry_id" json:"registry_id" yaml:"registry_id"` } type ImagesByService struct { ServiceName string `bson:"service_name" json:"service_name" yaml:"service_name"` - Images []*ImageData `bson:"images" json:"images" yaml:"images"` + Images []*ImageData `bson:"images" json:"images" yaml:"images"` } type ArtifactPackageTaskArgs struct { - ProductName string `bson:"product_name" json:"product_name"` - Images []*ImagesByService `bson:"images" json:"images"` + ProductName string `bson:"product_name" json:"product_name"` + Images []*ImagesByService `bson:"images" json:"images"` SourceRegistries []string `bson:"source_registries" json:"source_registries"` TargetRegistries []string `bson:"target_registries" json:"target_registries"` } -- Gitee From ef95d2ce9456f412617aa7d5f66f1da4f329876d Mon Sep 17 00:00:00 2001 From: allenshen Date: Fri, 10 Dec 2021 11:16:45 +0800 Subject: [PATCH 110/134] resolve comments Signed-off-by: allenshen --- docker/service/packager-plugin.Dockerfile | 8 -------- pkg/microservice/packager/core/service/service.go | 8 ++++++++ pkg/microservice/packager/executor/executor.go | 2 +- pkg/microservice/warpdrive/config/const.go | 12 ++++++------ .../core/service/taskplugin/artifact_package.go | 11 ----------- .../warpdrive/core/service/types/task/model.go | 14 +++++++------- 6 files changed, 22 insertions(+), 33 deletions(-) diff --git a/docker/service/packager-plugin.Dockerfile b/docker/service/packager-plugin.Dockerfile index 2ae89592a..5ef3c5d5e 100644 --- a/docker/service/packager-plugin.Dockerfile +++ b/docker/service/packager-plugin.Dockerfile @@ -4,14 +4,6 @@ RUN go build -v -o /packager-plugin ./cmd/packager/main.go #alpine.Dockerfile -RUN apk --no-cache add curl -# install docker client -RUN apk --no-cache add curl && \ - curl -fsSL "http://resources.koderover.com/docker-cli-v19.03.2.tar.gz" -o docker.tgz &&\ - tar -xvzf docker.tgz &&\ - mv docker/* /usr/local/bin &&\ - rm -rf docke* - WORKDIR /app COPY --from=build /packager-plugin . diff --git a/pkg/microservice/packager/core/service/service.go b/pkg/microservice/packager/core/service/service.go index 192196021..339ab5de9 100644 --- a/pkg/microservice/packager/core/service/service.go +++ b/pkg/microservice/packager/core/service/service.go @@ -160,8 +160,16 @@ func (p *Packager) Exec() error { cli, err := client.NewClientWithOpts(client.FromEnv) if err != nil { log.Errorf("failed to init docker client %s", err) + return err } + defer func() { + err = cli.Close() + if err != nil { + log.Errorf("failed to close client: %s", err) + } + }() + // run docker info to ensure docker daemon connection for i := 0; i < 120; i++ { _, err := cli.Info(context.TODO()) diff --git a/pkg/microservice/packager/executor/executor.go b/pkg/microservice/packager/executor/executor.go index f4d1c0aa2..840ca0134 100644 --- a/pkg/microservice/packager/executor/executor.go +++ b/pkg/microservice/packager/executor/executor.go @@ -38,7 +38,7 @@ func Execute() error { } if err := packager.Exec(); err != nil { - log.Errorf("Failed to run exec step, error: %s", err) + log.Errorf("Failed to run packager, error: %s", err) return err } diff --git a/pkg/microservice/warpdrive/config/const.go b/pkg/microservice/warpdrive/config/const.go index 88c00a895..380b211f5 100644 --- a/pkg/microservice/warpdrive/config/const.go +++ b/pkg/microservice/warpdrive/config/const.go @@ -56,17 +56,17 @@ const ( type PipelineType string const ( - // SingleType 单服务工作流 + // SingleType single-service workflow SingleType PipelineType = "single" - // WorkflowType 多服务工作流 + // WorkflowType multi-service workflow WorkflowType PipelineType = "workflow" - // FreestyleType 自由编排工作流 + // FreestyleType freeStyle workflow FreestyleType PipelineType = "freestyle" - // TestType 测试 + // TestType testing TestType PipelineType = "test" - // ServiceType 服务 + // ServiceType pipeline ServiceType PipelineType = "service" - // ArtifactType 服务 + // ArtifactType artifact build ArtifactType PipelineType = "artifact" ) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go b/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go index f8e8f2de0..a546856e7 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go @@ -35,7 +35,6 @@ import ( "github.com/koderover/zadig/pkg/tool/kube/getter" "github.com/koderover/zadig/pkg/tool/kube/podexec" "github.com/koderover/zadig/pkg/tool/kube/updater" - "github.com/koderover/zadig/pkg/tool/log" ) // InitializeArtifactPackagePlugin to ini @@ -132,16 +131,6 @@ func (p *ArtifactPackageTaskPlugin) Run(ctx context.Context, pipelineTask *task. } } - log.Infof("######## source registry is %v", sourceRegistries) - log.Infof("######## targetRegistries registry is %+v", targetRegistries) - for _, singleImage := range pipelineTask.ArtifactPackageTaskArgs.Images { - log.Infof("##### the image service name is %s", singleImage.ServiceName) - log.Infof("##### the image service is %v", singleImage.Images) - for _, image := range singleImage.Images { - log.Infof("######## single image %+v", *image) - } - } - jobCtx := &types.ArtifactPackagerContext{ JobType: setting.BuildChartPackage, ProgressFile: setting.ProgressFile, diff --git a/pkg/microservice/warpdrive/core/service/types/task/model.go b/pkg/microservice/warpdrive/core/service/types/task/model.go index a7bd4e9d8..e3f776067 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/model.go +++ b/pkg/microservice/warpdrive/core/service/types/task/model.go @@ -246,20 +246,20 @@ type ServiceTaskArgs struct { } type ImageData struct { - ImageUrl string `bson:"image_url" yaml:"image_url" json:"image_url"` - ImageName string `bson:"image_name" yaml:"image_name" json:"image_name"` - ImageTag string `bson:"image_tag" yaml:"image_tag" json:"image_tag"` - RegistryID string `bson:"registry_id,omitempty" yaml:"registry_id,omitempty" json:"registry_id,omitempty"` + ImageUrl string `bson:"image_url" json:"image_url" yaml:"image_url"` + ImageName string `bson:"image_name" json:"image_name" yaml:"image_name"` + ImageTag string `bson:"image_tag" json:"image_tag" yaml:"image_tag"` + RegistryID string `bson:"registry_id" json:"registry_id" yaml:"registry_id"` } type ImagesByService struct { ServiceName string `bson:"service_name" json:"service_name" yaml:"service_name"` - Images []*ImageData `bson:"images" json:"images" yaml:"images"` + Images []*ImageData `bson:"images" json:"images" yaml:"images"` } type ArtifactPackageTaskArgs struct { - ProductName string `bson:"product_name" json:"product_name"` - Images []*ImagesByService `bson:"images" json:"images"` + ProductName string `bson:"product_name" json:"product_name"` + Images []*ImagesByService `bson:"images" json:"images"` SourceRegistries []string `bson:"source_registries" json:"source_registries"` TargetRegistries []string `bson:"target_registries" json:"target_registries"` } -- Gitee From 8ce5eee7b386bee294e4663457463f76c55a17d9 Mon Sep 17 00:00:00 2001 From: allenshen Date: Fri, 10 Dec 2021 11:41:31 +0800 Subject: [PATCH 111/134] fix conflicts Signed-off-by: allenshen --- .../warpdrive/core/service/taskplugin/artifact_package.go | 4 ++-- pkg/microservice/warpdrive/core/service/taskplugin/job.go | 5 ----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go b/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go index a546856e7..a2eec1c00 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go @@ -175,7 +175,7 @@ func (p *ArtifactPackageTaskPlugin) Run(ctx context.Context, pipelineTask *task. } p.Log.Infof("succeed to create cm for artifact package job %s", p.JobName) - job, err := buildJob(p.Type(), pipelineTask.ConfigPayload.Release.PackagerImage, p.JobName, serviceName, setting.MinRequest, setting.LowRequestSpec, pipelineCtx, pipelineTask, []*task.RegistryNamespace{}) + job, err := buildJob(p.Type(), pipelineTask.ConfigPayload.Release.PackagerImage, p.JobName, serviceName, "", pipelineTask.ConfigPayload.Build.KubeNamespace, setting.MinRequest, setting.LowRequestSpec, pipelineCtx, pipelineTask, []*task.RegistryNamespace{}) if err != nil { msg := fmt.Sprintf("create release artifact package job context error: %v", err) p.Log.Error(msg) @@ -355,7 +355,7 @@ func (p *ArtifactPackageTaskPlugin) Complete(ctx context.Context, pipelineTask * }() // 保存实时日志到s3 - err := saveContainerLog(pipelineTask, p.KubeNamespace, p.FileName, jobLabel, p.kubeClient) + err := saveContainerLog(pipelineTask, p.KubeNamespace, "", p.FileName, jobLabel, p.kubeClient) if err != nil { p.Log.Error(err) p.Task.Error = err.Error() diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/job.go b/pkg/microservice/warpdrive/core/service/taskplugin/job.go index a542babe1..bfcce997b 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/job.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/job.go @@ -433,13 +433,8 @@ func buildJobWithLinkedNs(taskType config.TaskType, jobImage, jobName, serviceNa reaperBinaryFile = strings.Replace(reaperBinaryFile, ResourceServer, ResourceServer+"."+currentNamespace, -1) } -<<<<<<< HEAD if !strings.Contains(jobImage, PredatorPlugin) && !strings.Contains(jobImage, JenkinsPlugin) && !strings.Contains(jobImage, PackagerPlugin) { - reaperBootingScript = fmt.Sprintf("curl -m 60 --retry-delay 5 --retry 3 -sL %s -o reaper && chmod +x reaper && mv reaper /usr/local/bin && /usr/local/bin/reaper", pipelineTask.ConfigPayload.Release.ReaperBinaryFile) -======= - if !strings.Contains(jobImage, PredatorPlugin) && !strings.Contains(jobImage, JenkinsPlugin) { reaperBootingScript = fmt.Sprintf("curl -m 60 --retry-delay 5 --retry 3 -sL %s -o reaper && chmod +x reaper && mv reaper /usr/local/bin && /usr/local/bin/reaper", reaperBinaryFile) ->>>>>>> upstream/main if pipelineTask.ConfigPayload.Proxy.EnableApplicationProxy && pipelineTask.ConfigPayload.Proxy.Type == "http" { reaperBootingScript = fmt.Sprintf("curl -m 60 --retry-delay 5 --retry 3 -sL --proxy %s %s -o reaper && chmod +x reaper && mv reaper /usr/local/bin && /usr/local/bin/reaper", pipelineTask.ConfigPayload.Proxy.GetProxyURL(), -- Gitee From 367454034e8c14faccdd66d423dd38824c8810ce Mon Sep 17 00:00:00 2001 From: ddh27 Date: Fri, 10 Dec 2021 11:43:21 +0800 Subject: [PATCH 112/134] Add init to aslan dependent health check Signed-off-by: ddh27 --- pkg/cli/initconfig/cmd/healthz.go | 9 +++++++++ pkg/shared/client/aslan/healthz.go | 24 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 pkg/shared/client/aslan/healthz.go diff --git a/pkg/cli/initconfig/cmd/healthz.go b/pkg/cli/initconfig/cmd/healthz.go index 7e270b8cd..bdc4d036e 100644 --- a/pkg/cli/initconfig/cmd/healthz.go +++ b/pkg/cli/initconfig/cmd/healthz.go @@ -19,6 +19,8 @@ package cmd import ( "fmt" + "github.com/koderover/zadig/pkg/config" + "github.com/koderover/zadig/pkg/shared/client/aslan" "github.com/koderover/zadig/pkg/shared/client/policy" "github.com/koderover/zadig/pkg/shared/client/user" ) @@ -30,6 +32,9 @@ func Healthz() error { if err := checkPolicyServiceHealth(); err != nil { return fmt.Errorf("checkPolicyServiceHealth error:%s", err) } + if err := checkAslanServiceHealth(); err != nil { + return fmt.Errorf("checkPolicyServiceHealth error:%s", err) + } return nil } @@ -40,3 +45,7 @@ func checkUserServiceHealth() error { func checkPolicyServiceHealth() error { return policy.NewDefault().Healthz() } + +func checkAslanServiceHealth() error { + return aslan.New(config.AslanServiceAddress()).Healthz() +} diff --git a/pkg/shared/client/aslan/healthz.go b/pkg/shared/client/aslan/healthz.go new file mode 100644 index 000000000..d47bcee3b --- /dev/null +++ b/pkg/shared/client/aslan/healthz.go @@ -0,0 +1,24 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package aslan + +// Healthz api/health +func (c *Client) Healthz() error { + url := "/health" + _, err := c.Get(url) + return err +} -- Gitee From ec50023d7bfd9f9eb05d71e5aab0d27844133854 Mon Sep 17 00:00:00 2001 From: shendongdong Date: Fri, 10 Dec 2021 11:43:26 +0800 Subject: [PATCH 113/134] helm chart packager (#698) * add basic logic to push images by running jobs Signed-off-by: allenshen * add more detail to progress data Signed-off-by: allenshen * optimize code Signed-off-by: allenshen * fix comments Signed-off-by: allenshen * resolve comments Signed-off-by: allenshen * fix conflicts Signed-off-by: allenshen --- Makefile | 2 +- cmd/packager/main.go | 29 ++ docker/service/packager-plugin.Dockerfile | 11 + pkg/microservice/aslan/config/config.go | 4 + pkg/microservice/aslan/config/consts.go | 31 +- .../core/common/repository/models/queue.go | 123 ++--- .../models/task/artifact_package.go | 50 +++ .../common/repository/models/task/model.go | 37 +- .../aslan/core/common/service/base/convert.go | 8 + .../core/common/service/config_payload.go | 1 + .../service/workflow/artifact_task.go | 140 ++++++ .../core/workflow/service/workflow/convert.go | 162 +++---- .../service/workflow/workflow_task.go | 2 + pkg/microservice/packager/config/config.go | 33 ++ .../packager/core/service/packager.go | 48 ++ .../packager/core/service/service.go | 236 ++++++++++ .../packager/executor/executor.go | 46 ++ pkg/microservice/warpdrive/config/const.go | 41 +- .../service/taskcontroller/task_handler.go | 3 + .../service/taskcontroller/task_helper.go | 26 +- .../service/taskplugin/artifact_package.go | 422 ++++++++++++++++++ .../warpdrive/core/service/taskplugin/job.go | 15 +- .../core/service/taskplugin/utils.go | 38 +- .../warpdrive/core/service/types/packager.go | 27 ++ .../warpdrive/core/service/types/reaper.go | 9 +- .../service/types/task/artifact_package.go | 50 +++ .../core/service/types/task/config_payload.go | 3 + .../core/service/types/task/model.go | 21 + pkg/setting/consts.go | 7 + 29 files changed, 1401 insertions(+), 224 deletions(-) create mode 100644 cmd/packager/main.go create mode 100644 docker/service/packager-plugin.Dockerfile create mode 100644 pkg/microservice/aslan/core/common/repository/models/task/artifact_package.go create mode 100644 pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go create mode 100644 pkg/microservice/packager/config/config.go create mode 100644 pkg/microservice/packager/core/service/packager.go create mode 100644 pkg/microservice/packager/core/service/service.go create mode 100644 pkg/microservice/packager/executor/executor.go create mode 100644 pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go create mode 100644 pkg/microservice/warpdrive/core/service/types/packager.go create mode 100644 pkg/microservice/warpdrive/core/service/types/task/artifact_package.go diff --git a/Makefile b/Makefile index 08428072a..224828be5 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ IMAGE_REPOSITORY = ccr.ccs.tencentyun.com/koderover-rc VERSION ?= $(shell date +'%Y%m%d%H%M%S') -TARGETS = aslan cron hub-agent hub-server jenkins-plugin podexec predator-plugin resource-server ua warpdrive policy user picket config init +TARGETS = aslan cron hub-agent hub-server jenkins-plugin podexec predator-plugin packager-plugin resource-server ua warpdrive policy user picket config init REAPER_OS= focal xenial bionic ALL_IMAGES=$(TARGETS:=.image) diff --git a/cmd/packager/main.go b/cmd/packager/main.go new file mode 100644 index 000000000..bd2fa8bc1 --- /dev/null +++ b/cmd/packager/main.go @@ -0,0 +1,29 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "log" + + "github.com/koderover/zadig/pkg/microservice/packager/executor" +) + +func main() { + if err := executor.Execute(); err != nil { + log.Fatalf("Failed to run packager, the error is: %+v", err) + } +} diff --git a/docker/service/packager-plugin.Dockerfile b/docker/service/packager-plugin.Dockerfile new file mode 100644 index 000000000..5ef3c5d5e --- /dev/null +++ b/docker/service/packager-plugin.Dockerfile @@ -0,0 +1,11 @@ +#golang.Dockerfile + +RUN go build -v -o /packager-plugin ./cmd/packager/main.go + +#alpine.Dockerfile + +WORKDIR /app + +COPY --from=build /packager-plugin . + +ENTRYPOINT ["/app/packager-plugin"] diff --git a/pkg/microservice/aslan/config/config.go b/pkg/microservice/aslan/config/config.go index c9c115c8d..edca3a57f 100644 --- a/pkg/microservice/aslan/config/config.go +++ b/pkg/microservice/aslan/config/config.go @@ -190,6 +190,10 @@ func PredatorImage() string { return viper.GetString(setting.ENVPredatorImage) } +func PackagerImage() string { + return viper.GetString(setting.EnvPackagerImage) +} + func DockerHosts() []string { return strings.Split(viper.GetString(setting.ENVDockerHosts), ",") } diff --git a/pkg/microservice/aslan/config/consts.go b/pkg/microservice/aslan/config/consts.go index a028737fd..99f468214 100644 --- a/pkg/microservice/aslan/config/consts.go +++ b/pkg/microservice/aslan/config/consts.go @@ -83,6 +83,8 @@ const ( TestType PipelineType = "test" // ServiceType 服务 ServiceType PipelineType = "service" + // ArtifactPackageType package artifact + ArtifactType PipelineType = "artifact" ) type Status string @@ -117,20 +119,21 @@ const ( type TaskType string const ( - TaskPipeline TaskType = "pipeline" - TaskBuild TaskType = "buildv2" - TaskJenkinsBuild TaskType = "jenkins_build" - TaskArtifact TaskType = "artifact" - TaskArtifactDeploy TaskType = "artifact_deploy" - TaskDeploy TaskType = "deploy" - TaskTestingV2 TaskType = "testingv2" - TaskDistributeToS3 TaskType = "distribute2kodo" - TaskReleaseImage TaskType = "release_image" - TaskJira TaskType = "jira" - TaskDockerBuild TaskType = "docker_build" - TaskSecurity TaskType = "security" - TaskResetImage TaskType = "reset_image" - TaskDistribute TaskType = "distribute" + TaskPipeline TaskType = "pipeline" + TaskBuild TaskType = "buildv2" + TaskJenkinsBuild TaskType = "jenkins_build" + TaskArtifact TaskType = "artifact" + TaskArtifactDeploy TaskType = "artifact_deploy" + TaskDeploy TaskType = "deploy" + TaskTestingV2 TaskType = "testingv2" + TaskDistributeToS3 TaskType = "distribute2kodo" + TaskReleaseImage TaskType = "release_image" + TaskJira TaskType = "jira" + TaskDockerBuild TaskType = "docker_build" + TaskSecurity TaskType = "security" + TaskResetImage TaskType = "reset_image" + TaskDistribute TaskType = "distribute" + TaskArtifactPackage TaskType = "artifact_package" ) type DistributeType string diff --git a/pkg/microservice/aslan/core/common/repository/models/queue.go b/pkg/microservice/aslan/core/common/repository/models/queue.go index 2286fb79a..1a7247d3b 100644 --- a/pkg/microservice/aslan/core/common/repository/models/queue.go +++ b/pkg/microservice/aslan/core/common/repository/models/queue.go @@ -25,63 +25,50 @@ import ( ) type Queue struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - TaskID int64 `bson:"task_id" json:"task_id"` - ProductName string `bson:"product_name" json:"product_name"` - PipelineName string `bson:"pipeline_name" json:"pipeline_name"` - Namespace string `bson:"namespace,omitempty" json:"namespace,omitempty"` - Type config.PipelineType `bson:"type" json:"type"` - Status config.Status `bson:"status" json:"status,omitempty"` - Description string `bson:"description,omitempty" json:"description,omitempty"` - TaskCreator string `bson:"task_creator" json:"task_creator,omitempty"` - TaskRevoker string `bson:"task_revoker,omitempty" json:"task_revoker,omitempty"` - CreateTime int64 `bson:"create_time" json:"create_time,omitempty"` - StartTime int64 `bson:"start_time" json:"start_time,omitempty"` - EndTime int64 `bson:"end_time" json:"end_time,omitempty"` - SubTasks []map[string]interface{} `bson:"sub_tasks" json:"sub_tasks"` - Stages []*Stage `bson:"stages" json:"stages"` - ReqID string `bson:"req_id,omitempty" json:"req_id,omitempty"` - AgentHost string `bson:"agent_host,omitempty" json:"agent_host,omitempty"` - DockerHost string `bson:"-" json:"docker_host,omitempty"` - TeamID int `bson:"team_id,omitempty" json:"team_id,omitempty"` - TeamName string `bson:"team,omitempty" json:"team,omitempty"` - IsDeleted bool `bson:"is_deleted" json:"is_deleted"` - IsArchived bool `bson:"is_archived" json:"is_archived"` - AgentID string `bson:"agent_id" json:"agent_id"` - // 是否允许同时运行多次 - MultiRun bool `bson:"multi_run" json:"multi_run"` - // target 服务名称, k8s为容器名称, 物理机为服务名 - Target string `bson:"target,omitempty" json:"target"` - // 使用预定义编译管理模块中的内容生成SubTasks, - // 查询条件为 服务模板名称: ServiceTmpl, 版本: BuildModuleVer - // 如果为空,则使用pipeline自定义SubTasks - BuildModuleVer string `bson:"build_module_ver,omitempty" json:"build_module_ver"` - ServiceName string `bson:"service_name,omitempty" json:"service_name,omitempty"` - // TaskArgs 单服务工作流任务参数 - TaskArgs *TaskArgs `bson:"task_args,omitempty" json:"task_args,omitempty"` - // WorkflowArgs 多服务工作流任务参数 - WorkflowArgs *WorkflowTaskArgs `bson:"workflow_args" json:"workflow_args,omitempty"` - // TestArgs 测试任务参数 - TestArgs *TestTaskArgs `bson:"test_args,omitempty" json:"test_args,omitempty"` - // ServiceTaskArgs 脚本部署工作流任务参数 - ServiceTaskArgs *ServiceTaskArgs `bson:"service_args,omitempty" json:"service_args,omitempty"` - ConfigPayload *ConfigPayload `json:"config_payload,omitempty"` - Error string `bson:"error,omitempty" json:"error,omitempty"` - Services [][]*ProductService `bson:"services" json:"services"` - Render *RenderInfo `bson:"render" json:"render"` - StorageURI string `bson:"storage_uri,omitempty" json:"storage_uri,omitempty"` - // interface{} 为types.TestReport - TestReports map[string]interface{} `bson:"test_reports,omitempty" json:"test_reports,omitempty"` - - RwLock sync.Mutex `bson:"-" json:"-"` - - ResetImage bool `json:"resetImage" bson:"resetImage"` - - TriggerBy *TriggerBy `json:"trigger_by,omitempty" bson:"trigger_by,omitempty"` - - Features []string `bson:"features" json:"features"` - IsRestart bool `bson:"is_restart" json:"is_restart"` - StorageEndpoint string `bson:"storage_endpoint" json:"storage_endpoint"` + ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + TaskID int64 `bson:"task_id" json:"task_id"` + ProductName string `bson:"product_name" json:"product_name"` + PipelineName string `bson:"pipeline_name" json:"pipeline_name"` + Namespace string `bson:"namespace,omitempty" json:"namespace,omitempty"` + Type config.PipelineType `bson:"type" json:"type"` + Status config.Status `bson:"status" json:"status,omitempty"` + Description string `bson:"description,omitempty" json:"description,omitempty"` + TaskCreator string `bson:"task_creator" json:"task_creator,omitempty"` + TaskRevoker string `bson:"task_revoker,omitempty" json:"task_revoker,omitempty"` + CreateTime int64 `bson:"create_time" json:"create_time,omitempty"` + StartTime int64 `bson:"start_time" json:"start_time,omitempty"` + EndTime int64 `bson:"end_time" json:"end_time,omitempty"` + SubTasks []map[string]interface{} `bson:"sub_tasks" json:"sub_tasks"` + Stages []*Stage `bson:"stages" json:"stages"` + ReqID string `bson:"req_id,omitempty" json:"req_id,omitempty"` + AgentHost string `bson:"agent_host,omitempty" json:"agent_host,omitempty"` + DockerHost string `bson:"-" json:"docker_host,omitempty"` + TeamID int `bson:"team_id,omitempty" json:"team_id,omitempty"` + TeamName string `bson:"team,omitempty" json:"team,omitempty"` + IsDeleted bool `bson:"is_deleted" json:"is_deleted"` + IsArchived bool `bson:"is_archived" json:"is_archived"` + AgentID string `bson:"agent_id" json:"agent_id"` + MultiRun bool `bson:"multi_run" json:"multi_run"` + Target string `bson:"target,omitempty" json:"target"` // target 服务名称, k8s为容器名称, 物理机为服务名 + BuildModuleVer string `bson:"build_module_ver,omitempty" json:"build_module_ver"` // 使用预定义编译管理模块中的内容生成SubTasks, 查询条件为 服务模板名称: ServiceTmpl, 版本: BuildModuleVer 如果为空,则使用pipeline自定义SubTasks + ServiceName string `bson:"service_name,omitempty" json:"service_name,omitempty"` + TaskArgs *TaskArgs `bson:"task_args,omitempty" json:"task_args,omitempty"` // TaskArgs 单服务工作流任务参数 + WorkflowArgs *WorkflowTaskArgs `bson:"workflow_args" json:"workflow_args,omitempty"` // WorkflowArgs 多服务工作流任务参数 + TestArgs *TestTaskArgs `bson:"test_args,omitempty" json:"test_args,omitempty"` // TestArgs 测试任务参数 + ServiceTaskArgs *ServiceTaskArgs `bson:"service_args,omitempty" json:"service_args,omitempty"` // ServiceTaskArgs 脚本部署工作流任务参数 + ArtifactPackageTaskArgs *ArtifactPackageTaskArgs `bson:"artifact_package_args,omitempty" json:"artifact_package_args,omitempty"` + ConfigPayload *ConfigPayload `bson:"configpayload,omitempty" json:"config_payload"` + Error string `bson:"error,omitempty" json:"error,omitempty"` + Services [][]*ProductService `bson:"services" json:"services"` + Render *RenderInfo `bson:"render" json:"render"` + StorageURI string `bson:"storage_uri,omitempty" json:"storage_uri,omitempty"` + TestReports map[string]interface{} `bson:"test_reports,omitempty" json:"test_reports,omitempty"` + RwLock sync.Mutex `bson:"-" json:"-"` + ResetImage bool `bson:"resetImage" json:"resetImage"` + TriggerBy *TriggerBy `bson:"trigger_by,omitempty" json:"trigger_by,omitempty"` + Features []string `bson:"features" json:"features"` + IsRestart bool `bson:"is_restart" json:"is_restart"` + StorageEndpoint string `bson:"storage_endpoint" json:"storage_endpoint"` } type TriggerBy struct { @@ -108,6 +95,25 @@ type ServiceTaskArgs struct { Updatable bool `bson:"updatable" json:"updatable"` } +type ImageData struct { + ImageUrl string `bson:"image_url" json:"image_url"` + ImageName string `bson:"image_name" json:"image_name"` + ImageTag string `bson:"image_tag" json:"image_tag"` +} + +type ImagesByService struct { + ServiceName string `bson:"service_name" json:"service_name"` + Images []*ImageData `bson:"images" json:"images"` +} + +type ArtifactPackageTaskArgs struct { + ProjectName string `bson:"project_name" json:"project_name"` + EnvName string `bson:"env_name" json:"env_name"` + Images []*ImagesByService `bson:"images" json:"images"` + SourceRegistries []string `json:"source_registries" json:"source_registries"` + TargetRegistries []string `json:"target_registries" json:"target_registries"` +} + type ConfigPayload struct { Proxy Proxy `json:"proxy"` S3Storage S3Config `json:"s3_storage"` @@ -210,6 +216,9 @@ type ReleaseConfig struct { // PredatorImage sets docker build image // e.g. xxx.com/resources/predator-plugin:v0.1.0 PredatorImage string + // PackagerImage sets docker build image + // e.g. xxx.com/resources/predator-plugin:v0.1.0 + PackagerImage string } type ImageReleaseConfig struct { diff --git a/pkg/microservice/aslan/core/common/repository/models/task/artifact_package.go b/pkg/microservice/aslan/core/common/repository/models/task/artifact_package.go new file mode 100644 index 000000000..8f578b62c --- /dev/null +++ b/pkg/microservice/aslan/core/common/repository/models/task/artifact_package.go @@ -0,0 +1,50 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package task + +import ( + "fmt" + + "github.com/koderover/zadig/pkg/microservice/aslan/config" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" +) + +type ArtifactPackage struct { + TaskType config.TaskType `bson:"type" json:"type"` + TaskStatus config.Status `bson:"status" json:"status"` + Enabled bool `bson:"enabled" json:"enabled"` + Timeout int `bson:"timeout,omitempty" json:"timeout,omitempty"` + Error string `bson:"error,omitempty" json:"error,omitempty"` + StartTime int64 `bson:"start_time,omitempty" json:"start_time,omitempty"` + EndTime int64 `bson:"end_time,omitempty" json:"end_time,omitempty"` + LogFile string `bson:"log_file" json:"log_file"` + + // source images + Images []*models.ImagesByService `bson:"images" json:"images"` + // source registries need auth to pull images + SourceRegistries []string `bson:"source_registries" json:"source_registries"` + // target registries to push images + TargetRegistries []string `bson:"target_registries" json:"target_registries"` +} + +func (ri *ArtifactPackage) ToSubTask() (map[string]interface{}, error) { + var task map[string]interface{} + if err := IToi(ri, &task); err != nil { + return nil, fmt.Errorf("convert ReleaseImageTask to interface error: %v", err) + } + return task, nil +} diff --git a/pkg/microservice/aslan/core/common/repository/models/task/model.go b/pkg/microservice/aslan/core/common/repository/models/task/model.go index c503d9c6f..d1d23f200 100644 --- a/pkg/microservice/aslan/core/common/repository/models/task/model.go +++ b/pkg/microservice/aslan/core/common/repository/models/task/model.go @@ -28,7 +28,7 @@ import ( ) type Task struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` TaskID int64 `bson:"task_id" json:"task_id"` ProductName string `bson:"product_name" json:"product_name"` PipelineName string `bson:"pipeline_name" json:"pipeline_name"` @@ -48,7 +48,7 @@ type Task struct { TeamName string `bson:"team,omitempty" json:"team,omitempty"` IsDeleted bool `bson:"is_deleted" json:"is_deleted"` IsArchived bool `bson:"is_archived" json:"is_archived"` - AgentID string `bson:"agent_id" json:"agent_id"` + AgentID string `bson:"agent_id" json:"agent_id"` // 是否允许同时运行多次 MultiRun bool `bson:"multi_run" json:"multi_run"` // target 服务名称, k8s为容器名称, 物理机为服务名 @@ -57,8 +57,7 @@ type Task struct { // 查询条件为 服务模板名称: ServiceTmpl, 版本: BuildModuleVer // 如果为空,则使用pipeline自定义SubTasks BuildModuleVer string `bson:"build_module_ver,omitempty" json:"build_module_ver"` - - ServiceName string `bson:"service_name,omitempty" json:"service_name,omitempty"` + ServiceName string `bson:"service_name,omitempty" json:"service_name,omitempty"` // TaskArgs 单服务工作流任务参数 TaskArgs *models.TaskArgs `bson:"task_args,omitempty" json:"task_args,omitempty"` // WorkflowArgs 多服务工作流任务参数 @@ -67,24 +66,22 @@ type Task struct { TestArgs *models.TestTaskArgs `bson:"test_args,omitempty" json:"test_args,omitempty"` // ServiceTaskArgs 脚本部署工作流任务参数 ServiceTaskArgs *models.ServiceTaskArgs `bson:"service_args,omitempty" json:"service_args,omitempty"` + // ArtifactPackageTaskArgs arguments for artifact-package type tasks + ArtifactPackageTaskArgs *models.ArtifactPackageTaskArgs `bson:"artifact_package_args,omitempty" json:"artifact_package_args,omitempty"` // ConfigPayload 系统配置信息 - ConfigPayload *models.ConfigPayload `json:"config_payload,omitempty"` - Error string `bson:"error,omitempty" json:"error,omitempty"` - Services [][]*models.ProductService `bson:"services" json:"services"` - Render *models.RenderInfo `bson:"render" json:"render"` - StorageURI string `bson:"storage_uri,omitempty" json:"storage_uri,omitempty"` + ConfigPayload *models.ConfigPayload `bson:"configpayload" json:"config_payload,omitempty"` + Error string `bson:"error,omitempty" json:"error,omitempty"` + Services [][]*models.ProductService `bson:"services" json:"services"` + Render *models.RenderInfo `bson:"render" json:"render"` + StorageURI string `bson:"storage_uri,omitempty" json:"storage_uri,omitempty"` // interface{} 为types.TestReport - TestReports map[string]interface{} `bson:"test_reports,omitempty" json:"test_reports,omitempty"` - - RwLock sync.Mutex `bson:"-" json:"-"` - - ResetImage bool `json:"resetImage" bson:"resetImage"` - - TriggerBy *models.TriggerBy `json:"trigger_by,omitempty" bson:"trigger_by,omitempty"` - - Features []string `bson:"features" json:"features"` - IsRestart bool `bson:"is_restart" json:"is_restart"` - StorageEndpoint string `bson:"storage_endpoint" json:"storage_endpoint"` + TestReports map[string]interface{} `bson:"test_reports,omitempty" json:"test_reports,omitempty"` + RwLock sync.Mutex `bson:"-" json:"-"` + ResetImage bool `json:"resetImage" bson:"resetImage"` + TriggerBy *models.TriggerBy `json:"trigger_by,omitempty" bson:"trigger_by,omitempty"` + Features []string `bson:"features" json:"features"` + IsRestart bool `bson:"is_restart" json:"is_restart"` + StorageEndpoint string `bson:"storage_endpoint" json:"storage_endpoint"` } //type RenderInfo struct { diff --git a/pkg/microservice/aslan/core/common/service/base/convert.go b/pkg/microservice/aslan/core/common/service/base/convert.go index b69135480..95ae17408 100644 --- a/pkg/microservice/aslan/core/common/service/base/convert.go +++ b/pkg/microservice/aslan/core/common/service/base/convert.go @@ -92,6 +92,14 @@ func ToReleaseImageTask(sb map[string]interface{}) (*task.ReleaseImage, error) { return t, nil } +func ToArtifactPackageImageTask(sb map[string]interface{}) (*task.ArtifactPackage, error) { + var t *task.ArtifactPackage + if err := task.IToi(sb, &t); err != nil { + return nil, fmt.Errorf("convert interface to ReleaseImageTask error: %v", err) + } + return t, nil +} + func ToJiraTask(sb map[string]interface{}) (*task.Jira, error) { var t *task.Jira if err := task.IToi(sb, &t); err != nil { diff --git a/pkg/microservice/aslan/core/common/service/config_payload.go b/pkg/microservice/aslan/core/common/service/config_payload.go index c4981fd53..87905f822 100644 --- a/pkg/microservice/aslan/core/common/service/config_payload.go +++ b/pkg/microservice/aslan/core/common/service/config_payload.go @@ -55,6 +55,7 @@ func GetConfigPayload(codeHostID int) *models.ConfigPayload { ReaperImage: config.ReaperImage(), ReaperBinaryFile: config.ReaperBinaryFile(), PredatorImage: config.PredatorImage(), + PackagerImage: config.PackagerImage(), }, Docker: models.DockerConfig{ HostList: config.DockerHosts(), diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go new file mode 100644 index 000000000..00ca9b6c0 --- /dev/null +++ b/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go @@ -0,0 +1,140 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package workflow + +import ( + "fmt" + "sort" + + "go.uber.org/zap" + "k8s.io/apimachinery/pkg/util/sets" + + "github.com/koderover/zadig/pkg/microservice/aslan/config" + commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/task" + taskmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/task" + commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" + commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/s3" + "github.com/koderover/zadig/pkg/setting" + e "github.com/koderover/zadig/pkg/tool/errors" + "github.com/koderover/zadig/pkg/util" +) + +func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, log *zap.SugaredLogger) error { + + // 获取全局configpayload + configPayload := commonservice.GetConfigPayload(0) + repos, err := commonrepo.NewRegistryNamespaceColl().FindAll(&commonrepo.FindRegOps{}) + + if err != nil { + log.Errorf("CreateArtifactPackageTask query registries failed, err: %s", err) + return fmt.Errorf("failed to query registries") + } + + registriesInvolved := sets.NewString() + registriesInvolved.Insert(args.SourceRegistries...) + registriesInvolved.Insert(args.TargetRegistries...) + + configPayload.RepoConfigs = make(map[string]*commonmodels.RegistryNamespace) + for _, repo := range repos { + if !registriesInvolved.Has(repo.ID.Hex()) { + continue + } + // if the registry is SWR, we need to modify ak/sk according to the rule + if repo.RegProvider == config.SWRProvider { + ak := fmt.Sprintf("%s@%s", repo.Region, repo.AccessKey) + sk := util.ComputeHmacSha256(repo.AccessKey, repo.SecretKey) + repo.AccessKey = ak + repo.SecretKey = sk + } + configPayload.RepoConfigs[repo.ID.Hex()] = repo + } + + defaultS3, err := s3.FindDefaultS3() + if err != nil { + err = e.ErrFindDefaultS3Storage.AddDesc("default storage is required by distribute task") + return err + } + + defaultURL, err := defaultS3.GetEncryptedURL() + if err != nil { + err = e.ErrS3Storage.AddErr(err) + return err + } + + task := &task.Task{ + Type: config.ArtifactType, + ProductName: args.ProjectName, + Status: config.StatusCreated, + ArtifactPackageTaskArgs: args, + ConfigPayload: configPayload, + StorageURI: defaultURL, + } + + subTask, err := (&taskmodels.ArtifactPackage{ + TaskType: config.TaskArtifactPackage, + Enabled: true, + TaskStatus: "", + Timeout: 0, + StartTime: 0, + EndTime: 0, + LogFile: "", + Images: args.Images, + SourceRegistries: args.SourceRegistries, + TargetRegistries: args.TargetRegistries, + }).ToSubTask() + + if err != nil { + return err + } + + task.SubTasks = []map[string]interface{}{subTask} + + if err := ensurePipelineTask(task, "", log); err != nil { + log.Errorf("CreateServiceTask ensurePipelineTask err : %v", err) + return err + } + + stages := make([]*commonmodels.Stage, 0) + for _, subTask := range task.SubTasks { + AddSubtaskToStage(&stages, subTask, args.EnvName) + } + sort.Sort(ByStageKind(stages)) + task.Stages = stages + if len(task.Stages) == 0 { + return e.ErrCreateTask.AddDesc(e.PipelineSubTaskNotFoundErrMsg) + } + + pipelineName := fmt.Sprintf("%s-%s-%s", args.ProjectName, args.EnvName, "artifact") + nextTaskID, err := commonrepo.NewCounterColl().GetNextSeq(fmt.Sprintf(setting.ServiceTaskFmt, pipelineName)) + if err != nil { + log.Errorf("CreateServiceTask Counter.GetNextSeq error: %v", err) + return e.ErrGetCounter.AddDesc(err.Error()) + } + + task.SubTasks = []map[string]interface{}{} + task.TaskID = nextTaskID + task.PipelineName = pipelineName + + if err := CreateTask(task); err != nil { + log.Error(err) + return e.ErrCreateTask + } + + return nil +} diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/convert.go b/pkg/microservice/aslan/core/workflow/service/workflow/convert.go index 4003a1c6c..9c8dc8c6e 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/convert.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/convert.go @@ -31,91 +31,93 @@ import ( func ConvertQueueToTask(queueTask *commonmodels.Queue) *task.Task { return &task.Task{ - TaskID: queueTask.TaskID, - ProductName: queueTask.ProductName, - PipelineName: queueTask.PipelineName, - Type: queueTask.Type, - Status: queueTask.Status, - Description: queueTask.Description, - TaskCreator: queueTask.TaskCreator, - TaskRevoker: queueTask.TaskRevoker, - CreateTime: queueTask.CreateTime, - StartTime: queueTask.StartTime, - EndTime: queueTask.EndTime, - SubTasks: queueTask.SubTasks, - Stages: queueTask.Stages, - ReqID: queueTask.ReqID, - AgentHost: queueTask.AgentHost, - DockerHost: queueTask.DockerHost, - TeamName: queueTask.TeamName, - IsDeleted: queueTask.IsDeleted, - IsArchived: queueTask.IsArchived, - AgentID: queueTask.AgentID, - MultiRun: queueTask.MultiRun, - Target: queueTask.Target, - BuildModuleVer: queueTask.BuildModuleVer, - ServiceName: queueTask.ServiceName, - TaskArgs: queueTask.TaskArgs, - WorkflowArgs: queueTask.WorkflowArgs, - TestArgs: queueTask.TestArgs, - ServiceTaskArgs: queueTask.ServiceTaskArgs, - ConfigPayload: queueTask.ConfigPayload, - Error: queueTask.Error, - Services: queueTask.Services, - Render: queueTask.Render, - StorageURI: queueTask.StorageURI, - TestReports: queueTask.TestReports, - RwLock: queueTask.RwLock, - ResetImage: queueTask.ResetImage, - TriggerBy: queueTask.TriggerBy, - Features: queueTask.Features, - IsRestart: queueTask.IsRestart, - StorageEndpoint: queueTask.StorageEndpoint, + TaskID: queueTask.TaskID, + ProductName: queueTask.ProductName, + PipelineName: queueTask.PipelineName, + Type: queueTask.Type, + Status: queueTask.Status, + Description: queueTask.Description, + TaskCreator: queueTask.TaskCreator, + TaskRevoker: queueTask.TaskRevoker, + CreateTime: queueTask.CreateTime, + StartTime: queueTask.StartTime, + EndTime: queueTask.EndTime, + SubTasks: queueTask.SubTasks, + Stages: queueTask.Stages, + ReqID: queueTask.ReqID, + AgentHost: queueTask.AgentHost, + DockerHost: queueTask.DockerHost, + TeamName: queueTask.TeamName, + IsDeleted: queueTask.IsDeleted, + IsArchived: queueTask.IsArchived, + AgentID: queueTask.AgentID, + MultiRun: queueTask.MultiRun, + Target: queueTask.Target, + BuildModuleVer: queueTask.BuildModuleVer, + ServiceName: queueTask.ServiceName, + TaskArgs: queueTask.TaskArgs, + WorkflowArgs: queueTask.WorkflowArgs, + TestArgs: queueTask.TestArgs, + ServiceTaskArgs: queueTask.ServiceTaskArgs, + ArtifactPackageTaskArgs: queueTask.ArtifactPackageTaskArgs, + ConfigPayload: queueTask.ConfigPayload, + Error: queueTask.Error, + Services: queueTask.Services, + Render: queueTask.Render, + StorageURI: queueTask.StorageURI, + TestReports: queueTask.TestReports, + RwLock: queueTask.RwLock, + ResetImage: queueTask.ResetImage, + TriggerBy: queueTask.TriggerBy, + Features: queueTask.Features, + IsRestart: queueTask.IsRestart, + StorageEndpoint: queueTask.StorageEndpoint, } } func ConvertTaskToQueue(task *task.Task) *commonmodels.Queue { return &commonmodels.Queue{ - TaskID: task.TaskID, - ProductName: task.ProductName, - PipelineName: task.PipelineName, - Type: task.Type, - Status: task.Status, - Description: task.Description, - TaskCreator: task.TaskCreator, - TaskRevoker: task.TaskRevoker, - CreateTime: task.CreateTime, - StartTime: task.StartTime, - EndTime: task.EndTime, - SubTasks: task.SubTasks, - Stages: task.Stages, - ReqID: task.ReqID, - AgentHost: task.AgentHost, - DockerHost: task.DockerHost, - TeamName: task.TeamName, - IsDeleted: task.IsDeleted, - IsArchived: task.IsArchived, - AgentID: task.AgentID, - MultiRun: task.MultiRun, - Target: task.Target, - BuildModuleVer: task.BuildModuleVer, - ServiceName: task.ServiceName, - TaskArgs: task.TaskArgs, - WorkflowArgs: task.WorkflowArgs, - TestArgs: task.TestArgs, - ServiceTaskArgs: task.ServiceTaskArgs, - ConfigPayload: task.ConfigPayload, - Error: task.Error, - Services: task.Services, - Render: task.Render, - StorageURI: task.StorageURI, - TestReports: task.TestReports, - RwLock: task.RwLock, - ResetImage: task.ResetImage, - TriggerBy: task.TriggerBy, - Features: task.Features, - IsRestart: task.IsRestart, - StorageEndpoint: task.StorageEndpoint, + TaskID: task.TaskID, + ProductName: task.ProductName, + PipelineName: task.PipelineName, + Type: task.Type, + Status: task.Status, + Description: task.Description, + TaskCreator: task.TaskCreator, + TaskRevoker: task.TaskRevoker, + CreateTime: task.CreateTime, + StartTime: task.StartTime, + EndTime: task.EndTime, + SubTasks: task.SubTasks, + Stages: task.Stages, + ReqID: task.ReqID, + AgentHost: task.AgentHost, + DockerHost: task.DockerHost, + TeamName: task.TeamName, + IsDeleted: task.IsDeleted, + IsArchived: task.IsArchived, + AgentID: task.AgentID, + MultiRun: task.MultiRun, + Target: task.Target, + BuildModuleVer: task.BuildModuleVer, + ServiceName: task.ServiceName, + TaskArgs: task.TaskArgs, + WorkflowArgs: task.WorkflowArgs, + TestArgs: task.TestArgs, + ServiceTaskArgs: task.ServiceTaskArgs, + ArtifactPackageTaskArgs: task.ArtifactPackageTaskArgs, + ConfigPayload: task.ConfigPayload, + Error: task.Error, + Services: task.Services, + Render: task.Render, + StorageURI: task.StorageURI, + TestReports: task.TestReports, + RwLock: task.RwLock, + ResetImage: task.ResetImage, + TriggerBy: task.TriggerBy, + Features: task.Features, + IsRestart: task.IsRestart, + StorageEndpoint: task.StorageEndpoint, } } diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go index 7c349f5f9..ef57ef162 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go @@ -2179,6 +2179,8 @@ func ensurePipelineTask(pt *task.Task, envName string, log *zap.SugaredLogger) e } case config.TaskDistribute: // 为了兼容历史数据类型,目前什么都不用做,避免出错 + case config.TaskArtifactPackage: + // do nothing default: return e.NewErrInvalidTaskType(string(pre.TaskType)) } diff --git a/pkg/microservice/packager/config/config.go b/pkg/microservice/packager/config/config.go new file mode 100644 index 000000000..76ed9e113 --- /dev/null +++ b/pkg/microservice/packager/config/config.go @@ -0,0 +1,33 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package config + +import ( + "github.com/spf13/viper" + + // init the config first + _ "github.com/koderover/zadig/pkg/config" + "github.com/koderover/zadig/pkg/setting" +) + +func JobConfigFile() string { + return viper.GetString(setting.JobConfigFile) +} + +func Home() string { + return viper.GetString(setting.Home) +} diff --git a/pkg/microservice/packager/core/service/packager.go b/pkg/microservice/packager/core/service/packager.go new file mode 100644 index 000000000..d58b587bc --- /dev/null +++ b/pkg/microservice/packager/core/service/packager.go @@ -0,0 +1,48 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package service + +type ImageData struct { + ImageUrl string `yaml:"image_url"` + ImageName string `yaml:"image_name"` + ImageTag string `yaml:"image_tag"` + RegistryID string `yaml:"registry_id,omitempty"` +} + +// ImagesByService defines all images in a service +type ImagesByService struct { + ServiceName string `yaml:"service_name"` + Images []*ImageData `yaml:"images"` +} + +//DockerRegistry registry host/user/password +type DockerRegistry struct { + RegistryID string `yaml:"registry_id"` + Host string `yaml:"host"` + UserName string `yaml:"username"` + Password string `yaml:"password"` + Namespace string `yaml:"namespace"` +} + +// Context parameters for job to run with +type Context struct { + JobType string `yaml:"job_type"` + ProgressFile string `yaml:"progress_file"` + Images []*ImagesByService `yaml:"images"` + SourceRegistries []*DockerRegistry `yaml:"source_registries"` + TargetRegistries []*DockerRegistry `yaml:"target_registries"` +} diff --git a/pkg/microservice/packager/core/service/service.go b/pkg/microservice/packager/core/service/service.go new file mode 100644 index 000000000..339ab5de9 --- /dev/null +++ b/pkg/microservice/packager/core/service/service.go @@ -0,0 +1,236 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package service + +import ( + "bytes" + "context" + "encoding/base64" + "encoding/json" + "fmt" + "os" + "path/filepath" + "strings" + "time" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/client" + "github.com/pkg/errors" + "gopkg.in/yaml.v3" + + "github.com/koderover/zadig/pkg/microservice/packager/config" + "github.com/koderover/zadig/pkg/tool/log" +) + +type Packager struct { + Ctx *Context +} + +type PackageResult struct { + ServiceName string `json:"service_name"` + Result string `json:"result"` + ErrorMsg string `json:"error_msg"` + ImageData []*ImageData `json:"image_data"` +} + +func NewPackager() (*Packager, error) { + context, err := os.ReadFile(config.JobConfigFile()) + if err != nil { + return nil, err + } + + var ctx *Context + if err := yaml.Unmarshal(context, &ctx); err != nil { + return nil, err + } + + packager := &Packager{ + Ctx: ctx, + } + + return packager, nil +} + +func buildRegistryMap(registries []*DockerRegistry) map[string]*DockerRegistry { + ret := make(map[string]*DockerRegistry) + for _, registry := range registries { + ret[registry.RegistryID] = registry + } + return ret +} + +func base64EncodeAuth(auth *types.AuthConfig) (string, error) { + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(auth); err != nil { + return "", err + } + return base64.URLEncoding.EncodeToString(buf.Bytes()), nil +} + +func buildTargetImage(imageName, imageTag, host, nameSpace string) string { + ret := "" + if len(nameSpace) > 0 { + ret = fmt.Sprintf("%s/%s/%s:%s", host, nameSpace, imageName, imageTag) + } else { + ret = fmt.Sprintf("%s/%s:%s", host, imageName, imageTag) + } + ret = strings.TrimPrefix(ret, "http://") + ret = strings.TrimPrefix(ret, "https://") + return ret +} + +func handleSingleService(imageByService *ImagesByService, allRegistries map[string]*DockerRegistry, targetRegistries []*DockerRegistry, dockerClient *client.Client) error { + targetImageUrlByRepo := make(map[string][]string) + for _, singleImage := range imageByService.Images { + options := types.ImagePullOptions{} + // for images from public repo,registryID won't be appointed + if len(singleImage.RegistryID) > 0 { + registryInfo, ok := allRegistries[singleImage.RegistryID] + if !ok { + return fmt.Errorf("failed to find source registry for image: %s", singleImage.ImageUrl) + } + encodedAuth, err := base64EncodeAuth(&types.AuthConfig{ + Username: registryInfo.UserName, + Password: registryInfo.Password, + ServerAddress: registryInfo.Host, + }) + if err != nil { + return errors.Wrapf(err, "faied to create docker pull auth data") + } + options.RegistryAuth = encodedAuth + } + + // pull image + _, err := dockerClient.ImagePull(context.TODO(), singleImage.ImageUrl, options) + if err != nil { + return errors.Wrapf(err, "failed to pull image: %s", singleImage.ImageUrl) + } + + // tag image + for _, registry := range targetRegistries { + targetImage := buildTargetImage(singleImage.ImageName, singleImage.ImageTag, registry.Host, registry.Namespace) + err = dockerClient.ImageTag(context.TODO(), singleImage.ImageUrl, targetImage) + if err != nil { + return errors.Wrapf(err, "failed to tag image from: %s to: %s", singleImage.ImageUrl, targetImage) + } + targetImageUrlByRepo[registry.RegistryID] = append(targetImageUrlByRepo[registry.RegistryID], targetImage) + } + } + + // push image + for _, registry := range targetRegistries { + encodedAuth, err := base64EncodeAuth(&types.AuthConfig{ + Username: registry.UserName, + Password: registry.Password, + ServerAddress: registry.Host, + }) + if err != nil { + return errors.Wrapf(err, "faied to create docker push auth data") + } + options := types.ImagePushOptions{ + RegistryAuth: encodedAuth, + } + for _, targetImageUrl := range targetImageUrlByRepo[registry.RegistryID] { + _, err = dockerClient.ImagePush(context.TODO(), targetImageUrl, options) + if err != nil { + return errors.Wrapf(err, "failed to push image: %s", targetImageUrl) + } + } + } + return nil +} + +func (p *Packager) Exec() error { + + // init docker client + cli, err := client.NewClientWithOpts(client.FromEnv) + if err != nil { + log.Errorf("failed to init docker client %s", err) + return err + } + + defer func() { + err = cli.Close() + if err != nil { + log.Errorf("failed to close client: %s", err) + } + }() + + // run docker info to ensure docker daemon connection + for i := 0; i < 120; i++ { + _, err := cli.Info(context.TODO()) + if err == nil { + break + } + log.Errorf("failed tor run docker info, try index: %d, err: %s", i, err) + time.Sleep(time.Second * 1) + } + + // create log file + if len(p.Ctx.ProgressFile) >= 0 { + if err := os.MkdirAll(filepath.Dir(p.Ctx.ProgressFile), 0770); err != nil { + return errors.Wrapf(err, "failed to create progress file dir") + } + file, err := os.Create(p.Ctx.ProgressFile) + if err != nil { + return errors.Wrapf(err, "failed to create progress file") + } + if err = file.Close(); err != nil { + return errors.Wrapf(err, "failed to close progress file") + } + } + + allRegistries := append(p.Ctx.SourceRegistries, p.Ctx.TargetRegistries...) + realTimeProgress := make([]*PackageResult, 0) + + for _, imageByService := range p.Ctx.Images { + result := &PackageResult{ + ServiceName: imageByService.ServiceName, + } + err = handleSingleService(imageByService, buildRegistryMap(allRegistries), p.Ctx.TargetRegistries, cli) + + if err != nil { + result.Result = "failed" + result.ErrorMsg = err.Error() + log.Errorf("[result][fail][%s][%s]", imageByService.ServiceName, err) + } else { + result.Result = "success" + result.ImageData = imageByService.Images + log.Infof("[result][success][%s]", imageByService.ServiceName) + } + + realTimeProgress = append(realTimeProgress, result) + + if len(p.Ctx.ProgressFile) > 0 { + bs, err := json.Marshal(realTimeProgress) + if err != nil { + log.Errorf("failed to marshal progress data %s", err) + continue + } + err = os.WriteFile(p.Ctx.ProgressFile, bs, 0644) + if err != nil { + log.Errorf("failed to write progress data %s", err) + continue + } + } + } + + // keep job alive for extra 10 seconds to make the runner be able to catch all progress info + // TODO need optimize + time.Sleep(time.Second * 10) + return nil +} diff --git a/pkg/microservice/packager/executor/executor.go b/pkg/microservice/packager/executor/executor.go new file mode 100644 index 000000000..840ca0134 --- /dev/null +++ b/pkg/microservice/packager/executor/executor.go @@ -0,0 +1,46 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package executor + +import ( + commonconfig "github.com/koderover/zadig/pkg/config" + "github.com/koderover/zadig/pkg/microservice/packager/core/service" + "github.com/koderover/zadig/pkg/setting" + "github.com/koderover/zadig/pkg/tool/log" +) + +func Execute() error { + log.Init(&log.Config{ + Level: commonconfig.LogLevel(), + NoCaller: true, + NoLogLevel: true, + Development: commonconfig.Mode() != setting.ReleaseMode, + }) + + packager, err := service.NewPackager() + if err != nil { + log.Errorf("Failed to start packager, error: %s", err) + return err + } + + if err := packager.Exec(); err != nil { + log.Errorf("Failed to run packager, error: %s", err) + return err + } + + return nil +} diff --git a/pkg/microservice/warpdrive/config/const.go b/pkg/microservice/warpdrive/config/const.go index 6e4fcaca3..380b211f5 100644 --- a/pkg/microservice/warpdrive/config/const.go +++ b/pkg/microservice/warpdrive/config/const.go @@ -19,20 +19,21 @@ package config type TaskType string const ( - TaskPipeline TaskType = "pipeline" - TaskBuild TaskType = "buildv2" - TaskArtifactDeploy TaskType = "artifact_deploy" - TaskJenkinsBuild TaskType = "jenkins_build" - TaskArtifact TaskType = "artifact" - TaskDeploy TaskType = "deploy" - TaskTestingV2 TaskType = "testingv2" - TaskDistributeToS3 TaskType = "distribute2kodo" - TaskReleaseImage TaskType = "release_image" - TaskJira TaskType = "jira" - TaskDockerBuild TaskType = "docker_build" - TaskSecurity TaskType = "security" - TaskResetImage TaskType = "reset_image" - TaskDistribute TaskType = "distribute" + TaskPipeline TaskType = "pipeline" + TaskBuild TaskType = "buildv2" + TaskArtifactDeploy TaskType = "artifact_deploy" + TaskJenkinsBuild TaskType = "jenkins_build" + TaskArtifact TaskType = "artifact" + TaskDeploy TaskType = "deploy" + TaskTestingV2 TaskType = "testingv2" + TaskDistributeToS3 TaskType = "distribute2kodo" + TaskReleaseImage TaskType = "release_image" + TaskJira TaskType = "jira" + TaskDockerBuild TaskType = "docker_build" + TaskSecurity TaskType = "security" + TaskResetImage TaskType = "reset_image" + TaskDistribute TaskType = "distribute" + TaskArtifactPackage TaskType = "artifact_package" ) type Status string @@ -55,16 +56,18 @@ const ( type PipelineType string const ( - // SingleType 单服务工作流 + // SingleType single-service workflow SingleType PipelineType = "single" - // WorkflowType 多服务工作流 + // WorkflowType multi-service workflow WorkflowType PipelineType = "workflow" - // FreestyleType 自由编排工作流 + // FreestyleType freeStyle workflow FreestyleType PipelineType = "freestyle" - // TestType 测试 + // TestType testing TestType PipelineType = "test" - // ServiceType 服务 + // ServiceType pipeline ServiceType PipelineType = "service" + // ArtifactType artifact build + ArtifactType PipelineType = "artifact" ) type NotifyType int diff --git a/pkg/microservice/warpdrive/core/service/taskcontroller/task_handler.go b/pkg/microservice/warpdrive/core/service/taskcontroller/task_handler.go index 301be7bf6..db98e0842 100644 --- a/pkg/microservice/warpdrive/core/service/taskcontroller/task_handler.go +++ b/pkg/microservice/warpdrive/core/service/taskcontroller/task_handler.go @@ -411,6 +411,9 @@ func (h *ExecHandler) executeTask(taskCtx context.Context, plugin plugins.TaskPl } else if pipelineTask.Type == config.ServiceType { fileName = strings.Replace(strings.ToLower(fmt.Sprintf("%s-%s-%d-%s-%s", config.ServiceType, pipelineTask.PipelineName, pipelineTask.TaskID, plugin.Type(), servicename)), "_", "-", -1) + } else if pipelineTask.Type == config.ArtifactType { + fileName = strings.Replace(strings.ToLower(fmt.Sprintf("%s-%s-%d-%s", config.ArtifactType, pipelineTask.PipelineName, pipelineTask.TaskID, plugin.Type())), + "_", "-", -1) } plugin.Init(jobName, fileName, xl) diff --git a/pkg/microservice/warpdrive/core/service/taskcontroller/task_helper.go b/pkg/microservice/warpdrive/core/service/taskcontroller/task_helper.go index b0a13595e..f8b7a57ee 100644 --- a/pkg/microservice/warpdrive/core/service/taskcontroller/task_helper.go +++ b/pkg/microservice/warpdrive/core/service/taskcontroller/task_helper.go @@ -136,6 +136,9 @@ func updatePipelineSubTask(t interface{}, pipelineTask *task.Task, pos int, serv } else if pipelineTask.Type == config.ServiceType { xl.Info("pipeline type is service type: pipeline 3.0") pipelineTask.Stages[pos].SubTasks[servicename] = subTask + } else if pipelineTask.Type == config.ArtifactType { + xl.Info("pipeline type is artifact-package type: pipeline 3.0") + pipelineTask.Stages[pos].SubTasks[servicename] = subTask } } @@ -538,17 +541,18 @@ func getSubTaskTypeAndIsRestart(subTask map[string]interface{}) bool { func initTaskPlugins(execHandler *ExecHandler) { pluginConf := map[config.TaskType]plugins.Initiator{ - config.TaskJira: plugins.InitializeJiraTaskPlugin, - config.TaskBuild: plugins.InitializeBuildTaskPlugin, - config.TaskArtifactDeploy: plugins.InitializeArtifactTaskPlugin, - config.TaskJenkinsBuild: plugins.InitializeJenkinsBuildPlugin, - config.TaskDockerBuild: plugins.InitializeDockerBuildTaskPlugin, - config.TaskDeploy: plugins.InitializeDeployTaskPlugin, - config.TaskTestingV2: plugins.InitializeTestTaskPlugin, - config.TaskSecurity: plugins.InitializeSecurityPlugin, - config.TaskReleaseImage: plugins.InitializeReleaseImagePlugin, - config.TaskDistributeToS3: plugins.InitializeDistribute2S3TaskPlugin, - config.TaskResetImage: plugins.InitializeDeployTaskPlugin, + config.TaskJira: plugins.InitializeJiraTaskPlugin, + config.TaskBuild: plugins.InitializeBuildTaskPlugin, + config.TaskArtifactDeploy: plugins.InitializeArtifactTaskPlugin, + config.TaskJenkinsBuild: plugins.InitializeJenkinsBuildPlugin, + config.TaskDockerBuild: plugins.InitializeDockerBuildTaskPlugin, + config.TaskDeploy: plugins.InitializeDeployTaskPlugin, + config.TaskTestingV2: plugins.InitializeTestTaskPlugin, + config.TaskSecurity: plugins.InitializeSecurityPlugin, + config.TaskReleaseImage: plugins.InitializeReleaseImagePlugin, + config.TaskDistributeToS3: plugins.InitializeDistribute2S3TaskPlugin, + config.TaskResetImage: plugins.InitializeDeployTaskPlugin, + config.TaskArtifactPackage: plugins.InitializeArtifactPackagePlugin, } for name, pluginInitiator := range pluginConf { registerTaskPlugin(execHandler, name, pluginInitiator) diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go b/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go new file mode 100644 index 000000000..a2eec1c00 --- /dev/null +++ b/pkg/microservice/warpdrive/core/service/taskplugin/artifact_package.go @@ -0,0 +1,422 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package taskplugin + +import ( + "context" + "fmt" + "time" + + "go.uber.org/zap" + "gopkg.in/yaml.v3" + "k8s.io/apimachinery/pkg/labels" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/koderover/zadig/pkg/microservice/warpdrive/config" + "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types" + "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types/task" + "github.com/koderover/zadig/pkg/setting" + "github.com/koderover/zadig/pkg/shared/kube/wrapper" + krkubeclient "github.com/koderover/zadig/pkg/tool/kube/client" + "github.com/koderover/zadig/pkg/tool/kube/getter" + "github.com/koderover/zadig/pkg/tool/kube/podexec" + "github.com/koderover/zadig/pkg/tool/kube/updater" +) + +// InitializeArtifactPackagePlugin to ini +func InitializeArtifactPackagePlugin(taskType config.TaskType) TaskPlugin { + return &ArtifactPackageTaskPlugin{ + Name: taskType, + kubeClient: krkubeclient.Client(), + } +} + +type ArtifactPackageTaskPlugin struct { + Name config.TaskType + KubeNamespace string + JobName string + FileName string + kubeClient client.Client + Task *task.ArtifactPackage + AckFunc func() + Log *zap.SugaredLogger + + RealTimeProgress string +} + +const ( + // ArtifactPackageBuildImageTaskTimeout ... + ArtifactPackageBuildImageTaskTimeout = 60 * 5 // 5 minutes +) + +// Init ... +func (p *ArtifactPackageTaskPlugin) Init(jobname, filename string, xl *zap.SugaredLogger) { + p.JobName = jobname + p.FileName = filename + // SetLogger ... + p.Log = xl +} + +func (p *ArtifactPackageTaskPlugin) SetAckFunc(f func()) { + p.AckFunc = f +} + +// Type ... +func (p *ArtifactPackageTaskPlugin) Type() config.TaskType { + return p.Name +} + +// Status ... +func (p *ArtifactPackageTaskPlugin) Status() config.Status { + return p.Task.TaskStatus +} + +// SetStatus ... +func (p *ArtifactPackageTaskPlugin) SetStatus(status config.Status) { + p.Task.TaskStatus = status +} + +func (p *ArtifactPackageTaskPlugin) SetProgress(progress string) { + p.Task.Progress = progress +} + +// TaskTimeout ... +func (p *ArtifactPackageTaskPlugin) TaskTimeout() int { + if p.Task.Timeout == 0 { + p.Task.Timeout = ArtifactPackageBuildImageTaskTimeout + } + return p.Task.Timeout +} + +func (p *ArtifactPackageTaskPlugin) Run(ctx context.Context, pipelineTask *task.Task, pipelineCtx *task.PipelineCtx, serviceName string) { + p.KubeNamespace = pipelineTask.ConfigPayload.Build.KubeNamespace + + sourceRegistries := make([]*types.DockerRegistry, 0) + for _, registryID := range pipelineTask.ArtifactPackageTaskArgs.SourceRegistries { + if registry, ok := pipelineTask.ConfigPayload.RepoConfigs[registryID]; ok { + sourceRegistries = append(sourceRegistries, &types.DockerRegistry{ + RegistryID: registryID, + Host: registry.RegAddr, + Namespace: registry.Namespace, + UserName: registry.AccessKey, + Password: registry.SecretKey, + }) + } + } + + targetRegistries := make([]*types.DockerRegistry, 0) + for _, registryID := range pipelineTask.ArtifactPackageTaskArgs.TargetRegistries { + if registry, ok := pipelineTask.ConfigPayload.RepoConfigs[registryID]; ok { + targetRegistries = append(targetRegistries, &types.DockerRegistry{ + RegistryID: registryID, + Host: registry.RegAddr, + Namespace: registry.Namespace, + UserName: registry.AccessKey, + Password: registry.SecretKey, + }) + } + } + + jobCtx := &types.ArtifactPackagerContext{ + JobType: setting.BuildChartPackage, + ProgressFile: setting.ProgressFile, + Images: pipelineTask.ArtifactPackageTaskArgs.Images, + SourceRegistries: sourceRegistries, + TargetRegistries: targetRegistries, + } + + jobCtxBytes, err := yaml.Marshal(jobCtx) + if err != nil { + msg := fmt.Sprintf("cannot mashal predetor.Context data: %v", err) + p.Log.Error(msg) + p.Task.TaskStatus = config.StatusFailed + p.Task.Error = msg + return + } + + p.Task.Error = "" + + jobLabel := &JobLabel{ + PipelineName: pipelineTask.PipelineName, + TaskID: pipelineTask.TaskID, + TaskType: string(p.Type()), + PipelineType: string(pipelineTask.Type), + } + + if err := ensureDeleteConfigMap(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + msg := fmt.Sprintf("ensureDeleteConfigMap error: %v", err) + p.Log.Error(msg) + p.Task.TaskStatus = config.StatusFailed + p.Task.Error = msg + return + } + + if err := createJobConfigMap( + p.KubeNamespace, p.JobName, jobLabel, string(jobCtxBytes), p.kubeClient); err != nil { + msg := fmt.Sprintf("createJobConfigMap error: %v", err) + p.Log.Error(msg) + p.Task.TaskStatus = config.StatusFailed + p.Task.Error = msg + return + } + p.Log.Infof("succeed to create cm for artifact package job %s", p.JobName) + + job, err := buildJob(p.Type(), pipelineTask.ConfigPayload.Release.PackagerImage, p.JobName, serviceName, "", pipelineTask.ConfigPayload.Build.KubeNamespace, setting.MinRequest, setting.LowRequestSpec, pipelineCtx, pipelineTask, []*task.RegistryNamespace{}) + if err != nil { + msg := fmt.Sprintf("create release artifact package job context error: %v", err) + p.Log.Error(msg) + p.Task.TaskStatus = config.StatusFailed + p.Task.Error = msg + return + } + + if err := ensureDeleteJob(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + msg := fmt.Sprintf("delete release artifact package job error: %v", err) + p.Log.Error(msg) + p.Task.TaskStatus = config.StatusFailed + p.Task.Error = msg + return + } + + job.Namespace = p.KubeNamespace + if err := updater.CreateJob(job, p.kubeClient); err != nil { + msg := fmt.Sprintf("create release image job error: %v", err) + p.Log.Error(msg) + p.Task.TaskStatus = config.StatusFailed + p.Task.Error = msg + return + } + p.Log.Infof("succeed to create artifact package job %s", p.JobName) +} + +// SetTask ... +func (p *ArtifactPackageTaskPlugin) SetTask(t map[string]interface{}) error { + task, err := ToArtifactTask(t) + if err != nil { + return err + } + p.Task = task + return nil +} + +// GetTask ... +func (p *ArtifactPackageTaskPlugin) GetTask() interface{} { + return p.Task +} + +// Wait ... +func (p *ArtifactPackageTaskPlugin) Wait(ctx context.Context) { + + status := p.waitJobStart() + if status != config.StatusRunning { + p.SetStatus(status) + return + } + + status = p.waitJobEnd(ctx, p.TaskTimeout()) + p.SetProgress(p.RealTimeProgress) + p.SetStatus(status) +} + +func (p *ArtifactPackageTaskPlugin) waitJobStart() config.Status { + namespace, jobName, kubeClient, xl := p.KubeNamespace, p.JobName, p.kubeClient, p.Log + xl.Infof("wait job to start: %s/%s", namespace, jobName) + podTimeout := time.After(120 * time.Second) + var started bool + for { + select { + case <-podTimeout: + return config.StatusTimeout + default: + job, _, err := getter.GetJob(namespace, jobName, kubeClient) + if err != nil { + xl.Errorf("get job failed, namespace:%s, jobName:%s, err:%v", namespace, jobName, err) + } + if job != nil { + started = job.Status.Active > 0 + } + } + if started { + break + } + + time.Sleep(time.Second) + } + return config.StatusRunning +} + +func (p *ArtifactPackageTaskPlugin) waitJobEnd(ctx context.Context, taskTimeout int) (status config.Status) { + namespace, jobName, kubeClient, xl := p.KubeNamespace, p.JobName, p.kubeClient, p.Log + xl.Infof("wait job to start: %s/%s", namespace, jobName) + timeout := time.After(time.Duration(taskTimeout) * time.Second) + + // 等待job 运行结束 + xl.Infof("wait job to end: %s %s", namespace, jobName) + for { + select { + case <-ctx.Done(): + return config.StatusCancelled + + case <-timeout: + return config.StatusTimeout + + default: + job, found, err := getter.GetJob(namespace, jobName, kubeClient) + if err != nil || !found { + xl.Errorf("failed to get pod with label job-name=%s %v", jobName, err) + return config.StatusFailed + } + // pod is still running + if job.Status.Active != 0 { + + pods, err := getter.ListPods(namespace, labels.Set{"job-name": jobName}.AsSelector(), kubeClient) + if err != nil { + xl.Errorf("failed to find pod with label job-name=%s %v", jobName, err) + return config.StatusFailed + } + + var done bool + for _, pod := range pods { + ipod := wrapper.Pod(pod) + if ipod.Pending() { + continue + } + if ipod.Failed() { + return config.StatusFailed + } + + if !ipod.Finished() { + progressInfo, err := getProgressInfo(namespace, ipod.Name, ipod.ContainerNames()[0], setting.ProgressFile) + if err != nil { + xl.Infof("failed to check dog food file %s %v", pods[0].Name, err) + break + } + p.RealTimeProgress = progressInfo + xl.Infof("find progress info %s", progressInfo) + p.SetProgress(progressInfo) + p.SetStatus(config.StatusRunning) + + if p.AckFunc != nil { + p.AckFunc() + } + } else { + done = true + } + } + + if done { + return config.StatusPassed + } + } else if job.Status.Succeeded != 0 { + return config.StatusPassed + } else { + return config.StatusFailed + } + } + + time.Sleep(time.Second * 5) + } + +} + +// Complete ... +func (p *ArtifactPackageTaskPlugin) Complete(ctx context.Context, pipelineTask *task.Task, serviceName string) { + jobLabel := &JobLabel{ + PipelineName: pipelineTask.PipelineName, + ServiceName: serviceName, + TaskID: pipelineTask.TaskID, + TaskType: string(p.Type()), + PipelineType: string(pipelineTask.Type), + } + + // 清理用户取消和超时的任务 + defer func() { + if p.Task.TaskStatus == config.StatusCancelled || p.Task.TaskStatus == config.StatusTimeout { + if err := ensureDeleteJob(p.KubeNamespace, jobLabel, p.kubeClient); err != nil { + p.Log.Error(err) + p.Task.Error = err.Error() + } + return + } + }() + + // 保存实时日志到s3 + err := saveContainerLog(pipelineTask, p.KubeNamespace, "", p.FileName, jobLabel, p.kubeClient) + if err != nil { + p.Log.Error(err) + p.Task.Error = err.Error() + return + } + + p.Task.LogFile = p.JobName +} + +// IsTaskDone ... +func (p *ArtifactPackageTaskPlugin) IsTaskDone() bool { + if p.Task.TaskStatus != config.StatusCreated && p.Task.TaskStatus != config.StatusRunning { + return true + } + return false +} + +// IsTaskFailed ... +func (p *ArtifactPackageTaskPlugin) IsTaskFailed() bool { + if p.Task.TaskStatus == config.StatusFailed || p.Task.TaskStatus == config.StatusTimeout || p.Task.TaskStatus == config.StatusCancelled { + return true + } + return false +} + +// SetStartTime ... +func (p *ArtifactPackageTaskPlugin) SetStartTime() { + p.Task.StartTime = time.Now().Unix() +} + +// SetEndTime ... +func (p *ArtifactPackageTaskPlugin) SetEndTime() { + p.Task.EndTime = time.Now().Unix() +} + +// IsTaskEnabled ... +func (p *ArtifactPackageTaskPlugin) IsTaskEnabled() bool { + return p.Task.Enabled +} + +// ResetError ... +func (p *ArtifactPackageTaskPlugin) ResetError() { + p.Task.Error = "" +} + +func getProgressInfo(namespace string, pod string, container string, progressInfoFile string) (string, error) { + stdOut, stdErr, success, err := podexec.ExecWithOptions(podexec.ExecOptions{ + Command: []string{"cat", progressInfoFile}, + Namespace: namespace, + PodName: pod, + ContainerName: container, + }) + + if err != nil { + return "", err + } + if len(stdErr) != 0 { + return "", fmt.Errorf(stdErr) + } + if !success { + return "", fmt.Errorf("pod exec execute failed") + } + return stdOut, nil +} diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/job.go b/pkg/microservice/warpdrive/core/service/taskplugin/job.go index 1d889e59f..bfcce997b 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/job.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/job.go @@ -58,6 +58,7 @@ const ( defaultSecretEmail = "bot@koderover.com" PredatorPlugin = "predator-plugin" JenkinsPlugin = "jenkins-plugin" + PackagerPlugin = "packager-plugin" NormalSchedule = "normal" RequiredSchedule = "required" PreferredSchedule = "preferred" @@ -118,6 +119,7 @@ func saveContainerLog(pipelineTask *task.Task, namespace, clusterID, fileName st if err = saveFile(buf, tempFileName); err == nil { var store *s3.S3 if store, err = s3.NewS3StorageFromEncryptedURI(pipelineTask.StorageURI); err != nil { + log.Errorf("failed to NewS3StorageFromEncryptedURI ") return err } if store.Subfolder != "" { @@ -364,12 +366,19 @@ const ( // getJobLabels get labels k-v map from JobLabel struct func getJobLabels(jobLabel *JobLabel) map[string]string { - return map[string]string{ + retMap := map[string]string{ jobLabelTaskKey: fmt.Sprintf("%s-%d", strings.ToLower(jobLabel.PipelineName), jobLabel.TaskID), jobLabelServiceKey: strings.ToLower(jobLabel.ServiceName), jobLabelSTypeKey: strings.Replace(jobLabel.TaskType, "_", "-", -1), jobLabelPTypeKey: jobLabel.PipelineType, } + // no need to add labels with empty value to a job + for k, v := range retMap { + if len(v) == 0 { + delete(retMap, k) + } + } + return retMap } func createJobConfigMap(namespace, jobName string, jobLabel *JobLabel, jobCtx string, kubeClient client.Client) error { @@ -424,7 +433,7 @@ func buildJobWithLinkedNs(taskType config.TaskType, jobImage, jobName, serviceNa reaperBinaryFile = strings.Replace(reaperBinaryFile, ResourceServer, ResourceServer+"."+currentNamespace, -1) } - if !strings.Contains(jobImage, PredatorPlugin) && !strings.Contains(jobImage, JenkinsPlugin) { + if !strings.Contains(jobImage, PredatorPlugin) && !strings.Contains(jobImage, JenkinsPlugin) && !strings.Contains(jobImage, PackagerPlugin) { reaperBootingScript = fmt.Sprintf("curl -m 60 --retry-delay 5 --retry 3 -sL %s -o reaper && chmod +x reaper && mv reaper /usr/local/bin && /usr/local/bin/reaper", reaperBinaryFile) if pipelineTask.ConfigPayload.Proxy.EnableApplicationProxy && pipelineTask.ConfigPayload.Proxy.Type == "http" { reaperBootingScript = fmt.Sprintf("curl -m 60 --retry-delay 5 --retry 3 -sL --proxy %s %s -o reaper && chmod +x reaper && mv reaper /usr/local/bin && /usr/local/bin/reaper", @@ -505,7 +514,7 @@ func buildJobWithLinkedNs(taskType config.TaskType, jobImage, jobName, serviceNa }, } - if !strings.Contains(jobImage, PredatorPlugin) && !strings.Contains(jobImage, JenkinsPlugin) { + if !strings.Contains(jobImage, PredatorPlugin) && !strings.Contains(jobImage, JenkinsPlugin) && !strings.Contains(jobImage, PackagerPlugin) { job.Spec.Template.Spec.Containers[0].Command = []string{"/bin/sh", "-c"} job.Spec.Template.Spec.Containers[0].Args = []string{reaperBootingScript} } diff --git a/pkg/microservice/warpdrive/core/service/taskplugin/utils.go b/pkg/microservice/warpdrive/core/service/taskplugin/utils.go index 6d4111015..35236b813 100644 --- a/pkg/microservice/warpdrive/core/service/taskplugin/utils.go +++ b/pkg/microservice/warpdrive/core/service/taskplugin/utils.go @@ -98,7 +98,7 @@ type Preview struct { func ToPreview(sb map[string]interface{}) (*Preview, error) { var pre *Preview if err := IToi(sb, &pre); err != nil { - return nil, fmt.Errorf("convert interface to SubTaskPreview error: %v", err) + return nil, fmt.Errorf("convert interface to SubTaskPreview error: %s", err) } return pre, nil } @@ -106,15 +106,15 @@ func ToPreview(sb map[string]interface{}) (*Preview, error) { func ToBuildTask(sb map[string]interface{}) (*task.Build, error) { var t *task.Build if err := IToi(sb, &t); err != nil { - return nil, fmt.Errorf("convert interface to BuildTaskV2 error: %v", err) + return nil, fmt.Errorf("convert interface to BuildTaskV2 error: %s", err) } return t, nil } -func ToArtifactTask(sb map[string]interface{}) (*task.Artifact, error) { - var t *task.Artifact +func ToArtifactTask(sb map[string]interface{}) (*task.ArtifactPackage, error) { + var t *task.ArtifactPackage if err := IToi(sb, &t); err != nil { - return nil, fmt.Errorf("convert interface to ArtifactTask error: %v", err) + return nil, fmt.Errorf("convert interface to ArtifactTask error: %s", err) } return t, nil } @@ -122,7 +122,7 @@ func ToArtifactTask(sb map[string]interface{}) (*task.Artifact, error) { func ToDockerBuildTask(sb map[string]interface{}) (*task.DockerBuild, error) { var t *task.DockerBuild if err := IToi(sb, &t); err != nil { - return nil, fmt.Errorf("convert interface to DockerBuildTask error: %v", err) + return nil, fmt.Errorf("convert interface to DockerBuildTask error: %s", err) } return t, nil } @@ -130,7 +130,7 @@ func ToDockerBuildTask(sb map[string]interface{}) (*task.DockerBuild, error) { func ToDeployTask(sb map[string]interface{}) (*task.Deploy, error) { var t *task.Deploy if err := IToi(sb, &t); err != nil { - return nil, fmt.Errorf("convert interface to DeployTask error: %v", err) + return nil, fmt.Errorf("convert interface to DeployTask error: %s", err) } return t, nil } @@ -138,7 +138,7 @@ func ToDeployTask(sb map[string]interface{}) (*task.Deploy, error) { func ToTestingTask(sb map[string]interface{}) (*task.Testing, error) { var t *task.Testing if err := IToi(sb, &t); err != nil { - return nil, fmt.Errorf("convert interface to Testing error: %v", err) + return nil, fmt.Errorf("convert interface to Testing error: %s", err) } return t, nil } @@ -146,7 +146,7 @@ func ToTestingTask(sb map[string]interface{}) (*task.Testing, error) { func ToDistributeToS3Task(sb map[string]interface{}) (*task.DistributeToS3, error) { var t *task.DistributeToS3 if err := IToi(sb, &t); err != nil { - return nil, fmt.Errorf("convert interface to DistributeToS3Task error: %v", err) + return nil, fmt.Errorf("convert interface to DistributeToS3Task error: %s", err) } return t, nil } @@ -154,15 +154,23 @@ func ToDistributeToS3Task(sb map[string]interface{}) (*task.DistributeToS3, erro func ToReleaseImageTask(sb map[string]interface{}) (*task.ReleaseImage, error) { var t *task.ReleaseImage if err := IToi(sb, &t); err != nil { - return nil, fmt.Errorf("convert interface to ReleaseImageTask error: %v", err) + return nil, fmt.Errorf("convert interface to ReleaseImageTask error: %s", err) } return t, nil } +func ToArtifactPackageTask(sb map[string]interface{}) (*task.ArtifactPackageTaskArgs, error) { + var ret *task.ArtifactPackageTaskArgs + if err := IToi(sb, &ret); err != nil { + return nil, fmt.Errorf("convert interface to ArtifactPackageTaskArgs error: %s", err) + } + return ret, nil +} + func ToJiraTask(sb map[string]interface{}) (*task.Jira, error) { var t *task.Jira if err := IToi(sb, &t); err != nil { - return nil, fmt.Errorf("convert interface to JiraTask error: %v", err) + return nil, fmt.Errorf("convert interface to JiraTask error: %s", err) } return t, nil } @@ -170,7 +178,7 @@ func ToJiraTask(sb map[string]interface{}) (*task.Jira, error) { func ToSecurityTask(sb map[string]interface{}) (*task.Security, error) { var t *task.Security if err := IToi(sb, &t); err != nil { - return nil, fmt.Errorf("convert interface to securityTask error: %v", err) + return nil, fmt.Errorf("convert interface to securityTask error: %s", err) } return t, nil } @@ -178,7 +186,7 @@ func ToSecurityTask(sb map[string]interface{}) (*task.Security, error) { func ToJenkinsBuildTask(sb map[string]interface{}) (*task.JenkinsBuild, error) { var task *task.JenkinsBuild if err := IToi(sb, &task); err != nil { - return nil, fmt.Errorf("convert interface to JenkinsBuildTask error: %v", err) + return nil, fmt.Errorf("convert interface to JenkinsBuildTask error: %s", err) } return task, nil } @@ -186,11 +194,11 @@ func ToJenkinsBuildTask(sb map[string]interface{}) (*task.JenkinsBuild, error) { func IToi(before interface{}, after interface{}) error { b, err := json.Marshal(before) if err != nil { - return fmt.Errorf("marshal task error: %v", err) + return fmt.Errorf("marshal task error: %s", err) } if err := json.Unmarshal(b, &after); err != nil { - return fmt.Errorf("unmarshal task error: %v", err) + return fmt.Errorf("unmarshal task error: %s", err) } return nil diff --git a/pkg/microservice/warpdrive/core/service/types/packager.go b/pkg/microservice/warpdrive/core/service/types/packager.go new file mode 100644 index 000000000..19aac50ae --- /dev/null +++ b/pkg/microservice/warpdrive/core/service/types/packager.go @@ -0,0 +1,27 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package types + +import "github.com/koderover/zadig/pkg/microservice/warpdrive/core/service/types/task" + +type ArtifactPackagerContext struct { + JobType string `yaml:"job_type"` + ProgressFile string `yaml:"progress_file"` + Images []*task.ImagesByService `yaml:"images"` + SourceRegistries []*DockerRegistry `yaml:"source_registries"` + TargetRegistries []*DockerRegistry `yaml:"target_registries"` +} diff --git a/pkg/microservice/warpdrive/core/service/types/reaper.go b/pkg/microservice/warpdrive/core/service/types/reaper.go index c3fa2fa75..ca4f4ec1d 100644 --- a/pkg/microservice/warpdrive/core/service/types/reaper.go +++ b/pkg/microservice/warpdrive/core/service/types/reaper.go @@ -270,10 +270,11 @@ type GinkgoTest struct { // DockerRegistry 推送镜像到 docker registry 配置 type DockerRegistry struct { - Host string `yaml:"host"` - Namespace string `yaml:"namespace"` - UserName string `yaml:"username"` - Password string `yaml:"password"` + RegistryID string `yaml:"registry_id"` + Host string `yaml:"host"` + Namespace string `yaml:"namespace"` + UserName string `yaml:"username"` + Password string `yaml:"password"` } // Git ... diff --git a/pkg/microservice/warpdrive/core/service/types/task/artifact_package.go b/pkg/microservice/warpdrive/core/service/types/task/artifact_package.go new file mode 100644 index 000000000..9ac39d95a --- /dev/null +++ b/pkg/microservice/warpdrive/core/service/types/task/artifact_package.go @@ -0,0 +1,50 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package task + +import ( + "fmt" + + "github.com/koderover/zadig/pkg/microservice/warpdrive/config" +) + +type ArtifactPackage struct { + TaskType config.TaskType `bson:"type" json:"type"` + Enabled bool `bson:"enabled" json:"enabled"` + TaskStatus config.Status `bson:"status" json:"status"` + Progress string `bson:"progress" json:"progress"` + Timeout int `bson:"timeout,omitempty" json:"timeout,omitempty"` + Error string `bson:"error,omitempty" json:"error,omitempty"` + StartTime int64 `bson:"start_time,omitempty" json:"start_time,omitempty"` + EndTime int64 `bson:"end_time,omitempty" json:"end_time,omitempty"` + LogFile string `bson:"log_file" json:"log_file"` + + // source images + Images []*ImagesByService `bson:"images" json:"images"` + // target registries to push images + SourceRegistries []string `bson:"source_registries" json:"source_registries"` + // target registries to push images + TargetRegistries []string `bson:"target_registries" json:"target_registries"` +} + +func (ri *ArtifactPackage) ToSubTask() (map[string]interface{}, error) { + var task map[string]interface{} + if err := IToi(ri, &task); err != nil { + return nil, fmt.Errorf("convert ReleaseImageTask to interface error: %v", err) + } + return task, nil +} diff --git a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go index cd6fb6267..caca4a5a5 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go +++ b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go @@ -133,6 +133,9 @@ type ReleaseConfig struct { // PredatorImage sets docker build image // e.g. xxx.com/resources/predator-plugin:v0.1.0 PredatorImage string + // PackagerImage sets docker build image + // e.g. xxx.com/resources/predator-plugin:v0.1.0 + PackagerImage string } type ImageReleaseConfig struct { diff --git a/pkg/microservice/warpdrive/core/service/types/task/model.go b/pkg/microservice/warpdrive/core/service/types/task/model.go index d6a0d9751..e3f776067 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/model.go +++ b/pkg/microservice/warpdrive/core/service/types/task/model.go @@ -64,6 +64,8 @@ type Task struct { TestArgs *TestTaskArgs `bson:"test_args,omitempty" json:"test_args,omitempty"` // ServiceTaskArgs 脚本部署工作流任务参数 ServiceTaskArgs *ServiceTaskArgs `bson:"service_args,omitempty" json:"service_args,omitempty"` + // ArtifactPackageTaskArgs arguments for artifact-package type tasks + ArtifactPackageTaskArgs *ArtifactPackageTaskArgs `bson:"artifact_package_args,omitempty" json:"artifact_package_args,omitempty"` // ConfigPayload 系统配置信息 ConfigPayload *ConfigPayload `json:"config_payload,omitempty"` Error string `bson:"error,omitempty" json:"error,omitempty"` @@ -243,6 +245,25 @@ type ServiceTaskArgs struct { Updatable bool `bson:"updatable" json:"updatable"` } +type ImageData struct { + ImageUrl string `bson:"image_url" json:"image_url" yaml:"image_url"` + ImageName string `bson:"image_name" json:"image_name" yaml:"image_name"` + ImageTag string `bson:"image_tag" json:"image_tag" yaml:"image_tag"` + RegistryID string `bson:"registry_id" json:"registry_id" yaml:"registry_id"` +} + +type ImagesByService struct { + ServiceName string `bson:"service_name" json:"service_name" yaml:"service_name"` + Images []*ImageData `bson:"images" json:"images" yaml:"images"` +} + +type ArtifactPackageTaskArgs struct { + ProductName string `bson:"product_name" json:"product_name"` + Images []*ImagesByService `bson:"images" json:"images"` + SourceRegistries []string `bson:"source_registries" json:"source_registries"` + TargetRegistries []string `bson:"target_registries" json:"target_registries"` +} + type ProductService struct { ServiceName string `bson:"service_name" json:"service_name"` ProductName string `bson:"product_name" json:"product_name"` diff --git a/pkg/setting/consts.go b/pkg/setting/consts.go index 02085f398..df2c1159d 100644 --- a/pkg/setting/consts.go +++ b/pkg/setting/consts.go @@ -50,6 +50,7 @@ const ( ENVReaperImage = "REAPER_IMAGE" ENVReaperBinaryFile = "REAPER_BINARY_FILE" ENVPredatorImage = "PREDATOR_IMAGE" + EnvPackagerImage = "PACKAGER_IMAGE" ENVDockerHosts = "DOCKER_HOSTS" @@ -299,6 +300,10 @@ const ( ReleaseImageJob = "docker-release" ) +const ( + BuildChartPackage = "chart-package" +) + const ( JenkinsBuildJob = "jenkins-build" ) @@ -525,6 +530,8 @@ const MaxTries = 1 const DogFood = "/var/run/koderover-dog-food" +const ProgressFile = "/var/log/job-progress" + const ( ResponseError = "error" ResponseData = "response" -- Gitee From 3c001439de472b740df5ae98570ad27442c7b917 Mon Sep 17 00:00:00 2001 From: allenshen Date: Fri, 10 Dec 2021 14:09:21 +0800 Subject: [PATCH 114/134] fix image missing bug Signed-off-by: allenshen --- .../aslan/core/delivery/service/version.go | 2 - .../packager/core/service/packager.go | 8 +- .../packager/core/service/service.go | 85 ++++++++++++++++--- 3 files changed, 77 insertions(+), 18 deletions(-) diff --git a/pkg/microservice/aslan/core/delivery/service/version.go b/pkg/microservice/aslan/core/delivery/service/version.go index 961cdcfb7..7bba266c3 100644 --- a/pkg/microservice/aslan/core/delivery/service/version.go +++ b/pkg/microservice/aslan/core/delivery/service/version.go @@ -1348,8 +1348,6 @@ func GetChartVersions(chartName, chartRepoName string) ([]*ChartVersionResp, err return nil, errors.Wrapf(getChartmuseumError(b, resp.StatusCode), "failed to download index.yaml") } - log.Infof("###### the raw data is %s", string(b)) - index, err := helm.LoadIndex(b) if err != nil { return nil, errors.Wrapf(err, "failed to parse index.yaml") diff --git a/pkg/microservice/packager/core/service/packager.go b/pkg/microservice/packager/core/service/packager.go index d58b587bc..8f9e41da9 100644 --- a/pkg/microservice/packager/core/service/packager.go +++ b/pkg/microservice/packager/core/service/packager.go @@ -17,10 +17,10 @@ limitations under the License. package service type ImageData struct { - ImageUrl string `yaml:"image_url"` - ImageName string `yaml:"image_name"` - ImageTag string `yaml:"image_tag"` - RegistryID string `yaml:"registry_id,omitempty"` + ImageUrl string `yaml:"image_url" json:"image_url"` + ImageName string `yaml:"image_name" json:"image_name"` + ImageTag string `yaml:"image_tag" json:"image_tag"` + RegistryID string `yaml:"registry_id" json:"registry_id"` } // ImagesByService defines all images in a service diff --git a/pkg/microservice/packager/core/service/service.go b/pkg/microservice/packager/core/service/service.go index 339ab5de9..ba4e036e5 100644 --- a/pkg/microservice/packager/core/service/service.go +++ b/pkg/microservice/packager/core/service/service.go @@ -22,6 +22,7 @@ import ( "encoding/base64" "encoding/json" "fmt" + "io" "os" "path/filepath" "strings" @@ -93,15 +94,68 @@ func buildTargetImage(imageName, imageTag, host, nameSpace string) string { return ret } -func handleSingleService(imageByService *ImagesByService, allRegistries map[string]*DockerRegistry, targetRegistries []*DockerRegistry, dockerClient *client.Client) error { +func pullImage(dockerClient *client.Client, imageUrl string, options *types.ImagePullOptions) error { + // pull image + pullResponse, err := dockerClient.ImagePull(context.TODO(), imageUrl, *options) + if err != nil { + return err + } + + defer func(pullResponse io.ReadCloser) { + err := pullResponse.Close() + if err != nil { + log.Errorf("failed to close response reader") + } + }(pullResponse) + + bs, err := io.ReadAll(pullResponse) + if err != nil { + return err + } + + if strings.Contains(string(bs), "error") { + log.Errorf("image push failed: %s", string(bs)) + return fmt.Errorf("failed to push image") + } + return nil +} + +func pushImage(dockerClient *client.Client, targetImageUrl string, options *types.ImagePushOptions) error { + pushResponse, err := dockerClient.ImagePush(context.TODO(), targetImageUrl, *options) + if err != nil { + return errors.Wrapf(err, "failed to push image: %s", targetImageUrl) + } + + defer func(pullResponse io.ReadCloser) { + err := pullResponse.Close() + if err != nil { + log.Errorf("failed to close response reader") + } + }(pushResponse) + + bs, err := io.ReadAll(pushResponse) + if err != nil { + return err + } + + if strings.Contains(string(bs), "error") { + log.Errorf("image push failed: %s", string(bs)) + return fmt.Errorf("failed to push image") + } + return nil +} + +func handleSingleService(imageByService *ImagesByService, allRegistries map[string]*DockerRegistry, targetRegistries []*DockerRegistry, dockerClient *client.Client) ([]*ImageData, error) { targetImageUrlByRepo := make(map[string][]string) + retImages := make([]*ImageData, 0) + for _, singleImage := range imageByService.Images { options := types.ImagePullOptions{} // for images from public repo,registryID won't be appointed if len(singleImage.RegistryID) > 0 { registryInfo, ok := allRegistries[singleImage.RegistryID] if !ok { - return fmt.Errorf("failed to find source registry for image: %s", singleImage.ImageUrl) + return nil, fmt.Errorf("failed to find source registry for image: %s", singleImage.ImageUrl) } encodedAuth, err := base64EncodeAuth(&types.AuthConfig{ Username: registryInfo.UserName, @@ -109,15 +163,15 @@ func handleSingleService(imageByService *ImagesByService, allRegistries map[stri ServerAddress: registryInfo.Host, }) if err != nil { - return errors.Wrapf(err, "faied to create docker pull auth data") + return nil, errors.Wrapf(err, "faied to create docker pull auth data") } options.RegistryAuth = encodedAuth } // pull image - _, err := dockerClient.ImagePull(context.TODO(), singleImage.ImageUrl, options) + err := pullImage(dockerClient, singleImage.ImageUrl, &options) if err != nil { - return errors.Wrapf(err, "failed to pull image: %s", singleImage.ImageUrl) + return nil, errors.Wrapf(err, "failed to pull image: %s", singleImage.ImageUrl) } // tag image @@ -125,9 +179,15 @@ func handleSingleService(imageByService *ImagesByService, allRegistries map[stri targetImage := buildTargetImage(singleImage.ImageName, singleImage.ImageTag, registry.Host, registry.Namespace) err = dockerClient.ImageTag(context.TODO(), singleImage.ImageUrl, targetImage) if err != nil { - return errors.Wrapf(err, "failed to tag image from: %s to: %s", singleImage.ImageUrl, targetImage) + return nil, errors.Wrapf(err, "failed to tag image from: %s to: %s", singleImage.ImageUrl, targetImage) } targetImageUrlByRepo[registry.RegistryID] = append(targetImageUrlByRepo[registry.RegistryID], targetImage) + retImages = append(retImages, &ImageData{ + ImageUrl: targetImage, + ImageName: singleImage.ImageName, + ImageTag: singleImage.ImageTag, + RegistryID: singleImage.RegistryID, + }) } } @@ -139,19 +199,20 @@ func handleSingleService(imageByService *ImagesByService, allRegistries map[stri ServerAddress: registry.Host, }) if err != nil { - return errors.Wrapf(err, "faied to create docker push auth data") + return nil, errors.Wrapf(err, "faied to create docker push auth data") } options := types.ImagePushOptions{ RegistryAuth: encodedAuth, } + for _, targetImageUrl := range targetImageUrlByRepo[registry.RegistryID] { - _, err = dockerClient.ImagePush(context.TODO(), targetImageUrl, options) + err = pushImage(dockerClient, targetImageUrl, &options) if err != nil { - return errors.Wrapf(err, "failed to push image: %s", targetImageUrl) + return nil, errors.Wrapf(err, "failed to push image: %s", targetImageUrl) } } } - return nil + return retImages, nil } func (p *Packager) Exec() error { @@ -201,7 +262,7 @@ func (p *Packager) Exec() error { result := &PackageResult{ ServiceName: imageByService.ServiceName, } - err = handleSingleService(imageByService, buildRegistryMap(allRegistries), p.Ctx.TargetRegistries, cli) + images, err := handleSingleService(imageByService, buildRegistryMap(allRegistries), p.Ctx.TargetRegistries, cli) if err != nil { result.Result = "failed" @@ -209,7 +270,7 @@ func (p *Packager) Exec() error { log.Errorf("[result][fail][%s][%s]", imageByService.ServiceName, err) } else { result.Result = "success" - result.ImageData = imageByService.Images + result.ImageData = images log.Infof("[result][success][%s]", imageByService.ServiceName) } -- Gitee From b4a360f624ab9c208cbedc1dafd4ce20af623164 Mon Sep 17 00:00:00 2001 From: panxunying Date: Fri, 10 Dec 2021 14:11:22 +0800 Subject: [PATCH 115/134] fix conflict Signed-off-by: panxunying --- .../aslan/core/environment/service/environment.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/microservice/aslan/core/environment/service/environment.go b/pkg/microservice/aslan/core/environment/service/environment.go index b1d5206e9..3e74fc9a8 100644 --- a/pkg/microservice/aslan/core/environment/service/environment.go +++ b/pkg/microservice/aslan/core/environment/service/environment.go @@ -550,7 +550,7 @@ func UpdateProductRegistry(namespace, registryID string, log *zap.SugaredLogger) log.Errorf("UpdateProductRegistry UpdateRegistry by namespace:%s registryID:%s error: %v", namespace, registryID, err) return e.ErrUpdateEnv.AddErr(err) } - kubeClient, err := kube.GetKubeClient(exitedProd.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), exitedProd.ClusterID) if err != nil { return e.ErrUpdateEnv.AddErr(err) } @@ -1025,7 +1025,7 @@ func UpdateHelmProductRenderset(productName, envName, userName, requestID string if err != nil { return err } - kubeClient, err := kube.GetKubeClient(product.ClusterID) + kubeClient, err := kubeclient.GetKubeClient(config.HubServerAddress(), product.ClusterID) if err != nil { log.Errorf("UpdateHelmProductRenderset GetKubeClient error, error msg:%s", err) return err -- Gitee From 58e1ad95c72a07c16410e8d0be705924ae4b7f12 Mon Sep 17 00:00:00 2001 From: panxunying Date: Fri, 10 Dec 2021 14:15:11 +0800 Subject: [PATCH 116/134] optimize Signed-off-by: panxunying --- .../aslan/core/common/service/registry.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/microservice/aslan/core/common/service/registry.go b/pkg/microservice/aslan/core/common/service/registry.go index 301e02245..62c35be8e 100644 --- a/pkg/microservice/aslan/core/common/service/registry.go +++ b/pkg/microservice/aslan/core/common/service/registry.go @@ -39,7 +39,7 @@ func findRegisty(regOps *mongodb.FindRegOps, log *zap.SugaredLogger) (*models.Re resp, err := mongodb.NewRegistryNamespaceColl().Find(regOps) if err != nil { - log.Warnf("RegistryNamespace.Find error: %v", err) + log.Warnf("RegistryNamespace.Find error: %s", err) resp = &models.RegistryNamespace{ RegAddr: config.RegistryAddress(), AccessKey: config.RegistryAccessKey(), @@ -67,8 +67,8 @@ func FindDefaultRegistry(log *zap.SugaredLogger) (*models.RegistryNamespace, err func GetDefaultRegistryNamespace(log *zap.SugaredLogger) (*models.RegistryNamespace, error) { resp, err := mongodb.NewRegistryNamespaceColl().Find(&mongodb.FindRegOps{IsDefault: true}) if err != nil { - log.Errorf("get default registry error: %v", err) - return resp, fmt.Errorf("get default registry error: %v", err) + log.Errorf("get default registry error: %s", err) + return resp, fmt.Errorf("get default registry error: %s", err) } return resp, nil } @@ -76,8 +76,8 @@ func GetDefaultRegistryNamespace(log *zap.SugaredLogger) (*models.RegistryNamesp func ListRegistryNamespaces(log *zap.SugaredLogger) ([]*models.RegistryNamespace, error) { resp, err := mongodb.NewRegistryNamespaceColl().FindAll(&mongodb.FindRegOps{}) if err != nil { - log.Errorf("RegistryNamespace.List error: %v", err) - return resp, fmt.Errorf("RegistryNamespace.List error: %v", err) + log.Errorf("RegistryNamespace.List error: %s", err) + return resp, fmt.Errorf("RegistryNamespace.List error: %s", err) } return resp, nil } @@ -89,7 +89,7 @@ func EnsureDefaultRegistrySecret(namespace string, registryId string, kubeClient reg, err = FindRegistryById(registryId, log) if err != nil { log.Errorf( - "service.EnsureRegistrySecret: failed to find registry: %s error msg:%v", + "service.EnsureRegistrySecret: failed to find registry: %s error msg:%s", registryId, err, ) return err @@ -98,7 +98,7 @@ func EnsureDefaultRegistrySecret(namespace string, registryId string, kubeClient reg, err = FindDefaultRegistry(log) if err != nil { log.Errorf( - "service.EnsureRegistrySecret: failed to find default candidate registry: %s %v", + "service.EnsureRegistrySecret: failed to find default candidate registry: %s %s", namespace, err, ) return err @@ -107,7 +107,7 @@ func EnsureDefaultRegistrySecret(namespace string, registryId string, kubeClient err = kube.CreateOrUpdateRegistrySecret(namespace, reg, kubeClient) if err != nil { - log.Errorf("[%s] CreateDockerSecret error: %v", namespace, err) + log.Errorf("[%s] CreateDockerSecret error: %s", namespace, err) return e.ErrUpdateSecret.AddDesc(e.CreateDefaultRegistryErrMsg) } -- Gitee From c51ad65f638cb22415f6ba914586b928540d3c40 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Fri, 10 Dec 2021 14:24:40 +0800 Subject: [PATCH 117/134] filter k8s default namespaces Signed-off-by: liu deyi --- pkg/microservice/aslan/core/environment/service/kube.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pkg/microservice/aslan/core/environment/service/kube.go b/pkg/microservice/aslan/core/environment/service/kube.go index 7c8e0fa39..277fcf60e 100644 --- a/pkg/microservice/aslan/core/environment/service/kube.go +++ b/pkg/microservice/aslan/core/environment/service/kube.go @@ -25,6 +25,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/util/sets" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" @@ -122,7 +123,7 @@ func ListAvailableNamespaces(clusterID string, log *zap.SugaredLogger) ([]*resou } return resp, err } - + filterK8sNamespaces := sets.NewString("kube-node-lease", "kube-public", "kube-system") for _, namespace := range namespaces { if value, IsExist := namespace.Labels[setting.EnvCreatedBy]; IsExist { if value == setting.EnvCreator { @@ -130,6 +131,10 @@ func ListAvailableNamespaces(clusterID string, log *zap.SugaredLogger) ([]*resou } } + if filterK8sNamespaces.Has(namespace.Name) { + continue + } + resp = append(resp, wrapper.Namespace(namespace).Resource()) } -- Gitee From 91321d8b09d56ca2ff631ece8b6366e924b49987 Mon Sep 17 00:00:00 2001 From: Landy Date: Fri, 10 Dec 2021 15:28:41 +0800 Subject: [PATCH 118/134] Revert "create delivery version" --- go.mod | 1 - go.sum | 5 - pkg/config/config.go | 4 - pkg/microservice/aslan/config/config.go | 4 - pkg/microservice/aslan/config/consts.go | 1 - .../repository/models/delivery_distribute.go | 23 +- .../repository/models/delivery_version.go | 34 +- .../core/common/repository/models/queue.go | 27 +- .../models/task/artifact_package.go | 25 - .../common/repository/models/task/model.go | 12 +- .../repository/mongodb/delivery_distribute.go | 9 +- .../repository/mongodb/delivery_version.go | 21 +- .../common/repository/mongodb/helm_repo.go | 32 +- .../repository/mongodb/template/product.go | 37 +- .../aslan/core/common/service/fs/s3.go | 30 +- .../aslan/core/common/service/s3/s3.go | 10 - .../aslan/core/common/service/service.go | 54 +- .../aslan/core/delivery/handler/router.go | 8 - .../aslan/core/delivery/handler/version.go | 283 ++-- .../aslan/core/delivery/service/docker.go | 57 - .../aslan/core/delivery/service/version.go | 1472 +---------------- .../aslan/core/environment/handler/helm.go | 40 - .../aslan/core/environment/handler/router.go | 3 - .../aslan/core/environment/service/helm.go | 259 --- .../aslan/core/project/service/project.go | 26 +- .../aslan/core/service/handler/helm.go | 21 +- .../aslan/core/service/service/helm.go | 60 +- .../aslan/core/system/handler/helm.go | 1 - .../service/workflow/artifact_task.go | 23 +- .../packager/core/service/packager.go | 8 +- .../packager/core/service/service.go | 85 +- .../service/types/task/artifact_package.go | 2 +- .../core/service/types/task/config_payload.go | 2 +- pkg/setting/consts.go | 25 - pkg/tool/errors/http_errors.go | 6 - 35 files changed, 314 insertions(+), 2396 deletions(-) delete mode 100644 pkg/microservice/aslan/core/delivery/service/docker.go delete mode 100644 pkg/microservice/aslan/core/environment/handler/helm.go delete mode 100644 pkg/microservice/aslan/core/environment/service/helm.go diff --git a/go.mod b/go.mod index 0f9924dca..c00c91906 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,6 @@ require ( github.com/bugsnag/bugsnag-go v2.1.0+incompatible // indirect github.com/bugsnag/panicwrap v1.3.1 // indirect github.com/cenkalti/backoff/v4 v4.1.1 - github.com/chartmuseum/helm-push v0.10.1 github.com/coocood/freecache v1.1.0 github.com/coreos/go-oidc/v3 v3.0.0 github.com/dexidp/dex v0.0.0-20210802203454-3fac2ab6bc3b diff --git a/go.sum b/go.sum index 123658a63..79c316c2d 100644 --- a/go.sum +++ b/go.sum @@ -286,8 +286,6 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= -github.com/chartmuseum/helm-push v0.10.1 h1:NqStAmarEy0GnrDCk0zubGKeRmkhOm/rRi5au8h76BA= -github.com/chartmuseum/helm-push v0.10.1/go.mod h1:s6xTICU31jKdLkOXS+GgaR61E+oU4h8TWb1yZcHq8OE= github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -539,7 +537,6 @@ github.com/garyburd/redigo v1.6.2 h1:yE/pwKCrbLpLpQICzYTeZ7JsTA/C53wFTJHaEtRqniM github.com/garyburd/redigo v1.6.2/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/gzip v0.0.1 h1:ezvKOL6jH+jlzdHNE4h9h8q8uMpDQjyl0NN0Jd7jozc= github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w= @@ -2353,8 +2350,6 @@ k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8 k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/helm v2.17.0+incompatible h1:Bpn6o1wKLYqKM3+Osh8e+1/K2g/GsQJ4F4yNF2+deao= -k8s.io/helm v2.17.0+incompatible/go.mod h1:LZzlS4LQBHfciFOurYBFkCMTaZ0D1l+p0teMg7TSULI= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= diff --git a/pkg/config/config.go b/pkg/config/config.go index 4f2ef7d94..593eff9c1 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -210,10 +210,6 @@ func ObjectStorageTemplatePath(name, kind string) string { return filepath.Join("templates", kind, name) } -func ObjectStorageDeliveryVersionPath(project string) string { - return filepath.Join("delivery-distributes", "files", project) -} - func ObjectStorageChartTemplatePath(name string) string { return ObjectStorageTemplatePath(name, setting.ChartTemplatesPath) } diff --git a/pkg/microservice/aslan/config/config.go b/pkg/microservice/aslan/config/config.go index 121add2cc..edca3a57f 100644 --- a/pkg/microservice/aslan/config/config.go +++ b/pkg/microservice/aslan/config/config.go @@ -234,10 +234,6 @@ func LocalServicePathWithRevision(project, service string, revision int64) strin return configbase.LocalServicePathWithRevision(project, service, fmt.Sprintf("%d", revision)) } -func LocalDeliveryChartPathWithRevision(project, service string, revision int64) string { - return configbase.LocalServicePathWithRevision(project, service, fmt.Sprintf("delivery/%d", revision)) -} - func ServiceNameWithRevision(serviceName string, revision int64) string { return fmt.Sprintf("%s-%d", serviceName, revision) } diff --git a/pkg/microservice/aslan/config/consts.go b/pkg/microservice/aslan/config/consts.go index 9b91eb4c0..99f468214 100644 --- a/pkg/microservice/aslan/config/consts.go +++ b/pkg/microservice/aslan/config/consts.go @@ -141,7 +141,6 @@ type DistributeType string const ( File DistributeType = "file" Image DistributeType = "image" - Chart DistributeType = "chart" ) type NotifyType int diff --git a/pkg/microservice/aslan/core/common/repository/models/delivery_distribute.go b/pkg/microservice/aslan/core/common/repository/models/delivery_distribute.go index 4365fa139..db24294d6 100644 --- a/pkg/microservice/aslan/core/common/repository/models/delivery_distribute.go +++ b/pkg/microservice/aslan/core/common/repository/models/delivery_distribute.go @@ -25,23 +25,16 @@ import ( type DeliveryDistribute struct { ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` ReleaseID primitive.ObjectID `bson:"release_id" json:"releaseId"` - ServiceName string `bson:"service_name" json:"serviceName,omitempty"` + ServiceName string `bson:"service_name" json:"serviceName"` DistributeType config.DistributeType `bson:"distribute_type" json:"distributeType"` RegistryName string `bson:"registry_name" json:"registryName"` - ChartVersion string `bson:"chart_version" json:"chartVersion,omitempty"` - ChartName string `bson:"chart_name" json:"chartName,omitempty"` - ChartRepoName string `bson:"chart_repo_name" json:"chartRepoName,omitempty"` - SubDistributes []*DeliveryDistribute `bson:"-" json:"subDistributes,omitempty"` - Namespace string `bson:"namespace" json:"namespace,omitempty"` - PackageFile string `bson:"package_file" json:"packageFile,omitempty"` - RemoteFileKey string `bson:"remote_file_key" json:"remoteFileKey,omitempty"` - DestStorageURL string `bson:"dest_storage_url" json:"destStorageUrl,omitempty"` - S3StorageID string `bson:"s3_storage_id" json:"s3StorageID"` - StorageURL string `bson:"-" json:"storageUrl"` - StorageBucket string `bson:"-" json:"storageBucket"` - SrcStorageURL string `bson:"src_storage_url" json:"srcStorageUrl,omitempty"` - StartTime int64 `bson:"start_time,omitempty" json:"start_time,omitempty,omitempty"` - EndTime int64 `bson:"end_time,omitempty" json:"end_time,omitempty,omitempty"` + Namespace string `bson:"namespace" json:"namespace"` + PackageFile string `bson:"package_file" json:"packageFile"` + RemoteFileKey string `bson:"remote_file_key" json:"remoteFileKey"` + DestStorageURL string `bson:"dest_storage_url" json:"destStorageUrl"` + SrcStorageURL string `bson:"src_storage_url" json:"srcStorageUrl"` + StartTime int64 `bson:"start_time,omitempty" json:"start_time,omitempty"` + EndTime int64 `bson:"end_time,omitempty" json:"end_time,omitempty"` CreatedAt int64 `bson:"created_at" json:"created_at"` DeletedAt int64 `bson:"deleted_at" json:"deleted_at"` } diff --git a/pkg/microservice/aslan/core/common/repository/models/delivery_version.go b/pkg/microservice/aslan/core/common/repository/models/delivery_version.go index ed851379d..459d7f96f 100644 --- a/pkg/microservice/aslan/core/common/repository/models/delivery_version.go +++ b/pkg/microservice/aslan/core/common/repository/models/delivery_version.go @@ -20,30 +20,18 @@ import ( "go.mongodb.org/mongo-driver/bson/primitive" ) -type DeliveryVersionProgress struct { - SuccessChartCount int `json:"successChartCount"` - TotalChartCount int `json:"totalChartCount"` - PackageUploadStatus string `json:"packageStatus"` - Error string `json:"error"` -} - type DeliveryVersion struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - Version string `bson:"version" json:"version"` - ProductName string `bson:"product_name" json:"productName"` - WorkflowName string `bson:"workflow_name" json:"workflowName"` - Type string `bson:"type" json:"type"` - TaskID int `bson:"task_id" json:"taskId"` - Desc string `bson:"desc" json:"desc"` - Labels []string `bson:"labels" json:"labels"` - ProductEnvInfo *Product `bson:"product_env_info" json:"productEnvInfo"` - Status string `bson:"status" json:"status"` - Error string `bson:"error" json:"-"` - Progress *DeliveryVersionProgress `bson:"-" json:"progress"` - CreateArgument interface{} `bson:"createArgument" json:"-"` - CreatedBy string `bson:"created_by" json:"createdBy"` - CreatedAt int64 `bson:"created_at" json:"created_at"` - DeletedAt int64 `bson:"deleted_at" json:"deleted_at"` + ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + Version string `bson:"version" json:"version"` + ProductName string `bson:"product_name" json:"productName"` + WorkflowName string `bson:"workflow_name" json:"workflowName"` + TaskID int `bson:"task_id" json:"taskId"` + Desc string `bson:"desc" json:"desc"` + Labels []string `bson:"labels" json:"labels"` + ProductEnvInfo *Product `bson:"product_env_info" json:"productEnvInfo"` + CreatedBy string `bson:"created_by" json:"createdBy"` + CreatedAt int64 `bson:"created_at" json:"created_at"` + DeletedAt int64 `bson:"deleted_at" json:"deleted_at"` } func (DeliveryVersion) TableName() string { diff --git a/pkg/microservice/aslan/core/common/repository/models/queue.go b/pkg/microservice/aslan/core/common/repository/models/queue.go index 5c472c3e6..1a7247d3b 100644 --- a/pkg/microservice/aslan/core/common/repository/models/queue.go +++ b/pkg/microservice/aslan/core/common/repository/models/queue.go @@ -49,13 +49,13 @@ type Queue struct { IsArchived bool `bson:"is_archived" json:"is_archived"` AgentID string `bson:"agent_id" json:"agent_id"` MultiRun bool `bson:"multi_run" json:"multi_run"` - Target string `bson:"target,omitempty" json:"target"` // target service name, for k8s: containerName, for pm: serviceName - BuildModuleVer string `bson:"build_module_ver,omitempty" json:"build_module_ver"` + Target string `bson:"target,omitempty" json:"target"` // target 服务名称, k8s为容器名称, 物理机为服务名 + BuildModuleVer string `bson:"build_module_ver,omitempty" json:"build_module_ver"` // 使用预定义编译管理模块中的内容生成SubTasks, 查询条件为 服务模板名称: ServiceTmpl, 版本: BuildModuleVer 如果为空,则使用pipeline自定义SubTasks ServiceName string `bson:"service_name,omitempty" json:"service_name,omitempty"` - TaskArgs *TaskArgs `bson:"task_args,omitempty" json:"task_args,omitempty"` // TaskArgs job parameters for single-service workflow - WorkflowArgs *WorkflowTaskArgs `bson:"workflow_args" json:"workflow_args,omitempty"` // WorkflowArgs job parameters for multi-service workflow - TestArgs *TestTaskArgs `bson:"test_args,omitempty" json:"test_args,omitempty"` // TestArgs parameters for testing - ServiceTaskArgs *ServiceTaskArgs `bson:"service_args,omitempty" json:"service_args,omitempty"` // ServiceTaskArgs parameters for script-deployed workflows + TaskArgs *TaskArgs `bson:"task_args,omitempty" json:"task_args,omitempty"` // TaskArgs 单服务工作流任务参数 + WorkflowArgs *WorkflowTaskArgs `bson:"workflow_args" json:"workflow_args,omitempty"` // WorkflowArgs 多服务工作流任务参数 + TestArgs *TestTaskArgs `bson:"test_args,omitempty" json:"test_args,omitempty"` // TestArgs 测试任务参数 + ServiceTaskArgs *ServiceTaskArgs `bson:"service_args,omitempty" json:"service_args,omitempty"` // ServiceTaskArgs 脚本部署工作流任务参数 ArtifactPackageTaskArgs *ArtifactPackageTaskArgs `bson:"artifact_package_args,omitempty" json:"artifact_package_args,omitempty"` ConfigPayload *ConfigPayload `bson:"configpayload,omitempty" json:"config_payload"` Error string `bson:"error,omitempty" json:"error,omitempty"` @@ -96,10 +96,9 @@ type ServiceTaskArgs struct { } type ImageData struct { - ImageUrl string `bson:"image_url" json:"image_url"` - ImageName string `bson:"image_name" json:"image_name"` - ImageTag string `bson:"image_tag" json:"image_tag"` - RegistryID string `bson:"registry_id" json:"registry_id"` + ImageUrl string `bson:"image_url" json:"image_url"` + ImageName string `bson:"image_name" json:"image_name"` + ImageTag string `bson:"image_tag" json:"image_tag"` } type ImagesByService struct { @@ -109,10 +108,10 @@ type ImagesByService struct { type ArtifactPackageTaskArgs struct { ProjectName string `bson:"project_name" json:"project_name"` - EnvName string `bson:"env_name" json:"env_name"` - Images []*ImagesByService `bson:"images" json:"images"` - SourceRegistries []string `json:"source_registries" json:"source_registries"` - TargetRegistries []string `json:"target_registries" json:"target_registries"` + EnvName string `bson:"env_name" json:"env_name"` + Images []*ImagesByService `bson:"images" json:"images"` + SourceRegistries []string `json:"source_registries" json:"source_registries"` + TargetRegistries []string `json:"target_registries" json:"target_registries"` } type ConfigPayload struct { diff --git a/pkg/microservice/aslan/core/common/repository/models/task/artifact_package.go b/pkg/microservice/aslan/core/common/repository/models/task/artifact_package.go index 89f89de42..8f578b62c 100644 --- a/pkg/microservice/aslan/core/common/repository/models/task/artifact_package.go +++ b/pkg/microservice/aslan/core/common/repository/models/task/artifact_package.go @@ -17,27 +17,12 @@ limitations under the License. package task import ( - "encoding/json" "fmt" "github.com/koderover/zadig/pkg/microservice/aslan/config" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" ) -type ImageData struct { - ImageUrl string `bson:"image_url" json:"image_url"` - ImageName string `bson:"image_name" json:"image_name"` - ImageNamespace string `bson:"image_namespace" json:"image_namespace"` - ImageTag string `bson:"image_tag" json:"image_tag"` -} - -type ServicePackageResult struct { - ServiceName string `json:"service_name"` - Result string `json:"result"` - ErrorMsg string `json:"error_msg"` - ImageData []*ImageData `json:"image_data"` -} - type ArtifactPackage struct { TaskType config.TaskType `bson:"type" json:"type"` TaskStatus config.Status `bson:"status" json:"status"` @@ -47,7 +32,6 @@ type ArtifactPackage struct { StartTime int64 `bson:"start_time,omitempty" json:"start_time,omitempty"` EndTime int64 `bson:"end_time,omitempty" json:"end_time,omitempty"` LogFile string `bson:"log_file" json:"log_file"` - Progress string `bson:"progress" json:"progress"` // source images Images []*models.ImagesByService `bson:"images" json:"images"` @@ -64,12 +48,3 @@ func (ri *ArtifactPackage) ToSubTask() (map[string]interface{}, error) { } return task, nil } - -func (ri *ArtifactPackage) GetProgress() ([]*ServicePackageResult, error) { - if len(ri.Progress) == 0 { - return nil, nil - } - ret := make([]*ServicePackageResult, 0) - err := json.Unmarshal([]byte(ri.Progress), &ret) - return ret, err -} diff --git a/pkg/microservice/aslan/core/common/repository/models/task/model.go b/pkg/microservice/aslan/core/common/repository/models/task/model.go index d4783d2e6..d1d23f200 100644 --- a/pkg/microservice/aslan/core/common/repository/models/task/model.go +++ b/pkg/microservice/aslan/core/common/repository/models/task/model.go @@ -76,12 +76,12 @@ type Task struct { StorageURI string `bson:"storage_uri,omitempty" json:"storage_uri,omitempty"` // interface{} 为types.TestReport TestReports map[string]interface{} `bson:"test_reports,omitempty" json:"test_reports,omitempty"` - RwLock sync.Mutex `bson:"-" json:"-"` - ResetImage bool `bson:"resetImage" json:"resetImage"` - TriggerBy *models.TriggerBy `bson:"trigger_by,omitempty" json:"trigger_by,omitempty"` - Features []string `bson:"features" json:"features"` - IsRestart bool `bson:"is_restart" json:"is_restart"` - StorageEndpoint string `bson:"storage_endpoint" json:"storage_endpoint"` + RwLock sync.Mutex `bson:"-" json:"-"` + ResetImage bool `json:"resetImage" bson:"resetImage"` + TriggerBy *models.TriggerBy `json:"trigger_by,omitempty" bson:"trigger_by,omitempty"` + Features []string `bson:"features" json:"features"` + IsRestart bool `bson:"is_restart" json:"is_restart"` + StorageEndpoint string `bson:"storage_endpoint" json:"storage_endpoint"` } //type RenderInfo struct { diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/delivery_distribute.go b/pkg/microservice/aslan/core/common/repository/mongodb/delivery_distribute.go index 98a9c39ed..0b3ce01a7 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/delivery_distribute.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/delivery_distribute.go @@ -35,7 +35,6 @@ type DeliveryDistributeArgs struct { ID string `json:"id"` ReleaseID string `json:"releaseId"` ServiceName string `json:"serviceName"` - ChartName string `json:"chartName"` DistributeType config.DistributeType `json:"distributeType"` } @@ -63,7 +62,6 @@ func (c *DeliveryDistributeColl) EnsureIndex(ctx context.Context) error { Keys: bson.D{ bson.E{Key: "release_id", Value: 1}, bson.E{Key: "service_name", Value: 1}, - bson.E{Key: "chart_name", Value: 1}, bson.E{Key: "deleted_at", Value: 1}, }, Options: options.Index().SetUnique(false), @@ -117,11 +115,8 @@ func (c *DeliveryDistributeColl) Find(args *DeliveryDistributeArgs) ([]*models.D } query := bson.M{"release_id": releaseID, "deleted_at": 0} - if len(args.DistributeType) > 0 { - query["distribute_type"] = string(args.DistributeType) - } - if len(args.ChartName) > 0 { - query["chart_name"] = args.ChartName + if args.DistributeType != "" { + query["distribute_type"] = config.File } cursor, err := c.Collection.Find(context.TODO(), query) if err != nil { diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go b/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go index e0adcfc8e..bae5fc668 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go @@ -34,7 +34,6 @@ import ( type DeliveryVersionArgs struct { ID string `json:"id"` ProductName string `json:"productName"` - Version string `json:"version"` WorkflowName string `json:"workflowName"` TaskID int `json:"taskId"` PerPage int `json:"perPage"` @@ -90,6 +89,7 @@ func (c *DeliveryVersionColl) Find(args *DeliveryVersionArgs) ([]*models.Deliver return nil, errors.New("nil delivery_version args") } + var resp []*models.DeliveryVersion query := bson.M{"deleted_at": 0} if args.ProductName != "" { query["product_name"] = args.ProductName @@ -113,7 +113,6 @@ func (c *DeliveryVersionColl) Find(args *DeliveryVersionArgs) ([]*models.Deliver return nil, err } - resp := make([]*models.DeliveryVersion, 0) err = cursor.All(ctx, &resp) if err != nil { return nil, err @@ -165,13 +164,7 @@ func (c *DeliveryVersionColl) Get(args *DeliveryVersionArgs) (*models.DeliveryVe resp := new(models.DeliveryVersion) var query map[string]interface{} if args.ID != "" { - oid, err := primitive.ObjectIDFromHex(args.ID) - if err != nil { - return nil, err - } - query = bson.M{"_id": oid, "deleted_at": 0} - } else if len(args.Version) > 0 { - query = bson.M{"product_name": args.ProductName, "version": args.Version, "deleted_at": 0} + query = bson.M{"_id": args.ID, "deleted_at": 0} } else { query = bson.M{"product_name": args.ProductName, "workflow_name": args.WorkflowName, "task_id": args.TaskID, "deleted_at": 0} } @@ -197,16 +190,6 @@ func (c *DeliveryVersionColl) Insert(args *models.DeliveryVersion) error { return nil } -func (c *DeliveryVersionColl) UpdateStatusByName(versionName, status, errorStr string) error { - query := bson.M{"version": versionName, "deleted_at": 0} - change := bson.M{"$set": bson.M{ - "status": status, - "error": errorStr, - }} - _, err := c.UpdateOne(context.TODO(), query, change) - return err -} - func (c *DeliveryVersionColl) Update(args *models.DeliveryVersion) error { if args == nil { return errors.New("nil delivery_version args") diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/helm_repo.go b/pkg/microservice/aslan/core/common/repository/mongodb/helm_repo.go index 86fff875e..6d7731676 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/helm_repo.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/helm_repo.go @@ -37,11 +37,6 @@ type HelmRepoColl struct { coll string } -type HelmRepoFindOption struct { - Id string - RepoName string -} - func NewHelmRepoColl() *HelmRepoColl { name := models.HelmRepo{}.TableName() coll := &HelmRepoColl{Collection: mongotool.Database(config.MongoDatabase()).Collection(name), coll: name} @@ -54,12 +49,7 @@ func (c *HelmRepoColl) GetCollectionName() string { } func (c *HelmRepoColl) EnsureIndex(ctx context.Context) error { - mod := mongo.IndexModel{ - Keys: bson.M{"repo_name": 1}, - Options: options.Index().SetUnique(false), - } - _, err := c.Indexes().CreateOne(ctx, mod) - return err + return nil } func (c *HelmRepoColl) Create(args *models.HelmRepo) error { @@ -74,26 +64,6 @@ func (c *HelmRepoColl) Create(args *models.HelmRepo) error { return err } -func (c *HelmRepoColl) Find(opt *HelmRepoFindOption) (*models.HelmRepo, error) { - query := bson.M{} - if len(opt.Id) > 0 { - oid, err := primitive.ObjectIDFromHex(opt.Id) - if err != nil { - return nil, err - } - query["_id"] = oid - } - if len(opt.RepoName) > 0 { - query["repo_name"] = opt.RepoName - } - ret := new(models.HelmRepo) - err := c.FindOne(context.TODO(), query).Decode(ret) - if err != nil { - return nil, err - } - return ret, nil -} - func (c *HelmRepoColl) Update(id string, args *models.HelmRepo) error { oid, err := primitive.ObjectIDFromHex(id) if err != nil { diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/template/product.go b/pkg/microservice/aslan/core/common/repository/mongodb/template/product.go index 474d2e960..4cf141c2d 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/template/product.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/template/product.go @@ -39,7 +39,6 @@ type ProjectInfo struct { UpdatedBy string `bson:"update_by"` OnboardStatus int `bson:"onboarding_status"` Public bool `bson:"public"` - DeployType string `bson:"deploy_type"` } type ProductColl struct { @@ -83,8 +82,8 @@ func (c *ProductColl) FindProjectName(project string) (*template.Product, error) } func (c *ProductColl) ListNames(inNames []string) ([]string, error) { - res, err := c.listProjects(inNames, bson.M{ - "product_name": "$product_name", + res, err := c.listProjects(inNames, bson.D{ + {"product_name", 1}, }) if err != nil { return nil, err @@ -99,34 +98,29 @@ func (c *ProductColl) ListNames(inNames []string) ([]string, error) { } func (c *ProductColl) ListProjectBriefs(inNames []string) ([]*ProjectInfo, error) { - return c.listProjects(inNames, bson.M{ - "product_name": "$product_name", - "project_name": "$project_name", - "description": "$description", - "update_time": "$update_time", - "update_by": "$update_by", - "onboarding_status": "$onboarding_status", - "public": "$public", - "deploy_type": "$product_feature.deploy_type", + return c.listProjects(inNames, bson.D{ + {"product_name", 1}, + {"project_name", 1}, + {"description", 1}, + {"update_time", 1}, + {"update_by", 1}, + {"onboarding_status", 1}, + {"public", 1}, }) } -func (c *ProductColl) listProjects(inNames []string, projection bson.M) ([]*ProjectInfo, error) { +func (c *ProductColl) listProjects(inNames []string, projection bson.D) ([]*ProjectInfo, error) { + opts := options.Find() filter := bson.M{} if len(inNames) > 0 { filter["product_name"] = bson.M{"$in": inNames} } - pipeline := []bson.M{ - { - "$match": filter, - }, - { - "$project": projection, - }, + if len(projection) > 0 { + opts.SetProjection(projection) } - cursor, err := c.Collection.Aggregate(context.TODO(), pipeline) + cursor, err := c.Collection.Find(context.TODO(), filter, opts) if err != nil { return nil, err } @@ -136,6 +130,7 @@ func (c *ProductColl) listProjects(inNames []string, projection bson.M) ([]*Proj if err != nil { return nil, err } + return res, nil } diff --git a/pkg/microservice/aslan/core/common/service/fs/s3.go b/pkg/microservice/aslan/core/common/service/fs/s3.go index dfe02ea2c..67c5db651 100644 --- a/pkg/microservice/aslan/core/common/service/fs/s3.go +++ b/pkg/microservice/aslan/core/common/service/fs/s3.go @@ -24,35 +24,15 @@ import ( "go.uber.org/zap" - "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/s3" s3service "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/s3" "github.com/koderover/zadig/pkg/setting" s3tool "github.com/koderover/zadig/pkg/tool/s3" fsutil "github.com/koderover/zadig/pkg/util/fs" ) -func ArchiveAndUploadFilesToSpecifiedS3(fileTree fs.FS, names []string, s3Base, s3Id string, logger *zap.SugaredLogger) error { - s3Storage, err := s3service.FindS3ById(s3Id) - if err != nil { - logger.Errorf("Failed to find default s3, err:%v", err) - return err - } - return archiveAndUploadFiles(fileTree, names, s3Base, s3Storage, logger) -} - -func ArchiveAndUploadFilesToS3(fileTree fs.FS, names []string, s3Base string, logger *zap.SugaredLogger) error { - s3Storage, err := s3service.FindDefaultS3() - if err != nil { - logger.Errorf("Failed to find default s3, err:%v", err) - return err - } - return archiveAndUploadFiles(fileTree, names, s3Base, s3Storage, logger) -} - -// archiveAndUploadFiles archive local files and upload to default s3 storage +// ArchiveAndUploadFilesToS3 archive local files and upload to default s3 storage // if multiple names appointed, s3storage.copy will be used to handle extra names -func archiveAndUploadFiles(fileTree fs.FS, names []string, s3Base string, s3Storage *s3.S3, logger *zap.SugaredLogger) error { - +func ArchiveAndUploadFilesToS3(fileTree fs.FS, names []string, s3Base string, logger *zap.SugaredLogger) error { if len(names) == 0 { return fmt.Errorf("names not appointed") } @@ -73,7 +53,11 @@ func archiveAndUploadFiles(fileTree fs.FS, names []string, s3Base string, s3Stor logger.Errorf("Failed to archive tarball %s, err: %s", localPath, err) return err } - + s3Storage, err := s3service.FindDefaultS3() + if err != nil { + logger.Errorf("Failed to find default s3, err:%v", err) + return err + } forcedPathStyle := true if s3Storage.Provider == setting.ProviderSourceAli { forcedPathStyle = false diff --git a/pkg/microservice/aslan/core/common/service/s3/s3.go b/pkg/microservice/aslan/core/common/service/s3/s3.go index fc363b616..24655148c 100644 --- a/pkg/microservice/aslan/core/common/service/s3/s3.go +++ b/pkg/microservice/aslan/core/common/service/s3/s3.go @@ -148,16 +148,6 @@ func FindDefaultS3() (*S3, error) { return &S3{S3Storage: storage}, nil } -func FindS3ById(id string) (*S3, error) { - storage, err := commonrepo.NewS3StorageColl().Find(id) - if err != nil { - log.Warnf("Failed to find s3 in db, err: %s", err) - return nil, err - } - - return &S3{S3Storage: storage}, nil -} - // 获取内置的s3 func FindInternalS3() *S3 { storage := &models.S3Storage{ diff --git a/pkg/microservice/aslan/core/common/service/service.go b/pkg/microservice/aslan/core/common/service/service.go index fbcf8086c..780409314 100644 --- a/pkg/microservice/aslan/core/common/service/service.go +++ b/pkg/microservice/aslan/core/common/service/service.go @@ -21,7 +21,6 @@ import ( "encoding/json" "errors" "fmt" - "net/url" "regexp" "strings" templ "text/template" @@ -91,9 +90,8 @@ type ServiceProductMap struct { } var ( - imageParseRegex = regexp.MustCompile(`(?P.+/)?(?P[^:]+){1}(:)?(?P.+)?`) - imageSpaceParseRegex = regexp.MustCompile(`\/(.*?)\/`) - presetPatterns = []map[string]string{ + imageParseRegex = regexp.MustCompile(`(?P.+/)?(?P[^:]+){1}(:)?(?P.+)?`) + presetPatterns = []map[string]string{ {setting.PathSearchComponentImage: "image.repository", setting.PathSearchComponentTag: "image.tag"}, {setting.PathSearchComponentImage: "image"}, } @@ -616,54 +614,6 @@ func ExtractImageName(imageURI string) string { return "" } -// ExtractImageRegistry extract registry url from total image uri -func ExtractImageRegistry(imageURI string) (string, error) { - subMatchAll := imageParseRegex.FindStringSubmatch(imageURI) - exNames := imageParseRegex.SubexpNames() - for i, matchedStr := range subMatchAll { - if i != 0 && matchedStr != "" && matchedStr != ":" { - if exNames[i] == "repo" { - u, err := url.Parse(matchedStr) - if err != nil { - return "", err - } - if len(u.Scheme) > 0 { - matchedStr = strings.TrimPrefix(matchedStr, fmt.Sprintf("%s://", u.Scheme)) - } - return matchedStr, nil - } - } - } - return "", fmt.Errorf("failed to extract registry url") -} - -// ExtractImageTag extract image tag from total image uri -func ExtractImageTag(imageURI string) string { - subMatchAll := imageParseRegex.FindStringSubmatch(imageURI) - exNames := imageParseRegex.SubexpNames() - for i, matchedStr := range subMatchAll { - if i != 0 && matchedStr != "" && matchedStr != ":" { - if exNames[i] == "tag" { - return matchedStr - } - } - } - return "" -} - -// ExtractRegistryNamespace extract registry namespace form image uri -func ExtractRegistryNamespace(imageURI string) string { - imageURI = strings.TrimPrefix(imageURI, "http://") - imageURI = strings.TrimPrefix(imageURI, "https://") - - firstIndex := strings.Index(imageURI, "/") - lastIndex := strings.LastIndex(imageURI, "/") - if lastIndex == firstIndex { - return "" - } - return strings.TrimPrefix(imageURI[firstIndex:lastIndex], "/") -} - func parseImagesByPattern(nested map[string]interface{}, patterns []map[string]string) ([]*models.Container, error) { flatMap, err := converter.Flatten(nested) if err != nil { diff --git a/pkg/microservice/aslan/core/delivery/handler/router.go b/pkg/microservice/aslan/core/delivery/handler/router.go index 7b58bcade..889b7e7aa 100644 --- a/pkg/microservice/aslan/core/delivery/handler/router.go +++ b/pkg/microservice/aslan/core/delivery/handler/router.go @@ -45,14 +45,6 @@ func (*Router) Inject(router *gin.RouterGroup) { deliveryRelease.GET("/:id", GetDeliveryVersion) deliveryRelease.GET("", ListDeliveryVersion) deliveryRelease.DELETE("/:id", GetProductNameByDelivery, gin2.UpdateOperationLogStatus, DeleteDeliveryVersion) - - deliveryRelease.POST("/helm", CreateHelmDeliveryVersion) - deliveryRelease.POST("/helm/global-variables", ApplyDeliveryGlobalVariables) - deliveryRelease.GET("/helm/charts", DownloadDeliveryChart) - deliveryRelease.GET("/helm/charts/version", GetChartVersionFromRepo) - deliveryRelease.GET("/helm/charts/preview", PreviewGetDeliveryChart) - deliveryRelease.GET("/helm/charts/filePath", GetDeliveryChartFilePath) - deliveryRelease.GET("/helm/charts/fileContent", GetDeliveryChartFileContent) } deliveryPackage := router.Group("packages") diff --git a/pkg/microservice/aslan/core/delivery/handler/version.go b/pkg/microservice/aslan/core/delivery/handler/version.go index 39a4e5519..44ea5e998 100644 --- a/pkg/microservice/aslan/core/delivery/handler/version.go +++ b/pkg/microservice/aslan/core/delivery/handler/version.go @@ -17,15 +17,19 @@ limitations under the License. package handler import ( + "encoding/json" "fmt" - "net/http" + "strconv" "strings" "github.com/gin-gonic/gin" "github.com/koderover/zadig/pkg/microservice/aslan/config" + commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/base" deliveryservice "github.com/koderover/zadig/pkg/microservice/aslan/core/delivery/service" + workflowservice "github.com/koderover/zadig/pkg/microservice/aslan/core/workflow/service/workflow" internalhandler "github.com/koderover/zadig/pkg/shared/handler" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/log" @@ -61,31 +65,189 @@ func GetDeliveryVersion(c *gin.Context) { } version := new(commonrepo.DeliveryVersionArgs) version.ID = ID - ctx.Resp, ctx.Err = deliveryservice.GetDetailReleaseData(version, ctx.Logger) + ctx.Resp, ctx.Err = deliveryservice.GetDeliveryVersion(version, ctx.Logger) +} + +type ReleaseInfo struct { + VersionInfo *commonmodels.DeliveryVersion `json:"versionInfo"` + BuildInfo []*commonmodels.DeliveryBuild `json:"buildInfo"` + DeployInfo []*commonmodels.DeliveryDeploy `json:"deployInfo"` + TestInfo []*commonmodels.DeliveryTest `json:"testInfo"` + DistributeInfo []*commonmodels.DeliveryDistribute `json:"distributeInfo"` + SecurityInfo []*DeliverySecurityStats `json:"securityStatsInfo"` +} + +type DeliverySecurityStats struct { + ImageName string `json:"imageName"` + ImageID string `json:"imageId"` + DeliverySecurityStatsInfo DeliverySecurityStatsInfo `json:"deliverySecurityStatsInfo"` +} + +type DeliverySecurityStatsInfo struct { + Total int `json:"total"` + Unknown int `json:"unkown"` + Negligible int `json:"negligible"` + Low int `json:"low"` + Medium int `json:"medium"` + High int `json:"high"` + Critical int `json:"critical"` } func ListDeliveryVersion(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - args := new(deliveryservice.ListDeliveryVersionArgs) - err := c.BindQuery(args) - if err != nil { - ctx.Err = e.ErrInvalidParam.AddErr(err) - return + taskIDStr := c.Query("taskId") + var taskID = 0 + var err error + if taskIDStr != "" { + taskID, err = strconv.Atoi(taskIDStr) + if err != nil { + ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) + return + } } - if args.Page <= 0 { - args.Page = 1 + perPageStr := c.Query("per_page") + pageStr := c.Query("page") + var ( + perPage int + page int + ) + if perPageStr == "" { + perPage = 20 + } else { + perPage, err = strconv.Atoi(perPageStr) + if err != nil { + ctx.Err = e.ErrInvalidParam.AddDesc(fmt.Sprintf("perPage args err :%s", err)) + return + } } - if args.PerPage <= 0 { - args.PerPage = 20 + + if pageStr == "" { + page = 1 + } else { + page, err = strconv.Atoi(pageStr) + if err != nil { + ctx.Err = e.ErrInvalidParam.AddDesc(fmt.Sprintf("page args err :%s", err)) + return + } } - if len(args.Verbosity) == 0 { - args.Verbosity = deliveryservice.VerbosityDetailed + + serviceName := c.Query("serviceName") + + version := new(commonrepo.DeliveryVersionArgs) + version.ProductName = c.Query("projectName") + version.WorkflowName = c.Query("workflowName") + version.TaskID = taskID + version.PerPage = perPage + version.Page = page + deliveryVersions, err := deliveryservice.FindDeliveryVersion(version, ctx.Logger) + + if err != nil { + ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) + return } + releaseInfos := make([]*ReleaseInfo, 0) + for _, deliveryVersion := range deliveryVersions { + releaseInfo := new(ReleaseInfo) + //versionInfo + releaseInfo.VersionInfo = deliveryVersion + + //deployInfo + deliveryDeployArgs := new(commonrepo.DeliveryDeployArgs) + deliveryDeployArgs.ReleaseID = deliveryVersion.ID.Hex() + deliveryDeploys, err := deliveryservice.FindDeliveryDeploy(deliveryDeployArgs, ctx.Logger) + if err != nil { + ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) + } + // 查询条件serviceName + if serviceName != "" { + match := false + for _, deliveryDeploy := range deliveryDeploys { + if deliveryDeploy.ServiceName == serviceName { + match = true + break + } + } + if !match { + continue + } + } + // 将serviceName替换为服务名/服务组件的形式,用于前端展示 + for _, deliveryDeploy := range deliveryDeploys { + if deliveryDeploy.ContainerName != "" { + deliveryDeploy.ServiceName = deliveryDeploy.ServiceName + "/" + deliveryDeploy.ContainerName + } + } + releaseInfo.DeployInfo = deliveryDeploys + + //buildInfo + deliveryBuildArgs := new(commonrepo.DeliveryBuildArgs) + deliveryBuildArgs.ReleaseID = deliveryVersion.ID.Hex() + deliveryBuilds, err := deliveryservice.FindDeliveryBuild(deliveryBuildArgs, ctx.Logger) + if err != nil { + ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) + } + releaseInfo.BuildInfo = deliveryBuilds + + //testInfo + deliveryTestArgs := new(commonrepo.DeliveryTestArgs) + deliveryTestArgs.ReleaseID = deliveryVersion.ID.Hex() + deliveryTests, err := deliveryservice.FindDeliveryTest(deliveryTestArgs, ctx.Logger) + if err != nil { + ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) + } + releaseInfo.TestInfo = deliveryTests + + //securityStatsInfo + deliverySecurityStatss := make([]*DeliverySecurityStats, 0) + if pipelineTask, err := workflowservice.GetPipelineTaskV2(int64(deliveryVersion.TaskID), deliveryVersion.WorkflowName, config.WorkflowType, ctx.Logger); err == nil { + for _, subStage := range pipelineTask.Stages { + if subStage.TaskType == config.TaskSecurity { + subSecurityTaskMap := subStage.SubTasks + for _, subTask := range subSecurityTaskMap { + securityInfo, _ := base.ToSecurityTask(subTask) + + deliverySecurityStats := new(DeliverySecurityStats) + deliverySecurityStats.ImageName = securityInfo.ImageName + deliverySecurityStats.ImageID = securityInfo.ImageID + deliverySecurityStatsMap, err := deliveryservice.FindDeliverySecurityStatistics(securityInfo.ImageID, ctx.Logger) + if err != nil { + ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) + } + var transErr error + b, err := json.Marshal(deliverySecurityStatsMap) + if err != nil { + transErr = fmt.Errorf("marshal task error: %v", err) + } + + if err := json.Unmarshal(b, &deliverySecurityStats.DeliverySecurityStatsInfo); err != nil { + transErr = fmt.Errorf("unmarshal task error: %v", err) + } + if transErr != nil { + ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) + } + + deliverySecurityStatss = append(deliverySecurityStatss, deliverySecurityStats) + } + break + } + } + releaseInfo.SecurityInfo = deliverySecurityStatss + } + + //distributeInfo + deliveryDistributeArgs := new(commonrepo.DeliveryDistributeArgs) + deliveryDistributeArgs.ReleaseID = deliveryVersion.ID.Hex() + deliveryDistributes, _ := deliveryservice.FindDeliveryDistribute(deliveryDistributeArgs, ctx.Logger) + + releaseInfo.DistributeInfo = deliveryDistributes - ctx.Resp, ctx.Err = deliveryservice.ListDeliveryVersion(args, ctx.Logger) + releaseInfos = append(releaseInfos, releaseInfo) + } + ctx.Err = err + ctx.Resp = releaseInfos } func getFileName(fileName string) string { @@ -164,20 +326,6 @@ func ListPackagesVersion(c *gin.Context) { ctx.Resp = fileInfoList } -func CreateHelmDeliveryVersion(c *gin.Context) { - ctx := internalhandler.NewContext(c) - defer func() { internalhandler.JSONResponse(c, ctx) }() - - args := new(deliveryservice.CreateHelmDeliveryVersionArgs) - err := c.ShouldBindJSON(args) - if err != nil { - ctx.Err = e.ErrInvalidParam.AddErr(err) - return - } - args.CreateBy = ctx.UserName - ctx.Err = deliveryservice.CreateHelmDeliveryVersion(args, ctx.Logger) -} - func DeleteDeliveryVersion(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() @@ -223,82 +371,3 @@ func ListDeliveryServiceNames(c *gin.Context) { productName := c.Query("projectName") ctx.Resp, ctx.Err = deliveryservice.ListDeliveryServiceNames(productName, ctx.Logger) } - -func DownloadDeliveryChart(c *gin.Context) { - ctx := internalhandler.NewContext(c) - defer func() { internalhandler.JSONResponse(c, ctx) }() - - versionName := c.Query("version") - chartName := c.Query("chartName") - projectName := c.Query("projectName") - - fileBytes, fileName, err := deliveryservice.DownloadDeliveryChart(projectName, versionName, chartName, ctx.Logger) - if err != nil { - ctx.Err = err - return - } - - c.Writer.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, fileName)) - c.Data(http.StatusOK, "application/octet-stream", fileBytes) -} - -func GetChartVersionFromRepo(c *gin.Context) { - ctx := internalhandler.NewContext(c) - defer func() { internalhandler.JSONResponse(c, ctx) }() - - chartName := c.Query("chartName") - chartRepoName := c.Query("chartRepoName") - - ctx.Resp, ctx.Err = deliveryservice.GetChartVersions(chartName, chartRepoName) -} - -func PreviewGetDeliveryChart(c *gin.Context) { - ctx := internalhandler.NewContext(c) - defer func() { internalhandler.JSONResponse(c, ctx) }() - - versionName := c.Query("version") - chartName := c.Query("chartName") - projectName := c.Query("projectName") - - ctx.Resp, ctx.Err = deliveryservice.PreviewDeliveryChart(projectName, versionName, chartName, ctx.Logger) -} - -func GetDeliveryChartFilePath(c *gin.Context) { - ctx := internalhandler.NewContext(c) - defer func() { internalhandler.JSONResponse(c, ctx) }() - - args := new(deliveryservice.DeliveryChartFilePathArgs) - err := c.BindQuery(args) - if err != nil { - ctx.Err = e.ErrInvalidParam.AddErr(err) - return - } - - ctx.Resp, ctx.Err = deliveryservice.GetDeliveryChartFilePath(args, ctx.Logger) -} - -func GetDeliveryChartFileContent(c *gin.Context) { - ctx := internalhandler.NewContext(c) - defer func() { internalhandler.JSONResponse(c, ctx) }() - - args := new(deliveryservice.DeliveryChartFileContentArgs) - err := c.BindQuery(args) - if err != nil { - ctx.Err = e.ErrInvalidParam.AddErr(err) - return - } - ctx.Resp, ctx.Err = deliveryservice.GetDeliveryChartFileContent(args, ctx.Logger) -} - -func ApplyDeliveryGlobalVariables(c *gin.Context) { - ctx := internalhandler.NewContext(c) - defer func() { internalhandler.JSONResponse(c, ctx) }() - - args := new(deliveryservice.DeliveryVariablesApplyArgs) - err := c.BindJSON(args) - if err != nil { - ctx.Err = e.ErrInvalidParam.AddErr(err) - return - } - ctx.Resp, ctx.Err = deliveryservice.ApplyDeliveryGlobalVariables(args, ctx.Logger) -} diff --git a/pkg/microservice/aslan/core/delivery/service/docker.go b/pkg/microservice/aslan/core/delivery/service/docker.go deleted file mode 100644 index 65a35941e..000000000 --- a/pkg/microservice/aslan/core/delivery/service/docker.go +++ /dev/null @@ -1,57 +0,0 @@ -/* -Copyright 2021 The KodeRover Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package service - -import "os/exec" - -const dockerExe = "/usr/local/bin/docker" - -func dockerLogin(user, password, registry string) *exec.Cmd { - return exec.Command( - dockerExe, - "login", - "-u", user, - "-p", password, - registry, - ) -} - -func dockerInfo() *exec.Cmd { - return exec.Command(dockerExe, "info") -} - -func dockerPush(fullImage string) *exec.Cmd { - args := []string{ - "push", - fullImage, - } - return exec.Command(dockerExe, args...) -} - -func dockerPull(image string) *exec.Cmd { - args := []string{"pull", image} - return exec.Command(dockerExe, args...) -} - -func dockerTag(sourceFullImage, targetFullImage string) *exec.Cmd { - args := []string{ - "tag", - sourceFullImage, - targetFullImage, - } - return exec.Command(dockerExe, args...) -} diff --git a/pkg/microservice/aslan/core/delivery/service/version.go b/pkg/microservice/aslan/core/delivery/service/version.go index 7bba266c3..1c013f689 100644 --- a/pkg/microservice/aslan/core/delivery/service/version.go +++ b/pkg/microservice/aslan/core/delivery/service/version.go @@ -17,189 +17,21 @@ limitations under the License. package service import ( - "encoding/json" - "fmt" - "io" - "io/ioutil" - "net/http" - "net/url" - "os" - "path/filepath" - "strings" - "sync" - "time" - - cm "github.com/chartmuseum/helm-push/pkg/chartmuseum" - "github.com/chartmuseum/helm-push/pkg/helm" - "github.com/hashicorp/go-multierror" - "github.com/otiai10/copy" - "github.com/pkg/errors" - "go.mongodb.org/mongo-driver/bson/primitive" "go.uber.org/zap" - chartloader "helm.sh/helm/v3/pkg/chart/loader" - "helm.sh/helm/v3/pkg/chartutil" "k8s.io/apimachinery/pkg/util/sets" - "sigs.k8s.io/yaml" - "github.com/koderover/zadig/pkg/microservice/aslan/config" commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" - "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/task" - "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/template" - "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" - commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" - "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/base" - workflowservice "github.com/koderover/zadig/pkg/microservice/aslan/core/workflow/service/workflow" - "github.com/koderover/zadig/pkg/setting" e "github.com/koderover/zadig/pkg/tool/errors" - helmtool "github.com/koderover/zadig/pkg/tool/helmclient" - "github.com/koderover/zadig/pkg/tool/log" - "github.com/koderover/zadig/pkg/types" - fsutil "github.com/koderover/zadig/pkg/util/fs" - yamlutil "github.com/koderover/zadig/pkg/util/yaml" -) - -const ( - VerbosityBrief string = "brief" // brief delivery data - VerbosityDetailed string = "detailed" // detailed delivery version with total data ) -type DeliveryVersionFilter struct { - ServiceName string -} - -type CreateHelmDeliveryVersionOption struct { - EnableOfflineDist bool `json:"enableOfflineDist"` - S3StorageID string `json:"s3StorageID"` -} - -type CreateHelmDeliveryVersionChartData struct { - ServiceName string `json:"serviceName"` - Version string `json:"version,omitempty"` - ValuesYamlContent string `json:"valuesYamlContent"` -} - -type CreateHelmDeliveryVersionArgs struct { - CreateBy string `json:"-"` - ProductName string `json:"productName"` - Retry bool `json:"retry"` - Version string `json:"version"` - Desc string `json:"desc"` - EnvName string `json:"envName"` - Labels []string `json:"labels"` - ImageRepoName string `json:"imageRepoName"` - *DeliveryVersionChartData -} - -type DeliveryVersionChartData struct { - GlobalVariables string `json:"globalVariables"` - ChartRepoName string `json:"chartRepoName"` - ImageRegistryID string `json:"imageRegistryID"` - ChartDatas []*CreateHelmDeliveryVersionChartData `json:"chartDatas"` - Options *CreateHelmDeliveryVersionOption `json:"options"` -} - -type DeliveryChartData struct { - ChartData *CreateHelmDeliveryVersionChartData - ServiceObj *commonmodels.Service - ProductService *commonmodels.ProductService - RenderChart *template.RenderChart - RenderSet *commonmodels.RenderSet -} - -type DeliveryChartResp struct { - FileInfos []*types.FileInfo `json:"fileInfos"` -} - -type DeliveryChartFilePathArgs struct { - Dir string `json:"dir"` - ProjectName string `json:"projectName"` - ChartName string `json:"chartName"` - Version string `json:"version"` -} - -type DeliveryChartFileContentArgs struct { - FilePath string `json:"filePath"` - FileName string `json:"fileName"` - ProjectName string `json:"projectName"` - ChartName string `json:"chartName"` - Version string `json:"version"` -} - -type DeliveryVariablesApplyArgs struct { - GlobalVariables string `json:"globalVariables,omitempty"` - ChartDatas []*CreateHelmDeliveryVersionChartData `json:"chartDatas"` -} - -type ListDeliveryVersionArgs struct { - Page int `form:"page"` - PerPage int `form:"per_page"` - TaskId int `form:"taskId"` - ServiceName string `form:"serviceName"` - Verbosity string `form:"verbosity"` - ProjectName string `form:"projectName"` - WorkflowName string `form:"workflowName"` -} - -type ReleaseInfo struct { - VersionInfo *commonmodels.DeliveryVersion `json:"versionInfo"` - BuildInfo []*commonmodels.DeliveryBuild `json:"buildInfo,omitempty"` - DeployInfo []*commonmodels.DeliveryDeploy `json:"deployInfo,omitempty"` - TestInfo []*commonmodels.DeliveryTest `json:"testInfo,omitempty"` - DistributeInfo []*commonmodels.DeliveryDistribute `json:"distributeInfo,omitempty"` - SecurityInfo []*DeliverySecurityStats `json:"securityStatsInfo,omitempty"` -} - -type DeliverySecurityStatsInfo struct { - Total int `json:"total"` - Unknown int `json:"unkown"` - Negligible int `json:"negligible"` - Low int `json:"low"` - Medium int `json:"medium"` - High int `json:"high"` - Critical int `json:"critical"` -} - -type DeliverySecurityStats struct { - ImageName string `json:"imageName"` - ImageID string `json:"imageId"` - DeliverySecurityStatsInfo DeliverySecurityStatsInfo `json:"deliverySecurityStatsInfo"` -} - -type ImageUrlDetail struct { - ImageUrl string - Name string - Registry string - Tag string -} - -type ServiceImageDetails struct { - ServiceName string - Images []*ImageUrlDetail - Registries []string -} - -type ChartVersionResp struct { - ChartName string `json:"chartName"` - ChartVersion string `json:"chartVersion"` -} - func GetDeliveryVersion(args *commonrepo.DeliveryVersionArgs, log *zap.SugaredLogger) (*commonmodels.DeliveryVersion, error) { - versionData, err := commonrepo.NewDeliveryVersionColl().Get(args) - if err != nil { - log.Errorf("get deliveryVersion error: %v", err) - return nil, e.ErrGetDeliveryVersion - } - return versionData, err -} - -func GetDetailReleaseData(args *commonrepo.DeliveryVersionArgs, log *zap.SugaredLogger) (*ReleaseInfo, error) { - versionData, err := commonrepo.NewDeliveryVersionColl().Get(args) + resp, err := commonrepo.NewDeliveryVersionColl().Get(args) if err != nil { log.Errorf("get deliveryVersion error: %v", err) return nil, e.ErrGetDeliveryVersion } - return buildListReleaseResp(VerbosityDetailed, versionData, nil, log) + return resp, err } func FindDeliveryVersion(args *commonrepo.DeliveryVersionArgs, log *zap.SugaredLogger) ([]*commonmodels.DeliveryVersion, error) { @@ -220,1303 +52,29 @@ func DeleteDeliveryVersion(args *commonrepo.DeliveryVersionArgs, log *zap.Sugare return nil } -func filterReleases(filter *DeliveryVersionFilter, deliveryVersion *commonmodels.DeliveryVersion, logger *zap.SugaredLogger) bool { - if filter == nil { - return true - } - if filter.ServiceName != "" { - deliveryDeployArgs := new(commonrepo.DeliveryDeployArgs) - deliveryDeployArgs.ReleaseID = deliveryVersion.ID.Hex() - deliveryDeploys, err := FindDeliveryDeploy(deliveryDeployArgs, logger) - if err != nil { - return true - } - match := false - for _, deliveryDeploy := range deliveryDeploys { - if deliveryDeploy.ServiceName == filter.ServiceName { - match = true - break - } - } - if !match { - return false - } - } - return true -} - -func buildBriefRelease(deliveryVersion *commonmodels.DeliveryVersion, _ *zap.SugaredLogger) (*ReleaseInfo, error) { - return &ReleaseInfo{ - VersionInfo: deliveryVersion, - }, nil -} - -func buildDetailedRelease(deliveryVersion *commonmodels.DeliveryVersion, filterOpt *DeliveryVersionFilter, logger *zap.SugaredLogger) (*ReleaseInfo, error) { - releaseInfo := new(ReleaseInfo) - //versionInfo - releaseInfo.VersionInfo = deliveryVersion - - //deployInfo - deliveryDeployArgs := new(commonrepo.DeliveryDeployArgs) - deliveryDeployArgs.ReleaseID = deliveryVersion.ID.Hex() - deliveryDeploys, err := FindDeliveryDeploy(deliveryDeployArgs, logger) - if err != nil { - return nil, err - } - if filterOpt != nil { - if !filterReleases(filterOpt, deliveryVersion, logger) { - return nil, nil - } - } - // 将serviceName替换为服务名/服务组件的形式,用于前端展示 - for _, deliveryDeploy := range deliveryDeploys { - if deliveryDeploy.ContainerName != "" { - deliveryDeploy.ServiceName = deliveryDeploy.ServiceName + "/" + deliveryDeploy.ContainerName - } - } - releaseInfo.DeployInfo = deliveryDeploys - - //buildInfo - deliveryBuildArgs := new(commonrepo.DeliveryBuildArgs) - deliveryBuildArgs.ReleaseID = deliveryVersion.ID.Hex() - deliveryBuilds, err := FindDeliveryBuild(deliveryBuildArgs, logger) - if err != nil { - return nil, err - } - releaseInfo.BuildInfo = deliveryBuilds - - //testInfo - deliveryTestArgs := new(commonrepo.DeliveryTestArgs) - deliveryTestArgs.ReleaseID = deliveryVersion.ID.Hex() - deliveryTests, err := FindDeliveryTest(deliveryTestArgs, logger) - if err != nil { - return nil, err - } - releaseInfo.TestInfo = deliveryTests - - //securityStatsInfo - deliverySecurityStatss := make([]*DeliverySecurityStats, 0) - if pipelineTask, err := workflowservice.GetPipelineTaskV2(int64(deliveryVersion.TaskID), deliveryVersion.WorkflowName, config.WorkflowType, logger); err == nil { - for _, subStage := range pipelineTask.Stages { - if subStage.TaskType == config.TaskSecurity { - subSecurityTaskMap := subStage.SubTasks - for _, subTask := range subSecurityTaskMap { - securityInfo, _ := base.ToSecurityTask(subTask) - - deliverySecurityStats := new(DeliverySecurityStats) - deliverySecurityStats.ImageName = securityInfo.ImageName - deliverySecurityStats.ImageID = securityInfo.ImageID - deliverySecurityStatsMap, err := FindDeliverySecurityStatistics(securityInfo.ImageID, logger) - if err != nil { - return nil, err - } - var transErr error - b, err := json.Marshal(deliverySecurityStatsMap) - if err != nil { - transErr = fmt.Errorf("marshal task error: %v", err) - } - if err := json.Unmarshal(b, &deliverySecurityStats.DeliverySecurityStatsInfo); err != nil { - transErr = fmt.Errorf("unmarshal task error: %v", err) - } - if transErr != nil { - return nil, transErr - } - - deliverySecurityStatss = append(deliverySecurityStatss, deliverySecurityStats) - } - break - } - } - releaseInfo.SecurityInfo = deliverySecurityStatss - } - - //distributeInfo - deliveryDistributeArgs := new(commonrepo.DeliveryDistributeArgs) - deliveryDistributeArgs.ReleaseID = deliveryVersion.ID.Hex() - deliveryDistributes, _ := FindDeliveryDistribute(deliveryDistributeArgs, logger) - releaseInfo.DistributeInfo = deliveryDistributes - - // fill some data for helm delivery releases - processReleaseRespData(releaseInfo) - - return releaseInfo, nil -} - -func buildListReleaseResp(verbosity string, deliveryVersion *commonmodels.DeliveryVersion, filterOpt *DeliveryVersionFilter, logger *zap.SugaredLogger) (*ReleaseInfo, error) { - switch verbosity { - case VerbosityBrief: - return buildBriefRelease(deliveryVersion, logger) - case VerbosityDetailed: - return buildDetailedRelease(deliveryVersion, filterOpt, logger) - default: - return buildDetailedRelease(deliveryVersion, filterOpt, logger) - } -} +func ListDeliveryServiceNames(productName string, log *zap.SugaredLogger) ([]string, error) { + serviceNames := sets.String{} -func ListDeliveryVersion(args *ListDeliveryVersionArgs, logger *zap.SugaredLogger) ([]*ReleaseInfo, error) { - versionListArgs := new(commonrepo.DeliveryVersionArgs) - versionListArgs.ProductName = args.ProjectName - versionListArgs.WorkflowName = args.WorkflowName - versionListArgs.TaskID = args.TaskId - versionListArgs.PerPage = args.PerPage - versionListArgs.Page = args.Page - deliveryVersions, err := FindDeliveryVersion(versionListArgs, logger) + version := new(commonrepo.DeliveryVersionArgs) + version.ProductName = productName + deliveryVersions, err := FindDeliveryVersion(version, log) if err != nil { - return nil, err + log.Errorf("FindDeliveryVersion failed, err:%v", err) + return serviceNames.List(), err } - releaseInfos := make([]*ReleaseInfo, 0) for _, deliveryVersion := range deliveryVersions { - releaseInfo, err := buildListReleaseResp(args.Verbosity, deliveryVersion, &DeliveryVersionFilter{ServiceName: args.ServiceName}, logger) + deliveryDeployArgs := new(commonrepo.DeliveryDeployArgs) + deliveryDeployArgs.ReleaseID = deliveryVersion.ID.Hex() + deliveryDeploys, err := FindDeliveryDeploy(deliveryDeployArgs, log) if err != nil { - return nil, err - } - if releaseInfo == nil { - continue - } - releaseInfos = append(releaseInfos, releaseInfo) - } - return releaseInfos, nil -} - -// fill release -func processReleaseRespData(release *ReleaseInfo) { - if release.VersionInfo.Type != setting.DeliveryVersionTypeChart { - return - } - - distributeMap := make(map[string][]*commonmodels.DeliveryDistribute) - for _, distributeImage := range release.DistributeInfo { - if distributeImage.DistributeType != config.Image { - continue - } - distributeMap[distributeImage.ChartName] = append(distributeMap[distributeImage.ChartName], distributeImage) - } - - chartDistributeCount := 0 - distributes := make([]*commonmodels.DeliveryDistribute, 0) - for _, distribute := range release.DistributeInfo { - if distribute.DistributeType == config.Image { + log.Errorf("FindDeliveryDeploy failed, ReleaseID:%s, err:%v", deliveryVersion.ID, err) continue } - switch distribute.DistributeType { - case config.Chart: - chartDistributeCount++ - distribute.SubDistributes = distributeMap[distribute.ChartName] - case config.File: - s3Storage, err := commonrepo.NewS3StorageColl().Find(distribute.S3StorageID) - if err != nil { - log.Errorf("failed to query s3 storageID: %s, err: %s", distribute.S3StorageID, err) - } else { - distribute.StorageURL = s3Storage.Endpoint - distribute.StorageBucket = s3Storage.Bucket - } - } - distributes = append(distributes, distribute) - } - release.DistributeInfo = distributes - - release.VersionInfo.Progress = buildDeliveryProgressInfo(release.VersionInfo, chartDistributeCount) -} - -func buildDeliveryProgressInfo(deliveryVersion *commonmodels.DeliveryVersion, successfulChartCount int) *commonmodels.DeliveryVersionProgress { - if deliveryVersion.Type != setting.DeliveryVersionTypeChart { - return nil - } - - progress := &commonmodels.DeliveryVersionProgress{ - SuccessChartCount: successfulChartCount, - TotalChartCount: 0, - PackageUploadStatus: "", - Error: "", - } - if deliveryVersion.Status == setting.DeliveryVersionStatusSuccess { - progress.TotalChartCount = successfulChartCount - progress.PackageUploadStatus = setting.DeliveryVersionPackageStatusSuccess - return progress - } - - argsBytes, err := json.Marshal(deliveryVersion.CreateArgument) - if err != nil { - log.Errorf("failed to marshal arguments, versionName: %s err %s", deliveryVersion.Version, err) - return progress - } - createArgs := new(DeliveryVersionChartData) - err = json.Unmarshal(argsBytes, createArgs) - if err != nil { - log.Errorf("failed to unMarshal arguments, versionName: %s err %s", deliveryVersion.Version, err) - return progress - } - - progress.TotalChartCount = len(createArgs.ChartDatas) - - if deliveryVersion.Status == setting.DeliveryVersionStatusFailed { - progress.PackageUploadStatus = setting.DeliveryVersionPackageStatusFailed - progress.Error = deliveryVersion.Error - return progress - } - - if len(createArgs.ChartDatas) > successfulChartCount { - progress.PackageUploadStatus = setting.DeliveryVersionPackageStatusWaiting - return progress - } - - progress.PackageUploadStatus = setting.DeliveryVersionPackageStatusUploading - return progress - -} - -func getChartTGZDir(productName, versionName string) string { - tmpDir := os.TempDir() - return filepath.Join(tmpDir, "chart-tgz", productName, versionName) -} - -func getChartExpandDir(productName, versionName string) string { - tmpDir := os.TempDir() - return filepath.Join(tmpDir, "chart", productName, versionName) -} - -func getProductEnvInfo(productName, envName string) (*commonmodels.Product, error) { - productInfo, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{ - Name: productName, - EnvName: envName, - }) - if err != nil { - log.Errorf("failed to query product info, productName: %s envName: %s err: %s", productName, envName, err) - return nil, fmt.Errorf("failed to query product info, productName: %s envName: %s", productName, envName) - } - return productInfo, nil -} - -func getChartRepoData(repoName string) (*commonmodels.HelmRepo, error) { - return commonrepo.NewHelmRepoColl().Find(&commonrepo.HelmRepoFindOption{RepoName: repoName}) -} - -func createChartRepoClient(repo *commonmodels.HelmRepo) (*cm.Client, error) { - client, err := cm.NewClient( - cm.URL(repo.URL), - cm.Username(repo.Username), - cm.Password(repo.Password), - // need support more auth types - ) - if err != nil { - return nil, errors.Wrapf(err, "failed to create chart repo client, repoName: %s", repo.RepoName) - } - return client, nil -} - -// find all images in one single chart -func extractImages(productService *commonmodels.ProductService, registryMap map[string]*commonmodels.RegistryNamespace) (*ServiceImageDetails, error) { - imageUrlsSet := sets.NewString() - for _, container := range productService.Containers { - imageUrlsSet.Insert(container.Image) - } - - ret := &ServiceImageDetails{ - ServiceName: productService.ServiceName, - Images: make([]*ImageUrlDetail, 0), - } - - registrySet := sets.NewString() - - for _, imageUrl := range imageUrlsSet.List() { - - registryUrl, err := commonservice.ExtractImageRegistry(imageUrl) - if err != nil { - return nil, errors.Wrapf(err, "failed to parse registry from image uri: %s", imageUrl) - } - registryUrl = strings.TrimSuffix(registryUrl, "/") - - imageName := commonservice.ExtractImageName(imageUrl) - imageTag := commonservice.ExtractImageTag(imageUrl) - - registryID := "" - // used source registry - if registry, ok := registryMap[registryUrl]; ok { - registryID = registry.ID.Hex() - registrySet.Insert(registryID) - } - - ret.Images = append(ret.Images, &ImageUrlDetail{ - ImageUrl: imageUrl, - Name: imageName, - Tag: imageTag, - Registry: registryID, - }) - } - - ret.Registries = registrySet.List() - return ret, nil -} - -// ensure chart files exist -func ensureChartFiles(chartData *DeliveryChartData) (string, error) { - serviceObj := chartData.ServiceObj - revisionBasePath := config.LocalDeliveryChartPathWithRevision(serviceObj.ProductName, serviceObj.ServiceName, serviceObj.Revision) - deliveryChartPath := filepath.Join(revisionBasePath, serviceObj.ServiceName) - if exists, _ := fsutil.DirExists(deliveryChartPath); exists { - return deliveryChartPath, nil - } - - serviceName, revision := serviceObj.ServiceName, serviceObj.Revision - basePath := config.LocalServicePathWithRevision(serviceObj.ProductName, serviceName, revision) - if err := commonservice.PreloadServiceManifestsByRevision(basePath, serviceObj); err != nil { - log.Warnf("failed to get chart of revision: %d for service: %s, use latest version", revision, serviceName) - // use the latest version when it fails to download the specific version - basePath = config.LocalServicePath(serviceObj.ProductName, serviceName) - if err = commonservice.PreLoadServiceManifests(basePath, serviceObj); err != nil { - log.Errorf("failed to load chart info for service %v", serviceObj.ServiceName) - return "", err - } - } - - fullPath := filepath.Join(basePath, serviceObj.ServiceName) - err := copy.Copy(fullPath, deliveryChartPath) - if err != nil { - return "", err - } - - mergedValuesYaml, err := helmtool.MergeOverrideValues(chartData.RenderChart.ValuesYaml, chartData.RenderSet.DefaultValues, chartData.RenderChart.GetOverrideYaml(), chartData.RenderChart.OverrideValues) - if err != nil { - return "", err - } - err = os.WriteFile(filepath.Join(deliveryChartPath, setting.ValuesYaml), []byte(mergedValuesYaml), 0644) - if err != nil { - return "", errors.Wrapf(err, "failed to write values.yaml") - } - - return deliveryChartPath, nil -} - -func buildChartPackage(chartData *DeliveryChartData, chartRepo *commonmodels.HelmRepo, dir string, globalVariables string, registryMap map[string]*commonmodels.RegistryNamespace) error { - serviceObj := chartData.ServiceObj - - deliveryChartPath, err := ensureChartFiles(chartData) - if err != nil { - return err - } - - valuesYamlData := make(map[string]interface{}) - valuesFilePath := filepath.Join(deliveryChartPath, setting.ValuesYaml) - valueYamlContent, err := os.ReadFile(valuesFilePath) - if err != nil { - return errors.Wrapf(err, "failed to read values.yaml for service %s", serviceObj.ServiceName) - } - err = yaml.Unmarshal(valueYamlContent, &valuesYamlData) - if err != nil { - return errors.Wrapf(err, "failed to unmarshal values.yaml for service %s", serviceObj.ServiceName) - } - - // write values.yaml file before load - if len(chartData.ChartData.ValuesYamlContent) > 0 { // values.yaml was edited directly - if err = yaml.Unmarshal([]byte(chartData.ChartData.ValuesYamlContent), map[string]interface{}{}); err != nil { - log.Errorf("invalid yaml content, serviceName: %s, yamlContent: %s", serviceObj.ServiceName, chartData.ChartData.ValuesYamlContent) - return errors.Wrapf(err, "invalid yaml content for service: %s", serviceObj.ServiceName) - } - valueYamlContent = []byte(chartData.ChartData.ValuesYamlContent) - } else if len(globalVariables) > 0 { // merge global variables - valueYamlContent, err = yamlutil.Merge([][]byte{valueYamlContent, []byte(globalVariables)}) - if err != nil { - return errors.Wrapf(err, "failed to merge global variables for service: %s", serviceObj.ServiceName) - } - } - err = os.WriteFile(valuesFilePath, valueYamlContent, 0644) - if err != nil { - return errors.Wrapf(err, "failed to write values.yaml file for service %s", serviceObj.ServiceName) - } - - //load chart info from local storage - chartRequested, err := chartloader.Load(deliveryChartPath) - if err != nil { - return errors.Wrapf(err, "failed to load chart info, path %s", deliveryChartPath) - } - - //set metadata - chartRequested.Metadata.Name = chartData.ChartData.ServiceName - chartRequested.Metadata.Version = chartData.ChartData.Version - chartRequested.Metadata.AppVersion = chartData.ChartData.Version - - //create local chart package - chartPackagePath, err := helm.CreateChartPackage(&helm.Chart{Chart: chartRequested}, dir) - if err != nil { - return err - } - - client, err := createChartRepoClient(chartRepo) - if err != nil { - return errors.Wrapf(err, "failed to create chart repo client, repoName: %s", chartRepo.RepoName) - } - - log.Infof("pushing chart %s to %s...", filepath.Base(chartPackagePath), chartRepo.URL) - resp, err := client.UploadChartPackage(chartPackagePath, false) - if err != nil { - return errors.Wrapf(err, "failed to prepare pushing chart: %s", chartPackagePath) - } - err = handlePushResponse(resp) - if err != nil { - return errors.Wrapf(err, "failed to push chart: %s ", chartPackagePath) - } - return nil -} - -func handlePushResponse(resp *http.Response) error { - if resp.StatusCode != 201 && resp.StatusCode != 202 { - b, err := ioutil.ReadAll(resp.Body) - defer func(Body io.ReadCloser) { - _ = Body.Close() - }(resp.Body) - if err != nil { - return err - } - return getChartmuseumError(b, resp.StatusCode) - } - log.Infof("push chart to chart repo done") - return nil -} - -func getChartmuseumError(b []byte, code int) error { - var er struct { - Error string `json:"error"` - } - err := json.Unmarshal(b, &er) - if err != nil || er.Error == "" { - return errors.Errorf("%d: could not properly parse response JSON: %s", code, string(b)) - } - return errors.Errorf("%d: %s", code, er.Error) -} - -func makeChartTGZFileDir(productName, versionName string) (string, error) { - path := getChartTGZDir(productName, versionName) - if err := os.RemoveAll(path); err != nil { - if !os.IsExist(err) { - return "", errors.Wrapf(err, "failed to claer dir for chart tgz files") - } - } - err := os.MkdirAll(path, 0777) - if err != nil { - return "", errors.Wrapf(err, "failed to create chart tgz dir for version: %s", versionName) - } - return path, nil -} - -func CreateHelmDeliveryVersion(args *CreateHelmDeliveryVersionArgs, logger *zap.SugaredLogger) error { - if args.Retry { - return RetryCreateHelmDeliveryVersion(args.ProductName, args.Version, logger) - } else { - return CreateNewHelmDeliveryVersion(args, logger) - } -} - -// validate chartInfo, make sure service is in environment -// prepare data set for chart delivery -func prepareChartData(chartDatas []*CreateHelmDeliveryVersionChartData, productInfo *commonmodels.Product) (map[string]*DeliveryChartData, error) { - - renderSet, err := commonrepo.NewRenderSetColl().Find(&commonrepo.RenderSetFindOption{ - Revision: productInfo.Render.Revision, - Name: productInfo.Render.Name, - }) - if err != nil { - return nil, fmt.Errorf("failed to find renderSet: %s, revision: %d", productInfo.Render.Name, productInfo.Render.Revision) - } - chartMap := make(map[string]*template.RenderChart) - for _, rChart := range renderSet.ChartInfos { - chartMap[rChart.ServiceName] = rChart - } - - chartDataMap := make(map[string]*DeliveryChartData) - serviceMap := productInfo.GetServiceMap() - for _, chartData := range chartDatas { - if productService, ok := serviceMap[chartData.ServiceName]; ok { - serviceObj, err := commonrepo.NewServiceColl().Find(&commonrepo.ServiceFindOption{ - ServiceName: chartData.ServiceName, - Revision: productService.Revision, - Type: setting.HelmDeployType, - ProductName: productInfo.ProductName, - }) - if err != nil { - return nil, fmt.Errorf("failed to query service: %s", chartData.ServiceName) - } - renderChart, ok := chartMap[chartData.ServiceName] - if !ok { - return nil, fmt.Errorf("can't find renderChart for service: %s", chartData.ServiceName) - } - chartDataMap[chartData.ServiceName] = &DeliveryChartData{ - ChartData: chartData, - RenderChart: renderChart, - ServiceObj: serviceObj, - ProductService: productService, - RenderSet: renderSet, - } - } else { - return nil, fmt.Errorf("service %s not found in environment", chartData.ServiceName) - } - } - return chartDataMap, nil -} - -func buildRegistryMap() (map[string]*commonmodels.RegistryNamespace, error) { - registries, err := commonrepo.NewRegistryNamespaceColl().FindAll(&mongodb.FindRegOps{}) - if err != nil { - return nil, fmt.Errorf("failed to query registries") - } - ret := make(map[string]*commonmodels.RegistryNamespace) - for _, singleRegistry := range registries { - fullUrl := fmt.Sprintf("%s/%s", singleRegistry.RegAddr, singleRegistry.Namespace) - fullUrl = strings.TrimSuffix(fullUrl, "/") - u, _ := url.Parse(fullUrl) - if len(u.Scheme) > 0 { - fullUrl = strings.TrimPrefix(fullUrl, fmt.Sprintf("%s://", u.Scheme)) - } - ret[fullUrl] = singleRegistry - } - return ret, nil -} - -func buildArtifactTaskArgs(projectName, envName string, imagesMap *sync.Map) *commonmodels.ArtifactPackageTaskArgs { - imageArgs := make([]*commonmodels.ImagesByService, 0) - sourceRegistry := sets.NewString() - imagesMap.Range(func(key, value interface{}) bool { - imageDetail := value.(*ServiceImageDetails) - imagesByService := &commonmodels.ImagesByService{ - ServiceName: imageDetail.ServiceName, - Images: make([]*commonmodels.ImageData, 0), - } - for _, image := range imageDetail.Images { - imagesByService.Images = append(imagesByService.Images, &commonmodels.ImageData{ - ImageUrl: image.ImageUrl, - ImageName: image.Name, - ImageTag: image.Tag, - RegistryID: image.Registry, - }) - } - imageArgs = append(imageArgs, imagesByService) - sourceRegistry.Insert(imageDetail.Registries...) - return true - }) - - ret := &commonmodels.ArtifactPackageTaskArgs{ - ProjectName: projectName, - EnvName: envName, - Images: imageArgs, - SourceRegistries: sourceRegistry.List(), - } - return ret -} - -// insert delivery distribution data for single chart, include image and chart -func insertDeliveryDistributions(result *task.ServicePackageResult, chartVersion string, deliveryVersion *commonmodels.DeliveryVersion, args *DeliveryVersionChartData) error { - for _, image := range result.ImageData { - err := commonrepo.NewDeliveryDistributeColl().Insert(&commonmodels.DeliveryDistribute{ - ReleaseID: deliveryVersion.ID, - ServiceName: image.ImageName, // image name - ChartName: result.ServiceName, - DistributeType: config.Image, - RegistryName: image.ImageUrl, - Namespace: commonservice.ExtractRegistryNamespace(image.ImageUrl), - CreatedAt: time.Now().Unix(), - }) - if err != nil { - log.Errorf("failed to insert image distribute data, chartName: %s, err: %s", result.ServiceName, err) - return fmt.Errorf("failed to insert image distribute data, chartName: %s", result.ServiceName) - } - } - - err := commonrepo.NewDeliveryDistributeColl().Insert(&commonmodels.DeliveryDistribute{ - ReleaseID: deliveryVersion.ID, - DistributeType: config.Chart, - ChartName: result.ServiceName, - ChartVersion: chartVersion, - ChartRepoName: args.ChartRepoName, - SubDistributes: nil, - CreatedAt: time.Now().Unix(), - }) - if err != nil { - log.Errorf("failed to insert chart distribute data, chartName: %s, err: %s", result.ServiceName, err) - return fmt.Errorf("failed to insert chart distribute data, chartName: %s", result.ServiceName) - } - return nil -} - -func buildDeliveryCharts(chartDataMap map[string]*DeliveryChartData, deliveryVersion *commonmodels.DeliveryVersion, args *DeliveryVersionChartData, logger *zap.SugaredLogger) (err error) { - defer func() { - if err != nil { - deliveryVersion.Status = setting.DeliveryVersionStatusFailed - deliveryVersion.Error = err.Error() - } - err = commonrepo.NewDeliveryVersionColl().UpdateStatusByName(deliveryVersion.Version, deliveryVersion.Status, deliveryVersion.Error) - if err != nil { - logger.Errorf("failed to update delivery version data, name: %s error: %s", deliveryVersion.Version, err) - } - }() - - var errLock sync.Mutex - errorList := &multierror.Error{} - - appendError := func(err error) { - errLock.Lock() - defer errLock.Unlock() - errorList = multierror.Append(errorList, err) - } - - dir, err := makeChartTGZFileDir(deliveryVersion.ProductName, deliveryVersion.Version) - if err != nil { - return err - } - repoInfo, err := getChartRepoData(args.ChartRepoName) - if err != nil { - log.Errorf("failed to query chart-repo info, productName: %s, err: %s", deliveryVersion.ProductName, err) - return fmt.Errorf("failed to query chart-repo info, productName: %s, repoName: %s", deliveryVersion.ProductName, args.ChartRepoName) - } - - registryMap, err := buildRegistryMap() - if err != nil { - return fmt.Errorf("failed to build registry map") - } - - imagesDataMap := &sync.Map{} - - // push charts to repo - wg := sync.WaitGroup{} - for _, chartData := range chartDataMap { - wg.Add(1) - go func(cData *DeliveryChartData) { - defer wg.Done() - err := buildChartPackage(cData, repoInfo, dir, args.GlobalVariables, registryMap) - if err != nil { - logger.Errorf("failed to build chart package, serviceName: %s err: %s", cData.ChartData.ServiceName, err) - appendError(err) - return - } - imageData, err := extractImages(cData.ProductService, registryMap) - if err != nil { - logger.Errorf("failed to extract image data, serviceName: %s err: %s", cData.ChartData.ServiceName, err) - appendError(err) - return - } - imagesDataMap.Store(cData.ServiceObj.ServiceName, imageData) - }(chartData) - } - wg.Wait() - - if errorList.ErrorOrNil() != nil { - err = errorList.ErrorOrNil() - return - } - - // create task to deal with images - // offline docker images are not supported - taskArgs := buildArtifactTaskArgs(deliveryVersion.ProductName, deliveryVersion.ProductEnvInfo.EnvName, imagesDataMap) - taskArgs.TargetRegistries = []string{args.ImageRegistryID} - taskID, err := workflowservice.CreateArtifactPackageTask(taskArgs, deliveryVersion.Version, logger) - if err != nil { - return err - } - deliveryVersion.TaskID = int(taskID) - - // start a new routine to check task results - go waitVersionDone(deliveryVersion) - - return -} - -func updateVersionStatus(versionName, status, errStr string) { - err := commonrepo.NewDeliveryVersionColl().UpdateStatusByName(versionName, status, errStr) - if err != nil { - log.Errorf("failed to update version status, name: %s, err: %s", versionName, err) - } -} - -func taskFinished(status config.Status) bool { - return status == config.StatusPassed || status == config.StatusFailed || status == config.StatusTimeout || status == config.StatusCancelled -} - -func waitVersionDone(deliveryVersion *commonmodels.DeliveryVersion) { - waitTimeout := time.After(60 * time.Minute * 2) - for { - select { - case <-waitTimeout: - updateVersionStatus(deliveryVersion.Version, setting.DeliveryVersionStatusFailed, "timeout") - return - default: - done, err := checkVersionStatus(deliveryVersion) - if err != nil { - updateVersionStatus(deliveryVersion.Version, setting.DeliveryVersionStatusFailed, err.Error()) - return - } - if done { - return - } - } - time.Sleep(time.Second * 5) - } -} - -func checkVersionStatus(deliveryVersion *commonmodels.DeliveryVersion) (bool, error) { - if deliveryVersion.Status == setting.DeliveryVersionStatusSuccess || deliveryVersion.Status == setting.DeliveryVersionStatusFailed { - return true, nil - } - pipelineName := fmt.Sprintf("%s-%s-%s", deliveryVersion.ProductName, deliveryVersion.ProductEnvInfo.EnvName, "artifact") - taskData, err := commonrepo.NewTaskColl().Find(int64(deliveryVersion.TaskID), pipelineName, config.ArtifactType) - if err != nil { - return false, fmt.Errorf("failed to query taskData, id: %d, pipelineName: %s", deliveryVersion.TaskID) - } - - if len(taskData.Stages) != 1 { - return false, fmt.Errorf("invalid task data, stage length not leagal") - } - - argsBytes, err := json.Marshal(deliveryVersion.CreateArgument) - if err != nil { - return false, errors.Wrapf(err, "failed to marshal arguments, versionName: %s err: %s", deliveryVersion.Version, err) - } - createArgs := new(DeliveryVersionChartData) - err = json.Unmarshal(argsBytes, createArgs) - if err != nil { - return false, errors.Wrapf(err, "failed to unMarshal arguments, versionName: %s err: %s", deliveryVersion.Version, err) - } - - distributes, err := commonrepo.NewDeliveryDistributeColl().Find(&commonrepo.DeliveryDistributeArgs{ - DistributeType: config.Chart, - ReleaseID: deliveryVersion.ID.Hex(), - }) - if err != nil { - return false, errors.Wrapf(err, "failed to query distrubutes, versionName: %s", deliveryVersion.Version) - } - - // for charts has been successfully handled, download charts directly - successCharts := sets.NewString() - for _, distribute := range distributes { - successCharts.Insert(distribute.ChartName) - } - - stage := taskData.Stages[0] - errorList := &multierror.Error{} - - allTaskDone := true - for _, taskData := range stage.SubTasks { - artifactPackageArgs, err := base.ToArtifactPackageImageTask(taskData) - if err != nil { - return false, errors.Wrapf(err, "failed to generate origin artifact task data") - } - - progressData, err := artifactPackageArgs.GetProgress() - if err != nil { - return false, errors.Wrapf(err, "failed to get progress data from data") - } - progressDataMap := make(map[string]*task.ServicePackageResult) - for _, singleResult := range progressData { - progressDataMap[singleResult.ServiceName] = singleResult - } - - for _, chartData := range createArgs.ChartDatas { - // service artifact has been marked as success - if successCharts.Has(chartData.ServiceName) { - continue - } - if singleResult, ok := progressDataMap[chartData.ServiceName]; ok { - if singleResult.Result != "success" { - errorList = multierror.Append(errorList, fmt.Errorf("failed to build image distribute for service:%s ", singleResult.ServiceName)) - continue - } - err = insertDeliveryDistributions(singleResult, chartData.Version, deliveryVersion, createArgs) - if err != nil { - errorList = multierror.Append(errorList, fmt.Errorf("failed to insert distribute data for service:%s ", singleResult.ServiceName)) - continue - } - successCharts.Insert(chartData.ServiceName) - } - } - - if !taskFinished(artifactPackageArgs.TaskStatus) { - allTaskDone = false - } - if len(artifactPackageArgs.Error) > 0 { - errorList = multierror.Append(errorList, fmt.Errorf(artifactPackageArgs.Error)) - } - } - - if allTaskDone { - if successCharts.Len() == len(createArgs.ChartDatas) { - deliveryVersion.Status = setting.DeliveryVersionStatusSuccess - } else { - deliveryVersion.Status = setting.DeliveryVersionStatusFailed - } - } - if errorList.ErrorOrNil() != nil { - deliveryVersion.Error = errorList.Error() - } - updateVersionStatus(deliveryVersion.Version, deliveryVersion.Status, deliveryVersion.Error) - return allTaskDone, nil -} - -func CreateNewHelmDeliveryVersion(args *CreateHelmDeliveryVersionArgs, logger *zap.SugaredLogger) error { - // need appoint chart info - if len(args.ChartDatas) == 0 { - return e.ErrCreateDeliveryVersion.AddDesc("no chart info appointed") - } - - // prepare data - productInfo, err := getProductEnvInfo(args.ProductName, args.EnvName) - if err != nil { - log.Infof("failed to query product info, productName: %s envName %s, err: %s", args.ProductName, args.EnvName, err) - return e.ErrCreateDeliveryVersion.AddDesc(fmt.Sprintf("failed to query product info, procutName: %s envName %s", args.ProductName, args.EnvName)) - } - - // validate necessary params - if len(args.ChartRepoName) == 0 { - return e.ErrCreateDeliveryVersion.AddDesc("chart repo not appointed") - } - if len(args.ImageRegistryID) == 0 { - return e.ErrCreateDeliveryVersion.AddDesc("image registry not appointed") - } - - chartDataMap, err := prepareChartData(args.ChartDatas, productInfo) - if err != nil { - return e.ErrCreateDeliveryVersion.AddErr(err) - } - - productInfo.ID, _ = primitive.ObjectIDFromHex("") - - versionObj := &commonmodels.DeliveryVersion{ - Version: args.Version, - ProductName: args.ProductName, - Type: setting.DeliveryVersionTypeChart, - Desc: args.Desc, - Labels: args.Labels, - ProductEnvInfo: productInfo, - Status: setting.DeliveryVersionStatusCreating, - CreateArgument: args.DeliveryVersionChartData, - CreatedBy: args.CreateBy, - CreatedAt: time.Now().Unix(), - DeletedAt: 0, - } - - err = buildDeliveryCharts(chartDataMap, versionObj, args.DeliveryVersionChartData, logger) - if err != nil { - return err - } - - err = commonrepo.NewDeliveryVersionColl().Insert(versionObj) - if err != nil { - logger.Errorf("failed to insert version data, err: %s", err) - return e.ErrCreateDeliveryVersion.AddErr(fmt.Errorf("failed to insert delivery version: %s", versionObj.Version)) - } - - return nil -} - -func RetryCreateHelmDeliveryVersion(projectName, versionName string, logger *zap.SugaredLogger) error { - deliveryVersion, err := commonrepo.NewDeliveryVersionColl().Get(&commonrepo.DeliveryVersionArgs{ - ProductName: projectName, - Version: versionName, - }) - if err != nil { - logger.Errorf("failed to query delivery version data, verisonName: %s, error: %s", versionName, err) - return fmt.Errorf("failed to query delivery version data, verisonName: %s", versionName) - } - - if deliveryVersion.Status != setting.DeliveryVersionStatusFailed { - return fmt.Errorf("can't reCreate version with status:%s", deliveryVersion.Status) - } - - argsBytes, err := json.Marshal(deliveryVersion.CreateArgument) - if err != nil { - return errors.Wrapf(err, "failed to marshal arguments, versionName: %s err: %s", deliveryVersion.Version, err) - } - createArgs := new(DeliveryVersionChartData) - err = json.Unmarshal(argsBytes, createArgs) - if err != nil { - return errors.Wrapf(err, "failed to unMarshal arguments, versionName: %s err: %s", deliveryVersion.Version, err) - } - - productInfoSnap := deliveryVersion.ProductEnvInfo - - distributes, err := commonrepo.NewDeliveryDistributeColl().Find(&commonrepo.DeliveryDistributeArgs{ - DistributeType: config.Chart, - ReleaseID: deliveryVersion.ID.Hex(), - }) - if err != nil { - return errors.Wrapf(err, "failed to query distrubutes, versionName: %s", deliveryVersion.Version) - } - - // for charts has been successfully handled, download charts directly - successCharts := sets.NewString() - for _, distribute := range distributes { - if distribute.DistributeType != config.Chart { - continue - } - _, err := downloadChart(deliveryVersion, distribute) - if err != nil { - log.Errorf("failed to download chart from chart repo, chartName: %s, err: %s", distribute.ChartName, err) - continue - } - successCharts.Insert(distribute.ChartName) - } - - chartsToBeHandled := make([]*CreateHelmDeliveryVersionChartData, 0) - for _, chartConfig := range createArgs.ChartDatas { - if successCharts.Has(chartConfig.ServiceName) { - continue - } - chartsToBeHandled = append(chartsToBeHandled, chartConfig) - } - - chartDataMap, err := prepareChartData(chartsToBeHandled, productInfoSnap) - if err != nil { - return e.ErrCreateDeliveryVersion.AddErr(err) - } - - err = buildDeliveryCharts(chartDataMap, deliveryVersion, createArgs, logger) - if err != nil { - return err - } - - // update status - deliveryVersion.Status = setting.DeliveryVersionStatusRetrying - err = commonrepo.NewDeliveryVersionColl().UpdateStatusByName(deliveryVersion.Version, deliveryVersion.Status, "") - if err != nil { - logger.Errorf("failed to update delivery status, name: %s, err: %s", deliveryVersion.Version, err) - return fmt.Errorf("failed to update delivery status, name: %s", deliveryVersion.Version) - } - - return nil -} - -func ListDeliveryServiceNames(productName string, log *zap.SugaredLogger) ([]string, error) { - serviceNames := sets.String{} - - version := new(commonrepo.DeliveryVersionArgs) - version.ProductName = productName - deliveryVersions, err := FindDeliveryVersion(version, log) - if err != nil { - log.Errorf("FindDeliveryVersion failed, err:%v", err) - return serviceNames.List(), err - } - - for _, deliveryVersion := range deliveryVersions { - deliveryDeployArgs := new(commonrepo.DeliveryDeployArgs) - deliveryDeployArgs.ReleaseID = deliveryVersion.ID.Hex() - deliveryDeploys, err := FindDeliveryDeploy(deliveryDeployArgs, log) - if err != nil { - log.Errorf("FindDeliveryDeploy failed, ReleaseID:%s, err:%v", deliveryVersion.ID, err) - continue - } - for _, deliveryDeploy := range deliveryDeploys { - serviceNames.Insert(deliveryDeploy.ServiceName) + for _, deliveryDeploy := range deliveryDeploys { + serviceNames.Insert(deliveryDeploy.ServiceName) } } return serviceNames.UnsortedList(), nil } - -func downloadChart(deliveryVersion *commonmodels.DeliveryVersion, chartInfo *commonmodels.DeliveryDistribute) (string, error) { - productName, versionName := deliveryVersion.ProductName, deliveryVersion.Version - chartTGZName := fmt.Sprintf("%s-%s.tgz", chartInfo.ChartName, chartInfo.ChartVersion) - chartTGZFileParent := getChartTGZDir(productName, versionName) - chartTGZFilePath := filepath.Join(chartTGZFileParent, chartTGZName) - if _, err := os.Stat(chartTGZFilePath); err == nil { - // local cache exists - log.Infof("local cache exists, path %s", chartTGZFilePath) - return chartTGZFilePath, nil - } - - chartRepo, err := getChartRepoData(chartInfo.ChartRepoName) - if err != nil { - return "", fmt.Errorf("failed to query chart-repo info, repoName %s", chartInfo.ChartRepoName) - } - - client, err := createChartRepoClient(chartRepo) - if err != nil { - return "", err - } - - if err = os.MkdirAll(chartTGZFileParent, 0644); err != nil { - return "", errors.Wrapf(err, "failed to craete tgz parent dir") - } - - out, err := os.Create(chartTGZFilePath) - if err != nil { - _ = os.RemoveAll(chartTGZFilePath) - return "", errors.Wrapf(err, "failed to create chart tgz file") - } - - response, err := client.DownloadFile(fmt.Sprintf("charts/%s", chartTGZName)) - if err != nil { - return "", errors.Wrapf(err, "failed to download file") - } - - if response.StatusCode != 200 { - return "", errors.Wrapf(err, "download file failed %s", chartTGZName) - } - defer func() { _ = response.Body.Close() }() - - b, err := ioutil.ReadAll(response.Body) - if err != nil { - return "", errors.Wrapf(err, "failed to read response data") - } - - defer func(out *os.File) { - _ = out.Close() - }(out) - - err = ioutil.WriteFile(chartTGZFilePath, b, 0644) - if err != nil { - return "", err - } - return chartTGZFilePath, nil -} - -func getChartDistributeInfo(releaseID, chartName string, log *zap.SugaredLogger) (*commonmodels.DeliveryDistribute, error) { - distributes, _ := FindDeliveryDistribute(&commonrepo.DeliveryDistributeArgs{ - ReleaseID: releaseID, - ChartName: chartName, - DistributeType: config.Chart, - }, log) - - if len(distributes) != 1 { - log.Warnf("find chart %s failed, expect count %d, found count %d, release_id: %s", chartName, 1, len(distributes), releaseID) - return nil, fmt.Errorf("can't find target charts") - } - - chartInfo := distributes[0] - return chartInfo, nil -} - -func DownloadDeliveryChart(projectName, version string, chartName string, log *zap.SugaredLogger) ([]byte, string, error) { - - filePath, err := preDownloadChart(projectName, version, chartName, log) - if err != nil { - return nil, "", err - } - - fileBytes, err := os.ReadFile(filePath) - if err != nil { - return nil, "", err - } - - return fileBytes, filepath.Base(filePath), err -} - -func preDownloadChart(projectName, versionName, chartName string, log *zap.SugaredLogger) (string, error) { - deliveryInfo, err := GetDeliveryVersion(&commonrepo.DeliveryVersionArgs{ - ProductName: projectName, - Version: versionName, - }, log) - if err != nil { - return "", fmt.Errorf("failed to query delivery info") - } - - chartInfo, err := getChartDistributeInfo(deliveryInfo.ID.Hex(), chartName, log) - if err != nil { - return "", err - } - // prepare chart data - filePath, err := downloadChart(deliveryInfo, chartInfo) - if err != nil { - return "", err - } - return filePath, err -} - -func GetChartVersions(chartName, chartRepoName string) ([]*ChartVersionResp, error) { - - chartRepo, err := getChartRepoData(chartRepoName) - if err != nil { - return nil, fmt.Errorf("failed to query chart-repo info, repoName %s", chartRepoName) - } - - client, err := createChartRepoClient(chartRepo) - if err != nil { - return nil, errors.Wrapf(err, "failed to create chart repo client") - } - - resp, err := client.DownloadFile("index.yaml") - if err != nil { - return nil, errors.Wrapf(err, "failed to download index.yaml") - } - - defer func(Body io.ReadCloser) { - _ = Body.Close() - }(resp.Body) - - b, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, err - } - - if resp.StatusCode != 200 { - return nil, errors.Wrapf(getChartmuseumError(b, resp.StatusCode), "failed to download index.yaml") - } - - index, err := helm.LoadIndex(b) - if err != nil { - return nil, errors.Wrapf(err, "failed to parse index.yaml") - } - - chartNameList := strings.Split(chartName, ",") - chartNameSet := sets.NewString(chartNameList...) - - ret := make([]*ChartVersionResp, 0) - - for name, entry := range index.Entries { - if !chartNameSet.Has(name) { - continue - } - if len(entry) == 0 { - continue - } - latestEntry := entry[0] - ret = append(ret, &ChartVersionResp{ - ChartName: name, - ChartVersion: latestEntry.Version, - }) - } - - return ret, nil -} - -func preDownloadAndUncompressChart(projectName, versionName, chartName string, log *zap.SugaredLogger) (string, error) { - - deliveryInfo, err := GetDeliveryVersion(&commonrepo.DeliveryVersionArgs{ - ProductName: projectName, - Version: versionName, - }, log) - if err != nil { - return "", fmt.Errorf("failed to query delivery info") - } - - chartDistribute, err := getChartDistributeInfo(deliveryInfo.ID.Hex(), chartName, log) - if err != nil { - return "", err - } - dstDir := getChartExpandDir(projectName, versionName) - dstDir = filepath.Join(dstDir, fmt.Sprintf("%s-%s", chartDistribute.ChartName, chartDistribute.ChartVersion)) - - filePath, err := preDownloadChart(projectName, versionName, chartName, log) - if err != nil { - return "", err - } - - file, err := os.Open(filePath) - if err != nil { - return "", errors.Wrap(err, "unable to open tarball") - } - defer func() { _ = file.Close() }() - - err = chartutil.Expand(dstDir, file) - if err != nil { - log.Errorf("failed to uncompress file: %s", filePath) - return "", errors.Wrapf(err, "failed to uncompress file") - } - return dstDir, nil -} - -func PreviewDeliveryChart(projectName, version, chartName string, log *zap.SugaredLogger) (*DeliveryChartResp, error) { - - dstDir, err := preDownloadAndUncompressChart(projectName, version, chartName, log) - if err != nil { - return nil, err - } - - ret := &DeliveryChartResp{ - FileInfos: make([]*types.FileInfo, 0), - } - - var fis []*types.FileInfo - files, err := os.ReadDir(filepath.Join(dstDir, chartName)) - if err != nil { - return nil, err - } - - for _, file := range files { - info, _ := file.Info() - if info == nil { - continue - } - fi := &types.FileInfo{ - Parent: "", - Name: file.Name(), - Size: info.Size(), - Mode: file.Type(), - ModTime: info.ModTime().Unix(), - IsDir: file.IsDir(), - } - - fis = append(fis, fi) - } - ret.FileInfos = fis - return ret, nil -} - -// load chart file infos -func loadChartFileInfos(fileDir, chartName string, dir string) ([]*types.FileInfo, error) { - var fis []*types.FileInfo - files, err := os.ReadDir(filepath.Join(fileDir, chartName, dir)) - if err != nil { - return nil, e.ErrFilePath.AddDesc(err.Error()) - } - - for _, file := range files { - info, _ := file.Info() - if info == nil { - continue - } - fi := &types.FileInfo{ - Parent: dir, - Name: file.Name(), - Size: info.Size(), - Mode: file.Type(), - ModTime: info.ModTime().Unix(), - IsDir: file.IsDir(), - } - fis = append(fis, fi) - } - return fis, nil -} - -func GetDeliveryChartFilePath(args *DeliveryChartFilePathArgs, log *zap.SugaredLogger) ([]*types.FileInfo, error) { - projectName, version, chartName := args.ProjectName, args.Version, args.ChartName - dstDir, err := preDownloadAndUncompressChart(projectName, version, chartName, log) - if err != nil { - return nil, nil - } - - fileInfos, err := loadChartFileInfos(dstDir, chartName, args.Dir) - if err != nil { - return nil, err - } - return fileInfos, nil -} - -func GetDeliveryChartFileContent(args *DeliveryChartFileContentArgs, log *zap.SugaredLogger) (string, error) { - projectName, version, chartName := args.ProjectName, args.Version, args.ChartName - dstDir, err := preDownloadAndUncompressChart(projectName, version, chartName, log) - if err != nil { - return "", nil - } - - file := filepath.Join(dstDir, chartName, args.FilePath, args.FileName) - fileContent, err := os.ReadFile(file) - if err != nil { - log.Errorf("Failed to read file %s, err: %s", file, err) - return "", e.ErrFileContent.AddDesc(err.Error()) - } - - return string(fileContent), nil -} - -func ApplyDeliveryGlobalVariables(args *DeliveryVariablesApplyArgs, logger *zap.SugaredLogger) (interface{}, error) { - ret := new(DeliveryVariablesApplyArgs) - for _, chartData := range args.ChartDatas { - mergedYaml, err := yamlutil.Merge([][]byte{[]byte(chartData.ValuesYamlContent), []byte(args.GlobalVariables)}) - if err != nil { - logger.Errorf("failed to merge gobal variables for service: %s", chartData.ServiceName) - return nil, errors.Wrapf(err, "failed to merge global variables for service: %s", chartData.ServiceName) - } - ret.ChartDatas = append(ret.ChartDatas, &CreateHelmDeliveryVersionChartData{ - ServiceName: chartData.ServiceName, - ValuesYamlContent: string(mergedYaml), - }) - } - return ret, nil -} diff --git a/pkg/microservice/aslan/core/environment/handler/helm.go b/pkg/microservice/aslan/core/environment/handler/helm.go deleted file mode 100644 index 9e097cd91..000000000 --- a/pkg/microservice/aslan/core/environment/handler/helm.go +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright 2021 The KodeRover Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package handler - -import ( - "github.com/gin-gonic/gin" - "github.com/koderover/zadig/pkg/microservice/aslan/core/environment/service" - internalhandler "github.com/koderover/zadig/pkg/shared/handler" -) - -func ListReleases(c *gin.Context) { - ctx := internalhandler.NewContext(c) - defer func() { internalhandler.JSONResponse(c, ctx) }() - envName := c.Param("name") - projectName := c.Query("projectName") - ctx.Resp, ctx.Err = service.ListReleases(projectName, envName, ctx.Logger) -} - -func GetChartInfos(c *gin.Context) { - ctx := internalhandler.NewContext(c) - defer func() { internalhandler.JSONResponse(c, ctx) }() - envName := c.Param("name") - servicesName := c.Query("serviceName") - projectName := c.Query("projectName") - ctx.Resp, ctx.Err = service.GetChartInfos(projectName, envName, servicesName, ctx.Logger) -} diff --git a/pkg/microservice/aslan/core/environment/handler/router.go b/pkg/microservice/aslan/core/environment/handler/router.go index 4204db671..f439c59ce 100644 --- a/pkg/microservice/aslan/core/environment/handler/router.go +++ b/pkg/microservice/aslan/core/environment/handler/router.go @@ -108,9 +108,6 @@ func (*Router) Inject(router *gin.RouterGroup) { environments.GET("/:name/groups", ListGroups) environments.GET("/:name/workloads", ListWorkloadsInEnv) - environments.GET("/:name/helm/releases", ListReleases) - environments.GET("/:name/helm/charts", GetChartInfos) - environments.GET("/:name/services/:serviceName", GetService) environments.PUT("/:name/services/:serviceName", gin2.UpdateOperationLogStatus, UpdateService) environments.POST("/:name/services/:serviceName/restart", gin2.UpdateOperationLogStatus, RestartService) diff --git a/pkg/microservice/aslan/core/environment/service/helm.go b/pkg/microservice/aslan/core/environment/service/helm.go deleted file mode 100644 index 255a2ba7d..000000000 --- a/pkg/microservice/aslan/core/environment/service/helm.go +++ /dev/null @@ -1,259 +0,0 @@ -/* -Copyright 2021 The KodeRover Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package service - -import ( - "fmt" - "os" - "path/filepath" - "strings" - "sync" - - "github.com/hashicorp/go-multierror" - "github.com/otiai10/copy" - "go.uber.org/zap" - - "github.com/koderover/zadig/pkg/microservice/aslan/config" - "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" - "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/template" - commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" - commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" - "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" - "github.com/koderover/zadig/pkg/setting" - e "github.com/koderover/zadig/pkg/tool/errors" - helmtool "github.com/koderover/zadig/pkg/tool/helmclient" - "github.com/koderover/zadig/pkg/tool/log" - "github.com/koderover/zadig/pkg/types" - "github.com/koderover/zadig/pkg/util" -) - -type HelmReleaseResp struct { - ReleaseName string `json:"releaseName"` - ServiceName string `json:"serviceName"` - Revision int `json:"revision"` - Chart string `json:"chart"` - AppVersion string `json:"appVersion"` -} - -type ChartInfo struct { - ServiceName string `json:"serviceName"` - Revision int64 `json:"revision"` -} - -type HelmChartsResp struct { - ChartInfos []*ChartInfo `json:"chartInfos"` - FileInfos []*types.FileInfo `json:"fileInfos"` -} - -func ListReleases(productName, envName string, log *zap.SugaredLogger) ([]*HelmReleaseResp, error) { - opt := &commonrepo.ProductFindOptions{Name: productName, EnvName: envName} - prod, err := commonrepo.NewProductColl().Find(opt) - if err != nil { - return nil, e.ErrCreateDeliveryVersion.AddDesc(err.Error()) - } - - restConfig, err := kube.GetRESTConfig(prod.ClusterID) - if err != nil { - log.Errorf("GetRESTConfig error: %v", err) - return nil, e.ErrCreateDeliveryVersion.AddDesc(err.Error()) - } - helmClient, err := helmtool.NewClientFromRestConf(restConfig, prod.Namespace) - if err != nil { - log.Errorf("[%s][%s] NewClientFromRestConf error: %v", envName, productName, err) - return nil, e.ErrCreateDeliveryVersion.AddErr(err) - } - - releases, err := helmClient.ListDeployedReleases() - if err != nil { - return nil, e.ErrCreateDeliveryVersion.AddErr(err) - } - - ret := make([]*HelmReleaseResp, 0, len(releases)) - for _, release := range releases { - ret = append(ret, &HelmReleaseResp{ - ReleaseName: release.Name, - ServiceName: util.ExtraServiceName(release.Name, prod.Namespace), - Revision: release.Version, - Chart: release.Chart.Name(), - AppVersion: release.Chart.AppVersion(), - }) - } - return ret, nil -} - -func loadChartFilesInfo(productName, serviceName string, revision int64, dir string) ([]*types.FileInfo, error) { - base := config.LocalServicePathWithRevision(productName, serviceName, revision) - - var fis []*types.FileInfo - files, err := os.ReadDir(filepath.Join(base, serviceName, dir)) - if err != nil { - log.Warnf("failed to read chart info for service %s with revision %d", serviceName, revision) - base = config.LocalServicePath(productName, serviceName) - files, err = os.ReadDir(filepath.Join(base, serviceName, dir)) - if err != nil { - return nil, err - } - } - - for _, file := range files { - info, _ := file.Info() - if info == nil { - continue - } - fi := &types.FileInfo{ - Parent: dir, - Name: file.Name(), - Size: info.Size(), - Mode: file.Type(), - ModTime: info.ModTime().Unix(), - IsDir: file.IsDir(), - } - - fis = append(fis, fi) - } - return fis, nil -} - -//prepare chart version data -func prepareChartVersionData(productName string, serviceObj *models.Service, renderChart *template.RenderChart, renderset *models.RenderSet) error { - serviceName, revision := serviceObj.ServiceName, serviceObj.Revision - base := config.LocalServicePathWithRevision(productName, serviceName, revision) - if err := commonservice.PreloadServiceManifestsByRevision(base, serviceObj); err != nil { - log.Warnf("failed to get chart of revision: %d for service: %s, use latest version", revision, serviceName) - // use the latest version when it fails to download the specific version - base = config.LocalServicePath(productName, serviceName) - if err = commonservice.PreLoadServiceManifests(base, serviceObj); err != nil { - log.Errorf("failed to load chart info for service %v", serviceObj.ServiceName) - return err - } - } - - fullPath := filepath.Join(base, serviceObj.ServiceName) - deliveryChartPath := filepath.Join(config.LocalDeliveryChartPathWithRevision(productName, serviceObj.ServiceName, serviceObj.Revision), serviceObj.ServiceName) - err := copy.Copy(fullPath, deliveryChartPath) - if err != nil { - return err - } - - mergedValuesYaml, err := helmtool.MergeOverrideValues(renderChart.ValuesYaml, renderset.DefaultValues, renderChart.GetOverrideYaml(), renderChart.OverrideValues) - if err != nil { - return err - } - - // write values.yaml - if err = os.WriteFile(filepath.Join(deliveryChartPath, setting.ValuesYaml), []byte(mergedValuesYaml), 0644); err != nil { - return err - } - - return nil -} - -func GetChartInfos(productName, envName, serviceName string, log *zap.SugaredLogger) (*HelmChartsResp, error) { - opt := &commonrepo.ProductFindOptions{Name: productName, EnvName: envName} - prod, err := commonrepo.NewProductColl().Find(opt) - if err != nil { - return nil, e.ErrGetHelmCharts.AddErr(err) - } - renderSet, err := FindHelmRenderSet(productName, prod.Render.Name, log) - if err != nil { - log.Errorf("[%s][P:%s] find product renderset error: %v", envName, productName, err) - return nil, e.ErrGetHelmCharts.AddErr(err) - } - - chartMap := make(map[string]*template.RenderChart) - for _, chart := range renderSet.ChartInfos { - chartMap[chart.ServiceName] = chart - } - - allServiceMap := prod.GetServiceMap() - serviceMap := make(map[string]*models.ProductService) - - //validate data, make sure service and chart info exists - if len(serviceName) > 0 { - serviceList := strings.Split(serviceName, ",") - for _, singleService := range serviceList { - if service, ok := allServiceMap[singleService]; ok { - serviceMap[service.ServiceName] = service - } else { - return nil, e.ErrGetHelmCharts.AddDesc(fmt.Sprintf("failed to find service %s in target namespace", singleService)) - } - } - } else { - serviceMap = allServiceMap - } - - if len(serviceMap) == 0 { - return nil, nil - } - - ret := &HelmChartsResp{ - ChartInfos: make([]*ChartInfo, 0), - FileInfos: make([]*types.FileInfo, 0), - } - - errList := new(multierror.Error) - wg := sync.WaitGroup{} - - for _, service := range serviceMap { - ret.ChartInfos = append(ret.ChartInfos, &ChartInfo{ - ServiceName: service.ServiceName, - Revision: service.Revision, - }) - wg.Add(1) - // download chart info with particular version - go func(serviceName string, revision int64) { - defer wg.Done() - serviceObj, err := commonrepo.NewServiceColl().Find(&commonrepo.ServiceFindOption{ - ProductName: productName, - ServiceName: serviceName, - Revision: revision, - Type: setting.HelmDeployType, - }) - if err != nil { - log.Errorf("failed to query services name: %s, revision: %d, error: %s", serviceName, revision, err) - errList = multierror.Append(errList, fmt.Errorf("failed to query service, serviceName: %s, revision: %d", serviceName, revision)) - return - } - renderChart, ok := chartMap[serviceName] - if !ok { - errList = multierror.Append(errList, fmt.Errorf("failed to find render chart for service %s in target namespace", serviceName)) - return - } - err = prepareChartVersionData(productName, serviceObj, renderChart, renderSet) - if err != nil { - errList = multierror.Append(errList, fmt.Errorf("failed to prepare chart info for service %s", serviceObj.ServiceName)) - return - } - }(service.ServiceName, service.Revision) - } - wg.Wait() - - if errList.ErrorOrNil() != nil { - return nil, errList.ErrorOrNil() - } - - // expand file info for first service - serviceToExpand := ret.ChartInfos[0].ServiceName - fis, err := loadChartFilesInfo(productName, serviceToExpand, serviceMap[serviceToExpand].Revision, "") - if err != nil { - log.Errorf("Failed to load service file info, err: %s", err) - return nil, e.ErrListTemplate.AddErr(err) - } - ret.FileInfos = fis - - return ret, nil -} diff --git a/pkg/microservice/aslan/core/project/service/project.go b/pkg/microservice/aslan/core/project/service/project.go index 196d63db0..4c9e1fb92 100644 --- a/pkg/microservice/aslan/core/project/service/project.go +++ b/pkg/microservice/aslan/core/project/service/project.go @@ -41,13 +41,12 @@ type ProjectListOptions struct { type ProjectDetailedRepresentation struct { *ProjectBriefRepresentation - Alias string `json:"alias"` - Desc string `json:"desc"` - UpdatedAt int64 `json:"updatedAt"` - UpdatedBy string `json:"updatedBy"` - Onboard bool `json:"onboard"` - Public bool `json:"public"` - DeployType string `json:"deployType"` + Alias string `json:"alias"` + Desc string `json:"desc"` + UpdatedAt int64 `json:"updatedAt"` + UpdatedBy string `json:"updatedBy"` + Onboard bool `json:"onboard"` + Public bool `json:"public"` } type ProjectBriefRepresentation struct { @@ -99,13 +98,12 @@ func listDetailedProjectInfos(opts *ProjectListOptions, logger *zap.SugaredLogge ProjectMinimalRepresentation: &ProjectMinimalRepresentation{Name: name}, Envs: nameWithEnvMap[name], }, - Alias: info.Alias, - Desc: info.Desc, - UpdatedAt: info.UpdatedAt, - UpdatedBy: info.UpdatedBy, - Onboard: info.OnboardStatus != 0, - Public: info.Public, - DeployType: info.DeployType, + Alias: info.Alias, + Desc: info.Desc, + UpdatedAt: info.UpdatedAt, + UpdatedBy: info.UpdatedBy, + Onboard: info.OnboardStatus != 0, + Public: info.Public, }) } diff --git a/pkg/microservice/aslan/core/service/handler/helm.go b/pkg/microservice/aslan/core/service/handler/helm.go index d1462e369..0573b0989 100644 --- a/pkg/microservice/aslan/core/service/handler/helm.go +++ b/pkg/microservice/aslan/core/service/handler/helm.go @@ -46,30 +46,13 @@ func GetHelmServiceModule(c *gin.Context) { func GetFilePath(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - revision := int64(0) - var err error - if len(c.Query("revision")) > 0 { - revision, err = strconv.ParseInt(c.Query("revision"), 10, 64) - } - if err != nil { - ctx.Err = e.ErrInvalidParam.AddDesc("invalid revision number") - return - } - ctx.Resp, ctx.Err = svcservice.GetFilePath(c.Param("serviceName"), c.Param("productName"), revision, c.Query("dir"), ctx.Logger) + ctx.Resp, ctx.Err = svcservice.GetFilePath(c.Param("serviceName"), c.Param("productName"), c.Query("dir"), ctx.Logger) } func GetFileContent(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - - param := new(svcservice.GetFileContentParam) - err := c.ShouldBindQuery(param) - if err != nil { - ctx.Err = e.ErrInvalidParam.AddErr(err) - return - } - - ctx.Resp, ctx.Err = svcservice.GetFileContent(c.Param("serviceName"), c.Param("productName"), param, ctx.Logger) + ctx.Resp, ctx.Err = svcservice.GetFileContent(c.Param("serviceName"), c.Param("productName"), c.Query("filePath"), c.Query("fileName"), ctx.Logger) } func CreateOrUpdateHelmService(c *gin.Context) { diff --git a/pkg/microservice/aslan/core/service/service/helm.go b/pkg/microservice/aslan/core/service/service/helm.go index a9d2dec2c..562b38523 100644 --- a/pkg/microservice/aslan/core/service/service/helm.go +++ b/pkg/microservice/aslan/core/service/service/helm.go @@ -113,13 +113,6 @@ type ChartTemplateData struct { DefaultValuesYAML []byte // content of values.yaml in template } -type GetFileContentParam struct { - FilePath string `json:"filePath" form:"filePath"` - FileName string `json:"fileName" form:"fileName"` - Revision int64 `json:"revision" form:"revision"` - DeliveryVersion bool `json:"deliveryVersion" form:"deliveryVersion"` -} - func ListHelmServices(productName string, log *zap.SugaredLogger) (*HelmService, error) { helmService := &HelmService{ ServiceInfos: []*models.Service{}, @@ -140,7 +133,7 @@ func ListHelmServices(productName string, log *zap.SugaredLogger) (*HelmService, helmService.ServiceInfos = services if len(services) > 0 { - fis, err := loadServiceFileInfos(services[0].ProductName, services[0].ServiceName, 0, "") + fis, err := loadServiceFileInfos(services[0].ProductName, services[0].ServiceName, "") if err != nil { log.Errorf("Failed to load service file info, err: %s", err) return nil, e.ErrListTemplate.AddErr(err) @@ -179,39 +172,24 @@ func GetHelmServiceModule(serviceName, productName string, revision int64, log * return helmServiceModule, err } -func GetFilePath(serviceName, productName string, revision int64, dir string, _ *zap.SugaredLogger) ([]*types.FileInfo, error) { - return loadServiceFileInfos(productName, serviceName, revision, dir) +func GetFilePath(serviceName, productName, dir string, _ *zap.SugaredLogger) ([]*types.FileInfo, error) { + return loadServiceFileInfos(productName, serviceName, dir) } -func GetFileContent(serviceName, productName string, param *GetFileContentParam, log *zap.SugaredLogger) (string, error) { - filePath, fileName, revision, forDelivery := param.FilePath, param.FileName, param.Revision, param.DeliveryVersion +func GetFileContent(serviceName, productName, filePath, fileName string, log *zap.SugaredLogger) (string, error) { + base := config.LocalServicePath(productName, serviceName) + svc, err := commonrepo.NewServiceColl().Find(&commonrepo.ServiceFindOption{ ProductName: productName, ServiceName: serviceName, - Revision: revision, }) if err != nil { return "", e.ErrFileContent.AddDesc(err.Error()) } - base := config.LocalServicePath(productName, serviceName) - if revision > 0 { - base = config.LocalServicePathWithRevision(productName, serviceName, revision) - if err = commonservice.PreloadServiceManifestsByRevision(base, svc); err != nil { - log.Warnf("failed to get chart of revision: %d for service: %s, use latest version", - svc.Revision, svc.ServiceName) - } - } - if err != nil || revision == 0 { - base = config.LocalServicePath(productName, serviceName) - err = commonservice.PreLoadServiceManifests(base, svc) - if err != nil { - return "", e.ErrFileContent.AddDesc(err.Error()) - } - } - - if forDelivery { - base = config.LocalDeliveryChartPathWithRevision(productName, serviceName, revision) + err = commonservice.PreLoadServiceManifests(base, svc) + if err != nil { + return "", e.ErrFileContent.AddDesc(err.Error()) } file := filepath.Join(base, serviceName, filePath, fileName) @@ -934,7 +912,9 @@ func createOrUpdateHelmService(fsTree fs.FS, args *helmServiceCreationArgs, logg return serviceObj, nil } -func loadServiceFileInfos(productName, serviceName string, revision int64, dir string) ([]*types.FileInfo, error) { +func loadServiceFileInfos(productName, serviceName, dir string) ([]*types.FileInfo, error) { + base := config.LocalServicePath(productName, serviceName) + svc, err := commonrepo.NewServiceColl().Find(&commonrepo.ServiceFindOption{ ProductName: productName, ServiceName: serviceName, @@ -943,22 +923,6 @@ func loadServiceFileInfos(productName, serviceName string, revision int64, dir s return nil, e.ErrFilePath.AddDesc(err.Error()) } - base := config.LocalServicePath(productName, serviceName) - if revision > 0 { - base = config.LocalServicePathWithRevision(productName, serviceName, revision) - if err = commonservice.PreloadServiceManifestsByRevision(base, svc); err != nil { - log.Warnf("failed to get chart of revision: %d for service: %s, use latest version", - svc.Revision, svc.ServiceName) - } - } - if err != nil || revision == 0 { - base = config.LocalServicePath(productName, serviceName) - err = commonservice.PreLoadServiceManifests(base, svc) - if err != nil { - return nil, e.ErrFilePath.AddDesc(err.Error()) - } - } - err = commonservice.PreLoadServiceManifests(base, svc) if err != nil { return nil, e.ErrFilePath.AddDesc(err.Error()) diff --git a/pkg/microservice/aslan/core/system/handler/helm.go b/pkg/microservice/aslan/core/system/handler/helm.go index 7f92809e6..31a84a53d 100644 --- a/pkg/microservice/aslan/core/system/handler/helm.go +++ b/pkg/microservice/aslan/core/system/handler/helm.go @@ -49,7 +49,6 @@ func CreateHelmRepo(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid url") return } - ctx.Err = service.CreateHelmRepo(args, ctx.Logger) } diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go index decf797e9..00ca9b6c0 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go @@ -35,15 +35,15 @@ import ( "github.com/koderover/zadig/pkg/util" ) -// get global config payload -func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, taskCreator string, log *zap.SugaredLogger) (int64, error) { +func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, log *zap.SugaredLogger) error { + // 获取全局configpayload configPayload := commonservice.GetConfigPayload(0) repos, err := commonrepo.NewRegistryNamespaceColl().FindAll(&commonrepo.FindRegOps{}) if err != nil { log.Errorf("CreateArtifactPackageTask query registries failed, err: %s", err) - return 0, fmt.Errorf("failed to query registries") + return fmt.Errorf("failed to query registries") } registriesInvolved := sets.NewString() @@ -68,13 +68,13 @@ func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, taskC defaultS3, err := s3.FindDefaultS3() if err != nil { err = e.ErrFindDefaultS3Storage.AddDesc("default storage is required by distribute task") - return 0, err + return err } defaultURL, err := defaultS3.GetEncryptedURL() if err != nil { err = e.ErrS3Storage.AddErr(err) - return 0, err + return err } task := &task.Task{ @@ -82,7 +82,6 @@ func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, taskC ProductName: args.ProjectName, Status: config.StatusCreated, ArtifactPackageTaskArgs: args, - TaskCreator: taskCreator, ConfigPayload: configPayload, StorageURI: defaultURL, } @@ -101,14 +100,14 @@ func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, taskC }).ToSubTask() if err != nil { - return 0, err + return err } task.SubTasks = []map[string]interface{}{subTask} if err := ensurePipelineTask(task, "", log); err != nil { log.Errorf("CreateServiceTask ensurePipelineTask err : %v", err) - return 0, err + return err } stages := make([]*commonmodels.Stage, 0) @@ -118,14 +117,14 @@ func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, taskC sort.Sort(ByStageKind(stages)) task.Stages = stages if len(task.Stages) == 0 { - return 0, e.ErrCreateTask.AddDesc(e.PipelineSubTaskNotFoundErrMsg) + return e.ErrCreateTask.AddDesc(e.PipelineSubTaskNotFoundErrMsg) } pipelineName := fmt.Sprintf("%s-%s-%s", args.ProjectName, args.EnvName, "artifact") nextTaskID, err := commonrepo.NewCounterColl().GetNextSeq(fmt.Sprintf(setting.ServiceTaskFmt, pipelineName)) if err != nil { log.Errorf("CreateServiceTask Counter.GetNextSeq error: %v", err) - return 0, e.ErrGetCounter.AddDesc(err.Error()) + return e.ErrGetCounter.AddDesc(err.Error()) } task.SubTasks = []map[string]interface{}{} @@ -134,8 +133,8 @@ func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, taskC if err := CreateTask(task); err != nil { log.Error(err) - return 0, e.ErrCreateTask + return e.ErrCreateTask } - return nextTaskID, nil + return nil } diff --git a/pkg/microservice/packager/core/service/packager.go b/pkg/microservice/packager/core/service/packager.go index 8f9e41da9..d58b587bc 100644 --- a/pkg/microservice/packager/core/service/packager.go +++ b/pkg/microservice/packager/core/service/packager.go @@ -17,10 +17,10 @@ limitations under the License. package service type ImageData struct { - ImageUrl string `yaml:"image_url" json:"image_url"` - ImageName string `yaml:"image_name" json:"image_name"` - ImageTag string `yaml:"image_tag" json:"image_tag"` - RegistryID string `yaml:"registry_id" json:"registry_id"` + ImageUrl string `yaml:"image_url"` + ImageName string `yaml:"image_name"` + ImageTag string `yaml:"image_tag"` + RegistryID string `yaml:"registry_id,omitempty"` } // ImagesByService defines all images in a service diff --git a/pkg/microservice/packager/core/service/service.go b/pkg/microservice/packager/core/service/service.go index ba4e036e5..339ab5de9 100644 --- a/pkg/microservice/packager/core/service/service.go +++ b/pkg/microservice/packager/core/service/service.go @@ -22,7 +22,6 @@ import ( "encoding/base64" "encoding/json" "fmt" - "io" "os" "path/filepath" "strings" @@ -94,68 +93,15 @@ func buildTargetImage(imageName, imageTag, host, nameSpace string) string { return ret } -func pullImage(dockerClient *client.Client, imageUrl string, options *types.ImagePullOptions) error { - // pull image - pullResponse, err := dockerClient.ImagePull(context.TODO(), imageUrl, *options) - if err != nil { - return err - } - - defer func(pullResponse io.ReadCloser) { - err := pullResponse.Close() - if err != nil { - log.Errorf("failed to close response reader") - } - }(pullResponse) - - bs, err := io.ReadAll(pullResponse) - if err != nil { - return err - } - - if strings.Contains(string(bs), "error") { - log.Errorf("image push failed: %s", string(bs)) - return fmt.Errorf("failed to push image") - } - return nil -} - -func pushImage(dockerClient *client.Client, targetImageUrl string, options *types.ImagePushOptions) error { - pushResponse, err := dockerClient.ImagePush(context.TODO(), targetImageUrl, *options) - if err != nil { - return errors.Wrapf(err, "failed to push image: %s", targetImageUrl) - } - - defer func(pullResponse io.ReadCloser) { - err := pullResponse.Close() - if err != nil { - log.Errorf("failed to close response reader") - } - }(pushResponse) - - bs, err := io.ReadAll(pushResponse) - if err != nil { - return err - } - - if strings.Contains(string(bs), "error") { - log.Errorf("image push failed: %s", string(bs)) - return fmt.Errorf("failed to push image") - } - return nil -} - -func handleSingleService(imageByService *ImagesByService, allRegistries map[string]*DockerRegistry, targetRegistries []*DockerRegistry, dockerClient *client.Client) ([]*ImageData, error) { +func handleSingleService(imageByService *ImagesByService, allRegistries map[string]*DockerRegistry, targetRegistries []*DockerRegistry, dockerClient *client.Client) error { targetImageUrlByRepo := make(map[string][]string) - retImages := make([]*ImageData, 0) - for _, singleImage := range imageByService.Images { options := types.ImagePullOptions{} // for images from public repo,registryID won't be appointed if len(singleImage.RegistryID) > 0 { registryInfo, ok := allRegistries[singleImage.RegistryID] if !ok { - return nil, fmt.Errorf("failed to find source registry for image: %s", singleImage.ImageUrl) + return fmt.Errorf("failed to find source registry for image: %s", singleImage.ImageUrl) } encodedAuth, err := base64EncodeAuth(&types.AuthConfig{ Username: registryInfo.UserName, @@ -163,15 +109,15 @@ func handleSingleService(imageByService *ImagesByService, allRegistries map[stri ServerAddress: registryInfo.Host, }) if err != nil { - return nil, errors.Wrapf(err, "faied to create docker pull auth data") + return errors.Wrapf(err, "faied to create docker pull auth data") } options.RegistryAuth = encodedAuth } // pull image - err := pullImage(dockerClient, singleImage.ImageUrl, &options) + _, err := dockerClient.ImagePull(context.TODO(), singleImage.ImageUrl, options) if err != nil { - return nil, errors.Wrapf(err, "failed to pull image: %s", singleImage.ImageUrl) + return errors.Wrapf(err, "failed to pull image: %s", singleImage.ImageUrl) } // tag image @@ -179,15 +125,9 @@ func handleSingleService(imageByService *ImagesByService, allRegistries map[stri targetImage := buildTargetImage(singleImage.ImageName, singleImage.ImageTag, registry.Host, registry.Namespace) err = dockerClient.ImageTag(context.TODO(), singleImage.ImageUrl, targetImage) if err != nil { - return nil, errors.Wrapf(err, "failed to tag image from: %s to: %s", singleImage.ImageUrl, targetImage) + return errors.Wrapf(err, "failed to tag image from: %s to: %s", singleImage.ImageUrl, targetImage) } targetImageUrlByRepo[registry.RegistryID] = append(targetImageUrlByRepo[registry.RegistryID], targetImage) - retImages = append(retImages, &ImageData{ - ImageUrl: targetImage, - ImageName: singleImage.ImageName, - ImageTag: singleImage.ImageTag, - RegistryID: singleImage.RegistryID, - }) } } @@ -199,20 +139,19 @@ func handleSingleService(imageByService *ImagesByService, allRegistries map[stri ServerAddress: registry.Host, }) if err != nil { - return nil, errors.Wrapf(err, "faied to create docker push auth data") + return errors.Wrapf(err, "faied to create docker push auth data") } options := types.ImagePushOptions{ RegistryAuth: encodedAuth, } - for _, targetImageUrl := range targetImageUrlByRepo[registry.RegistryID] { - err = pushImage(dockerClient, targetImageUrl, &options) + _, err = dockerClient.ImagePush(context.TODO(), targetImageUrl, options) if err != nil { - return nil, errors.Wrapf(err, "failed to push image: %s", targetImageUrl) + return errors.Wrapf(err, "failed to push image: %s", targetImageUrl) } } } - return retImages, nil + return nil } func (p *Packager) Exec() error { @@ -262,7 +201,7 @@ func (p *Packager) Exec() error { result := &PackageResult{ ServiceName: imageByService.ServiceName, } - images, err := handleSingleService(imageByService, buildRegistryMap(allRegistries), p.Ctx.TargetRegistries, cli) + err = handleSingleService(imageByService, buildRegistryMap(allRegistries), p.Ctx.TargetRegistries, cli) if err != nil { result.Result = "failed" @@ -270,7 +209,7 @@ func (p *Packager) Exec() error { log.Errorf("[result][fail][%s][%s]", imageByService.ServiceName, err) } else { result.Result = "success" - result.ImageData = images + result.ImageData = imageByService.Images log.Infof("[result][success][%s]", imageByService.ServiceName) } diff --git a/pkg/microservice/warpdrive/core/service/types/task/artifact_package.go b/pkg/microservice/warpdrive/core/service/types/task/artifact_package.go index 5ebe24fb0..9ac39d95a 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/artifact_package.go +++ b/pkg/microservice/warpdrive/core/service/types/task/artifact_package.go @@ -26,7 +26,7 @@ type ArtifactPackage struct { TaskType config.TaskType `bson:"type" json:"type"` Enabled bool `bson:"enabled" json:"enabled"` TaskStatus config.Status `bson:"status" json:"status"` - Progress string `bson:"progress" json:"progress"` + Progress string `bson:"progress" json:"progress"` Timeout int `bson:"timeout,omitempty" json:"timeout,omitempty"` Error string `bson:"error,omitempty" json:"error,omitempty"` StartTime int64 `bson:"start_time,omitempty" json:"start_time,omitempty"` diff --git a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go index beb9d603c..caca4a5a5 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go +++ b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go @@ -134,7 +134,7 @@ type ReleaseConfig struct { // e.g. xxx.com/resources/predator-plugin:v0.1.0 PredatorImage string // PackagerImage sets docker build image - // e.g. xxx.com/resources/packager-plugin:v0.1.0 + // e.g. xxx.com/resources/predator-plugin:v0.1.0 PackagerImage string } diff --git a/pkg/setting/consts.go b/pkg/setting/consts.go index 250cc4b4b..df2c1159d 100644 --- a/pkg/setting/consts.go +++ b/pkg/setting/consts.go @@ -272,16 +272,6 @@ const ( FunctionTestType = "function" ) -const ( - DeliveryVersionTypeChart = "HelmChart" - DeliveryVersionTypeK8SWorkflow = "K8SWorkflow" -) - -const ( - DeliveryDeployTypeImage = "image" - DeliveryDeployTypeChart = "chart" -) - const ( AuthorizationHeader = "Authorization" ) @@ -337,21 +327,6 @@ const ( ProductStatusUnstable = "Unstable" ) -// DeliveryVersion status -const ( - DeliveryVersionStatusSuccess = "success" - DeliveryVersionStatusFailed = "failed" - DeliveryVersionStatusCreating = "creating" - DeliveryVersionStatusRetrying = "retrying" -) - -const ( - DeliveryVersionPackageStatusSuccess = "success" - DeliveryVersionPackageStatusFailed = "failed" - DeliveryVersionPackageStatusWaiting = "waiting" - DeliveryVersionPackageStatusUploading = "uploading" -) - const ( NormalModeProduct = "normal" ) diff --git a/pkg/tool/errors/http_errors.go b/pkg/tool/errors/http_errors.go index e0ffc2eed..45554ea76 100644 --- a/pkg/tool/errors/http_errors.go +++ b/pkg/tool/errors/http_errors.go @@ -680,10 +680,4 @@ var ( ErrUpdateExternalLink = NewHTTPError(6842, "更新链接失败") ErrDeleteExternalLink = NewHTTPError(6843, "删除链接失败") ErrListExternalLink = NewHTTPError(6844, "获取链接列表失败") - - //----------------------------------------------------------------------------------------------- - // helm releated Error Range: 6850 - 6869 - //----------------------------------------------------------------------------------------------- - ErrListHelmReleases = NewHTTPError(6850, "获取release失败") - ErrGetHelmCharts = NewHTTPError(6851, "获取chart信息失败") ) -- Gitee From 8f668de8f6367b425127ed1488acd7feb98e980a Mon Sep 17 00:00:00 2001 From: allenshen Date: Fri, 10 Dec 2021 15:36:07 +0800 Subject: [PATCH 119/134] optimize extract image logic Signed-off-by: allenshen --- pkg/microservice/aslan/core/common/service/service.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pkg/microservice/aslan/core/common/service/service.go b/pkg/microservice/aslan/core/common/service/service.go index fbcf8086c..7715df4b8 100644 --- a/pkg/microservice/aslan/core/common/service/service.go +++ b/pkg/microservice/aslan/core/common/service/service.go @@ -651,17 +651,18 @@ func ExtractImageTag(imageURI string) string { return "" } -// ExtractRegistryNamespace extract registry namespace form image uri +// ExtractRegistryNamespace extract registry namespace from image uri func ExtractRegistryNamespace(imageURI string) string { imageURI = strings.TrimPrefix(imageURI, "http://") imageURI = strings.TrimPrefix(imageURI, "https://") - firstIndex := strings.Index(imageURI, "/") - lastIndex := strings.LastIndex(imageURI, "/") - if lastIndex == firstIndex { + imageComponent := strings.Split(imageURI, "/") + if len(imageComponent) <= 2 { return "" } - return strings.TrimPrefix(imageURI[firstIndex:lastIndex], "/") + + nsComponent := imageComponent[1 : len(imageComponent)-1] + return strings.Join(nsComponent, "/") } func parseImagesByPattern(nested map[string]interface{}, patterns []map[string]string) ([]*models.Container, error) { -- Gitee From 641d26251cdbab21a5f9ad17bb03433b7e84225a Mon Sep 17 00:00:00 2001 From: allenshen Date: Fri, 10 Dec 2021 15:55:42 +0800 Subject: [PATCH 120/134] optimize code Signed-off-by: allenshen --- .../repository/models/delivery_distribute.go | 16 +++--- .../aslan/core/delivery/service/docker.go | 57 ------------------- 2 files changed, 8 insertions(+), 65 deletions(-) delete mode 100644 pkg/microservice/aslan/core/delivery/service/docker.go diff --git a/pkg/microservice/aslan/core/common/repository/models/delivery_distribute.go b/pkg/microservice/aslan/core/common/repository/models/delivery_distribute.go index 4365fa139..732e24fc0 100644 --- a/pkg/microservice/aslan/core/common/repository/models/delivery_distribute.go +++ b/pkg/microservice/aslan/core/common/repository/models/delivery_distribute.go @@ -23,22 +23,22 @@ import ( ) type DeliveryDistribute struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` ReleaseID primitive.ObjectID `bson:"release_id" json:"releaseId"` ServiceName string `bson:"service_name" json:"serviceName,omitempty"` DistributeType config.DistributeType `bson:"distribute_type" json:"distributeType"` RegistryName string `bson:"registry_name" json:"registryName"` - ChartVersion string `bson:"chart_version" json:"chartVersion,omitempty"` - ChartName string `bson:"chart_name" json:"chartName,omitempty"` - ChartRepoName string `bson:"chart_repo_name" json:"chartRepoName,omitempty"` - SubDistributes []*DeliveryDistribute `bson:"-" json:"subDistributes,omitempty"` + ChartVersion string `bson:"chart_version" json:"chartVersion,omitempty"` + ChartName string `bson:"chart_name" json:"chartName,omitempty"` + ChartRepoName string `bson:"chart_repo_name" json:"chartRepoName,omitempty"` + SubDistributes []*DeliveryDistribute `bson:"-" json:"subDistributes,omitempty"` Namespace string `bson:"namespace" json:"namespace,omitempty"` PackageFile string `bson:"package_file" json:"packageFile,omitempty"` RemoteFileKey string `bson:"remote_file_key" json:"remoteFileKey,omitempty"` DestStorageURL string `bson:"dest_storage_url" json:"destStorageUrl,omitempty"` - S3StorageID string `bson:"s3_storage_id" json:"s3StorageID"` - StorageURL string `bson:"-" json:"storageUrl"` - StorageBucket string `bson:"-" json:"storageBucket"` + S3StorageID string `bson:"s3_storage_id" json:"s3StorageID"` + StorageURL string `bson:"-" json:"storageUrl"` + StorageBucket string `bson:"-" json:"storageBucket"` SrcStorageURL string `bson:"src_storage_url" json:"srcStorageUrl,omitempty"` StartTime int64 `bson:"start_time,omitempty" json:"start_time,omitempty,omitempty"` EndTime int64 `bson:"end_time,omitempty" json:"end_time,omitempty,omitempty"` diff --git a/pkg/microservice/aslan/core/delivery/service/docker.go b/pkg/microservice/aslan/core/delivery/service/docker.go deleted file mode 100644 index 65a35941e..000000000 --- a/pkg/microservice/aslan/core/delivery/service/docker.go +++ /dev/null @@ -1,57 +0,0 @@ -/* -Copyright 2021 The KodeRover Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package service - -import "os/exec" - -const dockerExe = "/usr/local/bin/docker" - -func dockerLogin(user, password, registry string) *exec.Cmd { - return exec.Command( - dockerExe, - "login", - "-u", user, - "-p", password, - registry, - ) -} - -func dockerInfo() *exec.Cmd { - return exec.Command(dockerExe, "info") -} - -func dockerPush(fullImage string) *exec.Cmd { - args := []string{ - "push", - fullImage, - } - return exec.Command(dockerExe, args...) -} - -func dockerPull(image string) *exec.Cmd { - args := []string{"pull", image} - return exec.Command(dockerExe, args...) -} - -func dockerTag(sourceFullImage, targetFullImage string) *exec.Cmd { - args := []string{ - "tag", - sourceFullImage, - targetFullImage, - } - return exec.Command(dockerExe, args...) -} -- Gitee From ad661bd796ec54b7849cdb847246e54e221a064a Mon Sep 17 00:00:00 2001 From: Landy Date: Fri, 10 Dec 2021 16:06:37 +0800 Subject: [PATCH 121/134] Revert "Revert "create delivery version"" --- go.mod | 1 + go.sum | 5 + pkg/config/config.go | 4 + pkg/microservice/aslan/config/config.go | 4 + pkg/microservice/aslan/config/consts.go | 1 + .../repository/models/delivery_distribute.go | 23 +- .../repository/models/delivery_version.go | 34 +- .../core/common/repository/models/queue.go | 27 +- .../models/task/artifact_package.go | 25 + .../common/repository/models/task/model.go | 12 +- .../repository/mongodb/delivery_distribute.go | 9 +- .../repository/mongodb/delivery_version.go | 21 +- .../common/repository/mongodb/helm_repo.go | 32 +- .../repository/mongodb/template/product.go | 37 +- .../aslan/core/common/service/fs/s3.go | 30 +- .../aslan/core/common/service/s3/s3.go | 10 + .../aslan/core/common/service/service.go | 54 +- .../aslan/core/delivery/handler/router.go | 8 + .../aslan/core/delivery/handler/version.go | 283 ++-- .../aslan/core/delivery/service/docker.go | 57 + .../aslan/core/delivery/service/version.go | 1474 ++++++++++++++++- .../aslan/core/environment/handler/helm.go | 40 + .../aslan/core/environment/handler/router.go | 3 + .../aslan/core/environment/service/helm.go | 259 +++ .../aslan/core/project/service/project.go | 26 +- .../aslan/core/service/handler/helm.go | 21 +- .../aslan/core/service/service/helm.go | 60 +- .../aslan/core/system/handler/helm.go | 1 + .../service/workflow/artifact_task.go | 23 +- .../packager/core/service/packager.go | 8 +- .../packager/core/service/service.go | 85 +- .../service/types/task/artifact_package.go | 2 +- .../core/service/types/task/config_payload.go | 2 +- pkg/setting/consts.go | 25 + pkg/tool/errors/http_errors.go | 6 + 35 files changed, 2397 insertions(+), 315 deletions(-) create mode 100644 pkg/microservice/aslan/core/delivery/service/docker.go create mode 100644 pkg/microservice/aslan/core/environment/handler/helm.go create mode 100644 pkg/microservice/aslan/core/environment/service/helm.go diff --git a/go.mod b/go.mod index c00c91906..0f9924dca 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/bugsnag/bugsnag-go v2.1.0+incompatible // indirect github.com/bugsnag/panicwrap v1.3.1 // indirect github.com/cenkalti/backoff/v4 v4.1.1 + github.com/chartmuseum/helm-push v0.10.1 github.com/coocood/freecache v1.1.0 github.com/coreos/go-oidc/v3 v3.0.0 github.com/dexidp/dex v0.0.0-20210802203454-3fac2ab6bc3b diff --git a/go.sum b/go.sum index 79c316c2d..123658a63 100644 --- a/go.sum +++ b/go.sum @@ -286,6 +286,8 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= +github.com/chartmuseum/helm-push v0.10.1 h1:NqStAmarEy0GnrDCk0zubGKeRmkhOm/rRi5au8h76BA= +github.com/chartmuseum/helm-push v0.10.1/go.mod h1:s6xTICU31jKdLkOXS+GgaR61E+oU4h8TWb1yZcHq8OE= github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -537,6 +539,7 @@ github.com/garyburd/redigo v1.6.2 h1:yE/pwKCrbLpLpQICzYTeZ7JsTA/C53wFTJHaEtRqniM github.com/garyburd/redigo v1.6.2/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/gzip v0.0.1 h1:ezvKOL6jH+jlzdHNE4h9h8q8uMpDQjyl0NN0Jd7jozc= github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w= @@ -2350,6 +2353,8 @@ k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8 k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/helm v2.17.0+incompatible h1:Bpn6o1wKLYqKM3+Osh8e+1/K2g/GsQJ4F4yNF2+deao= +k8s.io/helm v2.17.0+incompatible/go.mod h1:LZzlS4LQBHfciFOurYBFkCMTaZ0D1l+p0teMg7TSULI= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= diff --git a/pkg/config/config.go b/pkg/config/config.go index 593eff9c1..4f2ef7d94 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -210,6 +210,10 @@ func ObjectStorageTemplatePath(name, kind string) string { return filepath.Join("templates", kind, name) } +func ObjectStorageDeliveryVersionPath(project string) string { + return filepath.Join("delivery-distributes", "files", project) +} + func ObjectStorageChartTemplatePath(name string) string { return ObjectStorageTemplatePath(name, setting.ChartTemplatesPath) } diff --git a/pkg/microservice/aslan/config/config.go b/pkg/microservice/aslan/config/config.go index edca3a57f..121add2cc 100644 --- a/pkg/microservice/aslan/config/config.go +++ b/pkg/microservice/aslan/config/config.go @@ -234,6 +234,10 @@ func LocalServicePathWithRevision(project, service string, revision int64) strin return configbase.LocalServicePathWithRevision(project, service, fmt.Sprintf("%d", revision)) } +func LocalDeliveryChartPathWithRevision(project, service string, revision int64) string { + return configbase.LocalServicePathWithRevision(project, service, fmt.Sprintf("delivery/%d", revision)) +} + func ServiceNameWithRevision(serviceName string, revision int64) string { return fmt.Sprintf("%s-%d", serviceName, revision) } diff --git a/pkg/microservice/aslan/config/consts.go b/pkg/microservice/aslan/config/consts.go index 99f468214..9b91eb4c0 100644 --- a/pkg/microservice/aslan/config/consts.go +++ b/pkg/microservice/aslan/config/consts.go @@ -141,6 +141,7 @@ type DistributeType string const ( File DistributeType = "file" Image DistributeType = "image" + Chart DistributeType = "chart" ) type NotifyType int diff --git a/pkg/microservice/aslan/core/common/repository/models/delivery_distribute.go b/pkg/microservice/aslan/core/common/repository/models/delivery_distribute.go index db24294d6..4365fa139 100644 --- a/pkg/microservice/aslan/core/common/repository/models/delivery_distribute.go +++ b/pkg/microservice/aslan/core/common/repository/models/delivery_distribute.go @@ -25,16 +25,23 @@ import ( type DeliveryDistribute struct { ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` ReleaseID primitive.ObjectID `bson:"release_id" json:"releaseId"` - ServiceName string `bson:"service_name" json:"serviceName"` + ServiceName string `bson:"service_name" json:"serviceName,omitempty"` DistributeType config.DistributeType `bson:"distribute_type" json:"distributeType"` RegistryName string `bson:"registry_name" json:"registryName"` - Namespace string `bson:"namespace" json:"namespace"` - PackageFile string `bson:"package_file" json:"packageFile"` - RemoteFileKey string `bson:"remote_file_key" json:"remoteFileKey"` - DestStorageURL string `bson:"dest_storage_url" json:"destStorageUrl"` - SrcStorageURL string `bson:"src_storage_url" json:"srcStorageUrl"` - StartTime int64 `bson:"start_time,omitempty" json:"start_time,omitempty"` - EndTime int64 `bson:"end_time,omitempty" json:"end_time,omitempty"` + ChartVersion string `bson:"chart_version" json:"chartVersion,omitempty"` + ChartName string `bson:"chart_name" json:"chartName,omitempty"` + ChartRepoName string `bson:"chart_repo_name" json:"chartRepoName,omitempty"` + SubDistributes []*DeliveryDistribute `bson:"-" json:"subDistributes,omitempty"` + Namespace string `bson:"namespace" json:"namespace,omitempty"` + PackageFile string `bson:"package_file" json:"packageFile,omitempty"` + RemoteFileKey string `bson:"remote_file_key" json:"remoteFileKey,omitempty"` + DestStorageURL string `bson:"dest_storage_url" json:"destStorageUrl,omitempty"` + S3StorageID string `bson:"s3_storage_id" json:"s3StorageID"` + StorageURL string `bson:"-" json:"storageUrl"` + StorageBucket string `bson:"-" json:"storageBucket"` + SrcStorageURL string `bson:"src_storage_url" json:"srcStorageUrl,omitempty"` + StartTime int64 `bson:"start_time,omitempty" json:"start_time,omitempty,omitempty"` + EndTime int64 `bson:"end_time,omitempty" json:"end_time,omitempty,omitempty"` CreatedAt int64 `bson:"created_at" json:"created_at"` DeletedAt int64 `bson:"deleted_at" json:"deleted_at"` } diff --git a/pkg/microservice/aslan/core/common/repository/models/delivery_version.go b/pkg/microservice/aslan/core/common/repository/models/delivery_version.go index 459d7f96f..ed851379d 100644 --- a/pkg/microservice/aslan/core/common/repository/models/delivery_version.go +++ b/pkg/microservice/aslan/core/common/repository/models/delivery_version.go @@ -20,18 +20,30 @@ import ( "go.mongodb.org/mongo-driver/bson/primitive" ) +type DeliveryVersionProgress struct { + SuccessChartCount int `json:"successChartCount"` + TotalChartCount int `json:"totalChartCount"` + PackageUploadStatus string `json:"packageStatus"` + Error string `json:"error"` +} + type DeliveryVersion struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - Version string `bson:"version" json:"version"` - ProductName string `bson:"product_name" json:"productName"` - WorkflowName string `bson:"workflow_name" json:"workflowName"` - TaskID int `bson:"task_id" json:"taskId"` - Desc string `bson:"desc" json:"desc"` - Labels []string `bson:"labels" json:"labels"` - ProductEnvInfo *Product `bson:"product_env_info" json:"productEnvInfo"` - CreatedBy string `bson:"created_by" json:"createdBy"` - CreatedAt int64 `bson:"created_at" json:"created_at"` - DeletedAt int64 `bson:"deleted_at" json:"deleted_at"` + ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + Version string `bson:"version" json:"version"` + ProductName string `bson:"product_name" json:"productName"` + WorkflowName string `bson:"workflow_name" json:"workflowName"` + Type string `bson:"type" json:"type"` + TaskID int `bson:"task_id" json:"taskId"` + Desc string `bson:"desc" json:"desc"` + Labels []string `bson:"labels" json:"labels"` + ProductEnvInfo *Product `bson:"product_env_info" json:"productEnvInfo"` + Status string `bson:"status" json:"status"` + Error string `bson:"error" json:"-"` + Progress *DeliveryVersionProgress `bson:"-" json:"progress"` + CreateArgument interface{} `bson:"createArgument" json:"-"` + CreatedBy string `bson:"created_by" json:"createdBy"` + CreatedAt int64 `bson:"created_at" json:"created_at"` + DeletedAt int64 `bson:"deleted_at" json:"deleted_at"` } func (DeliveryVersion) TableName() string { diff --git a/pkg/microservice/aslan/core/common/repository/models/queue.go b/pkg/microservice/aslan/core/common/repository/models/queue.go index ab5887674..8aee0760d 100644 --- a/pkg/microservice/aslan/core/common/repository/models/queue.go +++ b/pkg/microservice/aslan/core/common/repository/models/queue.go @@ -49,13 +49,13 @@ type Queue struct { IsArchived bool `bson:"is_archived" json:"is_archived"` AgentID string `bson:"agent_id" json:"agent_id"` MultiRun bool `bson:"multi_run" json:"multi_run"` - Target string `bson:"target,omitempty" json:"target"` // target 服务名称, k8s为容器名称, 物理机为服务名 - BuildModuleVer string `bson:"build_module_ver,omitempty" json:"build_module_ver"` // 使用预定义编译管理模块中的内容生成SubTasks, 查询条件为 服务模板名称: ServiceTmpl, 版本: BuildModuleVer 如果为空,则使用pipeline自定义SubTasks + Target string `bson:"target,omitempty" json:"target"` // target service name, for k8s: containerName, for pm: serviceName + BuildModuleVer string `bson:"build_module_ver,omitempty" json:"build_module_ver"` ServiceName string `bson:"service_name,omitempty" json:"service_name,omitempty"` - TaskArgs *TaskArgs `bson:"task_args,omitempty" json:"task_args,omitempty"` // TaskArgs 单服务工作流任务参数 - WorkflowArgs *WorkflowTaskArgs `bson:"workflow_args" json:"workflow_args,omitempty"` // WorkflowArgs 多服务工作流任务参数 - TestArgs *TestTaskArgs `bson:"test_args,omitempty" json:"test_args,omitempty"` // TestArgs 测试任务参数 - ServiceTaskArgs *ServiceTaskArgs `bson:"service_args,omitempty" json:"service_args,omitempty"` // ServiceTaskArgs 脚本部署工作流任务参数 + TaskArgs *TaskArgs `bson:"task_args,omitempty" json:"task_args,omitempty"` // TaskArgs job parameters for single-service workflow + WorkflowArgs *WorkflowTaskArgs `bson:"workflow_args" json:"workflow_args,omitempty"` // WorkflowArgs job parameters for multi-service workflow + TestArgs *TestTaskArgs `bson:"test_args,omitempty" json:"test_args,omitempty"` // TestArgs parameters for testing + ServiceTaskArgs *ServiceTaskArgs `bson:"service_args,omitempty" json:"service_args,omitempty"` // ServiceTaskArgs parameters for script-deployed workflows ArtifactPackageTaskArgs *ArtifactPackageTaskArgs `bson:"artifact_package_args,omitempty" json:"artifact_package_args,omitempty"` ConfigPayload *ConfigPayload `bson:"configpayload,omitempty" json:"config_payload"` Error string `bson:"error,omitempty" json:"error,omitempty"` @@ -96,9 +96,10 @@ type ServiceTaskArgs struct { } type ImageData struct { - ImageUrl string `bson:"image_url" json:"image_url"` - ImageName string `bson:"image_name" json:"image_name"` - ImageTag string `bson:"image_tag" json:"image_tag"` + ImageUrl string `bson:"image_url" json:"image_url"` + ImageName string `bson:"image_name" json:"image_name"` + ImageTag string `bson:"image_tag" json:"image_tag"` + RegistryID string `bson:"registry_id" json:"registry_id"` } type ImagesByService struct { @@ -108,10 +109,10 @@ type ImagesByService struct { type ArtifactPackageTaskArgs struct { ProjectName string `bson:"project_name" json:"project_name"` - EnvName string `bson:"env_name" json:"env_name"` - Images []*ImagesByService `bson:"images" json:"images"` - SourceRegistries []string `json:"source_registries" json:"source_registries"` - TargetRegistries []string `json:"target_registries" json:"target_registries"` + EnvName string `bson:"env_name" json:"env_name"` + Images []*ImagesByService `bson:"images" json:"images"` + SourceRegistries []string `json:"source_registries" json:"source_registries"` + TargetRegistries []string `json:"target_registries" json:"target_registries"` } type ConfigPayload struct { diff --git a/pkg/microservice/aslan/core/common/repository/models/task/artifact_package.go b/pkg/microservice/aslan/core/common/repository/models/task/artifact_package.go index 8f578b62c..89f89de42 100644 --- a/pkg/microservice/aslan/core/common/repository/models/task/artifact_package.go +++ b/pkg/microservice/aslan/core/common/repository/models/task/artifact_package.go @@ -17,12 +17,27 @@ limitations under the License. package task import ( + "encoding/json" "fmt" "github.com/koderover/zadig/pkg/microservice/aslan/config" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" ) +type ImageData struct { + ImageUrl string `bson:"image_url" json:"image_url"` + ImageName string `bson:"image_name" json:"image_name"` + ImageNamespace string `bson:"image_namespace" json:"image_namespace"` + ImageTag string `bson:"image_tag" json:"image_tag"` +} + +type ServicePackageResult struct { + ServiceName string `json:"service_name"` + Result string `json:"result"` + ErrorMsg string `json:"error_msg"` + ImageData []*ImageData `json:"image_data"` +} + type ArtifactPackage struct { TaskType config.TaskType `bson:"type" json:"type"` TaskStatus config.Status `bson:"status" json:"status"` @@ -32,6 +47,7 @@ type ArtifactPackage struct { StartTime int64 `bson:"start_time,omitempty" json:"start_time,omitempty"` EndTime int64 `bson:"end_time,omitempty" json:"end_time,omitempty"` LogFile string `bson:"log_file" json:"log_file"` + Progress string `bson:"progress" json:"progress"` // source images Images []*models.ImagesByService `bson:"images" json:"images"` @@ -48,3 +64,12 @@ func (ri *ArtifactPackage) ToSubTask() (map[string]interface{}, error) { } return task, nil } + +func (ri *ArtifactPackage) GetProgress() ([]*ServicePackageResult, error) { + if len(ri.Progress) == 0 { + return nil, nil + } + ret := make([]*ServicePackageResult, 0) + err := json.Unmarshal([]byte(ri.Progress), &ret) + return ret, err +} diff --git a/pkg/microservice/aslan/core/common/repository/models/task/model.go b/pkg/microservice/aslan/core/common/repository/models/task/model.go index d1d23f200..d4783d2e6 100644 --- a/pkg/microservice/aslan/core/common/repository/models/task/model.go +++ b/pkg/microservice/aslan/core/common/repository/models/task/model.go @@ -76,12 +76,12 @@ type Task struct { StorageURI string `bson:"storage_uri,omitempty" json:"storage_uri,omitempty"` // interface{} 为types.TestReport TestReports map[string]interface{} `bson:"test_reports,omitempty" json:"test_reports,omitempty"` - RwLock sync.Mutex `bson:"-" json:"-"` - ResetImage bool `json:"resetImage" bson:"resetImage"` - TriggerBy *models.TriggerBy `json:"trigger_by,omitempty" bson:"trigger_by,omitempty"` - Features []string `bson:"features" json:"features"` - IsRestart bool `bson:"is_restart" json:"is_restart"` - StorageEndpoint string `bson:"storage_endpoint" json:"storage_endpoint"` + RwLock sync.Mutex `bson:"-" json:"-"` + ResetImage bool `bson:"resetImage" json:"resetImage"` + TriggerBy *models.TriggerBy `bson:"trigger_by,omitempty" json:"trigger_by,omitempty"` + Features []string `bson:"features" json:"features"` + IsRestart bool `bson:"is_restart" json:"is_restart"` + StorageEndpoint string `bson:"storage_endpoint" json:"storage_endpoint"` } //type RenderInfo struct { diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/delivery_distribute.go b/pkg/microservice/aslan/core/common/repository/mongodb/delivery_distribute.go index 0b3ce01a7..98a9c39ed 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/delivery_distribute.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/delivery_distribute.go @@ -35,6 +35,7 @@ type DeliveryDistributeArgs struct { ID string `json:"id"` ReleaseID string `json:"releaseId"` ServiceName string `json:"serviceName"` + ChartName string `json:"chartName"` DistributeType config.DistributeType `json:"distributeType"` } @@ -62,6 +63,7 @@ func (c *DeliveryDistributeColl) EnsureIndex(ctx context.Context) error { Keys: bson.D{ bson.E{Key: "release_id", Value: 1}, bson.E{Key: "service_name", Value: 1}, + bson.E{Key: "chart_name", Value: 1}, bson.E{Key: "deleted_at", Value: 1}, }, Options: options.Index().SetUnique(false), @@ -115,8 +117,11 @@ func (c *DeliveryDistributeColl) Find(args *DeliveryDistributeArgs) ([]*models.D } query := bson.M{"release_id": releaseID, "deleted_at": 0} - if args.DistributeType != "" { - query["distribute_type"] = config.File + if len(args.DistributeType) > 0 { + query["distribute_type"] = string(args.DistributeType) + } + if len(args.ChartName) > 0 { + query["chart_name"] = args.ChartName } cursor, err := c.Collection.Find(context.TODO(), query) if err != nil { diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go b/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go index bae5fc668..e0adcfc8e 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/delivery_version.go @@ -34,6 +34,7 @@ import ( type DeliveryVersionArgs struct { ID string `json:"id"` ProductName string `json:"productName"` + Version string `json:"version"` WorkflowName string `json:"workflowName"` TaskID int `json:"taskId"` PerPage int `json:"perPage"` @@ -89,7 +90,6 @@ func (c *DeliveryVersionColl) Find(args *DeliveryVersionArgs) ([]*models.Deliver return nil, errors.New("nil delivery_version args") } - var resp []*models.DeliveryVersion query := bson.M{"deleted_at": 0} if args.ProductName != "" { query["product_name"] = args.ProductName @@ -113,6 +113,7 @@ func (c *DeliveryVersionColl) Find(args *DeliveryVersionArgs) ([]*models.Deliver return nil, err } + resp := make([]*models.DeliveryVersion, 0) err = cursor.All(ctx, &resp) if err != nil { return nil, err @@ -164,7 +165,13 @@ func (c *DeliveryVersionColl) Get(args *DeliveryVersionArgs) (*models.DeliveryVe resp := new(models.DeliveryVersion) var query map[string]interface{} if args.ID != "" { - query = bson.M{"_id": args.ID, "deleted_at": 0} + oid, err := primitive.ObjectIDFromHex(args.ID) + if err != nil { + return nil, err + } + query = bson.M{"_id": oid, "deleted_at": 0} + } else if len(args.Version) > 0 { + query = bson.M{"product_name": args.ProductName, "version": args.Version, "deleted_at": 0} } else { query = bson.M{"product_name": args.ProductName, "workflow_name": args.WorkflowName, "task_id": args.TaskID, "deleted_at": 0} } @@ -190,6 +197,16 @@ func (c *DeliveryVersionColl) Insert(args *models.DeliveryVersion) error { return nil } +func (c *DeliveryVersionColl) UpdateStatusByName(versionName, status, errorStr string) error { + query := bson.M{"version": versionName, "deleted_at": 0} + change := bson.M{"$set": bson.M{ + "status": status, + "error": errorStr, + }} + _, err := c.UpdateOne(context.TODO(), query, change) + return err +} + func (c *DeliveryVersionColl) Update(args *models.DeliveryVersion) error { if args == nil { return errors.New("nil delivery_version args") diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/helm_repo.go b/pkg/microservice/aslan/core/common/repository/mongodb/helm_repo.go index 6d7731676..86fff875e 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/helm_repo.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/helm_repo.go @@ -37,6 +37,11 @@ type HelmRepoColl struct { coll string } +type HelmRepoFindOption struct { + Id string + RepoName string +} + func NewHelmRepoColl() *HelmRepoColl { name := models.HelmRepo{}.TableName() coll := &HelmRepoColl{Collection: mongotool.Database(config.MongoDatabase()).Collection(name), coll: name} @@ -49,7 +54,12 @@ func (c *HelmRepoColl) GetCollectionName() string { } func (c *HelmRepoColl) EnsureIndex(ctx context.Context) error { - return nil + mod := mongo.IndexModel{ + Keys: bson.M{"repo_name": 1}, + Options: options.Index().SetUnique(false), + } + _, err := c.Indexes().CreateOne(ctx, mod) + return err } func (c *HelmRepoColl) Create(args *models.HelmRepo) error { @@ -64,6 +74,26 @@ func (c *HelmRepoColl) Create(args *models.HelmRepo) error { return err } +func (c *HelmRepoColl) Find(opt *HelmRepoFindOption) (*models.HelmRepo, error) { + query := bson.M{} + if len(opt.Id) > 0 { + oid, err := primitive.ObjectIDFromHex(opt.Id) + if err != nil { + return nil, err + } + query["_id"] = oid + } + if len(opt.RepoName) > 0 { + query["repo_name"] = opt.RepoName + } + ret := new(models.HelmRepo) + err := c.FindOne(context.TODO(), query).Decode(ret) + if err != nil { + return nil, err + } + return ret, nil +} + func (c *HelmRepoColl) Update(id string, args *models.HelmRepo) error { oid, err := primitive.ObjectIDFromHex(id) if err != nil { diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/template/product.go b/pkg/microservice/aslan/core/common/repository/mongodb/template/product.go index 4cf141c2d..474d2e960 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/template/product.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/template/product.go @@ -39,6 +39,7 @@ type ProjectInfo struct { UpdatedBy string `bson:"update_by"` OnboardStatus int `bson:"onboarding_status"` Public bool `bson:"public"` + DeployType string `bson:"deploy_type"` } type ProductColl struct { @@ -82,8 +83,8 @@ func (c *ProductColl) FindProjectName(project string) (*template.Product, error) } func (c *ProductColl) ListNames(inNames []string) ([]string, error) { - res, err := c.listProjects(inNames, bson.D{ - {"product_name", 1}, + res, err := c.listProjects(inNames, bson.M{ + "product_name": "$product_name", }) if err != nil { return nil, err @@ -98,29 +99,34 @@ func (c *ProductColl) ListNames(inNames []string) ([]string, error) { } func (c *ProductColl) ListProjectBriefs(inNames []string) ([]*ProjectInfo, error) { - return c.listProjects(inNames, bson.D{ - {"product_name", 1}, - {"project_name", 1}, - {"description", 1}, - {"update_time", 1}, - {"update_by", 1}, - {"onboarding_status", 1}, - {"public", 1}, + return c.listProjects(inNames, bson.M{ + "product_name": "$product_name", + "project_name": "$project_name", + "description": "$description", + "update_time": "$update_time", + "update_by": "$update_by", + "onboarding_status": "$onboarding_status", + "public": "$public", + "deploy_type": "$product_feature.deploy_type", }) } -func (c *ProductColl) listProjects(inNames []string, projection bson.D) ([]*ProjectInfo, error) { - opts := options.Find() +func (c *ProductColl) listProjects(inNames []string, projection bson.M) ([]*ProjectInfo, error) { filter := bson.M{} if len(inNames) > 0 { filter["product_name"] = bson.M{"$in": inNames} } - if len(projection) > 0 { - opts.SetProjection(projection) + pipeline := []bson.M{ + { + "$match": filter, + }, + { + "$project": projection, + }, } - cursor, err := c.Collection.Find(context.TODO(), filter, opts) + cursor, err := c.Collection.Aggregate(context.TODO(), pipeline) if err != nil { return nil, err } @@ -130,7 +136,6 @@ func (c *ProductColl) listProjects(inNames []string, projection bson.D) ([]*Proj if err != nil { return nil, err } - return res, nil } diff --git a/pkg/microservice/aslan/core/common/service/fs/s3.go b/pkg/microservice/aslan/core/common/service/fs/s3.go index 67c5db651..dfe02ea2c 100644 --- a/pkg/microservice/aslan/core/common/service/fs/s3.go +++ b/pkg/microservice/aslan/core/common/service/fs/s3.go @@ -24,15 +24,35 @@ import ( "go.uber.org/zap" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/s3" s3service "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/s3" "github.com/koderover/zadig/pkg/setting" s3tool "github.com/koderover/zadig/pkg/tool/s3" fsutil "github.com/koderover/zadig/pkg/util/fs" ) -// ArchiveAndUploadFilesToS3 archive local files and upload to default s3 storage -// if multiple names appointed, s3storage.copy will be used to handle extra names +func ArchiveAndUploadFilesToSpecifiedS3(fileTree fs.FS, names []string, s3Base, s3Id string, logger *zap.SugaredLogger) error { + s3Storage, err := s3service.FindS3ById(s3Id) + if err != nil { + logger.Errorf("Failed to find default s3, err:%v", err) + return err + } + return archiveAndUploadFiles(fileTree, names, s3Base, s3Storage, logger) +} + func ArchiveAndUploadFilesToS3(fileTree fs.FS, names []string, s3Base string, logger *zap.SugaredLogger) error { + s3Storage, err := s3service.FindDefaultS3() + if err != nil { + logger.Errorf("Failed to find default s3, err:%v", err) + return err + } + return archiveAndUploadFiles(fileTree, names, s3Base, s3Storage, logger) +} + +// archiveAndUploadFiles archive local files and upload to default s3 storage +// if multiple names appointed, s3storage.copy will be used to handle extra names +func archiveAndUploadFiles(fileTree fs.FS, names []string, s3Base string, s3Storage *s3.S3, logger *zap.SugaredLogger) error { + if len(names) == 0 { return fmt.Errorf("names not appointed") } @@ -53,11 +73,7 @@ func ArchiveAndUploadFilesToS3(fileTree fs.FS, names []string, s3Base string, lo logger.Errorf("Failed to archive tarball %s, err: %s", localPath, err) return err } - s3Storage, err := s3service.FindDefaultS3() - if err != nil { - logger.Errorf("Failed to find default s3, err:%v", err) - return err - } + forcedPathStyle := true if s3Storage.Provider == setting.ProviderSourceAli { forcedPathStyle = false diff --git a/pkg/microservice/aslan/core/common/service/s3/s3.go b/pkg/microservice/aslan/core/common/service/s3/s3.go index 24655148c..fc363b616 100644 --- a/pkg/microservice/aslan/core/common/service/s3/s3.go +++ b/pkg/microservice/aslan/core/common/service/s3/s3.go @@ -148,6 +148,16 @@ func FindDefaultS3() (*S3, error) { return &S3{S3Storage: storage}, nil } +func FindS3ById(id string) (*S3, error) { + storage, err := commonrepo.NewS3StorageColl().Find(id) + if err != nil { + log.Warnf("Failed to find s3 in db, err: %s", err) + return nil, err + } + + return &S3{S3Storage: storage}, nil +} + // 获取内置的s3 func FindInternalS3() *S3 { storage := &models.S3Storage{ diff --git a/pkg/microservice/aslan/core/common/service/service.go b/pkg/microservice/aslan/core/common/service/service.go index 780409314..fbcf8086c 100644 --- a/pkg/microservice/aslan/core/common/service/service.go +++ b/pkg/microservice/aslan/core/common/service/service.go @@ -21,6 +21,7 @@ import ( "encoding/json" "errors" "fmt" + "net/url" "regexp" "strings" templ "text/template" @@ -90,8 +91,9 @@ type ServiceProductMap struct { } var ( - imageParseRegex = regexp.MustCompile(`(?P.+/)?(?P[^:]+){1}(:)?(?P.+)?`) - presetPatterns = []map[string]string{ + imageParseRegex = regexp.MustCompile(`(?P.+/)?(?P[^:]+){1}(:)?(?P.+)?`) + imageSpaceParseRegex = regexp.MustCompile(`\/(.*?)\/`) + presetPatterns = []map[string]string{ {setting.PathSearchComponentImage: "image.repository", setting.PathSearchComponentTag: "image.tag"}, {setting.PathSearchComponentImage: "image"}, } @@ -614,6 +616,54 @@ func ExtractImageName(imageURI string) string { return "" } +// ExtractImageRegistry extract registry url from total image uri +func ExtractImageRegistry(imageURI string) (string, error) { + subMatchAll := imageParseRegex.FindStringSubmatch(imageURI) + exNames := imageParseRegex.SubexpNames() + for i, matchedStr := range subMatchAll { + if i != 0 && matchedStr != "" && matchedStr != ":" { + if exNames[i] == "repo" { + u, err := url.Parse(matchedStr) + if err != nil { + return "", err + } + if len(u.Scheme) > 0 { + matchedStr = strings.TrimPrefix(matchedStr, fmt.Sprintf("%s://", u.Scheme)) + } + return matchedStr, nil + } + } + } + return "", fmt.Errorf("failed to extract registry url") +} + +// ExtractImageTag extract image tag from total image uri +func ExtractImageTag(imageURI string) string { + subMatchAll := imageParseRegex.FindStringSubmatch(imageURI) + exNames := imageParseRegex.SubexpNames() + for i, matchedStr := range subMatchAll { + if i != 0 && matchedStr != "" && matchedStr != ":" { + if exNames[i] == "tag" { + return matchedStr + } + } + } + return "" +} + +// ExtractRegistryNamespace extract registry namespace form image uri +func ExtractRegistryNamespace(imageURI string) string { + imageURI = strings.TrimPrefix(imageURI, "http://") + imageURI = strings.TrimPrefix(imageURI, "https://") + + firstIndex := strings.Index(imageURI, "/") + lastIndex := strings.LastIndex(imageURI, "/") + if lastIndex == firstIndex { + return "" + } + return strings.TrimPrefix(imageURI[firstIndex:lastIndex], "/") +} + func parseImagesByPattern(nested map[string]interface{}, patterns []map[string]string) ([]*models.Container, error) { flatMap, err := converter.Flatten(nested) if err != nil { diff --git a/pkg/microservice/aslan/core/delivery/handler/router.go b/pkg/microservice/aslan/core/delivery/handler/router.go index 889b7e7aa..7b58bcade 100644 --- a/pkg/microservice/aslan/core/delivery/handler/router.go +++ b/pkg/microservice/aslan/core/delivery/handler/router.go @@ -45,6 +45,14 @@ func (*Router) Inject(router *gin.RouterGroup) { deliveryRelease.GET("/:id", GetDeliveryVersion) deliveryRelease.GET("", ListDeliveryVersion) deliveryRelease.DELETE("/:id", GetProductNameByDelivery, gin2.UpdateOperationLogStatus, DeleteDeliveryVersion) + + deliveryRelease.POST("/helm", CreateHelmDeliveryVersion) + deliveryRelease.POST("/helm/global-variables", ApplyDeliveryGlobalVariables) + deliveryRelease.GET("/helm/charts", DownloadDeliveryChart) + deliveryRelease.GET("/helm/charts/version", GetChartVersionFromRepo) + deliveryRelease.GET("/helm/charts/preview", PreviewGetDeliveryChart) + deliveryRelease.GET("/helm/charts/filePath", GetDeliveryChartFilePath) + deliveryRelease.GET("/helm/charts/fileContent", GetDeliveryChartFileContent) } deliveryPackage := router.Group("packages") diff --git a/pkg/microservice/aslan/core/delivery/handler/version.go b/pkg/microservice/aslan/core/delivery/handler/version.go index 44ea5e998..39a4e5519 100644 --- a/pkg/microservice/aslan/core/delivery/handler/version.go +++ b/pkg/microservice/aslan/core/delivery/handler/version.go @@ -17,19 +17,15 @@ limitations under the License. package handler import ( - "encoding/json" "fmt" - "strconv" + "net/http" "strings" "github.com/gin-gonic/gin" "github.com/koderover/zadig/pkg/microservice/aslan/config" - commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" - "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/base" deliveryservice "github.com/koderover/zadig/pkg/microservice/aslan/core/delivery/service" - workflowservice "github.com/koderover/zadig/pkg/microservice/aslan/core/workflow/service/workflow" internalhandler "github.com/koderover/zadig/pkg/shared/handler" e "github.com/koderover/zadig/pkg/tool/errors" "github.com/koderover/zadig/pkg/tool/log" @@ -65,189 +61,31 @@ func GetDeliveryVersion(c *gin.Context) { } version := new(commonrepo.DeliveryVersionArgs) version.ID = ID - ctx.Resp, ctx.Err = deliveryservice.GetDeliveryVersion(version, ctx.Logger) -} - -type ReleaseInfo struct { - VersionInfo *commonmodels.DeliveryVersion `json:"versionInfo"` - BuildInfo []*commonmodels.DeliveryBuild `json:"buildInfo"` - DeployInfo []*commonmodels.DeliveryDeploy `json:"deployInfo"` - TestInfo []*commonmodels.DeliveryTest `json:"testInfo"` - DistributeInfo []*commonmodels.DeliveryDistribute `json:"distributeInfo"` - SecurityInfo []*DeliverySecurityStats `json:"securityStatsInfo"` -} - -type DeliverySecurityStats struct { - ImageName string `json:"imageName"` - ImageID string `json:"imageId"` - DeliverySecurityStatsInfo DeliverySecurityStatsInfo `json:"deliverySecurityStatsInfo"` -} - -type DeliverySecurityStatsInfo struct { - Total int `json:"total"` - Unknown int `json:"unkown"` - Negligible int `json:"negligible"` - Low int `json:"low"` - Medium int `json:"medium"` - High int `json:"high"` - Critical int `json:"critical"` + ctx.Resp, ctx.Err = deliveryservice.GetDetailReleaseData(version, ctx.Logger) } func ListDeliveryVersion(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - taskIDStr := c.Query("taskId") - var taskID = 0 - var err error - if taskIDStr != "" { - taskID, err = strconv.Atoi(taskIDStr) - if err != nil { - ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) - return - } + args := new(deliveryservice.ListDeliveryVersionArgs) + err := c.BindQuery(args) + if err != nil { + ctx.Err = e.ErrInvalidParam.AddErr(err) + return } - perPageStr := c.Query("per_page") - pageStr := c.Query("page") - var ( - perPage int - page int - ) - if perPageStr == "" { - perPage = 20 - } else { - perPage, err = strconv.Atoi(perPageStr) - if err != nil { - ctx.Err = e.ErrInvalidParam.AddDesc(fmt.Sprintf("perPage args err :%s", err)) - return - } + if args.Page <= 0 { + args.Page = 1 } - - if pageStr == "" { - page = 1 - } else { - page, err = strconv.Atoi(pageStr) - if err != nil { - ctx.Err = e.ErrInvalidParam.AddDesc(fmt.Sprintf("page args err :%s", err)) - return - } + if args.PerPage <= 0 { + args.PerPage = 20 } - - serviceName := c.Query("serviceName") - - version := new(commonrepo.DeliveryVersionArgs) - version.ProductName = c.Query("projectName") - version.WorkflowName = c.Query("workflowName") - version.TaskID = taskID - version.PerPage = perPage - version.Page = page - deliveryVersions, err := deliveryservice.FindDeliveryVersion(version, ctx.Logger) - - if err != nil { - ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) - return + if len(args.Verbosity) == 0 { + args.Verbosity = deliveryservice.VerbosityDetailed } - releaseInfos := make([]*ReleaseInfo, 0) - for _, deliveryVersion := range deliveryVersions { - releaseInfo := new(ReleaseInfo) - //versionInfo - releaseInfo.VersionInfo = deliveryVersion - - //deployInfo - deliveryDeployArgs := new(commonrepo.DeliveryDeployArgs) - deliveryDeployArgs.ReleaseID = deliveryVersion.ID.Hex() - deliveryDeploys, err := deliveryservice.FindDeliveryDeploy(deliveryDeployArgs, ctx.Logger) - if err != nil { - ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) - } - // 查询条件serviceName - if serviceName != "" { - match := false - for _, deliveryDeploy := range deliveryDeploys { - if deliveryDeploy.ServiceName == serviceName { - match = true - break - } - } - if !match { - continue - } - } - // 将serviceName替换为服务名/服务组件的形式,用于前端展示 - for _, deliveryDeploy := range deliveryDeploys { - if deliveryDeploy.ContainerName != "" { - deliveryDeploy.ServiceName = deliveryDeploy.ServiceName + "/" + deliveryDeploy.ContainerName - } - } - releaseInfo.DeployInfo = deliveryDeploys - - //buildInfo - deliveryBuildArgs := new(commonrepo.DeliveryBuildArgs) - deliveryBuildArgs.ReleaseID = deliveryVersion.ID.Hex() - deliveryBuilds, err := deliveryservice.FindDeliveryBuild(deliveryBuildArgs, ctx.Logger) - if err != nil { - ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) - } - releaseInfo.BuildInfo = deliveryBuilds - - //testInfo - deliveryTestArgs := new(commonrepo.DeliveryTestArgs) - deliveryTestArgs.ReleaseID = deliveryVersion.ID.Hex() - deliveryTests, err := deliveryservice.FindDeliveryTest(deliveryTestArgs, ctx.Logger) - if err != nil { - ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) - } - releaseInfo.TestInfo = deliveryTests - - //securityStatsInfo - deliverySecurityStatss := make([]*DeliverySecurityStats, 0) - if pipelineTask, err := workflowservice.GetPipelineTaskV2(int64(deliveryVersion.TaskID), deliveryVersion.WorkflowName, config.WorkflowType, ctx.Logger); err == nil { - for _, subStage := range pipelineTask.Stages { - if subStage.TaskType == config.TaskSecurity { - subSecurityTaskMap := subStage.SubTasks - for _, subTask := range subSecurityTaskMap { - securityInfo, _ := base.ToSecurityTask(subTask) - - deliverySecurityStats := new(DeliverySecurityStats) - deliverySecurityStats.ImageName = securityInfo.ImageName - deliverySecurityStats.ImageID = securityInfo.ImageID - deliverySecurityStatsMap, err := deliveryservice.FindDeliverySecurityStatistics(securityInfo.ImageID, ctx.Logger) - if err != nil { - ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) - } - var transErr error - b, err := json.Marshal(deliverySecurityStatsMap) - if err != nil { - transErr = fmt.Errorf("marshal task error: %v", err) - } - - if err := json.Unmarshal(b, &deliverySecurityStats.DeliverySecurityStatsInfo); err != nil { - transErr = fmt.Errorf("unmarshal task error: %v", err) - } - if transErr != nil { - ctx.Err = e.ErrInvalidParam.AddDesc(err.Error()) - } - - deliverySecurityStatss = append(deliverySecurityStatss, deliverySecurityStats) - } - break - } - } - releaseInfo.SecurityInfo = deliverySecurityStatss - } - - //distributeInfo - deliveryDistributeArgs := new(commonrepo.DeliveryDistributeArgs) - deliveryDistributeArgs.ReleaseID = deliveryVersion.ID.Hex() - deliveryDistributes, _ := deliveryservice.FindDeliveryDistribute(deliveryDistributeArgs, ctx.Logger) - - releaseInfo.DistributeInfo = deliveryDistributes - releaseInfos = append(releaseInfos, releaseInfo) - } - ctx.Err = err - ctx.Resp = releaseInfos + ctx.Resp, ctx.Err = deliveryservice.ListDeliveryVersion(args, ctx.Logger) } func getFileName(fileName string) string { @@ -326,6 +164,20 @@ func ListPackagesVersion(c *gin.Context) { ctx.Resp = fileInfoList } +func CreateHelmDeliveryVersion(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + args := new(deliveryservice.CreateHelmDeliveryVersionArgs) + err := c.ShouldBindJSON(args) + if err != nil { + ctx.Err = e.ErrInvalidParam.AddErr(err) + return + } + args.CreateBy = ctx.UserName + ctx.Err = deliveryservice.CreateHelmDeliveryVersion(args, ctx.Logger) +} + func DeleteDeliveryVersion(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() @@ -371,3 +223,82 @@ func ListDeliveryServiceNames(c *gin.Context) { productName := c.Query("projectName") ctx.Resp, ctx.Err = deliveryservice.ListDeliveryServiceNames(productName, ctx.Logger) } + +func DownloadDeliveryChart(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + versionName := c.Query("version") + chartName := c.Query("chartName") + projectName := c.Query("projectName") + + fileBytes, fileName, err := deliveryservice.DownloadDeliveryChart(projectName, versionName, chartName, ctx.Logger) + if err != nil { + ctx.Err = err + return + } + + c.Writer.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, fileName)) + c.Data(http.StatusOK, "application/octet-stream", fileBytes) +} + +func GetChartVersionFromRepo(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + chartName := c.Query("chartName") + chartRepoName := c.Query("chartRepoName") + + ctx.Resp, ctx.Err = deliveryservice.GetChartVersions(chartName, chartRepoName) +} + +func PreviewGetDeliveryChart(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + versionName := c.Query("version") + chartName := c.Query("chartName") + projectName := c.Query("projectName") + + ctx.Resp, ctx.Err = deliveryservice.PreviewDeliveryChart(projectName, versionName, chartName, ctx.Logger) +} + +func GetDeliveryChartFilePath(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + args := new(deliveryservice.DeliveryChartFilePathArgs) + err := c.BindQuery(args) + if err != nil { + ctx.Err = e.ErrInvalidParam.AddErr(err) + return + } + + ctx.Resp, ctx.Err = deliveryservice.GetDeliveryChartFilePath(args, ctx.Logger) +} + +func GetDeliveryChartFileContent(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + args := new(deliveryservice.DeliveryChartFileContentArgs) + err := c.BindQuery(args) + if err != nil { + ctx.Err = e.ErrInvalidParam.AddErr(err) + return + } + ctx.Resp, ctx.Err = deliveryservice.GetDeliveryChartFileContent(args, ctx.Logger) +} + +func ApplyDeliveryGlobalVariables(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + args := new(deliveryservice.DeliveryVariablesApplyArgs) + err := c.BindJSON(args) + if err != nil { + ctx.Err = e.ErrInvalidParam.AddErr(err) + return + } + ctx.Resp, ctx.Err = deliveryservice.ApplyDeliveryGlobalVariables(args, ctx.Logger) +} diff --git a/pkg/microservice/aslan/core/delivery/service/docker.go b/pkg/microservice/aslan/core/delivery/service/docker.go new file mode 100644 index 000000000..65a35941e --- /dev/null +++ b/pkg/microservice/aslan/core/delivery/service/docker.go @@ -0,0 +1,57 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package service + +import "os/exec" + +const dockerExe = "/usr/local/bin/docker" + +func dockerLogin(user, password, registry string) *exec.Cmd { + return exec.Command( + dockerExe, + "login", + "-u", user, + "-p", password, + registry, + ) +} + +func dockerInfo() *exec.Cmd { + return exec.Command(dockerExe, "info") +} + +func dockerPush(fullImage string) *exec.Cmd { + args := []string{ + "push", + fullImage, + } + return exec.Command(dockerExe, args...) +} + +func dockerPull(image string) *exec.Cmd { + args := []string{"pull", image} + return exec.Command(dockerExe, args...) +} + +func dockerTag(sourceFullImage, targetFullImage string) *exec.Cmd { + args := []string{ + "tag", + sourceFullImage, + targetFullImage, + } + return exec.Command(dockerExe, args...) +} diff --git a/pkg/microservice/aslan/core/delivery/service/version.go b/pkg/microservice/aslan/core/delivery/service/version.go index 1c013f689..7bba266c3 100644 --- a/pkg/microservice/aslan/core/delivery/service/version.go +++ b/pkg/microservice/aslan/core/delivery/service/version.go @@ -17,21 +17,189 @@ limitations under the License. package service import ( + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "os" + "path/filepath" + "strings" + "sync" + "time" + + cm "github.com/chartmuseum/helm-push/pkg/chartmuseum" + "github.com/chartmuseum/helm-push/pkg/helm" + "github.com/hashicorp/go-multierror" + "github.com/otiai10/copy" + "github.com/pkg/errors" + "go.mongodb.org/mongo-driver/bson/primitive" "go.uber.org/zap" + chartloader "helm.sh/helm/v3/pkg/chart/loader" + "helm.sh/helm/v3/pkg/chartutil" "k8s.io/apimachinery/pkg/util/sets" + "sigs.k8s.io/yaml" + "github.com/koderover/zadig/pkg/microservice/aslan/config" commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/task" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/template" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" + commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/base" + workflowservice "github.com/koderover/zadig/pkg/microservice/aslan/core/workflow/service/workflow" + "github.com/koderover/zadig/pkg/setting" e "github.com/koderover/zadig/pkg/tool/errors" + helmtool "github.com/koderover/zadig/pkg/tool/helmclient" + "github.com/koderover/zadig/pkg/tool/log" + "github.com/koderover/zadig/pkg/types" + fsutil "github.com/koderover/zadig/pkg/util/fs" + yamlutil "github.com/koderover/zadig/pkg/util/yaml" +) + +const ( + VerbosityBrief string = "brief" // brief delivery data + VerbosityDetailed string = "detailed" // detailed delivery version with total data ) +type DeliveryVersionFilter struct { + ServiceName string +} + +type CreateHelmDeliveryVersionOption struct { + EnableOfflineDist bool `json:"enableOfflineDist"` + S3StorageID string `json:"s3StorageID"` +} + +type CreateHelmDeliveryVersionChartData struct { + ServiceName string `json:"serviceName"` + Version string `json:"version,omitempty"` + ValuesYamlContent string `json:"valuesYamlContent"` +} + +type CreateHelmDeliveryVersionArgs struct { + CreateBy string `json:"-"` + ProductName string `json:"productName"` + Retry bool `json:"retry"` + Version string `json:"version"` + Desc string `json:"desc"` + EnvName string `json:"envName"` + Labels []string `json:"labels"` + ImageRepoName string `json:"imageRepoName"` + *DeliveryVersionChartData +} + +type DeliveryVersionChartData struct { + GlobalVariables string `json:"globalVariables"` + ChartRepoName string `json:"chartRepoName"` + ImageRegistryID string `json:"imageRegistryID"` + ChartDatas []*CreateHelmDeliveryVersionChartData `json:"chartDatas"` + Options *CreateHelmDeliveryVersionOption `json:"options"` +} + +type DeliveryChartData struct { + ChartData *CreateHelmDeliveryVersionChartData + ServiceObj *commonmodels.Service + ProductService *commonmodels.ProductService + RenderChart *template.RenderChart + RenderSet *commonmodels.RenderSet +} + +type DeliveryChartResp struct { + FileInfos []*types.FileInfo `json:"fileInfos"` +} + +type DeliveryChartFilePathArgs struct { + Dir string `json:"dir"` + ProjectName string `json:"projectName"` + ChartName string `json:"chartName"` + Version string `json:"version"` +} + +type DeliveryChartFileContentArgs struct { + FilePath string `json:"filePath"` + FileName string `json:"fileName"` + ProjectName string `json:"projectName"` + ChartName string `json:"chartName"` + Version string `json:"version"` +} + +type DeliveryVariablesApplyArgs struct { + GlobalVariables string `json:"globalVariables,omitempty"` + ChartDatas []*CreateHelmDeliveryVersionChartData `json:"chartDatas"` +} + +type ListDeliveryVersionArgs struct { + Page int `form:"page"` + PerPage int `form:"per_page"` + TaskId int `form:"taskId"` + ServiceName string `form:"serviceName"` + Verbosity string `form:"verbosity"` + ProjectName string `form:"projectName"` + WorkflowName string `form:"workflowName"` +} + +type ReleaseInfo struct { + VersionInfo *commonmodels.DeliveryVersion `json:"versionInfo"` + BuildInfo []*commonmodels.DeliveryBuild `json:"buildInfo,omitempty"` + DeployInfo []*commonmodels.DeliveryDeploy `json:"deployInfo,omitempty"` + TestInfo []*commonmodels.DeliveryTest `json:"testInfo,omitempty"` + DistributeInfo []*commonmodels.DeliveryDistribute `json:"distributeInfo,omitempty"` + SecurityInfo []*DeliverySecurityStats `json:"securityStatsInfo,omitempty"` +} + +type DeliverySecurityStatsInfo struct { + Total int `json:"total"` + Unknown int `json:"unkown"` + Negligible int `json:"negligible"` + Low int `json:"low"` + Medium int `json:"medium"` + High int `json:"high"` + Critical int `json:"critical"` +} + +type DeliverySecurityStats struct { + ImageName string `json:"imageName"` + ImageID string `json:"imageId"` + DeliverySecurityStatsInfo DeliverySecurityStatsInfo `json:"deliverySecurityStatsInfo"` +} + +type ImageUrlDetail struct { + ImageUrl string + Name string + Registry string + Tag string +} + +type ServiceImageDetails struct { + ServiceName string + Images []*ImageUrlDetail + Registries []string +} + +type ChartVersionResp struct { + ChartName string `json:"chartName"` + ChartVersion string `json:"chartVersion"` +} + func GetDeliveryVersion(args *commonrepo.DeliveryVersionArgs, log *zap.SugaredLogger) (*commonmodels.DeliveryVersion, error) { - resp, err := commonrepo.NewDeliveryVersionColl().Get(args) + versionData, err := commonrepo.NewDeliveryVersionColl().Get(args) if err != nil { log.Errorf("get deliveryVersion error: %v", err) return nil, e.ErrGetDeliveryVersion } - return resp, err + return versionData, err +} + +func GetDetailReleaseData(args *commonrepo.DeliveryVersionArgs, log *zap.SugaredLogger) (*ReleaseInfo, error) { + versionData, err := commonrepo.NewDeliveryVersionColl().Get(args) + if err != nil { + log.Errorf("get deliveryVersion error: %v", err) + return nil, e.ErrGetDeliveryVersion + } + return buildListReleaseResp(VerbosityDetailed, versionData, nil, log) } func FindDeliveryVersion(args *commonrepo.DeliveryVersionArgs, log *zap.SugaredLogger) ([]*commonmodels.DeliveryVersion, error) { @@ -52,29 +220,1303 @@ func DeleteDeliveryVersion(args *commonrepo.DeliveryVersionArgs, log *zap.Sugare return nil } -func ListDeliveryServiceNames(productName string, log *zap.SugaredLogger) ([]string, error) { - serviceNames := sets.String{} +func filterReleases(filter *DeliveryVersionFilter, deliveryVersion *commonmodels.DeliveryVersion, logger *zap.SugaredLogger) bool { + if filter == nil { + return true + } + if filter.ServiceName != "" { + deliveryDeployArgs := new(commonrepo.DeliveryDeployArgs) + deliveryDeployArgs.ReleaseID = deliveryVersion.ID.Hex() + deliveryDeploys, err := FindDeliveryDeploy(deliveryDeployArgs, logger) + if err != nil { + return true + } + match := false + for _, deliveryDeploy := range deliveryDeploys { + if deliveryDeploy.ServiceName == filter.ServiceName { + match = true + break + } + } + if !match { + return false + } + } + return true +} - version := new(commonrepo.DeliveryVersionArgs) - version.ProductName = productName - deliveryVersions, err := FindDeliveryVersion(version, log) +func buildBriefRelease(deliveryVersion *commonmodels.DeliveryVersion, _ *zap.SugaredLogger) (*ReleaseInfo, error) { + return &ReleaseInfo{ + VersionInfo: deliveryVersion, + }, nil +} + +func buildDetailedRelease(deliveryVersion *commonmodels.DeliveryVersion, filterOpt *DeliveryVersionFilter, logger *zap.SugaredLogger) (*ReleaseInfo, error) { + releaseInfo := new(ReleaseInfo) + //versionInfo + releaseInfo.VersionInfo = deliveryVersion + + //deployInfo + deliveryDeployArgs := new(commonrepo.DeliveryDeployArgs) + deliveryDeployArgs.ReleaseID = deliveryVersion.ID.Hex() + deliveryDeploys, err := FindDeliveryDeploy(deliveryDeployArgs, logger) if err != nil { - log.Errorf("FindDeliveryVersion failed, err:%v", err) - return serviceNames.List(), err + return nil, err } + if filterOpt != nil { + if !filterReleases(filterOpt, deliveryVersion, logger) { + return nil, nil + } + } + // 将serviceName替换为服务名/服务组件的形式,用于前端展示 + for _, deliveryDeploy := range deliveryDeploys { + if deliveryDeploy.ContainerName != "" { + deliveryDeploy.ServiceName = deliveryDeploy.ServiceName + "/" + deliveryDeploy.ContainerName + } + } + releaseInfo.DeployInfo = deliveryDeploys + + //buildInfo + deliveryBuildArgs := new(commonrepo.DeliveryBuildArgs) + deliveryBuildArgs.ReleaseID = deliveryVersion.ID.Hex() + deliveryBuilds, err := FindDeliveryBuild(deliveryBuildArgs, logger) + if err != nil { + return nil, err + } + releaseInfo.BuildInfo = deliveryBuilds + + //testInfo + deliveryTestArgs := new(commonrepo.DeliveryTestArgs) + deliveryTestArgs.ReleaseID = deliveryVersion.ID.Hex() + deliveryTests, err := FindDeliveryTest(deliveryTestArgs, logger) + if err != nil { + return nil, err + } + releaseInfo.TestInfo = deliveryTests + + //securityStatsInfo + deliverySecurityStatss := make([]*DeliverySecurityStats, 0) + if pipelineTask, err := workflowservice.GetPipelineTaskV2(int64(deliveryVersion.TaskID), deliveryVersion.WorkflowName, config.WorkflowType, logger); err == nil { + for _, subStage := range pipelineTask.Stages { + if subStage.TaskType == config.TaskSecurity { + subSecurityTaskMap := subStage.SubTasks + for _, subTask := range subSecurityTaskMap { + securityInfo, _ := base.ToSecurityTask(subTask) + + deliverySecurityStats := new(DeliverySecurityStats) + deliverySecurityStats.ImageName = securityInfo.ImageName + deliverySecurityStats.ImageID = securityInfo.ImageID + deliverySecurityStatsMap, err := FindDeliverySecurityStatistics(securityInfo.ImageID, logger) + if err != nil { + return nil, err + } + var transErr error + b, err := json.Marshal(deliverySecurityStatsMap) + if err != nil { + transErr = fmt.Errorf("marshal task error: %v", err) + } + if err := json.Unmarshal(b, &deliverySecurityStats.DeliverySecurityStatsInfo); err != nil { + transErr = fmt.Errorf("unmarshal task error: %v", err) + } + if transErr != nil { + return nil, transErr + } + + deliverySecurityStatss = append(deliverySecurityStatss, deliverySecurityStats) + } + break + } + } + releaseInfo.SecurityInfo = deliverySecurityStatss + } + + //distributeInfo + deliveryDistributeArgs := new(commonrepo.DeliveryDistributeArgs) + deliveryDistributeArgs.ReleaseID = deliveryVersion.ID.Hex() + deliveryDistributes, _ := FindDeliveryDistribute(deliveryDistributeArgs, logger) + releaseInfo.DistributeInfo = deliveryDistributes + // fill some data for helm delivery releases + processReleaseRespData(releaseInfo) + + return releaseInfo, nil +} + +func buildListReleaseResp(verbosity string, deliveryVersion *commonmodels.DeliveryVersion, filterOpt *DeliveryVersionFilter, logger *zap.SugaredLogger) (*ReleaseInfo, error) { + switch verbosity { + case VerbosityBrief: + return buildBriefRelease(deliveryVersion, logger) + case VerbosityDetailed: + return buildDetailedRelease(deliveryVersion, filterOpt, logger) + default: + return buildDetailedRelease(deliveryVersion, filterOpt, logger) + } +} + +func ListDeliveryVersion(args *ListDeliveryVersionArgs, logger *zap.SugaredLogger) ([]*ReleaseInfo, error) { + versionListArgs := new(commonrepo.DeliveryVersionArgs) + versionListArgs.ProductName = args.ProjectName + versionListArgs.WorkflowName = args.WorkflowName + versionListArgs.TaskID = args.TaskId + versionListArgs.PerPage = args.PerPage + versionListArgs.Page = args.Page + deliveryVersions, err := FindDeliveryVersion(versionListArgs, logger) + if err != nil { + return nil, err + } + + releaseInfos := make([]*ReleaseInfo, 0) for _, deliveryVersion := range deliveryVersions { - deliveryDeployArgs := new(commonrepo.DeliveryDeployArgs) - deliveryDeployArgs.ReleaseID = deliveryVersion.ID.Hex() - deliveryDeploys, err := FindDeliveryDeploy(deliveryDeployArgs, log) + releaseInfo, err := buildListReleaseResp(args.Verbosity, deliveryVersion, &DeliveryVersionFilter{ServiceName: args.ServiceName}, logger) if err != nil { - log.Errorf("FindDeliveryDeploy failed, ReleaseID:%s, err:%v", deliveryVersion.ID, err) + return nil, err + } + if releaseInfo == nil { continue } - for _, deliveryDeploy := range deliveryDeploys { - serviceNames.Insert(deliveryDeploy.ServiceName) + releaseInfos = append(releaseInfos, releaseInfo) + } + return releaseInfos, nil +} + +// fill release +func processReleaseRespData(release *ReleaseInfo) { + if release.VersionInfo.Type != setting.DeliveryVersionTypeChart { + return + } + + distributeMap := make(map[string][]*commonmodels.DeliveryDistribute) + for _, distributeImage := range release.DistributeInfo { + if distributeImage.DistributeType != config.Image { + continue } + distributeMap[distributeImage.ChartName] = append(distributeMap[distributeImage.ChartName], distributeImage) } - return serviceNames.UnsortedList(), nil + chartDistributeCount := 0 + distributes := make([]*commonmodels.DeliveryDistribute, 0) + for _, distribute := range release.DistributeInfo { + if distribute.DistributeType == config.Image { + continue + } + switch distribute.DistributeType { + case config.Chart: + chartDistributeCount++ + distribute.SubDistributes = distributeMap[distribute.ChartName] + case config.File: + s3Storage, err := commonrepo.NewS3StorageColl().Find(distribute.S3StorageID) + if err != nil { + log.Errorf("failed to query s3 storageID: %s, err: %s", distribute.S3StorageID, err) + } else { + distribute.StorageURL = s3Storage.Endpoint + distribute.StorageBucket = s3Storage.Bucket + } + } + distributes = append(distributes, distribute) + } + release.DistributeInfo = distributes + + release.VersionInfo.Progress = buildDeliveryProgressInfo(release.VersionInfo, chartDistributeCount) +} + +func buildDeliveryProgressInfo(deliveryVersion *commonmodels.DeliveryVersion, successfulChartCount int) *commonmodels.DeliveryVersionProgress { + if deliveryVersion.Type != setting.DeliveryVersionTypeChart { + return nil + } + + progress := &commonmodels.DeliveryVersionProgress{ + SuccessChartCount: successfulChartCount, + TotalChartCount: 0, + PackageUploadStatus: "", + Error: "", + } + if deliveryVersion.Status == setting.DeliveryVersionStatusSuccess { + progress.TotalChartCount = successfulChartCount + progress.PackageUploadStatus = setting.DeliveryVersionPackageStatusSuccess + return progress + } + + argsBytes, err := json.Marshal(deliveryVersion.CreateArgument) + if err != nil { + log.Errorf("failed to marshal arguments, versionName: %s err %s", deliveryVersion.Version, err) + return progress + } + createArgs := new(DeliveryVersionChartData) + err = json.Unmarshal(argsBytes, createArgs) + if err != nil { + log.Errorf("failed to unMarshal arguments, versionName: %s err %s", deliveryVersion.Version, err) + return progress + } + + progress.TotalChartCount = len(createArgs.ChartDatas) + + if deliveryVersion.Status == setting.DeliveryVersionStatusFailed { + progress.PackageUploadStatus = setting.DeliveryVersionPackageStatusFailed + progress.Error = deliveryVersion.Error + return progress + } + + if len(createArgs.ChartDatas) > successfulChartCount { + progress.PackageUploadStatus = setting.DeliveryVersionPackageStatusWaiting + return progress + } + + progress.PackageUploadStatus = setting.DeliveryVersionPackageStatusUploading + return progress + +} + +func getChartTGZDir(productName, versionName string) string { + tmpDir := os.TempDir() + return filepath.Join(tmpDir, "chart-tgz", productName, versionName) +} + +func getChartExpandDir(productName, versionName string) string { + tmpDir := os.TempDir() + return filepath.Join(tmpDir, "chart", productName, versionName) +} + +func getProductEnvInfo(productName, envName string) (*commonmodels.Product, error) { + productInfo, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{ + Name: productName, + EnvName: envName, + }) + if err != nil { + log.Errorf("failed to query product info, productName: %s envName: %s err: %s", productName, envName, err) + return nil, fmt.Errorf("failed to query product info, productName: %s envName: %s", productName, envName) + } + return productInfo, nil +} + +func getChartRepoData(repoName string) (*commonmodels.HelmRepo, error) { + return commonrepo.NewHelmRepoColl().Find(&commonrepo.HelmRepoFindOption{RepoName: repoName}) +} + +func createChartRepoClient(repo *commonmodels.HelmRepo) (*cm.Client, error) { + client, err := cm.NewClient( + cm.URL(repo.URL), + cm.Username(repo.Username), + cm.Password(repo.Password), + // need support more auth types + ) + if err != nil { + return nil, errors.Wrapf(err, "failed to create chart repo client, repoName: %s", repo.RepoName) + } + return client, nil +} + +// find all images in one single chart +func extractImages(productService *commonmodels.ProductService, registryMap map[string]*commonmodels.RegistryNamespace) (*ServiceImageDetails, error) { + imageUrlsSet := sets.NewString() + for _, container := range productService.Containers { + imageUrlsSet.Insert(container.Image) + } + + ret := &ServiceImageDetails{ + ServiceName: productService.ServiceName, + Images: make([]*ImageUrlDetail, 0), + } + + registrySet := sets.NewString() + + for _, imageUrl := range imageUrlsSet.List() { + + registryUrl, err := commonservice.ExtractImageRegistry(imageUrl) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse registry from image uri: %s", imageUrl) + } + registryUrl = strings.TrimSuffix(registryUrl, "/") + + imageName := commonservice.ExtractImageName(imageUrl) + imageTag := commonservice.ExtractImageTag(imageUrl) + + registryID := "" + // used source registry + if registry, ok := registryMap[registryUrl]; ok { + registryID = registry.ID.Hex() + registrySet.Insert(registryID) + } + + ret.Images = append(ret.Images, &ImageUrlDetail{ + ImageUrl: imageUrl, + Name: imageName, + Tag: imageTag, + Registry: registryID, + }) + } + + ret.Registries = registrySet.List() + return ret, nil +} + +// ensure chart files exist +func ensureChartFiles(chartData *DeliveryChartData) (string, error) { + serviceObj := chartData.ServiceObj + revisionBasePath := config.LocalDeliveryChartPathWithRevision(serviceObj.ProductName, serviceObj.ServiceName, serviceObj.Revision) + deliveryChartPath := filepath.Join(revisionBasePath, serviceObj.ServiceName) + if exists, _ := fsutil.DirExists(deliveryChartPath); exists { + return deliveryChartPath, nil + } + + serviceName, revision := serviceObj.ServiceName, serviceObj.Revision + basePath := config.LocalServicePathWithRevision(serviceObj.ProductName, serviceName, revision) + if err := commonservice.PreloadServiceManifestsByRevision(basePath, serviceObj); err != nil { + log.Warnf("failed to get chart of revision: %d for service: %s, use latest version", revision, serviceName) + // use the latest version when it fails to download the specific version + basePath = config.LocalServicePath(serviceObj.ProductName, serviceName) + if err = commonservice.PreLoadServiceManifests(basePath, serviceObj); err != nil { + log.Errorf("failed to load chart info for service %v", serviceObj.ServiceName) + return "", err + } + } + + fullPath := filepath.Join(basePath, serviceObj.ServiceName) + err := copy.Copy(fullPath, deliveryChartPath) + if err != nil { + return "", err + } + + mergedValuesYaml, err := helmtool.MergeOverrideValues(chartData.RenderChart.ValuesYaml, chartData.RenderSet.DefaultValues, chartData.RenderChart.GetOverrideYaml(), chartData.RenderChart.OverrideValues) + if err != nil { + return "", err + } + err = os.WriteFile(filepath.Join(deliveryChartPath, setting.ValuesYaml), []byte(mergedValuesYaml), 0644) + if err != nil { + return "", errors.Wrapf(err, "failed to write values.yaml") + } + + return deliveryChartPath, nil +} + +func buildChartPackage(chartData *DeliveryChartData, chartRepo *commonmodels.HelmRepo, dir string, globalVariables string, registryMap map[string]*commonmodels.RegistryNamespace) error { + serviceObj := chartData.ServiceObj + + deliveryChartPath, err := ensureChartFiles(chartData) + if err != nil { + return err + } + + valuesYamlData := make(map[string]interface{}) + valuesFilePath := filepath.Join(deliveryChartPath, setting.ValuesYaml) + valueYamlContent, err := os.ReadFile(valuesFilePath) + if err != nil { + return errors.Wrapf(err, "failed to read values.yaml for service %s", serviceObj.ServiceName) + } + err = yaml.Unmarshal(valueYamlContent, &valuesYamlData) + if err != nil { + return errors.Wrapf(err, "failed to unmarshal values.yaml for service %s", serviceObj.ServiceName) + } + + // write values.yaml file before load + if len(chartData.ChartData.ValuesYamlContent) > 0 { // values.yaml was edited directly + if err = yaml.Unmarshal([]byte(chartData.ChartData.ValuesYamlContent), map[string]interface{}{}); err != nil { + log.Errorf("invalid yaml content, serviceName: %s, yamlContent: %s", serviceObj.ServiceName, chartData.ChartData.ValuesYamlContent) + return errors.Wrapf(err, "invalid yaml content for service: %s", serviceObj.ServiceName) + } + valueYamlContent = []byte(chartData.ChartData.ValuesYamlContent) + } else if len(globalVariables) > 0 { // merge global variables + valueYamlContent, err = yamlutil.Merge([][]byte{valueYamlContent, []byte(globalVariables)}) + if err != nil { + return errors.Wrapf(err, "failed to merge global variables for service: %s", serviceObj.ServiceName) + } + } + err = os.WriteFile(valuesFilePath, valueYamlContent, 0644) + if err != nil { + return errors.Wrapf(err, "failed to write values.yaml file for service %s", serviceObj.ServiceName) + } + + //load chart info from local storage + chartRequested, err := chartloader.Load(deliveryChartPath) + if err != nil { + return errors.Wrapf(err, "failed to load chart info, path %s", deliveryChartPath) + } + + //set metadata + chartRequested.Metadata.Name = chartData.ChartData.ServiceName + chartRequested.Metadata.Version = chartData.ChartData.Version + chartRequested.Metadata.AppVersion = chartData.ChartData.Version + + //create local chart package + chartPackagePath, err := helm.CreateChartPackage(&helm.Chart{Chart: chartRequested}, dir) + if err != nil { + return err + } + + client, err := createChartRepoClient(chartRepo) + if err != nil { + return errors.Wrapf(err, "failed to create chart repo client, repoName: %s", chartRepo.RepoName) + } + + log.Infof("pushing chart %s to %s...", filepath.Base(chartPackagePath), chartRepo.URL) + resp, err := client.UploadChartPackage(chartPackagePath, false) + if err != nil { + return errors.Wrapf(err, "failed to prepare pushing chart: %s", chartPackagePath) + } + err = handlePushResponse(resp) + if err != nil { + return errors.Wrapf(err, "failed to push chart: %s ", chartPackagePath) + } + return nil +} + +func handlePushResponse(resp *http.Response) error { + if resp.StatusCode != 201 && resp.StatusCode != 202 { + b, err := ioutil.ReadAll(resp.Body) + defer func(Body io.ReadCloser) { + _ = Body.Close() + }(resp.Body) + if err != nil { + return err + } + return getChartmuseumError(b, resp.StatusCode) + } + log.Infof("push chart to chart repo done") + return nil +} + +func getChartmuseumError(b []byte, code int) error { + var er struct { + Error string `json:"error"` + } + err := json.Unmarshal(b, &er) + if err != nil || er.Error == "" { + return errors.Errorf("%d: could not properly parse response JSON: %s", code, string(b)) + } + return errors.Errorf("%d: %s", code, er.Error) +} + +func makeChartTGZFileDir(productName, versionName string) (string, error) { + path := getChartTGZDir(productName, versionName) + if err := os.RemoveAll(path); err != nil { + if !os.IsExist(err) { + return "", errors.Wrapf(err, "failed to claer dir for chart tgz files") + } + } + err := os.MkdirAll(path, 0777) + if err != nil { + return "", errors.Wrapf(err, "failed to create chart tgz dir for version: %s", versionName) + } + return path, nil +} + +func CreateHelmDeliveryVersion(args *CreateHelmDeliveryVersionArgs, logger *zap.SugaredLogger) error { + if args.Retry { + return RetryCreateHelmDeliveryVersion(args.ProductName, args.Version, logger) + } else { + return CreateNewHelmDeliveryVersion(args, logger) + } +} + +// validate chartInfo, make sure service is in environment +// prepare data set for chart delivery +func prepareChartData(chartDatas []*CreateHelmDeliveryVersionChartData, productInfo *commonmodels.Product) (map[string]*DeliveryChartData, error) { + + renderSet, err := commonrepo.NewRenderSetColl().Find(&commonrepo.RenderSetFindOption{ + Revision: productInfo.Render.Revision, + Name: productInfo.Render.Name, + }) + if err != nil { + return nil, fmt.Errorf("failed to find renderSet: %s, revision: %d", productInfo.Render.Name, productInfo.Render.Revision) + } + chartMap := make(map[string]*template.RenderChart) + for _, rChart := range renderSet.ChartInfos { + chartMap[rChart.ServiceName] = rChart + } + + chartDataMap := make(map[string]*DeliveryChartData) + serviceMap := productInfo.GetServiceMap() + for _, chartData := range chartDatas { + if productService, ok := serviceMap[chartData.ServiceName]; ok { + serviceObj, err := commonrepo.NewServiceColl().Find(&commonrepo.ServiceFindOption{ + ServiceName: chartData.ServiceName, + Revision: productService.Revision, + Type: setting.HelmDeployType, + ProductName: productInfo.ProductName, + }) + if err != nil { + return nil, fmt.Errorf("failed to query service: %s", chartData.ServiceName) + } + renderChart, ok := chartMap[chartData.ServiceName] + if !ok { + return nil, fmt.Errorf("can't find renderChart for service: %s", chartData.ServiceName) + } + chartDataMap[chartData.ServiceName] = &DeliveryChartData{ + ChartData: chartData, + RenderChart: renderChart, + ServiceObj: serviceObj, + ProductService: productService, + RenderSet: renderSet, + } + } else { + return nil, fmt.Errorf("service %s not found in environment", chartData.ServiceName) + } + } + return chartDataMap, nil +} + +func buildRegistryMap() (map[string]*commonmodels.RegistryNamespace, error) { + registries, err := commonrepo.NewRegistryNamespaceColl().FindAll(&mongodb.FindRegOps{}) + if err != nil { + return nil, fmt.Errorf("failed to query registries") + } + ret := make(map[string]*commonmodels.RegistryNamespace) + for _, singleRegistry := range registries { + fullUrl := fmt.Sprintf("%s/%s", singleRegistry.RegAddr, singleRegistry.Namespace) + fullUrl = strings.TrimSuffix(fullUrl, "/") + u, _ := url.Parse(fullUrl) + if len(u.Scheme) > 0 { + fullUrl = strings.TrimPrefix(fullUrl, fmt.Sprintf("%s://", u.Scheme)) + } + ret[fullUrl] = singleRegistry + } + return ret, nil +} + +func buildArtifactTaskArgs(projectName, envName string, imagesMap *sync.Map) *commonmodels.ArtifactPackageTaskArgs { + imageArgs := make([]*commonmodels.ImagesByService, 0) + sourceRegistry := sets.NewString() + imagesMap.Range(func(key, value interface{}) bool { + imageDetail := value.(*ServiceImageDetails) + imagesByService := &commonmodels.ImagesByService{ + ServiceName: imageDetail.ServiceName, + Images: make([]*commonmodels.ImageData, 0), + } + for _, image := range imageDetail.Images { + imagesByService.Images = append(imagesByService.Images, &commonmodels.ImageData{ + ImageUrl: image.ImageUrl, + ImageName: image.Name, + ImageTag: image.Tag, + RegistryID: image.Registry, + }) + } + imageArgs = append(imageArgs, imagesByService) + sourceRegistry.Insert(imageDetail.Registries...) + return true + }) + + ret := &commonmodels.ArtifactPackageTaskArgs{ + ProjectName: projectName, + EnvName: envName, + Images: imageArgs, + SourceRegistries: sourceRegistry.List(), + } + return ret +} + +// insert delivery distribution data for single chart, include image and chart +func insertDeliveryDistributions(result *task.ServicePackageResult, chartVersion string, deliveryVersion *commonmodels.DeliveryVersion, args *DeliveryVersionChartData) error { + for _, image := range result.ImageData { + err := commonrepo.NewDeliveryDistributeColl().Insert(&commonmodels.DeliveryDistribute{ + ReleaseID: deliveryVersion.ID, + ServiceName: image.ImageName, // image name + ChartName: result.ServiceName, + DistributeType: config.Image, + RegistryName: image.ImageUrl, + Namespace: commonservice.ExtractRegistryNamespace(image.ImageUrl), + CreatedAt: time.Now().Unix(), + }) + if err != nil { + log.Errorf("failed to insert image distribute data, chartName: %s, err: %s", result.ServiceName, err) + return fmt.Errorf("failed to insert image distribute data, chartName: %s", result.ServiceName) + } + } + + err := commonrepo.NewDeliveryDistributeColl().Insert(&commonmodels.DeliveryDistribute{ + ReleaseID: deliveryVersion.ID, + DistributeType: config.Chart, + ChartName: result.ServiceName, + ChartVersion: chartVersion, + ChartRepoName: args.ChartRepoName, + SubDistributes: nil, + CreatedAt: time.Now().Unix(), + }) + if err != nil { + log.Errorf("failed to insert chart distribute data, chartName: %s, err: %s", result.ServiceName, err) + return fmt.Errorf("failed to insert chart distribute data, chartName: %s", result.ServiceName) + } + return nil +} + +func buildDeliveryCharts(chartDataMap map[string]*DeliveryChartData, deliveryVersion *commonmodels.DeliveryVersion, args *DeliveryVersionChartData, logger *zap.SugaredLogger) (err error) { + defer func() { + if err != nil { + deliveryVersion.Status = setting.DeliveryVersionStatusFailed + deliveryVersion.Error = err.Error() + } + err = commonrepo.NewDeliveryVersionColl().UpdateStatusByName(deliveryVersion.Version, deliveryVersion.Status, deliveryVersion.Error) + if err != nil { + logger.Errorf("failed to update delivery version data, name: %s error: %s", deliveryVersion.Version, err) + } + }() + + var errLock sync.Mutex + errorList := &multierror.Error{} + + appendError := func(err error) { + errLock.Lock() + defer errLock.Unlock() + errorList = multierror.Append(errorList, err) + } + + dir, err := makeChartTGZFileDir(deliveryVersion.ProductName, deliveryVersion.Version) + if err != nil { + return err + } + repoInfo, err := getChartRepoData(args.ChartRepoName) + if err != nil { + log.Errorf("failed to query chart-repo info, productName: %s, err: %s", deliveryVersion.ProductName, err) + return fmt.Errorf("failed to query chart-repo info, productName: %s, repoName: %s", deliveryVersion.ProductName, args.ChartRepoName) + } + + registryMap, err := buildRegistryMap() + if err != nil { + return fmt.Errorf("failed to build registry map") + } + + imagesDataMap := &sync.Map{} + + // push charts to repo + wg := sync.WaitGroup{} + for _, chartData := range chartDataMap { + wg.Add(1) + go func(cData *DeliveryChartData) { + defer wg.Done() + err := buildChartPackage(cData, repoInfo, dir, args.GlobalVariables, registryMap) + if err != nil { + logger.Errorf("failed to build chart package, serviceName: %s err: %s", cData.ChartData.ServiceName, err) + appendError(err) + return + } + imageData, err := extractImages(cData.ProductService, registryMap) + if err != nil { + logger.Errorf("failed to extract image data, serviceName: %s err: %s", cData.ChartData.ServiceName, err) + appendError(err) + return + } + imagesDataMap.Store(cData.ServiceObj.ServiceName, imageData) + }(chartData) + } + wg.Wait() + + if errorList.ErrorOrNil() != nil { + err = errorList.ErrorOrNil() + return + } + + // create task to deal with images + // offline docker images are not supported + taskArgs := buildArtifactTaskArgs(deliveryVersion.ProductName, deliveryVersion.ProductEnvInfo.EnvName, imagesDataMap) + taskArgs.TargetRegistries = []string{args.ImageRegistryID} + taskID, err := workflowservice.CreateArtifactPackageTask(taskArgs, deliveryVersion.Version, logger) + if err != nil { + return err + } + deliveryVersion.TaskID = int(taskID) + + // start a new routine to check task results + go waitVersionDone(deliveryVersion) + + return +} + +func updateVersionStatus(versionName, status, errStr string) { + err := commonrepo.NewDeliveryVersionColl().UpdateStatusByName(versionName, status, errStr) + if err != nil { + log.Errorf("failed to update version status, name: %s, err: %s", versionName, err) + } +} + +func taskFinished(status config.Status) bool { + return status == config.StatusPassed || status == config.StatusFailed || status == config.StatusTimeout || status == config.StatusCancelled +} + +func waitVersionDone(deliveryVersion *commonmodels.DeliveryVersion) { + waitTimeout := time.After(60 * time.Minute * 2) + for { + select { + case <-waitTimeout: + updateVersionStatus(deliveryVersion.Version, setting.DeliveryVersionStatusFailed, "timeout") + return + default: + done, err := checkVersionStatus(deliveryVersion) + if err != nil { + updateVersionStatus(deliveryVersion.Version, setting.DeliveryVersionStatusFailed, err.Error()) + return + } + if done { + return + } + } + time.Sleep(time.Second * 5) + } +} + +func checkVersionStatus(deliveryVersion *commonmodels.DeliveryVersion) (bool, error) { + if deliveryVersion.Status == setting.DeliveryVersionStatusSuccess || deliveryVersion.Status == setting.DeliveryVersionStatusFailed { + return true, nil + } + pipelineName := fmt.Sprintf("%s-%s-%s", deliveryVersion.ProductName, deliveryVersion.ProductEnvInfo.EnvName, "artifact") + taskData, err := commonrepo.NewTaskColl().Find(int64(deliveryVersion.TaskID), pipelineName, config.ArtifactType) + if err != nil { + return false, fmt.Errorf("failed to query taskData, id: %d, pipelineName: %s", deliveryVersion.TaskID) + } + + if len(taskData.Stages) != 1 { + return false, fmt.Errorf("invalid task data, stage length not leagal") + } + + argsBytes, err := json.Marshal(deliveryVersion.CreateArgument) + if err != nil { + return false, errors.Wrapf(err, "failed to marshal arguments, versionName: %s err: %s", deliveryVersion.Version, err) + } + createArgs := new(DeliveryVersionChartData) + err = json.Unmarshal(argsBytes, createArgs) + if err != nil { + return false, errors.Wrapf(err, "failed to unMarshal arguments, versionName: %s err: %s", deliveryVersion.Version, err) + } + + distributes, err := commonrepo.NewDeliveryDistributeColl().Find(&commonrepo.DeliveryDistributeArgs{ + DistributeType: config.Chart, + ReleaseID: deliveryVersion.ID.Hex(), + }) + if err != nil { + return false, errors.Wrapf(err, "failed to query distrubutes, versionName: %s", deliveryVersion.Version) + } + + // for charts has been successfully handled, download charts directly + successCharts := sets.NewString() + for _, distribute := range distributes { + successCharts.Insert(distribute.ChartName) + } + + stage := taskData.Stages[0] + errorList := &multierror.Error{} + + allTaskDone := true + for _, taskData := range stage.SubTasks { + artifactPackageArgs, err := base.ToArtifactPackageImageTask(taskData) + if err != nil { + return false, errors.Wrapf(err, "failed to generate origin artifact task data") + } + + progressData, err := artifactPackageArgs.GetProgress() + if err != nil { + return false, errors.Wrapf(err, "failed to get progress data from data") + } + progressDataMap := make(map[string]*task.ServicePackageResult) + for _, singleResult := range progressData { + progressDataMap[singleResult.ServiceName] = singleResult + } + + for _, chartData := range createArgs.ChartDatas { + // service artifact has been marked as success + if successCharts.Has(chartData.ServiceName) { + continue + } + if singleResult, ok := progressDataMap[chartData.ServiceName]; ok { + if singleResult.Result != "success" { + errorList = multierror.Append(errorList, fmt.Errorf("failed to build image distribute for service:%s ", singleResult.ServiceName)) + continue + } + err = insertDeliveryDistributions(singleResult, chartData.Version, deliveryVersion, createArgs) + if err != nil { + errorList = multierror.Append(errorList, fmt.Errorf("failed to insert distribute data for service:%s ", singleResult.ServiceName)) + continue + } + successCharts.Insert(chartData.ServiceName) + } + } + + if !taskFinished(artifactPackageArgs.TaskStatus) { + allTaskDone = false + } + if len(artifactPackageArgs.Error) > 0 { + errorList = multierror.Append(errorList, fmt.Errorf(artifactPackageArgs.Error)) + } + } + + if allTaskDone { + if successCharts.Len() == len(createArgs.ChartDatas) { + deliveryVersion.Status = setting.DeliveryVersionStatusSuccess + } else { + deliveryVersion.Status = setting.DeliveryVersionStatusFailed + } + } + if errorList.ErrorOrNil() != nil { + deliveryVersion.Error = errorList.Error() + } + updateVersionStatus(deliveryVersion.Version, deliveryVersion.Status, deliveryVersion.Error) + return allTaskDone, nil +} + +func CreateNewHelmDeliveryVersion(args *CreateHelmDeliveryVersionArgs, logger *zap.SugaredLogger) error { + // need appoint chart info + if len(args.ChartDatas) == 0 { + return e.ErrCreateDeliveryVersion.AddDesc("no chart info appointed") + } + + // prepare data + productInfo, err := getProductEnvInfo(args.ProductName, args.EnvName) + if err != nil { + log.Infof("failed to query product info, productName: %s envName %s, err: %s", args.ProductName, args.EnvName, err) + return e.ErrCreateDeliveryVersion.AddDesc(fmt.Sprintf("failed to query product info, procutName: %s envName %s", args.ProductName, args.EnvName)) + } + + // validate necessary params + if len(args.ChartRepoName) == 0 { + return e.ErrCreateDeliveryVersion.AddDesc("chart repo not appointed") + } + if len(args.ImageRegistryID) == 0 { + return e.ErrCreateDeliveryVersion.AddDesc("image registry not appointed") + } + + chartDataMap, err := prepareChartData(args.ChartDatas, productInfo) + if err != nil { + return e.ErrCreateDeliveryVersion.AddErr(err) + } + + productInfo.ID, _ = primitive.ObjectIDFromHex("") + + versionObj := &commonmodels.DeliveryVersion{ + Version: args.Version, + ProductName: args.ProductName, + Type: setting.DeliveryVersionTypeChart, + Desc: args.Desc, + Labels: args.Labels, + ProductEnvInfo: productInfo, + Status: setting.DeliveryVersionStatusCreating, + CreateArgument: args.DeliveryVersionChartData, + CreatedBy: args.CreateBy, + CreatedAt: time.Now().Unix(), + DeletedAt: 0, + } + + err = buildDeliveryCharts(chartDataMap, versionObj, args.DeliveryVersionChartData, logger) + if err != nil { + return err + } + + err = commonrepo.NewDeliveryVersionColl().Insert(versionObj) + if err != nil { + logger.Errorf("failed to insert version data, err: %s", err) + return e.ErrCreateDeliveryVersion.AddErr(fmt.Errorf("failed to insert delivery version: %s", versionObj.Version)) + } + + return nil +} + +func RetryCreateHelmDeliveryVersion(projectName, versionName string, logger *zap.SugaredLogger) error { + deliveryVersion, err := commonrepo.NewDeliveryVersionColl().Get(&commonrepo.DeliveryVersionArgs{ + ProductName: projectName, + Version: versionName, + }) + if err != nil { + logger.Errorf("failed to query delivery version data, verisonName: %s, error: %s", versionName, err) + return fmt.Errorf("failed to query delivery version data, verisonName: %s", versionName) + } + + if deliveryVersion.Status != setting.DeliveryVersionStatusFailed { + return fmt.Errorf("can't reCreate version with status:%s", deliveryVersion.Status) + } + + argsBytes, err := json.Marshal(deliveryVersion.CreateArgument) + if err != nil { + return errors.Wrapf(err, "failed to marshal arguments, versionName: %s err: %s", deliveryVersion.Version, err) + } + createArgs := new(DeliveryVersionChartData) + err = json.Unmarshal(argsBytes, createArgs) + if err != nil { + return errors.Wrapf(err, "failed to unMarshal arguments, versionName: %s err: %s", deliveryVersion.Version, err) + } + + productInfoSnap := deliveryVersion.ProductEnvInfo + + distributes, err := commonrepo.NewDeliveryDistributeColl().Find(&commonrepo.DeliveryDistributeArgs{ + DistributeType: config.Chart, + ReleaseID: deliveryVersion.ID.Hex(), + }) + if err != nil { + return errors.Wrapf(err, "failed to query distrubutes, versionName: %s", deliveryVersion.Version) + } + + // for charts has been successfully handled, download charts directly + successCharts := sets.NewString() + for _, distribute := range distributes { + if distribute.DistributeType != config.Chart { + continue + } + _, err := downloadChart(deliveryVersion, distribute) + if err != nil { + log.Errorf("failed to download chart from chart repo, chartName: %s, err: %s", distribute.ChartName, err) + continue + } + successCharts.Insert(distribute.ChartName) + } + + chartsToBeHandled := make([]*CreateHelmDeliveryVersionChartData, 0) + for _, chartConfig := range createArgs.ChartDatas { + if successCharts.Has(chartConfig.ServiceName) { + continue + } + chartsToBeHandled = append(chartsToBeHandled, chartConfig) + } + + chartDataMap, err := prepareChartData(chartsToBeHandled, productInfoSnap) + if err != nil { + return e.ErrCreateDeliveryVersion.AddErr(err) + } + + err = buildDeliveryCharts(chartDataMap, deliveryVersion, createArgs, logger) + if err != nil { + return err + } + + // update status + deliveryVersion.Status = setting.DeliveryVersionStatusRetrying + err = commonrepo.NewDeliveryVersionColl().UpdateStatusByName(deliveryVersion.Version, deliveryVersion.Status, "") + if err != nil { + logger.Errorf("failed to update delivery status, name: %s, err: %s", deliveryVersion.Version, err) + return fmt.Errorf("failed to update delivery status, name: %s", deliveryVersion.Version) + } + + return nil +} + +func ListDeliveryServiceNames(productName string, log *zap.SugaredLogger) ([]string, error) { + serviceNames := sets.String{} + + version := new(commonrepo.DeliveryVersionArgs) + version.ProductName = productName + deliveryVersions, err := FindDeliveryVersion(version, log) + if err != nil { + log.Errorf("FindDeliveryVersion failed, err:%v", err) + return serviceNames.List(), err + } + + for _, deliveryVersion := range deliveryVersions { + deliveryDeployArgs := new(commonrepo.DeliveryDeployArgs) + deliveryDeployArgs.ReleaseID = deliveryVersion.ID.Hex() + deliveryDeploys, err := FindDeliveryDeploy(deliveryDeployArgs, log) + if err != nil { + log.Errorf("FindDeliveryDeploy failed, ReleaseID:%s, err:%v", deliveryVersion.ID, err) + continue + } + for _, deliveryDeploy := range deliveryDeploys { + serviceNames.Insert(deliveryDeploy.ServiceName) + } + } + + return serviceNames.UnsortedList(), nil +} + +func downloadChart(deliveryVersion *commonmodels.DeliveryVersion, chartInfo *commonmodels.DeliveryDistribute) (string, error) { + productName, versionName := deliveryVersion.ProductName, deliveryVersion.Version + chartTGZName := fmt.Sprintf("%s-%s.tgz", chartInfo.ChartName, chartInfo.ChartVersion) + chartTGZFileParent := getChartTGZDir(productName, versionName) + chartTGZFilePath := filepath.Join(chartTGZFileParent, chartTGZName) + if _, err := os.Stat(chartTGZFilePath); err == nil { + // local cache exists + log.Infof("local cache exists, path %s", chartTGZFilePath) + return chartTGZFilePath, nil + } + + chartRepo, err := getChartRepoData(chartInfo.ChartRepoName) + if err != nil { + return "", fmt.Errorf("failed to query chart-repo info, repoName %s", chartInfo.ChartRepoName) + } + + client, err := createChartRepoClient(chartRepo) + if err != nil { + return "", err + } + + if err = os.MkdirAll(chartTGZFileParent, 0644); err != nil { + return "", errors.Wrapf(err, "failed to craete tgz parent dir") + } + + out, err := os.Create(chartTGZFilePath) + if err != nil { + _ = os.RemoveAll(chartTGZFilePath) + return "", errors.Wrapf(err, "failed to create chart tgz file") + } + + response, err := client.DownloadFile(fmt.Sprintf("charts/%s", chartTGZName)) + if err != nil { + return "", errors.Wrapf(err, "failed to download file") + } + + if response.StatusCode != 200 { + return "", errors.Wrapf(err, "download file failed %s", chartTGZName) + } + defer func() { _ = response.Body.Close() }() + + b, err := ioutil.ReadAll(response.Body) + if err != nil { + return "", errors.Wrapf(err, "failed to read response data") + } + + defer func(out *os.File) { + _ = out.Close() + }(out) + + err = ioutil.WriteFile(chartTGZFilePath, b, 0644) + if err != nil { + return "", err + } + return chartTGZFilePath, nil +} + +func getChartDistributeInfo(releaseID, chartName string, log *zap.SugaredLogger) (*commonmodels.DeliveryDistribute, error) { + distributes, _ := FindDeliveryDistribute(&commonrepo.DeliveryDistributeArgs{ + ReleaseID: releaseID, + ChartName: chartName, + DistributeType: config.Chart, + }, log) + + if len(distributes) != 1 { + log.Warnf("find chart %s failed, expect count %d, found count %d, release_id: %s", chartName, 1, len(distributes), releaseID) + return nil, fmt.Errorf("can't find target charts") + } + + chartInfo := distributes[0] + return chartInfo, nil +} + +func DownloadDeliveryChart(projectName, version string, chartName string, log *zap.SugaredLogger) ([]byte, string, error) { + + filePath, err := preDownloadChart(projectName, version, chartName, log) + if err != nil { + return nil, "", err + } + + fileBytes, err := os.ReadFile(filePath) + if err != nil { + return nil, "", err + } + + return fileBytes, filepath.Base(filePath), err +} + +func preDownloadChart(projectName, versionName, chartName string, log *zap.SugaredLogger) (string, error) { + deliveryInfo, err := GetDeliveryVersion(&commonrepo.DeliveryVersionArgs{ + ProductName: projectName, + Version: versionName, + }, log) + if err != nil { + return "", fmt.Errorf("failed to query delivery info") + } + + chartInfo, err := getChartDistributeInfo(deliveryInfo.ID.Hex(), chartName, log) + if err != nil { + return "", err + } + // prepare chart data + filePath, err := downloadChart(deliveryInfo, chartInfo) + if err != nil { + return "", err + } + return filePath, err +} + +func GetChartVersions(chartName, chartRepoName string) ([]*ChartVersionResp, error) { + + chartRepo, err := getChartRepoData(chartRepoName) + if err != nil { + return nil, fmt.Errorf("failed to query chart-repo info, repoName %s", chartRepoName) + } + + client, err := createChartRepoClient(chartRepo) + if err != nil { + return nil, errors.Wrapf(err, "failed to create chart repo client") + } + + resp, err := client.DownloadFile("index.yaml") + if err != nil { + return nil, errors.Wrapf(err, "failed to download index.yaml") + } + + defer func(Body io.ReadCloser) { + _ = Body.Close() + }(resp.Body) + + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + return nil, errors.Wrapf(getChartmuseumError(b, resp.StatusCode), "failed to download index.yaml") + } + + index, err := helm.LoadIndex(b) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse index.yaml") + } + + chartNameList := strings.Split(chartName, ",") + chartNameSet := sets.NewString(chartNameList...) + + ret := make([]*ChartVersionResp, 0) + + for name, entry := range index.Entries { + if !chartNameSet.Has(name) { + continue + } + if len(entry) == 0 { + continue + } + latestEntry := entry[0] + ret = append(ret, &ChartVersionResp{ + ChartName: name, + ChartVersion: latestEntry.Version, + }) + } + + return ret, nil +} + +func preDownloadAndUncompressChart(projectName, versionName, chartName string, log *zap.SugaredLogger) (string, error) { + + deliveryInfo, err := GetDeliveryVersion(&commonrepo.DeliveryVersionArgs{ + ProductName: projectName, + Version: versionName, + }, log) + if err != nil { + return "", fmt.Errorf("failed to query delivery info") + } + + chartDistribute, err := getChartDistributeInfo(deliveryInfo.ID.Hex(), chartName, log) + if err != nil { + return "", err + } + dstDir := getChartExpandDir(projectName, versionName) + dstDir = filepath.Join(dstDir, fmt.Sprintf("%s-%s", chartDistribute.ChartName, chartDistribute.ChartVersion)) + + filePath, err := preDownloadChart(projectName, versionName, chartName, log) + if err != nil { + return "", err + } + + file, err := os.Open(filePath) + if err != nil { + return "", errors.Wrap(err, "unable to open tarball") + } + defer func() { _ = file.Close() }() + + err = chartutil.Expand(dstDir, file) + if err != nil { + log.Errorf("failed to uncompress file: %s", filePath) + return "", errors.Wrapf(err, "failed to uncompress file") + } + return dstDir, nil +} + +func PreviewDeliveryChart(projectName, version, chartName string, log *zap.SugaredLogger) (*DeliveryChartResp, error) { + + dstDir, err := preDownloadAndUncompressChart(projectName, version, chartName, log) + if err != nil { + return nil, err + } + + ret := &DeliveryChartResp{ + FileInfos: make([]*types.FileInfo, 0), + } + + var fis []*types.FileInfo + files, err := os.ReadDir(filepath.Join(dstDir, chartName)) + if err != nil { + return nil, err + } + + for _, file := range files { + info, _ := file.Info() + if info == nil { + continue + } + fi := &types.FileInfo{ + Parent: "", + Name: file.Name(), + Size: info.Size(), + Mode: file.Type(), + ModTime: info.ModTime().Unix(), + IsDir: file.IsDir(), + } + + fis = append(fis, fi) + } + ret.FileInfos = fis + return ret, nil +} + +// load chart file infos +func loadChartFileInfos(fileDir, chartName string, dir string) ([]*types.FileInfo, error) { + var fis []*types.FileInfo + files, err := os.ReadDir(filepath.Join(fileDir, chartName, dir)) + if err != nil { + return nil, e.ErrFilePath.AddDesc(err.Error()) + } + + for _, file := range files { + info, _ := file.Info() + if info == nil { + continue + } + fi := &types.FileInfo{ + Parent: dir, + Name: file.Name(), + Size: info.Size(), + Mode: file.Type(), + ModTime: info.ModTime().Unix(), + IsDir: file.IsDir(), + } + fis = append(fis, fi) + } + return fis, nil +} + +func GetDeliveryChartFilePath(args *DeliveryChartFilePathArgs, log *zap.SugaredLogger) ([]*types.FileInfo, error) { + projectName, version, chartName := args.ProjectName, args.Version, args.ChartName + dstDir, err := preDownloadAndUncompressChart(projectName, version, chartName, log) + if err != nil { + return nil, nil + } + + fileInfos, err := loadChartFileInfos(dstDir, chartName, args.Dir) + if err != nil { + return nil, err + } + return fileInfos, nil +} + +func GetDeliveryChartFileContent(args *DeliveryChartFileContentArgs, log *zap.SugaredLogger) (string, error) { + projectName, version, chartName := args.ProjectName, args.Version, args.ChartName + dstDir, err := preDownloadAndUncompressChart(projectName, version, chartName, log) + if err != nil { + return "", nil + } + + file := filepath.Join(dstDir, chartName, args.FilePath, args.FileName) + fileContent, err := os.ReadFile(file) + if err != nil { + log.Errorf("Failed to read file %s, err: %s", file, err) + return "", e.ErrFileContent.AddDesc(err.Error()) + } + + return string(fileContent), nil +} + +func ApplyDeliveryGlobalVariables(args *DeliveryVariablesApplyArgs, logger *zap.SugaredLogger) (interface{}, error) { + ret := new(DeliveryVariablesApplyArgs) + for _, chartData := range args.ChartDatas { + mergedYaml, err := yamlutil.Merge([][]byte{[]byte(chartData.ValuesYamlContent), []byte(args.GlobalVariables)}) + if err != nil { + logger.Errorf("failed to merge gobal variables for service: %s", chartData.ServiceName) + return nil, errors.Wrapf(err, "failed to merge global variables for service: %s", chartData.ServiceName) + } + ret.ChartDatas = append(ret.ChartDatas, &CreateHelmDeliveryVersionChartData{ + ServiceName: chartData.ServiceName, + ValuesYamlContent: string(mergedYaml), + }) + } + return ret, nil } diff --git a/pkg/microservice/aslan/core/environment/handler/helm.go b/pkg/microservice/aslan/core/environment/handler/helm.go new file mode 100644 index 000000000..9e097cd91 --- /dev/null +++ b/pkg/microservice/aslan/core/environment/handler/helm.go @@ -0,0 +1,40 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package handler + +import ( + "github.com/gin-gonic/gin" + "github.com/koderover/zadig/pkg/microservice/aslan/core/environment/service" + internalhandler "github.com/koderover/zadig/pkg/shared/handler" +) + +func ListReleases(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + envName := c.Param("name") + projectName := c.Query("projectName") + ctx.Resp, ctx.Err = service.ListReleases(projectName, envName, ctx.Logger) +} + +func GetChartInfos(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + envName := c.Param("name") + servicesName := c.Query("serviceName") + projectName := c.Query("projectName") + ctx.Resp, ctx.Err = service.GetChartInfos(projectName, envName, servicesName, ctx.Logger) +} diff --git a/pkg/microservice/aslan/core/environment/handler/router.go b/pkg/microservice/aslan/core/environment/handler/router.go index 18901f285..1d598a141 100644 --- a/pkg/microservice/aslan/core/environment/handler/router.go +++ b/pkg/microservice/aslan/core/environment/handler/router.go @@ -109,6 +109,9 @@ func (*Router) Inject(router *gin.RouterGroup) { environments.GET("/:name/groups", ListGroups) environments.GET("/:name/workloads", ListWorkloadsInEnv) + environments.GET("/:name/helm/releases", ListReleases) + environments.GET("/:name/helm/charts", GetChartInfos) + environments.GET("/:name/services/:serviceName", GetService) environments.PUT("/:name/services/:serviceName", gin2.UpdateOperationLogStatus, UpdateService) environments.POST("/:name/services/:serviceName/restart", gin2.UpdateOperationLogStatus, RestartService) diff --git a/pkg/microservice/aslan/core/environment/service/helm.go b/pkg/microservice/aslan/core/environment/service/helm.go new file mode 100644 index 000000000..255a2ba7d --- /dev/null +++ b/pkg/microservice/aslan/core/environment/service/helm.go @@ -0,0 +1,259 @@ +/* +Copyright 2021 The KodeRover Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package service + +import ( + "fmt" + "os" + "path/filepath" + "strings" + "sync" + + "github.com/hashicorp/go-multierror" + "github.com/otiai10/copy" + "go.uber.org/zap" + + "github.com/koderover/zadig/pkg/microservice/aslan/config" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models/template" + commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" + commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/kube" + "github.com/koderover/zadig/pkg/setting" + e "github.com/koderover/zadig/pkg/tool/errors" + helmtool "github.com/koderover/zadig/pkg/tool/helmclient" + "github.com/koderover/zadig/pkg/tool/log" + "github.com/koderover/zadig/pkg/types" + "github.com/koderover/zadig/pkg/util" +) + +type HelmReleaseResp struct { + ReleaseName string `json:"releaseName"` + ServiceName string `json:"serviceName"` + Revision int `json:"revision"` + Chart string `json:"chart"` + AppVersion string `json:"appVersion"` +} + +type ChartInfo struct { + ServiceName string `json:"serviceName"` + Revision int64 `json:"revision"` +} + +type HelmChartsResp struct { + ChartInfos []*ChartInfo `json:"chartInfos"` + FileInfos []*types.FileInfo `json:"fileInfos"` +} + +func ListReleases(productName, envName string, log *zap.SugaredLogger) ([]*HelmReleaseResp, error) { + opt := &commonrepo.ProductFindOptions{Name: productName, EnvName: envName} + prod, err := commonrepo.NewProductColl().Find(opt) + if err != nil { + return nil, e.ErrCreateDeliveryVersion.AddDesc(err.Error()) + } + + restConfig, err := kube.GetRESTConfig(prod.ClusterID) + if err != nil { + log.Errorf("GetRESTConfig error: %v", err) + return nil, e.ErrCreateDeliveryVersion.AddDesc(err.Error()) + } + helmClient, err := helmtool.NewClientFromRestConf(restConfig, prod.Namespace) + if err != nil { + log.Errorf("[%s][%s] NewClientFromRestConf error: %v", envName, productName, err) + return nil, e.ErrCreateDeliveryVersion.AddErr(err) + } + + releases, err := helmClient.ListDeployedReleases() + if err != nil { + return nil, e.ErrCreateDeliveryVersion.AddErr(err) + } + + ret := make([]*HelmReleaseResp, 0, len(releases)) + for _, release := range releases { + ret = append(ret, &HelmReleaseResp{ + ReleaseName: release.Name, + ServiceName: util.ExtraServiceName(release.Name, prod.Namespace), + Revision: release.Version, + Chart: release.Chart.Name(), + AppVersion: release.Chart.AppVersion(), + }) + } + return ret, nil +} + +func loadChartFilesInfo(productName, serviceName string, revision int64, dir string) ([]*types.FileInfo, error) { + base := config.LocalServicePathWithRevision(productName, serviceName, revision) + + var fis []*types.FileInfo + files, err := os.ReadDir(filepath.Join(base, serviceName, dir)) + if err != nil { + log.Warnf("failed to read chart info for service %s with revision %d", serviceName, revision) + base = config.LocalServicePath(productName, serviceName) + files, err = os.ReadDir(filepath.Join(base, serviceName, dir)) + if err != nil { + return nil, err + } + } + + for _, file := range files { + info, _ := file.Info() + if info == nil { + continue + } + fi := &types.FileInfo{ + Parent: dir, + Name: file.Name(), + Size: info.Size(), + Mode: file.Type(), + ModTime: info.ModTime().Unix(), + IsDir: file.IsDir(), + } + + fis = append(fis, fi) + } + return fis, nil +} + +//prepare chart version data +func prepareChartVersionData(productName string, serviceObj *models.Service, renderChart *template.RenderChart, renderset *models.RenderSet) error { + serviceName, revision := serviceObj.ServiceName, serviceObj.Revision + base := config.LocalServicePathWithRevision(productName, serviceName, revision) + if err := commonservice.PreloadServiceManifestsByRevision(base, serviceObj); err != nil { + log.Warnf("failed to get chart of revision: %d for service: %s, use latest version", revision, serviceName) + // use the latest version when it fails to download the specific version + base = config.LocalServicePath(productName, serviceName) + if err = commonservice.PreLoadServiceManifests(base, serviceObj); err != nil { + log.Errorf("failed to load chart info for service %v", serviceObj.ServiceName) + return err + } + } + + fullPath := filepath.Join(base, serviceObj.ServiceName) + deliveryChartPath := filepath.Join(config.LocalDeliveryChartPathWithRevision(productName, serviceObj.ServiceName, serviceObj.Revision), serviceObj.ServiceName) + err := copy.Copy(fullPath, deliveryChartPath) + if err != nil { + return err + } + + mergedValuesYaml, err := helmtool.MergeOverrideValues(renderChart.ValuesYaml, renderset.DefaultValues, renderChart.GetOverrideYaml(), renderChart.OverrideValues) + if err != nil { + return err + } + + // write values.yaml + if err = os.WriteFile(filepath.Join(deliveryChartPath, setting.ValuesYaml), []byte(mergedValuesYaml), 0644); err != nil { + return err + } + + return nil +} + +func GetChartInfos(productName, envName, serviceName string, log *zap.SugaredLogger) (*HelmChartsResp, error) { + opt := &commonrepo.ProductFindOptions{Name: productName, EnvName: envName} + prod, err := commonrepo.NewProductColl().Find(opt) + if err != nil { + return nil, e.ErrGetHelmCharts.AddErr(err) + } + renderSet, err := FindHelmRenderSet(productName, prod.Render.Name, log) + if err != nil { + log.Errorf("[%s][P:%s] find product renderset error: %v", envName, productName, err) + return nil, e.ErrGetHelmCharts.AddErr(err) + } + + chartMap := make(map[string]*template.RenderChart) + for _, chart := range renderSet.ChartInfos { + chartMap[chart.ServiceName] = chart + } + + allServiceMap := prod.GetServiceMap() + serviceMap := make(map[string]*models.ProductService) + + //validate data, make sure service and chart info exists + if len(serviceName) > 0 { + serviceList := strings.Split(serviceName, ",") + for _, singleService := range serviceList { + if service, ok := allServiceMap[singleService]; ok { + serviceMap[service.ServiceName] = service + } else { + return nil, e.ErrGetHelmCharts.AddDesc(fmt.Sprintf("failed to find service %s in target namespace", singleService)) + } + } + } else { + serviceMap = allServiceMap + } + + if len(serviceMap) == 0 { + return nil, nil + } + + ret := &HelmChartsResp{ + ChartInfos: make([]*ChartInfo, 0), + FileInfos: make([]*types.FileInfo, 0), + } + + errList := new(multierror.Error) + wg := sync.WaitGroup{} + + for _, service := range serviceMap { + ret.ChartInfos = append(ret.ChartInfos, &ChartInfo{ + ServiceName: service.ServiceName, + Revision: service.Revision, + }) + wg.Add(1) + // download chart info with particular version + go func(serviceName string, revision int64) { + defer wg.Done() + serviceObj, err := commonrepo.NewServiceColl().Find(&commonrepo.ServiceFindOption{ + ProductName: productName, + ServiceName: serviceName, + Revision: revision, + Type: setting.HelmDeployType, + }) + if err != nil { + log.Errorf("failed to query services name: %s, revision: %d, error: %s", serviceName, revision, err) + errList = multierror.Append(errList, fmt.Errorf("failed to query service, serviceName: %s, revision: %d", serviceName, revision)) + return + } + renderChart, ok := chartMap[serviceName] + if !ok { + errList = multierror.Append(errList, fmt.Errorf("failed to find render chart for service %s in target namespace", serviceName)) + return + } + err = prepareChartVersionData(productName, serviceObj, renderChart, renderSet) + if err != nil { + errList = multierror.Append(errList, fmt.Errorf("failed to prepare chart info for service %s", serviceObj.ServiceName)) + return + } + }(service.ServiceName, service.Revision) + } + wg.Wait() + + if errList.ErrorOrNil() != nil { + return nil, errList.ErrorOrNil() + } + + // expand file info for first service + serviceToExpand := ret.ChartInfos[0].ServiceName + fis, err := loadChartFilesInfo(productName, serviceToExpand, serviceMap[serviceToExpand].Revision, "") + if err != nil { + log.Errorf("Failed to load service file info, err: %s", err) + return nil, e.ErrListTemplate.AddErr(err) + } + ret.FileInfos = fis + + return ret, nil +} diff --git a/pkg/microservice/aslan/core/project/service/project.go b/pkg/microservice/aslan/core/project/service/project.go index 4c9e1fb92..196d63db0 100644 --- a/pkg/microservice/aslan/core/project/service/project.go +++ b/pkg/microservice/aslan/core/project/service/project.go @@ -41,12 +41,13 @@ type ProjectListOptions struct { type ProjectDetailedRepresentation struct { *ProjectBriefRepresentation - Alias string `json:"alias"` - Desc string `json:"desc"` - UpdatedAt int64 `json:"updatedAt"` - UpdatedBy string `json:"updatedBy"` - Onboard bool `json:"onboard"` - Public bool `json:"public"` + Alias string `json:"alias"` + Desc string `json:"desc"` + UpdatedAt int64 `json:"updatedAt"` + UpdatedBy string `json:"updatedBy"` + Onboard bool `json:"onboard"` + Public bool `json:"public"` + DeployType string `json:"deployType"` } type ProjectBriefRepresentation struct { @@ -98,12 +99,13 @@ func listDetailedProjectInfos(opts *ProjectListOptions, logger *zap.SugaredLogge ProjectMinimalRepresentation: &ProjectMinimalRepresentation{Name: name}, Envs: nameWithEnvMap[name], }, - Alias: info.Alias, - Desc: info.Desc, - UpdatedAt: info.UpdatedAt, - UpdatedBy: info.UpdatedBy, - Onboard: info.OnboardStatus != 0, - Public: info.Public, + Alias: info.Alias, + Desc: info.Desc, + UpdatedAt: info.UpdatedAt, + UpdatedBy: info.UpdatedBy, + Onboard: info.OnboardStatus != 0, + Public: info.Public, + DeployType: info.DeployType, }) } diff --git a/pkg/microservice/aslan/core/service/handler/helm.go b/pkg/microservice/aslan/core/service/handler/helm.go index 0573b0989..d1462e369 100644 --- a/pkg/microservice/aslan/core/service/handler/helm.go +++ b/pkg/microservice/aslan/core/service/handler/helm.go @@ -46,13 +46,30 @@ func GetHelmServiceModule(c *gin.Context) { func GetFilePath(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Resp, ctx.Err = svcservice.GetFilePath(c.Param("serviceName"), c.Param("productName"), c.Query("dir"), ctx.Logger) + revision := int64(0) + var err error + if len(c.Query("revision")) > 0 { + revision, err = strconv.ParseInt(c.Query("revision"), 10, 64) + } + if err != nil { + ctx.Err = e.ErrInvalidParam.AddDesc("invalid revision number") + return + } + ctx.Resp, ctx.Err = svcservice.GetFilePath(c.Param("serviceName"), c.Param("productName"), revision, c.Query("dir"), ctx.Logger) } func GetFileContent(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - ctx.Resp, ctx.Err = svcservice.GetFileContent(c.Param("serviceName"), c.Param("productName"), c.Query("filePath"), c.Query("fileName"), ctx.Logger) + + param := new(svcservice.GetFileContentParam) + err := c.ShouldBindQuery(param) + if err != nil { + ctx.Err = e.ErrInvalidParam.AddErr(err) + return + } + + ctx.Resp, ctx.Err = svcservice.GetFileContent(c.Param("serviceName"), c.Param("productName"), param, ctx.Logger) } func CreateOrUpdateHelmService(c *gin.Context) { diff --git a/pkg/microservice/aslan/core/service/service/helm.go b/pkg/microservice/aslan/core/service/service/helm.go index 562b38523..a9d2dec2c 100644 --- a/pkg/microservice/aslan/core/service/service/helm.go +++ b/pkg/microservice/aslan/core/service/service/helm.go @@ -113,6 +113,13 @@ type ChartTemplateData struct { DefaultValuesYAML []byte // content of values.yaml in template } +type GetFileContentParam struct { + FilePath string `json:"filePath" form:"filePath"` + FileName string `json:"fileName" form:"fileName"` + Revision int64 `json:"revision" form:"revision"` + DeliveryVersion bool `json:"deliveryVersion" form:"deliveryVersion"` +} + func ListHelmServices(productName string, log *zap.SugaredLogger) (*HelmService, error) { helmService := &HelmService{ ServiceInfos: []*models.Service{}, @@ -133,7 +140,7 @@ func ListHelmServices(productName string, log *zap.SugaredLogger) (*HelmService, helmService.ServiceInfos = services if len(services) > 0 { - fis, err := loadServiceFileInfos(services[0].ProductName, services[0].ServiceName, "") + fis, err := loadServiceFileInfos(services[0].ProductName, services[0].ServiceName, 0, "") if err != nil { log.Errorf("Failed to load service file info, err: %s", err) return nil, e.ErrListTemplate.AddErr(err) @@ -172,24 +179,39 @@ func GetHelmServiceModule(serviceName, productName string, revision int64, log * return helmServiceModule, err } -func GetFilePath(serviceName, productName, dir string, _ *zap.SugaredLogger) ([]*types.FileInfo, error) { - return loadServiceFileInfos(productName, serviceName, dir) +func GetFilePath(serviceName, productName string, revision int64, dir string, _ *zap.SugaredLogger) ([]*types.FileInfo, error) { + return loadServiceFileInfos(productName, serviceName, revision, dir) } -func GetFileContent(serviceName, productName, filePath, fileName string, log *zap.SugaredLogger) (string, error) { - base := config.LocalServicePath(productName, serviceName) - +func GetFileContent(serviceName, productName string, param *GetFileContentParam, log *zap.SugaredLogger) (string, error) { + filePath, fileName, revision, forDelivery := param.FilePath, param.FileName, param.Revision, param.DeliveryVersion svc, err := commonrepo.NewServiceColl().Find(&commonrepo.ServiceFindOption{ ProductName: productName, ServiceName: serviceName, + Revision: revision, }) if err != nil { return "", e.ErrFileContent.AddDesc(err.Error()) } - err = commonservice.PreLoadServiceManifests(base, svc) - if err != nil { - return "", e.ErrFileContent.AddDesc(err.Error()) + base := config.LocalServicePath(productName, serviceName) + if revision > 0 { + base = config.LocalServicePathWithRevision(productName, serviceName, revision) + if err = commonservice.PreloadServiceManifestsByRevision(base, svc); err != nil { + log.Warnf("failed to get chart of revision: %d for service: %s, use latest version", + svc.Revision, svc.ServiceName) + } + } + if err != nil || revision == 0 { + base = config.LocalServicePath(productName, serviceName) + err = commonservice.PreLoadServiceManifests(base, svc) + if err != nil { + return "", e.ErrFileContent.AddDesc(err.Error()) + } + } + + if forDelivery { + base = config.LocalDeliveryChartPathWithRevision(productName, serviceName, revision) } file := filepath.Join(base, serviceName, filePath, fileName) @@ -912,9 +934,7 @@ func createOrUpdateHelmService(fsTree fs.FS, args *helmServiceCreationArgs, logg return serviceObj, nil } -func loadServiceFileInfos(productName, serviceName, dir string) ([]*types.FileInfo, error) { - base := config.LocalServicePath(productName, serviceName) - +func loadServiceFileInfos(productName, serviceName string, revision int64, dir string) ([]*types.FileInfo, error) { svc, err := commonrepo.NewServiceColl().Find(&commonrepo.ServiceFindOption{ ProductName: productName, ServiceName: serviceName, @@ -923,6 +943,22 @@ func loadServiceFileInfos(productName, serviceName, dir string) ([]*types.FileIn return nil, e.ErrFilePath.AddDesc(err.Error()) } + base := config.LocalServicePath(productName, serviceName) + if revision > 0 { + base = config.LocalServicePathWithRevision(productName, serviceName, revision) + if err = commonservice.PreloadServiceManifestsByRevision(base, svc); err != nil { + log.Warnf("failed to get chart of revision: %d for service: %s, use latest version", + svc.Revision, svc.ServiceName) + } + } + if err != nil || revision == 0 { + base = config.LocalServicePath(productName, serviceName) + err = commonservice.PreLoadServiceManifests(base, svc) + if err != nil { + return nil, e.ErrFilePath.AddDesc(err.Error()) + } + } + err = commonservice.PreLoadServiceManifests(base, svc) if err != nil { return nil, e.ErrFilePath.AddDesc(err.Error()) diff --git a/pkg/microservice/aslan/core/system/handler/helm.go b/pkg/microservice/aslan/core/system/handler/helm.go index 31a84a53d..7f92809e6 100644 --- a/pkg/microservice/aslan/core/system/handler/helm.go +++ b/pkg/microservice/aslan/core/system/handler/helm.go @@ -49,6 +49,7 @@ func CreateHelmRepo(c *gin.Context) { ctx.Err = e.ErrInvalidParam.AddDesc("invalid url") return } + ctx.Err = service.CreateHelmRepo(args, ctx.Logger) } diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go index 00ca9b6c0..decf797e9 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/artifact_task.go @@ -35,15 +35,15 @@ import ( "github.com/koderover/zadig/pkg/util" ) -func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, log *zap.SugaredLogger) error { +// get global config payload +func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, taskCreator string, log *zap.SugaredLogger) (int64, error) { - // 获取全局configpayload configPayload := commonservice.GetConfigPayload(0) repos, err := commonrepo.NewRegistryNamespaceColl().FindAll(&commonrepo.FindRegOps{}) if err != nil { log.Errorf("CreateArtifactPackageTask query registries failed, err: %s", err) - return fmt.Errorf("failed to query registries") + return 0, fmt.Errorf("failed to query registries") } registriesInvolved := sets.NewString() @@ -68,13 +68,13 @@ func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, log * defaultS3, err := s3.FindDefaultS3() if err != nil { err = e.ErrFindDefaultS3Storage.AddDesc("default storage is required by distribute task") - return err + return 0, err } defaultURL, err := defaultS3.GetEncryptedURL() if err != nil { err = e.ErrS3Storage.AddErr(err) - return err + return 0, err } task := &task.Task{ @@ -82,6 +82,7 @@ func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, log * ProductName: args.ProjectName, Status: config.StatusCreated, ArtifactPackageTaskArgs: args, + TaskCreator: taskCreator, ConfigPayload: configPayload, StorageURI: defaultURL, } @@ -100,14 +101,14 @@ func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, log * }).ToSubTask() if err != nil { - return err + return 0, err } task.SubTasks = []map[string]interface{}{subTask} if err := ensurePipelineTask(task, "", log); err != nil { log.Errorf("CreateServiceTask ensurePipelineTask err : %v", err) - return err + return 0, err } stages := make([]*commonmodels.Stage, 0) @@ -117,14 +118,14 @@ func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, log * sort.Sort(ByStageKind(stages)) task.Stages = stages if len(task.Stages) == 0 { - return e.ErrCreateTask.AddDesc(e.PipelineSubTaskNotFoundErrMsg) + return 0, e.ErrCreateTask.AddDesc(e.PipelineSubTaskNotFoundErrMsg) } pipelineName := fmt.Sprintf("%s-%s-%s", args.ProjectName, args.EnvName, "artifact") nextTaskID, err := commonrepo.NewCounterColl().GetNextSeq(fmt.Sprintf(setting.ServiceTaskFmt, pipelineName)) if err != nil { log.Errorf("CreateServiceTask Counter.GetNextSeq error: %v", err) - return e.ErrGetCounter.AddDesc(err.Error()) + return 0, e.ErrGetCounter.AddDesc(err.Error()) } task.SubTasks = []map[string]interface{}{} @@ -133,8 +134,8 @@ func CreateArtifactPackageTask(args *commonmodels.ArtifactPackageTaskArgs, log * if err := CreateTask(task); err != nil { log.Error(err) - return e.ErrCreateTask + return 0, e.ErrCreateTask } - return nil + return nextTaskID, nil } diff --git a/pkg/microservice/packager/core/service/packager.go b/pkg/microservice/packager/core/service/packager.go index d58b587bc..8f9e41da9 100644 --- a/pkg/microservice/packager/core/service/packager.go +++ b/pkg/microservice/packager/core/service/packager.go @@ -17,10 +17,10 @@ limitations under the License. package service type ImageData struct { - ImageUrl string `yaml:"image_url"` - ImageName string `yaml:"image_name"` - ImageTag string `yaml:"image_tag"` - RegistryID string `yaml:"registry_id,omitempty"` + ImageUrl string `yaml:"image_url" json:"image_url"` + ImageName string `yaml:"image_name" json:"image_name"` + ImageTag string `yaml:"image_tag" json:"image_tag"` + RegistryID string `yaml:"registry_id" json:"registry_id"` } // ImagesByService defines all images in a service diff --git a/pkg/microservice/packager/core/service/service.go b/pkg/microservice/packager/core/service/service.go index 339ab5de9..ba4e036e5 100644 --- a/pkg/microservice/packager/core/service/service.go +++ b/pkg/microservice/packager/core/service/service.go @@ -22,6 +22,7 @@ import ( "encoding/base64" "encoding/json" "fmt" + "io" "os" "path/filepath" "strings" @@ -93,15 +94,68 @@ func buildTargetImage(imageName, imageTag, host, nameSpace string) string { return ret } -func handleSingleService(imageByService *ImagesByService, allRegistries map[string]*DockerRegistry, targetRegistries []*DockerRegistry, dockerClient *client.Client) error { +func pullImage(dockerClient *client.Client, imageUrl string, options *types.ImagePullOptions) error { + // pull image + pullResponse, err := dockerClient.ImagePull(context.TODO(), imageUrl, *options) + if err != nil { + return err + } + + defer func(pullResponse io.ReadCloser) { + err := pullResponse.Close() + if err != nil { + log.Errorf("failed to close response reader") + } + }(pullResponse) + + bs, err := io.ReadAll(pullResponse) + if err != nil { + return err + } + + if strings.Contains(string(bs), "error") { + log.Errorf("image push failed: %s", string(bs)) + return fmt.Errorf("failed to push image") + } + return nil +} + +func pushImage(dockerClient *client.Client, targetImageUrl string, options *types.ImagePushOptions) error { + pushResponse, err := dockerClient.ImagePush(context.TODO(), targetImageUrl, *options) + if err != nil { + return errors.Wrapf(err, "failed to push image: %s", targetImageUrl) + } + + defer func(pullResponse io.ReadCloser) { + err := pullResponse.Close() + if err != nil { + log.Errorf("failed to close response reader") + } + }(pushResponse) + + bs, err := io.ReadAll(pushResponse) + if err != nil { + return err + } + + if strings.Contains(string(bs), "error") { + log.Errorf("image push failed: %s", string(bs)) + return fmt.Errorf("failed to push image") + } + return nil +} + +func handleSingleService(imageByService *ImagesByService, allRegistries map[string]*DockerRegistry, targetRegistries []*DockerRegistry, dockerClient *client.Client) ([]*ImageData, error) { targetImageUrlByRepo := make(map[string][]string) + retImages := make([]*ImageData, 0) + for _, singleImage := range imageByService.Images { options := types.ImagePullOptions{} // for images from public repo,registryID won't be appointed if len(singleImage.RegistryID) > 0 { registryInfo, ok := allRegistries[singleImage.RegistryID] if !ok { - return fmt.Errorf("failed to find source registry for image: %s", singleImage.ImageUrl) + return nil, fmt.Errorf("failed to find source registry for image: %s", singleImage.ImageUrl) } encodedAuth, err := base64EncodeAuth(&types.AuthConfig{ Username: registryInfo.UserName, @@ -109,15 +163,15 @@ func handleSingleService(imageByService *ImagesByService, allRegistries map[stri ServerAddress: registryInfo.Host, }) if err != nil { - return errors.Wrapf(err, "faied to create docker pull auth data") + return nil, errors.Wrapf(err, "faied to create docker pull auth data") } options.RegistryAuth = encodedAuth } // pull image - _, err := dockerClient.ImagePull(context.TODO(), singleImage.ImageUrl, options) + err := pullImage(dockerClient, singleImage.ImageUrl, &options) if err != nil { - return errors.Wrapf(err, "failed to pull image: %s", singleImage.ImageUrl) + return nil, errors.Wrapf(err, "failed to pull image: %s", singleImage.ImageUrl) } // tag image @@ -125,9 +179,15 @@ func handleSingleService(imageByService *ImagesByService, allRegistries map[stri targetImage := buildTargetImage(singleImage.ImageName, singleImage.ImageTag, registry.Host, registry.Namespace) err = dockerClient.ImageTag(context.TODO(), singleImage.ImageUrl, targetImage) if err != nil { - return errors.Wrapf(err, "failed to tag image from: %s to: %s", singleImage.ImageUrl, targetImage) + return nil, errors.Wrapf(err, "failed to tag image from: %s to: %s", singleImage.ImageUrl, targetImage) } targetImageUrlByRepo[registry.RegistryID] = append(targetImageUrlByRepo[registry.RegistryID], targetImage) + retImages = append(retImages, &ImageData{ + ImageUrl: targetImage, + ImageName: singleImage.ImageName, + ImageTag: singleImage.ImageTag, + RegistryID: singleImage.RegistryID, + }) } } @@ -139,19 +199,20 @@ func handleSingleService(imageByService *ImagesByService, allRegistries map[stri ServerAddress: registry.Host, }) if err != nil { - return errors.Wrapf(err, "faied to create docker push auth data") + return nil, errors.Wrapf(err, "faied to create docker push auth data") } options := types.ImagePushOptions{ RegistryAuth: encodedAuth, } + for _, targetImageUrl := range targetImageUrlByRepo[registry.RegistryID] { - _, err = dockerClient.ImagePush(context.TODO(), targetImageUrl, options) + err = pushImage(dockerClient, targetImageUrl, &options) if err != nil { - return errors.Wrapf(err, "failed to push image: %s", targetImageUrl) + return nil, errors.Wrapf(err, "failed to push image: %s", targetImageUrl) } } } - return nil + return retImages, nil } func (p *Packager) Exec() error { @@ -201,7 +262,7 @@ func (p *Packager) Exec() error { result := &PackageResult{ ServiceName: imageByService.ServiceName, } - err = handleSingleService(imageByService, buildRegistryMap(allRegistries), p.Ctx.TargetRegistries, cli) + images, err := handleSingleService(imageByService, buildRegistryMap(allRegistries), p.Ctx.TargetRegistries, cli) if err != nil { result.Result = "failed" @@ -209,7 +270,7 @@ func (p *Packager) Exec() error { log.Errorf("[result][fail][%s][%s]", imageByService.ServiceName, err) } else { result.Result = "success" - result.ImageData = imageByService.Images + result.ImageData = images log.Infof("[result][success][%s]", imageByService.ServiceName) } diff --git a/pkg/microservice/warpdrive/core/service/types/task/artifact_package.go b/pkg/microservice/warpdrive/core/service/types/task/artifact_package.go index 9ac39d95a..5ebe24fb0 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/artifact_package.go +++ b/pkg/microservice/warpdrive/core/service/types/task/artifact_package.go @@ -26,7 +26,7 @@ type ArtifactPackage struct { TaskType config.TaskType `bson:"type" json:"type"` Enabled bool `bson:"enabled" json:"enabled"` TaskStatus config.Status `bson:"status" json:"status"` - Progress string `bson:"progress" json:"progress"` + Progress string `bson:"progress" json:"progress"` Timeout int `bson:"timeout,omitempty" json:"timeout,omitempty"` Error string `bson:"error,omitempty" json:"error,omitempty"` StartTime int64 `bson:"start_time,omitempty" json:"start_time,omitempty"` diff --git a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go index 97e9f7dc9..82ee8535d 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go +++ b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go @@ -136,7 +136,7 @@ type ReleaseConfig struct { // e.g. xxx.com/resources/predator-plugin:v0.1.0 PredatorImage string // PackagerImage sets docker build image - // e.g. xxx.com/resources/predator-plugin:v0.1.0 + // e.g. xxx.com/resources/packager-plugin:v0.1.0 PackagerImage string } diff --git a/pkg/setting/consts.go b/pkg/setting/consts.go index df2c1159d..250cc4b4b 100644 --- a/pkg/setting/consts.go +++ b/pkg/setting/consts.go @@ -272,6 +272,16 @@ const ( FunctionTestType = "function" ) +const ( + DeliveryVersionTypeChart = "HelmChart" + DeliveryVersionTypeK8SWorkflow = "K8SWorkflow" +) + +const ( + DeliveryDeployTypeImage = "image" + DeliveryDeployTypeChart = "chart" +) + const ( AuthorizationHeader = "Authorization" ) @@ -327,6 +337,21 @@ const ( ProductStatusUnstable = "Unstable" ) +// DeliveryVersion status +const ( + DeliveryVersionStatusSuccess = "success" + DeliveryVersionStatusFailed = "failed" + DeliveryVersionStatusCreating = "creating" + DeliveryVersionStatusRetrying = "retrying" +) + +const ( + DeliveryVersionPackageStatusSuccess = "success" + DeliveryVersionPackageStatusFailed = "failed" + DeliveryVersionPackageStatusWaiting = "waiting" + DeliveryVersionPackageStatusUploading = "uploading" +) + const ( NormalModeProduct = "normal" ) diff --git a/pkg/tool/errors/http_errors.go b/pkg/tool/errors/http_errors.go index 45554ea76..e0ffc2eed 100644 --- a/pkg/tool/errors/http_errors.go +++ b/pkg/tool/errors/http_errors.go @@ -680,4 +680,10 @@ var ( ErrUpdateExternalLink = NewHTTPError(6842, "更新链接失败") ErrDeleteExternalLink = NewHTTPError(6843, "删除链接失败") ErrListExternalLink = NewHTTPError(6844, "获取链接列表失败") + + //----------------------------------------------------------------------------------------------- + // helm releated Error Range: 6850 - 6869 + //----------------------------------------------------------------------------------------------- + ErrListHelmReleases = NewHTTPError(6850, "获取release失败") + ErrGetHelmCharts = NewHTTPError(6851, "获取chart信息失败") ) -- Gitee From 4c7d8a8275be4726b59578d688d8c48b3a7ff0ac Mon Sep 17 00:00:00 2001 From: dyliu Date: Fri, 10 Dec 2021 16:55:26 +0800 Subject: [PATCH 122/134] fix cvm bug (#726) Signed-off-by: liu deyi --- .../aslan/core/workflow/service/workflow/workflow_task.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go index f45587889..7a73ad5bc 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go @@ -1625,7 +1625,6 @@ func BuildModuleToSubTasks(args *commonmodels.BuildModuleArgs, log *zap.SugaredL } if serviceTmpl != nil { - build.Namespace = args.Env.Namespace build.ServiceType = setting.PMDeployType envHost := make(map[string][]string) for _, envConfig := range serviceTmpl.EnvConfigs { -- Gitee From a92b53ff41096f60ba5e6c4ea2dbf94401dce632 Mon Sep 17 00:00:00 2001 From: allenshen Date: Fri, 10 Dec 2021 19:06:38 +0800 Subject: [PATCH 123/134] fix disordered build info bug Signed-off-by: allenshen --- .../aslan/core/workflow/service/workflow/workflow_task.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go index f45587889..954438ec7 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go @@ -538,7 +538,8 @@ func CreateWorkflowTask(args *commonmodels.WorkflowTaskArgs, taskCreator string, buildModuleArgs := &commonmodels.BuildModuleArgs{ Target: target.Name, ServiceName: target.ServiceName, - ProductName: target.ProductName, + //ProductName: target.ProductName, // TODO productName may be nil in some situation, need to figure out reason + ProductName: args.ProductTmplName, Variables: target.Envs, Env: env, } -- Gitee From e6623453e20cbaabdfc24ab79a835654666e0434 Mon Sep 17 00:00:00 2001 From: Min Min Date: Fri, 10 Dec 2021 20:32:02 +0800 Subject: [PATCH 124/134] changed helm chart package dependency to fix a memory leak Signed-off-by: Min Min --- go.mod | 24 +++++++++++--------- go.sum | 72 +++++++++++++++++++++++++++++++++++----------------------- 2 files changed, 57 insertions(+), 39 deletions(-) diff --git a/go.mod b/go.mod index 0f9924dca..b62c82d82 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/coreos/go-oidc/v3 v3.0.0 github.com/dexidp/dex v0.0.0-20210802203454-3fac2ab6bc3b github.com/docker/distribution v2.7.1+incompatible - github.com/docker/docker v20.10.7+incompatible + github.com/docker/docker v20.10.11+incompatible github.com/docker/go-connections v0.4.0 github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect github.com/dsnet/compress v0.0.1 // indirect @@ -41,7 +41,7 @@ require ( github.com/jasonlvhit/gocron v0.0.0-20171226191223-3c914c8681c3 github.com/jinzhu/now v1.1.2 github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect - github.com/mittwald/go-helm-client v0.8.2 + github.com/mittwald/go-helm-client v0.8.3 github.com/moby/buildkit v0.9.1 github.com/nsqio/go-nsq v1.0.7 github.com/nwaples/rardecode v1.0.0 // indirect @@ -67,8 +67,8 @@ require ( github.com/yvasiyarov/newrelic_platform_go v0.0.0-20160601141957-9c099fbc30e9 // indirect go.mongodb.org/mongo-driver v1.5.0 go.uber.org/zap v1.19.0 - golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a - golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 + golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 + golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect @@ -79,25 +79,27 @@ require ( gorm.io/driver/mysql v1.1.2 gorm.io/gorm v1.21.16 helm.sh/helm/v3 v3.7.1 - k8s.io/api v0.22.1 - k8s.io/apimachinery v0.22.1 - k8s.io/apiserver v0.22.1 // indirect - k8s.io/client-go v0.22.1 - k8s.io/kubectl v0.22.1 - k8s.io/utils v0.0.0-20210802155522-efc7438f0176 + k8s.io/api v0.22.4 + k8s.io/apimachinery v0.22.4 + k8s.io/client-go v0.22.4 + k8s.io/kubectl v0.22.4 + k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a sigs.k8s.io/controller-runtime v0.10.0 - sigs.k8s.io/yaml v1.2.0 + sigs.k8s.io/yaml v1.3.0 ) replace ( github.com/docker/distribution => github.com/docker/distribution v2.6.0-rc.1.0.20170726174610-edc3ab29cdff+incompatible github.com/docker/docker => github.com/docker/docker v0.0.0-20180502112750-51a9119f6b81 github.com/docker/go-connections => github.com/docker/go-connections v0.3.1-0.20180212134524-7beb39f0b969 + github.com/go-logr/logr => github.com/go-logr/logr v0.4.0 k8s.io/api => k8s.io/api v0.21.0 k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.21.0 k8s.io/apimachinery => k8s.io/apimachinery v0.21.0 k8s.io/cli-runtime => k8s.io/cli-runtime v0.21.0 k8s.io/client-go => k8s.io/client-go v0.21.0 + k8s.io/klog/v2 => k8s.io/klog/v2 v2.9.0 k8s.io/kubectl => k8s.io/kubectl v0.21.0 + oras.land/oras-go => oras.land/oras-go v0.4.0 ) diff --git a/go.sum b/go.sum index 123658a63..80995ae87 100644 --- a/go.sum +++ b/go.sum @@ -111,8 +111,9 @@ github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbt github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzUzbJPqhK839ygXJ82sde8x3ogr6R28= github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw= +github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= @@ -135,8 +136,9 @@ github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZC github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8= github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= -github.com/Masterminds/squirrel v1.5.0 h1:JukIZisrUXadA9pl3rMkjhiamxiB0cXiu+HGp/Y8cY8= github.com/Masterminds/squirrel v1.5.0/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= +github.com/Masterminds/squirrel v1.5.2 h1:UiOEi2ZX4RCSkpiNDQN5kro/XIBpSRk9iTqdIRPzUXE= +github.com/Masterminds/squirrel v1.5.2/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/Masterminds/vcs v1.13.1/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= @@ -158,8 +160,9 @@ github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2 github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600= github.com/Microsoft/hcsshim v0.8.18/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= -github.com/Microsoft/hcsshim v0.8.21 h1:btRfUDThBE5IKcvI8O8jOiIkujUsAMBSRsYDYmEi6oM= github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= +github.com/Microsoft/hcsshim v0.8.23 h1:47MSwtKGXet80aIn+7h4YI6fwPmwIghAnsx2aOUrG2M= +github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg= github.com/Microsoft/hcsshim/test v0.0.0-20200826032352-301c83a30e7c/go.mod h1:30A5igQ91GEmhYJF8TaRP79pMBOYynRsyOByfVV0dU4= github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= @@ -339,6 +342,7 @@ github.com/containerd/containerd v1.4.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMX github.com/containerd/containerd v1.4.1-0.20201117152358-0edc412565dc/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.9/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ= github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU= github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI= @@ -347,8 +351,9 @@ github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTV github.com/containerd/containerd v1.5.2/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g= github.com/containerd/containerd v1.5.3/go.mod h1:sx18RgvW6ABJ4iYUw7Q5x7bgFOAB9B6G7+yO0XBc4zw= github.com/containerd/containerd v1.5.4/go.mod h1:sx18RgvW6ABJ4iYUw7Q5x7bgFOAB9B6G7+yO0XBc4zw= -github.com/containerd/containerd v1.5.7 h1:rQyoYtj4KddB3bxG6SAqd4+08gePNyJjRqvOIfV3rkM= github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c= +github.com/containerd/containerd v1.5.8 h1:NmkCC1/QxyZFBny8JogwLpOy2f+VEbO/f6bV2Mqtwuw= +github.com/containerd/containerd v1.5.8/go.mod h1:YdFSv5bTFLpG2HIYmfqDpSYYTDX+mc5qtSuYx1YUb/s= github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= @@ -386,6 +391,7 @@ github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDG github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ= github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= @@ -435,12 +441,14 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI= +github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= +github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -465,14 +473,16 @@ github.com/docker/cli v0.0.0-20190925022749-754388324470/go.mod h1:JLrzqnKDaYBop github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v20.10.0-beta1.0.20201029214301-1d20b15adc38+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v20.10.6+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/cli v20.10.7+incompatible h1:pv/3NqibQKphWZiAskMzdz8w0PRbtTaEB+f6NwdU7Is= github.com/docker/cli v20.10.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v20.10.11+incompatible h1:tXU1ezXcruZQRrMP8RN2z9N91h+6egZTS1gsPsKantc= +github.com/docker/cli v20.10.11+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.6.0-rc.1.0.20170726174610-edc3ab29cdff+incompatible h1:357nGVUC8gSpeSc2Axup8HfrfTLLUfWfCsCUhiQSKIg= github.com/docker/distribution v2.6.0-rc.1.0.20170726174610-edc3ab29cdff+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v0.0.0-20180502112750-51a9119f6b81 h1:VnJAjP/7FbY46wddaiKakrc1ogXW+3MlP7cg+S4j4Og= github.com/docker/docker v0.0.0-20180502112750-51a9119f6b81/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/docker-credential-helpers v0.6.4 h1:axCks+yV+2MR3/kZhAmy07yC56WZ2Pwu/fKWtKuZB0o= +github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c= github.com/docker/go-connections v0.3.1-0.20180212134524-7beb39f0b969 h1:Z8LR4yJgA3vaXpBiUWcWdQZpB9h+dzj4NdLjP9Sfdb0= github.com/docker/go-connections v0.3.1-0.20180212134524-7beb39f0b969/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= @@ -499,7 +509,6 @@ github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFP github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -574,8 +583,6 @@ github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTD github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/zapr v0.4.0 h1:uc1uML3hRYL9/ZZPdgHS/n8Nzo+eaYL/Efxkkamf7OM= @@ -994,8 +1001,9 @@ github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHW github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmoiron/sqlx v1.2.1-0.20190826204134-d7d95172beb5/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= -github.com/jmoiron/sqlx v1.3.1 h1:aLN7YINNZ7cYOPK3QC83dbM6KT0NMqVMw961TqrejlE= github.com/jmoiron/sqlx v1.3.1/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= +github.com/jmoiron/sqlx v1.3.4 h1:wv+0IJZfL5z0uZoUjlpKgHkgaFSYD+r9CfrXjEXsO7w= +github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= @@ -1070,8 +1078,9 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk= +github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= @@ -1144,8 +1153,9 @@ github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.2/go.mod h1:6iaV0fGdElS6dPBx0EApTxHrcWvmJphyh2n8YBLPPZ4= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= -github.com/mitchellh/copystructure v1.1.1 h1:Bp6x9R1Wn16SIz3OfeDr0b7RnCG2OB66Y7PQyC/cvq4= github.com/mitchellh/copystructure v1.1.1/go.mod h1:EBArHfARyrSWO/+Wyr9zwEkc6XMFB9XyNgFNmRkZZU4= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk= @@ -1162,10 +1172,11 @@ github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxd github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mittwald/go-helm-client v0.8.2 h1:tWPe+e4Bx2bAC0lY55nxuOxOvNEP4aBfCdizvGpM24U= -github.com/mittwald/go-helm-client v0.8.2/go.mod h1:DVtyXr7KDPIT44X320DkxF39nfbZn8KdjvibnN7iHnQ= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mittwald/go-helm-client v0.8.3 h1:4l8W1PBZiNyapjJjoyQUU3qI8yWhOhpdD6wWdG3Z33g= +github.com/mittwald/go-helm-client v0.8.3/go.mod h1:ZdBFetgIkFiJivTy+P/Ruz6y5YtQMk5BnMSja4+wMdA= github.com/moby/buildkit v0.8.1/go.mod h1:/kyU1hKy/aYCuP39GZA9MaKioovHku57N6cqlKZIaiQ= github.com/moby/buildkit v0.9.1 h1:6noq8jvkaRs3OQGTIDf5U5Etkgq6zsPmQHGWi5yhh88= github.com/moby/buildkit v0.9.1/go.mod h1:oVZKk3TMm0MlDx7XxnlF0wKmcpyrzOs9GEp0VXKWFPk= @@ -1255,8 +1266,9 @@ github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQ github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v1.0.0-rc10/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= @@ -1695,8 +1707,9 @@ golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 h1:/pEO3GD/ABYAjuakUS6xSEmmlyVS4kxBNkeA9tLJiTI= +golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1804,8 +1817,9 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180724155351-3d292e4d0cdc/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1948,6 +1962,7 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 h1:c8PlLMqBbOHoqtjteWm5/kbe6rNY2pbRfbIMVnepueo= @@ -2327,8 +2342,9 @@ k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM= k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= k8s.io/apiserver v0.21.0/go.mod h1:w2YSn4/WIwYuxG5zJmcqtRdtqgW/J2JRgFAqps3bBpg= -k8s.io/apiserver v0.22.1 h1:Ul9Iv8OMB2s45h2tl5XWPpAZo1VPIJ/6N+MESeed7L8= k8s.io/apiserver v0.22.1/go.mod h1:2mcM6dzSt+XndzVQJX21Gx0/Klo7Aen7i0Ai6tIa400= +k8s.io/apiserver v0.22.4 h1:L+220cy+94UWmyBl1kiVTklBXrBtKsbjlPV60eL2u6s= +k8s.io/apiserver v0.22.4/go.mod h1:38WmcUZiiy41A7Aty8/VorWRa8vDGqoUzDf2XYlku0E= k8s.io/cli-runtime v0.21.0 h1:/V2Kkxtf6x5NI2z+Sd/mIrq4FQyQ8jzZAUD6N5RnN7Y= k8s.io/cli-runtime v0.21.0/go.mod h1:XoaHP93mGPF37MkLbjGVYqg3S1MnsFdKtiA/RZzzxOo= k8s.io/client-go v0.21.0 h1:n0zzzJsAQmJngpC0IhgFcApZyoGXPrDIAD601HD09ag= @@ -2341,8 +2357,9 @@ k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeY k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI= k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM= k8s.io/component-base v0.21.0/go.mod h1:qvtjz6X0USWXbgmbfXR+Agik4RZ3jv2Bgr5QnZzdPYw= -k8s.io/component-base v0.22.1 h1:SFqIXsEN3v3Kkr1bS6rstrs1wd45StJqbtgbQ4nRQdo= k8s.io/component-base v0.22.1/go.mod h1:0D+Bl8rrnsPN9v0dyYvkqFfBeAd4u7n77ze+p8CMiPo= +k8s.io/component-base v0.22.4 h1:7qwLJnua2ppGNZrRGDQ0vhsFebI39VGbZ4zdR5ArViI= +k8s.io/component-base v0.22.4/go.mod h1:MrSaQy4a3tFVViff8TZL6JHYSewNCLshZCwHYM58v5A= k8s.io/component-helpers v0.21.0/go.mod h1:tezqefP7lxfvJyR+0a+6QtVrkZ/wIkyMLK4WcQ3Cj8U= k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= @@ -2359,18 +2376,15 @@ k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUc k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= -k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM= k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/kube-openapi v0.0.0-20180731170545-e3762e86a74c/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= -k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= +k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c h1:jvamsI1tn9V0S8jicyX82qaFC0H/NKxv2e5mbqsgR80= +k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/kubectl v0.21.0 h1:WZXlnG/yjcE4LWO2g6ULjFxtzK6H1TKzsfaBFuVIhNg= k8s.io/kubectl v0.21.0/go.mod h1:EU37NukZRXn1TpAkMUoy8Z/B2u6wjHDS4aInsDzVvks= k8s.io/kubernetes v1.11.10/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= @@ -2380,8 +2394,9 @@ k8s.io/metrics v0.21.0/go.mod h1:L3Ji9EGPP1YBbfm9sPfEXSpnj8i24bfQbAFAsW0NueQ= k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210707171843-4b05e18ac7d9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210802155522-efc7438f0176 h1:Mx0aa+SUAcNRQbs5jUzV8lkDlGFU8laZsY9jrcVX5SY= k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a h1:8dYfu/Fc9Gz2rNJKB9IQRGgQOh2clmRzNIPPY1xLY5g= +k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= @@ -2421,7 +2436,8 @@ sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= sourcegraph.com/sqs/pbtypes v1.0.0/go.mod h1:3AciMUv4qUuRHRHhOG4TZOB+72GdPVz5k+c648qsFS4= -- Gitee From a80a11f71a24c800c90cfc1fd412d3deca3cdf2c Mon Sep 17 00:00:00 2001 From: allenshen Date: Fri, 10 Dec 2021 20:37:31 +0800 Subject: [PATCH 125/134] fix env update bug Signed-off-by: allenshen --- pkg/microservice/aslan/core/environment/handler/environment.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/microservice/aslan/core/environment/handler/environment.go b/pkg/microservice/aslan/core/environment/handler/environment.go index 72debf2a9..43627a1e6 100644 --- a/pkg/microservice/aslan/core/environment/handler/environment.go +++ b/pkg/microservice/aslan/core/environment/handler/environment.go @@ -426,7 +426,7 @@ func GetHelmChartVersions(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - envName := c.Param("Name") + envName := c.Param("name") projectName := c.Query("projectName") ctx.Resp, ctx.Err = service.GetHelmChartVersions(projectName, envName, ctx.Logger) -- Gitee From 6bc91d0668556b6e0e493f1e47e1fdfceb7e57c6 Mon Sep 17 00:00:00 2001 From: zhangyifei Date: Fri, 10 Dec 2021 13:48:22 +0800 Subject: [PATCH 126/134] try to fix problem of node log hang Signed-off-by: zhangyifei --- .../reaper/core/service/reaper/script.go | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/pkg/microservice/reaper/core/service/reaper/script.go b/pkg/microservice/reaper/core/service/reaper/script.go index 47cbf2409..1182452cf 100644 --- a/pkg/microservice/reaper/core/service/reaper/script.go +++ b/pkg/microservice/reaper/core/service/reaper/script.go @@ -206,6 +206,7 @@ func (r *Reaper) runScripts() error { // avoid non-blocking IO for stdout to workaround "stdout: write error" for _, script := range r.Ctx.Scripts { scripts = append(scripts, script) + // TODO: This may cause nodejs compilation problems, but it is not completely determined, so keep it for now. if strings.Contains(script, "yarn ") || strings.Contains(script, "npm ") || strings.Contains(script, "bower ") { scripts = append(scripts, "echo 'turn off O_NONBLOCK after using node'") scripts = append(scripts, "python -c 'import os,sys,fcntl; flags = fcntl.fcntl(sys.stdout, fcntl.F_GETFL); fcntl.fcntl(sys.stdout, fcntl.F_SETFL, flags&~os.O_NONBLOCK);'") @@ -229,33 +230,22 @@ func (r *Reaper) runScripts() error { if err != nil { return err } - outScanner := bufio.NewScanner(cmdOutReader) - go func() { - for outScanner.Scan() { - fmt.Printf("%s\n", r.maskSecretEnvs(outScanner.Text())) - if len(r.Ctx.PostScripts) > 0 { - util.WriteFile(fileName, []byte(outScanner.Text()+"\n"), 0700) - } - } - }() - cmdErrReader, err := cmd.StderrPipe() - if err != nil { + if err := cmd.Start(); err != nil { return err } - errScanner := bufio.NewScanner(cmdErrReader) go func() { - for errScanner.Scan() { - fmt.Printf("%s\n", r.maskSecretEnvs(errScanner.Text())) + for outScanner.Scan() { + fmt.Printf("%s\n", r.maskSecretEnvs(outScanner.Text())) if len(r.Ctx.PostScripts) > 0 { - util.WriteFile(fileName, []byte(errScanner.Text()+"\n"), 0700) + util.WriteFile(fileName, []byte(outScanner.Text()+"\n"), 0700) } } }() - return cmd.Run() + return cmd.Wait() } func (r *Reaper) prepareScriptsEnv() []string { -- Gitee From 36c83de6634cc0cb4523c553444a7edaf3c999f3 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Sun, 12 Dec 2021 12:32:26 +0800 Subject: [PATCH 127/134] fix sse log bug Signed-off-by: liu deyi --- pkg/microservice/aslan/core/log/service/sse.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/microservice/aslan/core/log/service/sse.go b/pkg/microservice/aslan/core/log/service/sse.go index 384a27d5b..33b43ff63 100644 --- a/pkg/microservice/aslan/core/log/service/sse.go +++ b/pkg/microservice/aslan/core/log/service/sse.go @@ -139,7 +139,7 @@ func TaskContainerLogStream(ctx context.Context, streamChan chan interface{}, op Targets: []string{options.ServiceName}, }) } - if build != nil && build.PreBuild != nil { + if build != nil && build.PreBuild != nil && build.PreBuild.ClusterID != "" && build.PreBuild.Namespace != "" { options.ClusterID = build.PreBuild.ClusterID options.Namespace = build.PreBuild.Namespace } @@ -157,7 +157,7 @@ func TestJobContainerLogStream(ctx context.Context, streamChan chan interface{}, selector := getPipelineSelector(options) // get cluster ID testing, _ := commonrepo.NewTestingColl().Find(getTestName(options.ServiceName), "") - if testing != nil && testing.PreTest != nil { + if testing != nil && testing.PreTest != nil && testing.PreTest.ClusterID != "" && testing.PreTest.Namespace != "" { options.ClusterID = testing.PreTest.ClusterID options.Namespace = testing.PreTest.Namespace } -- Gitee From 02fc98a87e426cb6fce58eec9b206082ec0a0c89 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Sun, 12 Dec 2021 12:37:22 +0800 Subject: [PATCH 128/134] add annotation Signed-off-by: liu deyi --- pkg/microservice/aslan/core/log/service/sse.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/microservice/aslan/core/log/service/sse.go b/pkg/microservice/aslan/core/log/service/sse.go index 33b43ff63..1cd19e6d3 100644 --- a/pkg/microservice/aslan/core/log/service/sse.go +++ b/pkg/microservice/aslan/core/log/service/sse.go @@ -139,6 +139,7 @@ func TaskContainerLogStream(ctx context.Context, streamChan chan interface{}, op Targets: []string{options.ServiceName}, }) } + // Compatible with the situation where the old data has not been modified if build != nil && build.PreBuild != nil && build.PreBuild.ClusterID != "" && build.PreBuild.Namespace != "" { options.ClusterID = build.PreBuild.ClusterID options.Namespace = build.PreBuild.Namespace @@ -157,6 +158,7 @@ func TestJobContainerLogStream(ctx context.Context, streamChan chan interface{}, selector := getPipelineSelector(options) // get cluster ID testing, _ := commonrepo.NewTestingColl().Find(getTestName(options.ServiceName), "") + // Compatible with the situation where the old data has not been modified if testing != nil && testing.PreTest != nil && testing.PreTest.ClusterID != "" && testing.PreTest.Namespace != "" { options.ClusterID = testing.PreTest.ClusterID options.Namespace = testing.PreTest.Namespace -- Gitee From 0f5e31d3cdf10d3fb07a2c6402fb8c6449206170 Mon Sep 17 00:00:00 2001 From: mouuii <49775493+mouuii@users.noreply.github.com> Date: Mon, 13 Dec 2021 14:39:39 +0800 Subject: [PATCH 129/134] testing add webhook (#690) Signed-off-by: mouuii --- .../core/common/service/webhook/client.go | 1 + .../aslan/core/common/service/workflow.go | 11 + .../aslan/core/workflow/handler/webhook.go | 7 +- .../core/workflow/service/webhook/github.go | 36 ++++ .../service/webhook/github_testing_task.go | 190 ++++++++++++++++++ .../core/workflow/testing/service/testing.go | 11 + 6 files changed, 255 insertions(+), 1 deletion(-) create mode 100644 pkg/microservice/aslan/core/workflow/service/webhook/github_testing_task.go diff --git a/pkg/microservice/aslan/core/common/service/webhook/client.go b/pkg/microservice/aslan/core/common/service/webhook/client.go index a51ee7455..6cce34ad7 100644 --- a/pkg/microservice/aslan/core/common/service/webhook/client.go +++ b/pkg/microservice/aslan/core/common/service/webhook/client.go @@ -26,6 +26,7 @@ const ( PipelinePrefix = "pipeline-" ColliePrefix = "collie-" ServicePrefix = "service-" + TestingPrefix = "testing-" taskTimeoutSecond = 10 ) diff --git a/pkg/microservice/aslan/core/common/service/workflow.go b/pkg/microservice/aslan/core/common/service/workflow.go index 6592413ea..fef943231 100644 --- a/pkg/microservice/aslan/core/common/service/workflow.go +++ b/pkg/microservice/aslan/core/common/service/workflow.go @@ -273,6 +273,17 @@ func toHookSet(hooks interface{}) HookSet { codeHostID: h.CodeHostID, }) } + case []*models.TestingHook: + for _, h := range hs { + res.Insert(hookItem{ + hookUniqueID: hookUniqueID{ + name: h.MainRepo.Name, + owner: h.MainRepo.RepoOwner, + repo: h.MainRepo.RepoName, + }, + codeHostID: h.MainRepo.CodehostID, + }) + } } return res diff --git a/pkg/microservice/aslan/core/workflow/handler/webhook.go b/pkg/microservice/aslan/core/workflow/handler/webhook.go index fb9b8a500..0a6dcea60 100644 --- a/pkg/microservice/aslan/core/workflow/handler/webhook.go +++ b/pkg/microservice/aslan/core/workflow/handler/webhook.go @@ -72,6 +72,11 @@ func processGithub(payload []byte, req *http.Request, requestID string, log *zap log.Errorf("error happens to trigger workflow %v", err) errs = multierror.Append(errs, err) } - + //测试管理webhook + err = webhook.ProcessGithubWebHookForTest(payload, req, requestID, log) + if err != nil { + log.Errorf("error happens to trigger ProcessGithubWebHookForTest %v", err) + errs = multierror.Append(errs, err) + } return errs.ErrorOrNil() } diff --git a/pkg/microservice/aslan/core/workflow/service/webhook/github.go b/pkg/microservice/aslan/core/workflow/service/webhook/github.go index 195536612..595710dc8 100644 --- a/pkg/microservice/aslan/core/workflow/service/webhook/github.go +++ b/pkg/microservice/aslan/core/workflow/service/webhook/github.go @@ -381,6 +381,42 @@ func pushEventCommitsFiles(e *github.PushEvent) []string { return files } + +func ProcessGithubWebHookForTest(payload []byte, req *http.Request, requestID string, log *zap.SugaredLogger)error{ + hookType := github.WebHookType(req) + if hookType == "integration_installation" || hookType == "installation" || hookType == "ping" { + return nil + } + + err := validateSecret(payload, []byte(gitservice.GetHookSecret()), req) + if err != nil { + return err + } + + event, err := github.ParseWebHook(github.WebHookType(req), payload) + if err != nil { + return err + } + + switch et := event.(type) { + case *github.PullRequestEvent: + err = TriggerTestByGithubEvent(et, requestID, log) + if err != nil { + log.Errorf("TriggerTestByGithubEvent error: %v", err) + return e.ErrGithubWebHook.AddErr(err) + } + + case *github.PushEvent: + err = TriggerTestByGithubEvent(et, requestID, log) + if err != nil { + log.Infof("TriggerTestByGithubEvent error: %v", err) + return e.ErrGithubWebHook.AddErr(err) + } + } + return nil +} + + func ProcessGithubWebHook(payload []byte, req *http.Request, requestID string, log *zap.SugaredLogger) error { forwardedProto := req.Header.Get("X-Forwarded-Proto") forwardedHost := req.Header.Get("X-Forwarded-Host") diff --git a/pkg/microservice/aslan/core/workflow/service/webhook/github_testing_task.go b/pkg/microservice/aslan/core/workflow/service/webhook/github_testing_task.go new file mode 100644 index 000000000..fcd494c97 --- /dev/null +++ b/pkg/microservice/aslan/core/workflow/service/webhook/github_testing_task.go @@ -0,0 +1,190 @@ +package webhook + +import ( + "regexp" + "strconv" + + "github.com/google/go-github/v35/github" + "github.com/hashicorp/go-multierror" + "go.uber.org/zap" + + "github.com/koderover/zadig/pkg/microservice/aslan/config" + commonmodels "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" + commonrepo "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/mongodb" + testingservice "github.com/koderover/zadig/pkg/microservice/aslan/core/workflow/testing/service" + "github.com/koderover/zadig/pkg/setting" +) + +func TriggerTestByGithubEvent(event interface{}, requestID string, log *zap.SugaredLogger) error { + //1.find configured testing + testingList, err := commonrepo.NewTestingColl().List(&commonrepo.ListTestOption{}) + if err != nil { + log.Errorf("failed to list testing %v", err) + return err + } + mErr := &multierror.Error{} + diffSrv := func(pullRequestEvent *github.PullRequestEvent, codehostId int) ([]string, error) { + return findChangedFilesOfPullRequest(pullRequestEvent, codehostId) + } + for _, testing := range testingList { + if testing.HookCtl != nil && testing.HookCtl.Enabled { + for _, item := range testing.HookCtl.Items { + if item.TestArgs == nil { + continue + } + matcher := createGithubEventMatcherForTesting(event, diffSrv, testing, log) + if matcher == nil { + continue + } + if matches, err := matcher.Match(item.MainRepo); err != nil { + mErr = multierror.Append(err) + } else if matches { + log.Infof("event match hook %v of %s", item.MainRepo, testing.Name) + var mergeRequestID, commitID string + if ev, isPr := event.(*github.PullRequestEvent); isPr { + mergeRequestID = strconv.Itoa(*ev.PullRequest.Number) + commitID = *ev.PullRequest.Head.SHA + } + args := matcher.UpdateTaskArgs(item.TestArgs, requestID) + args.MergeRequestID = mergeRequestID + args.CommitID = commitID + args.Source = setting.SourceFromGitlab + args.CodehostID = item.MainRepo.CodehostID + args.RepoOwner = item.MainRepo.RepoOwner + args.RepoName = item.MainRepo.RepoName + if resp, err := testingservice.CreateTestTask(args, log); err != nil { + log.Errorf("failed to create testing task when receive event %v due to %v ", event, err) + mErr = multierror.Append(mErr, err) + } else { + log.Infof("succeed to create task %v", resp) + } + } else { + log.Debugf("event not matches %v", item.MainRepo) + } + } + } + } + return mErr.ErrorOrNil() +} + +type githubPushEventMatcherForTesting struct { + log *zap.SugaredLogger + testing *commonmodels.Testing + event *github.PushEvent +} + +type githubMergeEventMatcherForTesting struct { + diffFunc githubPullRequestDiffFunc + log *zap.SugaredLogger + testing *commonmodels.Testing + event *github.PullRequestEvent +} + +func (gpem *githubPushEventMatcherForTesting) Match(hookRepo *commonmodels.MainHookRepo) (bool, error) { + ev := gpem.event + if (hookRepo.RepoOwner + "/" + hookRepo.RepoName) == *ev.Repo.FullName { + if !EventConfigured(hookRepo, config.HookEventPush) { + return false, nil + } + isRegular := hookRepo.IsRegular + if !isRegular && hookRepo.Branch != getBranchFromRef(*ev.Ref) { + return false, nil + } + + if isRegular { + if matched, _ := regexp.MatchString(hookRepo.Branch, getBranchFromRef(*ev.Ref)); !matched { + return false, nil + } + } + hookRepo.Branch = getBranchFromRef(*ev.Ref) + var changedFiles []string + for _, commit := range ev.Commits { + changedFiles = append(changedFiles, commit.Added...) + changedFiles = append(changedFiles, commit.Removed...) + changedFiles = append(changedFiles, commit.Modified...) + } + + return MatchChanges(hookRepo, changedFiles), nil + } + + return false, nil +} + +func (gpem *githubPushEventMatcherForTesting) UpdateTaskArgs(args *commonmodels.TestTaskArgs, requestID string) *commonmodels.TestTaskArgs { + factory := &testArgsFactory{ + testing: gpem.testing, + reqID: requestID, + } + + factory.Update(args) + return args +} + +func createGithubEventMatcherForTesting( + event interface{}, diffSrv githubPullRequestDiffFunc, testing *commonmodels.Testing, log *zap.SugaredLogger, +) gitEventMatcherForTesting { + switch evt := event.(type) { + case *github.PushEvent: + return &githubPushEventMatcherForTesting{ + testing: testing, + log: log, + event: evt, + } + case *github.PullRequestEvent: + return &githubMergeEventMatcherForTesting{ + diffFunc: diffSrv, + log: log, + event: evt, + testing: testing, + } + } + + return nil +} + +func (gmem *githubMergeEventMatcherForTesting) Match(hookRepo *commonmodels.MainHookRepo) (bool, error) { + ev := gmem.event + // TODO: match codehost + if (hookRepo.RepoOwner + "/" + hookRepo.RepoName) == *ev.PullRequest.Base.Repo.FullName { + if !EventConfigured(hookRepo, config.HookEventPr) { + return false, nil + } + + isRegular := hookRepo.IsRegular + if !isRegular && hookRepo.Branch != *ev.PullRequest.Base.Ref { + return false, nil + } + + if isRegular { + if matched, _ := regexp.MatchString(hookRepo.Branch, *ev.PullRequest.Base.Ref); !matched { + return false, nil + } + } + hookRepo.Branch = *ev.PullRequest.Base.Ref + + if *ev.PullRequest.State == "open" { + var changedFiles []string + changedFiles, err := gmem.diffFunc(ev, hookRepo.CodehostID) + if err != nil { + gmem.log.Warnf("failed to get changes of event %v", ev) + return false, err + } + gmem.log.Debugf("succeed to get %d changes in merge event", len(changedFiles)) + + return MatchChanges(hookRepo, changedFiles), nil + } + + } + return false, nil +} + +func (gmem *githubMergeEventMatcherForTesting) UpdateTaskArgs(args *commonmodels.TestTaskArgs, requestID string) *commonmodels.TestTaskArgs { + factory := &testArgsFactory{ + testing: gmem.testing, + reqID: requestID, + } + + args = factory.Update(args) + + return args +} diff --git a/pkg/microservice/aslan/core/workflow/testing/service/testing.go b/pkg/microservice/aslan/core/workflow/testing/service/testing.go index 2647c29c5..78d6daf60 100644 --- a/pkg/microservice/aslan/core/workflow/testing/service/testing.go +++ b/pkg/microservice/aslan/core/workflow/testing/service/testing.go @@ -32,6 +32,7 @@ import ( commonservice "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/nsq" "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/s3" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/service/webhook" commonutil "github.com/koderover/zadig/pkg/microservice/aslan/core/common/util" workflowservice "github.com/koderover/zadig/pkg/microservice/aslan/core/workflow/service/workflow" "github.com/koderover/zadig/pkg/setting" @@ -52,6 +53,11 @@ func CreateTesting(username string, testing *commonmodels.Testing, log *zap.Suga return e.ErrCreateTestModule.AddErr(err) } + err = commonservice.ProcessWebhook(testing.HookCtl.Items,nil,webhook.TestingPrefix+testing.Name,log) + if err != nil { + return e.ErrUpdateTestModule.AddErr(err) + } + testing.UpdateBy = username err = commonrepo.NewTestingColl().Create(testing) if err != nil { @@ -112,6 +118,11 @@ func UpdateTesting(username string, testing *commonmodels.Testing, log *zap.Suga commonservice.EnsureSecretEnvs(existed.PreTest.Envs, testing.PreTest.Envs) } + err = commonservice.ProcessWebhook(testing.HookCtl.Items,existed.HookCtl.Items,webhook.TestingPrefix+testing.Name,log) + if err != nil { + return e.ErrUpdateTestModule.AddErr(err) + } + testing.UpdateBy = username testing.UpdateTime = time.Now().Unix() -- Gitee From be50101f5eb3b29445608fca68751af08acde4b9 Mon Sep 17 00:00:00 2001 From: liu deyi Date: Mon, 13 Dec 2021 16:24:20 +0800 Subject: [PATCH 130/134] fix pod debug bug Signed-off-by: liu deyi --- pkg/microservice/podexec/core/service/ws_terminal.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/microservice/podexec/core/service/ws_terminal.go b/pkg/microservice/podexec/core/service/ws_terminal.go index dfb805ecc..003ad1f5d 100644 --- a/pkg/microservice/podexec/core/service/ws_terminal.go +++ b/pkg/microservice/podexec/core/service/ws_terminal.go @@ -35,6 +35,7 @@ import ( "k8s.io/client-go/tools/remotecommand" conf "github.com/koderover/zadig/pkg/microservice/podexec/config" + "github.com/koderover/zadig/pkg/setting" "github.com/koderover/zadig/pkg/tool/log" ) @@ -206,7 +207,7 @@ func NewKubeOutClusterClient(clusterID string) (kubernetes.Interface, *rest.Conf var config *rest.Config var err error - if clusterID == "" { + if clusterID == "" || clusterID == setting.LocalClusterID { kubeConfig := "" config, err = clientcmd.BuildConfigFromFlags("", kubeConfig) if err != nil { -- Gitee From 6d4db53b5924c5bcebd68c282e633ecc849c040c Mon Sep 17 00:00:00 2001 From: lou Date: Tue, 14 Dec 2021 10:29:01 +0800 Subject: [PATCH 131/134] add json tag for github config Signed-off-by: lou --- .../core/service/types/task/config_payload.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go index 82ee8535d..61f65238f 100644 --- a/pkg/microservice/warpdrive/core/service/types/task/config_payload.go +++ b/pkg/microservice/warpdrive/core/service/types/task/config_payload.go @@ -88,15 +88,15 @@ type S3Config struct { type GithubConfig struct { // github API access token - AccessToken string + AccessToken string `json:"access_token"` // github ssh key with base64 encoded - SSHKey string + SSHKey string `json:"ssh_key"` // github knownhost - KnownHost string + KnownHost string `json:"known_host"` // github app private key - AppKey string + AppKey string `json:"app_key"` // gihhub app id - AppID int + AppID int `json:"app_id"` } type GitlabConfig struct { -- Gitee From e6de2789bea1e7c35fc5ca08b9f380e556ceac19 Mon Sep 17 00:00:00 2001 From: dyliu Date: Tue, 14 Dec 2021 19:18:03 +0800 Subject: [PATCH 132/134] externally exposed artifact interface (#738) * externally exposed deliverable interface Signed-off-by: liu deyi * optimize code Signed-off-by: liu deyi * fix import cycle not allowed problem Signed-off-by: liu deyi * optimize code Signed-off-by: liu deyi * optimize code Signed-off-by: liu deyi * optimize code Signed-off-by: liu deyi * modify return field Signed-off-by: liu deyi * debug code Signed-off-by: liu deyi * remove debug code Signed-off-by: liu deyi * modify function name Signed-off-by: liu deyi * optimize code Signed-off-by: liu deyi --- .../repository/mongodb/delivery_artifact.go | 17 +++-- .../aslan/core/delivery/handler/artifact.go | 17 ++++- .../aslan/core/delivery/handler/router.go | 1 + .../aslan/core/delivery/service/artifact.go | 9 +++ .../picket/client/aslan/artifact.go | 31 ++++++++ .../picket/client/aslan/delivery.go | 25 +++++++ .../picket/client/aslan/workflow.go | 11 --- .../picket/core/public/handler/public.go | 7 ++ .../picket/core/public/handler/router.go | 1 + .../picket/core/public/service/public.go | 72 +++++++++++++++++++ 10 files changed, 174 insertions(+), 17 deletions(-) create mode 100644 pkg/microservice/picket/client/aslan/artifact.go create mode 100644 pkg/microservice/picket/client/aslan/delivery.go diff --git a/pkg/microservice/aslan/core/common/repository/mongodb/delivery_artifact.go b/pkg/microservice/aslan/core/common/repository/mongodb/delivery_artifact.go index e0e0cc75b..a7fb5ebc5 100644 --- a/pkg/microservice/aslan/core/common/repository/mongodb/delivery_artifact.go +++ b/pkg/microservice/aslan/core/common/repository/mongodb/delivery_artifact.go @@ -140,13 +140,20 @@ func (c *DeliveryArtifactColl) Get(args *DeliveryArtifactArgs) (*models.Delivery return nil, errors.New("nil delivery_artifact args") } resp := new(models.DeliveryArtifact) - id, err := primitive.ObjectIDFromHex(args.ID) - if err != nil { - return nil, err + query := bson.M{} + if args.ID != "" { + id, err := primitive.ObjectIDFromHex(args.ID) + if err != nil { + return nil, err + } + query["_id"] = id + } + + if args.Image != "" { + query["image"] = args.Image } - query := bson.M{"_id": id} - err = c.FindOne(context.TODO(), query).Decode(&resp) + err := c.FindOne(context.TODO(), query).Decode(&resp) if err != nil { return nil, err } diff --git a/pkg/microservice/aslan/core/delivery/handler/artifact.go b/pkg/microservice/aslan/core/delivery/handler/artifact.go index a8eed0c3d..2e84ec667 100644 --- a/pkg/microservice/aslan/core/delivery/handler/artifact.go +++ b/pkg/microservice/aslan/core/delivery/handler/artifact.go @@ -77,6 +77,22 @@ func ListDeliveryArtifacts(c *gin.Context) { ctx.Resp, ctx.Err = artifacts, err } +func GetDeliveryArtifactIDByImage(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + + image := c.Query("image") + if image == "" { + ctx.Err = e.ErrInvalidParam.AddDesc("image can't be empty!") + return + } + args := &commonrepo.DeliveryArtifactArgs{ + Image: image, + } + + ctx.Resp, ctx.Err = deliveryservice.GetDeliveryArtifactIDByImage(args, ctx.Logger) +} + func GetDeliveryArtifact(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() @@ -89,7 +105,6 @@ func GetDeliveryArtifact(c *gin.Context) { args := &commonrepo.DeliveryArtifactArgs{ ID: id, } - args.ID = id ctx.Resp, ctx.Err = deliveryservice.GetDeliveryArtifact(args, ctx.Logger) } diff --git a/pkg/microservice/aslan/core/delivery/handler/router.go b/pkg/microservice/aslan/core/delivery/handler/router.go index 7b58bcade..11141b24e 100644 --- a/pkg/microservice/aslan/core/delivery/handler/router.go +++ b/pkg/microservice/aslan/core/delivery/handler/router.go @@ -30,6 +30,7 @@ func (*Router) Inject(router *gin.RouterGroup) { { deliveryArtifact.GET("", ListDeliveryArtifacts) deliveryArtifact.GET("/:id", GetDeliveryArtifact) + deliveryArtifact.GET("/image", GetDeliveryArtifactIDByImage) deliveryArtifact.POST("", CreateDeliveryArtifacts) deliveryArtifact.POST("/:id", UpdateDeliveryArtifact) deliveryArtifact.POST("/:id/activities", CreateDeliveryActivities) diff --git a/pkg/microservice/aslan/core/delivery/service/artifact.go b/pkg/microservice/aslan/core/delivery/service/artifact.go index ac941e49b..cf8ee9683 100644 --- a/pkg/microservice/aslan/core/delivery/service/artifact.go +++ b/pkg/microservice/aslan/core/delivery/service/artifact.go @@ -168,3 +168,12 @@ func getDeliveryActivitiesMap(deliveryActivities []*commonmodels.DeliveryActivit } return artifactMapInfo } + +func GetDeliveryArtifactIDByImage(deliveryArtifactArgs *commonrepo.DeliveryArtifactArgs, log *zap.SugaredLogger) (string, error) { + deliveryArtifact, err := commonrepo.NewDeliveryArtifactColl().Get(deliveryArtifactArgs) + if err != nil { + log.Errorf("get deliveryArtifact error: %s", err) + return "", e.ErrFindArtifact.AddErr(err) + } + return deliveryArtifact.ID.Hex(), nil +} diff --git a/pkg/microservice/picket/client/aslan/artifact.go b/pkg/microservice/picket/client/aslan/artifact.go new file mode 100644 index 000000000..9a5042f94 --- /dev/null +++ b/pkg/microservice/picket/client/aslan/artifact.go @@ -0,0 +1,31 @@ +package aslan + +import ( + "fmt" + "net/http" + "net/url" + + "github.com/koderover/zadig/pkg/tool/httpclient" +) + +func (c *Client) GetArtifactByImage(header http.Header, qs url.Values, image string) ([]byte, error) { + url := fmt.Sprintf("/delivery/artifacts/image") + + res, err := c.Get(url, httpclient.SetHeadersFromHTTPHeader(header), httpclient.SetQueryParamsFromValues(qs), httpclient.SetQueryParam(image, image)) + if err != nil { + return nil, err + } + + return res.Body(), nil +} + +func (c *Client) GetArtifactInfo(header http.Header, qs url.Values, id string) ([]byte, error) { + url := fmt.Sprintf("/delivery/artifacts/%s", id) + + res, err := c.Get(url, httpclient.SetHeadersFromHTTPHeader(header), httpclient.SetQueryParamsFromValues(qs)) + if err != nil { + return nil, err + } + + return res.Body(), nil +} diff --git a/pkg/microservice/picket/client/aslan/delivery.go b/pkg/microservice/picket/client/aslan/delivery.go new file mode 100644 index 000000000..58e11011c --- /dev/null +++ b/pkg/microservice/picket/client/aslan/delivery.go @@ -0,0 +1,25 @@ +package aslan + +import ( + "fmt" + "net/http" + "net/url" + + "github.com/koderover/zadig/pkg/tool/httpclient" +) + +func (c *Client) ListDelivery(header http.Header, qs url.Values, productName, workflowName, taskId, perPage, page string) ([]byte, error) { + url := fmt.Sprintf("/delivery/releases") + queryParams := make(map[string]string) + queryParams["productName"] = productName + queryParams["workflowName"] = workflowName + queryParams["taskId"] = taskId + queryParams["per_page"] = perPage + queryParams["page"] = page + res, err := c.Get(url, httpclient.SetHeadersFromHTTPHeader(header), httpclient.SetQueryParamsFromValues(qs), httpclient.SetQueryParams(queryParams)) + if err != nil { + return nil, err + } + + return res.Body(), nil +} diff --git a/pkg/microservice/picket/client/aslan/workflow.go b/pkg/microservice/picket/client/aslan/workflow.go index b1a50012e..40bd045dc 100644 --- a/pkg/microservice/picket/client/aslan/workflow.go +++ b/pkg/microservice/picket/client/aslan/workflow.go @@ -90,14 +90,3 @@ func (c *Client) ListWorkflowTask(header http.Header, qs url.Values, commitId st return res.Body(), nil } - -func (c *Client) ListDelivery(header http.Header, qs url.Values, productName, workflowName, taskId, perPage, page string) ([]byte, error) { - url := fmt.Sprintf("/delivery/releases?orgId=1&productName=%s&workflowName=%s&taskId=%s&per_page=%s&page=%s", productName, workflowName, taskId, perPage, page) - - res, err := c.Get(url, httpclient.SetHeadersFromHTTPHeader(header), httpclient.SetQueryParamsFromValues(qs)) - if err != nil { - return nil, err - } - - return res.Body(), nil -} diff --git a/pkg/microservice/picket/core/public/handler/public.go b/pkg/microservice/picket/core/public/handler/public.go index 17c209e3a..78280759d 100644 --- a/pkg/microservice/picket/core/public/handler/public.go +++ b/pkg/microservice/picket/core/public/handler/public.go @@ -123,3 +123,10 @@ func ListDelivery(c *gin.Context) { pageStr := c.Query("page") ctx.Resp, ctx.Err = service.ListDelivery(c.Request.Header, c.Request.URL.Query(), productName, workflowName, taskIDStr, perPageStr, pageStr, ctx.Logger) } + +func GetArtifactInfo(c *gin.Context) { + ctx := internalhandler.NewContext(c) + defer func() { internalhandler.JSONResponse(c, ctx) }() + image := c.Query("image") + ctx.Resp, ctx.Err = service.GetArtifactInfo(c.Request.Header, c.Request.URL.Query(), image, ctx.Logger) +} diff --git a/pkg/microservice/picket/core/public/handler/router.go b/pkg/microservice/picket/core/public/handler/router.go index a4eeca51f..d6fd88ddf 100644 --- a/pkg/microservice/picket/core/public/handler/router.go +++ b/pkg/microservice/picket/core/public/handler/router.go @@ -31,5 +31,6 @@ func (*Router) Inject(router *gin.RouterGroup) { dev.POST("/workflowTask/id/:id/pipelines/:name/restart", RestartWorkflowTask) dev.GET("/workflowTask", ListWorkflowTask) dev.GET("/dc/releases", ListDelivery) + dev.GET("/dc/artifact", GetArtifactInfo) } } diff --git a/pkg/microservice/picket/core/public/service/public.go b/pkg/microservice/picket/core/public/service/public.go index f3d9ef9ee..632d96e09 100644 --- a/pkg/microservice/picket/core/public/service/public.go +++ b/pkg/microservice/picket/core/public/service/public.go @@ -17,6 +17,8 @@ limitations under the License. package service import ( + "encoding/json" + "fmt" "net/http" "net/url" @@ -44,3 +46,73 @@ func ListWorkflowTask(header http.Header, qs url.Values, commitId string, _ *zap func ListDelivery(header http.Header, qs url.Values, productName string, workflowName string, taskId string, perPage string, page string, _ *zap.SugaredLogger) ([]byte, error) { return aslan.New().ListDelivery(header, qs, productName, workflowName, taskId, perPage, page) } + +type DeliveryArtifact struct { + Name string `json:"name"` + Type string `json:"type"` + Source string `json:"source"` + Image string `json:"image,omitempty"` + ImageHash string `json:"image_hash,omitempty"` + ImageTag string `json:"image_tag"` + ImageDigest string `json:"image_digest,omitempty"` + ImageSize int64 `json:"image_size,omitempty"` + Architecture string `json:"architecture,omitempty"` + Os string `json:"os,omitempty"` + PackageFileLocation string `json:"package_file_location,omitempty"` + PackageStorageURI string `json:"package_storage_uri,omitempty"` + CreatedBy string `json:"created_by"` + CreatedTime int64 `json:"created_time"` +} + +type DeliveryActivity struct { + Type string `json:"type"` + Content string `json:"content,omitempty"` + URL string `json:"url,omitempty"` + Commits []*ActivityCommit `json:"commits,omitempty"` + Issues []string `json:"issues,omitempty"` + Namespace string `json:"namespace,omitempty"` + EnvName string `json:"env_name,omitempty"` + PublishHosts []string `json:"publish_hosts,omitempty"` + PublishNamespaces []string `json:"publish_namespaces,omitempty"` + RemoteFileKey string `json:"remote_file_key,omitempty"` + DistStorageURL string `json:"dist_storage_url,omitempty"` + SrcStorageURL string `json:"src_storage_url,omitempty"` + StartTime int64 `json:"start_time,omitempty"` + EndTime int64 `json:"end_time,omitempty"` + CreatedBy string `json:"created_by"` + CreatedTime int64 `json:"created_time"` +} + +type ActivityCommit struct { + Address string `json:"address"` + Source string `json:"source,omitempty"` + RepoOwner string `json:"repo_owner"` + RepoName string `json:"repo_name"` + Branch string `json:"branch"` + PR int `json:"pr,omitempty"` + Tag string `json:"tag,omitempty"` + CommitID string `json:"commit_id,omitempty"` + CommitMessage string `json:"commit_message,omitempty"` + AuthorName string `json:"author_name,omitempty"` +} + +type DeliveryArtifactInfo struct { + *DeliveryArtifact + DeliveryActivities []*DeliveryActivity `json:"activities"` + DeliveryActivitiesMap map[string][]*DeliveryActivity `json:"sortedActivities,omitempty"` +} + +func GetArtifactInfo(header http.Header, qs url.Values, image string, _ *zap.SugaredLogger) (*DeliveryArtifactInfo, error) { + artifactID, err := aslan.New().GetArtifactByImage(header, qs, image) + if err != nil { + return nil, fmt.Errorf("failed to get artifact by image err:%s", err) + } + + body, err := aslan.New().GetArtifactInfo(header, qs, string(artifactID)) + var deliveryArtifactInfo *DeliveryArtifactInfo + if err = json.Unmarshal(body, &deliveryArtifactInfo); err != nil { + return nil, fmt.Errorf("failed to unmarshal deliveryArtifactInfo err:%s", err) + } + + return deliveryArtifactInfo, nil +} -- Gitee From 92e4e4ae89981e32cf65ad16d1e5a9f23fc8bdd6 Mon Sep 17 00:00:00 2001 From: mouuii <49775493+mouuii@users.noreply.github.com> Date: Tue, 14 Dec 2021 20:19:56 +0800 Subject: [PATCH 133/134] workflowtask (#736) * workflowtask Signed-off-by: mouuii * code refactor Signed-off-by: mouuii * code refactor Signed-off-by: mouuii --- .../core/common/repository/models/workflow.go | 1 + .../workflow/service/workflow/workflow_task.go | 14 +++++++++----- .../picket/core/public/handler/public.go | 18 +++++++++++++++++- .../picket/core/public/handler/router.go | 2 +- 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/pkg/microservice/aslan/core/common/repository/models/workflow.go b/pkg/microservice/aslan/core/common/repository/models/workflow.go index 3cd5e8368..714dbef30 100644 --- a/pkg/microservice/aslan/core/common/repository/models/workflow.go +++ b/pkg/microservice/aslan/core/common/repository/models/workflow.go @@ -168,6 +168,7 @@ type WorkflowTaskArgs struct { // 请求模式,openAPI表示外部客户调用 RequestMode string `json:"request_mode,omitempty"` IsParallel bool `json:"is_parallel" bson:"is_parallel"` + EnvName string `json:"env_name" bson:"-"` } type TestTaskArgs struct { diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go index a0752500d..360b76b15 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go @@ -451,17 +451,21 @@ func CreateWorkflowTask(args *commonmodels.WorkflowTaskArgs, taskCreator string, } } - productTempl, err := template.NewProductColl().Find(args.ProductTmplName) + workflow, err := commonrepo.NewWorkflowColl().Find(args.WorkflowName) if err != nil { - log.Errorf("productTempl.Find error: %v", err) + log.Errorf("Workflow.Find error: %v", err) return nil, e.ErrFindWorkflow.AddDesc(err.Error()) } - workflow, err := commonrepo.NewWorkflowColl().Find(args.WorkflowName) + project, err := template.NewProductColl().Find(workflow.ProductTmplName) if err != nil { - log.Errorf("Workflow.Find error: %v", err) + log.Errorf("project.Find error: %v", err) return nil, e.ErrFindWorkflow.AddDesc(err.Error()) } + // developer don't pass args.ProductTmplName + if args.ProductTmplName == "" { + args.ProductTmplName = workflow.ProductTmplName + } args.IsParallel = workflow.IsParallel var env *commonmodels.Product @@ -563,7 +567,7 @@ func CreateWorkflowTask(args *commonmodels.WorkflowTaskArgs, taskCreator string, if deployEnv.Type == setting.PMDeployType { continue } - deployTask, err := deployEnvToSubTasks(deployEnv, env, productTempl.Timeout) + deployTask, err := deployEnvToSubTasks(deployEnv, env, project.Timeout) if err != nil { log.Errorf("deploy env to subtask error: %v", err) return nil, e.ErrCreateTask.AddErr(err) diff --git a/pkg/microservice/picket/core/public/handler/public.go b/pkg/microservice/picket/core/public/handler/public.go index 78280759d..602ee5e39 100644 --- a/pkg/microservice/picket/core/public/handler/public.go +++ b/pkg/microservice/picket/core/public/handler/public.go @@ -22,6 +22,7 @@ import ( "github.com/gin-gonic/gin" + "github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models" "github.com/koderover/zadig/pkg/microservice/picket/core/public/service" internalhandler "github.com/koderover/zadig/pkg/shared/handler" ) @@ -29,10 +30,24 @@ import ( func CreateWorkflowTask(c *gin.Context) { ctx := internalhandler.NewContext(c) defer func() { internalhandler.JSONResponse(c, ctx) }() - body, _ := c.GetRawData() + req := new(models.WorkflowTaskArgs) + if err := c.ShouldBindJSON(req); err != nil { + ctx.Err = err + ctx.Logger.Errorf("ShouldBindJSON err:%s", err) + return + } + req.Namespace = req.EnvName + req.RequestMode = "openAPI" + body, err := json.Marshal(req) + if err != nil { + ctx.Err = err + ctx.Logger.Errorf("Marshal err:%s", err) + return + } res, err := service.CreateWorkflowTask(c.Request.Header, c.Request.URL.Query(), body, ctx.Logger) if err != nil { ctx.Err = err + ctx.Logger.Errorf("CreateWorkflowTask err:%s", err) return } // to avoid customer feel confused ,return workflow_name instead of pipline_name @@ -40,6 +55,7 @@ func CreateWorkflowTask(c *gin.Context) { err = json.Unmarshal(res, &resp) if err != nil { ctx.Err = err + ctx.Logger.Errorf("Unmarshal err:%s", err) return } resp.WorkflowName = resp.PipelineName diff --git a/pkg/microservice/picket/core/public/handler/router.go b/pkg/microservice/picket/core/public/handler/router.go index d6fd88ddf..550478ab7 100644 --- a/pkg/microservice/picket/core/public/handler/router.go +++ b/pkg/microservice/picket/core/public/handler/router.go @@ -27,7 +27,7 @@ func (*Router) Inject(router *gin.RouterGroup) { dev := router.Group("") { dev.POST("/workflowTask/create", CreateWorkflowTask) - dev.DELETE("workflowTask/id/:id/pipelines/:name/cancel", CancelWorkflowTask) + dev.POST("workflowTask/id/:id/pipelines/:name/cancel", CancelWorkflowTask) dev.POST("/workflowTask/id/:id/pipelines/:name/restart", RestartWorkflowTask) dev.GET("/workflowTask", ListWorkflowTask) dev.GET("/dc/releases", ListDelivery) -- Gitee From 34efecab0f15c659e30f085ca4e5e7192a1739d8 Mon Sep 17 00:00:00 2001 From: dyliu Date: Wed, 15 Dec 2021 17:30:44 +0800 Subject: [PATCH 134/134] external workflow interface supports helm type (#741) * external workflow interface supports helm type Signed-off-by: liu deyi * modify api router Signed-off-by: liu deyi * add code annotaion Signed-off-by: liu deyi * modify function name Signed-off-by: liu deyi --- .../core/common/repository/models/workflow.go | 1 + .../service/workflow/workflow_task.go | 20 +++++++++++++++++-- .../picket/core/public/handler/router.go | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/pkg/microservice/aslan/core/common/repository/models/workflow.go b/pkg/microservice/aslan/core/common/repository/models/workflow.go index 714dbef30..61fcbb4e8 100644 --- a/pkg/microservice/aslan/core/common/repository/models/workflow.go +++ b/pkg/microservice/aslan/core/common/repository/models/workflow.go @@ -309,6 +309,7 @@ type HookPayload struct { type TargetArgs struct { Name string `bson:"name" json:"name"` ServiceName string `bson:"service_name" json:"service_name"` + ServiceType string `bson:"service_type,omitempty" json:"service_type,omitempty"` ProductName string `bson:"product_name" json:"product_name"` Build *BuildArgs `bson:"build" json:"build"` Deploy []DeployEnv `bson:"deloy" json:"deploy"` diff --git a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go index 360b76b15..08014a9ca 100644 --- a/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go +++ b/pkg/microservice/aslan/core/workflow/service/workflow/workflow_task.go @@ -787,11 +787,14 @@ func AddDataToArgs(args *commonmodels.WorkflowTaskArgs, log *zap.SugaredLogger) for _, target := range args.Target { target.HasBuild = true // openAPI模式,传入的name是服务名称 - // 只支持k8s服务 + serviceType, err := getValidServiceType(target.ServiceType) + if err != nil { + return err + } opt := &commonrepo.ServiceFindOption{ ServiceName: target.Name, ProductName: workflow.ProductTmplName, - Type: setting.K8SDeployType, + Type: serviceType, ExcludeStatus: setting.ProductStatusDeleting} serviceTmpl, err := commonrepo.NewServiceColl().Find(opt) if err != nil { @@ -897,6 +900,19 @@ func AddDataToArgs(args *commonmodels.WorkflowTaskArgs, log *zap.SugaredLogger) return nil } +// Only supports k8s and helm two service types currently +func getValidServiceType(serviceType string) (string, error) { + switch serviceType { + // Compatible when the service_type is equal to empty + case setting.K8SDeployType, "": + return setting.K8SDeployType, nil + case setting.HelmDeployType: + return setting.HelmDeployType, nil + default: + return "", fmt.Errorf("Unsupported service type") + } +} + func dealWithNamespace(args *commonmodels.WorkflowTaskArgs) { args.Namespace = strings.TrimPrefix(args.Namespace, ",") args.Namespace = strings.TrimSuffix(args.Namespace, ",") diff --git a/pkg/microservice/picket/core/public/handler/router.go b/pkg/microservice/picket/core/public/handler/router.go index 550478ab7..177292def 100644 --- a/pkg/microservice/picket/core/public/handler/router.go +++ b/pkg/microservice/picket/core/public/handler/router.go @@ -27,7 +27,7 @@ func (*Router) Inject(router *gin.RouterGroup) { dev := router.Group("") { dev.POST("/workflowTask/create", CreateWorkflowTask) - dev.POST("workflowTask/id/:id/pipelines/:name/cancel", CancelWorkflowTask) + dev.POST("/workflowTask/id/:id/pipelines/:name/cancel", CancelWorkflowTask) dev.POST("/workflowTask/id/:id/pipelines/:name/restart", RestartWorkflowTask) dev.GET("/workflowTask", ListWorkflowTask) dev.GET("/dc/releases", ListDelivery) -- Gitee