From d0cc334cab1d78fdc4837734cc9a86b01b0cfd05 Mon Sep 17 00:00:00 2001 From: Qu Xuan Date: Mon, 28 Dec 2020 10:21:12 +0800 Subject: [PATCH] fix(region): optimized secgroup rule sync --- pkg/apis/compute/secgroup_const.go | 5 +- pkg/compute/models/guests.go | 51 ++---------- pkg/compute/models/instance_snapshots.go | 3 +- pkg/compute/models/secgroupcache.go | 38 +++++++++ pkg/compute/models/secgroups.go | 80 ++++++++++++------- .../tasks/security_group_sync_rules_task.go | 64 +++++++++++++++ 6 files changed, 167 insertions(+), 74 deletions(-) create mode 100644 pkg/compute/tasks/security_group_sync_rules_task.go diff --git a/pkg/apis/compute/secgroup_const.go b/pkg/apis/compute/secgroup_const.go index fc604dfae4..0e6cff51db 100644 --- a/pkg/apis/compute/secgroup_const.go +++ b/pkg/apis/compute/secgroup_const.go @@ -15,8 +15,9 @@ package compute const ( - SECGROUP_STATUS_READY = "ready" - SECGROUP_STATUS_DELETING = "deleting" + SECGROUP_STATUS_READY = "ready" + SECGROUP_STATUS_DELETING = "deleting" // 删除中 + SECGROUP_STATUS_SYNC_RULES = "sync_rules" // 同步规则中 SECGROUP_DEFAULT_ID = "default" ) diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 0ee72caa28..29601d1f4b 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -32,7 +32,6 @@ import ( "yunion.io/x/pkg/util/netutils" "yunion.io/x/pkg/util/osprofile" "yunion.io/x/pkg/util/regutils" - "yunion.io/x/pkg/util/secrules" "yunion.io/x/pkg/util/timeutils" "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" @@ -2310,20 +2309,9 @@ func (self *SGuest) GetSecgroups() ([]SSecurityGroup, error) { return secgroups, nil } -func (self *SGuest) getSecgroup() *SSecurityGroup { - return SecurityGroupManager.FetchSecgroupById(self.SecgrpId) -} - func (self *SGuest) getAdminSecgroup() *SSecurityGroup { - return SecurityGroupManager.FetchSecgroupById(self.AdminSecgrpId) -} - -func (self *SGuest) GetSecgroupName() string { - secgrp := self.getSecgroup() - if secgrp != nil { - return secgrp.GetName() - } - return "" + secGrp, _ := SecurityGroupManager.FetchSecgroupById(self.AdminSecgrpId) + return secGrp } func (self *SGuest) getAdminSecgroupName() string { @@ -2334,31 +2322,6 @@ func (self *SGuest) getAdminSecgroupName() string { return "" } -func (self *SGuest) GetSecRules() []secrules.SecurityRule { - return self.getSecRules() -} - -func (self *SGuest) getSecRules() []secrules.SecurityRule { - if secgrp := self.getSecgroup(); secgrp != nil { - return secgrp.GetSecRules("") - } - if rule, err := secrules.ParseSecurityRule(options.Options.DefaultSecurityRules); err == nil { - return []secrules.SecurityRule{*rule} - } else { - log.Errorf("Default SecurityRules error: %v", err) - } - return []secrules.SecurityRule{} -} - -func (self *SGuest) getSecurityRules() string { - secgrp := self.getSecgroup() - if secgrp != nil { - return secgrp.getSecurityRuleString("") - } else { - return options.Options.DefaultSecurityRules - } -} - //获取多个安全组规则,优先级降序排序 func (self *SGuest) getSecurityGroupsRules() string { secgroups, _ := self.GetSecgroups() @@ -4091,10 +4054,12 @@ func (self *SGuest) GetJsonDescAtHypervisor(ctx context.Context, host *SHost) *j desc.Add(jsonutils.NewStringArray(netRoles), "network_roles") } - secGrp := self.getSecgroup() - if secGrp != nil { - desc.Add(jsonutils.NewString(secGrp.Name), "secgroup") - } + /* + secGrp := self.getSecgroup() + if secGrp != nil { + desc.Add(jsonutils.NewString(secGrp.Name), "secgroup") + } + */ secgroups, _ := self.getSecgroupJson() if secgroups != nil { diff --git a/pkg/compute/models/instance_snapshots.go b/pkg/compute/models/instance_snapshots.go index d8879d84d3..b28befb81b 100644 --- a/pkg/compute/models/instance_snapshots.go +++ b/pkg/compute/models/instance_snapshots.go @@ -430,7 +430,8 @@ func (self *SInstanceSnapshot) ToInstanceCreateInput( inputSecgs := make([]string, 0) self.SecGroups.Unmarshal(&secGroups) for i := 0; i < len(secGroups); i++ { - if secGrp := SecurityGroupManager.FetchSecgroupById(secGroups[i]); secGrp != nil { + _, err := SecurityGroupManager.FetchSecgroupById(secGroups[i]) + if err == nil { inputSecgs = append(inputSecgs, secGroups[i]) } } diff --git a/pkg/compute/models/secgroupcache.go b/pkg/compute/models/secgroupcache.go index 48b92c354f..fc8f884e2f 100644 --- a/pkg/compute/models/secgroupcache.go +++ b/pkg/compute/models/secgroupcache.go @@ -23,6 +23,7 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" + "yunion.io/x/pkg/util/secrules" "yunion.io/x/sqlchemy" "yunion.io/x/onecloud/pkg/apis" @@ -630,3 +631,40 @@ func (self *SSecurityGroupCache) GetISecurityGroup() (cloudprovider.ICloudSecuri } return iRegion.GetISecurityGroupById(self.ExternalId) } + +func (self *SSecurityGroupCache) SyncRules() error { + region := self.GetRegion() + if region == nil { + return fmt.Errorf("failed to get region for secgroupcache %s(%s)", self.Name, self.Id) + } + iSecgroup, err := self.GetISecurityGroup() + if err != nil { + return errors.Wrapf(err, "GetISecurityGroup") + } + secgroup, err := self.GetSecgroup() + if err != nil { + return errors.Wrapf(err, "GetSecgroup") + } + + rules, err := iSecgroup.GetRules() + if err != nil { + return errors.Wrapf(err, "iSecgroup.GetRules") + } + + maxPriority := region.GetDriver().GetSecurityGroupRuleMaxPriority() + minPriority := region.GetDriver().GetSecurityGroupRuleMinPriority() + + defaultInRule := region.GetDriver().GetDefaultSecurityGroupInRule() + defaultOutRule := region.GetDriver().GetDefaultSecurityGroupOutRule() + order := region.GetDriver().GetSecurityGroupRuleOrder() + onlyAllowRules := region.GetDriver().IsOnlySupportAllowRules() + + localRules := secrules.SecurityRuleSet(secgroup.GetSecRules("")) + + common, inAdds, outAdds, inDels, outDels := cloudprovider.CompareRules(minPriority, maxPriority, order, localRules, rules, defaultInRule, defaultOutRule, onlyAllowRules, false) + + if len(inAdds) == 0 && len(inDels) == 0 && len(outAdds) == 0 && len(outDels) == 0 { + return nil + } + return iSecgroup.SyncRules(common, inAdds, outAdds, inDels, outDels) +} diff --git a/pkg/compute/models/secgroups.go b/pkg/compute/models/secgroups.go index 023c96dcf5..89728c1791 100644 --- a/pkg/compute/models/secgroups.go +++ b/pkg/compute/models/secgroups.go @@ -291,6 +291,16 @@ func (self *SSecurityGroup) GetGuests() []SGuest { return guests } +func (self *SSecurityGroup) GetKvmGuests() ([]SGuest, error) { + guests := []SGuest{} + q := self.GetGuestsQuery().Equals("hypervisor", api.HYPERVISOR_KVM) + err := db.FetchModelObjects(GuestManager, q, &guests) + if err != nil { + return nil, errors.Wrapf(err, "db.FetchModelObjects") + } + return guests, nil +} + func (self *SSecurityGroup) GetSecgroupCacheQuery() *sqlchemy.SQuery { return SecurityGroupCacheManager.Query().Equals("secgroup_id", self.Id) } @@ -529,14 +539,12 @@ func (self *SSecurityGroup) PostCreate(ctx context.Context, userCred mcclient.To } } -func (manager *SSecurityGroupManager) FetchSecgroupById(secId string) *SSecurityGroup { - if len(secId) > 0 { - secgrp, _ := manager.FetchById(secId) - if secgrp != nil { - return secgrp.(*SSecurityGroup) - } +func (manager *SSecurityGroupManager) FetchSecgroupById(secId string) (*SSecurityGroup, error) { + secgrp, err := manager.FetchById(secId) + if err != nil { + return nil, errors.Wrapf(err, "FetchById(%s)", secId) } - return nil + return secgrp.(*SSecurityGroup), nil } func (self *SSecurityGroup) getSecurityRules(direction string) (rules []SSecurityGroupRule) { @@ -1027,33 +1035,49 @@ func (manager *SSecurityGroupManager) newFromCloudSecgroup(ctx context.Context, return &secgroup, nil } -func (manager *SSecurityGroupManager) DelaySync(ctx context.Context, userCred mcclient.TokenCredential, idStr string) { - if secgrp := manager.FetchSecgroupById(idStr); secgrp == nil { - log.Errorf("DelaySync secgroup failed") - } else { - needSync := false +func (manager *SSecurityGroupManager) DelaySync(ctx context.Context, userCred mcclient.TokenCredential, idStr string) error { + secgrp, err := manager.FetchSecgroupById(idStr) + if err != nil { + return errors.Wrapf(err, "FetchSecgroupById(%s)", idStr) + } + needSync := false - func() { - lockman.LockObject(ctx, secgrp) - defer lockman.ReleaseObject(ctx, secgrp) + func() { + lockman.LockObject(ctx, secgrp) + defer lockman.ReleaseObject(ctx, secgrp) - if secgrp.IsDirty { - if _, err := db.Update(secgrp, func() error { - secgrp.IsDirty = false - return nil - }); err != nil { - log.Errorf("Update Security Group error: %s", err.Error()) - } - needSync = true + if secgrp.IsDirty { + if _, err := db.Update(secgrp, func() error { + secgrp.IsDirty = false + return nil + }); err != nil { + log.Errorf("Update Security Group error: %s", err.Error()) } - }() + needSync = true + } + }() - if needSync { - for _, guest := range secgrp.GetGuests() { - guest.StartSyncTask(ctx, userCred, true, "") - } + if needSync { + guests, err := secgrp.GetKvmGuests() + if err != nil { + return errors.Wrapf(err, "GetKvmGuests") + } + for _, guest := range guests { + guest.StartSyncTask(ctx, userCred, true, "") } } + return secgrp.StartSecurityGroupSyncRulesTask(ctx, userCred, "") +} + +func (self *SSecurityGroup) StartSecurityGroupSyncRulesTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error { + params := jsonutils.NewDict() + task, err := taskman.TaskManager.NewTask(ctx, "SecurityGroupSyncRulesTask", self, userCred, params, parentTaskId, "", nil) + if err != nil { + return errors.Wrapf(err, "NewTask") + } + self.SetStatus(userCred, api.SECGROUP_STATUS_SYNC_RULES, "") + task.ScheduleRun(nil) + return nil } func (self *SSecurityGroup) DoSync(ctx context.Context, userCred mcclient.TokenCredential) { diff --git a/pkg/compute/tasks/security_group_sync_rules_task.go b/pkg/compute/tasks/security_group_sync_rules_task.go new file mode 100644 index 0000000000..fb7e3e6425 --- /dev/null +++ b/pkg/compute/tasks/security_group_sync_rules_task.go @@ -0,0 +1,64 @@ +// Copyright 2019 Yunion +// +// 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 tasks + +import ( + "context" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" + "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type SecurityGroupSyncRulesTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(SecurityGroupSyncRulesTask{}) +} + +func (self *SecurityGroupSyncRulesTask) taskFailed(ctx context.Context, secgroup *models.SSecurityGroup, err error) { + secgroup.SetStatus(self.UserCred, api.SECGROUP_STATUS_READY, "") + logclient.AddActionLogWithContext(ctx, secgroup, logclient.ACT_SYNC_CONF, err, self.UserCred, false) + self.SetStageFailed(ctx, jsonutils.NewString(err.Error())) +} + +func (self *SecurityGroupSyncRulesTask) taskComplete(ctx context.Context, secgroup *models.SSecurityGroup) { + secgroup.SetStatus(self.UserCred, api.SECGROUP_STATUS_READY, "") + self.SetStageComplete(ctx, nil) +} + +func (self *SecurityGroupSyncRulesTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + secgroup := obj.(*models.SSecurityGroup) + caches, err := secgroup.GetSecurityGroupCaches() + if err != nil { + self.taskFailed(ctx, secgroup, errors.Wrapf(err, "GetSecurityGroupCaches")) + return + } + + for i := range caches { + err := caches[i].SyncRules() + if err != nil { + logclient.AddActionLogWithContext(ctx, secgroup, logclient.ACT_SYNC_CONF, errors.Wrapf(err, "SyncRules"), self.UserCred, false) + } + } + self.taskComplete(ctx, secgroup) +}