From 0cdda0c629d50420f62e60e425b7e4d7f5f1c237 Mon Sep 17 00:00:00 2001 From: ioito Date: Thu, 23 Dec 2021 16:18:05 +0800 Subject: [PATCH] fix(region): secgroup purge with cloudaccount deleted --- pkg/apis/compute/secgroup.go | 12 +++++ pkg/compute/models/purge.go | 7 --- pkg/compute/models/secgroupcache.go | 24 ++++++++-- pkg/compute/models/secgroups.go | 72 +++++++++++++++++++++++++---- 4 files changed, 97 insertions(+), 18 deletions(-) diff --git a/pkg/apis/compute/secgroup.go b/pkg/apis/compute/secgroup.go index 91ca585329..df2ef7a599 100644 --- a/pkg/apis/compute/secgroup.go +++ b/pkg/apis/compute/secgroup.go @@ -321,3 +321,15 @@ type SecgroupJsonDesc struct { Id string `json:"id"` Name string `json:"name"` } + +type SSecurityGroupRef struct { + GuestCnt int `json:"guest_cnt"` + AdminGuestCnt int `json:"admin_guest_cnt"` + RdsCnt int `json:"rds_cnt"` + RedisCnt int `json:"redis_cnt"` + TotalCnt int `json:"total_cnt"` +} + +func (self *SSecurityGroupRef) Sum() { + self.TotalCnt = self.GuestCnt + self.AdminGuestCnt + self.RdsCnt + self.RedisCnt +} diff --git a/pkg/compute/models/purge.go b/pkg/compute/models/purge.go index 73ca340033..ad9d6aea1a 100644 --- a/pkg/compute/models/purge.go +++ b/pkg/compute/models/purge.go @@ -1804,13 +1804,6 @@ func (manager *SElasticcacheManager) purgeAll(ctx context.Context, userCred mccl return nil } -func (cache *SSecurityGroupCache) purge(ctx context.Context, userCred mcclient.TokenCredential) error { - lockman.LockObject(ctx, cache) - defer lockman.ReleaseObject(ctx, cache) - - return cache.RealDelete(ctx, userCred) -} - func (manager *SSecurityGroupCacheManager) purgeAll(ctx context.Context, userCred mcclient.TokenCredential, providerId string) error { caches := []SSecurityGroupCache{} err := fetchByManagerId(manager, providerId, &caches) diff --git a/pkg/compute/models/secgroupcache.go b/pkg/compute/models/secgroupcache.go index 61d4d22588..1927658999 100644 --- a/pkg/compute/models/secgroupcache.go +++ b/pkg/compute/models/secgroupcache.go @@ -46,7 +46,6 @@ type SSecurityGroupCacheManager struct { SCloudregionResourceBaseManager SVpcResourceBaseManager SSecurityGroupResourceBaseManager - SGlobalVpcResourceBaseManager } type SSecurityGroupCache struct { @@ -55,7 +54,6 @@ type SSecurityGroupCache struct { SCloudregionResourceBase SManagedResourceBase SSecurityGroupResourceBase - SGlobalVpcResourceBase `width:"36" charset:"ascii" list:"user" json:"globalvpc_id"` // 被其他安全组引用的次数 ReferenceCount int `nullable:"false" list:"user" json:"reference_count"` @@ -361,7 +359,7 @@ func (manager *SSecurityGroupCacheManager) getSecgroupcachesByProvider(provider func (self *SSecurityGroupCache) GetSecgroup() (*SSecurityGroup, error) { model, err := SecurityGroupManager.FetchById(self.SecgroupId) if err != nil { - return nil, fmt.Errorf("failed to fetch secgroup by %s", self.SecgroupId) + return nil, errors.Wrapf(err, "SecurityGroupManager.FetchById(%s)", self.SecgroupId) } return model.(*SSecurityGroup), nil } @@ -574,6 +572,26 @@ func (self *SSecurityGroupCache) RealDelete(ctx context.Context, userCred mcclie return self.SStatusStandaloneResourceBase.Delete(ctx, userCred) } +func (self *SSecurityGroupCache) purge(ctx context.Context, userCred mcclient.TokenCredential) error { + lockman.LockObject(ctx, self) + defer lockman.ReleaseObject(ctx, self) + + if secgroup, _ := self.GetSecgroup(); secgroup != nil { + caches, err := secgroup.GetSecurityGroupCaches() + if err != nil { + return errors.Wrapf(err, "secgroup.GetSecurityGroupCaches") + } + if len(caches) == 1 { + err := secgroup.ValidateDeleteCondition(ctx, nil) + if err == nil { + secgroup.RealDelete(ctx, userCred) + } + } + } + + return self.RealDelete(ctx, userCred) +} + func (self *SSecurityGroupCache) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error { return self.StartSecurityGroupCacheDeleteTask(ctx, userCred, "") } diff --git a/pkg/compute/models/secgroups.go b/pkg/compute/models/secgroups.go index 0a88775379..fda383871c 100644 --- a/pkg/compute/models/secgroups.go +++ b/pkg/compute/models/secgroups.go @@ -1189,7 +1189,7 @@ func (manager *SSecurityGroupManager) InitializeData() error { log.Debugf("Init default secgroup") secGrp := &SSecurityGroup{} secGrp.SetModelManager(manager, secGrp) - secGrp.Id = "default" + secGrp.Id = api.SECGROUP_DEFAULT_ID secGrp.Name = "Default" secGrp.Status = api.SECGROUP_STATUS_READY secGrp.ProjectId = auth.AdminCredential().GetProjectId() @@ -1210,7 +1210,7 @@ func (manager *SSecurityGroupManager) InitializeData() error { defRule.Priority = 1 defRule.CIDR = "0.0.0.0/0" defRule.Action = string(secrules.SecurityRuleAllow) - defRule.SecgroupId = "default" + defRule.SecgroupId = api.SECGROUP_DEFAULT_ID err = SecurityGroupRuleManager.TableSpec().Insert(context.TODO(), &defRule) if err != nil { return errors.Wrapf(err, "Insert default secgroup rule") @@ -1260,17 +1260,73 @@ func (self *SSecurityGroup) GetSecurityGroupReferences() ([]SSecurityGroup, erro return groups, nil } -func (self *SSecurityGroup) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error { - cnt, err := self.GetGuestsCount() +func (sm *SSecurityGroupManager) query(manager db.IModelManager, field, label string, secIds []string) *sqlchemy.SSubQuery { + sq := manager.Query().SubQuery() + + return sq.Query( + sq.Field(field), + sqlchemy.COUNT(label), + ).In(field, secIds).GroupBy(sq.Field(field)).SubQuery() +} + +type sSecuriyGroupCnts struct { + Id string + Guest1Cnt int + api.SSecurityGroupRef +} + +func (sm *SSecurityGroupManager) TotalCnt(secIds []string) (map[string]api.SSecurityGroupRef, error) { + g1SQ := sm.query(GuestsecgroupManager, "secgroup_id", "guest1", secIds) + g2SQ := sm.query(GuestManager, "secgrp_id", "guest2", secIds) + g3SQ := sm.query(GuestManager, "admin_secgrp_id", "guest3", secIds) + + rdsSQ := sm.query(DBInstanceSecgroupManager, "secgroup_id", "rds", secIds) + redisSQ := sm.query(ElasticcachesecgroupManager, "secgroup_id", "redis", secIds) + + secs := sm.Query().SubQuery() + secQ := secs.Query( + sqlchemy.SUM("guest_cnt", g1SQ.Field("guest1")), + sqlchemy.SUM("guest1_cnt", g2SQ.Field("guest2")), + sqlchemy.SUM("admin_guest_cnt", g3SQ.Field("guest3")), + sqlchemy.SUM("rds_cnt", rdsSQ.Field("rds")), + sqlchemy.SUM("redis_cnt", redisSQ.Field("redis")), + ) + + secQ.AppendField(secQ.Field("id")) + + secQ = secQ.LeftJoin(g1SQ, sqlchemy.Equals(secQ.Field("id"), g1SQ.Field("secgroup_id"))) + secQ = secQ.LeftJoin(g2SQ, sqlchemy.Equals(secQ.Field("id"), g2SQ.Field("secgrp_id"))) + secQ = secQ.LeftJoin(g3SQ, sqlchemy.Equals(secQ.Field("id"), g3SQ.Field("admin_secgrp_id"))) + secQ = secQ.LeftJoin(rdsSQ, sqlchemy.Equals(secQ.Field("id"), rdsSQ.Field("secgroup_id"))) + secQ = secQ.LeftJoin(redisSQ, sqlchemy.Equals(secQ.Field("id"), redisSQ.Field("secgroup_id"))) + + secQ = secQ.Filter(sqlchemy.In(secQ.Field("id"), secIds)).GroupBy(secQ.Field("id")) + + cnts := []sSecuriyGroupCnts{} + err := secQ.All(&cnts) if err != nil { - return httperrors.NewInternalServerError("GetGuestsCount fail %s", err) + return nil, errors.Wrapf(err, "secQ.All") } - if cnt > 0 { - return httperrors.NewNotEmptyError("the security group is in use") + result := map[string]api.SSecurityGroupRef{} + for i := range cnts { + cnts[i].GuestCnt += cnts[i].Guest1Cnt + cnts[i].Sum() + result[cnts[i].Id] = cnts[i].SSecurityGroupRef } - if self.Id == "default" { + return result, nil +} + +func (self *SSecurityGroup) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error { + if self.Id == api.SECGROUP_DEFAULT_ID { return httperrors.NewProtectedResourceError("not allow to delete default security group") } + cnts, err := SecurityGroupManager.TotalCnt([]string{self.Id}) + if err != nil { + return errors.Wrapf(err, "SecurityGroupManager.TotalCnt") + } + if cnt, ok := cnts[self.Id]; ok && cnt.TotalCnt > 0 { + return httperrors.NewNotEmptyError("the security group %s is in use cnt: %s", self.Id, jsonutils.Marshal(cnt).String()) + } references, err := self.GetSecurityGroupReferences() if err != nil { return httperrors.NewGeneralError(err)