diff --git a/cmd/climc/shell/compute/secgrouprules.go b/cmd/climc/shell/compute/secgrouprules.go index ae86f4e373..89f52f47fe 100644 --- a/cmd/climc/shell/compute/secgrouprules.go +++ b/cmd/climc/shell/compute/secgrouprules.go @@ -15,142 +15,17 @@ package compute import ( - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/cmd/climc/shell" "yunion.io/x/onecloud/pkg/mcclient/modules" "yunion.io/x/onecloud/pkg/mcclient/options" + "yunion.io/x/onecloud/pkg/mcclient/options/compute" ) func init() { - type SecGroupRulesListOptions struct { - options.BaseListOptions - Secgroup string `help:"Secgroup ID or Name"` - SecgroupName string `help:"Search rules by fuzzy secgroup name"` - Projects []string `help:"Filter rules by project"` - Direction string `help:"filter Direction of rule" choices:"in|out"` - Protocol string `help:"filter Protocol of rule" choices:"any|tcp|udp|icmp"` - Action string `help:"filter Actin of rule" choices:"allow|deny"` - Ports string `help:"filter Ports of rule"` - Ip string `help:"filter cidr of rule"` - } - - R(&SecGroupRulesListOptions{}, "secgroup-rule-list", "List all security group", func(s *mcclient.ClientSession, args *SecGroupRulesListOptions) error { - params, err := options.ListStructToParams(args) - if err != nil { - return err - } - result, err := modules.SecGroupRules.List(s, params) - if err != nil { - return err - } - printList(result, modules.SecGroupRules.GetColumns(s)) - return nil - }) - - type SecGroupRuleDetailOptions struct { - ID string `help:"ID or Name of security group rule"` - } - R(&SecGroupRuleDetailOptions{}, "secgroup-rule-show", "Show details of rule", func(s *mcclient.ClientSession, args *SecGroupRuleDetailOptions) error { - if rule, e := modules.SecGroupRules.Get(s, args.ID, nil); e != nil { - return e - } else { - printObject(rule) - } - return nil - }) - - R(&SecGroupRuleDetailOptions{}, "secgroup-rule-delete", "Delete a secgroup rule", func(s *mcclient.ClientSession, args *SecGroupRuleDetailOptions) error { - if rule, e := modules.SecGroupRules.Delete(s, args.ID, nil); e != nil { - return e - } else { - printObject(rule) - } - return nil - }) - - type SecGroupRulesCreateOptions struct { - SECGROUP string `help:"Secgroup ID or Name" metavar:"Secgroup"` - Direction string `help:"Direction of rule" choices:"in|out"` - Action string `help:"Action of rule" choices:"allow|deny"` - Protocol string `help:"Protocol of rule" choices:"tcp|udp|icmp|any"` - Ports string `help:"Ports of rule"` - Cidr string `help:"Cidr of rule"` - Priority int64 `help:"priority of Rule"` - Desc string `help:"Description"` - } - - R(&SecGroupRulesCreateOptions{}, "secgroup-rule-create", "Create all security group rule", func(s *mcclient.ClientSession, args *SecGroupRulesCreateOptions) error { - params := jsonutils.NewDict() - if len(args.Desc) > 0 { - params.Add(jsonutils.NewString(args.Desc), "description") - } - if args.Priority > 0 { - params.Add(jsonutils.NewInt(args.Priority), "priority") - } - if len(args.Direction) > 0 { - params.Add(jsonutils.NewString(args.Direction), "direction") - } - if len(args.Action) > 0 { - params.Add(jsonutils.NewString(args.Action), "action") - } - if len(args.Protocol) > 0 { - params.Add(jsonutils.NewString(args.Protocol), "protocol") - } - if len(args.Ports) > 0 { - params.Add(jsonutils.NewString(args.Ports), "ports") - } - if len(args.Cidr) > 0 { - params.Add(jsonutils.NewString(args.Cidr), "cidr") - } - params.Add(jsonutils.NewString(args.SECGROUP), "secgroup") - secgrouprules, err := modules.SecGroupRules.Create(s, params) - if err != nil { - return err - } - printObject(secgrouprules) - return nil - }) - - type SecGroupRulesUpdateOptions struct { - ID string `help:"ID or name of rule"` - Name string `help:"New name of rule"` - Priority int64 `help:"priority of Rule"` - Protocol string `help:"Protocol of rule" choices:"any|tcp|udp|icmp"` - Ports string `help:"Ports of rule"` - Cidr string `help:"Cidr of rule"` - Action string `help:"filter Actin of rule" choices:"allow|deny"` - Desc string `help:"Description" metavar:"Description"` - } - - R(&SecGroupRulesUpdateOptions{}, "secgroup-rule-update", "Update property of a security group rule", func(s *mcclient.ClientSession, args *SecGroupRulesUpdateOptions) error { - params := jsonutils.NewDict() - if len(args.Name) > 0 { - params.Add(jsonutils.NewString(args.Name), "name") - } - if len(args.Desc) > 0 { - params.Add(jsonutils.NewString(args.Desc), "description") - } - if args.Priority > 0 { - params.Add(jsonutils.NewInt(args.Priority), "priority") - } - if len(args.Protocol) > 0 { - params.Add(jsonutils.NewString(args.Protocol), "protocol") - } - if len(args.Ports) > 0 { - params.Add(jsonutils.NewString(args.Ports), "ports") - } - if len(args.Cidr) > 0 { - params.Add(jsonutils.NewString(args.Cidr), "cidr") - } - if len(args.Action) > 0 { - params.Add(jsonutils.NewString(args.Action), "action") - } - if rule, e := modules.SecGroupRules.Update(s, args.ID, params); e != nil { - return e - } else { - printObject(rule) - } - return nil - }) + cmd := shell.NewResourceCmd(&modules.SecGroupRules).WithKeyword("secgroup-rule") + cmd.List(&compute.SecGroupRulesListOptions{}) + cmd.Show(&options.BaseShowOptions{}) + cmd.Delete(&options.BaseIdOptions{}) + cmd.Create(&compute.SecGroupRulesCreateOptions{}) + cmd.Update(&compute.SecGroupRulesUpdateOptions{}) } diff --git a/pkg/apis/compute/secgroup.go b/pkg/apis/compute/secgroup.go index 4c08d9643d..a4ec4392b8 100644 --- a/pkg/apis/compute/secgroup.go +++ b/pkg/apis/compute/secgroup.go @@ -24,14 +24,12 @@ import ( "yunion.io/x/onecloud/pkg/apis" ) -type SSecgroupRuleCreateInput struct { - apis.ResourceBaseCreateInput - +type SSecgroupRuleResource struct { // 优先级, 数字越大优先级越高 // minimum: 1 // maximum: 100 // required: true - Priority int `json:"priority"` + Priority *int `json:"priority"` // 协议 // required: true @@ -68,7 +66,7 @@ type SSecgroupRuleCreateInput struct { // required: true Direction string `json:"direction"` - // ip或cidr地址 + // ip或cidr地址, 若指定peer_secgroup_id此参数不生效 // example: 192.168.222.121 CIDR string `json:"cidr"` @@ -84,17 +82,36 @@ type SSecgroupRuleCreateInput struct { // example: test to create rule Description string `json:"description"` - // 仅单独创建安全组规则时需要指定安全组 - // required: true - Secgroup string `json:"secgroup"` - - // swagger:ignore - SecgroupId string + // 对端安全组Id, 此参数和cidr参数互斥,并且优先级高于cidr, 同事peer_secgroup_id不能和它所在的安全组ID相同 + // required: false + PeerSecgroupId string `json:"peer_secgroup_id"` } -func (input *SSecgroupRuleCreateInput) Check() error { +type SSecgroupRuleCreateInput struct { + apis.ResourceBaseCreateInput + SSecgroupRuleResource + + // swagger:ignore + Secgroup string `json:"secgroup" yunion-deprecated-by:"secgroup_id"` + + // 安全组ID + // required: true + SecgroupId string `json:"secgroup_id"` +} + +type SSecgroupRuleUpdateInput struct { + apis.ResourceBaseUpdateInput + + SSecgroupRuleResource +} + +func (input *SSecgroupRuleResource) Check() error { + priority := 1 + if input.Priority != nil { + priority = *input.Priority + } rule := secrules.SecurityRule{ - Priority: input.Priority, + Priority: priority, Direction: secrules.TSecurityRuleDirection(input.Direction), Action: secrules.TSecurityRuleAction(input.Action), Protocol: input.Protocol, diff --git a/pkg/apis/compute/secgrouprule.go b/pkg/apis/compute/secgrouprule.go index 74ba469e96..7d48953221 100644 --- a/pkg/apis/compute/secgrouprule.go +++ b/pkg/apis/compute/secgrouprule.go @@ -22,5 +22,6 @@ type SecgroupRuleDetails struct { SSecurityGroupRule SecurityGroupResourceInfo - ProjectId string `json:"tenant_id"` + ProjectId string `json:"tenant_id"` + PeerSecgroup string `json:"peer_secgroup"` } diff --git a/pkg/cloudcommon/validators/validators.go b/pkg/cloudcommon/validators/validators.go index de862d5c8b..d7d4c7bbb5 100644 --- a/pkg/cloudcommon/validators/validators.go +++ b/pkg/cloudcommon/validators/validators.go @@ -829,6 +829,9 @@ var ValidateModel = func(userCred mcclient.TokenCredential, manager db.IStandalo if errors.Cause(err) == sql.ErrNoRows { return nil, httperrors.NewResourceNotFoundError2(manager.Keyword(), *id) } + if errors.Cause(err) == sqlchemy.ErrDuplicateEntry { + return nil, httperrors.NewDuplicateResourceError(manager.Keyword(), *id) + } return nil, httperrors.NewGeneralError(err) } *id = model.GetId() diff --git a/pkg/cloudprovider/securitygroup.go b/pkg/cloudprovider/securitygroup.go index 8bba34b335..a3677fd526 100644 --- a/pkg/cloudprovider/securitygroup.go +++ b/pkg/cloudprovider/securitygroup.go @@ -15,6 +15,7 @@ package cloudprovider import ( + "fmt" "sort" "strings" @@ -31,6 +32,7 @@ type SecDriver interface { GetSecurityGroupRuleMaxPriority() int GetSecurityGroupRuleMinPriority() int IsOnlySupportAllowRules() bool + IsSupportPeerSecgroup() bool } func NewSecRuleInfo(driver SecDriver) SecRuleInfo { @@ -40,6 +42,7 @@ func NewSecRuleInfo(driver SecDriver) SecRuleInfo { MinPriority: driver.GetSecurityGroupRuleMinPriority(), MaxPriority: driver.GetSecurityGroupRuleMaxPriority(), IsOnlySupportAllowRules: driver.IsOnlySupportAllowRules(), + IsSupportPeerSecgroup: driver.IsSupportPeerSecgroup(), } } @@ -53,6 +56,7 @@ type SecRuleInfo struct { MinPriority int MaxPriority int IsOnlySupportAllowRules bool + IsSupportPeerSecgroup bool } func (r SecRuleInfo) AddDefaultRule(d SecRuleInfo, inRules, outRules []SecurityRule, isSrc bool) ([]SecurityRule, []SecurityRule) { @@ -96,16 +100,28 @@ type SecurityRule struct { Name string ExternalId string Id string + + PeerSecgroupId string } func (r SecurityRule) String() string { - return r.SecurityRule.String() + if len(r.PeerSecgroupId) == 0 { + return r.SecurityRule.String() + } + return fmt.Sprintf("%s-%s", r.SecurityRule.String(), r.PeerSecgroupId) } type SecurityRuleSet []SecurityRule -func (rules SecurityRuleSet) Split() (in, out SecurityRuleSet) { +func (rules SecurityRuleSet) Split(isSupportPeerSecgroup bool) (in, out SecurityRuleSet, isStandardRules bool) { + isStandardRules = true for i := 0; i < len(rules); i++ { + if len(rules[i].PeerSecgroupId) > 0 { + isStandardRules = false + } + if !isSupportPeerSecgroup && len(rules[i].PeerSecgroupId) > 0 { + continue + } if rules[i].Direction == secrules.DIR_IN { in = append(in, rules[i]) } else { @@ -163,8 +179,8 @@ func isAllowListEqual(src, dest secrules.SecurityRuleSet) bool { } func CompareRules(src, dest SecRuleInfo, debug bool) (common, inAdds, outAdds, inDels, outDels SecurityRuleSet) { - srcInRules, srcOutRules := src.Rules.Split() - destInRules, destOutRules := dest.Rules.Split() + srcInRules, srcOutRules, isSrcStandardRules := src.Rules.Split(src.IsSupportPeerSecgroup) + destInRules, destOutRules, isDestStandardRules := dest.Rules.Split(dest.IsSupportPeerSecgroup) srcInRules, srcOutRules = src.AddDefaultRule(dest, srcInRules, srcOutRules, true) destInRules, destOutRules = dest.AddDefaultRule(src, destInRules, destOutRules, false) @@ -174,59 +190,61 @@ func CompareRules(src, dest SecRuleInfo, debug bool) (common, inAdds, outAdds, i srcInRules.Debug() } - // AllowList 需要优先级从高到低排序 - SortSecurityRule(srcInRules, src.MaxPriority, src.MinPriority, false, src.IsOnlySupportAllowRules) - SortSecurityRule(srcOutRules, src.MaxPriority, src.MinPriority, false, src.IsOnlySupportAllowRules) + if (isSrcStandardRules && isDestStandardRules) || (!src.IsSupportPeerSecgroup && !dest.IsSupportPeerSecgroup) { + // AllowList 需要优先级从高到低排序 + SortSecurityRule(srcInRules, src.MaxPriority, src.MinPriority, false, src.IsOnlySupportAllowRules) + SortSecurityRule(srcOutRules, src.MaxPriority, src.MinPriority, false, src.IsOnlySupportAllowRules) - SortSecurityRule(destInRules, dest.MaxPriority, dest.MinPriority, false, dest.IsOnlySupportAllowRules) - SortSecurityRule(destOutRules, dest.MaxPriority, dest.MinPriority, false, dest.IsOnlySupportAllowRules) + SortSecurityRule(destInRules, dest.MaxPriority, dest.MinPriority, false, dest.IsOnlySupportAllowRules) + SortSecurityRule(destOutRules, dest.MaxPriority, dest.MinPriority, false, dest.IsOnlySupportAllowRules) - srcInAllowList := srcInRules.AllowList() - srcOutAllowList := srcOutRules.AllowList() + srcInAllowList := srcInRules.AllowList() + srcOutAllowList := srcOutRules.AllowList() - destInAllowList := destInRules.AllowList() - destOutAllowList := destOutRules.AllowList() - inEquals, outEquals := isAllowListEqual(srcInAllowList, destInAllowList), isAllowListEqual(srcOutAllowList, destOutAllowList) + destInAllowList := destInRules.AllowList() + destOutAllowList := destOutRules.AllowList() + inEquals, outEquals := isAllowListEqual(srcInAllowList, destInAllowList), isAllowListEqual(srcOutAllowList, destOutAllowList) - if inEquals && outEquals { - return - } - - if debug { - log.Debugf("In: src: %s dest: %s result: %v", srcInAllowList.String(), destInAllowList.String(), inEquals) - log.Debugf("Out: src: %s dest: %s result: %v", srcOutAllowList.String(), destOutAllowList.String(), outEquals) - } - - var tryUseAllowList = func(defaultRule SecurityRule, allowList secrules.SecurityRuleSet, rules SecurityRuleSet, isOnlyAllowList bool) SecurityRuleSet { - if len(allowList) < len(rules) || isOnlyAllowList { - rules = SecurityRuleSet{} - for i := range allowList { - rule := SecurityRule{} - rule.SecurityRule = allowList[i] - rules = append(rules, rule) - } - - if !utils.IsInStringArray(allowList.String(), []string{ - "", - "in:allow any", - "out:allow any", - "in:deny any", - "out:deny any", - }) && strings.HasSuffix(defaultRule.SecurityRule.String(), "deny any") { - rules = append(rules, defaultRule) - } + if inEquals && outEquals { + return } - return rules - } - srcInRules = tryUseAllowList(src.InDefaultRule, srcInAllowList, srcInRules, dest.IsOnlySupportAllowRules) - srcOutRules = tryUseAllowList(src.OutDefaultRule, srcOutAllowList, srcOutRules, dest.IsOnlySupportAllowRules) + if debug { + log.Debugf("In: src: %s dest: %s result: %v", srcInAllowList.String(), destInAllowList.String(), inEquals) + log.Debugf("Out: src: %s dest: %s result: %v", srcOutAllowList.String(), destOutAllowList.String(), outEquals) + } - if inEquals { - srcInRules, destInRules = []SecurityRule{}, []SecurityRule{} - } - if outEquals { - srcOutRules, destOutRules = []SecurityRule{}, []SecurityRule{} + var tryUseAllowList = func(defaultRule SecurityRule, allowList secrules.SecurityRuleSet, rules SecurityRuleSet, isOnlyAllowList bool) SecurityRuleSet { + if len(allowList) < len(rules) || isOnlyAllowList { + rules = SecurityRuleSet{} + for i := range allowList { + rule := SecurityRule{} + rule.SecurityRule = allowList[i] + rules = append(rules, rule) + } + + if !utils.IsInStringArray(allowList.String(), []string{ + "", + "in:allow any", + "out:allow any", + "in:deny any", + "out:deny any", + }) && strings.HasSuffix(defaultRule.SecurityRule.String(), "deny any") { + rules = append(rules, defaultRule) + } + } + return rules + } + + srcInRules = tryUseAllowList(src.InDefaultRule, srcInAllowList, srcInRules, dest.IsOnlySupportAllowRules) + srcOutRules = tryUseAllowList(src.OutDefaultRule, srcOutAllowList, srcOutRules, dest.IsOnlySupportAllowRules) + + if inEquals { + srcInRules, destInRules = []SecurityRule{}, []SecurityRule{} + } + if outEquals { + srcOutRules, destOutRules = []SecurityRule{}, []SecurityRule{} + } } if debug { diff --git a/pkg/compute/models/regiondrivers.go b/pkg/compute/models/regiondrivers.go index 080655e7aa..88a52dfdfc 100644 --- a/pkg/compute/models/regiondrivers.go +++ b/pkg/compute/models/regiondrivers.go @@ -134,6 +134,8 @@ type IRegionDriver interface { GetSecurityGroupRuleMaxPriority() int GetSecurityGroupRuleMinPriority() int IsOnlySupportAllowRules() bool + IsPeerSecgroupWithSameProject() bool + IsSupportPeerSecgroup() bool IsSupportClassicSecurityGroup() bool IsSecurityGroupBelongVpc() bool IsVpcBelongGlobalVpc() bool diff --git a/pkg/compute/models/secgroupcache.go b/pkg/compute/models/secgroupcache.go index 9393c44d47..0178084cc6 100644 --- a/pkg/compute/models/secgroupcache.go +++ b/pkg/compute/models/secgroupcache.go @@ -18,6 +18,7 @@ import ( "context" "database/sql" "fmt" + "strings" "yunion.io/x/jsonutils" "yunion.io/x/log" @@ -33,6 +34,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/rand" "yunion.io/x/onecloud/pkg/util/rbacutils" "yunion.io/x/onecloud/pkg/util/stringutils2" ) @@ -330,18 +332,22 @@ func (manager *SSecurityGroupCacheManager) NewCache(ctx context.Context, userCre return nil, errors.Wrapf(err, "SecurityGroupManager.FetchById(%s)", secgroupId) } + return manager.newCache(ctx, secgroupId, secgroup.GetName(), vpcId, regionId, providerId, projectId) +} + +func (manager *SSecurityGroupCacheManager) newCache(ctx context.Context, secgroupId, secgroupName, vpcId, regionId string, providerId string, projectId string) (*SSecurityGroupCache, error) { secgroupCache := &SSecurityGroupCache{} secgroupCache.SecgroupId = secgroupId secgroupCache.VpcId = vpcId secgroupCache.ManagerId = providerId secgroupCache.Status = api.SECGROUP_CACHE_STATUS_CACHING secgroupCache.CloudregionId = regionId - secgroupCache.Name = secgroup.GetName() + secgroupCache.Name = secgroupName secgroupCache.ExternalProjectId = projectId secgroupCache.SetModelManager(manager, secgroupCache) - if err := manager.TableSpec().Insert(ctx, secgroupCache); err != nil { - log.Errorf("insert secgroupcache error: %v", err) - return nil, err + err := manager.TableSpec().Insert(ctx, secgroupCache) + if err != nil { + return nil, errors.Wrapf(err, "Insert") } return secgroupCache, nil } @@ -382,7 +388,7 @@ func (self *SSecurityGroupCache) GetSecgroup() (*SSecurityGroup, error) { return model.(*SSecurityGroup), nil } -func (self *SSecurityGroupCache) syncWithCloudSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, ext cloudprovider.ICloudSecurityGroup) error { +func (self *SSecurityGroupCache) syncWithCloudSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, ext cloudprovider.ICloudSecurityGroup) ([]SSecurityGroupRule, error) { _, err := db.Update(self, func() error { self.Status = api.SECGROUP_CACHE_STATUS_READY self.Name = ext.GetName() @@ -391,26 +397,26 @@ func (self *SSecurityGroupCache) syncWithCloudSecurityGroup(ctx context.Context, return nil }) if err != nil { - return errors.Wrapf(err, "db.Update") + return nil, errors.Wrapf(err, "db.Update") } secgroup, err := self.GetSecgroup() if err != nil { - return errors.Wrapf(err, "GetSecurity") + return nil, errors.Wrapf(err, "GetSecurity") } cacheCount, err := secgroup.GetSecgroupCacheCount() if err != nil { - return errors.Wrapf(err, "GetSecgroupCacheCount") + return nil, errors.Wrapf(err, "GetSecgroupCacheCount") } if cacheCount > 1 { - return nil + return nil, nil } dest := cloudprovider.NewSecRuleInfo(GetRegionDriver(provider.Provider)) dest.Rules, err = ext.GetRules() if err != nil { - return errors.Wrapf(err, "GetRules") + return nil, errors.Wrapf(err, "GetRules") } - secgroup.SyncSecurityGroupRules(ctx, userCred, dest) - return nil + rules, _ := secgroup.SyncSecurityGroupRules(ctx, userCred, dest) + return rules, nil } func (manager *SSecurityGroupCacheManager) SyncSecurityGroupCaches(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, secgroups []cloudprovider.ICloudSecurityGroup, vpc *SVpc) ([]SSecurityGroup, []cloudprovider.ICloudSecurityGroup, compare.SyncResult) { @@ -472,21 +478,25 @@ func (manager *SSecurityGroupCacheManager) SyncSecurityGroupCaches(ctx context.C } } + rules := []SSecurityGroupRule{} + for i := 0; i < len(commondb); i++ { - err = commondb[i].syncWithCloudSecurityGroup(ctx, userCred, provider, commonext[i]) + _rules, err := commondb[i].syncWithCloudSecurityGroup(ctx, userCred, provider, commonext[i]) if err != nil { syncResult.UpdateError(errors.Wrapf(err, "syncWithCloudSecurityGroup")) continue } + rules = append(rules, _rules...) syncResult.Update() } for i := 0; i < len(added); i++ { - secgroup, err := SecurityGroupManager.newFromCloudSecgroup(ctx, userCred, provider, added[i]) + secgroup, _rules, err := SecurityGroupManager.newFromCloudSecgroup(ctx, userCred, provider, added[i]) if err != nil { syncResult.AddError(errors.Wrapf(err, "newFromCloudSecgroup")) continue } + rules = append(rules, _rules...) if secgroup.ProjectId != provider.ProjectId { _, err = secgroup.PerformPublic(ctx, userCred, nil, apis.PerformPublicProjectInput{ @@ -519,6 +529,17 @@ func (manager *SSecurityGroupCacheManager) SyncSecurityGroupCaches(ctx context.C remoteSecgroups = append(remoteSecgroups, added[i]) syncResult.Add() } + for i := range rules { + if len(rules[i].PeerSecgroupId) > 0 { + cache, _ := db.FetchByExternalId(SecurityGroupCacheManager, rules[i].PeerSecgroupId) + if cache != nil { + db.Update(&rules[i], func() error { + rules[i].PeerSecgroupId = cache.(*SSecurityGroupCache).SecgroupId + return nil + }) + } + } + } return localSecgroups, remoteSecgroups, syncResult } @@ -614,7 +635,7 @@ func (manager *SSecurityGroupCacheManager) ListItemExportKeys(ctx context.Contex func (self *SSecurityGroupCache) GetISecurityGroup() (cloudprovider.ICloudSecurityGroup, error) { if len(self.ExternalId) == 0 { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty externalId") + return self.CreateISecurityGroup() } manager := self.GetCloudprovider() @@ -626,7 +647,123 @@ func (self *SSecurityGroupCache) GetISecurityGroup() (cloudprovider.ICloudSecuri if err != nil { return nil, errors.Wrapf(err, "GetIRegion") } - return iRegion.GetISecurityGroupById(self.ExternalId) + iSecgroup, err := iRegion.GetISecurityGroupById(self.ExternalId) + if err != nil { + if errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, errors.Wrap(err, "iRegion.GetSecurityGroupById") + } + return self.CreateISecurityGroup() + } + return iSecgroup, nil +} + +func (self *SSecurityGroupCache) CreateISecurityGroup() (cloudprovider.ICloudSecurityGroup, error) { + iRegion, err := self.GetIRegion() + if err != nil { + return nil, errors.Wrapf(err, "self.GetIRegion") + } + + if strings.ToLower(self.Name) == "default" { //避免有些云不支持default关键字 + self.Name = "DefaultGroup" + } + // 避免有的云不支持重名安全组 + randomString := func(prefix string, length int) string { + return fmt.Sprintf("%s-%s", prefix, rand.String(length)) + } + opts := &cloudprovider.SecurityGroupFilterOptions{ + Name: randomString(self.Name, 1), + VpcId: self.VpcId, + ProjectId: self.ExternalProjectId, + } + for i := 2; i < 30; i++ { + _, err := iRegion.GetISecurityGroupByName(opts) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + break + } + if errors.Cause(err) != cloudprovider.ErrDuplicateId { + return nil, errors.Wrapf(err, "GetISecurityGroupByName") + } + } + opts.Name = randomString(self.Name, i) + } + conf := &cloudprovider.SecurityGroupCreateInput{ + Name: opts.Name, + Desc: self.Description, + VpcId: self.VpcId, + ProjectId: self.ExternalProjectId, + } + iSecgroup, err := iRegion.CreateISecurityGroup(conf) + if err != nil { + return nil, errors.Wrapf(err, "iRegion.CreateISecurityGroup") + } + _, err = db.Update(self, func() error { + self.ExternalId = iSecgroup.GetGlobalId() + self.Name = iSecgroup.GetName() + self.Status = api.SECGROUP_CACHE_STATUS_READY + return nil + }) + return iSecgroup, nil +} + +func (self *SSecurityGroupCache) GetSecuritRuleSet() (cloudprovider.SecurityRuleSet, []SSecurityGroupCache, error) { + ruleSet := cloudprovider.SecurityRuleSet{} + secgroup, err := self.GetSecgroup() + if err != nil { + return ruleSet, nil, errors.Wrapf(err, "GetSecgroup") + } + rules, err := secgroup.getSecurityRules() + if err != nil { + return ruleSet, nil, errors.Wrapf(err, "getSecurityRules") + } + + caches := []SSecurityGroupCache{} + + driver := GetRegionDriver(self.GetProviderName()) + for i := range rules { + if !driver.IsSupportPeerSecgroup() && len(rules[i].PeerSecgroupId) > 0 { + continue + } + //这里没必要拆分为单个单个的端口,到公有云那边适配 + rule, err := rules[i].toRule() + if err != nil { + return nil, nil, errors.Wrapf(err, "toRule") + } + peerId := "" + if len(rules[i].PeerSecgroupId) > 0 { + _peerSecgroup, err := SecurityGroupManager.FetchById(rules[i].PeerSecgroupId) + if err != nil { + return nil, nil, errors.Wrapf(err, "SecurityGroupManager.FetchById(%s)", rules[i].PeerSecgroupId) + } + peerSecgroup := _peerSecgroup.(*SSecurityGroup) + peerCaches, err := peerSecgroup.GetSecurityGroupCaches() + if err != nil { + return nil, nil, errors.Wrapf(err, "peerSecgroup.GetSecurityGroupCaches") + } + + for _, cache := range peerCaches { + if cache.ManagerId == self.ManagerId && cache.VpcId == self.VpcId && len(cache.ExternalId) > 0 && (!driver.IsPeerSecgroupWithSameProject() || cache.ExternalProjectId == self.ExternalProjectId) { + peerId = cache.ExternalId + break + } + } + + if len(peerId) == 0 { + cache, err := SecurityGroupCacheManager.newCache(context.TODO(), peerSecgroup.Id, peerSecgroup.Name, self.VpcId, self.CloudregionId, self.ManagerId, self.ExternalProjectId) + if err != nil { + return nil, nil, errors.Wrapf(err, "SecurityGroupCacheManager.newCache") + } + iSecgroup, err := cache.CreateISecurityGroup() + if err != nil { + return nil, nil, errors.Wrapf(err, "cache.CreateISecurityGroup") + } + peerId = iSecgroup.GetGlobalId() + caches = append(caches, *cache) + } + } + ruleSet = append(ruleSet, cloudprovider.SecurityRule{SecurityRule: *rule, ExternalId: rules[i].Id, PeerSecgroupId: peerId}) + } + return ruleSet, caches, nil } func (self *SSecurityGroupCache) SyncRules() error { @@ -638,17 +775,13 @@ func (self *SSecurityGroupCache) SyncRules() error { 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") } - localRules, err := secgroup.GetSecuritRuleSet() + localRules, caches, err := self.GetSecuritRuleSet() if err != nil { return errors.Wrapf(err, "GetSecuritRuleSet") } @@ -664,5 +797,15 @@ func (self *SSecurityGroupCache) SyncRules() error { if len(inAdds) == 0 && len(inDels) == 0 && len(outAdds) == 0 && len(outDels) == 0 { return nil } - return iSecgroup.SyncRules(common, inAdds, outAdds, inDels, outDels) + err = iSecgroup.SyncRules(common, inAdds, outAdds, inDels, outDels) + if err != nil { + return errors.Wrapf(err, "iSecgroup.SyncRules") + } + for i := range caches { + err = caches[i].SyncRules() + if err != nil { + return errors.Wrapf(err, "SyncRules for caches %s(%s)", caches[i].Name, caches[i].Id) + } + } + return nil } diff --git a/pkg/compute/models/secgrouprules.go b/pkg/compute/models/secgrouprules.go index b2e5dc0b74..e622b11145 100644 --- a/pkg/compute/models/secgrouprules.go +++ b/pkg/compute/models/secgrouprules.go @@ -17,7 +17,6 @@ package models import ( "context" "net" - "strings" "yunion.io/x/jsonutils" "yunion.io/x/log" @@ -27,7 +26,6 @@ import ( "yunion.io/x/pkg/util/stringutils" "yunion.io/x/sqlchemy" - "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" @@ -63,40 +61,21 @@ type SSecurityGroupRule struct { db.SResourceBase SSecurityGroupResourceBase `create:"required"` - Id string `width:"128" charset:"ascii" primary:"true" list:"user"` - Priority int64 `default:"1" list:"user" update:"user" list:"user"` - Protocol string `width:"5" charset:"ascii" nullable:"false" list:"user" update:"user" create:"required"` - Ports string `width:"256" charset:"ascii" list:"user" update:"user" create:"optional"` - Direction string `width:"3" charset:"ascii" list:"user" create:"required"` - CIDR string `width:"256" charset:"ascii" list:"user" update:"user" create:"required"` - Action string `width:"5" charset:"ascii" nullable:"false" list:"user" update:"user" create:"required"` - Description string `width:"256" charset:"utf8" list:"user" update:"user" create:"optional"` - // SecgroupID string `width:"128" charset:"ascii" create:"required"` + Id string `width:"128" charset:"ascii" primary:"true" list:"user"` + Priority int64 `default:"1" list:"user" update:"user" list:"user"` + Protocol string `width:"5" charset:"ascii" nullable:"false" list:"user" update:"user" create:"required"` + Ports string `width:"256" charset:"ascii" list:"user" update:"user" create:"optional"` + Direction string `width:"3" charset:"ascii" list:"user" create:"required"` + CIDR string `width:"256" charset:"ascii" list:"user" update:"user" create:"optional"` + Action string `width:"5" charset:"ascii" nullable:"false" list:"user" update:"user" create:"required"` + Description string `width:"256" charset:"utf8" list:"user" update:"user" create:"optional"` + PeerSecgroupId string `width:"128" charset:"ascii" create:"optional" list:"user" update:"user"` } func (self *SSecurityGroupRule) GetId() string { return self.Id } -type SecurityGroupRuleSet []SSecurityGroupRule - -func (v SecurityGroupRuleSet) Len() int { - return len(v) -} - -func (v SecurityGroupRuleSet) Swap(i, j int) { - v[i], v[j] = v[j], v[i] -} - -func (v SecurityGroupRuleSet) Less(i, j int) bool { - if v[i].Priority < v[j].Priority { - return true - } else if v[i].Priority == v[j].Priority { - return strings.Compare(v[i].String(), v[j].String()) <= 0 - } - return false -} - func (manager *SSecurityGroupRuleManager) FetchUniqValues(ctx context.Context, data jsonutils.JSONObject) jsonutils.JSONObject { secgroupId, _ := data.GetString("secgroup_id") return jsonutils.Marshal(map[string]string{"secgroup_id": secgroupId}) @@ -219,6 +198,7 @@ func (manager *SSecurityGroupRuleManager) FetchCustomizeColumns( bRows := manager.SResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) secRows := manager.SSecurityGroupResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) secIds := make([]string, len(objs)) + peerIds := make([]string, len(objs)) for i := range rows { rows[i] = api.SecgroupRuleDetails{ ResourceBaseDetails: bRows[i], @@ -226,6 +206,7 @@ func (manager *SSecurityGroupRuleManager) FetchCustomizeColumns( } rule := objs[i].(*SSecurityGroupRule) secIds[i] = rule.SecgroupId + peerIds[i] = rule.PeerSecgroupId } secgroups := make(map[string]SSecurityGroup) @@ -235,6 +216,12 @@ func (manager *SSecurityGroupRuleManager) FetchCustomizeColumns( return rows } + peerMaps, err := db.FetchIdNameMap2(SecurityGroupManager, peerIds) + if err != nil { + log.Errorf("db.FetchIdNameMap2 fail: %v", err) + return rows + } + virObjs := make([]interface{}, len(objs)) for i := range rows { if secgroup, ok := secgroups[secIds[i]]; ok { @@ -246,6 +233,7 @@ func (manager *SSecurityGroupRuleManager) FetchCustomizeColumns( projRows := SecurityGroupManager.SProjectizedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, virObjs, fields, isList) for i := range rows { rows[i].ProjectizedResourceInfo = projRows[i] + rows[i].PeerSecgroup, _ = peerMaps[peerIds[i]] } return rows @@ -297,30 +285,32 @@ func (self *SSecurityGroupRule) BeforeInsert() { } func (manager *SSecurityGroupRuleManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.SSecgroupRuleCreateInput) (api.SSecgroupRuleCreateInput, error) { - data := jsonutils.Marshal(input).(*jsonutils.JSONDict) + if input.Priority == nil { + return input, httperrors.NewMissingParameterError("priority") + } + if *input.Priority < 1 || *input.Priority > 100 { + return input, httperrors.NewOutOfRangeError("Invalid priority %d, must be in range or 1 ~ 100", input.Priority) + } - priorityV := validators.NewRangeValidator("priority", 1, 100) - priorityV.Optional(true) - err := priorityV.Validate(data) + _secgroup, err := validators.ValidateModel(userCred, SecurityGroupManager, &input.SecgroupId) if err != nil { return input, err } - secgroupV := validators.NewModelIdOrNameValidator("secgroup", "secgroup", ownerId) - err = secgroupV.Validate(data) - if err != nil { - return input, err - } - - secgroup := secgroupV.Model.(*SSecurityGroup) + secgroup := _secgroup.(*SSecurityGroup) if !secgroup.IsOwner(userCred) && !userCred.HasSystemAdminPrivilege() { return input, httperrors.NewForbiddenError("not enough privilege") } - err = data.Unmarshal(&input) - if err != nil { - return input, httperrors.NewInputParameterError("Failed to unmarshal input: %v", err) + if len(input.PeerSecgroupId) > 0 { + _, err = validators.ValidateModel(userCred, SecurityGroupManager, &input.PeerSecgroupId) + if err != nil { + return input, err + } + if input.PeerSecgroupId == input.SecgroupId { + return input, httperrors.NewInputParameterError("peer_secgroup_id can not point to secgroup self") + } } err = input.Check() @@ -335,48 +325,47 @@ func (manager *SSecurityGroupRuleManager) ValidateCreateData(ctx context.Context return input, nil } -func (self *SSecurityGroupRule) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { - priorityV := validators.NewRangeValidator("priority", 1, 100) - priorityV.Optional(true) - err := priorityV.Validate(data) +func (self *SSecurityGroupRule) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.SSecgroupRuleUpdateInput) (api.SSecgroupRuleUpdateInput, error) { + priority := int(self.Priority) + output := api.SSecgroupRuleUpdateInput{ + SSecgroupRuleResource: api.SSecgroupRuleResource{ + Priority: &priority, + Protocol: self.Protocol, + Ports: self.Ports, + Direction: self.Direction, + CIDR: self.CIDR, + Action: self.Action, + Description: self.Description, + PeerSecgroupId: self.PeerSecgroupId, + }, + } + jsonutils.Update(&output, input) + + if *output.Priority < 1 || *output.Priority > 100 { + return output, httperrors.NewOutOfRangeError("Invalid priority %d, must be in range or 1 ~ 100", input.Priority) + } + + if len(input.PeerSecgroupId) > 0 { + _, err := validators.ValidateModel(userCred, SecurityGroupManager, &input.PeerSecgroupId) + if err != nil { + return output, err + } + if input.PeerSecgroupId == self.Id { + return output, httperrors.NewInputParameterError("peer_secgroup_id can not point to secgroup self") + } + } + + err := output.Check() if err != nil { - return nil, err + return output, err } - input := &api.SSecgroupRuleCreateInput{ - Direction: self.Direction, - Action: self.Action, - CIDR: self.CIDR, - Protocol: self.Protocol, - Ports: self.Ports, - Priority: int(self.Priority), - } - - err = jsonutils.Update(input, data) + output.ResourceBaseUpdateInput, err = self.SResourceBase.ValidateUpdateData(ctx, userCred, query, input.ResourceBaseUpdateInput) if err != nil { - return nil, err + return output, errors.Wrap(err, "SResourceBase.ValidateUpdateData") } - err = input.Check() - if err != nil { - return nil, err - } - - // 更新操作日志: 对比可以知道改了原有规则哪些内容 - data.Add(jsonutils.Marshal(self), "origin") - - rinput := apis.ResourceBaseUpdateInput{} - err = data.Unmarshal(&rinput) - if err != nil { - return nil, errors.Wrap(err, "Unmarshal") - } - rinput, err = self.SResourceBase.ValidateUpdateData(ctx, userCred, query, rinput) - if err != nil { - return nil, errors.Wrap(err, "SResourceBase.ValidateUpdateData") - } - data.Update(jsonutils.Marshal(rinput)) - - return data, nil + return output, nil } func (self *SSecurityGroupRule) String() string { @@ -420,6 +409,13 @@ func (self *SSecurityGroupRule) toRule() (*secrules.SecurityRule, error) { func (self *SSecurityGroupRule) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) { self.SResourceBase.PostCreate(ctx, userCred, ownerId, query, data) + if len(self.PeerSecgroupId) > 0 { + db.Update(self, func() error { + self.CIDR = "" + return nil + }) + } + log.Debugf("POST Create %s", data) if secgroup := self.GetSecGroup(); secgroup != nil { logclient.AddSimpleActionLog(secgroup, logclient.ACT_ALLOCATE, data, userCred, true) @@ -439,6 +435,13 @@ func (self *SSecurityGroupRule) PreDelete(ctx context.Context, userCred mcclient func (self *SSecurityGroupRule) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) { self.SResourceBase.PostUpdate(ctx, userCred, query, data) + if len(self.PeerSecgroupId) > 0 { + db.Update(self, func() error { + self.CIDR = "" + return nil + }) + } + log.Debugf("POST Update %s", data) if secgroup := self.GetSecGroup(); secgroup != nil { logclient.AddSimpleActionLog(secgroup, logclient.ACT_UPDATE, data, userCred, true) @@ -455,10 +458,12 @@ func (manager *SSecurityGroupRuleManager) getRulesBySecurityGroup(secgroup *SSec return rules, nil } -func (self *SSecurityGroup) newFromCloudSecurityGroupRule(ctx context.Context, userCred mcclient.TokenCredential, rule cloudprovider.SecurityRule) (*SSecurityGroupRule, error) { +func (self *SSecurityGroup) newFromCloudSecurityGroupRule(ctx context.Context, userCred mcclient.TokenCredential, rule cloudprovider.SecurityRule) (*SSecurityGroupRule, bool, error) { lockman.LockObject(ctx, self) defer lockman.ReleaseObject(ctx, self) + isNeedFix := false + protocol := rule.Protocol if len(protocol) == 0 { protocol = secrules.PROTO_ANY @@ -469,28 +474,38 @@ func (self *SSecurityGroup) newFromCloudSecurityGroupRule(ctx context.Context, u cidr = rule.IPNet.String() } + if len(rule.PeerSecgroupId) > 0 { + cidr = "" + cache, _ := db.FetchByExternalId(SecurityGroupCacheManager, rule.PeerSecgroupId) + if cache != nil { + rule.PeerSecgroupId = cache.(*SSecurityGroupCache).SecgroupId + } + isNeedFix = true + } + err := rule.ValidateRule() if err != nil { - return nil, errors.Wrapf(err, "ValidateRule") + return nil, isNeedFix, errors.Wrapf(err, "ValidateRule %s ", jsonutils.Marshal(rule).String()) } secrule := &SSecurityGroupRule{ - Priority: int64(rule.Priority), - Protocol: protocol, - Ports: rule.GetPortsString(), - Direction: string(rule.Direction), - CIDR: cidr, - Action: string(rule.Action), - Description: rule.Description, + Priority: int64(rule.Priority), + Protocol: protocol, + Ports: rule.GetPortsString(), + Direction: string(rule.Direction), + CIDR: cidr, + Action: string(rule.Action), + Description: rule.Description, + PeerSecgroupId: rule.PeerSecgroupId, } secrule.SetModelManager(SecurityGroupRuleManager, secrule) secrule.SecgroupId = self.Id err = SecurityGroupRuleManager.TableSpec().Insert(ctx, secrule) if err != nil { - return nil, errors.Wrapf(err, "SecurityGroupRuleManager.Insert") + return nil, isNeedFix, errors.Wrapf(err, "SecurityGroupRuleManager.Insert") } - return secrule, nil + return secrule, isNeedFix, nil } func (self *SSecurityGroupRule) GetOwnerId() mcclient.IIdentityProvider { diff --git a/pkg/compute/models/secgroups.go b/pkg/compute/models/secgroups.go index 20f7358be1..e32c9a6b17 100644 --- a/pkg/compute/models/secgroups.go +++ b/pkg/compute/models/secgroups.go @@ -527,7 +527,7 @@ func (self *SSecurityGroup) PostCreate(ctx context.Context, userCred mcclient.To for _, r := range input.Rules { rule := &SSecurityGroupRule{ - Priority: int64(r.Priority), + Priority: int64(*r.Priority), Protocol: r.Protocol, Ports: r.Ports, Direction: r.Direction, @@ -944,12 +944,12 @@ func (self *SSecurityGroup) removeRules(ruleIds []string, result *compare.SyncRe } } -func (self *SSecurityGroup) SyncSecurityGroupRules(ctx context.Context, userCred mcclient.TokenCredential, src cloudprovider.SecRuleInfo) compare.SyncResult { +func (self *SSecurityGroup) SyncSecurityGroupRules(ctx context.Context, userCred mcclient.TokenCredential, src cloudprovider.SecRuleInfo) ([]SSecurityGroupRule, compare.SyncResult) { result := compare.SyncResult{} localRules, err := self.GetSecuritRuleSet() if err != nil { result.Error(errors.Wrapf(err, "GetSecuritRuleSet")) - return result + return nil, result } dest := cloudprovider.NewSecRuleInfo(GetRegionDriver(api.CLOUD_PROVIDER_ONECLOUD)) @@ -957,7 +957,7 @@ func (self *SSecurityGroup) SyncSecurityGroupRules(ctx context.Context, userCred _, inAdds, outAdds, inDels, outDels := cloudprovider.CompareRules(src, dest, false) if len(inAdds)+len(inDels)+len(outAdds)+len(outDels) == 0 { - return result + return nil, result } ruleIds := []string{} @@ -971,27 +971,31 @@ func (self *SSecurityGroup) SyncSecurityGroupRules(ctx context.Context, userCred self.removeRules(ruleIds, &result) + rules := []SSecurityGroupRule{} for _, adds := range [][]cloudprovider.SecurityRule{inAdds, outAdds} { for i := range adds { - _, err := self.newFromCloudSecurityGroupRule(ctx, userCred, adds[i]) + rule, isNeedFix, err := self.newFromCloudSecurityGroupRule(ctx, userCred, adds[i]) if err != nil { result.AddError(errors.Wrapf(err, "newFromCloudSecurityGroupRule")) continue } + if isNeedFix && rule != nil { + rules = append(rules, *rule) + } result.Add() } } log.Infof("Sync Rules for Secgroup %s(%s) result: %s", self.Name, self.Id, result.Result()) - return result + return rules, result } -func (manager *SSecurityGroupManager) newFromCloudSecgroup(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, extSec cloudprovider.ICloudSecurityGroup) (*SSecurityGroup, error) { +func (manager *SSecurityGroupManager) newFromCloudSecgroup(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, extSec cloudprovider.ICloudSecurityGroup) (*SSecurityGroup, []SSecurityGroupRule, error) { dest := cloudprovider.NewSecRuleInfo(GetRegionDriver(provider.Provider)) var err error dest.Rules, err = extSec.GetRules() if err != nil { - return nil, errors.Wrapf(err, "extSec.GetRules") + return nil, nil, errors.Wrapf(err, "extSec.GetRules") } src := cloudprovider.NewSecRuleInfo(GetRegionDriver(api.CLOUD_PROVIDER_ONECLOUD)) @@ -1001,7 +1005,7 @@ func (manager *SSecurityGroupManager) newFromCloudSecgroup(ctx context.Context, q := manager.Query().Equals("domain_id", provider.DomainId) err = db.FetchModelObjects(manager, q, &secgroups) if err != nil { - return nil, errors.Wrap(err, "db.FetchModelObjects") + return nil, nil, errors.Wrap(err, "db.FetchModelObjects") } for i := range secgroups { src.Rules, err = secgroups[i].GetSecuritRuleSet() @@ -1011,7 +1015,7 @@ func (manager *SSecurityGroupManager) newFromCloudSecgroup(ctx context.Context, } _, inAdds, outAdds, inDels, outDels := cloudprovider.CompareRules(src, dest, false) if len(inAdds) == 0 && len(outAdds) == 0 && len(inDels) == 0 && len(outDels) == 0 { - return &secgroups[i], nil + return &secgroups[i], nil, nil } } } @@ -1023,7 +1027,7 @@ func (manager *SSecurityGroupManager) newFromCloudSecgroup(ctx context.Context, secgroup.SetModelManager(manager, &secgroup) secgroup.Name, err = db.GenerateName(manager, userCred, extSec.GetName()) if err != nil { - return nil, err + return nil, nil, err } secgroup.Status = api.SECGROUP_STATUS_READY @@ -1033,13 +1037,13 @@ func (manager *SSecurityGroupManager) newFromCloudSecgroup(ctx context.Context, err = manager.TableSpec().Insert(ctx, &secgroup) if err != nil { - return nil, errors.Wrapf(err, "Insert") + return nil, nil, errors.Wrapf(err, "Insert") } - secgroup.SyncSecurityGroupRules(ctx, userCred, dest) + rules, _ := secgroup.SyncSecurityGroupRules(ctx, userCred, dest) db.OpsLog.LogEvent(&secgroup, db.ACT_CREATE, secgroup.GetShortDesc(ctx), userCred) - return &secgroup, nil + return &secgroup, rules, nil } func (manager *SSecurityGroupManager) DelaySync(ctx context.Context, userCred mcclient.TokenCredential, idStr string) error { @@ -1254,6 +1258,9 @@ func (self *SSecurityGroup) AllowPerformImportRules(ctx context.Context, userCre func (self *SSecurityGroup) PerformImportRules(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.SecgroupImportRulesInput) (jsonutils.JSONObject, error) { for i := range input.Rules { + if input.Rules[i].Priority == nil { + return nil, httperrors.NewMissingParameterError("priority") + } err := input.Rules[i].Check() if err != nil { return nil, httperrors.NewInputParameterError("rule %d is invalid: %s", i+1, err) @@ -1261,7 +1268,7 @@ func (self *SSecurityGroup) PerformImportRules(ctx context.Context, userCred mcc } for _, r := range input.Rules { rule := &SSecurityGroupRule{ - Priority: int64(r.Priority), + Priority: int64(*r.Priority), Protocol: r.Protocol, Ports: r.Ports, Direction: r.Direction, diff --git a/pkg/compute/models/syncworkers.go b/pkg/compute/models/syncworkers.go index 84e626de98..0413b2c3e8 100644 --- a/pkg/compute/models/syncworkers.go +++ b/pkg/compute/models/syncworkers.go @@ -28,10 +28,9 @@ import ( ) var ( - syncSecgroupWorker *appsrv.SWorkerManager - syncAccountWorker *appsrv.SWorkerManager - syncWorkers []*appsrv.SWorkerManager - syncWorkerRing *hashring.HashRing + syncAccountWorker *appsrv.SWorkerManager + syncWorkers []*appsrv.SWorkerManager + syncWorkerRing *hashring.HashRing ) func InitSyncWorkers(count int) { @@ -53,12 +52,6 @@ func InitSyncWorkers(count int) { 2048, true, ) - syncSecgroupWorker = appsrv.NewWorkerManager( - "syncSecgroupProbeWorkerManager", - 1, - 2048, - true, - ) } func RunSyncCloudproviderRegionTask(ctx context.Context, key string, syncFunc func()) { @@ -75,9 +68,3 @@ func RunSyncCloudAccountTask(ctx context.Context, probeFunc func()) { panicutils.SendPanicMessage(ctx, err) }) } - -func RunSyncSecgroupTask(ctx context.Context, syncFunc func()) { - syncSecgroupWorker.Run(syncFunc, nil, func(err error) { - panicutils.SendPanicMessage(ctx, err) - }) -} diff --git a/pkg/compute/regiondrivers/aliyun.go b/pkg/compute/regiondrivers/aliyun.go index 07377d63a9..51e2488d9d 100644 --- a/pkg/compute/regiondrivers/aliyun.go +++ b/pkg/compute/regiondrivers/aliyun.go @@ -69,6 +69,10 @@ func (self *SAliyunRegionDriver) GetSecurityGroupRuleMinPriority() int { return 100 } +func (self *SAliyunRegionDriver) IsSupportPeerSecgroup() bool { + return true +} + func (self *SAliyunRegionDriver) GetProvider() string { return api.CLOUD_PROVIDER_ALIYUN } diff --git a/pkg/compute/regiondrivers/base.go b/pkg/compute/regiondrivers/base.go index 89a1ef223b..f0b8d820c7 100644 --- a/pkg/compute/regiondrivers/base.go +++ b/pkg/compute/regiondrivers/base.go @@ -267,6 +267,14 @@ func (self *SBaseRegionDriver) IsOnlySupportAllowRules() bool { return false } +func (self *SBaseRegionDriver) IsSupportPeerSecgroup() bool { + return false +} + +func (self *SBaseRegionDriver) IsPeerSecgroupWithSameProject() bool { + return false +} + func (self *SBaseRegionDriver) GetDefaultSecurityGroupInRule() cloudprovider.SecurityRule { return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("in:deny any")} } diff --git a/pkg/compute/regiondrivers/kvm.go b/pkg/compute/regiondrivers/kvm.go index d1eb291515..55085b54df 100644 --- a/pkg/compute/regiondrivers/kvm.go +++ b/pkg/compute/regiondrivers/kvm.go @@ -24,7 +24,6 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/secrules" "yunion.io/x/pkg/utils" api "yunion.io/x/onecloud/pkg/apis/compute" @@ -68,24 +67,8 @@ func (self *SKVMRegionDriver) GetProvider() string { return api.CLOUD_PROVIDER_ONECLOUD } -func GetDefaultSecurityGroupInRule() cloudprovider.SecurityRule { - return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("in:deny any")} -} - -func GetDefaultSecurityGroupOutRule() cloudprovider.SecurityRule { - return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("out:allow any")} -} - -func GetSecurityGroupRuleMaxPriority() int { - return 100 -} - -func GetSecurityGroupRuleMinPriority() int { - return 1 -} - -func IsOnlySupportAllowRules() bool { - return false +func (self *SKVMRegionDriver) IsSupportPeerSecgroup() bool { + return true } func (self *SKVMRegionDriver) ValidateCreateLoadbalancerData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { diff --git a/pkg/compute/regiondrivers/managedvirtual.go b/pkg/compute/regiondrivers/managedvirtual.go index 5f5b5e3b67..d176cddc80 100644 --- a/pkg/compute/regiondrivers/managedvirtual.go +++ b/pkg/compute/regiondrivers/managedvirtual.go @@ -1605,116 +1605,7 @@ func (self *SManagedVirtualizationRegionDriver) RequestSyncSecurityGroup(ctx con return "", errors.Wrap(err, "SSecurityGroupCache.Register") } - waitChan := make(chan error) - - models.RunSyncSecgroupTask(ctx, func() { - err := func() error { - iRegion, err := vpc.GetIRegion() - if err != nil { - return errors.Wrap(err, "vpc.GetIRegion") - } - - var iSecgroup cloudprovider.ICloudSecurityGroup = nil - if len(cache.ExternalId) > 0 { - iSecgroup, err = iRegion.GetISecurityGroupById(cache.ExternalId) - if err != nil { - if errors.Cause(err) != cloudprovider.ErrNotFound { - return errors.Wrap(err, "iRegion.GetSecurityGroupById") - } - cache.ExternalId = "" - } - } - - if len(cache.ExternalId) == 0 { - if strings.ToLower(secgroup.Name) == "default" { //避免有些云不支持default关键字 - secgroup.Name = "DefaultGroup" - } - // 避免有的云不支持重名安全组 - randomString := func(prefix string, length int) string { - return fmt.Sprintf("%s-%s", prefix, rand.String(length)) - } - opts := &cloudprovider.SecurityGroupFilterOptions{ - Name: randomString(secgroup.Name, 1), - VpcId: vpcId, - ProjectId: remoteProjectId, - } - for i := 2; i < 30; i++ { - _, err := iRegion.GetISecurityGroupByName(opts) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - break - } - if errors.Cause(err) != cloudprovider.ErrDuplicateId { - return errors.Wrapf(err, "GetISecurityGroupByName") - } - } - opts.Name = randomString(secgroup.Name, i) - } - conf := &cloudprovider.SecurityGroupCreateInput{ - Name: opts.Name, - Desc: secgroup.Description, - VpcId: vpcId, - ProjectId: remoteProjectId, - } - conf.Rules, err = secgroup.GetSecRules() - if err != nil { - return errors.Wrapf(err, "GetSecRules") - } - iSecgroup, err = iRegion.CreateISecurityGroup(conf) - if err != nil { - return errors.Wrapf(err, "iRegion.CreateISecurityGroup") - } - } - - _, err = db.Update(cache, func() error { - cache.ExternalId = iSecgroup.GetGlobalId() - cache.Name = iSecgroup.GetName() - cache.Status = api.SECGROUP_CACHE_STATUS_READY - return nil - }) - - if err != nil { - return errors.Wrapf(err, "db.Update") - } - - rules, err := iSecgroup.GetRules() - if err != nil { - return errors.Wrapf(err, "iSecgroup.GetRules") - } - - localRules, err := secgroup.GetSecuritRuleSet() - if err != nil { - return errors.Wrapf(err, "GetSecuritRuleSet") - } - - src := cloudprovider.NewSecRuleInfo(&SKVMRegionDriver{}) - src.Rules = localRules - - dest := cloudprovider.NewSecRuleInfo(region.GetDriver()) - dest.Rules = rules - - common, inAdds, outAdds, inDels, outDels := cloudprovider.CompareRules(src, dest, false) - - if len(inAdds) == 0 && len(inDels) == 0 && len(outAdds) == 0 && len(outDels) == 0 { - return nil - } - return iSecgroup.SyncRules(common, inAdds, outAdds, inDels, outDels) - }() - - waitChan <- err - }) - - err = <-waitChan - if err != nil { - return "", err - } - - cache, err = models.SecurityGroupCacheManager.Register(ctx, userCred, secgroup.Id, vpcId, region.Id, vpc.ManagerId, remoteProjectId) - if err != nil { - return "", errors.Wrap(err, "SSecurityGroupCache.Register") - } - - return cache.ExternalId, nil + return cache.ExternalId, cache.SyncRules() } func (self *SManagedVirtualizationRegionDriver) RequestCacheSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, region *models.SCloudregion, vpc *models.SVpc, secgroup *models.SSecurityGroup, classic bool, removeProjectId string, task taskman.ITask) error { diff --git a/pkg/compute/regiondrivers/qcloud.go b/pkg/compute/regiondrivers/qcloud.go index d91e706174..b97d11ed54 100644 --- a/pkg/compute/regiondrivers/qcloud.go +++ b/pkg/compute/regiondrivers/qcloud.go @@ -69,6 +69,14 @@ func (self *SQcloudRegionDriver) GetSecurityGroupRuleMinPriority() int { return 100 } +func (self *SQcloudRegionDriver) IsSupportPeerSecgroup() bool { + return true +} + +func (self *SQcloudRegionDriver) IsPeerSecgroupWithSameProject() bool { + return true +} + func (self *SQcloudRegionDriver) GetProvider() string { return api.CLOUD_PROVIDER_QCLOUD } diff --git a/pkg/compute/regiondrivers/secgroup_kvm_test.go b/pkg/compute/regiondrivers/secgroup_kvm_test.go index 3663f15944..6f77f5e051 100644 --- a/pkg/compute/regiondrivers/secgroup_kvm_test.go +++ b/pkg/compute/regiondrivers/secgroup_kvm_test.go @@ -75,6 +75,22 @@ func TestKvmRuleSync(t *testing.T) { }, OutDels: []cloudprovider.SecurityRule{}, }, + { + Name: "Test aliyun peer rules", + SrcRules: cloudprovider.SecurityRuleSet{ + ruleWithPeerSecgroup("allow tcp 443", "in:allow tcp 443", 1, "peer1"), + ruleWithName("deny tcp 1521", "in:deny tcp 1521", 12), + }, + DestRules: []cloudprovider.SecurityRule{}, + Common: []cloudprovider.SecurityRule{}, + InAdds: []cloudprovider.SecurityRule{ + ruleWithPeerSecgroup("allow tcp 443", "in:allow tcp 443", 51, "peer1"), + ruleWithName("deny tcp 1521", "in:deny tcp 1521", 51), + }, + OutAdds: []cloudprovider.SecurityRule{}, + InDels: []cloudprovider.SecurityRule{}, + OutDels: []cloudprovider.SecurityRule{}, + }, } for _, d := range aliyun { diff --git a/pkg/compute/regiondrivers/secgroup_test.go b/pkg/compute/regiondrivers/secgroup_test.go index 84ed022df7..44130c1d40 100644 --- a/pkg/compute/regiondrivers/secgroup_test.go +++ b/pkg/compute/regiondrivers/secgroup_test.go @@ -114,6 +114,15 @@ var ruleWithName = func(name, ruleStr string, priority int) cloudprovider.Securi } } +var ruleWithPeerSecgroup = func(name, ruleStr string, priority int, peerSecgroup string) cloudprovider.SecurityRule { + return cloudprovider.SecurityRule{ + Name: name, + ExternalId: name, + PeerSecgroupId: peerSecgroup, + SecurityRule: ruleWithPriority(ruleStr, priority).SecurityRule, + } +} + var check = func(t *testing.T, name string, ret, expect []cloudprovider.SecurityRule, min, max int) { var show = func(info string, rules []cloudprovider.SecurityRule) { t.Logf("%s: %d\n", info, len(rules)) diff --git a/pkg/mcclient/modules/mod_secgrouprules.go b/pkg/mcclient/modules/mod_secgrouprules.go index e0583a1738..e44761b4d6 100644 --- a/pkg/mcclient/modules/mod_secgrouprules.go +++ b/pkg/mcclient/modules/mod_secgrouprules.go @@ -24,7 +24,7 @@ func init() { SecGroupRules = NewComputeManager("secgrouprule", "secgrouprules", []string{"ID", "Name", "Direction", "Action", "Protocol", "Ports", "Priority", - "Cidr", "Secgroup", "Tenant", "Description"}, + "Cidr", "Secgroup", "Peer_Secgroup_Id", "Peer_Secgroup", "Tenant", "Description"}, []string{"SecGroups"}) registerCompute(&SecGroupRules) diff --git a/pkg/mcclient/options/base.go b/pkg/mcclient/options/base.go index 6dee13004c..3a8d3ebd41 100644 --- a/pkg/mcclient/options/base.go +++ b/pkg/mcclient/options/base.go @@ -381,16 +381,24 @@ type EnabledStatusCreateOptions struct { Enabled *bool `help:"turn on enabled flag"` } +type BaseIdOptions struct { + ID string `json:"-"` +} + +func (o *BaseIdOptions) GetId() string { + return o.ID +} + +func (o *BaseIdOptions) Params() (jsonutils.JSONObject, error) { + return nil, nil +} + type BaseShowOptions struct { - ID string `json:"-"` - WithMeta *bool `help:"With meta data"` - ShowFailReason *bool `help:"show fail reason fields"` + BaseIdOptions + WithMeta *bool `help:"With meta data"` + ShowFailReason *bool `help:"show fail reason fields"` } func (o BaseShowOptions) Params() (jsonutils.JSONObject, error) { return StructToParams(o) } - -func (o BaseShowOptions) GetId() string { - return o.ID -} diff --git a/pkg/mcclient/options/compute/secgrouprule.go b/pkg/mcclient/options/compute/secgrouprule.go new file mode 100644 index 0000000000..3061d17e04 --- /dev/null +++ b/pkg/mcclient/options/compute/secgrouprule.go @@ -0,0 +1,106 @@ +// 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 compute + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/secrules" + + "yunion.io/x/onecloud/pkg/mcclient/options" +) + +type SecGroupRulesListOptions struct { + options.BaseListOptions + Secgroup string `help:"Secgroup ID or Name"` + SecgroupName string `help:"Search rules by fuzzy secgroup name"` + Projects []string `help:"Filter rules by project"` + Direction string `help:"filter Direction of rule" choices:"in|out"` + Protocol string `help:"filter Protocol of rule" choices:"any|tcp|udp|icmp"` + Action string `help:"filter Actin of rule" choices:"allow|deny"` + Ports string `help:"filter Ports of rule"` + Ip string `help:"filter cidr of rule"` +} + +func (opts *SecGroupRulesListOptions) Params() (jsonutils.JSONObject, error) { + return options.ListStructToParams(opts) +} + +type SecGroupRulesCreateOptions struct { + SECGROUP string `help:"Secgroup ID or Name" metavar:"Secgroup"` + RULE string `json:"-"` + Priority int64 `help:"priority of Rule" default:"50"` + Desc string `help:"Description" json:"description"` + PeerSecgroupId string `help:"Peer Secgroup Id" json:"peer_secgroup_id"` +} + +func (opts *SecGroupRulesCreateOptions) Params() (jsonutils.JSONObject, error) { + rule, err := secrules.ParseSecurityRule(opts.RULE) + if err != nil { + return nil, errors.Wrapf(err, "invalid rule %s", opts.RULE) + } + return jsonutils.Marshal(map[string]interface{}{ + "direction": rule.Direction, + "action": rule.Action, + "protocol": rule.Protocol, + "cidr": rule.IPNet.String(), + "ports": rule.GetPortsString(), + "priority": opts.Priority, + "description": opts.Desc, + "secgroup_id": opts.SECGROUP, + "peer_secgroup_id": opts.PeerSecgroupId, + }), nil +} + +type SecGroupRulesUpdateOptions struct { + options.BaseIdOptions + Name string `help:"New name of rule"` + Priority int64 `help:"priority of Rule"` + Protocol string `help:"Protocol of rule" choices:"any|tcp|udp|icmp"` + Ports string `help:"Ports of rule"` + Cidr string `help:"Cidr of rule"` + Action string `help:"filter Actin of rule" choices:"allow|deny"` + Desc string `help:"Description" metavar:"Description"` + PeerSecgroupId string `help:"Peer Secgroup Id" json:"peer_secgroup_id"` +} + +func (opts *SecGroupRulesUpdateOptions) Params() (jsonutils.JSONObject, error) { + params := jsonutils.NewDict() + if len(opts.Name) > 0 { + params.Add(jsonutils.NewString(opts.Name), "name") + } + if len(opts.Desc) > 0 { + params.Add(jsonutils.NewString(opts.Desc), "description") + } + if opts.Priority > 0 { + params.Add(jsonutils.NewInt(opts.Priority), "priority") + } + if len(opts.Protocol) > 0 { + params.Add(jsonutils.NewString(opts.Protocol), "protocol") + } + if len(opts.Ports) > 0 { + params.Add(jsonutils.NewString(opts.Ports), "ports") + } + if len(opts.Cidr) > 0 { + params.Add(jsonutils.NewString(opts.Cidr), "cidr") + } + if len(opts.Action) > 0 { + params.Add(jsonutils.NewString(opts.Action), "action") + } + if len(opts.PeerSecgroupId) > 0 { + params.Add(jsonutils.NewString(opts.PeerSecgroupId), "peer_secgroup_id") + } + return params, nil +} diff --git a/pkg/multicloud/aliyun/securitygroup.go b/pkg/multicloud/aliyun/securitygroup.go index b76a239e80..1cbd180db5 100644 --- a/pkg/multicloud/aliyun/securitygroup.go +++ b/pkg/multicloud/aliyun/securitygroup.go @@ -300,7 +300,7 @@ func (self *SRegion) modifySecurityGroup(secGrpId string, name string, desc stri return err } -func (self *SRegion) AddSecurityGroupRules(secGrpId string, rule secrules.SecurityRule) error { +func (self *SRegion) AddSecurityGroupRules(secGrpId string, rule cloudprovider.SecurityRule) error { if len(rule.Ports) != 0 { for _, port := range rule.Ports { rule.PortStart, rule.PortEnd = port, port @@ -314,7 +314,7 @@ func (self *SRegion) AddSecurityGroupRules(secGrpId string, rule secrules.Securi return self.addSecurityGroupRule(secGrpId, rule) } -func (self *SRegion) addSecurityGroupRule(secGrpId string, rule secrules.SecurityRule) error { +func (self *SRegion) addSecurityGroupRule(secGrpId string, rule cloudprovider.SecurityRule) error { params := make(map[string]string) params["RegionId"] = self.RegionId params["SecurityGroupId"] = secGrpId @@ -340,13 +340,15 @@ func (self *SRegion) addSecurityGroupRule(secGrpId string, rule secrules.Securit } // 忽略地址为0.0.0.0/32这样的阿里云规则 - if rule.IPNet.IP.String() == "0.0.0.0" && rule.IPNet.String() != "0.0.0.0/0" { + if rule.IPNet.IP.String() == "0.0.0.0" && rule.IPNet.String() != "0.0.0.0/0" && len(rule.PeerSecgroupId) == 0 { return nil } params["Priority"] = fmt.Sprintf("%d", rule.Priority) if rule.Direction == secrules.SecurityRuleIngress { - if rule.IPNet != nil { + if len(rule.PeerSecgroupId) > 0 { + params["SourceGroupId"] = rule.PeerSecgroupId + } else if rule.IPNet != nil { params["SourceCidrIp"] = rule.IPNet.String() } else { params["SourceCidrIp"] = "0.0.0.0/0" @@ -354,7 +356,9 @@ func (self *SRegion) addSecurityGroupRule(secGrpId string, rule secrules.Securit _, err := self.ecsRequest("AuthorizeSecurityGroup", params) return err } else { // rule.Direction == secrules.SecurityRuleEgress { - if rule.IPNet != nil { + if len(rule.PeerSecgroupId) > 0 { + params["DestGroupId"] = rule.PeerSecgroupId + } else if rule.IPNet != nil { params["DestCidrIp"] = rule.IPNet.String() } else { params["DestCidrIp"] = "0.0.0.0/0" @@ -364,7 +368,7 @@ func (self *SRegion) addSecurityGroupRule(secGrpId string, rule secrules.Securit } } -func (self *SRegion) DelSecurityGroupRule(secGrpId string, rule secrules.SecurityRule) error { +func (self *SRegion) DelSecurityGroupRule(secGrpId string, rule cloudprovider.SecurityRule) error { params := make(map[string]string) params["RegionId"] = self.RegionId params["SecurityGroupId"] = secGrpId @@ -389,7 +393,9 @@ func (self *SRegion) DelSecurityGroupRule(secGrpId string, rule secrules.Securit } params["Priority"] = fmt.Sprintf("%d", rule.Priority) if rule.Direction == secrules.SecurityRuleIngress { - if rule.IPNet != nil { + if len(rule.PeerSecgroupId) > 0 { + params["SourceGroupId"] = rule.PeerSecgroupId + } else if rule.IPNet != nil { params["SourceCidrIp"] = rule.IPNet.String() } else { params["SourceCidrIp"] = "0.0.0.0/0" @@ -397,7 +403,9 @@ func (self *SRegion) DelSecurityGroupRule(secGrpId string, rule secrules.Securit _, err := self.ecsRequest("RevokeSecurityGroup", params) return err } else { // rule.Direction == secrules.SecurityRuleEgress { - if rule.IPNet != nil { + if len(rule.PeerSecgroupId) > 0 { + params["DestGroupId"] = rule.PeerSecgroupId + } else if rule.IPNet != nil { params["DestCidrIp"] = rule.IPNet.String() } else { params["DestCidrIp"] = "0.0.0.0/0" @@ -409,6 +417,7 @@ func (self *SRegion) DelSecurityGroupRule(secGrpId string, rule secrules.Securit func (self *SPermission) toRule() (cloudprovider.SecurityRule, error) { rule := cloudprovider.SecurityRule{ + PeerSecgroupId: self.SourceGroupId, SecurityRule: secrules.SecurityRule{ Action: secrules.SecurityRuleDeny, Direction: secrules.DIR_IN, @@ -426,6 +435,7 @@ func (self *SPermission) toRule() (cloudprovider.SecurityRule, error) { if self.Direction == "egress" { rule.Direction = secrules.DIR_OUT cidr = self.DestCidrIp + rule.PeerSecgroupId = self.DestGroupId } rule.ParseCIDR(cidr) @@ -508,13 +518,13 @@ func (self *SSecurityGroup) GetProjectId() string { func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { for _, rule := range append(inDels, outDels...) { - err := self.vpc.region.DelSecurityGroupRule(self.SecurityGroupId, rule.SecurityRule) + err := self.vpc.region.DelSecurityGroupRule(self.SecurityGroupId, rule) if err != nil { return errors.Wrapf(err, "DelSecurityGroupRule(Name:%s priority: %d %s)", rule.Name, rule.Priority, rule.String()) } } for _, rule := range append(inAdds, outAdds...) { - err := self.vpc.region.AddSecurityGroupRules(self.SecurityGroupId, rule.SecurityRule) + err := self.vpc.region.AddSecurityGroupRules(self.SecurityGroupId, rule) if err != nil { return errors.Wrapf(err, "AddSecurityGroupRules(priority: %d %s)", rule.Priority, rule.String()) } diff --git a/pkg/multicloud/qcloud/securitygroup.go b/pkg/multicloud/qcloud/securitygroup.go index 55a5cda4c6..c73d138eee 100644 --- a/pkg/multicloud/qcloud/securitygroup.go +++ b/pkg/multicloud/qcloud/securitygroup.go @@ -212,6 +212,9 @@ func (self *SecurityGroupPolicy) toRules() []cloudprovider.SecurityRule { return nil } result = append(result, rules...) + } else if len(self.SecurityGroupId) > 0 { + rule.PeerSecgroupId = self.SecurityGroupId + result = append(result, rule) } else if len(self.CidrBlock) > 0 { rule.ParseCIDR(self.CidrBlock) result = append(result, rule) @@ -367,7 +370,11 @@ func (self *SRegion) AddRule(secgroupId string, policyIndex int, rule cloudprovi params[fmt.Sprintf("SecurityGroupPolicySet.%s.0.Action", direction)] = action params[fmt.Sprintf("SecurityGroupPolicySet.%s.0.PolicyDescription", direction)] = rule.Description params[fmt.Sprintf("SecurityGroupPolicySet.%s.0.Protocol", direction)] = protocol - params[fmt.Sprintf("SecurityGroupPolicySet.%s.0.CidrBlock", direction)] = rule.IPNet.String() + if len(rule.PeerSecgroupId) > 0 { + params[fmt.Sprintf("SecurityGroupPolicySet.%s.0.SecurityGroupId", direction)] = rule.PeerSecgroupId + } else { + params[fmt.Sprintf("SecurityGroupPolicySet.%s.0.CidrBlock", direction)] = rule.IPNet.String() + } if rule.Protocol == secrules.PROTO_TCP || rule.Protocol == secrules.PROTO_UDP { port := "ALL" if rule.PortEnd > 0 && rule.PortStart > 0 { diff --git a/pkg/vpcagent/ovn/keeper.go b/pkg/vpcagent/ovn/keeper.go index 67d12efa09..b361c84726 100644 --- a/pkg/vpcagent/ovn/keeper.go +++ b/pkg/vpcagent/ovn/keeper.go @@ -578,6 +578,10 @@ func (keeper *OVNNorthboundKeeper) ClaimGuestnetwork(ctx context.Context, guestn { sgrs := guest.OrderedSecurityGroupRules() for _, sgr := range sgrs { + // kvm not support peer secgroup + if len(sgr.PeerSecgroupId) > 0 { + continue + } acl, err := ruleToAcl(lportName, sgr) if err != nil { log.Errorf("converting security group rule to acl: %v", err)