Merge pull request #6731 from ioito/automated-cherry-pick-of-#6663-upstream-release-3.2

Automated cherry pick of #6663: fix: 优化安全组同步逻辑
This commit is contained in:
Zexi Li
2020-06-10 11:19:30 +08:00
committed by GitHub
50 changed files with 1843 additions and 1703 deletions
+2 -3
View File
@@ -20,7 +20,6 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/tristate"
"yunion.io/x/pkg/util/secrules"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/billing"
@@ -346,10 +345,10 @@ type ICloudSecurityGroup interface {
ICloudResource
GetDescription() string
GetRules() ([]secrules.SecurityRule, error)
GetRules() ([]SecurityRule, error)
GetVpcId() string
SyncRules(rules []secrules.SecurityRule) error
SyncRules(common, inAdds, outAdds, inDels, outDels []SecurityRule) error
Delete() error
}
+274 -1
View File
@@ -14,7 +14,15 @@
package cloudprovider
import "yunion.io/x/pkg/util/secrules"
import (
"sort"
"strings"
"yunion.io/x/log"
"yunion.io/x/pkg/util/secrules"
)
const DEFAULT_CLOUD_RULE_ID = "default_cloud_rule_id"
type SecurityGroupCreateInput struct {
Name string
@@ -22,3 +30,268 @@ type SecurityGroupCreateInput struct {
VpcId string
Rules []secrules.SecurityRule
}
type SecurityRule struct {
secrules.SecurityRule
Name string
ExternalId string
}
type TPriorityOrder int
var (
PriorityOrderByDesc = TPriorityOrder(1)
PriorityOrderByAsc = TPriorityOrder(-1)
)
func (r SecurityRule) String() string {
return r.SecurityRule.String()
}
type SecurityRuleSet []SecurityRule
func (srs SecurityRuleSet) Len() int {
return len(srs)
}
func (srs SecurityRuleSet) Swap(i, j int) {
srs[i], srs[j] = srs[j], srs[i]
}
func (srs SecurityRuleSet) Less(i, j int) bool {
return srs[i].Priority < srs[j].Priority || (srs[i].Priority == srs[j].Priority && srs[i].String() < srs[j].String())
}
func (srs SecurityRuleSet) AllowList() secrules.SecurityRuleSet {
rules := secrules.SecurityRuleSet{}
for _, r := range srs {
rules = append(rules, r.SecurityRule)
}
return rules.AllowList()
}
func AddDefaultRule(rules []SecurityRule, defaultRule SecurityRule, localRuleStr string, order TPriorityOrder, min, max int, onlyAllowRules bool) []SecurityRule {
if defaultRule.String() == localRuleStr {
return rules
}
defaultRule.ExternalId = DEFAULT_CLOUD_RULE_ID
if order == PriorityOrderByDesc {
defaultRule.Priority = min
} else {
defaultRule.Priority = max
}
defaultRule.Priority -= int(order)
if onlyAllowRules {
defaultRule.Priority = -1
}
return append(rules, defaultRule)
}
func SortSecurityRule(rules SecurityRuleSet, order TPriorityOrder, onlyAllowRules bool) {
if onlyAllowRules {
sort.Sort(rules)
return
}
if order == PriorityOrderByAsc {
sort.Sort(sort.Reverse(rules))
return
}
sort.Sort(rules)
}
func CompareRules(
minPriority, maxPriority int, order TPriorityOrder,
localRules secrules.SecurityRuleSet, remoteRules []SecurityRule,
defaultInRule, defaultOutRule SecurityRule,
onlyAllowRules bool, debug bool,
) (common, inAdds, outAdds, inDels, outDels []SecurityRule) {
localInRules := secrules.SecurityRuleSet{}
localOutRules := secrules.SecurityRuleSet{}
for i := range localRules {
if localRules[i].Direction == secrules.DIR_IN {
localInRules = append(localInRules, localRules[i])
} else {
localOutRules = append(localOutRules, localRules[i])
}
}
inRules := SecurityRuleSet{}
outRules := SecurityRuleSet{}
for i := 0; i < len(remoteRules); i++ {
if remoteRules[i].Direction == secrules.DIR_IN {
inRules = append(inRules, remoteRules[i])
} else {
outRules = append(outRules, remoteRules[i])
}
}
var inCommon, outCommon = inRules, outRules
defaultLocalInRule := *secrules.MustParseSecurityRule("in:deny any")
defaultLocalOutRule := *secrules.MustParseSecurityRule("out:allow any")
inRules = AddDefaultRule(inRules, defaultInRule, defaultLocalInRule.String(), order, minPriority, maxPriority, onlyAllowRules)
outRules = AddDefaultRule(outRules, defaultOutRule, defaultLocalOutRule.String(), order, minPriority, maxPriority, onlyAllowRules)
if defaultLocalInRule.String() != defaultInRule.String() {
localInRules = append(localInRules, defaultLocalInRule)
}
if defaultLocalOutRule.String() != defaultOutRule.String() {
localOutRules = append(localOutRules, defaultLocalOutRule)
}
sort.Sort(localInRules)
sort.Sort(localOutRules)
localInAllowList := localInRules.AllowList()
localOutAllowList := localOutRules.AllowList()
if onlyAllowRules {
localInRules = localInAllowList
localOutRules = localOutAllowList
}
SortSecurityRule(inRules, order, onlyAllowRules)
SortSecurityRule(outRules, order, onlyAllowRules)
inAllowList := inRules.AllowList()
outAllowList := outRules.AllowList()
inEquals, outEquals := inAllowList.Equals(localInAllowList), outAllowList.Equals(localOutAllowList)
if inEquals && outEquals {
return
}
// priority从小到大排列(从默认规则开始对比)
sort.Sort(sort.Reverse(localInRules))
sort.Sort(sort.Reverse(localOutRules))
sort.Sort(sort.Reverse(inRules))
sort.Sort(sort.Reverse(outRules))
startPriority := minPriority - 1
if order == PriorityOrderByAsc {
startPriority = maxPriority + 1
}
var addPriority = func(priority int, order TPriorityOrder, inc int, min, max int, onlyAllowRules bool) int {
if onlyAllowRules {
return 0
}
inc = inc * int(order) //+ int(order)
priority += inc
if priority < min {
return min
}
if priority > max {
return max
}
return priority
}
var getInitPriority = func(init, min, max int) int {
if init < min || init > max {
return (min + max) / 2
}
return init
}
var compare = func(localRules secrules.SecurityRuleSet, remoteRules SecurityRuleSet) (common, add, del []SecurityRule) {
i, j, inc, prePriority := 0, 0, 1, 0
for i < len(localRules) || j < len(remoteRules) {
if i < len(localRules) && j < len(remoteRules) {
ruleStr := remoteRules[j].String()
localRuleStr := localRules[i].String()
if debug {
log.Debugf("compare local priority(%d) %s -> remote name(%s) priority(%d) %s\n", localRules[i].Priority, localRules[i].String(), remoteRules[j].Name, remoteRules[j].Priority, remoteRules[j].String())
}
cmp := strings.Compare(ruleStr, localRuleStr)
if cmp == 0 {
prePriority = remoteRules[j].Priority
if remoteRules[j].ExternalId == DEFAULT_CLOUD_RULE_ID {
remoteRules[j].Priority = addPriority(remoteRules[j].Priority, order, 1, minPriority, maxPriority, onlyAllowRules)
}
common = append(common, remoteRules[j])
i++
j++
} else if cmp < 0 {
if remoteRules[j].ExternalId != DEFAULT_CLOUD_RULE_ID {
del = append(del, remoteRules[j])
}
j++
} else {
initPriority := getInitPriority(prePriority, minPriority, maxPriority)
localRules[i].Priority = addPriority(initPriority, order, inc, minPriority, maxPriority, onlyAllowRules)
add = append(add, SecurityRule{SecurityRule: localRules[i]})
i++
inc++
}
} else if i >= len(localRules) {
if remoteRules[j].ExternalId != DEFAULT_CLOUD_RULE_ID {
del = append(del, remoteRules[j])
}
j++
} else if j >= len(remoteRules) {
initPriority := startPriority
if len(remoteRules) > 0 {
initPriority = remoteRules[len(remoteRules)-1].Priority
}
initPriority = getInitPriority(initPriority, minPriority, maxPriority) // 若是初始添加规则,尽量以中间为节点,避免仅出现天地规则
localRules[i].Priority = addPriority(initPriority, order, inc, minPriority, maxPriority, onlyAllowRules)
add = append(add, SecurityRule{SecurityRule: localRules[i]})
i++
inc++
}
}
return
}
type rulePair struct {
localRules []secrules.SecurityRule
remoteRules []SecurityRule
protocol string
}
var splitRules = func(localRules []secrules.SecurityRule, remoteRules []SecurityRule) []rulePair {
rules := map[string]rulePair{}
for _, r := range localRules {
pair, ok := rules[r.Protocol]
if !ok {
pair = rulePair{localRules: []secrules.SecurityRule{}, remoteRules: []SecurityRule{}, protocol: r.Protocol}
}
pair.localRules = append(pair.localRules, r)
rules[r.Protocol] = pair
}
for _, r := range remoteRules {
pair, ok := rules[r.Protocol]
if !ok {
pair = rulePair{localRules: []secrules.SecurityRule{}, remoteRules: []SecurityRule{}, protocol: r.Protocol}
}
pair.remoteRules = append(pair.remoteRules, r)
rules[r.Protocol] = pair
}
ret := []rulePair{}
for _, r := range rules {
ret = append(ret, r)
}
return ret
}
var compareRules = func(localRules []secrules.SecurityRule, remoteRules []SecurityRule) (common, add, dels []SecurityRule) {
pairs := splitRules(localRules, remoteRules)
for _, r := range pairs {
_common, _add, _dels := compare(r.localRules, r.remoteRules)
common = append(common, _common...)
add = append(add, _add...)
dels = append(dels, _dels...)
}
return
}
if !inEquals {
inCommon, inAdds, inDels = compareRules(localInRules, inRules)
}
if !outEquals {
outCommon, outAdds, outDels = compareRules(localOutRules, outRules)
}
common = append(inCommon, outCommon...)
return
}
+8
View File
@@ -1405,6 +1405,14 @@ func (self *SCloudprovider) StartCloudproviderDeleteTask(ctx context.Context, us
return nil
}
func (self *SCloudprovider) GetRegionDriver() (IRegionDriver, error) {
driver := GetRegionDriver(self.Provider)
if driver == nil {
return nil, fmt.Errorf("failed to found region driver for %s", self.Provider)
}
return driver, nil
}
func (self *SCloudprovider) ClearSchedDescCache() error {
hosts := make([]SHost, 0)
q := HostManager.Query().Equals("manager_id", self.Id)
+6
View File
@@ -119,6 +119,12 @@ type IRegionDriver interface {
RequestCacheSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, region *SCloudregion, vpc *SVpc, secgroup *SSecurityGroup, classic bool, task taskman.ITask) error
RequestSyncSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, vpcId string, vpc *SVpc, secgroup *SSecurityGroup) (string, error)
GetSecurityGroupRuleOrder() cloudprovider.TPriorityOrder // Desc(priority值越大,优先级越高) Asc(priority值越小,优先级越高)
GetDefaultSecurityGroupInRule() cloudprovider.SecurityRule
GetDefaultSecurityGroupOutRule() cloudprovider.SecurityRule
GetSecurityGroupRuleMaxPriority() int
GetSecurityGroupRuleMinPriority() int
IsOnlySupportAllowRules() bool
IsSupportClassicSecurityGroup() bool
IsSecurityGroupBelongVpc() bool
IsVpcBelongGlobalVpc() bool
+6 -5
View File
@@ -33,6 +33,7 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/logclient"
@@ -454,13 +455,13 @@ func (manager *SSecurityGroupRuleManager) getRulesBySecurityGroup(secgroup *SSec
return rules, nil
}
func (manager *SSecurityGroupRuleManager) SyncRules(ctx context.Context, userCred mcclient.TokenCredential, secgroup *SSecurityGroup, rules secrules.SecurityRuleSet) compare.SyncResult {
func (manager *SSecurityGroupRuleManager) SyncRules(ctx context.Context, userCred mcclient.TokenCredential, secgroup *SSecurityGroup, rules cloudprovider.SecurityRuleSet) compare.SyncResult {
syncResult := compare.SyncResult{}
priority, prePriority := 100, 0
priority, prePriority := 10, 0
for i := 0; i < len(rules); i++ {
// 这里避免了Rule规则优先级在 1-100之外的问题,ext.GetRules()不需要进行优先级转换
if prePriority != 0 && rules[i].Priority != prePriority && priority > 1 {
priority--
if prePriority != 0 && rules[i].Priority != prePriority && priority < 100 {
priority++
}
prePriority = rules[i].Priority
rules[i].Priority = priority
@@ -474,7 +475,7 @@ func (manager *SSecurityGroupRuleManager) SyncRules(ctx context.Context, userCre
return syncResult
}
func (manager *SSecurityGroupRuleManager) newFromCloudSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, rule secrules.SecurityRule, secgroup *SSecurityGroup) (*SSecurityGroupRule, error) {
func (manager *SSecurityGroupRuleManager) newFromCloudSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, rule cloudprovider.SecurityRule, secgroup *SSecurityGroup) (*SSecurityGroupRule, error) {
lockman.LockClass(ctx, manager, db.GetLockClassKey(manager, userCred))
defer lockman.ReleaseClass(ctx, manager, db.GetLockClassKey(manager, userCred))
+32 -16
View File
@@ -17,7 +17,6 @@ package models
import (
"context"
"database/sql"
"sort"
"strings"
"time"
@@ -696,35 +695,46 @@ func (manager *SSecurityGroupManager) getSecurityGroups() ([]SSecurityGroup, err
}
func (manager *SSecurityGroupManager) newFromCloudSecgroup(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, extSec cloudprovider.ICloudSecurityGroup) (*SSecurityGroup, error) {
regionDriver, err := provider.GetRegionDriver()
if err != nil {
return nil, errors.Wrap(err, "provider.GetRegionDriver")
}
rules, err := extSec.GetRules()
if err != nil {
return nil, err
return nil, errors.Wrap(err, "extSec.GetRules")
}
inRules := secrules.SecurityRuleSet{}
outRules := secrules.SecurityRuleSet{}
for i := 0; i < len(rules); i++ {
inRules := []cloudprovider.SecurityRule{}
outRules := []cloudprovider.SecurityRule{}
for i := range rules {
if rules[i].Direction == secrules.DIR_IN {
inRules = append(inRules, rules[i])
} else {
outRules = append(outRules, rules[i])
}
}
sort.Sort(inRules)
sort.Sort(outRules)
inAllowList := inRules.AllowList()
outAllowList := outRules.AllowList()
maxPriority := regionDriver.GetSecurityGroupRuleMaxPriority()
minPriority := regionDriver.GetSecurityGroupRuleMinPriority()
defaultInRule := regionDriver.GetDefaultSecurityGroupInRule()
defaultOutRule := regionDriver.GetDefaultSecurityGroupOutRule()
order := regionDriver.GetSecurityGroupRuleOrder()
onlyAllowRules := regionDriver.IsOnlySupportAllowRules()
// 查询与provider在同域的安全组,比对寻找一个与云上安全组规则相同的安全组
secgroups := []SSecurityGroup{}
q := manager.Query().Equals("domain_id", provider.DomainId)
if err := db.FetchModelObjects(manager, q, &secgroups); err != nil {
log.Errorf("failed to fetch secgroups %v", err)
err = db.FetchModelObjects(manager, q, &secgroups)
if err != nil {
return nil, errors.Wrap(err, "db.FetchModelObjects")
}
for _, secgroup := range secgroups {
_inAllowList := secgroup.GetInAllowList()
_outAllowList := secgroup.GetOutAllowList()
if outAllowList.Equals(_outAllowList) && inAllowList.Equals(_inAllowList) {
return &secgroup, nil
for i := range secgroups {
localRules := secrules.SecurityRuleSet(secgroups[i].GetSecRules(""))
_, inAdds, outAdds, inDels, outDels := cloudprovider.CompareRules(minPriority, maxPriority, order, localRules, rules, defaultInRule, defaultOutRule, onlyAllowRules, false)
if len(inAdds) == 0 && len(outAdds) == 0 && len(inDels) == 0 && len(outDels) == 0 {
return &secgroups[i], nil
}
}
@@ -737,6 +747,7 @@ func (manager *SSecurityGroupManager) newFromCloudSecgroup(ctx context.Context,
if err != nil {
return nil, err
}
secgroup.Name = newName
secgroup.Description = extSec.GetDescription()
secgroup.ProjectId = provider.ProjectId
@@ -747,6 +758,11 @@ func (manager *SSecurityGroupManager) newFromCloudSecgroup(ctx context.Context,
}
//这里必须先同步下规则,不然下次对比此安全组规则为空
inRules = cloudprovider.AddDefaultRule(inRules, defaultInRule, "in:deny any", order, minPriority, maxPriority, onlyAllowRules)
cloudprovider.SortSecurityRule(inRules, order, onlyAllowRules)
outRules = cloudprovider.AddDefaultRule(outRules, defaultOutRule, "out:allow any", order, minPriority, maxPriority, onlyAllowRules)
cloudprovider.SortSecurityRule(outRules, order, onlyAllowRules)
SecurityGroupRuleManager.SyncRules(ctx, userCred, &secgroup, inRules)
SecurityGroupRuleManager.SyncRules(ctx, userCred, &secgroup, outRules)
+21
View File
@@ -25,6 +25,7 @@ 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"
billing_api "yunion.io/x/onecloud/pkg/apis/billing"
@@ -52,6 +53,26 @@ func init() {
models.RegisterRegionDriver(&driver)
}
func (self *SAliyunRegionDriver) GetSecurityGroupRuleOrder() cloudprovider.TPriorityOrder {
return cloudprovider.PriorityOrderByAsc
}
func (self *SAliyunRegionDriver) GetDefaultSecurityGroupInRule() cloudprovider.SecurityRule {
return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("in:deny any")}
}
func (self *SAliyunRegionDriver) GetDefaultSecurityGroupOutRule() cloudprovider.SecurityRule {
return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("out:allow any")}
}
func (self *SAliyunRegionDriver) GetSecurityGroupRuleMaxPriority() int {
return 1
}
func (self *SAliyunRegionDriver) GetSecurityGroupRuleMinPriority() int {
return 100
}
func (self *SAliyunRegionDriver) GetProvider() string {
return api.CLOUD_PROVIDER_ALIYUN
}
+25
View File
@@ -24,6 +24,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/secrules"
"yunion.io/x/pkg/utils"
"yunion.io/x/sqlchemy"
@@ -50,6 +51,30 @@ func init() {
models.RegisterRegionDriver(&driver)
}
func (self *SAwsRegionDriver) GetSecurityGroupRuleOrder() cloudprovider.TPriorityOrder {
return cloudprovider.PriorityOrderByAsc
}
func (self *SAwsRegionDriver) GetDefaultSecurityGroupInRule() cloudprovider.SecurityRule {
return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("in:deny any")}
}
func (self *SAwsRegionDriver) GetDefaultSecurityGroupOutRule() cloudprovider.SecurityRule {
return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("out:allow any")}
}
func (self *SAwsRegionDriver) GetSecurityGroupRuleMaxPriority() int {
return 0
}
func (self *SAwsRegionDriver) GetSecurityGroupRuleMinPriority() int {
return 0
}
func (self *SAwsRegionDriver) IsOnlySupportAllowRules() bool {
return true
}
func (self *SAwsRegionDriver) GetProvider() string {
return api.CLOUD_PROVIDER_AWS
}
+22
View File
@@ -18,8 +18,10 @@ import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/util/secrules"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
@@ -53,3 +55,23 @@ func (self *SAzureRegionDriver) ValidateCreateLoadbalancerCertificateData(ctx co
func (self *SAzureRegionDriver) IsSupportClassicSecurityGroup() bool {
return true
}
func (self *SAzureRegionDriver) GetSecurityGroupRuleOrder() cloudprovider.TPriorityOrder {
return cloudprovider.PriorityOrderByAsc
}
func (self *SAzureRegionDriver) GetDefaultSecurityGroupInRule() cloudprovider.SecurityRule {
return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("in:deny any")}
}
func (self *SAzureRegionDriver) GetDefaultSecurityGroupOutRule() cloudprovider.SecurityRule {
return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("out:deny any")}
}
func (self *SAzureRegionDriver) GetSecurityGroupRuleMaxPriority() int {
return 4096
}
func (self *SAzureRegionDriver) GetSecurityGroupRuleMinPriority() int {
return 100
}
+25
View File
@@ -20,6 +20,7 @@ import (
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/util/secrules"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
@@ -247,6 +248,30 @@ func (self *SBaseRegionDriver) RequestSyncSecurityGroup(ctx context.Context, use
return "", fmt.Errorf("Not Implemented RequestSyncSecurityGroup")
}
func (self *SBaseRegionDriver) GetSecurityGroupRuleOrder() cloudprovider.TPriorityOrder {
return cloudprovider.PriorityOrderByDesc
}
func (self *SBaseRegionDriver) IsOnlySupportAllowRules() bool {
return false
}
func (self *SBaseRegionDriver) GetDefaultSecurityGroupInRule() cloudprovider.SecurityRule {
return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("in:deny any")}
}
func (self *SBaseRegionDriver) GetDefaultSecurityGroupOutRule() cloudprovider.SecurityRule {
return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("out:allow any")}
}
func (self *SBaseRegionDriver) GetSecurityGroupRuleMaxPriority() int {
return 100
}
func (self *SBaseRegionDriver) GetSecurityGroupRuleMinPriority() int {
return 1
}
func (self *SBaseRegionDriver) ValidateCreateDBInstanceData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, input api.DBInstanceCreateInput, skus []models.SDBInstanceSku, network *models.SNetwork) (api.DBInstanceCreateInput, error) {
return input, nil
}
+26
View File
@@ -18,8 +18,10 @@ import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/util/secrules"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
@@ -34,6 +36,30 @@ func init() {
models.RegisterRegionDriver(&driver)
}
func (self *SCtyunRegionDriver) GetSecurityGroupRuleOrder() cloudprovider.TPriorityOrder {
return cloudprovider.PriorityOrderByAsc
}
func (self *SCtyunRegionDriver) GetDefaultSecurityGroupInRule() cloudprovider.SecurityRule {
return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("in:deny any")}
}
func (self *SCtyunRegionDriver) GetDefaultSecurityGroupOutRule() cloudprovider.SecurityRule {
return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("out:deny any")}
}
func (self *SCtyunRegionDriver) GetSecurityGroupRuleMaxPriority() int {
return 0
}
func (self *SCtyunRegionDriver) GetSecurityGroupRuleMinPriority() int {
return 0
}
func (self *SCtyunRegionDriver) IsOnlySupportAllowRules() bool {
return true
}
func (self *SCtyunRegionDriver) GetProvider() string {
return api.CLOUD_PROVIDER_CTYUN
}
+21
View File
@@ -21,6 +21,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/secrules"
billing_api "yunion.io/x/onecloud/pkg/apis/billing"
api "yunion.io/x/onecloud/pkg/apis/compute"
@@ -41,6 +42,26 @@ func init() {
models.RegisterRegionDriver(&driver)
}
func (self *SGoogleRegionDriver) GetSecurityGroupRuleOrder() cloudprovider.TPriorityOrder {
return cloudprovider.PriorityOrderByAsc
}
func (self *SGoogleRegionDriver) GetDefaultSecurityGroupInRule() cloudprovider.SecurityRule {
return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("in:deny any")}
}
func (self *SGoogleRegionDriver) GetDefaultSecurityGroupOutRule() cloudprovider.SecurityRule {
return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("out:allow any")}
}
func (self *SGoogleRegionDriver) GetSecurityGroupRuleMaxPriority() int {
return 0
}
func (self *SGoogleRegionDriver) GetSecurityGroupRuleMinPriority() int {
return 65535
}
func (self *SGoogleRegionDriver) GetProvider() string {
return api.CLOUD_PROVIDER_GOOGLE
}
+25
View File
@@ -25,6 +25,7 @@ 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"
billing_api "yunion.io/x/onecloud/pkg/apis/billing"
@@ -52,6 +53,30 @@ func init() {
models.RegisterRegionDriver(&driver)
}
func (self *SHuaWeiRegionDriver) GetSecurityGroupRuleOrder() cloudprovider.TPriorityOrder {
return cloudprovider.PriorityOrderByAsc
}
func (self *SHuaWeiRegionDriver) GetDefaultSecurityGroupInRule() cloudprovider.SecurityRule {
return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("in:deny any")}
}
func (self *SHuaWeiRegionDriver) GetDefaultSecurityGroupOutRule() cloudprovider.SecurityRule {
return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("out:allow any")}
}
func (self *SHuaWeiRegionDriver) GetSecurityGroupRuleMaxPriority() int {
return 0
}
func (self *SHuaWeiRegionDriver) GetSecurityGroupRuleMinPriority() int {
return 0
}
func (self *SHuaWeiRegionDriver) IsOnlySupportAllowRules() bool {
return true
}
func (self *SHuaWeiRegionDriver) GetProvider() string {
return api.CLOUD_PROVIDER_HUAWEI
}
+15 -19
View File
@@ -18,7 +18,6 @@ import (
"context"
"database/sql"
"fmt"
"sort"
"strings"
"time"
@@ -1532,35 +1531,32 @@ func (self *SManagedVirtualizationRegionDriver) RequestSyncSecurityGroup(ctx con
return "", errors.Wrap(err, "db.Update")
}
inAllowList := secgroup.GetInAllowList()
outAllowList := secgroup.GetOutAllowList()
rules, err := iSecgroup.GetRules()
if err != nil {
return "", errors.Wrap(err, "iSecgroup.GetRules")
}
inRules := secrules.SecurityRuleSet{}
outRules := secrules.SecurityRuleSet{}
for i := 0; i < len(rules); i++ {
if rules[i].Direction == secrules.DIR_IN {
inRules = append(inRules, rules[i])
} else {
outRules = append(outRules, rules[i])
}
}
sort.Sort(inRules)
sort.Sort(outRules)
_inAllowList := inRules.AllowList()
_outAllowList := outRules.AllowList()
if inAllowList.Equals(_inAllowList) && outAllowList.Equals(_outAllowList) && (len(_inAllowList) > 0 && len(_outAllowList) > 0) { // 避免单个deny any的allowList为空,导致安全组规则未同步
maxPriority := region.GetDriver().GetSecurityGroupRuleMaxPriority()
minPriority := region.GetDriver().GetSecurityGroupRuleMinPriority()
defaultInRule := region.GetDriver().GetDefaultSecurityGroupInRule()
defaultOutRule := region.GetDriver().GetDefaultSecurityGroupOutRule()
order := region.GetDriver().GetSecurityGroupRuleOrder()
onlyAllowRules := region.GetDriver().IsOnlySupportAllowRules()
localRules := secrules.SecurityRuleSet(secgroup.GetSecRules(""))
common, inAdds, outAdds, inDels, outDels := cloudprovider.CompareRules(minPriority, maxPriority, order, localRules, rules, defaultInRule, defaultOutRule, onlyAllowRules, false)
if len(inAdds) == 0 && len(inDels) == 0 && len(outAdds) == 0 && len(outDels) == 0 {
return cache.ExternalId, nil
}
err = iSecgroup.SyncRules(secgroup.GetSecRules(""))
err = iSecgroup.SyncRules(common, inAdds, outAdds, inDels, outDels)
if err != nil {
return "", errors.Wrap(err, "iSecgroup.SyncRules")
}
return cache.ExternalId, nil
}
+26
View File
@@ -19,8 +19,10 @@ import (
"database/sql"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/util/secrules"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
@@ -35,6 +37,30 @@ func init() {
models.RegisterRegionDriver(&driver)
}
func (self *SOpenStackRegionDriver) GetSecurityGroupRuleOrder() cloudprovider.TPriorityOrder {
return cloudprovider.PriorityOrderByDesc
}
func (self *SOpenStackRegionDriver) GetDefaultSecurityGroupInRule() cloudprovider.SecurityRule {
return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("in:deny any")}
}
func (self *SOpenStackRegionDriver) GetDefaultSecurityGroupOutRule() cloudprovider.SecurityRule {
return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("out:deny any")}
}
func (self *SOpenStackRegionDriver) GetSecurityGroupRuleMaxPriority() int {
return 0
}
func (self *SOpenStackRegionDriver) GetSecurityGroupRuleMinPriority() int {
return 0
}
func (self *SOpenStackRegionDriver) IsOnlySupportAllowRules() bool {
return true
}
func (self *SOpenStackRegionDriver) GetProvider() string {
return api.CLOUD_PROVIDER_OPENSTACK
}
+21
View File
@@ -22,6 +22,7 @@ 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"
"yunion.io/x/sqlchemy"
@@ -45,6 +46,26 @@ func init() {
models.RegisterRegionDriver(&driver)
}
func (self *SQcloudRegionDriver) GetSecurityGroupRuleOrder() cloudprovider.TPriorityOrder {
return cloudprovider.PriorityOrderByAsc
}
func (self *SQcloudRegionDriver) GetDefaultSecurityGroupInRule() cloudprovider.SecurityRule {
return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("in:deny any")}
}
func (self *SQcloudRegionDriver) GetDefaultSecurityGroupOutRule() cloudprovider.SecurityRule {
return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("out:deny any")}
}
func (self *SQcloudRegionDriver) GetSecurityGroupRuleMaxPriority() int {
return 0
}
func (self *SQcloudRegionDriver) GetSecurityGroupRuleMinPriority() int {
return 100
}
func (self *SQcloudRegionDriver) GetProvider() string {
return api.CLOUD_PROVIDER_QCLOUD
}
@@ -0,0 +1,63 @@
// 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 regiondrivers
import (
"testing"
"yunion.io/x/pkg/util/secrules"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
func TestAwsRuleSync(t *testing.T) {
driver := SAwsRegionDriver{}
maxPriority := driver.GetSecurityGroupRuleMaxPriority()
minPriority := driver.GetSecurityGroupRuleMinPriority()
defaultInRule := driver.GetDefaultSecurityGroupInRule()
defaultOutRule := driver.GetDefaultSecurityGroupOutRule()
order := driver.GetSecurityGroupRuleOrder()
isOnlyAllowRules := driver.IsOnlySupportAllowRules()
data := []TestData{
{
Name: "Test out deny rules",
LocalRules: secrules.SecurityRuleSet{
localRuleWithPriority("out:deny any", 1),
},
RemoteRules: []cloudprovider.SecurityRule{
remoteRuleWithName("", "out:allow any", 1),
},
Common: []cloudprovider.SecurityRule{},
InAdds: []cloudprovider.SecurityRule{},
OutAdds: []cloudprovider.SecurityRule{},
InDels: []cloudprovider.SecurityRule{},
OutDels: []cloudprovider.SecurityRule{
remoteRuleWithName("", "out:allow any", 1),
},
},
}
for _, d := range data {
t.Logf("check %s", d.Name)
common, inAdds, outAdds, inDels, outDels := cloudprovider.CompareRules(minPriority, maxPriority, order, d.LocalRules, d.RemoteRules, defaultInRule, defaultOutRule, isOnlyAllowRules, true)
check(t, "common", common, d.Common)
check(t, "inAdds", inAdds, d.InAdds)
check(t, "outAdds", outAdds, d.OutAdds)
check(t, "inDels", inDels, d.InDels)
check(t, "outDels", outDels, d.OutDels)
}
}
@@ -0,0 +1,235 @@
// 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 regiondrivers
import (
"sort"
"testing"
"yunion.io/x/pkg/util/secrules"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
func TestAzureRuleSync(t *testing.T) {
driver := SAzureRegionDriver{}
maxPriority := driver.GetSecurityGroupRuleMaxPriority()
minPriority := driver.GetSecurityGroupRuleMinPriority()
defaultInRule := driver.GetDefaultSecurityGroupInRule()
defaultOutRule := driver.GetDefaultSecurityGroupOutRule()
order := driver.GetSecurityGroupRuleOrder()
isOnlyAllowRules := driver.IsOnlySupportAllowRules()
data := []TestData{
{
Name: "Test empty rules",
LocalRules: secrules.SecurityRuleSet{},
RemoteRules: []cloudprovider.SecurityRule{},
Common: []cloudprovider.SecurityRule{},
InAdds: []cloudprovider.SecurityRule{},
OutAdds: []cloudprovider.SecurityRule{
remoteRuleWithName("", "out:allow any", 2097),
},
InDels: []cloudprovider.SecurityRule{},
OutDels: []cloudprovider.SecurityRule{},
},
{
Name: "Test remove rules",
LocalRules: secrules.SecurityRuleSet{},
RemoteRules: []cloudprovider.SecurityRule{
remoteRuleWithName("test-name", "out:allow any", 1000),
},
Common: []cloudprovider.SecurityRule{},
InAdds: []cloudprovider.SecurityRule{},
OutAdds: []cloudprovider.SecurityRule{
remoteRuleWithName("", "out:allow any", 2097),
},
InDels: []cloudprovider.SecurityRule{},
OutDels: []cloudprovider.SecurityRule{
remoteRuleWithName("test-name", "out:allow any", 1000),
},
},
{
Name: "Test diff rules",
LocalRules: secrules.SecurityRuleSet{
localRuleWithPriority("out:allow tcp 100-200", 99),
localRuleWithPriority("out:allow udp 200-300", 98),
},
RemoteRules: []cloudprovider.SecurityRule{
remoteRuleWithName("test-tcp", "out:allow tcp 100-200", 1000),
remoteRuleWithName("test-udp", "out:allow udp 200-300", 1002),
},
Common: []cloudprovider.SecurityRule{
remoteRuleWithName("test-tcp", "out:allow tcp 100-200", 1000),
remoteRuleWithName("test-udp", "out:allow udp 200-300", 1002),
},
InAdds: []cloudprovider.SecurityRule{},
OutAdds: []cloudprovider.SecurityRule{
remoteRuleWithName("", "out:allow any", 2097),
},
InDels: []cloudprovider.SecurityRule{},
OutDels: []cloudprovider.SecurityRule{},
},
{
Name: "Test add rules",
LocalRules: secrules.SecurityRuleSet{
localRuleWithPriority("in:allow tcp", 100),
localRuleWithPriority("in:allow udp", 99),
localRuleWithPriority("out:deny any", 1),
},
RemoteRules: []cloudprovider.SecurityRule{
remoteRuleWithName("allow-ssh", "in:allow tcp 22", 300),
},
Common: []cloudprovider.SecurityRule{},
InAdds: []cloudprovider.SecurityRule{
remoteRuleWithName("", "in:allow tcp", 2097),
remoteRuleWithName("", "in:allow udp", 2097),
},
OutAdds: []cloudprovider.SecurityRule{},
InDels: []cloudprovider.SecurityRule{
remoteRuleWithName("allow-ssh", "in:allow tcp 22", 300),
},
OutDels: []cloudprovider.SecurityRule{},
},
{
Name: "Test insert rules",
LocalRules: secrules.SecurityRuleSet{
localRuleWithPriority("in:allow tcp", 100),
localRuleWithPriority("in:allow udp", 99),
localRuleWithPriority("in:allow icmp", 98),
localRuleWithPriority("out:deny any", 1),
},
RemoteRules: []cloudprovider.SecurityRule{
remoteRuleWithName("allow-tcp", "in:allow tcp", 300),
remoteRuleWithName("allow-icmp", "in:allow icmp", 400),
},
Common: []cloudprovider.SecurityRule{
remoteRuleWithName("allow-tcp", "in:allow tcp", 300),
remoteRuleWithName("allow-icmp", "in:allow icmp", 400),
},
InAdds: []cloudprovider.SecurityRule{
remoteRuleWithName("", "in:allow udp", 2097),
},
OutAdds: []cloudprovider.SecurityRule{},
InDels: []cloudprovider.SecurityRule{},
OutDels: []cloudprovider.SecurityRule{},
},
{
Name: "Test icmp rules",
LocalRules: secrules.SecurityRuleSet{
localRuleWithPriority("in:allow tcp 33", 10),
localRuleWithPriority("in:allow tcp 22", 1),
localRuleWithPriority("out:deny any", 1),
},
RemoteRules: []cloudprovider.SecurityRule{
remoteRuleWithName("allow-tcp-22", "in:allow tcp 22", 300),
},
Common: []cloudprovider.SecurityRule{
remoteRuleWithName("allow-tcp-22", "in:allow tcp 22", 300),
},
InAdds: []cloudprovider.SecurityRule{
remoteRuleWithName("", "in:allow tcp 33", 299),
},
OutAdds: []cloudprovider.SecurityRule{},
InDels: []cloudprovider.SecurityRule{},
OutDels: []cloudprovider.SecurityRule{},
},
{
Name: "Test a rules",
LocalRules: secrules.SecurityRuleSet{
localRuleWithPriority("in:allow tcp 1050", 5),
localRuleWithPriority("in:allow tcp 1011", 4),
localRuleWithPriority("in:allow tcp 1002", 3),
localRuleWithPriority("in:allow tcp 22", 2),
localRuleWithPriority("in:allow udp 55", 1),
localRuleWithPriority("out:deny any", 1),
},
RemoteRules: []cloudprovider.SecurityRule{
remoteRuleWithName("in_allow_udp_55_4014", "in:allow udp 55", 4014),
remoteRuleWithName("in_allow_tcp_22_4013", "in:allow tcp 22", 4013),
remoteRuleWithName("in_allow_tcp_1002_4012", "in:allow tcp 1002", 4012),
remoteRuleWithName("in_allow_tcp_1010_4011", "in:allow tcp 1010", 4011),
remoteRuleWithName("in_allow_tcp_1050_4010", "in:allow tcp 1050", 4010),
},
Common: []cloudprovider.SecurityRule{
remoteRuleWithName("in_allow_tcp_1050_4010", "in:allow tcp 1050", 4010),
remoteRuleWithName("in_allow_tcp_1002_4012", "in:allow tcp 1002", 4012),
remoteRuleWithName("in_allow_tcp_22_4013", "in:allow tcp 22", 4013),
remoteRuleWithName("in_allow_udp_55_4014", "in:allow udp 55", 4014),
},
InAdds: []cloudprovider.SecurityRule{
remoteRuleWithName("", "in:allow tcp 1011", 4011),
},
OutAdds: []cloudprovider.SecurityRule{},
InDels: []cloudprovider.SecurityRule{
remoteRuleWithName("in_allow_tcp_1010_4011", "in:allow tcp 1010", 4011),
},
OutDels: []cloudprovider.SecurityRule{},
},
{
Name: "Test b rules",
LocalRules: secrules.SecurityRuleSet{
localRuleWithPriority("in:allow udp 1055", 20),
localRuleWithPriority("in:allow icmp", 15),
localRuleWithPriority("in:allow tcp 1050", 5),
localRuleWithPriority("in:allow tcp 1012", 4),
localRuleWithPriority("in:allow tcp 1002", 3),
localRuleWithPriority("in:allow tcp 22", 2),
localRuleWithPriority("in:allow udp 55", 1),
localRuleWithPriority("out:deny any", 1),
},
RemoteRules: []cloudprovider.SecurityRule{
remoteRuleWithName("in_allow_udp_55_4014", "in:allow udp 55", 4014),
remoteRuleWithName("in_allow_tcp_22_4013", "in:allow tcp 22", 4013),
remoteRuleWithName("in_allow_tcp_1002_4012", "in:allow tcp 1002", 4012),
remoteRuleWithName("in_allow_tcp_1012_4011", "in:allow tcp 1012", 4011),
remoteRuleWithName("in_allow_tcp_1050_4010", "in:allow tcp 1050", 4010),
remoteRuleWithName("in_allow_tcp_1055_4009", "in:allow tcp 1055", 4009),
},
Common: []cloudprovider.SecurityRule{
remoteRuleWithName("in_allow_tcp_1050_4010", "in:allow tcp 1050", 4010),
remoteRuleWithName("in_allow_tcp_1012_4011", "in:allow tcp 1012", 4011),
remoteRuleWithName("in_allow_tcp_1002_4012", "in:allow tcp 1002", 4012),
remoteRuleWithName("in_allow_tcp_22_4013", "in:allow tcp 22", 4013),
remoteRuleWithName("in_allow_udp_55_4014", "in:allow udp 55", 4014),
},
InAdds: []cloudprovider.SecurityRule{
remoteRuleWithName("", "in:allow icmp", 2097),
remoteRuleWithName("", "in:allow udp 1055", 4013),
},
OutAdds: []cloudprovider.SecurityRule{},
InDels: []cloudprovider.SecurityRule{
remoteRuleWithName("in_allow_tcp_1055_4009", "in:allow tcp 1055", 4009),
},
OutDels: []cloudprovider.SecurityRule{},
},
}
for _, d := range data {
t.Logf("check %s", d.Name)
common, inAdds, outAdds, inDels, outDels := cloudprovider.CompareRules(minPriority, maxPriority, order, d.LocalRules, d.RemoteRules, defaultInRule, defaultOutRule, isOnlyAllowRules, true)
sort.Sort(cloudprovider.SecurityRuleSet(common))
sort.Sort(cloudprovider.SecurityRuleSet(inAdds))
sort.Sort(cloudprovider.SecurityRuleSet(outAdds))
sort.Sort(cloudprovider.SecurityRuleSet(inDels))
sort.Sort(cloudprovider.SecurityRuleSet(outDels))
check(t, "common", common, d.Common)
check(t, "inAdds", inAdds, d.InAdds)
check(t, "outAdds", outAdds, d.OutAdds)
check(t, "inDels", inDels, d.InDels)
check(t, "outDels", outDels, d.OutDels)
}
}
@@ -0,0 +1,70 @@
// 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 regiondrivers
import (
"sort"
"testing"
"yunion.io/x/pkg/util/secrules"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
func TestCtyunRuleSync(t *testing.T) {
driver := SCtyunRegionDriver{}
maxPriority := driver.GetSecurityGroupRuleMaxPriority()
minPriority := driver.GetSecurityGroupRuleMinPriority()
defaultInRule := driver.GetDefaultSecurityGroupInRule()
defaultOutRule := driver.GetDefaultSecurityGroupOutRule()
order := driver.GetSecurityGroupRuleOrder()
isOnlyAllowRules := driver.IsOnlySupportAllowRules()
data := []TestData{
{
Name: "Test out deny rules",
LocalRules: secrules.SecurityRuleSet{
localRuleWithPriority("out:deny tcp 200", 1),
},
RemoteRules: []cloudprovider.SecurityRule{},
Common: []cloudprovider.SecurityRule{},
InAdds: []cloudprovider.SecurityRule{},
OutAdds: []cloudprovider.SecurityRule{
remoteRuleWithName("", "out:allow icmp", 0),
remoteRuleWithName("", "out:allow tcp 1-199", 0),
remoteRuleWithName("", "out:allow tcp 201-65535", 0),
remoteRuleWithName("", "out:allow udp", 0),
},
InDels: []cloudprovider.SecurityRule{},
OutDels: []cloudprovider.SecurityRule{},
},
}
for _, d := range data {
t.Logf("check %s", d.Name)
common, inAdds, outAdds, inDels, outDels := cloudprovider.CompareRules(minPriority, maxPriority, order, d.LocalRules, d.RemoteRules, defaultInRule, defaultOutRule, isOnlyAllowRules, true)
sort.Sort(cloudprovider.SecurityRuleSet(common))
sort.Sort(cloudprovider.SecurityRuleSet(inAdds))
sort.Sort(cloudprovider.SecurityRuleSet(outAdds))
sort.Sort(cloudprovider.SecurityRuleSet(inDels))
sort.Sort(cloudprovider.SecurityRuleSet(outDels))
check(t, "common", common, d.Common)
check(t, "inAdds", inAdds, d.InAdds)
check(t, "outAdds", outAdds, d.OutAdds)
check(t, "inDels", inDels, d.InDels)
check(t, "outDels", outDels, d.OutDels)
}
}
@@ -0,0 +1,67 @@
// 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 regiondrivers
import (
"testing"
"yunion.io/x/pkg/util/secrules"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
func TestOpenStackRuleSync(t *testing.T) {
driver := SOpenStackRegionDriver{}
maxPriority := driver.GetSecurityGroupRuleMaxPriority()
minPriority := driver.GetSecurityGroupRuleMinPriority()
defaultInRule := driver.GetDefaultSecurityGroupInRule()
defaultOutRule := driver.GetDefaultSecurityGroupOutRule()
order := driver.GetSecurityGroupRuleOrder()
isOnlyAllowRules := driver.IsOnlySupportAllowRules()
data := []TestData{
{
Name: "Test deny rules",
LocalRules: secrules.SecurityRuleSet{
localRuleWithPriority("in:deny any", 100),
localRuleWithPriority("in:allow any", 99),
localRuleWithPriority("out:allow any", 100),
},
RemoteRules: []cloudprovider.SecurityRule{
remoteRuleWithName("", "in:allow any", 1),
},
Common: []cloudprovider.SecurityRule{},
InAdds: []cloudprovider.SecurityRule{},
OutAdds: []cloudprovider.SecurityRule{
remoteRuleWithName("", "out:allow any", 0),
},
InDels: []cloudprovider.SecurityRule{
remoteRuleWithName("", "in:allow any", 1),
},
OutDels: []cloudprovider.SecurityRule{},
},
}
for _, d := range data {
t.Logf("check %s", d.Name)
common, inAdds, outAdds, inDels, outDels := cloudprovider.CompareRules(minPriority, maxPriority, order, d.LocalRules, d.RemoteRules, defaultInRule, defaultOutRule, isOnlyAllowRules, true)
check(t, "common", common, d.Common)
check(t, "inAdds", inAdds, d.InAdds)
check(t, "outAdds", outAdds, d.OutAdds)
check(t, "inDels", inDels, d.InDels)
check(t, "outDels", outDels, d.OutDels)
}
}
@@ -0,0 +1,84 @@
// 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 regiondrivers
import (
"fmt"
"testing"
"yunion.io/x/log"
"yunion.io/x/pkg/util/secrules"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type TestData struct {
Name string
LocalRules secrules.SecurityRuleSet
RemoteRules cloudprovider.SecurityRuleSet
Common cloudprovider.SecurityRuleSet
InAdds cloudprovider.SecurityRuleSet
OutAdds cloudprovider.SecurityRuleSet
InDels cloudprovider.SecurityRuleSet
OutDels cloudprovider.SecurityRuleSet
}
var localRuleWithPriority = func(ruleStr string, priority int) secrules.SecurityRule {
rule := secrules.MustParseSecurityRule(ruleStr)
if rule == nil {
log.Errorf("invalid rule str %s", ruleStr)
return secrules.SecurityRule{}
}
rule.Priority = priority
return *rule
}
var remoteRuleWithName = func(name, ruleStr string, priority int) cloudprovider.SecurityRule {
return cloudprovider.SecurityRule{
Name: name,
SecurityRule: localRuleWithPriority(ruleStr, priority),
}
}
var check = func(t *testing.T, name string, ret, expect []cloudprovider.SecurityRule) {
var show = func(info string, rules []cloudprovider.SecurityRule) {
t.Logf("%s: %d\n", info, len(rules))
for _, r := range rules {
t.Logf("Name: %s priority: %d %s\n", r.Name, r.Priority, r.String())
}
}
if len(ret) != len(expect) {
show(fmt.Sprintf("%s rule", name), ret)
show(fmt.Sprintf("%s expect", name), expect)
t.Fatalf("invalid rules for %s current is %d expect %d", name, len(ret), len(expect))
}
for i := range ret {
if ret[i].Name != expect[i].Name {
show(fmt.Sprintf("%s rule", name), ret)
show(fmt.Sprintf("%s expect", name), expect)
t.Fatalf("invalid index(%d) %s rule name %s expect %s", i, name, ret[i].Name, expect[i].Name)
}
if ret[i].Priority != expect[i].Priority {
show(fmt.Sprintf("%s rule", name), ret)
show(fmt.Sprintf("%s expect", name), expect)
t.Fatalf("invalid index(%d) %s rule priority %d expect %d", i, name, ret[i].Priority, expect[i].Priority)
}
if ret[i].String() != expect[i].String() {
show(fmt.Sprintf("%s rule", name), ret)
show(fmt.Sprintf("%s expect", name), expect)
t.Fatalf("invalid index(%d) %s rules %s expect %s", i, name, ret[i].String(), expect[i].String())
}
}
}
+22
View File
@@ -18,8 +18,10 @@ import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/util/secrules"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
@@ -34,6 +36,26 @@ func init() {
models.RegisterRegionDriver(&driver)
}
func (self *SUcloudRegionDriver) GetSecurityGroupRuleOrder() cloudprovider.TPriorityOrder {
return cloudprovider.PriorityOrderByDesc
}
func (self *SUcloudRegionDriver) GetDefaultSecurityGroupInRule() cloudprovider.SecurityRule {
return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("in:deny any")}
}
func (self *SUcloudRegionDriver) GetDefaultSecurityGroupOutRule() cloudprovider.SecurityRule {
return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("out:allow any")}
}
func (self *SUcloudRegionDriver) GetSecurityGroupRuleMaxPriority() int {
return 3
}
func (self *SUcloudRegionDriver) GetSecurityGroupRuleMinPriority() int {
return 1
}
func (self *SUcloudRegionDriver) GetProvider() string {
return api.CLOUD_PROVIDER_UCLOUD
}
+26
View File
@@ -19,8 +19,10 @@ import (
"database/sql"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/util/secrules"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
@@ -35,6 +37,30 @@ func init() {
models.RegisterRegionDriver(&driver)
}
func (self *SZStackRegionDriver) GetSecurityGroupRuleOrder() cloudprovider.TPriorityOrder {
return cloudprovider.PriorityOrderByAsc
}
func (self *SZStackRegionDriver) GetDefaultSecurityGroupInRule() cloudprovider.SecurityRule {
return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("in:deny any")}
}
func (self *SZStackRegionDriver) GetDefaultSecurityGroupOutRule() cloudprovider.SecurityRule {
return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("out:allow any")}
}
func (self *SZStackRegionDriver) GetSecurityGroupRuleMaxPriority() int {
return 1
}
func (self *SZStackRegionDriver) GetSecurityGroupRuleMinPriority() int {
return 1
}
func (self *SZStackRegionDriver) IsOnlySupportAllowRules() bool {
return true
}
func (self *SZStackRegionDriver) GetProvider() string {
return api.CLOUD_PROVIDER_ZSTACK
}
+2
View File
@@ -84,6 +84,8 @@ const (
ErrTooManyAttempts = errors.Error("TooManyFailedAttempts")
ErrTooManyRequests = errors.Error("TooManyRequests")
ErrUnsupportedProtocol = errors.Error("UnsupportedProtocol")
ErrPolicyDefinition = errors.Error("PolicyDefinitionError")
)
-21
View File
@@ -26,7 +26,6 @@ import (
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/regutils"
"yunion.io/x/pkg/util/secrules"
"yunion.io/x/pkg/utils"
api "yunion.io/x/onecloud/pkg/apis/compute"
@@ -786,26 +785,6 @@ func (region *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCre
return region.GetISecurityGroupById(externalId)
}
func (region *SRegion) SyncSecurityGroup(secgroupId string, vpcId string, name string, desc string, rules []secrules.SecurityRule) (string, error) {
if len(secgroupId) > 0 {
_, total, err := region.GetSecurityGroups("", "", []string{secgroupId}, 0, 1)
if err != nil {
return "", err
}
if total == 0 {
secgroupId = ""
}
}
if len(secgroupId) == 0 {
extID, err := region.CreateSecurityGroup(vpcId, name, desc)
if err != nil {
return "", err
}
secgroupId = extID
}
return secgroupId, region.syncSecgroupRules(secgroupId, rules)
}
func (region *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) {
lbs, err := region.GetLoadbalancers(nil)
if err != nil {
+78 -145
View File
@@ -16,14 +16,18 @@ package aliyun
import (
"fmt"
"sort"
"net"
"strings"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/secrules"
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
)
// {"CreationTime":"2017-03-19T13:37:48Z","Description":"System created security group.","SecurityGroupId":"sg-j6cannq0xxj2r9z0yxwl","SecurityGroupName":"sg-j6cannq0xxj2r9z0yxwl","Tags":{"Tag":[]},"VpcId":"vpc-j6c86z3sh8ufhgsxwme0q"}
@@ -69,6 +73,8 @@ type Tag struct {
}
type SSecurityGroup struct {
multicloud.SSecurityGroup
vpc *SVpc
CreationTime time.Time
Description string
@@ -81,25 +87,6 @@ type SSecurityGroup struct {
Tags Tags
}
type PermissionSet []SPermission
func (v PermissionSet) Len() int {
return len(v)
}
func (v PermissionSet) Swap(i, j int) {
v[i], v[j] = v[j], v[i]
}
func (v PermissionSet) 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 (self *SSecurityGroup) GetVpcId() string {
return self.VpcId
}
@@ -127,24 +114,19 @@ func (self *SSecurityGroup) GetDescription() string {
return self.Description
}
func (self *SSecurityGroup) GetRules() ([]secrules.SecurityRule, error) {
rules := make([]secrules.SecurityRule, 0)
if secgrp, err := self.vpc.region.GetSecurityGroupDetails(self.SecurityGroupId); err != nil {
return rules, err
} else {
for _, permission := range secgrp.Permissions.Permission {
if rule, err := secrules.ParseSecurityRule(permission.String()); err != nil {
return rules, err
} else {
priority := permission.Priority
if priority > 100 {
priority = 100
}
rule.Priority = 101 - priority
rule.Description = permission.Description
rules = append(rules, *rule)
}
func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) {
rules := make([]cloudprovider.SecurityRule, 0)
secgrp, err := self.vpc.region.GetSecurityGroupDetails(self.SecurityGroupId)
if err != nil {
return nil, err
}
for _, permission := range secgrp.Permissions.Permission {
rule, err := permission.toRule()
if err != nil {
log.Errorf("convert rule %s for group %s(%s) error: %v", permission.Description, self.SecurityGroupName, self.SecurityGroupId, err)
continue
}
rules = append(rules, rule)
}
return rules, nil
}
@@ -165,11 +147,11 @@ func (self *SSecurityGroup) IsEmulated() bool {
}
func (self *SSecurityGroup) Refresh() error {
if new, err := self.vpc.region.GetSecurityGroupDetails(self.SecurityGroupId); err != nil {
group, err := self.vpc.region.GetSecurityGroupDetails(self.SecurityGroupId)
if err != nil {
return err
} else {
return jsonutils.Update(self, new)
}
return jsonutils.Update(self, group)
}
func (self *SRegion) GetSecurityGroups(vpcId, name string, securityGroupIds []string, offset int, limit int) ([]SSecurityGroup, int, error) {
@@ -214,16 +196,13 @@ func (self *SRegion) GetSecurityGroupDetails(secGroupId string) (*SSecurityGroup
body, err := self.ecsRequest("DescribeSecurityGroupAttribute", params)
if err != nil {
log.Errorf("DescribeSecurityGroupAttribute fail %s", err)
return nil, err
return nil, errors.Wrap(err, "DescribeSecurityGroupAttribute")
}
log.Debugf("%s", body)
secgrp := SSecurityGroup{}
err = body.Unmarshal(&secgrp)
if err != nil {
log.Errorf("Unmarshal security group details fail %s", err)
return nil, err
return nil, errors.Wrap(err, "body.Unmarshal")
}
return &secgrp, nil
}
@@ -248,7 +227,7 @@ func (self *SRegion) CreateSecurityGroup(vpcId string, name string, desc string)
body, err := self.ecsRequest("CreateSecurityGroup", params)
if err != nil {
return "", err
return "", errors.Wrap(err, "CreateSecurityGroup")
}
return body.GetString("SecurityGroupId")
}
@@ -311,21 +290,21 @@ 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 secrules.SecurityRule) error {
if len(rule.Ports) != 0 {
for _, port := range rule.Ports {
rule.PortStart, rule.PortEnd = port, port
if err := self.addSecurityGroupRule(secGrpId, rule); err != nil {
return err
err := self.addSecurityGroupRule(secGrpId, rule)
if err != nil {
return errors.Wrapf(err, "addSecurityGroupRule %s", rule.String())
}
}
} else {
return self.addSecurityGroupRule(secGrpId, rule)
return nil
}
return nil
return self.addSecurityGroupRule(secGrpId, rule)
}
func (self *SRegion) addSecurityGroupRule(secGrpId string, rule *secrules.SecurityRule) error {
func (self *SRegion) addSecurityGroupRule(secGrpId string, rule secrules.SecurityRule) error {
params := make(map[string]string)
params["RegionId"] = self.RegionId
params["SecurityGroupId"] = secGrpId
@@ -355,7 +334,7 @@ func (self *SRegion) addSecurityGroupRule(secGrpId string, rule *secrules.Securi
return nil
}
params["Priority"] = fmt.Sprintf("%d", 101-rule.Priority)
params["Priority"] = fmt.Sprintf("%d", rule.Priority)
if rule.Direction == secrules.SecurityRuleIngress {
if rule.IPNet != nil {
params["SourceCidrIp"] = rule.IPNet.String()
@@ -375,7 +354,7 @@ func (self *SRegion) addSecurityGroupRule(secGrpId string, rule *secrules.Securi
}
}
func (self *SRegion) delSecurityGroupRule(secGrpId string, rule *secrules.SecurityRule) error {
func (self *SRegion) DelSecurityGroupRule(secGrpId string, rule secrules.SecurityRule) error {
params := make(map[string]string)
params["RegionId"] = self.RegionId
params["SecurityGroupId"] = secGrpId
@@ -418,26 +397,38 @@ func (self *SRegion) delSecurityGroupRule(secGrpId string, rule *secrules.Securi
}
}
func (self *SPermission) String() string {
action := secrules.SecurityRuleDeny
func (self *SPermission) toRule() (cloudprovider.SecurityRule, error) {
rule := cloudprovider.SecurityRule{
SecurityRule: secrules.SecurityRule{
Action: secrules.SecurityRuleDeny,
Direction: secrules.DIR_IN,
Priority: self.Priority,
Description: self.Description,
PortStart: -1,
PortEnd: -1,
},
}
if strings.ToLower(self.Policy) == "accept" {
action = secrules.SecurityRuleAllow
}
direction := "in"
if self.Direction == "egress" {
direction = "out"
rule.Action = secrules.SecurityRuleAllow
}
cidr := self.SourceCidrIp
if direction == "out" {
if self.Direction == "egress" {
rule.Direction = secrules.DIR_OUT
cidr = self.DestCidrIp
}
if cidr == "0.0.0.0/0" {
cidr = ""
}
protocol := strings.ToLower(self.IpProtocol)
if protocol == "all" {
protocol = "any"
_, rule.IPNet, _ = net.ParseCIDR(cidr)
switch strings.ToLower(self.IpProtocol) {
case "tcp", "udp", "icmp":
rule.Protocol = strings.ToLower(self.IpProtocol)
case "all":
rule.Protocol = secrules.PROTO_ANY
default:
return rule, fmt.Errorf("unsupported protocal %s", self.IpProtocol)
}
port, ports := "", strings.Split(self.PortRange, "/")
if ports[0] == ports[1] {
if ports[0] != "-1" {
@@ -446,81 +437,11 @@ func (self *SPermission) String() string {
} else if ports[0] != "1" && ports[1] != "65535" {
port = fmt.Sprintf("%s-%s", ports[0], ports[1])
}
result := fmt.Sprintf("%s:%s", direction, string(action))
if len(cidr) > 0 {
result += fmt.Sprintf(" %s", cidr)
err := rule.ParsePorts(port)
if err != nil {
return rule, errors.Wrapf(err, "ParsePorts(%s)", port)
}
result += fmt.Sprintf(" %s", protocol)
if len(port) > 0 {
result += fmt.Sprintf(" %s", port)
}
return result
}
func (self *SRegion) syncSecgroupRules(secgroupId string, rules []secrules.SecurityRule) error {
if secgroup, err := self.GetSecurityGroupDetails(secgroupId); err != nil {
return err
} else {
sort.Sort(secrules.SecurityRuleSet(rules))
sort.Sort(PermissionSet(secgroup.Permissions.Permission))
i, j := 0, 0
for i < len(rules) || j < len(secgroup.Permissions.Permission) {
if i < len(rules) && j < len(secgroup.Permissions.Permission) {
permissionStr := secgroup.Permissions.Permission[j].String()
ruleStr := rules[i].String()
cmp := strings.Compare(permissionStr, ruleStr)
if cmp == 0 {
if secgroup.Permissions.Permission[j].Description != rules[i].Description {
rules[i].Priority = secgroup.Permissions.Permission[j].Priority
if err := self.modifySecurityGroupRule(secgroupId, &rules[i]); err != nil {
log.Errorf("modifySecurityGroupRule error %v", rules[i])
return err
}
}
i += 1
j += 1
} else if cmp > 0 {
if rule, err := secrules.ParseSecurityRule(permissionStr); err != nil {
return err
} else {
rule.Priority = secgroup.Permissions.Permission[j].Priority
if err := self.delSecurityGroupRule(secgroupId, rule); err != nil {
log.Errorf("delSecurityGroupRule error %v", rule)
return err
}
}
j += 1
} else {
if err := self.addSecurityGroupRules(secgroupId, &rules[i]); err != nil {
log.Errorf("addSecurityGroupRule error %v", rules[i])
return err
}
i += 1
}
} else if i >= len(rules) {
permissionStr := secgroup.Permissions.Permission[j].String()
if rule, err := secrules.ParseSecurityRule(permissionStr); err != nil {
return err
} else {
rule.Priority = secgroup.Permissions.Permission[j].Priority
if err := self.delSecurityGroupRule(secgroupId, rule); err != nil {
log.Errorf("delSecurityGroupRule error %v", rule)
return err
}
}
j += 1
} else if j >= len(secgroup.Permissions.Permission) {
if err := self.addSecurityGroupRules(secgroupId, &rules[i]); err != nil {
log.Errorf("addSecurityGroupRule error %v", rules[i])
return err
}
i += 1
}
}
}
return nil
return rule, nil
}
func (self *SRegion) AssignSecurityGroup(secgroupId, instanceId string) error {
@@ -575,6 +496,18 @@ func (self *SSecurityGroup) GetProjectId() string {
return ""
}
func (self *SSecurityGroup) SyncRules(rules []secrules.SecurityRule) error {
return self.vpc.region.syncSecgroupRules(self.SecurityGroupId, rules)
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)
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)
if err != nil {
return errors.Wrapf(err, "AddSecurityGroupRules(priority: %d %s)", rule.Priority, rule.String())
}
}
return nil
}
+10 -1
View File
@@ -15,6 +15,7 @@
package aws
import (
"github.com/aws/aws-sdk-go/aws"
sdk "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/client"
"github.com/aws/aws-sdk-go/aws/credentials"
@@ -189,7 +190,7 @@ func (self *SAwsClient) fetchRegions() error {
func (client *SAwsClient) getAwsSession(regionId string) (*session.Session, error) {
httpClient := client.cpcfg.HttpClient()
return session.NewSession(&sdk.Config{
s, err := session.NewSession(&sdk.Config{
Region: sdk.String(regionId),
Credentials: credentials.NewStaticCredentials(
client.accessKey, client.accessSecret, "",
@@ -198,6 +199,14 @@ func (client *SAwsClient) getAwsSession(regionId string) (*session.Session, erro
DisableParamValidation: sdk.Bool(true),
CredentialsChainVerboseErrors: sdk.Bool(true),
})
if err != nil {
return nil, err
}
if client.debug {
logLevel := aws.LogLevelType(uint(aws.LogDebugWithRequestErrors) + uint(aws.LogDebugWithHTTPBody) + uint(aws.LogDebugWithSigning))
s.Config.LogLevel = &logLevel
}
return s, nil
}
func (self *SAwsClient) invalidateIBuckets() {
+51 -94
View File
@@ -17,7 +17,6 @@ package aws
import (
"fmt"
"math/rand"
"sort"
"strings"
"time"
@@ -25,9 +24,12 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/secrules"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/multicloud"
)
type Tags struct {
@@ -40,6 +42,7 @@ type Tag struct {
}
type SSecurityGroup struct {
multicloud.SSecurityGroup
vpc *SVpc
RegionId string
@@ -47,7 +50,7 @@ type SSecurityGroup struct {
SecurityGroupId string
Description string
SecurityGroupName string
Permissions []secrules.SecurityRule
Permissions []cloudprovider.SecurityRule
Tags Tags
// CreationTime time.Time
@@ -114,33 +117,30 @@ func (self *SSecurityGroup) GetDescription() string {
return self.Description
}
func (self *SSecurityGroup) GetRules() ([]secrules.SecurityRule, error) {
rules := make([]secrules.SecurityRule, 0)
if secgrp, err := self.vpc.region.GetSecurityGroupDetails(self.SecurityGroupId); err != nil {
return rules, err
} else {
rules = secgrp.Permissions
func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) {
secgrp, err := self.vpc.region.GetSecurityGroupDetails(self.SecurityGroupId)
if err != nil {
return nil, err
}
return rules, nil
return secgrp.Permissions, nil
}
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
if err := self.addSecurityGroupRule(secGrpId, rule); err != nil {
return err
err := self.addSecurityGroupRule(secGrpId, rule)
if err != nil {
return errors.Wrapf(err, "addSecurityGroupRule(%d %s)", rule.Priority, rule.String())
}
}
} else {
return self.addSecurityGroupRule(secGrpId, rule)
return nil
}
return nil
return self.addSecurityGroupRule(secGrpId, rule)
}
func (self *SRegion) addSecurityGroupRule(secGrpId string, rule *secrules.SecurityRule) error {
ipPermissions, err := YunionSecRuleToAws(*rule)
func (self *SRegion) addSecurityGroupRule(secGrpId string, rule cloudprovider.SecurityRule) error {
ipPermissions, err := YunionSecRuleToAws(rule)
log.Debugf("Aws security group rule: %s", ipPermissions)
if err != nil {
return err
@@ -168,8 +168,8 @@ func (self *SRegion) addSecurityGroupRule(secGrpId string, rule *secrules.Securi
return err
}
func (self *SRegion) delSecurityGroupRule(secGrpId string, rule *secrules.SecurityRule) error {
ipPermissions, err := YunionSecRuleToAws(*rule)
func (self *SRegion) DelSecurityGroupRule(secGrpId string, rule cloudprovider.SecurityRule) error {
ipPermissions, err := YunionSecRuleToAws(rule)
if err != nil {
return err
}
@@ -195,8 +195,8 @@ func (self *SRegion) delSecurityGroupRule(secGrpId string, rule *secrules.Securi
return nil
}
func (self *SRegion) updateSecurityGroupRuleDescription(secGrpId string, rule *secrules.SecurityRule) error {
ipPermissions, err := YunionSecRuleToAws(*rule)
func (self *SRegion) updateSecurityGroupRuleDescription(secGrpId string, rule cloudprovider.SecurityRule) error {
ipPermissions, err := YunionSecRuleToAws(rule)
if err != nil {
return err
}
@@ -270,13 +270,15 @@ func (self *SRegion) createDefaultSecurityGroup(vpcId string) (string, error) {
return "", err
}
rule := &secrules.SecurityRule{
Priority: 1,
Action: secrules.SecurityRuleAllow,
Protocol: "",
Direction: secrules.SecurityRuleIngress,
PortStart: -1,
PortEnd: -1,
rule := cloudprovider.SecurityRule{
SecurityRule: secrules.SecurityRule{
Priority: 1,
Action: secrules.SecurityRuleAllow,
Protocol: "",
Direction: secrules.SecurityRuleIngress,
PortStart: -1,
PortEnd: -1,
},
}
err = self.addSecurityGroupRule(secId, rule)
@@ -360,68 +362,8 @@ func (self *SRegion) modifySecurityGroup(secGrpId string, name string, desc stri
return nil
}
func (self *SRegion) syncSecgroupRules(secgroupId string, rules []secrules.SecurityRule) error {
var DeleteRules []secrules.SecurityRule
var AddRules []secrules.SecurityRule
if secgroup, err := self.GetSecurityGroupDetails(secgroupId); err != nil {
return err
} else {
sort.Sort(secrules.SecurityRuleSet(rules))
sort.Sort(secrules.SecurityRuleSet(secgroup.Permissions))
i, j := 0, 0
for i < len(rules) || j < len(secgroup.Permissions) {
if i < len(rules) && j < len(secgroup.Permissions) {
permissionStr := secgroup.Permissions[j].String()
ruleStr := rules[i].String()
cmp := strings.Compare(permissionStr, ruleStr)
if cmp == 0 {
DeleteRules = append(DeleteRules, secgroup.Permissions[j])
AddRules = append(AddRules, rules[i])
i += 1
j += 1
} else if cmp > 0 {
DeleteRules = append(DeleteRules, secgroup.Permissions[j])
j += 1
} else {
AddRules = append(AddRules, rules[i])
i += 1
}
} else if i >= len(rules) {
DeleteRules = append(DeleteRules, secgroup.Permissions[j])
j += 1
} else if j >= len(secgroup.Permissions) {
AddRules = append(AddRules, rules[i])
i += 1
}
}
}
for _, r := range DeleteRules {
if err := self.delSecurityGroupRule(secgroupId, &r); err != nil {
if strings.Contains(err.Error(), "InvalidPermission.NotFound") {
continue
}
log.Errorf("delSecurityGroupRule %v error: %s", r, err.Error())
return err
}
}
for _, r := range AddRules {
if err := self.addSecurityGroupRules(secgroupId, &r); err != nil {
log.Errorf("addSecurityGroupRule %v error: %s", r, err.Error())
return err
}
}
return nil
}
func (self *SRegion) getSecRules(ingress []*ec2.IpPermission, egress []*ec2.IpPermission) []secrules.SecurityRule {
rules := []secrules.SecurityRule{}
func (self *SRegion) getSecRules(ingress []*ec2.IpPermission, egress []*ec2.IpPermission) []cloudprovider.SecurityRule {
rules := []cloudprovider.SecurityRule{}
for _, p := range ingress {
ret, err := AwsIpPermissionToYunion(secrules.SecurityRuleIngress, *p)
if err != nil {
@@ -511,9 +453,24 @@ func (self *SSecurityGroup) GetProjectId() string {
return ""
}
func (self *SSecurityGroup) SyncRules(rules []secrules.SecurityRule) error {
rules = SecurityRuleSetToAllowSet(rules)
return self.vpc.region.syncSecgroupRules(self.SecurityGroupId, rules)
func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error {
for _, r := range append(inDels, outDels...) {
err := self.vpc.region.DelSecurityGroupRule(self.SecurityGroupId, r)
if err != nil {
if strings.Contains(err.Error(), "InvalidPermission.NotFound") {
continue
}
return errors.Wrapf(err, "delSecurityGroupRule %s %d %s", r.Name, r.Priority, r.String())
}
}
for _, r := range append(inAdds, outAdds...) {
err := self.vpc.region.addSecurityGroupRules(self.SecurityGroupId, r)
if err != nil {
return errors.Wrapf(err, "addSecurityGroupRules %d %s", r.Priority, r.String())
}
}
return nil
}
func (self *SSecurityGroup) Delete() error {
+17
View File
@@ -17,6 +17,10 @@ package shell
import (
"fmt"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/secrules"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud/aws"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
@@ -64,4 +68,17 @@ func init() {
return nil
})
type SecurityGroupRuleDeleteOption struct {
SECGROUP_ID string
RULE string
}
shellutils.R(&SecurityGroupRuleDeleteOption{}, "security-group-rule-delete", "Delete security group rule", func(cli *aws.SRegion, args *SecurityGroupRuleDeleteOption) error {
rule, err := secrules.ParseSecurityRule(args.RULE)
if err != nil {
return errors.Wrapf(err, "ParseSecurityRule(%s)", args.RULE)
}
return cli.DelSecurityGroupRule(args.SECGROUP_ID, cloudprovider.SecurityRule{SecurityRule: *rule})
})
}
+40 -38
View File
@@ -18,7 +18,6 @@ import (
"fmt"
"net"
"reflect"
"regexp"
"sort"
"strings"
@@ -225,7 +224,7 @@ func awsProtocolToYunion(p ec2.IpPermission) string {
}
}
func yunionProtocolToAws(r secrules.SecurityRule) string {
func yunionProtocolToAws(r cloudprovider.SecurityRule) string {
if r.Protocol == secrules.PROTO_ANY {
return "-1"
} else {
@@ -244,7 +243,7 @@ func isYunionRuleAllPorts(r secrules.SecurityRule) bool {
}
}
func yunionPortRangeToAws(r secrules.SecurityRule) []portRange {
func yunionPortRangeToAws(r cloudprovider.SecurityRule) []portRange {
// port 0 / -1 都代表所有端口
portranges := []portRange{}
if len(r.Ports) == 0 {
@@ -287,7 +286,7 @@ func yunionPortRangeToAws(r secrules.SecurityRule) []portRange {
}
// Security Rule Transform
func AwsIpPermissionToYunion(direction secrules.TSecurityRuleDirection, p ec2.IpPermission) ([]secrules.SecurityRule, error) {
func AwsIpPermissionToYunion(direction secrules.TSecurityRuleDirection, p ec2.IpPermission) ([]cloudprovider.SecurityRule, error) {
if len(p.UserIdGroupPairs) > 0 {
return nil, fmt.Errorf("AwsIpPermissionToYunion not supported aws rule: UserIdGroupPairs specified")
@@ -301,7 +300,7 @@ func AwsIpPermissionToYunion(direction secrules.TSecurityRuleDirection, p ec2.Ip
log.Debugf("AwsIpPermissionToYunion ignored IPV6 rule: %s", p.Ipv6Ranges)
}
rules := []secrules.SecurityRule{}
rules := []cloudprovider.SecurityRule{}
isAllPorts := isAwsPermissionAllPorts(p)
protocol := awsProtocolToYunion(p)
for _, ip := range p.IpRanges {
@@ -311,24 +310,28 @@ func AwsIpPermissionToYunion(direction secrules.TSecurityRuleDirection, p ec2.Ip
continue
}
var rule secrules.SecurityRule
var rule cloudprovider.SecurityRule
if isAllPorts {
rule = secrules.SecurityRule{
Action: secrules.SecurityRuleAllow,
IPNet: ipNet,
Protocol: protocol,
Direction: direction,
Priority: 1,
Description: StrVal(ip.Description),
rule = cloudprovider.SecurityRule{
SecurityRule: secrules.SecurityRule{
Action: secrules.SecurityRuleAllow,
IPNet: ipNet,
Protocol: protocol,
Direction: direction,
Priority: 1,
Description: StrVal(ip.Description),
},
}
} else {
rule = secrules.SecurityRule{
Action: secrules.SecurityRuleAllow,
IPNet: ipNet,
Protocol: protocol,
Direction: direction,
Priority: 1,
Description: StrVal(ip.Description),
rule = cloudprovider.SecurityRule{
SecurityRule: secrules.SecurityRule{
Action: secrules.SecurityRuleAllow,
IPNet: ipNet,
Protocol: protocol,
Direction: direction,
Priority: 1,
Description: StrVal(ip.Description),
},
}
if p.FromPort != nil {
@@ -349,36 +352,35 @@ func AwsIpPermissionToYunion(direction secrules.TSecurityRuleDirection, p ec2.Ip
// YunionSecRuleToAws 不能保证无损转换
// 规则描述如果包含中文等字符,将被丢弃掉
func YunionSecRuleToAws(rule secrules.SecurityRule) ([]*ec2.IpPermission, error) {
if rule.Action == secrules.SecurityRuleDeny {
return nil, fmt.Errorf("YunionSecRuleToAws ignored aws not supported deny rule")
}
func YunionSecRuleToAws(rule cloudprovider.SecurityRule) ([]*ec2.IpPermission, error) {
iprange := rule.IPNet.String()
if iprange == "<nil>" {
return nil, fmt.Errorf("YunionSecRuleToAws ignored ipnet should not be empty")
}
description := ""
if match, err := regexp.MatchString("^[\\sa-zA-Z0-9. _:/()#,@\\]\\[+=&;{}!$*-]+$", rule.Description); err == nil && match {
description = rule.Description
}
ipranges := []*ec2.IpRange{}
ipranges = append(ipranges, &ec2.IpRange{CidrIp: &iprange, Description: &description})
ipranges = append(ipranges, &ec2.IpRange{CidrIp: &iprange})
portranges := yunionPortRangeToAws(rule)
protocol := yunionProtocolToAws(rule)
permissions := []*ec2.IpPermission{}
for i := range portranges {
port := portranges[i]
permission := ec2.IpPermission{
FromPort: &port.Start,
if rule.Protocol != secrules.PROTO_ANY {
for i := range portranges {
port := portranges[i]
permission := ec2.IpPermission{
FromPort: &port.Start,
IpProtocol: &protocol,
IpRanges: ipranges,
ToPort: &port.End,
}
permissions = append(permissions, &permission)
}
} else {
permissions = append(permissions, &ec2.IpPermission{
IpProtocol: &protocol,
IpRanges: ipranges,
ToPort: &port.End,
}
permissions = append(permissions, &permission)
})
}
return permissions, nil
-39
View File
@@ -21,9 +21,7 @@ import (
"github.com/aws/aws-sdk-go/service/ec2"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/secrules"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
@@ -166,43 +164,6 @@ func (self *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error)
return nil, ErrorNotFound()
}
func (self *SRegion) SyncSecurityGroup(secgroupId string, vpcId string, name string, desc string, rules []secrules.SecurityRule) (string, error) {
secgrpId := ""
// 名称为default的安全组与aws默认安全组名冲突
if strings.ToLower(name) == "default" {
name = randomString(fmt.Sprintf("%s-", vpcId), 9)
}
rules = SecurityRuleSetToAllowSet(rules)
if secgroup, err := self.getSecurityGroupById(vpcId, secgroupId); err != nil {
if len(desc) == 0 {
desc = fmt.Sprintf("security group %s for vpc %s", name, vpcId)
}
if secgrpId, err = self.CreateSecurityGroup(vpcId, name, secgroupId, desc); err != nil {
return "", err
}
//addRules
for _, rule := range rules {
if err := self.addSecurityGroupRule(secgrpId, &rule); err != nil {
return "", err
}
}
} else {
//syncRules
secgrpId = secgroup.SecurityGroupId
log.Debugf("Sync Rules for %s", secgroup.GetName())
if secgroup.GetName() != name {
if err := self.modifySecurityGroup(secgrpId, name, ""); err != nil {
log.Errorf("Change SecurityGroup name to %s failed: %v", name, err)
}
}
self.syncSecgroupRules(secgrpId, rules)
}
return secgrpId, nil
}
func (self *SVpc) getWireByZoneId(zoneId string) *SWire {
for i := 0; i < len(self.iwires); i += 1 {
wire := self.iwires[i].(*SWire)
+75 -128
View File
@@ -17,19 +17,21 @@ package azure
import (
"fmt"
"net"
"sort"
"strconv"
"strings"
"unicode"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/secrules"
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
)
type SClassicSecurityGroup struct {
multicloud.SSecurityGroup
region *SRegion
vpc *SClassicVpc
Properties ClassicSecurityGroupProperties `json:"properties,omitempty"`
@@ -65,31 +67,14 @@ type SClassicSecurityGroupRule struct {
Type string
}
type ClassicSecurityRulesSet []SClassicSecurityGroupRule
func (v ClassicSecurityRulesSet) Len() int {
return len(v)
}
func (v ClassicSecurityRulesSet) Swap(i, j int) {
v[i], v[j] = v[j], v[i]
}
func (v ClassicSecurityRulesSet) Less(i, j int) bool {
if v[i].Properties.Priority < v[j].Properties.Priority {
return true
} else if v[i].Properties.Priority == v[j].Properties.Priority {
return strings.Compare(v[i].Properties.String(), v[j].Properties.String()) <= 0
}
return false
}
func (self *ClassicSecurityGroupRuleProperties) toRules() []secrules.SecurityRule {
rules := []secrules.SecurityRule{}
rule := secrules.SecurityRule{
Action: secrules.TSecurityRuleAction(strings.ToLower(self.Action)),
Direction: secrules.TSecurityRuleDirection(strings.Replace(strings.ToLower(self.Type), "bound", "", -1)),
Protocol: strings.ToLower(self.Protocol),
func (self *ClassicSecurityGroupRuleProperties) toRule() *cloudprovider.SecurityRule {
rule := cloudprovider.SecurityRule{
SecurityRule: secrules.SecurityRule{
Action: secrules.TSecurityRuleAction(strings.ToLower(self.Action)),
Direction: secrules.TSecurityRuleDirection(strings.Replace(strings.ToLower(self.Type), "bound", "", -1)),
Protocol: strings.ToLower(self.Protocol),
Priority: int(self.Priority),
},
}
if rule.Protocol == "*" {
rule.Protocol = "any"
@@ -102,7 +87,7 @@ func (self *ClassicSecurityGroupRuleProperties) toRules() []secrules.SecurityRul
}
if utils.IsInStringArray(ip, []string{"INTERNET", "VIRTUAL_NETWORK", "AZURE_LOADBALANCER"}) {
return rules
return nil
}
if ip == "*" {
@@ -127,23 +112,7 @@ func (self *ClassicSecurityGroupRuleProperties) toRules() []secrules.SecurityRul
rule.PortStart, _ = strconv.Atoi(ports[0])
rule.PortEnd, _ = strconv.Atoi(ports[0])
}
if rule.PortStart > 0 && rule.Protocol == "any" {
rule.Protocol = secrules.PROTO_TCP
rules = append(rules, rule)
rule.Protocol = secrules.PROTO_UDP
rules = append(rules, rule)
rule.Protocol = secrules.PROTO_ICMP
rules = append(rules, rule)
}
return rules
}
func (self *ClassicSecurityGroupRuleProperties) String() string {
result := []string{}
for _, rule := range self.toRules() {
result = append(result, rule.String())
}
return strings.Join(result, ";")
return &rule
}
func (self *SClassicSecurityGroup) GetVpcId() string {
@@ -174,33 +143,27 @@ func (self *SClassicSecurityGroup) GetName() string {
return self.Name
}
func (self *SClassicSecurityGroup) GetRules() ([]secrules.SecurityRule, error) {
rules := make([]secrules.SecurityRule, 0)
func (self *SClassicSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) {
rules := make([]cloudprovider.SecurityRule, 0)
secgrouprules, err := self.region.getClassicSecurityGroupRules(self.ID)
if err != nil {
return nil, err
}
sort.Sort(ClassicSecurityRulesSet(secgrouprules))
priority := 100
for i := 0; i < len(secgrouprules); i++ {
if secgrouprules[i].Properties.Priority >= 65000 {
continue
}
_rules := secgrouprules[i].Properties.toRules()
for i := 0; i < len(_rules); i++ {
rule := _rules[i]
rule.Priority = priority
rule.Description = secgrouprules[i].Name
if err := rule.ValidateRule(); err != nil {
log.Errorf("Azure classic secgroup get rules error: %v", err)
return nil, err
}
rules = append(rules, rule)
rule := secgrouprules[i].Properties.toRule()
if rule == nil {
continue
}
if len(_rules) > 0 {
priority--
rule.Name = secgrouprules[i].Name
rule.ExternalId = secgrouprules[i].ID
if err := rule.ValidateRule(); err != nil && err != secrules.ErrInvalidPriority {
return nil, errors.Wrap(err, "rule.ValidateRule")
}
rules = append(rules, *rule)
}
return rules, nil
}
@@ -262,18 +225,32 @@ func (self *SClassicSecurityGroup) Refresh() error {
return jsonutils.Update(self, sec)
}
func convertClassicSecurityGroupRules(rule secrules.SecurityRule, priority int32) ([]SClassicSecurityGroupRule, error) {
name := strings.Replace(rule.String(), ":", "_", -1)
name = strings.Replace(name, " ", "_", -1)
name = strings.Replace(name, "-", "_", -1)
name = strings.Replace(name, "/", "_", -1)
name = fmt.Sprintf("%s_%d", name, rule.Priority)
func convertClassicSecurityGroupRules(rule cloudprovider.SecurityRule) ([]SClassicSecurityGroupRule, error) {
rules := []SClassicSecurityGroupRule{}
if len(rule.Name) == 0 {
rule.Name = fmt.Sprintf("%s_%d", rule.String(), rule.Priority)
}
rule.Name = func(name string) string {
// 名称必须以字母或数字开头,以字母、数字或下划线结尾,并且只能包含字母、数字、下划线、句点或连字符
for _, s := range name {
if !(unicode.IsDigit(s) || unicode.IsLetter(s) || s == '.' || s == '-' || s == '_') {
name = strings.ReplaceAll(name, string(s), "_")
}
}
if !unicode.IsDigit(rune(name[0])) && !unicode.IsLetter(rune(name[0])) {
name = fmt.Sprintf("r_%s", name)
}
last := len(name) - 1
if !unicode.IsDigit(rune(name[last])) && !unicode.IsLetter(rune(name[last])) && name[last] != '_' {
name = fmt.Sprintf("%s_", name)
}
return name
}(rule.Name)
secRule := SClassicSecurityGroupRule{
Name: name,
Name: rule.Name,
Properties: ClassicSecurityGroupRuleProperties{
Action: utils.Capitalize(string(rule.Action)),
Priority: priority,
Priority: int32(rule.Priority),
Type: utils.Capitalize(string(rule.Direction)) + "bound",
Protocol: utils.Capitalize(rule.Protocol),
SourcePortRange: "*",
@@ -286,7 +263,7 @@ func convertClassicSecurityGroupRules(rule secrules.SecurityRule, priority int32
secRule.Properties.Protocol = "*"
}
if rule.Protocol == secrules.PROTO_ICMP {
return nil, nil
return nil, fmt.Errorf("not support icmp protocol")
}
ipAddr := "*"
if rule.IPNet != nil {
@@ -319,72 +296,42 @@ func (self *SRegion) getClassicSecurityGroupRules(secgroupId string) ([]SClassic
return rules, result.Unmarshal(&rules, "value")
}
func (self *SRegion) syncClassicSecgroupRules(secgroupId string, rules []secrules.SecurityRule) (string, error) {
secgrouprules, err := self.getClassicSecurityGroupRules(secgroupId)
if err != nil {
return "", err
}
for _, rule := range secgrouprules {
if rule.Properties.Priority >= 65000 {
continue
}
if err := self.client.Delete(rule.ID); err != nil {
return "", err
}
}
sort.Sort(secrules.SecurityRuleSet(rules))
priority := int32(100)
ruleStrs := []string{}
for i, _rule := range rules {
ruleStr := rules[i].String()
if !utils.IsInStringArray(ruleStr, ruleStrs) {
_rules, err := convertClassicSecurityGroupRules(_rule, priority)
if err != nil {
return "", err
}
priority++
ruleStrs = append(ruleStrs, ruleStr)
for _, rule := range _rules {
if err := self.addClassicSecgroupRule(secgroupId, rule); err != nil {
return "", err
}
}
}
}
return secgroupId, nil
}
func (self *SRegion) addClassicSecgroupRule(secgroupId string, rule SClassicSecurityGroupRule) error {
url := fmt.Sprintf("%s/securityRules/%s?api-version=2015-06-01", secgroupId, rule.Name)
_, err := self.client.jsonRequest("PUT", url, jsonutils.Marshal(rule).String())
return err
}
func (region *SRegion) syncClassicSecurityGroup(secgroupId, name, desc string, rules []secrules.SecurityRule) (string, error) {
if len(secgroupId) > 0 {
if _, err := region.GetClassicSecurityGroupDetails(secgroupId); err != nil {
if err != cloudprovider.ErrNotFound {
return "", err
}
secgroupId = ""
}
}
if len(secgroupId) == 0 {
secgroup, err := region.CreateClassicSecurityGroup(name)
if err != nil {
return "", err
}
secgroupId = secgroup.ID
}
return region.syncClassicSecgroupRules(secgroupId, rules)
}
func (self *SClassicSecurityGroup) GetProjectId() string {
return getResourceGroup(self.ID)
}
func (self *SClassicSecurityGroup) SyncRules(rules []secrules.SecurityRule) error {
_, err := self.region.syncClassicSecgroupRules(self.ID, rules)
return err
func (self *SClassicSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error {
for _, r := range append(inDels, outDels...) {
err := self.region.client.Delete(r.ExternalId)
if err != nil {
return errors.Wrapf(err, "Delete(%s)", r.ExternalId)
}
for _, r := range append(inAdds, outAdds...) {
_rules, err := convertClassicSecurityGroupRules(r)
if err != nil {
return errors.Wrapf(err, "convertClassicSecurityGroupRules(%s)", r.String())
}
names := []string{}
for _, r := range _rules {
for {
if !utils.IsInStringArray(r.Name, names) {
names = append(names, r.Name)
break
}
r.Name = fmt.Sprintf("%s_", r.Name)
}
err = self.region.addClassicSecgroupRule(self.ID, r)
if err != nil {
return errors.Wrap(err, "addClassicSecgroupRule")
}
}
}
}
return nil
}
+1
View File
@@ -128,6 +128,7 @@ func (self *SClassicVpc) getClassicSecurityGroups() ([]SClassicSecurityGroup, er
}
for i := 0; i < len(securityGroups); i++ {
securityGroups[i].vpc = self
securityGroups[i].region = self.region
}
return securityGroups, nil
}
+1 -24
View File
@@ -22,7 +22,6 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/secrules"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
@@ -570,33 +569,11 @@ func (region *SRegion) GetISecurityGroupByName(vpcId string, name string) (cloud
func (region *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) {
if conf.VpcId == "classic" {
return region.CreateClassicSecurityGroup(conf.Desc)
return region.CreateClassicSecurityGroup(conf.Name)
}
return region.CreateSecurityGroup(conf.Name)
}
func (region *SRegion) SyncSecurityGroup(secgroupId, vpcId, name, desc string, rules []secrules.SecurityRule) (string, error) {
if vpcId == "classic" {
return region.syncClassicSecurityGroup(secgroupId, name, desc, rules)
}
if len(secgroupId) > 0 {
if _, err := region.GetSecurityGroupDetails(secgroupId); err != nil {
if err != cloudprovider.ErrNotFound {
return "", err
}
secgroupId = ""
}
}
if len(secgroupId) == 0 {
secgroup, err := region.CreateSecurityGroup(name)
if err != nil {
return "", err
}
secgroupId = secgroup.ID
}
return region.updateSecurityGroupRules(secgroupId, rules)
}
func (region *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) {
return nil, cloudprovider.ErrNotImplemented
}
+72 -116
View File
@@ -17,15 +17,19 @@ package azure
import (
"fmt"
"net"
"sort"
"strconv"
"strings"
"unicode"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/regutils"
"yunion.io/x/pkg/util/secrules"
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
)
type SecurityRulePropertiesFormat struct {
@@ -50,25 +54,6 @@ type SecurityRules struct {
ID string
}
type SecurityRulesSet []SecurityRules
func (v SecurityRulesSet) Len() int {
return len(v)
}
func (v SecurityRulesSet) Swap(i, j int) {
v[i], v[j] = v[j], v[i]
}
func (v SecurityRulesSet) Less(i, j int) bool {
if v[i].Properties.Priority < v[j].Properties.Priority {
return true
} else if v[i].Properties.Priority == v[j].Properties.Priority {
return strings.Compare(v[i].Properties.String(), v[j].Properties.String()) <= 0
}
return false
}
type Interface struct {
ID string
}
@@ -81,6 +66,7 @@ type SecurityGroupPropertiesFormat struct {
ProvisioningState string //Possible values are: 'Updating', 'Deleting', and 'Failed'
}
type SSecurityGroup struct {
multicloud.SSecurityGroup
vpc *SVpc
region *SRegion
Properties *SecurityGroupPropertiesFormat `json:"properties,omitempty"`
@@ -204,15 +190,16 @@ func paresPortsWithIpNet(port string, ports []string, ip string, ips []string) (
return portsResult, ipResult, nil
}
func (self *SecurityRulePropertiesFormat) toRules() ([]secrules.SecurityRule, error) {
result := []secrules.SecurityRule{}
rule := secrules.SecurityRule{
Action: secrules.TSecurityRuleAction(strings.ToLower(self.Access)),
Direction: secrules.TSecurityRuleDirection(strings.Replace(strings.ToLower(self.Direction), "bound", "", -1)),
Protocol: strings.ToLower(self.Protocol),
Priority: int(self.Priority),
Description: self.Description,
}
func (self *SecurityRulePropertiesFormat) toRules() ([]cloudprovider.SecurityRule, error) {
result := []cloudprovider.SecurityRule{}
rule := cloudprovider.SecurityRule{
SecurityRule: secrules.SecurityRule{
Action: secrules.TSecurityRuleAction(strings.ToLower(self.Access)),
Direction: secrules.TSecurityRuleDirection(strings.Replace(strings.ToLower(self.Direction), "bound", "", -1)),
Protocol: strings.ToLower(self.Protocol),
Priority: int(self.Priority),
Description: self.Description,
}}
if rule.Protocol == "*" {
rule.Protocol = "any"
@@ -240,47 +227,15 @@ func (self *SecurityRulePropertiesFormat) toRules() ([]secrules.SecurityRule, er
for i := 0; i < len(ips); i++ {
rule.IPNet = ips[i]
withICMP := false
for j := 0; j < len(ports); j++ {
rule.Ports = ports[j].ports
rule.PortStart = ports[j].portStart
rule.PortEnd = ports[j].portEnd
if rule.Protocol == secrules.PROTO_ANY && len(rule.Ports) > 0 || (rule.PortStart+rule.PortStart > 0) {
tcp := rule
tcp.Protocol = secrules.PROTO_TCP
err := tcp.ValidateRule()
if err != nil {
return nil, err
}
result = append(result, tcp)
udp := rule
udp.Protocol = secrules.PROTO_UDP
err = udp.ValidateRule()
if err != nil {
return nil, err
}
result = append(result, udp)
withICMP = true
} else {
err := rule.ValidateRule()
if err != nil {
return nil, err
}
result = append(result, rule)
}
}
if withICMP {
icmp := rule
icmp.Protocol = secrules.PROTO_ICMP
icmp.PortStart = -1
icmp.PortEnd = -1
icmp.Ports = []int{}
err := icmp.ValidateRule()
if err != nil {
err := rule.ValidateRule()
if err != nil && err != secrules.ErrInvalidPriority {
return nil, err
}
result = append(result, icmp)
result = append(result, rule)
}
}
@@ -316,24 +271,20 @@ func (self *SSecurityGroup) GetName() string {
return self.Name
}
func (self *SSecurityGroup) GetRules() ([]secrules.SecurityRule, error) {
rules := make([]secrules.SecurityRule, 0)
func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) {
rules := make([]cloudprovider.SecurityRule, 0)
if self.Properties.SecurityRules == nil {
return rules, nil
}
sort.Sort(SecurityRulesSet(self.Properties.SecurityRules))
priority := 100
for _, _rule := range self.Properties.SecurityRules {
_rule.Properties.Priority = int32(priority)
secRules, err := _rule.Properties.toRules()
if err != nil {
log.Errorf("Azure convert rule %v error: %v", _rule, err)
return nil, err
return nil, errors.Wrap(err, "_rule.Properties.toRules")
}
if len(secRules) > 0 {
priority--
for i := range secRules {
secRules[i].Name = _rule.Name
rules = append(rules, secRules[i])
}
rules = append(rules, secRules...)
}
return rules, nil
}
@@ -392,7 +343,7 @@ func (self *SSecurityGroup) Refresh() error {
return jsonutils.Update(self, sec)
}
func convertRulePort(rule secrules.SecurityRule) []string {
func convertRulePort(rule cloudprovider.SecurityRule) []string {
ports := []string{}
if len(rule.Ports) > 0 {
for i := 0; i < len(rule.Ports); i++ {
@@ -409,18 +360,31 @@ func convertRulePort(rule secrules.SecurityRule) []string {
return ports
}
func convertSecurityGroupRule(rule secrules.SecurityRule, priority int32) *SecurityRules {
name := strings.Replace(rule.String(), ":", "_", -1)
name = strings.Replace(name, " ", "_", -1)
name = strings.Replace(name, "-", "_", -1)
name = strings.Replace(name, "/", "_", -1)
name = strings.Replace(name, ",", "_", -1)
name = fmt.Sprintf("%s_%d", name, rule.Priority)
func convertSecurityGroupRule(rule cloudprovider.SecurityRule) *SecurityRules {
if len(rule.Name) == 0 {
rule.Name = fmt.Sprintf("%s_%d", rule.String(), rule.Priority)
}
rule.Name = func(name string) string {
// 名称必须以字母或数字开头,以字母、数字或下划线结尾,并且只能包含字母、数字、下划线、句点或连字符
for _, s := range name {
if !(unicode.IsDigit(s) || unicode.IsLetter(s) || s == '.' || s == '-' || s == '_') {
name = strings.ReplaceAll(name, string(s), "_")
}
}
if !unicode.IsDigit(rune(name[0])) && !unicode.IsLetter(rune(name[0])) {
name = fmt.Sprintf("r_%s", name)
}
last := len(name) - 1
if !unicode.IsDigit(rune(name[last])) && !unicode.IsLetter(rune(name[last])) && name[last] != '_' {
name = fmt.Sprintf("%s_", name)
}
return name
}(rule.Name)
destRule := SecurityRules{
Name: name,
Name: rule.Name,
Properties: SecurityRulePropertiesFormat{
Access: utils.Capitalize(string(rule.Action)),
Priority: priority,
Priority: int32(rule.Priority),
Protocol: "*",
Direction: utils.Capitalize((string(rule.Direction) + "bound")),
Description: rule.Description,
@@ -435,10 +399,6 @@ func convertSecurityGroupRule(rule secrules.SecurityRule, priority int32) *Secur
destRule.Properties.Protocol = utils.Capitalize(rule.Protocol)
}
if rule.Protocol == secrules.PROTO_ICMP {
return nil
}
if len(destRule.Properties.DestinationPortRanges) > 0 {
destRule.Properties.DestinationPortRange = ""
}
@@ -455,31 +415,6 @@ func convertSecurityGroupRule(rule secrules.SecurityRule, priority int32) *Secur
return &destRule
}
func (region *SRegion) updateSecurityGroupRules(secgroupId string, rules []secrules.SecurityRule) (string, error) {
secgroup, err := region.GetSecurityGroupDetails(secgroupId)
if err != nil {
return "", err
}
sort.Sort(secrules.SecurityRuleSet(rules))
securityRules := []SecurityRules{}
priority := int32(100)
ruleStrs := []string{}
for i := 0; i < len(rules); i++ {
ruleStr := rules[i].String()
if !utils.IsInStringArray(ruleStr, ruleStrs) {
rule := convertSecurityGroupRule(rules[i], priority)
if rule != nil {
securityRules = append(securityRules, *rule)
priority++
}
ruleStrs = append(ruleStrs, ruleStr)
}
}
secgroup.Properties.SecurityRules = securityRules
secgroup.Properties.ProvisioningState = ""
return secgroup.ID, region.client.Update(jsonutils.Marshal(secgroup), nil)
}
func (region *SRegion) AttachSecurityToInterfaces(secgroupId string, nicIds []string) error {
for _, nicId := range nicIds {
nic, err := region.GetNetworkInterfaceDetail(nicId)
@@ -526,7 +461,28 @@ func (self *SSecurityGroup) Delete() error {
return self.region.client.Delete(self.ID)
}
func (self *SSecurityGroup) SyncRules(rules []secrules.SecurityRule) error {
_, err := self.region.updateSecurityGroupRules(self.ID, rules)
return err
func (self *SSecurityGroup) SetRules(rules []cloudprovider.SecurityRule) error {
names := []string{}
securityRules := []SecurityRules{}
for i := 0; i < len(rules); i++ {
rule := convertSecurityGroupRule(rules[i])
if rule != nil {
for {
if !utils.IsInStringArray(rule.Name, names) {
names = append(names, rule.Name)
break
}
rule.Name = fmt.Sprintf("%s_", rule.Name)
}
securityRules = append(securityRules, *rule)
}
}
self.Properties.SecurityRules = securityRules
self.Properties.ProvisioningState = ""
return self.region.client.Update(jsonutils.Marshal(self), nil)
}
func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error {
rules := append(common, append(inAdds, outAdds...)...)
return self.SetRules(rules)
}
-28
View File
@@ -20,7 +20,6 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/secrules"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
@@ -153,11 +152,6 @@ func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreat
return nil, errors.Wrap(err, "Region.CreateISecurityGroup")
}
err = self.syncSecgroupRules(secgroup.GetId(), conf.Rules)
if err != nil {
return nil, errors.Wrap(err, "Region.CreateISecurityGroup.syncSecgroupRules")
}
return secgroup, nil
}
@@ -297,28 +291,6 @@ func (self *SRegion) DeleteSecurityGroup(securityGroupId string) error {
return nil
}
func (self *SRegion) SyncSecurityGroup(secgroupId string, vpcId string, name string, desc string, rules []secrules.SecurityRule) (string, error) {
if len(secgroupId) > 0 {
_, err := self.GetSecurityGroupDetails(secgroupId)
if err == cloudprovider.ErrNotFound {
secgroupId = ""
} else if err != nil {
return "", errors.Wrapf(err, "self.GetSecurityGroupDetails(%s)", secgroupId)
}
}
if len(secgroupId) == 0 {
secgroup, err := self.CreateSecurityGroup(vpcId, name)
if err != nil {
return "", errors.Wrap(err, "self.CreateSecurityGroup")
}
secgroupId = secgroup.GetId()
}
rules = SecurityRuleSetToAllowSet(rules)
return secgroupId, self.syncSecgroupRules(secgroupId, rules)
}
func (self *SRegion) CreateIVpc(name string, desc string, cidr string) (cloudprovider.ICloudVpc, error) {
return self.CreateVpc(name, cidr)
}
+36 -155
View File
@@ -17,18 +17,18 @@ package ctyun
import (
"fmt"
"net"
"sort"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/secrules"
apis "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
)
type SSecurityGroup struct {
multicloud.SSecurityGroup
region *SRegion
ResSecurityGroupID string `json:"resSecurityGroupId"`
@@ -42,136 +42,11 @@ type SSecurityGroup struct {
Status int64 `json:"status"`
}
// 将安全组规则全部转换为等价的allow规则
func SecurityRuleSetToAllowSet(srs secrules.SecurityRuleSet) secrules.SecurityRuleSet {
inRuleSet := secrules.SecurityRuleSet{}
outRuleSet := secrules.SecurityRuleSet{}
for _, rule := range srs {
if rule.Direction == secrules.SecurityRuleIngress {
inRuleSet = append(inRuleSet, rule)
}
if rule.Direction == secrules.SecurityRuleEgress {
outRuleSet = append(outRuleSet, rule)
}
}
sort.Sort(inRuleSet)
sort.Sort(outRuleSet)
inRuleSet = inRuleSet.AllowList()
// out方向空规则默认全部放行
if outRuleSet.Len() == 0 {
_, ipNet, _ := net.ParseCIDR("0.0.0.0/0")
outRuleSet = append(outRuleSet, secrules.SecurityRule{
Priority: 0,
Action: secrules.SecurityRuleAllow,
IPNet: ipNet,
Protocol: secrules.PROTO_ANY,
Direction: secrules.SecurityRuleEgress,
PortStart: -1,
PortEnd: -1,
})
}
outRuleSet = outRuleSet.AllowList()
ret := secrules.SecurityRuleSet{}
ret = append(ret, inRuleSet...)
ret = append(ret, outRuleSet...)
return ret
}
func (self *SSecurityGroup) GetRulesWithExtId() ([]secrules.SecurityRule, error) {
_rules, err := self.region.GetSecurityGroupRules(self.GetId())
if err != nil {
return nil, errors.Wrap(err, "SSecurityGroup.GetRulesWithExtId.GetSecurityGroupRules")
}
rules := make([]secrules.SecurityRule, 0)
for _, r := range _rules {
if !compatibleSecurityGroupRule(r) {
continue
}
rule, err := self.GetSecurityRule(r, true)
if err != nil {
return rules, err
}
rules = append(rules, rule)
}
return rules, nil
}
func (self *SRegion) syncSecgroupRules(secgroupId string, srules []secrules.SecurityRule) error {
var DeleteRules []secrules.SecurityRule
var AddRules []secrules.SecurityRule
rules := SecurityRuleSetToAllowSet(srules)
if secgroup, err := self.GetSecurityGroupDetails(secgroupId); err != nil {
return errors.Wrapf(err, "syncSecgroupRules.GetSecurityGroupDetails(%s)", secgroupId)
} else {
remoteRules, err := secgroup.GetRulesWithExtId()
if err != nil {
return errors.Wrap(err, "secgroup.GetRulesWithExtId")
}
sort.Sort(secrules.SecurityRuleSet(rules))
sort.Sort(secrules.SecurityRuleSet(remoteRules))
i, j := 0, 0
for i < len(rules) || j < len(remoteRules) {
if i < len(rules) && j < len(remoteRules) {
permissionStr := remoteRules[j].String()
ruleStr := rules[i].String()
cmp := strings.Compare(permissionStr, ruleStr)
if cmp == 0 {
// DeleteRules = append(DeleteRules, remoteRules[j])
// AddRules = append(AddRules, rules[i])
i += 1
j += 1
} else if cmp > 0 {
DeleteRules = append(DeleteRules, remoteRules[j])
j += 1
} else {
AddRules = append(AddRules, rules[i])
i += 1
}
} else if i >= len(rules) {
DeleteRules = append(DeleteRules, remoteRules[j])
j += 1
} else if j >= len(remoteRules) {
AddRules = append(AddRules, rules[i])
i += 1
}
}
}
for _, r := range DeleteRules {
// r.Description 实际存储的是ruleId
if err := self.delSecurityGroupRule(r.Description); err != nil {
log.Errorf("delSecurityGroupRule %v error: %s", r, err.Error())
return err
}
}
for _, r := range AddRules {
if err := self.addSecurityGroupRules(secgroupId, &r); err != nil {
log.Errorf("addSecurityGroupRule %v error: %s", r, err.Error())
return err
}
}
return nil
}
func (self *SRegion) delSecurityGroupRule(secGrpRuleId string) error {
return self.DeleteSecurityGroupRule(secGrpRuleId)
}
func (self *SRegion) addSecurityGroupRules(secGrpId string, rule *secrules.SecurityRule) error {
func (self *SRegion) AddSecurityGroupRules(secGrpId string, rule cloudprovider.SecurityRule) error {
direction := ""
if rule.Direction == secrules.SecurityRuleIngress {
direction = "ingress"
@@ -209,9 +84,20 @@ func (self *SRegion) addSecurityGroupRules(secGrpId string, rule *secrules.Secur
return nil
}
func (self *SSecurityGroup) SyncRules(rules []secrules.SecurityRule) error {
rules = SecurityRuleSetToAllowSet(rules)
return self.region.syncSecgroupRules(self.ResSecurityGroupID, rules)
func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error {
for _, r := range append(inDels, outDels...) {
err := self.region.delSecurityGroupRule(r.ExternalId)
if err != nil {
return errors.Wrapf(err, "delSecurityGroupRule(%s)", r.ExternalId)
}
}
for _, r := range append(inAdds, outAdds...) {
err := self.region.AddSecurityGroupRules(self.ResSecurityGroupID, r)
if err != nil {
return errors.Wrapf(err, "addSecurityGroupRule(%d %s)", r.Priority, r.String())
}
}
return nil
}
func (self *SSecurityGroup) Delete() error {
@@ -272,19 +158,19 @@ func compatibleSecurityGroupRule(r SSecurityGroupRule) bool {
return true
}
func (self *SSecurityGroup) GetRules() ([]secrules.SecurityRule, error) {
func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) {
_rules, err := self.region.GetSecurityGroupRules(self.GetId())
if err != nil {
return nil, errors.Wrap(err, "SSecurityGroup.GetRules.GetSecurityGroupRules")
}
rules := make([]secrules.SecurityRule, 0)
rules := make([]cloudprovider.SecurityRule, 0)
for _, r := range _rules {
if !compatibleSecurityGroupRule(r) {
continue
}
rule, err := self.GetSecurityRule(r, false)
rule, err := self.GetSecurityRule(r)
if err != nil {
return rules, err
}
@@ -295,7 +181,7 @@ func (self *SSecurityGroup) GetRules() ([]secrules.SecurityRule, error) {
return rules, nil
}
func (self *SSecurityGroup) GetSecurityRule(remoteRule SSecurityGroupRule, withRuleId bool) (secrules.SecurityRule, error) {
func (self *SSecurityGroup) GetSecurityRule(remoteRule SSecurityGroupRule) (cloudprovider.SecurityRule, error) {
var err error
var direction secrules.TSecurityRuleDirection
if remoteRule.Direction == "ingress" {
@@ -327,27 +213,22 @@ func (self *SSecurityGroup) GetSecurityRule(remoteRule SSecurityGroupRule, withR
}
if err != nil {
return secrules.SecurityRule{}, err
return cloudprovider.SecurityRule{}, err
}
// withRuleId.将ruleId附加到description字段。该hook有特殊目的,仅在同步安全组时使用。
desc := ""
if withRuleId {
desc = remoteRule.ID
} else {
desc = remoteRule.Description
}
rule := secrules.SecurityRule{
Priority: 1,
Action: secrules.SecurityRuleAllow,
IPNet: ipNet,
Protocol: protocol,
Direction: direction,
PortStart: portStart,
PortEnd: portEnd,
Ports: nil,
Description: desc,
rule := cloudprovider.SecurityRule{
ExternalId: remoteRule.ID,
SecurityRule: secrules.SecurityRule{
Priority: 1,
Action: secrules.SecurityRuleAllow,
IPNet: ipNet,
Protocol: protocol,
Direction: direction,
PortStart: portStart,
PortEnd: portEnd,
Ports: nil,
Description: remoteRule.Description,
},
}
err = rule.ValidateRule()
+10 -12
View File
@@ -15,6 +15,10 @@
package shell
import (
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/secrules"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud/ctyun"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
@@ -58,20 +62,14 @@ func init() {
})
type SecurityGroupRuleCreateOptions struct {
Group string `help:"secgroup id"`
Direction string `help:"direction"`
Ethertype string `help:"ethertype" choice:"IPv4|IPv6"`
Protocol string `help:"protocol,icmptcpudpand so on "`
IpPrefix string `help:"remote ip prefix"`
PortMin int64 `help:"portRangeMin"`
PortMax int64 `help:"portRangeMax"`
GROUP string `help:"secgroup id"`
RULE string
}
shellutils.R(&SecurityGroupRuleCreateOptions{}, "secrule-create", "Create secgroup rule", func(cli *ctyun.SRegion, args *SecurityGroupRuleCreateOptions) error {
e := cli.CreateSecurityGroupRule(args.Group, args.Direction, args.Ethertype, args.Protocol, args.IpPrefix, args.PortMin, args.PortMax)
if e != nil {
return e
rule, err := secrules.ParseSecurityRule(args.RULE)
if err != nil {
return errors.Wrap(err, "ParseSecurityRule")
}
return nil
return cli.AddSecurityGroupRules(args.GROUP, cloudprovider.SecurityRule{SecurityRule: *rule})
})
}
+29 -92
View File
@@ -17,7 +17,6 @@ package google
import (
"fmt"
"net"
"sort"
"strconv"
"strings"
"time"
@@ -29,6 +28,7 @@ import (
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
)
const (
@@ -60,24 +60,8 @@ type SFirewall struct {
Kind string
}
type FirewallSet []SFirewall
func (f FirewallSet) Len() int {
return len(f)
}
func (f FirewallSet) Swap(i, j int) {
f[i], f[j] = f[j], f[i]
}
func (f FirewallSet) Less(i, j int) bool {
if f[i].Priority != f[j].Priority {
return f[i].Priority < f[j].Priority
}
return len(f[i].Allowed) < len(f[j].Allowed)
}
type SSecurityGroup struct {
multicloud.SSecurityGroup
vpc *SVpc
ServiceAccount string
@@ -99,18 +83,20 @@ func (region *SRegion) GetFirewall(id string) (*SFirewall, error) {
return firewall, region.Get(id, firewall)
}
func (firewall *SFirewall) _toRules(action secrules.TSecurityRuleAction) ([]secrules.SecurityRule, error) {
rules := []secrules.SecurityRule{}
func (firewall *SFirewall) _toRules(action secrules.TSecurityRuleAction) ([]cloudprovider.SecurityRule, error) {
rules := []cloudprovider.SecurityRule{}
list := firewall.Allowed
if action == secrules.SecurityRuleDeny {
list = firewall.Denied
}
for _, allow := range list {
rule := secrules.SecurityRule{
Action: action,
Direction: secrules.DIR_IN,
Description: firewall.SelfLink,
Priority: firewall.Priority,
rule := cloudprovider.SecurityRule{
ExternalId: firewall.SelfLink,
SecurityRule: secrules.SecurityRule{
Action: action,
Direction: secrules.DIR_IN,
Priority: firewall.Priority,
},
}
if firewall.Direction == "EGRESS" {
rule.Direction = secrules.DIR_OUT
@@ -139,6 +125,7 @@ func (firewall *SFirewall) _toRules(action secrules.TSecurityRuleAction) ([]secr
ports := []int{}
for _, port := range allow.Ports {
if strings.Index(port, "-") > 0 {
port = strings.Replace(port, "0-", "1-", 1)
err := rule.ParsePorts(port)
if err != nil {
return nil, errors.Wrapf(err, "Parse port %s", port)
@@ -169,8 +156,8 @@ func (firewall *SFirewall) _toRules(action secrules.TSecurityRuleAction) ([]secr
return rules, nil
}
func (firewall *SFirewall) toRules() ([]secrules.SecurityRule, error) {
rules := []secrules.SecurityRule{}
func (firewall *SFirewall) toRules() ([]cloudprovider.SecurityRule, error) {
rules := []cloudprovider.SecurityRule{}
_rules, err := firewall._toRules(secrules.SecurityRuleAllow)
if err != nil {
return nil, err
@@ -234,7 +221,7 @@ func (secgroup *SSecurityGroup) Delete() error {
return errors.Wrap(err, "GetRules")
}
for _, rule := range rules {
err = secgroup.vpc.region.DeleteSecgroupRule(rule.Description, rule)
err = secgroup.vpc.region.DeleteSecgroupRule(rule)
if err != nil {
return errors.Wrapf(err, "DeleteSecgroupRule(%s)", rule.Description)
}
@@ -250,7 +237,7 @@ func (secgroup *SSecurityGroup) GetVpcId() string {
return secgroup.vpc.GetGlobalId()
}
func (self *SSecurityGroup) GetRules() ([]secrules.SecurityRule, error) {
func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) {
_firewalls, err := self.vpc.region.GetFirewalls(self.vpc.globalnetwork.SelfLink, 0, "")
if err != nil {
return nil, err
@@ -267,14 +254,8 @@ func (self *SSecurityGroup) GetRules() ([]secrules.SecurityRule, error) {
}
}
}
sort.Sort(FirewallSet(firewalls))
rules := []secrules.SecurityRule{}
priority := 100
rules := []cloudprovider.SecurityRule{}
for _, firewall := range firewalls {
firewall.Priority = priority
if priority > 2 {
priority--
}
_rules, err := firewall.toRules()
if err != nil {
return nil, err
@@ -284,8 +265,8 @@ func (self *SSecurityGroup) GetRules() ([]secrules.SecurityRule, error) {
return rules, nil
}
func (region *SRegion) DeleteSecgroupRule(ruleId string, rule secrules.SecurityRule) error {
firwall, err := region.GetFirewall(ruleId)
func (region *SRegion) DeleteSecgroupRule(rule cloudprovider.SecurityRule) error {
firwall, err := region.GetFirewall(rule.ExternalId)
if err != nil {
return errors.Wrap(err, "region.GetFirewall")
}
@@ -320,61 +301,17 @@ func (region *SRegion) DeleteSecgroupRule(ruleId string, rule secrules.SecurityR
return region.Delete(firwall.SelfLink)
}
func (secgroup *SSecurityGroup) SyncRules(rules []secrules.SecurityRule) error {
if len(rules) == 0 {
rules = append(rules, *secrules.MustParseSecurityRule("in:deny any"))
}
currentRule, err := secgroup.GetRules()
if err != nil {
return errors.Wrap(err, "secgroup.GetRules")
}
sort.Sort(secrules.SecurityRuleSet(rules))
region := secgroup.vpc.region
deleteRules := map[string]secrules.SecurityRule{}
addRules := []secrules.SecurityRule{}
i, j := 0, 0
for i < len(rules) || j < len(currentRule) {
if i < len(rules) && j < len(currentRule) {
currentRuleStr := currentRule[j].String()
ruleStr := rules[i].String()
cmp := strings.Compare(currentRuleStr, ruleStr)
if cmp == 0 {
i += 1
j += 1
} else if cmp > 0 {
// delete rule
deleteRules[currentRule[j].Description] = currentRule[j]
j += 1
} else {
rules[i].Priority = 101 - rules[i].Priority
addRules = append(addRules, rules[i])
i += 1
}
} else if i >= len(rules) {
// delete rule
deleteRules[currentRule[j].Description] = currentRule[j]
j += 1
} else if j >= len(currentRule) {
// add rule
rules[i].Priority = 101 - rules[i].Priority
addRules = append(addRules, rules[i])
err = region.CreateSecurityGroupRule(rules[i], secgroup.vpc.globalnetwork.SelfLink, secgroup.Tag, secgroup.ServiceAccount)
if err != nil {
return errors.Wrapf(err, "region.CreateSecurityGroupRule(%s)", rules[i].String())
}
i += 1
func (secgroup *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error {
for _, r := range append(inDels, outDels...) {
err := secgroup.vpc.region.DeleteSecgroupRule(r)
if err != nil {
return errors.Wrap(err, "DeleteSecgroupRule")
}
}
for id, rule := range deleteRules {
err = region.DeleteSecgroupRule(id, rule)
for _, r := range append(inAdds, outAdds...) {
err := secgroup.vpc.region.CreateSecurityGroupRule(r, secgroup.vpc.globalnetwork.SelfLink, secgroup.Tag, secgroup.ServiceAccount)
if err != nil {
return errors.Wrapf(err, "DeleteSecgroupRule(%s)", id)
}
}
for _, rule := range addRules {
err = region.CreateSecurityGroupRule(rule, secgroup.vpc.globalnetwork.SelfLink, secgroup.Tag, secgroup.ServiceAccount)
if err != nil {
return errors.Wrapf(err, "CreateSecurityGroupRule(%s)", rule.String())
return errors.Wrapf(err, "CreateSecurityGroupRule(%s)", r.String())
}
}
return nil
@@ -418,7 +355,7 @@ func (region *SRegion) GetISecurityGroupByName(vpcId string, name string) (cloud
return nil, cloudprovider.ErrNotFound
}
func (region *SRegion) CreateSecurityGroupRule(rule secrules.SecurityRule, vpcId string, tag string, serviceAccount string) error {
func (region *SRegion) CreateSecurityGroupRule(rule cloudprovider.SecurityRule, vpcId string, tag string, serviceAccount string) error {
name := fmt.Sprintf("%s-%d", rule.String(), rule.Priority)
if len(tag) > 0 {
name = fmt.Sprintf("for-tag-%s-%s", tag, name)
@@ -445,7 +382,7 @@ func (region *SRegion) CreateSecurityGroupRule(rule secrules.SecurityRule, vpcId
body["sourceRanges"] = []string{rule.IPNet.String()}
}
protocol := string(rule.Protocol)
protocol := strings.ToLower(rule.Protocol)
if protocol == secrules.PROTO_ANY {
protocol = "all"
}
+1 -87
View File
@@ -16,7 +16,6 @@ package huawei
import (
"fmt"
"sort"
"strings"
"time"
@@ -536,29 +535,6 @@ func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreat
return self.CreateSecurityGroup(conf.VpcId, conf.Name, conf.Desc)
}
func (self *SRegion) SyncSecurityGroup(secgroupId string, vpcId string, name string, desc string, rules []secrules.SecurityRule) (string, error) {
if len(secgroupId) > 0 {
_, err := self.GetSecurityGroupDetails(secgroupId)
if err == cloudprovider.ErrNotFound {
secgroupId = ""
} else if err != nil {
return "", errors.Wrapf(err, "self.GetSecurityGroupDetails(%s)", secgroupId)
}
}
if len(secgroupId) == 0 {
secgroup, err := self.CreateSecurityGroup(vpcId, name, desc)
if err != nil {
return "", errors.Wrap(err, "self.CreateSecurityGroup")
}
secgroupId = secgroup.GetId()
}
// 华为云默认deny。不需要显式指定
rules = SecurityRuleSetToAllowSet(rules)
return secgroupId, self.syncSecgroupRules(secgroupId, rules)
}
// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090608.html
func (self *SRegion) CreateIVpc(name string, desc string, cidr string) (cloudprovider.ICloudVpc, error) {
params := jsonutils.NewDict()
@@ -734,68 +710,6 @@ func (self *SRegion) CreateSecurityGroup(vpcId string, name string, desc string)
return &secgroup, err
}
func (self *SRegion) syncSecgroupRules(secgroupId string, srules []secrules.SecurityRule) error {
var DeleteRules []secrules.SecurityRule
var AddRules []secrules.SecurityRule
rules := SecurityRuleSetToAllowSet(srules)
if secgroup, err := self.GetSecurityGroupDetails(secgroupId); err != nil {
return errors.Wrapf(err, "syncSecgroupRules.GetSecurityGroupDetails(%s)", secgroupId)
} else {
remoteRules, err := secgroup.GetRulesWithExtId()
if err != nil {
return errors.Wrap(err, "secgroup.GetRulesWithExtId")
}
sort.Sort(secrules.SecurityRuleSet(rules))
sort.Sort(secrules.SecurityRuleSet(remoteRules))
i, j := 0, 0
for i < len(rules) || j < len(remoteRules) {
if i < len(rules) && j < len(remoteRules) {
permissionStr := remoteRules[j].String()
ruleStr := rules[i].String()
cmp := strings.Compare(permissionStr, ruleStr)
if cmp == 0 {
// DeleteRules = append(DeleteRules, remoteRules[j])
// AddRules = append(AddRules, rules[i])
i += 1
j += 1
} else if cmp > 0 {
DeleteRules = append(DeleteRules, remoteRules[j])
j += 1
} else {
AddRules = append(AddRules, rules[i])
i += 1
}
} else if i >= len(rules) {
DeleteRules = append(DeleteRules, remoteRules[j])
j += 1
} else if j >= len(remoteRules) {
AddRules = append(AddRules, rules[i])
i += 1
}
}
}
for _, r := range DeleteRules {
// r.Description 实际存储的是ruleId
if err := self.delSecurityGroupRule(r.Description); err != nil {
log.Errorf("delSecurityGroupRule %v error: %s", r, err.Error())
return err
}
}
for _, r := range AddRules {
if err := self.addSecurityGroupRules(secgroupId, &r); err != nil {
log.Errorf("addSecurityGroupRule %v error: %s", r, err.Error())
return err
}
}
return nil
}
// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0087467071.html
func (self *SRegion) delSecurityGroupRule(secGrpRuleId string) error {
return DoDelete(self.ecsClient.SecurityGroupRules.Delete, secGrpRuleId, nil, nil)
@@ -803,7 +717,7 @@ func (self *SRegion) delSecurityGroupRule(secGrpRuleId string) error {
// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0087451723.html
// icmp port对应关系:https://support.huaweicloud.com/api-vpc/zh-cn_topic_0024109590.html
func (self *SRegion) addSecurityGroupRules(secGrpId string, rule *secrules.SecurityRule) error {
func (self *SRegion) addSecurityGroupRules(secGrpId string, rule cloudprovider.SecurityRule) error {
direction := ""
if rule.Direction == secrules.SecurityRuleIngress {
direction = "ingress"
+37 -87
View File
@@ -27,12 +27,14 @@ https://support.huaweicloud.com/usermanual-vpc/zh-cn_topic_0073379079.html
import (
"net"
"sort"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/secrules"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
)
type SecurityGroupRule struct {
@@ -60,6 +62,7 @@ type SecurityGroupRuleDetail struct {
// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090615.html
type SSecurityGroup struct {
multicloud.SSecurityGroup
region *SRegion
ID string `json:"id"`
@@ -85,46 +88,6 @@ func compatibleSecurityGroupRule(r SecurityGroupRule) bool {
return true
}
// 将安全组规则全部转换为等价的allow规则
func SecurityRuleSetToAllowSet(srs secrules.SecurityRuleSet) secrules.SecurityRuleSet {
inRuleSet := secrules.SecurityRuleSet{}
outRuleSet := secrules.SecurityRuleSet{}
for _, rule := range srs {
if rule.Direction == secrules.SecurityRuleIngress {
inRuleSet = append(inRuleSet, rule)
}
if rule.Direction == secrules.SecurityRuleEgress {
outRuleSet = append(outRuleSet, rule)
}
}
sort.Sort(inRuleSet)
sort.Sort(outRuleSet)
inRuleSet = inRuleSet.AllowList()
// out方向空规则默认全部放行
if outRuleSet.Len() == 0 {
_, ipNet, _ := net.ParseCIDR("0.0.0.0/0")
outRuleSet = append(outRuleSet, secrules.SecurityRule{
Priority: 0,
Action: secrules.SecurityRuleAllow,
IPNet: ipNet,
Protocol: secrules.PROTO_ANY,
Direction: secrules.SecurityRuleEgress,
PortStart: -1,
PortEnd: -1,
})
}
outRuleSet = outRuleSet.AllowList()
ret := secrules.SecurityRuleSet{}
ret = append(ret, inRuleSet...)
ret = append(ret, outRuleSet...)
return ret
}
func (self *SSecurityGroup) GetId() string {
return self.ID
}
@@ -173,14 +136,14 @@ func (self *SSecurityGroup) GetDescription() string {
}
// todo: 这里需要优化查询太多了
func (self *SSecurityGroup) GetRules() ([]secrules.SecurityRule, error) {
rules := make([]secrules.SecurityRule, 0)
func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) {
rules := make([]cloudprovider.SecurityRule, 0)
for _, r := range self.SecurityGroupRules {
if !compatibleSecurityGroupRule(r) {
continue
}
rule, err := self.GetSecurityRule(r.ID, false)
rule, err := self.GetSecurityRule(r.ID)
if err != nil {
return rules, err
}
@@ -191,30 +154,11 @@ func (self *SSecurityGroup) GetRules() ([]secrules.SecurityRule, error) {
return rules, nil
}
func (self *SSecurityGroup) GetRulesWithExtId() ([]secrules.SecurityRule, error) {
rules := make([]secrules.SecurityRule, 0)
for _, r := range self.SecurityGroupRules {
if !compatibleSecurityGroupRule(r) {
continue
}
rule, err := self.GetSecurityRule(r.ID, true)
if err != nil {
return rules, err
}
rules = append(rules, rule)
}
return rules, nil
}
// withRuleId.
func (self *SSecurityGroup) GetSecurityRule(ruleId string, withRuleId bool) (secrules.SecurityRule, error) {
func (self *SSecurityGroup) GetSecurityRule(ruleId string) (cloudprovider.SecurityRule, error) {
remoteRule := SecurityGroupRuleDetail{}
err := DoGet(self.region.ecsClient.SecurityGroupRules.Get, ruleId, nil, &remoteRule)
if err != nil {
return secrules.SecurityRule{}, err
return cloudprovider.SecurityRule{}, err
}
var direction secrules.TSecurityRuleDirection
@@ -247,27 +191,22 @@ func (self *SSecurityGroup) GetSecurityRule(ruleId string, withRuleId bool) (sec
}
if err != nil {
return secrules.SecurityRule{}, err
return cloudprovider.SecurityRule{}, err
}
// withRuleId.将ruleId附加到description字段。该hook有特殊目的,仅在同步安全组时使用。
desc := ""
if withRuleId {
desc = ruleId
} else {
desc = remoteRule.Description
}
rule := secrules.SecurityRule{
Priority: 1,
Action: secrules.SecurityRuleAllow,
IPNet: ipNet,
Protocol: protocol,
Direction: direction,
PortStart: portStart,
PortEnd: portEnd,
Ports: nil,
Description: desc,
rule := cloudprovider.SecurityRule{
ExternalId: ruleId,
SecurityRule: secrules.SecurityRule{
Priority: 1,
Action: secrules.SecurityRuleAllow,
IPNet: ipNet,
Protocol: protocol,
Direction: direction,
PortStart: portStart,
PortEnd: portEnd,
Ports: nil,
Description: remoteRule.Description,
},
}
err = rule.ValidateRule()
@@ -322,7 +261,18 @@ func (self *SSecurityGroup) Delete() error {
return self.region.DeleteSecurityGroup(self.ID)
}
func (self *SSecurityGroup) SyncRules(rules []secrules.SecurityRule) error {
rules = SecurityRuleSetToAllowSet(rules)
return self.region.syncSecgroupRules(self.ID, rules)
func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error {
for _, r := range append(inDels, outDels...) {
err := self.region.delSecurityGroupRule(r.ExternalId)
if err != nil {
return errors.Wrapf(err, "delSecurityGroupRule(%s %s)", r.ExternalId, r.String())
}
}
for _, r := range append(inAdds, outAdds...) {
err := self.region.addSecurityGroupRules(self.ID, r)
if err != nil {
return errors.Wrapf(err, "addSecurityGroupRule(%d %s)", r.Priority, r.String())
}
}
return nil
}
+46 -188
View File
@@ -17,8 +17,6 @@ package openstack
import (
"fmt"
"net"
"sort"
"strings"
"time"
"yunion.io/x/jsonutils"
@@ -28,6 +26,8 @@ import (
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/multicloud"
"yunion.io/x/onecloud/pkg/util/httputils"
)
@@ -55,6 +55,7 @@ type SSecurityGroupRule struct {
}
type SSecurityGroup struct {
multicloud.SSecurityGroup
region *SRegion
Description string
@@ -69,20 +70,6 @@ type SSecurityGroup struct {
TenantID string
}
type SecurigyGroupRuleSet []SSecurityGroupRule
func (v SecurigyGroupRuleSet) Len() int {
return len(v)
}
func (v SecurigyGroupRuleSet) Swap(i, j int) {
v[i], v[j] = v[j], v[i]
}
func (v SecurigyGroupRuleSet) Less(i, j int) bool {
return strings.Compare(v[i].String(), v[j].String()) <= 0
}
func (region *SRegion) GetSecurityGroup(secgroupId string) (*SSecurityGroup, error) {
_, resp, err := region.Get("network", "/v2.0/security-groups/"+secgroupId, "", nil)
if err != nil {
@@ -158,26 +145,19 @@ func (secgroup *SSecurityGroup) GetName() string {
return secgroup.ID
}
func (secgroup *SSecurityGroupRule) String() string {
rules := secgroup.toRules()
result := []string{}
for _, rule := range rules {
result = append(result, rule.String())
}
return strings.Join(result, ";")
}
func (secgrouprule *SSecurityGroupRule) toRules() []secrules.SecurityRule {
rules := []secrules.SecurityRule{}
func (secgrouprule *SSecurityGroupRule) toRules() ([]cloudprovider.SecurityRule, error) {
rules := []cloudprovider.SecurityRule{}
// 暂时忽略IPv6安全组规则,忽略远端也是安全组的规则
if secgrouprule.Ethertype != "IPv4" || len(secgrouprule.RemoteGroupID) > 0 {
return rules
return rules, fmt.Errorf("ethertype: %s remoteGroupId: %s", secgrouprule.Ethertype, secgrouprule.RemoteGroupID)
}
rule := secrules.SecurityRule{
Direction: secrules.DIR_IN,
Action: secrules.SecurityRuleAllow,
Description: secgrouprule.Description,
Priority: 1,
rule := cloudprovider.SecurityRule{
ExternalId: secgrouprule.ID,
SecurityRule: secrules.SecurityRule{
Direction: secrules.DIR_IN,
Action: secrules.SecurityRuleAllow,
Description: secgrouprule.Description,
},
}
if utils.IsInStringArray(secgrouprule.Protocol, []string{"any", "-1", ""}) {
rule.Protocol = secrules.PROTO_ANY
@@ -188,7 +168,7 @@ func (secgrouprule *SSecurityGroupRule) toRules() []secrules.SecurityRule {
} else if utils.IsInStringArray(secgrouprule.Protocol, []string{"1", "icmp"}) {
rule.Protocol = secrules.PROTO_ICMP
} else {
return rules
return rules, errors.Wrap(httperrors.ErrUnsupportedProtocol, secgrouprule.Protocol)
}
if secgrouprule.Direction == "egress" {
rule.Direction = secrules.DIR_OUT
@@ -198,7 +178,7 @@ func (secgrouprule *SSecurityGroupRule) toRules() []secrules.SecurityRule {
}
_, ipnet, err := net.ParseCIDR(secgrouprule.RemoteIpPrefix)
if err != nil {
return rules
return rules, errors.Wrapf(err, "net.ParseCIDR(%s)", secgrouprule.RemoteIpPrefix)
}
rule.IPNet = ipnet
if secgrouprule.PortRangeMax > 0 && secgrouprule.PortRangeMin > 0 {
@@ -209,28 +189,23 @@ func (secgrouprule *SSecurityGroupRule) toRules() []secrules.SecurityRule {
rule.PortEnd = secgrouprule.PortRangeMax
}
}
if err := rule.ValidateRule(); err != nil {
return rules
err = rule.ValidateRule()
if err != nil && err != secrules.ErrInvalidPriority {
return rules, errors.Wrap(err, "rule.ValidateRule")
}
return []secrules.SecurityRule{rule}
return []cloudprovider.SecurityRule{rule}, nil
}
func (secgroup *SSecurityGroup) GetRules() ([]secrules.SecurityRule, error) {
rules := []secrules.SecurityRule{}
priority := 100
func (secgroup *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) {
rules := []cloudprovider.SecurityRule{}
for _, rule := range secgroup.SecurityGroupRules {
if priority < 2 {
priority = 2
}
subRules := rule.toRules()
for _, subRule := range subRules {
subRule.Priority = priority
rules = append(rules, subRule)
subRules, err := rule.toRules()
if err != nil {
log.Errorf("failed to convert rule %s for secgroup %s(%s) error: %v", rule.ID, secgroup.Name, secgroup.ID, err)
continue
}
rules = append(rules, subRules...)
}
defaultDenyRule := secrules.MustParseSecurityRule("out:deny any")
defaultDenyRule.Priority = 1
rules = append(rules, *defaultDenyRule)
return rules, nil
}
@@ -250,145 +225,12 @@ func (secgroup *SSecurityGroup) Refresh() error {
return jsonutils.Update(secgroup, new)
}
func (region *SRegion) SyncSecurityGroup(secgroupId string, vpcId string, name string, desc string, rules []secrules.SecurityRule) (string, error) {
if len(secgroupId) > 0 {
_, err := region.GetSecurityGroup(secgroupId)
if err != nil {
if err != cloudprovider.ErrNotFound {
return "", err
}
secgroupId = ""
}
}
if len(secgroupId) == 0 {
secgroups, err := region.GetSecurityGroups("")
if err != nil {
// 若返回 cloudprovider.ErrNotFound, 表明不支持安全组或者未安装安全组相关组件
if err == cloudprovider.ErrNotFound {
return SECGROUP_NOT_SUPPORT, nil
}
log.Errorf("failed to get secgroups: %v", err)
return "", err
}
secgroupNames := []string{}
for _, secgroup := range secgroups {
secgroupNames = append(secgroupNames, strings.ToLower(secgroup.Name))
}
uniqName := strings.ToLower(name)
if utils.IsInStringArray(uniqName, secgroupNames) {
for i := 0; i < 20; i++ {
uniqName = fmt.Sprintf("%s-%d", strings.ToLower(name), i)
if !utils.IsInStringArray(uniqName, secgroupNames) {
break
}
}
}
log.Errorf("create secgroup %s", uniqName)
secgroup, err := region.CreateSecurityGroup(uniqName, desc)
if err != nil {
return "", err
}
secgroupId = secgroup.ID
}
return region.syncSecgroupRules(secgroupId, rules)
}
func (region *SRegion) syncSecgroupRules(secgroupId string, rules []secrules.SecurityRule) (string, error) {
secgroup, err := region.GetSecurityGroup(secgroupId)
if err != nil {
return "", err
}
// OpenStack仅支持allow规则添加,需要将规则全转换为allow rules
inRules, outRules := secrules.SecurityRuleSet{}, secrules.SecurityRuleSet{}
for i := 0; i < len(rules); i++ {
if rules[i].Direction == secrules.DIR_IN {
inRules = append(inRules, rules[i])
} else {
outRules = append(outRules, rules[i])
}
}
// OpenStack Out方向默认是禁止所有流量,需要给本地安全组规则加一条优先级最低的allow any规则,和OpenStack规则语义保持一致
defaultAllow := secrules.MustParseSecurityRule("out:allow any")
defaultAllow.Priority = 0
outRules = append(outRules, *defaultAllow)
rules = inRules.AllowList()
rules = append(rules, outRules.AllowList()...)
sort.Sort(secrules.SecurityRuleSet(rules))
sort.Sort(SecurigyGroupRuleSet(secgroup.SecurityGroupRules))
delSecgroupRuleIds := []string{}
addSecgroupRules := []secrules.SecurityRule{}
addSecgroupRuleStrings := []string{}
i, j := 0, 0
for i < len(rules) || j < len(secgroup.SecurityGroupRules) {
if i < len(rules) && j < len(secgroup.SecurityGroupRules) {
secruleStr := secgroup.SecurityGroupRules[j].String()
ruleStr := rules[i].String()
cmp := strings.Compare(secruleStr, ruleStr)
if cmp == 0 {
i++
j++
} else if cmp > 0 {
delSecgroupRuleIds = append(delSecgroupRuleIds, secgroup.SecurityGroupRules[j].ID)
j++
} else {
if !utils.IsInStringArray(ruleStr, addSecgroupRuleStrings) {
addSecgroupRules = append(addSecgroupRules, rules[i])
addSecgroupRuleStrings = append(addSecgroupRuleStrings, ruleStr)
}
i++
}
} else if i >= len(rules) {
delSecgroupRuleIds = append(delSecgroupRuleIds, secgroup.SecurityGroupRules[j].ID)
j++
} else if j >= len(secgroup.SecurityGroupRules) {
ruleStr := rules[i].String()
if !utils.IsInStringArray(ruleStr, addSecgroupRuleStrings) {
addSecgroupRules = append(addSecgroupRules, rules[i])
addSecgroupRuleStrings = append(addSecgroupRuleStrings, ruleStr)
}
i++
}
}
for _, ruleId := range delSecgroupRuleIds {
if err := region.delSecurityGroupRule(ruleId); err != nil {
log.Errorf("delSecurityGroupRule error %v", err)
return "", err
}
}
for i := 0; i < len(addSecgroupRules); i++ {
if err := region.addSecurityGroupRules(secgroupId, &addSecgroupRules[i]); err != nil {
if jsonError, ok := err.(*httputils.JSONClientError); ok {
if jsonError.Class == "SecurityGroupRuleExists" {
continue
}
}
log.Errorf("addSecurityGroupRule error %v", rules[i])
return "", err
}
}
return secgroupId, nil
}
func (region *SRegion) delSecurityGroupRule(ruleId string) error {
_, err := region.Delete("network", "/v2.0/security-group-rules/"+ruleId, "")
return err
}
func (region *SRegion) addSecurityGroupRules(secgroupId string, rule *secrules.SecurityRule) error {
if rule.Action == secrules.SecurityRuleDeny {
// openstack 不支持deny规则
return nil
}
func (region *SRegion) addSecurityGroupRules(secgroupId string, rule cloudprovider.SecurityRule) error {
direction := "ingress"
if rule.Direction == secrules.SecurityRuleEgress {
direction = "egress"
@@ -457,7 +299,23 @@ func (secgroup *SSecurityGroup) GetProjectId() string {
return secgroup.TenantID
}
func (secgroup *SSecurityGroup) SyncRules(rules []secrules.SecurityRule) error {
_, err := secgroup.region.syncSecgroupRules(secgroup.ID, rules)
return err
func (secgroup *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error {
for _, r := range append(inDels, outDels...) {
err := secgroup.region.delSecurityGroupRule(r.ExternalId)
if err != nil {
return errors.Wrapf(err, "delSecurityGroupRule(%s)", r.ExternalId)
}
}
for _, r := range append(inAdds, outAdds...) {
err := secgroup.region.addSecurityGroupRules(secgroup.ID, r)
if err != nil {
if jsonError, ok := err.(*httputils.JSONClientError); ok {
if jsonError.Class == "SecurityGroupRuleExists" {
continue
}
}
return errors.Wrapf(err, "addSecgroupRules(%s)", r.String())
}
}
return nil
}
@@ -33,7 +33,8 @@ func init() {
})
type SecurityGroupShowOptions struct {
ID string `help:"ID of security group"`
ID string `help:"ID of security group"`
ShowRules bool `help:"Show rules"`
}
shellutils.R(&SecurityGroupShowOptions{}, "security-group-show", "Show security group", func(cli *openstack.SRegion, args *SecurityGroupShowOptions) error {
secgroup, err := cli.GetSecurityGroup(args.ID)
@@ -41,6 +42,15 @@ func init() {
return err
}
printObject(secgroup)
if args.ShowRules {
rules, err := secgroup.GetRules()
if err != nil {
return err
}
for _, r := range rules {
printObject(r)
}
}
return nil
})
+86 -115
View File
@@ -17,17 +17,18 @@ package qcloud
import (
"fmt"
"net"
"sort"
"strconv"
"strings"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/secrules"
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
)
type SecurityGroupPolicy struct {
@@ -61,6 +62,7 @@ type SecurityGroupPolicySet struct {
}
type SSecurityGroup struct {
multicloud.SSecurityGroup
region *SRegion
SecurityGroupId string // 安全组实例ID,例如:sg-ohuuioma。
SecurityGroupName string // 安全组名称,可任意命名,但不得超过60个字符。
@@ -71,25 +73,6 @@ type SSecurityGroup struct {
SecurityGroupPolicySet SecurityGroupPolicySet
}
type SecurityGroupRuleSet []SecurityGroupPolicy
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].PolicyIndex < v[j].PolicyIndex {
return true
} else if v[i].PolicyIndex == v[j].PolicyIndex {
return strings.Compare(v[i].String(), v[j].String()) <= 0
}
return false
}
func (self *SRegion) GetSecurityGroups(vpcId string, name string, offset int, limit int) ([]SSecurityGroup, int, error) {
if limit > 50 || limit <= 0 {
limit = 50
@@ -168,15 +151,19 @@ func parseCIDR(cidr string) (*net.IPNet, error) {
return &net.IPNet{IP: ip, Mask: net.CIDRMask(32, 32)}, nil
}
func (self *SecurityGroupPolicy) toRules() []secrules.SecurityRule {
result := []secrules.SecurityRule{}
rule := secrules.SecurityRule{
Action: secrules.SecurityRuleAllow,
Protocol: secrules.PROTO_ANY,
Direction: secrules.TSecurityRuleDirection(self.direction),
Ports: []int{},
PortStart: -1,
PortEnd: -1,
func (self *SecurityGroupPolicy) toRules() []cloudprovider.SecurityRule {
result := []cloudprovider.SecurityRule{}
rule := cloudprovider.SecurityRule{
ExternalId: fmt.Sprintf("%d", self.PolicyIndex),
SecurityRule: secrules.SecurityRule{
Action: secrules.SecurityRuleAllow,
Protocol: secrules.PROTO_ANY,
Direction: secrules.TSecurityRuleDirection(self.direction),
Priority: self.PolicyIndex,
Ports: []int{},
PortStart: -1,
PortEnd: -1,
},
}
if len(self.SecurityGroupId) != 0 {
//安全组关联安全组的规则忽略
@@ -251,8 +238,8 @@ func (self *SecurityGroupPolicy) toRules() []secrules.SecurityRule {
return result
}
func (self *SecurityGroupPolicy) getAddressRules(rule secrules.SecurityRule, addressId string) ([]secrules.SecurityRule, error) {
result := []secrules.SecurityRule{}
func (self *SecurityGroupPolicy) getAddressRules(rule cloudprovider.SecurityRule, addressId string) ([]cloudprovider.SecurityRule, error) {
result := []cloudprovider.SecurityRule{}
address, total, err := self.region.AddressList(addressId, "", 0, 1)
if err != nil {
log.Errorf("Get AddressList %s failed %v", self.AddressTemplate.AddressId, err)
@@ -272,7 +259,7 @@ func (self *SecurityGroupPolicy) getAddressRules(rule secrules.SecurityRule, add
return result, nil
}
func (self *SSecurityGroup) GetRules() ([]secrules.SecurityRule, error) {
func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) {
secgroup, err := self.region.GetSecurityGroupDetails(self.SecurityGroupId)
if err != nil {
return nil, err
@@ -289,26 +276,11 @@ func (self *SSecurityGroup) GetRules() ([]secrules.SecurityRule, error) {
for i := 0; i < len(originRules); i++ {
originRules[i].region = self.region
}
sort.Sort(SecurityGroupRuleSet(originRules))
rules := []secrules.SecurityRule{}
priority := 100
rules := []cloudprovider.SecurityRule{}
for _, rule := range originRules {
subRules := rule.toRules()
for i := 0; i < len(subRules); i++ {
subRules[i].Priority = priority
}
if len(subRules) > 0 {
priority--
}
rules = append(rules, subRules...)
}
// 腾讯云若出方向规则默认是拒绝所有流量
defaultDenyRule, err := secrules.ParseSecurityRule("out:deny any")
if err != nil {
return nil, err
}
defaultDenyRule.Priority = 1
rules = append(rules, *defaultDenyRule)
return rules, nil
}
@@ -321,36 +293,61 @@ func (self *SSecurityGroup) IsEmulated() bool {
}
func (self *SSecurityGroup) Refresh() error {
if new, err := self.region.GetSecurityGroupDetails(self.SecurityGroupId); err != nil {
group, err := self.region.GetSecurityGroupDetails(self.SecurityGroupId)
if err != nil {
return err
} else {
return jsonutils.Update(self, new)
}
return jsonutils.Update(self, group)
}
func (self *SSecurityGroup) SyncRules(rules []secrules.SecurityRule) error {
_, err := self.region.syncSecgroupRules(self.SecurityGroupId, rules)
return err
func (self *SSecurityGroup) deleteRules(rules []cloudprovider.SecurityRule, direction string) error {
ids := []string{}
for _, r := range rules {
ids = append(ids, r.ExternalId)
}
if len(ids) > 0 {
err := self.region.DeleteRules(self.SecurityGroupId, direction, ids)
if err != nil {
return errors.Wrapf(err, "deleteRules(%s)", ids)
}
}
return nil
}
func (self *SRegion) SyncSecurityGroup(secgroupId string, vpcId string, name string, desc string, rules []secrules.SecurityRule) (string, error) {
if len(secgroupId) > 0 {
_, err := self.GetSecurityGroupDetails(secgroupId)
func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error {
rules := append(common, append(inAdds, outAdds...)...)
return self.region.syncSecgroupRules(self.SecurityGroupId, rules)
}
func (self *SRegion) syncSecgroupRules(secgroupid string, rules []cloudprovider.SecurityRule) error {
err := self.deleteAllRules(secgroupid)
if err != nil {
return errors.Wrap(err, "deleteAllRules")
}
egressIndex, ingressIndex := -1, -1
for _, rule := range rules {
policyIndex := 0
switch rule.Direction {
case secrules.DIR_IN:
ingressIndex++
policyIndex = ingressIndex
case secrules.DIR_OUT:
egressIndex++
policyIndex = egressIndex
default:
return fmt.Errorf("Unknown rule direction %v for secgroup %s", rule, secgroupid)
}
//为什么不一次创建完成?
//答: 因为如果只有入方向安全组规则,创建时会提示缺少出方向规则。
//为什么不分两次,一次创建入方向规则,一次创建出方向规则?
//答: 因为这样就不能设置优先级了,一次性创建的出或入方向的优先级必须一样。
err := self.AddRule(secgroupid, policyIndex, rule)
if err != nil {
if err != cloudprovider.ErrNotFound {
return "", err
}
secgroupId = ""
return errors.Wrap(err, "AddRule")
}
}
if len(secgroupId) == 0 {
secgroup, err := self.CreateSecurityGroup(name, desc)
if err != nil {
return "", err
}
secgroupId = secgroup.SecurityGroupId
}
return self.syncSecgroupRules(secgroupId, rules)
return nil
}
func (self *SRegion) deleteAllRules(secgroupid string) error {
@@ -359,7 +356,19 @@ func (self *SRegion) deleteAllRules(secgroupid string) error {
return err
}
func (self *SRegion) addRule(secgroupId string, policyIndex int, rule *secrules.SecurityRule) error {
func (self *SRegion) DeleteRules(secgroupId, direction string, ids []string) error {
if len(ids) == 0 {
return nil
}
params := map[string]string{"SecurityGroupId": secgroupId}
for idx, id := range ids {
params[fmt.Sprintf("SecurityGroupPolicySet.%s.%d.PolicyIndex", direction, idx)] = id
}
_, err := self.vpcRequest("DeleteSecurityGroupPolicies", params)
return err
}
func (self *SRegion) AddRule(secgroupId string, policyIndex int, rule cloudprovider.SecurityRule) error {
params := map[string]string{}
params["SecurityGroupId"] = secgroupId
direction := "Egress"
@@ -404,47 +413,6 @@ func (self *SRegion) addRule(secgroupId string, policyIndex int, rule *secrules.
return nil
}
func (self *SRegion) syncSecgroupRules(secgroupid string, rules []secrules.SecurityRule) (string, error) {
if err := self.deleteAllRules(secgroupid); err != nil {
return "", err
}
egressIndex, ingressIndex := -1, -1
for _, rule := range rules {
policyIndex := 0
switch rule.Direction {
case secrules.DIR_IN:
ingressIndex++
policyIndex = ingressIndex
case secrules.DIR_OUT:
egressIndex++
policyIndex = egressIndex
default:
return "", fmt.Errorf("Unknown rule direction %v for secgroup %s", rule, secgroupid)
}
//为什么不一次创建完成?
//答: 因为如果只有入方向安全组规则,创建时会提示缺少出方向规则。
//为什么不分两次,一次创建入方向规则,一次创建出方向规则?
//答: 因为这样就不能设置优先级了,一次性创建的出或入方向的优先级必须一样。
err := self.addRule(secgroupid, policyIndex, &rule)
if err != nil {
return "", err
}
}
// 需要在云上加上优先级最低的 allow any 规则, 和本地语义保持一致
egressIndex++
rule, err := secrules.ParseSecurityRule("out:allow any")
if err != nil {
return "", err
}
err = self.addRule(secgroupid, egressIndex, rule)
if err != nil {
return "", err
}
return secgroupid, nil
}
func (self *SRegion) GetSecurityGroupDetails(secGroupId string) (*SSecurityGroup, error) {
params := make(map[string]string)
params["Region"] = self.Region
@@ -558,10 +526,13 @@ func (self *SRegion) CreateSecurityGroup(name, description string) (*SSecurityGr
params["GroupDescription"] = "Customize Create"
}
secgroup := SSecurityGroup{region: self}
if body, err := self.vpcRequest("CreateSecurityGroup", params); err != nil {
return nil, err
} else if err := body.Unmarshal(&secgroup, "SecurityGroup"); err != nil {
return nil, err
body, err := self.vpcRequest("CreateSecurityGroup", params)
if err != nil {
return nil, errors.Wrap(err, "CreateSecurityGroup")
}
err = body.Unmarshal(&secgroup, "SecurityGroup")
if err != nil {
return nil, errors.Wrap(err, "body.Unmarshal")
}
return &secgroup, nil
}
@@ -15,6 +15,10 @@
package shell
import (
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/secrules"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud/qcloud"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
@@ -78,4 +82,29 @@ func init() {
printList(address, total, args.Offset, args.Limit, []string{})
return nil
})
type RuleDeleteOptions struct {
SECGROUP_ID string
DIRECTION string `choices:"Egress|Ingress"`
IDS []string
}
shellutils.R(&RuleDeleteOptions{}, "security-group-rule-delete", "Delete rules", func(cli *qcloud.SRegion, args *RuleDeleteOptions) error {
return cli.DeleteRules(args.SECGROUP_ID, args.DIRECTION, args.IDS)
})
type RuleCreateOptions struct {
SECGROUP_ID string
INDEX int
RULE string
}
shellutils.R(&RuleCreateOptions{}, "security-group-rule-create", "Create rule", func(cli *qcloud.SRegion, args *RuleCreateOptions) error {
rule, err := secrules.ParseSecurityRule(args.RULE)
if err != nil {
return errors.Wrap(err, "secrules.ParseRuleString")
}
return cli.AddRule(args.SECGROUP_ID, args.INDEX, cloudprovider.SecurityRule{SecurityRule: *rule})
})
}
+19
View File
@@ -0,0 +1,19 @@
// 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 multicloud
type SSecurityGroup struct {
SVirtualResourceBase
}
+18 -86
View File
@@ -16,8 +16,6 @@ package ucloud
import (
"fmt"
"net"
"sort"
"strings"
"yunion.io/x/jsonutils"
@@ -227,41 +225,6 @@ func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreat
// https://docs.ucloud.cn/api/unet-api/describe_firewall
// 绑定防火墙组的资源类型,默认为全部资源类型。枚举值为:"unatgw"NAT网关; "uhost",云主机; "upm",物理云主机; "hadoophost"hadoop节点; "fortresshost",堡垒机; "udhost",私有专区主机;"udockhost",容器;"dbaudit",数据库审计.
// todo: 是否需要过滤出仅绑定云主机的安全组?
func (self *SRegion) SyncSecurityGroup(secgroupId string, vpcId string, name string, desc string, rules []secrules.SecurityRule) (string, error) {
if len(secgroupId) > 0 {
_, err := self.GetSecurityGroupById(secgroupId)
if err == cloudprovider.ErrNotFound {
secgroupId = ""
} else if err != nil {
return "", err
}
}
if len(secgroupId) == 0 {
extID, err := self.CreateDefaultSecurityGroup(name, desc)
if err != nil {
return "", err
}
secgroupId = extID
}
// 如果是空规则,onecloud。默认拒绝所有流量
if len(rules) == 0 {
_, IpNet, _ := net.ParseCIDR("0.0.0.0/0")
rules = []secrules.SecurityRule{{
Priority: 0,
Action: secrules.SecurityRuleDeny,
IPNet: IpNet,
Protocol: secrules.PROTO_ANY,
Direction: secrules.SecurityRuleIngress,
PortStart: 0,
PortEnd: 0,
Ports: nil,
Description: "",
}}
}
return secgroupId, self.syncSecgroupRules(secgroupId, rules)
}
func (self *SRegion) CreateIVpc(name string, desc string, cidr string) (cloudprovider.ICloudVpc, error) {
params := NewUcloudParams()
@@ -561,49 +524,9 @@ func (self *SRegion) GetInstanceByID(instanceId string) (SInstance, error) {
}
}
func inList(s int, lst []int) bool {
for _, e := range lst {
if s == e {
return true
}
}
return false
}
func toUcloudSecurityRules(rules []secrules.SecurityRule) ([]string, error) {
ps := make([]int, 0)
for _, rule := range rules {
if rule.Direction == secrules.SecurityRuleIngress && !inList(rule.Priority, ps) {
ps = append(ps, rule.Priority)
}
}
if len(ps) > 3 {
return nil, fmt.Errorf("unable map local security group rule priority %v to LOW/MEDIUM/LOW", ps)
}
sort.Ints(ps)
pmap := map[int]string{}
for i, p := range ps {
pmap[p] = []string{"LOW", "MEDIUM", "HIGH"}[i]
}
ucloudRules := make([]string, 0)
for _, rule := range rules {
if rule.Direction == secrules.SecurityRuleIngress {
// GRE协议被忽略了
ucloudRules = append(ucloudRules, toUcloudSecRule(rule, pmap)...)
}
}
return ucloudRules, nil
}
// GRE协议被忽略了
func toUcloudSecRule(rule secrules.SecurityRule, pmap map[int]string) []string {
func toUcloudSecRule(rule cloudprovider.SecurityRule) []string {
net := rule.IPNet.String()
priority := pmap[rule.Priority]
action := "DROP"
if rule.Action == secrules.SecurityRuleAllow {
action = "ACCEPT"
@@ -612,18 +535,18 @@ func toUcloudSecRule(rule secrules.SecurityRule, pmap map[int]string) []string {
rules := make([]string, 0)
if len(rule.Ports) > 0 {
for _, port := range rule.Ports {
_rules := generatorRule(rule.Protocol, priority, net, action, port, port)
_rules := generatorRule(rule.Protocol, net, action, port, port, rule.Priority)
rules = append(rules, _rules...)
}
} else {
_rules := generatorRule(rule.Protocol, priority, net, action, rule.PortStart, rule.PortEnd)
_rules := generatorRule(rule.Protocol, net, action, rule.PortStart, rule.PortEnd, rule.Priority)
rules = append(rules, _rules...)
}
return rules
}
func generatorRule(protocol, priority, net, action string, startPort, endPort int) []string {
func generatorRule(protocol, net, action string, startPort, endPort, priority int) []string {
rules := make([]string, 0)
var ports string
@@ -634,8 +557,17 @@ func generatorRule(protocol, priority, net, action string, startPort, endPort in
} else {
ports = fmt.Sprintf("%d-%d", startPort, endPort)
}
prio := "LOW"
switch priority {
case 1:
prio = "LOW"
case 2:
prio = "MEDIUM"
case 3:
prio = "HIGH"
}
template := fmt.Sprintf("%s|%s|%s|%s|%s|", "%s", "%s", net, action, priority)
template := fmt.Sprintf("%s|%s|%s|%s|%s|", "%s", "%s", net, action, prio)
switch protocol {
case secrules.PROTO_ANY:
rules = append(rules, fmt.Sprintf(template, "TCP", ports))
@@ -653,10 +585,10 @@ func generatorRule(protocol, priority, net, action string, startPort, endPort in
}
// https://docs.ucloud.cn/api/unet-api/update_firewall
func (self *SRegion) syncSecgroupRules(secgroupId string, rules []secrules.SecurityRule) error {
_rules, err := toUcloudSecurityRules(rules)
if err != nil {
return err
func (self *SRegion) syncSecgroupRules(secgroupId string, rules []cloudprovider.SecurityRule) error {
_rules := []string{}
for _, r := range rules {
_rules = append(_rules, toUcloudSecRule(r)...)
}
params := NewUcloudParams()
+24 -49
View File
@@ -18,20 +18,22 @@ import (
"fmt"
"math/rand"
"net"
"strconv"
"strings"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/secrules"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
)
// https://docs.ucloud.cn/api/unet-api/describe_firewall
type SSecurityGroup struct {
multicloud.SSecurityGroup
region *SRegion
vpc *SVPC // 安全组在UCLOUD实际上与VPC是没有直接关联的。这里的vpc字段只是为了统一,仅仅是标记是哪个VPC在操作该安全组。
@@ -99,15 +101,15 @@ func (self *SSecurityGroup) GetDescription() string {
return self.Remark
}
func (self *SSecurityGroup) UcloudSecRuleToOnecloud(rule Rule) secrules.SecurityRule {
secrule := secrules.SecurityRule{}
func (self *SSecurityGroup) UcloudSecRuleToOnecloud(rule Rule) (cloudprovider.SecurityRule, error) {
secrule := cloudprovider.SecurityRule{}
switch rule.Priority {
case "HIGH":
secrule.Priority = 90
secrule.Priority = 3
case "MEDIUM":
secrule.Priority = 60
secrule.Priority = 2
case "LOW":
secrule.Priority = 30
secrule.Priority = 1
default:
secrule.Priority = 1
}
@@ -123,46 +125,30 @@ func (self *SSecurityGroup) UcloudSecRuleToOnecloud(rule Rule) secrules.Security
_, ipNet, err := net.ParseCIDR(rule.SrcIP)
if err != nil {
log.Errorln(err)
return secrule, errors.Wrapf(err, "net.ParseCIDR(%s)", rule.SrcIP)
}
secrule.IPNet = ipNet
secrule.Protocol = strings.ToLower(rule.ProtocolType)
secrule.Direction = secrules.SecurityRuleIngress
if rule.DstPort == "" {
secrule.PortStart = -1
secrule.PortEnd = -1
} else if strings.Contains(rule.DstPort, "-") {
segs := strings.Split(rule.DstPort, "-")
s, err := strconv.Atoi(segs[0])
if err != nil {
log.Errorln(err)
}
e, err := strconv.Atoi(segs[1])
if err != nil {
log.Errorln(err)
}
secrule.PortStart = s
secrule.PortEnd = e
} else {
port, err := strconv.Atoi(rule.DstPort)
if err != nil {
log.Errorln(err)
}
secrule.PortStart = port
secrule.PortEnd = port
err = secrule.ParsePorts(rule.DstPort)
if err != nil {
return secrule, errors.Wrapf(err, "ParsePorts(%s)", rule.DstPort)
}
return secrule
return secrule, nil
}
// https://docs.ucloud.cn/network/firewall/firewall
// 只有入方向规则
func (self *SSecurityGroup) GetRules() ([]secrules.SecurityRule, error) {
rules := make([]secrules.SecurityRule, 0)
func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) {
rules := make([]cloudprovider.SecurityRule, 0)
for _, r := range self.Rule {
rule := self.UcloudSecRuleToOnecloud(r)
rule, err := self.UcloudSecRuleToOnecloud(r)
if err != nil {
log.Errorf("failed to convert rule for group %s(%s) error: %v", self.Name, self.GroupID, err)
continue
}
rules = append(rules, rule)
}
@@ -264,22 +250,11 @@ func (self *SRegion) GetSecurityGroups(secGroupId string, resourceId string, nam
return result, nil
}
func (self *SSecurityGroup) SyncRules(rules []secrules.SecurityRule) error {
// 如果是空规则,onecloud。默认拒绝所有流量
if len(rules) == 0 {
_, IpNet, _ := net.ParseCIDR("0.0.0.0/0")
rules = []secrules.SecurityRule{{
Priority: 0,
Action: secrules.SecurityRuleDeny,
IPNet: IpNet,
Protocol: secrules.PROTO_ANY,
Direction: secrules.SecurityRuleIngress,
PortStart: 0,
PortEnd: 0,
Ports: nil,
Description: "",
}}
func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error {
if len(inAdds) == 0 && len(inDels) == 0 {
return nil
}
rules := append(common, inAdds...)
return self.region.syncSecgroupRules(self.FWID, rules)
}
-22
View File
@@ -22,7 +22,6 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/secrules"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
@@ -381,27 +380,6 @@ func (region *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCre
return region.CreateSecurityGroup(conf.Name, conf.Desc)
}
func (region *SRegion) SyncSecurityGroup(secgroupId string, vpcId string, name string, desc string, rules []secrules.SecurityRule) (string, error) {
if len(secgroupId) > 0 {
_, err := region.GetSecurityGroup(secgroupId)
if err != nil {
if err == cloudprovider.ErrNotFound {
secgroupId = ""
} else {
return "", err
}
}
}
if len(secgroupId) == 0 {
secgroup, err := region.CreateSecurityGroup(name, desc)
if err != nil {
return "", err
}
secgroupId = secgroup.UUID
}
return secgroupId, region.syncSecgroupRules(secgroupId, rules)
}
func (region *SRegion) GetCapabilities() []string {
return region.client.GetCapabilities()
}
+28 -131
View File
@@ -18,13 +18,15 @@ import (
"fmt"
"net"
"net/url"
"sort"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/secrules"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
)
type SSecurityGroupRule struct {
@@ -41,29 +43,8 @@ type SSecurityGroupRule struct {
ZStackTime
}
type SSecurityGroupRuleSet []SSecurityGroupRule
func (v SSecurityGroupRuleSet) Len() int {
return len(v)
}
func (v SSecurityGroupRuleSet) Swap(i, j int) {
v[i], v[j] = v[j], v[i]
}
func (v SSecurityGroupRuleSet) Less(i, j int) bool {
rule, err := v[i].toRule()
if err != nil {
return false
}
_rule, err := v[j].toRule()
if err != nil {
return false
}
return strings.Compare(rule.String(), _rule.String()) <= 0
}
type SSecurityGroup struct {
multicloud.SSecurityGroup
region *SRegion
ZStackBasic
@@ -123,18 +104,21 @@ func (self *SSecurityGroup) GetDescription() string {
return self.Description
}
func (rule *SSecurityGroupRule) toRule() (*secrules.SecurityRule, error) {
r := &secrules.SecurityRule{
Direction: secrules.DIR_IN,
Action: secrules.SecurityRuleAllow,
Priority: 1,
Protocol: secrules.PROTO_ANY,
PortStart: rule.StartPort,
PortEnd: rule.EndPort,
func (rule *SSecurityGroupRule) toRule() (cloudprovider.SecurityRule, error) {
r := cloudprovider.SecurityRule{
ExternalId: rule.UUID,
SecurityRule: secrules.SecurityRule{
Direction: secrules.DIR_IN,
Action: secrules.SecurityRuleAllow,
Priority: 1,
Protocol: secrules.PROTO_ANY,
PortStart: rule.StartPort,
PortEnd: rule.EndPort,
},
}
_, ipNet, err := net.ParseCIDR(rule.AllowedCIDR)
if err != nil {
return nil, err
return r, err
}
r.IPNet = ipNet
if rule.Type == "Egress" {
@@ -146,29 +130,17 @@ func (rule *SSecurityGroupRule) toRule() (*secrules.SecurityRule, error) {
return r, nil
}
func (self *SSecurityGroup) GetRules() ([]secrules.SecurityRule, error) {
rules := []secrules.SecurityRule{}
priority := 100
outRuleCount := 0
func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) {
rules := []cloudprovider.SecurityRule{}
for i := 0; i < len(self.Rules); i++ {
if self.Rules[i].IPVersion == 4 {
rule, err := self.Rules[i].toRule()
if err != nil {
return nil, err
}
if rule.Direction == secrules.DIR_OUT {
outRuleCount++
}
rule.Priority = priority
rules = append(rules, *rule)
priority--
rules = append(rules, rule)
}
}
if outRuleCount != 0 {
rule := secrules.MustParseSecurityRule("out:deny any")
rule.Priority = 1
rules = append(rules, *rule)
}
return rules, nil
}
@@ -196,7 +168,7 @@ func (self *SSecurityGroup) GetProjectId() string {
return ""
}
func (region *SRegion) AddSecurityGroupRule(secgroupId string, rules []secrules.SecurityRule) error {
func (region *SRegion) AddSecurityGroupRule(secgroupId string, rules []cloudprovider.SecurityRule) error {
ruleParam := []map[string]interface{}{}
for _, rule := range rules {
Type := "Ingress"
@@ -280,91 +252,16 @@ func (region *SRegion) CreateSecurityGroup(name, desc string) (*SSecurityGroup,
return secgroup, region.client.create("security-groups", jsonutils.Marshal(params), secgroup)
}
func (region *SRegion) syncSecgroupRules(secgroupId string, rules []secrules.SecurityRule) error {
secgroup, err := region.GetSecurityGroup(secgroupId)
func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error {
deleteIds := []string{}
for _, r := range append(inDels, outDels...) {
deleteIds = append(deleteIds, r.ExternalId)
}
err := self.region.DeleteSecurityGroupRules(deleteIds)
if err != nil {
return err
return errors.Wrapf(err, "DeleteSecurityGroupRules(%s)", deleteIds)
}
inRules, outRules := secrules.SecurityRuleSet{}, secrules.SecurityRuleSet{}
for i := 0; i < len(rules); i++ {
if rules[i].Direction == secrules.DIR_IN {
inRules = append(inRules, rules[i])
} else {
outRules = append(outRules, rules[i])
}
}
if len(outRules) > 0 {
// 避免出现 {"error":{"class":"SYS.1007","code":503,"details":"rule should not be duplicated. rule dump: {\"type\":\"Egress\",\"ipVersion\":4,\"startPort\":-1,\"endPort\":-1,\"protocol\":\"ALL\",\"allowedCidr\":\"0.0.0.0/0\"}"}}
find := false
for _, _rule := range outRules {
if _rule.String() == "out:allow any" {
find = true
break
}
}
if !find {
rule := secrules.MustParseSecurityRule("out:allow any")
outRules = append(outRules, *rule)
}
}
rules = inRules.AllowList()
rules = append(rules, outRules.AllowList()...)
for i := 0; i < len(rules); i++ {
rules[i].Priority = 1
}
sort.Sort(secrules.SecurityRuleSet(rules))
sort.Sort(SSecurityGroupRuleSet(secgroup.Rules))
delRuleIds := []string{}
addRules := []secrules.SecurityRule{}
i, j := 0, 0
for i < len(rules) || j < len(secgroup.Rules) {
if i < len(rules) && j < len(secgroup.Rules) {
_rule, err := secgroup.Rules[j].toRule()
if err != nil {
return err
}
_ruleStr := _rule.String()
ruleStr := rules[i].String()
cmp := strings.Compare(_ruleStr, ruleStr)
if cmp == 0 {
if len(secgroup.Rules[j].RemoteSecurityGroupUUID) > 0 {
delRuleIds = append(delRuleIds, secgroup.Rules[j].UUID)
addRules = append(addRules, rules[i])
}
i++
j++
} else if cmp > 0 {
delRuleIds = append(delRuleIds, secgroup.Rules[j].UUID)
j++
} else {
addRules = append(addRules, rules[i])
i++
}
} else if i >= len(rules) {
delRuleIds = append(delRuleIds, secgroup.Rules[j].UUID)
j++
} else if j >= len(secgroup.Rules) {
addRules = append(addRules, rules[i])
i++
}
}
if len(delRuleIds) > 0 {
err = region.DeleteSecurityGroupRules(delRuleIds)
if err != nil {
return err
}
}
return region.AddSecurityGroupRule(secgroupId, addRules)
}
func (self *SSecurityGroup) SyncRules(rules []secrules.SecurityRule) error {
return self.region.syncSecgroupRules(self.UUID, rules)
return self.region.AddSecurityGroupRule(self.UUID, append(inAdds, outAdds...))
}
func (self *SSecurityGroup) Delete() error {