From e31058ad36ad1ebd310b87c33966d5104025352b Mon Sep 17 00:00:00 2001 From: closetool Date: Thu, 18 May 2023 12:34:22 +0800 Subject: [PATCH 1/3] feat: support tag for application Signed-off-by: closetool --- core/controller/application/controller.go | 59 ++++++++++++++++++- core/controller/application/models.go | 19 +++--- core/controller/application/v2models.go | 13 ++-- core/controller/cluster/controller_basic.go | 33 +++++++++-- .../controller/cluster/controller_basic_v2.go | 29 +++++---- core/controller/cluster/models_basic.go | 27 ++++++--- core/controller/cluster/models_basic_v2.go | 34 +++++++---- pkg/cluster/dao/dao.go | 14 ++++- pkg/tag/manager/manager.go | 4 ++ pkg/tag/models/tag.go | 51 ++++++++++++++++ 10 files changed, 231 insertions(+), 52 deletions(-) diff --git a/core/controller/application/controller.go b/core/controller/application/controller.go index 5186c218..4650c0a8 100644 --- a/core/controller/application/controller.go +++ b/core/controller/application/controller.go @@ -42,6 +42,8 @@ import ( pipelinemanager "github.com/horizoncd/horizon/pkg/pipelinerun/pipeline/manager" pipelinemodels "github.com/horizoncd/horizon/pkg/pipelinerun/pipeline/models" regionmodels "github.com/horizoncd/horizon/pkg/region/models" + tagmanager "github.com/horizoncd/horizon/pkg/tag/manager" + tagmodels "github.com/horizoncd/horizon/pkg/tag/models" trmanager "github.com/horizoncd/horizon/pkg/templaterelease/manager" templateschema "github.com/horizoncd/horizon/pkg/templaterelease/schema" usersvc "github.com/horizoncd/horizon/pkg/user/service" @@ -93,6 +95,7 @@ type controller struct { userSvc usersvc.Service memberManager member.Manager eventMgr eventmanager.Manager + tagMgr tagmanager.Manager applicationRegionMgr applicationregionmanager.Manager pipelinemanager pipelinemanager.Manager buildSchema *build.Schema @@ -113,6 +116,7 @@ func NewController(param *param.Param) Controller { userSvc: param.UserSvc, memberManager: param.MemberManager, eventMgr: param.EventManager, + tagMgr: param.TagManager, applicationRegionMgr: param.ApplicationRegionManager, pipelinemanager: param.PipelineMgr, buildSchema: param.BuildSchema, @@ -149,7 +153,14 @@ func (c *controller) GetApplication(ctx context.Context, id uint) (_ *GetApplica return nil, err } fullPath := fmt.Sprintf("%v/%v", group.FullPath, app.Name) - return ofApplicationModel(app, fullPath, trs, pipelineJSONBlob, applicationJSONBlob), nil + + // 5. get tags + tags, err := c.tagMgr.ListByResourceTypeID(ctx, common.ResourceApplication, app.ID) + if err != nil { + return nil, err + } + + return ofApplicationModel(app, fullPath, trs, pipelineJSONBlob, applicationJSONBlob, tags...), nil } func (c *controller) GetApplicationV2(ctx context.Context, id uint) (_ *GetApplicationResponseV2, err error) { @@ -174,6 +185,12 @@ func (c *controller) GetApplicationV2(ctx context.Context, id uint) (_ *GetAppli } fullPath := fmt.Sprintf("%v/%v", group.FullPath, app.Name) + // 4. get tags + tags, err := c.tagMgr.ListByResourceTypeID(ctx, common.ResourceApplication, app.ID) + if err != nil { + return nil, err + } + resp := &GetApplicationResponseV2{ ID: id, Name: app.Name, @@ -186,6 +203,7 @@ func (c *controller) GetApplicationV2(ctx context.Context, id uint) (_ *GetAppli return codemodels.NewGit(app.GitURL, app.GitSubfolder, app.GitRefType, app.GitRef) }(), BuildConfig: applicationRepo.BuildConf, + Tags: tagmodels.Tags(tags).IntoTagsBasic(), TemplateInfo: func() *codemodels.TemplateInfo { if app.Template == "" { return nil @@ -277,6 +295,15 @@ func (c *controller) CreateApplication(ctx context.Context, groupID uint, return nil, err } + // 7. create tags + if request.Tags != nil { + tags := request.Tags.IntoTags(common.ResourceApplication, applicationModel.ID) + err = c.tagMgr.UpsertByResourceTypeID(ctx, common.ResourceApplication, applicationModel.ID, tags) + if err != nil { + return nil, err + } + } + ret := ofApplicationModel(applicationModel, fullPath, trs, request.TemplateInput.Pipeline, request.TemplateInput.Application) @@ -384,6 +411,14 @@ func (c *controller) CreateApplicationV2(ctx context.Context, groupID uint, return nil, err } + if request.Tags != nil { + tags := request.Tags.IntoTags(common.ResourceApplication, applicationDBModel.ID) + err = c.tagMgr.UpsertByResourceTypeID(ctx, common.ResourceApplication, applicationDBModel.ID, tags) + if err != nil { + return nil, err + } + } + ret := &CreateApplicationResponseV2{ ID: applicationDBModel.ID, Name: request.Name, @@ -481,6 +516,15 @@ func (c *controller) UpdateApplication(ctx context.Context, id uint, return nil, err } + // 8. update tags + if request.Tags != nil { + tags := request.Tags.IntoTags(common.ResourceApplication, applicationModel.ID) + err = c.tagMgr.UpsertByResourceTypeID(ctx, common.ResourceApplication, applicationModel.ID, tags) + if err != nil { + return nil, err + } + } + return ofApplicationModel(applicationModel, fullPath, trs, request.TemplateInput.Pipeline, request.TemplateInput.Application), nil } @@ -525,6 +569,19 @@ func (c *controller) UpdateApplicationV2(ctx context.Context, id uint, // 4. update application in db applicationModel := request.UpdateToApplicationModel(appExistsInDB) _, err = c.applicationMgr.UpdateByID(ctx, id, applicationModel) + if err != nil { + return err + } + + // 5. update tags + if request.Tags != nil { + tags := request.Tags.IntoTags(common.ResourceApplication, id) + err = c.tagMgr.UpsertByResourceTypeID(ctx, common.ResourceApplication, id, tags) + if err != nil { + return err + } + } + return err } diff --git a/core/controller/application/models.go b/core/controller/application/models.go index 929b5109..e2c3e6ee 100644 --- a/core/controller/application/models.go +++ b/core/controller/application/models.go @@ -19,16 +19,18 @@ import ( "github.com/horizoncd/horizon/pkg/application/models" codemodels "github.com/horizoncd/horizon/pkg/cluster/code" + tagmodels "github.com/horizoncd/horizon/pkg/tag/models" trmodels "github.com/horizoncd/horizon/pkg/templaterelease/models" ) // Base holds the parameters which can be updated of an application type Base struct { - Description string `json:"description"` - Priority string `json:"priority"` - Template *Template `json:"template"` - Git *codemodels.Git `json:"git"` - TemplateInput *TemplateInput `json:"templateInput"` + Description string `json:"description"` + Priority string `json:"priority"` + Tags tagmodels.TagsBasic `json:"tags,omitempty"` + Template *Template `json:"template"` + Git *codemodels.Git `json:"git"` + TemplateInput *TemplateInput `json:"templateInput"` } type TemplateInput struct { @@ -129,7 +131,7 @@ func (m *UpdateApplicationRequest) toApplicationModel(appExistsInDB *models.Appl // ofApplicationModel transfer models.Application, templateInput, pipelineInput to GetApplicationResponse func ofApplicationModel(app *models.Application, fullPath string, trs []*trmodels.TemplateRelease, - pipelineJSONBlob, applicationJSONBlob map[string]interface{}) *GetApplicationResponse { + pipelineJSONBlob, applicationJSONBlob map[string]interface{}, tags ...*tagmodels.Tag) *GetApplicationResponse { var recommendedRelease string for _, tr := range trs { if *tr.Recommended { @@ -137,6 +139,8 @@ func ofApplicationModel(app *models.Application, fullPath string, trs []*trmodel } } + tagsBasic := tagmodels.Tags(tags).IntoTagsBasic() + resp := &GetApplicationResponse{ CreateApplicationRequest: CreateApplicationRequest{ Base: Base{ @@ -147,7 +151,8 @@ func ofApplicationModel(app *models.Application, fullPath string, trs []*trmodel Release: app.TemplateRelease, RecommendedRelease: recommendedRelease, }, - Git: codemodels.NewGit(app.GitURL, app.GitSubfolder, app.GitRefType, app.GitRef), + Tags: tagsBasic, + Git: codemodels.NewGit(app.GitURL, app.GitSubfolder, app.GitRefType, app.GitRef), TemplateInput: &TemplateInput{ Application: applicationJSONBlob, Pipeline: pipelineJSONBlob, diff --git a/core/controller/application/v2models.go b/core/controller/application/v2models.go index fd86fc16..b481a953 100644 --- a/core/controller/application/v2models.go +++ b/core/controller/application/v2models.go @@ -19,14 +19,16 @@ import ( "github.com/horizoncd/horizon/pkg/application/models" codemodels "github.com/horizoncd/horizon/pkg/cluster/code" + tagmodels "github.com/horizoncd/horizon/pkg/tag/models" ) type GetApplicationResponseV2 struct { - ID uint `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - Priority string `json:"priority"` - Git *codemodels.Git `json:"git"` + ID uint `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Priority string `json:"priority"` + Tags tagmodels.TagsBasic `json:"tags,omitempty"` + Git *codemodels.Git `json:"git"` BuildConfig map[string]interface{} `json:"buildConfig"` TemplateInfo *codemodels.TemplateInfo `json:"templateInfo"` @@ -45,6 +47,7 @@ type CreateOrUpdateApplicationRequestV2 struct { Name string `json:"name"` Description string `json:"description"` Priority *string `json:"priority"` + Tags tagmodels.TagsBasic `json:"tags,omitempty"` Git *codemodels.Git `json:"git"` BuildConfig map[string]interface{} `json:"buildConfig"` TemplateInfo *codemodels.TemplateInfo `json:"templateInfo"` diff --git a/core/controller/cluster/controller_basic.go b/core/controller/cluster/controller_basic.go index 04ba4830..1b759881 100644 --- a/core/controller/cluster/controller_basic.go +++ b/core/controller/cluster/controller_basic.go @@ -40,6 +40,7 @@ import ( membermodels "github.com/horizoncd/horizon/pkg/member/models" regionmodels "github.com/horizoncd/horizon/pkg/region/models" tagmanager "github.com/horizoncd/horizon/pkg/tag/manager" + tagmodels "github.com/horizoncd/horizon/pkg/tag/models" "github.com/horizoncd/horizon/pkg/util/jsonschema" "github.com/horizoncd/horizon/pkg/util/log" "github.com/horizoncd/horizon/pkg/util/mergemap" @@ -283,11 +284,17 @@ func (c *controller) GetCluster(ctx context.Context, clusterID uint) (_ *GetClus } } - // 7. transfer model + // 7. get tags + tags, err := c.tagMgr.ListByResourceTypeID(ctx, common.ResourceCluster, clusterID) + if err != nil { + return nil, err + } + + // 8. transfer model clusterResp := ofClusterModel(application, cluster, fullPath, envValue.Namespace, - clusterFiles.PipelineJSONBlob, clusterFiles.ApplicationJSONBlob) + clusterFiles.PipelineJSONBlob, clusterFiles.ApplicationJSONBlob, tags...) - // 8. get latest deployed commit + // 9. get latest deployed commit latestPR, err := c.pipelinerunMgr.GetLatestSuccessByClusterID(ctx, clusterID) if err != nil { return nil, err @@ -297,7 +304,7 @@ func (c *controller) GetCluster(ctx context.Context, clusterID uint) (_ *GetClus clusterResp.Image = latestPR.ImageURL } - // 9. get createdBy and updatedBy users + // 10. get createdBy and updatedBy users userMap, err := c.userManager.GetUserMapByIDs(ctx, []uint{cluster.CreatedBy, cluster.UpdatedBy}) if err != nil { return nil, err @@ -619,6 +626,9 @@ func (c *controller) UpdateCluster(ctx context.Context, clusterID uint, if err != nil { return nil, err } + + clusterModel, tags := r.toClusterModel(cluster, templateRelease, er) + // 4. if templateInput is not empty, validate templateInput and update templateInput in git repo if r.TemplateInput != nil { // merge cluster config and request config @@ -681,13 +691,26 @@ func (c *controller) UpdateCluster(ctx context.Context, clusterID uint, } // 5. update cluster in db - clusterModel := r.toClusterModel(cluster, templateRelease, er) // todo: atomicity cluster, err = c.clusterMgr.UpdateByID(ctx, clusterID, clusterModel) if err != nil { return nil, err } + // 7. update cluster tags + tagsInDB, err := c.tagMgr.ListByResourceTypeID(ctx, common.ResourceCluster, clusterID) + if err != nil { + return nil, err + } + if !tagmodels.Tags(tags).Eq(tagsInDB) { + if err := c.clusterGitRepo.UpdateTags(ctx, application.Name, cluster.Name, cluster.Template, tags); err != nil { + return nil, err + } + if err := c.tagMgr.UpsertByResourceTypeID(ctx, common.ResourceCluster, clusterID, tags); err != nil { + return nil, err + } + } + // 6. record event if _, err := c.eventMgr.CreateEvent(ctx, &eventmodels.Event{ EventSummary: eventmodels.EventSummary{ diff --git a/core/controller/cluster/controller_basic_v2.go b/core/controller/cluster/controller_basic_v2.go index 3ed2d1b7..087f73b7 100644 --- a/core/controller/cluster/controller_basic_v2.go +++ b/core/controller/cluster/controller_basic_v2.go @@ -21,7 +21,6 @@ import ( "github.com/horizoncd/horizon/core/common" "github.com/horizoncd/horizon/core/controller/build" - controllertag "github.com/horizoncd/horizon/core/controller/tag" herrors "github.com/horizoncd/horizon/core/errors" appgitrepo "github.com/horizoncd/horizon/pkg/application/gitrepo" appmodels "github.com/horizoncd/horizon/pkg/application/models" @@ -29,6 +28,7 @@ import ( "github.com/horizoncd/horizon/pkg/cluster/gitrepo" collectionmodels "github.com/horizoncd/horizon/pkg/collection/models" eventmodels "github.com/horizoncd/horizon/pkg/event/models" + tagmodels "github.com/horizoncd/horizon/pkg/tag/models" "github.com/horizoncd/horizon/pkg/templaterelease/models" templateschema "github.com/horizoncd/horizon/pkg/templaterelease/schema" "github.com/horizoncd/horizon/pkg/util/jsonschema" @@ -314,16 +314,7 @@ func (c *controller) GetClusterV2(ctx context.Context, clusterID uint) (*GetClus FullPath: fullPath, ApplicationName: application.Name, ApplicationID: application.ID, - Tags: func() []controllertag.Tag { - retTags := make([]controllertag.Tag, 0, len(tags)) - for _, tag := range retTags { - retTags = append(retTags, controllertag.Tag{ - Key: tag.Key, - Value: tag.Value, - }) - } - return retTags - }(), + Tags: tagmodels.Tags(tags).IntoTagsBasic(), Git: func() *codemodels.Git { if cluster.GitURL == "" { return nil @@ -509,12 +500,26 @@ func (c *controller) UpdateClusterV2(ctx context.Context, clusterID uint, } // 8. update cluster in db - clusterModel := r.toClusterModel(cluster, expireSeconds, environmentName, + clusterModel, tags := r.toClusterModel(cluster, expireSeconds, environmentName, regionName, templateInfo.Name, templateInfo.Release) _, err = c.clusterMgr.UpdateByID(ctx, clusterID, clusterModel) if err != nil { return err } + + // 9. update cluster tags + tagsInDB, err := c.tagMgr.ListByResourceTypeID(ctx, common.ResourceCluster, clusterID) + if err != nil { + return err + } + if !tagmodels.Tags(tags).Eq(tagsInDB) { + if err := c.clusterGitRepo.UpdateTags(ctx, application.Name, cluster.Name, cluster.Template, tags); err != nil { + return err + } + if err := c.tagMgr.UpsertByResourceTypeID(ctx, common.ResourceCluster, clusterID, tags); err != nil { + return err + } + } return nil } diff --git a/core/controller/cluster/models_basic.go b/core/controller/cluster/models_basic.go index 5e5240fc..25e07df5 100644 --- a/core/controller/cluster/models_basic.go +++ b/core/controller/cluster/models_basic.go @@ -17,7 +17,6 @@ package cluster import ( "time" - controllertag "github.com/horizoncd/horizon/core/controller/tag" appmodels "github.com/horizoncd/horizon/pkg/application/models" codemodels "github.com/horizoncd/horizon/pkg/cluster/code" "github.com/horizoncd/horizon/pkg/cluster/models" @@ -27,11 +26,11 @@ import ( ) type Base struct { - Description string `json:"description"` - Git *codemodels.Git `json:"git"` - Template *Template `json:"template"` - TemplateInput *TemplateInput `json:"templateInput"` - Tags []*controllertag.Tag `json:"tags"` + Description string `json:"description"` + Git *codemodels.Git `json:"git"` + Template *Template `json:"template"` + TemplateInput *TemplateInput `json:"templateInput"` + Tags []*tagmodels.TagBasic `json:"tags"` } type TemplateInput struct { @@ -136,7 +135,7 @@ func (r *CreateClusterRequest) toClusterModel(application *appmodels.Application } func (r *UpdateClusterRequest) toClusterModel(cluster *models.Cluster, - templateRelease string, er *envregionmodels.EnvironmentRegion) *models.Cluster { + templateRelease string, er *envregionmodels.EnvironmentRegion) (*models.Cluster, []*tagmodels.Tag) { var gitURL, gitSubfolder, gitRef, gitRefType string if r.Git != nil { gitURL, gitSubfolder, gitRefType, gitRef = r.Git.URL, @@ -148,6 +147,14 @@ func (r *UpdateClusterRequest) toClusterModel(cluster *models.Cluster, gitRef = cluster.GitRef } + tags := make([]*tagmodels.Tag, 0) + for _, tag := range r.Tags { + tags = append(tags, &tagmodels.Tag{ + Key: tag.Key, + Value: tag.Value, + }) + } + return &models.Cluster{ EnvironmentName: er.EnvironmentName, RegionName: er.RegionName, @@ -160,7 +167,7 @@ func (r *UpdateClusterRequest) toClusterModel(cluster *models.Cluster, TemplateRelease: templateRelease, Status: cluster.Status, ExpireSeconds: cluster.ExpireSeconds, - } + }, tags } func getUserFromMap(id uint, userMap map[uint]*usermodels.User) *usermodels.User { @@ -183,15 +190,17 @@ func toUser(user *usermodels.User) *User { } func ofClusterModel(application *appmodels.Application, cluster *models.Cluster, fullPath, namespace string, - pipelineJSONBlob, applicationJSONBlob map[string]interface{}) *GetClusterResponse { + pipelineJSONBlob, applicationJSONBlob map[string]interface{}, tags ...*tagmodels.Tag) *GetClusterResponse { expireTime := "" if cluster.ExpireSeconds > 0 { expireTime = time.Duration(cluster.ExpireSeconds * 1e9).String() } + return &GetClusterResponse{ CreateClusterRequest: &CreateClusterRequest{ Base: &Base{ Description: cluster.Description, + Tags: tagmodels.Tags(tags).IntoTagsBasic(), Git: codemodels.NewGit(cluster.GitURL, cluster.GitSubfolder, cluster.GitRefType, cluster.GitRef), TemplateInput: &TemplateInput{ diff --git a/core/controller/cluster/models_basic_v2.go b/core/controller/cluster/models_basic_v2.go index a68d8417..5ad80e2b 100644 --- a/core/controller/cluster/models_basic_v2.go +++ b/core/controller/cluster/models_basic_v2.go @@ -116,6 +116,7 @@ type UpdateClusterRequestV2 struct { Environment *string `json:"environment"` Region *string `json:"region"` + Tags []*controllertag.Tag `json:"tags"` // source info Git *codemodels.Git `json:"git"` @@ -126,7 +127,7 @@ type UpdateClusterRequestV2 struct { } func (r *UpdateClusterRequestV2) toClusterModel(cluster *models.Cluster, expireSeconds uint, environmentName, - regionName, templateName, templateRelease string) *models.Cluster { + regionName, templateName, templateRelease string) (*models.Cluster, []*tagmodels.Tag) { var gitURL, gitSubFolder, gitRef, gitRefType string if r.Git != nil { gitURL, gitSubFolder, gitRefType, gitRef = r.Git.URL, @@ -137,6 +138,15 @@ func (r *UpdateClusterRequestV2) toClusterModel(cluster *models.Cluster, expireS gitRefType = cluster.GitRefType gitRef = cluster.GitRef } + + tags := make([]*tagmodels.Tag, 0) + for _, tag := range r.Tags { + tags = append(tags, &tagmodels.Tag{ + Key: tag.Key, + Value: tag.Value, + }) + } + return &models.Cluster{ EnvironmentName: environmentName, RegionName: regionName, @@ -148,21 +158,21 @@ func (r *UpdateClusterRequestV2) toClusterModel(cluster *models.Cluster, expireS GitRefType: gitRefType, Template: templateName, TemplateRelease: templateRelease, - } + }, tags } type GetClusterResponseV2 struct { // basic infos - ID uint `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - Priority string `json:"priority"` - ExpireTime string `json:"expireTime"` - Scope *Scope `json:"scope"` - FullPath string `json:"fullPath"` - ApplicationName string `json:"applicationName"` - ApplicationID uint `json:"applicationID"` - Tags []controllertag.Tag `json:"tags"` + ID uint `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Priority string `json:"priority"` + ExpireTime string `json:"expireTime"` + Scope *Scope `json:"scope"` + FullPath string `json:"fullPath"` + ApplicationName string `json:"applicationName"` + ApplicationID uint `json:"applicationID"` + Tags []*tagmodels.TagBasic `json:"tags"` // source info Git *codemodels.Git `json:"git"` diff --git a/pkg/cluster/dao/dao.go b/pkg/cluster/dao/dao.go index a7fe044b..57152eb4 100644 --- a/pkg/cluster/dao/dao.go +++ b/pkg/cluster/dao/dao.go @@ -29,6 +29,7 @@ import ( "github.com/horizoncd/horizon/pkg/rbac/role" tagmodels "github.com/horizoncd/horizon/pkg/tag/models" usermodels "github.com/horizoncd/horizon/pkg/user/models" + "gorm.io/gorm/clause" "gorm.io/gorm" ) @@ -110,7 +111,18 @@ func (d *dao) Create(ctx context.Context, cluster *models.Cluster, tags[i].ResourceID = cluster.ID } - result = tx.Create(tags) + result = tx.Clauses(clause.OnConflict{ + Columns: []clause.Column{ + { + Name: "resource_type", + }, { + Name: "resource_id", + }, { + Name: "tag_key", + }, + }, + DoUpdates: clause.AssignmentColumns([]string{"tag_value"}), + }).Create(tags) if result.Error != nil { return herrors.NewErrInsertFailed(herrors.ClusterInDB, result.Error.Error()) } diff --git a/pkg/tag/manager/manager.go b/pkg/tag/manager/manager.go index 6383503c..d4996064 100644 --- a/pkg/tag/manager/manager.go +++ b/pkg/tag/manager/manager.go @@ -62,6 +62,10 @@ func (m *manager) ListByResourceTypeIDs(ctx context.Context, resourceType string func (m *manager) UpsertByResourceTypeID(ctx context.Context, resourceType string, resourceID uint, tags []*models.Tag) error { + for _, tag := range tags { + tag.ResourceID = resourceID + tag.ResourceType = resourceType + } return m.dao.UpsertByResourceTypeID(ctx, resourceType, resourceID, tags) } diff --git a/pkg/tag/models/tag.go b/pkg/tag/models/tag.go index 8cc6b911..4b6c52e4 100644 --- a/pkg/tag/models/tag.go +++ b/pkg/tag/models/tag.go @@ -18,6 +18,7 @@ package models import ( "time" + "github.com/horizoncd/horizon/pkg/member/models" "github.com/horizoncd/horizon/pkg/util/sets" ) @@ -33,6 +34,56 @@ type Tag struct { UpdatedBy uint } +type Tags []*Tag + +func (t Tags) IntoTagsBasic() TagsBasic { + tags := make(TagsBasic, 0, len(t)) + for _, tag := range t { + tags = append(tags, &TagBasic{ + Key: tag.Key, + Value: tag.Value, + }) + } + return tags +} + +func (t Tags) Eq(rhs Tags) bool { + if len(t) != len(rhs) { + return false + } + index := make(map[TagBasic]struct{}) + for _, tag := range t { + index[TagBasic{ + Key: tag.Key, + Value: tag.Value, + }] = struct{}{} + } + for _, tag := range rhs { + if _, ok := index[TagBasic{ + Key: tag.Key, + Value: tag.Value, + }]; !ok { + return false + } + } + return true +} + +type TagsBasic []*TagBasic + +func (t TagsBasic) IntoTags(resourceType models.ResourceType, resourceID uint) []*Tag { + tags := make([]*Tag, 0, len(t)) + for _, tag := range t { + tags = append(tags, &Tag{ + ResourceType: string(resourceType), + ResourceID: resourceID, + Key: tag.Key, + Value: tag.Value, + }) + } + return tags +} + type TagBasic struct { Key string `json:"key"` Value string `json:"value"` From daee22bd72e7e932e293c69f99823681718c9324 Mon Sep 17 00:00:00 2001 From: closetool Date: Mon, 22 May 2023 20:21:45 +0800 Subject: [PATCH 2/3] fix: unit-test Signed-off-by: closetool --- .../controller/application/controller_test.go | 6 ++ .../applicationregion/controller_test.go | 4 +- core/controller/cluster/controller_basic.go | 2 +- core/controller/cluster/controller_test.go | 96 ++++++++++++++++--- core/controller/cluster/models_basic_v2.go | 35 ++++--- 5 files changed, 110 insertions(+), 33 deletions(-) diff --git a/core/controller/application/controller_test.go b/core/controller/application/controller_test.go index 387f9e66..f0dec741 100644 --- a/core/controller/application/controller_test.go +++ b/core/controller/application/controller_test.go @@ -37,6 +37,7 @@ import ( membermodels "github.com/horizoncd/horizon/pkg/member/models" "github.com/horizoncd/horizon/pkg/param/managerparam" regionmodels "github.com/horizoncd/horizon/pkg/region/models" + tagmodels "github.com/horizoncd/horizon/pkg/tag/models" tmodels "github.com/horizoncd/horizon/pkg/template/models" trmodels "github.com/horizoncd/horizon/pkg/templaterelease/models" trschema "github.com/horizoncd/horizon/pkg/templaterelease/schema" @@ -286,6 +287,9 @@ func TestMain(m *testing.M) { if err := db.AutoMigrate(&membermodels.Member{}); err != nil { panic(err) } + if err := db.AutoMigrate(&tagmodels.Tag{}); err != nil { + panic(err) + } if err := db.AutoMigrate(&eventmodels.Event{}); err != nil { panic(err) } @@ -351,6 +355,7 @@ func Test(t *testing.T) { c = &controller{ applicationGitRepo: applicationGitRepo, templateSchemaGetter: templateSchemaGetter, + tagMgr: manager.TagManager, applicationMgr: manager.ApplicationManager, groupMgr: manager.GroupManager, groupSvc: groupservice.NewService(manager), @@ -506,6 +511,7 @@ func TestV2(t *testing.T) { applicationGitRepo: applicationGitRepo, templateSchemaGetter: templateSchemaGetter, applicationMgr: manager.ApplicationManager, + tagMgr: manager.TagManager, groupMgr: manager.GroupManager, groupSvc: groupservice.NewService(manager), templateReleaseMgr: manager.TemplateReleaseManager, diff --git a/core/controller/applicationregion/controller_test.go b/core/controller/applicationregion/controller_test.go index 0515cf15..6f54a3a9 100644 --- a/core/controller/applicationregion/controller_test.go +++ b/core/controller/applicationregion/controller_test.go @@ -90,7 +90,7 @@ func Test(t *testing.T) { }, }) assert.Nil(t, err) - err = manager.TagManager.UpsertByResourceTypeID(ctx, common.ResourceRegion, r1.ID, []*tagmodels.Tag{ + err = manager.TagManager.UpsertByResourceTypeID(ctx, common.ResourceRegion, r2.ID, []*tagmodels.Tag{ { ResourceID: r2.ID, ResourceType: common.ResourceRegion, @@ -99,7 +99,7 @@ func Test(t *testing.T) { }, }) assert.Nil(t, err) - err = manager.TagManager.UpsertByResourceTypeID(ctx, common.ResourceRegion, r1.ID, []*tagmodels.Tag{ + err = manager.TagManager.UpsertByResourceTypeID(ctx, common.ResourceRegion, r3.ID, []*tagmodels.Tag{ { ResourceID: r3.ID, ResourceType: common.ResourceRegion, diff --git a/core/controller/cluster/controller_basic.go b/core/controller/cluster/controller_basic.go index 1b759881..6b8a1367 100644 --- a/core/controller/cluster/controller_basic.go +++ b/core/controller/cluster/controller_basic.go @@ -738,7 +738,7 @@ func (c *controller) UpdateCluster(ctx context.Context, clusterID uint, } return ofClusterModel(application, cluster, fullPath, envValue.Namespace, - r.TemplateInput.Pipeline, r.TemplateInput.Application), nil + r.TemplateInput.Pipeline, r.TemplateInput.Application, tags...), nil } func (c *controller) GetClusterByName(ctx context.Context, diff --git a/core/controller/cluster/controller_test.go b/core/controller/cluster/controller_test.go index 9c5c28de..706f8cc5 100644 --- a/core/controller/cluster/controller_test.go +++ b/core/controller/cluster/controller_test.go @@ -45,7 +45,6 @@ import ( registryftymock "github.com/horizoncd/horizon/mock/pkg/cluster/registry/factory" tektonmock "github.com/horizoncd/horizon/mock/pkg/cluster/tekton" tektonftymock "github.com/horizoncd/horizon/mock/pkg/cluster/tekton/factory" - tagmock "github.com/horizoncd/horizon/mock/pkg/tag/manager" outputmock "github.com/horizoncd/horizon/mock/pkg/templaterelease/output" trschemamock "github.com/horizoncd/horizon/mock/pkg/templaterelease/schema" appgitrepo "github.com/horizoncd/horizon/pkg/application/gitrepo" @@ -74,11 +73,12 @@ import ( registrydao "github.com/horizoncd/horizon/pkg/registry/dao" registrymodels "github.com/horizoncd/horizon/pkg/registry/models" "github.com/horizoncd/horizon/pkg/server/global" + tagmodels "github.com/horizoncd/horizon/pkg/tag/models" tmodel "github.com/horizoncd/horizon/pkg/tag/models" trmodels "github.com/horizoncd/horizon/pkg/templaterelease/models" trschema "github.com/horizoncd/horizon/pkg/templaterelease/schema" gitlabschema "github.com/horizoncd/horizon/pkg/templaterelease/schema/gitlab" - tagmodel "github.com/horizoncd/horizon/pkg/templateschematag/models" + schematagmodel "github.com/horizoncd/horizon/pkg/templateschematag/models" tokenmodels "github.com/horizoncd/horizon/pkg/token/models" tokenservice "github.com/horizoncd/horizon/pkg/token/service" usermodels "github.com/horizoncd/horizon/pkg/user/models" @@ -453,7 +453,7 @@ func TestMain(m *testing.M) { &trmodels.TemplateRelease{}, &membermodels.Member{}, &usermodels.User{}, ®istrymodels.Registry{}, eventmodels.Event{}, ®ionmodels.Region{}, &envregionmodels.EnvironmentRegion{}, &eventmodels.Event{}, - &prmodels.Pipelinerun{}, &tagmodel.ClusterTemplateSchemaTag{}, &tmodel.Tag{}, + &prmodels.Pipelinerun{}, &schematagmodel.ClusterTemplateSchemaTag{}, &tmodel.Tag{}, &envmodels.Environment{}, &tokenmodels.Token{}); err != nil { panic(err) } @@ -526,7 +526,7 @@ func test(t *testing.T) { tektonFty := tektonftymock.NewMockFactory(mockCtl) registryFty := registryftymock.NewMockRegistryGetter(mockCtl) commitGetter := commitmock.NewMockGitGetter(mockCtl) - tagManager := tagmock.NewMockManager(mockCtl) + tagManager := manager.TagManager templateSchemaGetter := trschemamock.NewMockGetter(mockCtl) expectparams := make(map[string]string) @@ -656,7 +656,6 @@ func test(t *testing.T) { } commitGetter.EXPECT().GetHTTPLink(gomock.Any()).Return("https://cloudnative.com:22222/demo/springboot-demo", nil).AnyTimes() - tagManager.EXPECT().ListByResourceTypeIDs(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes() applicationGitRepo.EXPECT().GetApplication(ctx, gomock.Any(), gomock.Any()). Return(&appgitrepo.GetResponse{ Manifest: nil, @@ -691,6 +690,8 @@ func test(t *testing.T) { clusterGitRepo.EXPECT().DefaultBranch().Return("master").AnyTimes() cd.EXPECT().CreateCluster(ctx, gomock.Any()).Return(nil).AnyTimes() + clusterGitRepo.EXPECT().UpdateTags(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() + createClusterRequest := &CreateClusterRequest{ Base: &Base{ Description: "cluster description", @@ -701,6 +702,12 @@ func test(t *testing.T) { Application: applicationJSONBlob, Pipeline: pipelineJSONBlob, }, + Tags: tagmodels.TagsBasic{ + { + Key: "key1", + Value: "value1", + }, + }, }, Name: "app-cluster", ExpireTime: "24h0m0s", @@ -731,6 +738,12 @@ func test(t *testing.T) { Subfolder: "/new", Branch: "new", }, + Tags: tagmodels.TagsBasic{ + { + Key: "key1", + Value: "value2", + }, + }, TemplateInput: &TemplateInput{ Application: applicationJSONBlob, Pipeline: pipelineJSONBlob, @@ -760,6 +773,8 @@ func test(t *testing.T) { // NOTE: template name cannot be edited! template release can be edited assert.Equal(t, resp.Template.Name, "javaapp") assert.Equal(t, resp.Template.Release, "v1.0.1") + assert.Equal(t, 1, len(resp.Base.Tags)) + assert.Equal(t, "value2", resp.Base.Tags[0].Value) resp, err = c.GetCluster(ctx, resp.ID) assert.Nil(t, err) @@ -773,6 +788,8 @@ func test(t *testing.T) { assert.Equal(t, resp.Template.Release, "v1.0.1") assert.Equal(t, resp.TemplateInput.Application, applicationJSONBlob) assert.Equal(t, resp.TemplateInput.Pipeline, pipelineJSONBlob) + assert.Equal(t, 1, len(resp.Base.Tags)) + assert.Equal(t, "value2", resp.Base.Tags[0].Value) resp, err = c.UpdateCluster(ctx, resp.ID, &UpdateClusterRequest{ Base: &Base{}, @@ -782,6 +799,7 @@ func test(t *testing.T) { resp, err = c.GetCluster(ctx, resp.ID) assert.Nil(t, err) assert.Equal(t, "48h0m0s", resp.ExpireTime) + assert.Equal(t, 0, len(resp.Base.Tags)) count, respList, err := c.ListByApplication(ctx, q.New(q.KeyWords{ @@ -1249,7 +1267,6 @@ func testV2(t *testing.T) { clusterGitRepo := clustergitrepomock.NewMockClusterGitRepo(mockCtl) applicationGitRepo := applicationgitrepomock.NewMockApplicationGitRepo2(mockCtl) templateSchemaGetter := trschemamock.NewMockGetter(mockCtl) - tagManager := tagmock.NewMockManager(mockCtl) registryFty := registryftymock.NewMockRegistryGetter(mockCtl) mockCd := cdmock.NewMockCD(mockCtl) @@ -1270,6 +1287,48 @@ func testV2(t *testing.T) { groupMgr := manager.GroupManager envRegionMgr := manager.EnvRegionMgr + registryDAO := registrydao.NewDAO(db) + id, err := registryDAO.Create(ctx, ®istrymodels.Registry{ + Server: "https://harbor.com", + Token: "xxx", + }) + assert.Nil(t, err) + assert.NotNil(t, id) + + region, err := regionMgr.Create(ctx, ®ionmodels.Region{ + Name: "hz", + DisplayName: "HZ", + RegistryID: id, + }) + assert.Nil(t, err) + assert.NotNil(t, region) + + er, err := envRegionMgr.CreateEnvironmentRegion(ctx, &envregionmodels.EnvironmentRegion{ + EnvironmentName: "test2", + RegionName: "hz", + }) + assert.Nil(t, err) + assert.NotNil(t, er) + er, err = envRegionMgr.CreateEnvironmentRegion(ctx, &envregionmodels.EnvironmentRegion{ + EnvironmentName: "dev2", + RegionName: "hz", + }) + assert.Nil(t, err) + assert.NotNil(t, er) + + env, err := envMgr.CreateEnvironment(ctx, &envmodels.Environment{ + Name: "dev2", + DisplayName: "开发", + }) + assert.Nil(t, err) + assert.NotNil(t, env) + env, err = envMgr.CreateEnvironment(ctx, &envmodels.Environment{ + Name: "test2", + DisplayName: "开发", + }) + assert.Nil(t, err) + assert.NotNil(t, env) + // init data group, err := groupMgr.Create(ctx, &groupmodels.Group{ Name: "group1", @@ -1319,11 +1378,11 @@ func testV2(t *testing.T) { groupSvc: groupservice.NewService(manager), pipelinerunMgr: manager.PipelinerunMgr, userManager: manager.UserManager, - autoFreeSvc: param.AutoFreeSvc, + autoFreeSvc: service.New([]string{"dev2", "test2"}), userSvc: userservice.NewService(manager), schemaTagManager: manager.ClusterSchemaTagMgr, applicationGitRepo: applicationGitRepo, - tagMgr: tagManager, + tagMgr: manager.TagManager, registryFty: registryFty, cd: mockCd, eventMgr: manager.EventManager, @@ -1344,6 +1403,12 @@ func testV2(t *testing.T) { Git: &codemodels.Git{ Branch: "develop", }, + Tags: tagmodels.TagsBasic{ + { + Key: "key1", + Value: "value1", + }, + }, BuildConfig: pipelineJSONBlob, TemplateInfo: &codemodels.TemplateInfo{ Name: templateName, @@ -1352,7 +1417,7 @@ func testV2(t *testing.T) { TemplateConfig: applicationJSONBlob, ExtraMembers: nil, } - resp, err := c.CreateClusterV2(ctx, application.ID, "test", "hz", createReq, false) + resp, err := c.CreateClusterV2(ctx, application.ID, "test2", "hz", createReq, false) assert.Nil(t, err) assert.NotNil(t, resp) assert.Equal(t, resp.ApplicationID, application.ID) @@ -1360,7 +1425,6 @@ func testV2(t *testing.T) { t.Logf("%+v", resp) // then get cluster - tagManager.EXPECT().ListByResourceTypeID(ctx, gomock.Any(), resp.ID).Return(nil, nil).Times(1) clusterGitRepo.EXPECT().GetCluster(ctx, applicationName, createClusterName, templateName).Return(&gitrepo.ClusterFiles{ PipelineJSONBlob: pipelineJSONBlob, ApplicationJSONBlob: applicationJSONBlob, @@ -1383,6 +1447,8 @@ func testV2(t *testing.T) { assert.Equal(t, getClusterResp.TemplateInfo.Release, templateVersion) assert.Nil(t, getClusterResp.Manifest) assert.Equal(t, getClusterResp.Status, "") + assert.Equal(t, 1, len(getClusterResp.Tags)) + assert.Equal(t, getClusterResp.Tags[0].Value, "value1") t.Logf("%+v", getClusterResp) // update v2 @@ -1393,6 +1459,12 @@ func testV2(t *testing.T) { }, nil).Times(1) updateRequestV2 := &UpdateClusterRequestV2{ + Tags: tagmodels.TagsBasic{ + { + Key: "key1", + Value: "value2", + }, + }, Description: "", ExpireTime: "336h0m0s", BuildConfig: pipelineJSONBlob, @@ -1414,6 +1486,7 @@ func testV2(t *testing.T) { Manifest: manifest, }, nil).Times(1) clusterGitRepo.EXPECT().UpdateCluster(ctx, gomock.Any()).Return(nil).Times(1) + clusterGitRepo.EXPECT().UpdateTags(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).Times(1) templateSchemaGetter.EXPECT().GetTemplateSchema(gomock.Any(), templateName, "v1.0.0", gomock.Any()). Return(&trschema.Schemas{ Application: &trschema.Schema{ @@ -1453,7 +1526,6 @@ func testUpgrade(t *testing.T) { clusterGitRepo := clustergitrepomock.NewMockClusterGitRepo(mockCtl) applicationGitRepo := applicationgitrepomock.NewMockApplicationGitRepo2(mockCtl) templateSchemaGetter := trschemamock.NewMockGetter(mockCtl) - tagManager := tagmock.NewMockManager(mockCtl) registryFty := registryftymock.NewMockRegistryGetter(mockCtl) mockCd := cdmock.NewMockCD(mockCtl) @@ -1528,7 +1600,7 @@ func testUpgrade(t *testing.T) { userSvc: userservice.NewService(manager), schemaTagManager: manager.ClusterSchemaTagMgr, applicationGitRepo: applicationGitRepo, - tagMgr: tagManager, + tagMgr: manager.TagManager, registryFty: registryFty, cd: mockCd, eventMgr: manager.EventManager, diff --git a/core/controller/cluster/models_basic_v2.go b/core/controller/cluster/models_basic_v2.go index 5ad80e2b..052867c4 100644 --- a/core/controller/cluster/models_basic_v2.go +++ b/core/controller/cluster/models_basic_v2.go @@ -18,7 +18,6 @@ import ( "time" "github.com/horizoncd/horizon/core/common" - controllertag "github.com/horizoncd/horizon/core/controller/tag" appmodels "github.com/horizoncd/horizon/pkg/application/models" codemodels "github.com/horizoncd/horizon/pkg/cluster/code" "github.com/horizoncd/horizon/pkg/cluster/models" @@ -27,12 +26,12 @@ import ( ) type CreateClusterRequestV2 struct { - Name string `json:"name"` - Description string `json:"description"` - Priority string `json:"priority"` - ExpireTime string `json:"expireTime"` - Git *codemodels.Git `json:"git"` - Tags []*controllertag.Tag `json:"tags"` + Name string `json:"name"` + Description string `json:"description"` + Priority string `json:"priority"` + ExpireTime string `json:"expireTime"` + Git *codemodels.Git `json:"git"` + Tags tagmodels.TagsBasic `json:"tags"` BuildConfig map[string]interface{} `json:"buildConfig"` TemplateInfo *codemodels.TemplateInfo `json:"templateInfo"` @@ -116,7 +115,7 @@ type UpdateClusterRequestV2 struct { Environment *string `json:"environment"` Region *string `json:"region"` - Tags []*controllertag.Tag `json:"tags"` + Tags tagmodels.TagsBasic `json:"tags"` // source info Git *codemodels.Git `json:"git"` @@ -163,16 +162,16 @@ func (r *UpdateClusterRequestV2) toClusterModel(cluster *models.Cluster, expireS type GetClusterResponseV2 struct { // basic infos - ID uint `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - Priority string `json:"priority"` - ExpireTime string `json:"expireTime"` - Scope *Scope `json:"scope"` - FullPath string `json:"fullPath"` - ApplicationName string `json:"applicationName"` - ApplicationID uint `json:"applicationID"` - Tags []*tagmodels.TagBasic `json:"tags"` + ID uint `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Priority string `json:"priority"` + ExpireTime string `json:"expireTime"` + Scope *Scope `json:"scope"` + FullPath string `json:"fullPath"` + ApplicationName string `json:"applicationName"` + ApplicationID uint `json:"applicationID"` + Tags tagmodels.TagsBasic `json:"tags"` // source info Git *codemodels.Git `json:"git"` From 691a2ea5e14c1afc5fe7ed06a2a0b855bf04a2c3 Mon Sep 17 00:00:00 2001 From: closetool Date: Mon, 22 May 2023 20:51:19 +0800 Subject: [PATCH 3/3] fix: some bugs Signed-off-by: closetool --- core/controller/application/controller.go | 12 ++-- .../applicationregion/controller_test.go | 24 +++----- core/controller/cluster/controller_basic.go | 2 +- .../controller/cluster/controller_basic_v2.go | 2 +- .../cluster/controller_operation.go | 10 ++-- core/controller/tag/controller.go | 2 +- core/controller/tag/controller_test.go | 16 +++--- core/controller/tag/models.go | 2 +- pkg/group/manager/manager_test.go | 44 ++++++--------- pkg/region/manager/manager_test.go | 42 +++++--------- pkg/tag/manager/manager.go | 15 +++-- pkg/tag/manager/manager_test.go | 56 +++++++------------ pkg/tag/models/tag.go | 19 +++++++ 13 files changed, 109 insertions(+), 137 deletions(-) diff --git a/core/controller/application/controller.go b/core/controller/application/controller.go index 4650c0a8..2f74b674 100644 --- a/core/controller/application/controller.go +++ b/core/controller/application/controller.go @@ -297,8 +297,7 @@ func (c *controller) CreateApplication(ctx context.Context, groupID uint, // 7. create tags if request.Tags != nil { - tags := request.Tags.IntoTags(common.ResourceApplication, applicationModel.ID) - err = c.tagMgr.UpsertByResourceTypeID(ctx, common.ResourceApplication, applicationModel.ID, tags) + err = c.tagMgr.UpsertByResourceTypeID(ctx, common.ResourceApplication, applicationModel.ID, request.Tags) if err != nil { return nil, err } @@ -412,8 +411,7 @@ func (c *controller) CreateApplicationV2(ctx context.Context, groupID uint, } if request.Tags != nil { - tags := request.Tags.IntoTags(common.ResourceApplication, applicationDBModel.ID) - err = c.tagMgr.UpsertByResourceTypeID(ctx, common.ResourceApplication, applicationDBModel.ID, tags) + err = c.tagMgr.UpsertByResourceTypeID(ctx, common.ResourceApplication, applicationDBModel.ID, request.Tags) if err != nil { return nil, err } @@ -518,8 +516,7 @@ func (c *controller) UpdateApplication(ctx context.Context, id uint, // 8. update tags if request.Tags != nil { - tags := request.Tags.IntoTags(common.ResourceApplication, applicationModel.ID) - err = c.tagMgr.UpsertByResourceTypeID(ctx, common.ResourceApplication, applicationModel.ID, tags) + err = c.tagMgr.UpsertByResourceTypeID(ctx, common.ResourceApplication, applicationModel.ID, request.Tags) if err != nil { return nil, err } @@ -575,8 +572,7 @@ func (c *controller) UpdateApplicationV2(ctx context.Context, id uint, // 5. update tags if request.Tags != nil { - tags := request.Tags.IntoTags(common.ResourceApplication, id) - err = c.tagMgr.UpsertByResourceTypeID(ctx, common.ResourceApplication, id, tags) + err = c.tagMgr.UpsertByResourceTypeID(ctx, common.ResourceApplication, id, request.Tags) if err != nil { return err } diff --git a/core/controller/applicationregion/controller_test.go b/core/controller/applicationregion/controller_test.go index 6f54a3a9..0b89c83e 100644 --- a/core/controller/applicationregion/controller_test.go +++ b/core/controller/applicationregion/controller_test.go @@ -81,30 +81,24 @@ func Test(t *testing.T) { }) assert.Nil(t, err) assert.NotNil(t, r3) - err = manager.TagManager.UpsertByResourceTypeID(ctx, common.ResourceRegion, r1.ID, []*tagmodels.Tag{ + err = manager.TagManager.UpsertByResourceTypeID(ctx, common.ResourceRegion, r1.ID, []*tagmodels.TagBasic{ { - ResourceID: r1.ID, - ResourceType: common.ResourceRegion, - Key: "a", - Value: "1", + Key: "a", + Value: "1", }, }) assert.Nil(t, err) - err = manager.TagManager.UpsertByResourceTypeID(ctx, common.ResourceRegion, r2.ID, []*tagmodels.Tag{ + err = manager.TagManager.UpsertByResourceTypeID(ctx, common.ResourceRegion, r2.ID, []*tagmodels.TagBasic{ { - ResourceID: r2.ID, - ResourceType: common.ResourceRegion, - Key: "a", - Value: "1", + Key: "a", + Value: "1", }, }) assert.Nil(t, err) - err = manager.TagManager.UpsertByResourceTypeID(ctx, common.ResourceRegion, r3.ID, []*tagmodels.Tag{ + err = manager.TagManager.UpsertByResourceTypeID(ctx, common.ResourceRegion, r3.ID, []*tagmodels.TagBasic{ { - ResourceID: r3.ID, - ResourceType: common.ResourceRegion, - Key: "a", - Value: "1", + Key: "a", + Value: "1", }, }) assert.Nil(t, err) diff --git a/core/controller/cluster/controller_basic.go b/core/controller/cluster/controller_basic.go index 6b8a1367..d9e44e98 100644 --- a/core/controller/cluster/controller_basic.go +++ b/core/controller/cluster/controller_basic.go @@ -706,7 +706,7 @@ func (c *controller) UpdateCluster(ctx context.Context, clusterID uint, if err := c.clusterGitRepo.UpdateTags(ctx, application.Name, cluster.Name, cluster.Template, tags); err != nil { return nil, err } - if err := c.tagMgr.UpsertByResourceTypeID(ctx, common.ResourceCluster, clusterID, tags); err != nil { + if err := c.tagMgr.UpsertByResourceTypeID(ctx, common.ResourceCluster, clusterID, r.Tags); err != nil { return nil, err } } diff --git a/core/controller/cluster/controller_basic_v2.go b/core/controller/cluster/controller_basic_v2.go index 087f73b7..740cb1e9 100644 --- a/core/controller/cluster/controller_basic_v2.go +++ b/core/controller/cluster/controller_basic_v2.go @@ -516,7 +516,7 @@ func (c *controller) UpdateClusterV2(ctx context.Context, clusterID uint, if err := c.clusterGitRepo.UpdateTags(ctx, application.Name, cluster.Name, cluster.Template, tags); err != nil { return err } - if err := c.tagMgr.UpsertByResourceTypeID(ctx, common.ResourceCluster, clusterID, tags); err != nil { + if err := c.tagMgr.UpsertByResourceTypeID(ctx, common.ResourceCluster, clusterID, r.Tags); err != nil { return err } } diff --git a/core/controller/cluster/controller_operation.go b/core/controller/cluster/controller_operation.go index 2dbb699e..693b57b6 100644 --- a/core/controller/cluster/controller_operation.go +++ b/core/controller/cluster/controller_operation.go @@ -734,17 +734,15 @@ func (c *controller) updateTemplateAndTagsFromFile(ctx context.Context, } midMap := file.Content[release.ChartName].(map[string]interface{}) tagsMap := midMap[common.GitopsKeyTags].(map[string]interface{}) - tags := make([]*tmodels.Tag, 0, len(tagsMap)) + tags := make([]*tmodels.TagBasic, 0, len(tagsMap)) for k, v := range tagsMap { value, ok := v.(string) if !ok { continue } - tags = append(tags, &tmodels.Tag{ - ResourceID: cluster.ID, - ResourceType: common.ResourceCluster, - Key: k, - Value: value, + tags = append(tags, &tmodels.TagBasic{ + Key: k, + Value: value, }) } return cluster, c.tagMgr.UpsertByResourceTypeID(ctx, diff --git a/core/controller/tag/controller.go b/core/controller/tag/controller.go index 39727c4e..66473a76 100644 --- a/core/controller/tag/controller.go +++ b/core/controller/tag/controller.go @@ -93,7 +93,7 @@ func (c *controller) Update(ctx context.Context, resourceType string, resourceID } } - return c.tagMgr.UpsertByResourceTypeID(ctx, resourceType, resourceID, tags) + return c.tagMgr.UpsertByResourceTypeID(ctx, resourceType, resourceID, r.Tags) } func (c *controller) ListSubResourceTags(ctx context.Context, resourceType string, diff --git a/core/controller/tag/controller_test.go b/core/controller/tag/controller_test.go index 9c54dc55..4d1adb78 100644 --- a/core/controller/tag/controller_test.go +++ b/core/controller/tag/controller_test.go @@ -116,7 +116,7 @@ func Test(t *testing.T) { clusterID := cluster.ID err = c.Update(ctx, common.ResourceCluster, clusterID, &UpdateRequest{ - Tags: []*Tag{ + Tags: []*tagmodels.TagBasic{ { Key: "a", Value: "1", @@ -137,7 +137,7 @@ func Test(t *testing.T) { assert.Equal(t, "2", resp.Tags[1].Value) err = c.Update(ctx, common.ResourceCluster, clusterID, &UpdateRequest{ - Tags: []*Tag{ + Tags: []*tagmodels.TagBasic{ { Key: "a", Value: "1", @@ -158,7 +158,7 @@ func Test(t *testing.T) { assert.Equal(t, "3", resp.Tags[1].Value) err = c.Update(ctx, common.ResourceCluster, clusterID, &UpdateRequest{ - Tags: []*Tag{ + Tags: []*tagmodels.TagBasic{ { Key: "a", Value: "1", @@ -184,7 +184,7 @@ func Test(t *testing.T) { assert.Equal(t, "4", resp.Tags[2].Value) err = c.Update(ctx, common.ResourceCluster, clusterID, &UpdateRequest{ - Tags: []*Tag{ + Tags: []*tagmodels.TagBasic{ { Key: "d", Value: "4", @@ -200,7 +200,7 @@ func Test(t *testing.T) { assert.Equal(t, "4", resp.Tags[0].Value) err = c.Update(ctx, common.ResourceCluster, clusterID, &UpdateRequest{ - Tags: []*Tag{}, + Tags: []*tagmodels.TagBasic{}, }) assert.Nil(t, err) @@ -208,9 +208,9 @@ func Test(t *testing.T) { assert.Nil(t, err) assert.Equal(t, 0, len(resp.Tags)) - tags := make([]*Tag, 0) + tags := make([]*tagmodels.TagBasic, 0) for i := 0; i < 21; i++ { - tags = append(tags, &Tag{ + tags = append(tags, &tagmodels.TagBasic{ Key: strconv.Itoa(i), Value: strconv.Itoa(i), }) @@ -231,7 +231,7 @@ func Test(t *testing.T) { assert.Nil(t, err) err = c.Update(ctx, common.ResourceCluster, cluster2.ID, &UpdateRequest{ - Tags: []*Tag{ + Tags: []*tagmodels.TagBasic{ { Key: "d", Value: "4", diff --git a/core/controller/tag/models.go b/core/controller/tag/models.go index 9fe7a598..5cc9936b 100644 --- a/core/controller/tag/models.go +++ b/core/controller/tag/models.go @@ -28,7 +28,7 @@ type Tag struct { } type UpdateRequest struct { - Tags []*Tag `json:"tags"` + Tags []*tagmodels.TagBasic `json:"tags"` } func (r *UpdateRequest) toTags(resourceType string, resourceID uint) []*tagmodels.Tag { diff --git a/pkg/group/manager/manager_test.go b/pkg/group/manager/manager_test.go index 3d770bcd..5cb67cd6 100644 --- a/pkg/group/manager/manager_test.go +++ b/pkg/group/manager/manager_test.go @@ -511,30 +511,22 @@ func Test_manager_GetSelectableRegionsByEnv(t *testing.T) { EnvironmentName: devEnv.Name, RegionName: "hz3", }) - _ = tagMgr.UpsertByResourceTypeID(ctx, common.ResourceRegion, r1.ID, []*tagmodels.Tag{ + _ = tagMgr.UpsertByResourceTypeID(ctx, common.ResourceRegion, r1.ID, []*tagmodels.TagBasic{ { - ResourceType: common.ResourceRegion, - ResourceID: r1.ID, - Key: "a", - Value: "1", + Key: "a", + Value: "1", }, { - ResourceType: common.ResourceRegion, - ResourceID: r1.ID, - Key: "b", - Value: "1", + Key: "b", + Value: "1", }, }) - _ = tagMgr.UpsertByResourceTypeID(ctx, common.ResourceRegion, r3.ID, []*tagmodels.Tag{ + _ = tagMgr.UpsertByResourceTypeID(ctx, common.ResourceRegion, r3.ID, []*tagmodels.TagBasic{ { - ResourceType: common.ResourceRegion, - ResourceID: r3.ID, - Key: "a", - Value: "1", + Key: "a", + Value: "1", }, { - ResourceType: common.ResourceRegion, - ResourceID: r3.ID, - Key: "c", - Value: "1", + Key: "c", + Value: "1", }, }) g1, err := Mgr.Create(ctx, &models.Group{ @@ -617,20 +609,16 @@ func Test_manager_GetSelectableRegions(t *testing.T) { DisplayName: "HZ", }) - _ = tagMgr.UpsertByResourceTypeID(ctx, common.ResourceRegion, r1.ID, []*tagmodels.Tag{ + _ = tagMgr.UpsertByResourceTypeID(ctx, common.ResourceRegion, r1.ID, []*tagmodels.TagBasic{ { - ResourceType: common.ResourceRegion, - ResourceID: r1.ID, - Key: "a", - Value: "11", + Key: "a", + Value: "11", }, }) - _ = tagMgr.UpsertByResourceTypeID(ctx, common.ResourceRegion, r3.ID, []*tagmodels.Tag{ + _ = tagMgr.UpsertByResourceTypeID(ctx, common.ResourceRegion, r3.ID, []*tagmodels.TagBasic{ { - ResourceType: common.ResourceRegion, - ResourceID: r3.ID, - Key: "a", - Value: "11", + Key: "a", + Value: "11", }, }) diff --git a/pkg/region/manager/manager_test.go b/pkg/region/manager/manager_test.go index 741c3c3b..0a27ab7d 100644 --- a/pkg/region/manager/manager_test.go +++ b/pkg/region/manager/manager_test.go @@ -181,48 +181,36 @@ func Test_manager_ListByRegionSelectors(t *testing.T) { }) assert.Nil(t, err) - err = tagMgr.UpsertByResourceTypeID(ctx, common.ResourceRegion, r1.ID, []*tagmodels.Tag{ + err = tagMgr.UpsertByResourceTypeID(ctx, common.ResourceRegion, r1.ID, []*tagmodels.TagBasic{ { - ResourceID: r1.ID, - ResourceType: common.ResourceRegion, - Key: "a", - Value: "1", + Key: "a", + Value: "1", }, { - ResourceID: r1.ID, - ResourceType: common.ResourceRegion, - Key: "b", - Value: "2", + Key: "b", + Value: "2", }, }) assert.Nil(t, err) - err = tagMgr.UpsertByResourceTypeID(ctx, common.ResourceRegion, r2.ID, []*tagmodels.Tag{ + err = tagMgr.UpsertByResourceTypeID(ctx, common.ResourceRegion, r2.ID, []*tagmodels.TagBasic{ { - ResourceID: r2.ID, - ResourceType: common.ResourceRegion, - Key: "a", - Value: "1", + Key: "a", + Value: "1", }, { - ResourceID: r2.ID, - ResourceType: common.ResourceRegion, - Key: "b", - Value: "2", + Key: "b", + Value: "2", }, }) assert.Nil(t, err) - err = tagMgr.UpsertByResourceTypeID(ctx, common.ResourceRegion, r3.ID, []*tagmodels.Tag{ + err = tagMgr.UpsertByResourceTypeID(ctx, common.ResourceRegion, r3.ID, []*tagmodels.TagBasic{ { - ResourceID: r3.ID, - ResourceType: common.ResourceRegion, - Key: "a", - Value: "2", + Key: "a", + Value: "2", }, { - ResourceID: r3.ID, - ResourceType: common.ResourceRegion, - Key: "b", - Value: "2", + Key: "b", + Value: "2", }, }) assert.Nil(t, err) diff --git a/pkg/tag/manager/manager.go b/pkg/tag/manager/manager.go index d4996064..593d5956 100644 --- a/pkg/tag/manager/manager.go +++ b/pkg/tag/manager/manager.go @@ -34,7 +34,7 @@ type Manager interface { ListByResourceTypeIDs(ctx context.Context, resourceType string, resourceIDs []uint, deduplicate bool) ([]*models.Tag, error) // UpsertByResourceTypeID upsert tags - UpsertByResourceTypeID(ctx context.Context, resourceType string, resourceID uint, tags []*models.Tag) error + UpsertByResourceTypeID(ctx context.Context, resourceType string, resourceID uint, tags []*models.TagBasic) error CreateMetatags(ctx context.Context, metatags []*models.Metatag) error GetMetatagKeys(ctx context.Context) ([]string, error) GetMetatagsByKey(ctx context.Context, key string) ([]*models.Metatag, error) @@ -61,10 +61,15 @@ func (m *manager) ListByResourceTypeIDs(ctx context.Context, resourceType string } func (m *manager) UpsertByResourceTypeID(ctx context.Context, - resourceType string, resourceID uint, tags []*models.Tag) error { - for _, tag := range tags { - tag.ResourceID = resourceID - tag.ResourceType = resourceType + resourceType string, resourceID uint, tagsBasic []*models.TagBasic) error { + tags := make([]*models.Tag, 0, len(tagsBasic)) + for _, tag := range tagsBasic { + tags = append(tags, &models.Tag{ + Key: tag.Key, + Value: tag.Value, + ResourceID: resourceID, + ResourceType: resourceType, + }) } return m.dao.UpsertByResourceTypeID(ctx, resourceType, resourceID, tags) } diff --git a/pkg/tag/manager/manager_test.go b/pkg/tag/manager/manager_test.go index a74847e7..f14b8630 100644 --- a/pkg/tag/manager/manager_test.go +++ b/pkg/tag/manager/manager_test.go @@ -43,17 +43,13 @@ func TestMain(m *testing.M) { func Test(t *testing.T) { clusterID := uint(1) - err := mgr.UpsertByResourceTypeID(ctx, common.ResourceCluster, clusterID, []*models.Tag{ + err := mgr.UpsertByResourceTypeID(ctx, common.ResourceCluster, clusterID, []*models.TagBasic{ { - ResourceType: common.ResourceCluster, - ResourceID: clusterID, - Key: "a", - Value: "1", + Key: "a", + Value: "1", }, { - ResourceType: common.ResourceCluster, - ResourceID: clusterID, - Key: "b", - Value: "2", + Key: "b", + Value: "2", }, }) assert.Nil(t, err) @@ -67,17 +63,13 @@ func Test(t *testing.T) { assert.Equal(t, "b", tags[1].Key) assert.Equal(t, "2", tags[1].Value) - err = mgr.UpsertByResourceTypeID(ctx, common.ResourceCluster, clusterID, []*models.Tag{ + err = mgr.UpsertByResourceTypeID(ctx, common.ResourceCluster, clusterID, []*models.TagBasic{ { - ResourceType: common.ResourceCluster, - ResourceID: clusterID, - Key: "a", - Value: "1", + Key: "a", + Value: "1", }, { - ResourceType: common.ResourceCluster, - ResourceID: clusterID, - Key: "c", - Value: "3", + Key: "c", + Value: "3", }, }) assert.Nil(t, err) @@ -91,22 +83,16 @@ func Test(t *testing.T) { assert.Equal(t, "c", tags[1].Key) assert.Equal(t, "3", tags[1].Value) - err = mgr.UpsertByResourceTypeID(ctx, common.ResourceCluster, clusterID, []*models.Tag{ + err = mgr.UpsertByResourceTypeID(ctx, common.ResourceCluster, clusterID, []*models.TagBasic{ { - ResourceType: common.ResourceCluster, - ResourceID: clusterID, - Key: "a", - Value: "1", + Key: "a", + Value: "1", }, { - ResourceType: common.ResourceCluster, - ResourceID: clusterID, - Key: "c", - Value: "3", + Key: "c", + Value: "3", }, { - ResourceType: common.ResourceCluster, - ResourceID: clusterID, - Key: "d", - Value: "4", + Key: "d", + Value: "4", }, }) assert.Nil(t, err) @@ -122,12 +108,10 @@ func Test(t *testing.T) { assert.Equal(t, "d", tags[2].Key) assert.Equal(t, "4", tags[2].Value) - err = mgr.UpsertByResourceTypeID(ctx, common.ResourceCluster, clusterID, []*models.Tag{ + err = mgr.UpsertByResourceTypeID(ctx, common.ResourceCluster, clusterID, []*models.TagBasic{ { - ResourceType: common.ResourceCluster, - ResourceID: clusterID, - Key: "d", - Value: "4", + Key: "d", + Value: "4", }, }) assert.Nil(t, err) diff --git a/pkg/tag/models/tag.go b/pkg/tag/models/tag.go index 4b6c52e4..717ff33f 100644 --- a/pkg/tag/models/tag.go +++ b/pkg/tag/models/tag.go @@ -71,6 +71,25 @@ func (t Tags) Eq(rhs Tags) bool { type TagsBasic []*TagBasic +func (t TagsBasic) Eq(rhs Tags) bool { + if len(t) != len(rhs) { + return false + } + index := make(map[TagBasic]struct{}) + for _, tag := range t { + index[*tag] = struct{}{} + } + for _, tag := range rhs { + if _, ok := index[TagBasic{ + Key: tag.Key, + Value: tag.Value, + }]; !ok { + return false + } + } + return true +} + func (t TagsBasic) IntoTags(resourceType models.ResourceType, resourceID uint) []*Tag { tags := make([]*Tag, 0, len(t)) for _, tag := range t {