Merge pull request #10233 from ioito/feat/qx-peer-secgroup

fix(region): support peer secgroup
This commit is contained in:
Zexi Li
2021-02-22 20:39:36 +08:00
committed by GitHub
23 changed files with 611 additions and 489 deletions
+8 -133
View File
@@ -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{})
}
+30 -13
View File
@@ -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,
+2 -1
View File
@@ -22,5 +22,6 @@ type SecgroupRuleDetails struct {
SSecurityGroupRule
SecurityGroupResourceInfo
ProjectId string `json:"tenant_id"`
ProjectId string `json:"tenant_id"`
PeerSecgroup string `json:"peer_secgroup"`
}
+3
View File
@@ -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()
+68 -50
View File
@@ -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 {
+2
View File
@@ -134,6 +134,8 @@ type IRegionDriver interface {
GetSecurityGroupRuleMaxPriority() int
GetSecurityGroupRuleMinPriority() int
IsOnlySupportAllowRules() bool
IsPeerSecgroupWithSameProject() bool
IsSupportPeerSecgroup() bool
IsSupportClassicSecurityGroup() bool
IsSecurityGroupBelongVpc() bool
IsVpcBelongGlobalVpc() bool
+165 -22
View File
@@ -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
}
+106 -91
View File
@@ -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 {
+22 -15
View File
@@ -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,
+3 -16
View File
@@ -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)
})
}
+4
View File
@@ -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
}
+8
View File
@@ -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")}
}
+2 -19
View File
@@ -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) {
+1 -110
View File
@@ -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 {
+8
View File
@@ -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
}
@@ -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 {
@@ -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))
+1 -1
View File
@@ -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)
+15 -7
View File
@@ -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
}
@@ -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
}
+20 -10
View File
@@ -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())
}
+8 -1
View File
@@ -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 {
+4
View File
@@ -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)