mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-08-31 01:35:56 +08:00
fix: 默认不自动合并安全组
This commit is contained in:
@@ -15,194 +15,23 @@
|
||||
package compute
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/cmd/climc/shell"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/options"
|
||||
)
|
||||
|
||||
func init() {
|
||||
type SecGroupsListOptions struct {
|
||||
Equals string `help:"Secgroup ID or Name, filter secgroups whose rules equals the specified one"`
|
||||
Server string `help:"Filter secgroups bound to specified server"`
|
||||
options.BaseListOptions
|
||||
Ip string `help:"Filter secgroup by ip"`
|
||||
Ports string `help:"Filter secgroup by ports"`
|
||||
Direction string `help:"Filter secgroup by ports" choices:"all|in|out"`
|
||||
}
|
||||
|
||||
R(&SecGroupsListOptions{}, "secgroup-list", "List all security group", func(s *mcclient.ClientSession, args *SecGroupsListOptions) error {
|
||||
params, err := options.ListStructToParams(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result, err := modules.SecGroups.List(s, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printList(result, modules.SecGroups.GetColumns(s))
|
||||
return nil
|
||||
})
|
||||
|
||||
type SecGroupsCreateOptions struct {
|
||||
NAME string `help:"Name of security group to create"`
|
||||
RULES []string `help:"security rule to create"`
|
||||
Desc string `help:"Description"`
|
||||
}
|
||||
|
||||
R(&SecGroupsCreateOptions{}, "secgroup-create", "Create a security group", func(s *mcclient.ClientSession, args *SecGroupsCreateOptions) error {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(args.NAME), "name")
|
||||
if len(args.Desc) > 0 {
|
||||
params.Add(jsonutils.NewString(args.Desc), "description")
|
||||
}
|
||||
for i, a := range args.RULES {
|
||||
params.Add(jsonutils.NewString(a), fmt.Sprintf("rule.%d", i))
|
||||
}
|
||||
secgroups, err := modules.SecGroups.Create(s, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(secgroups)
|
||||
return nil
|
||||
|
||||
})
|
||||
|
||||
type SecGroupsUnionOptions struct {
|
||||
ID string `help:"ID or Name of security group destination"`
|
||||
SECGROUPS []string `help:"source IDs or Names of secgroup"`
|
||||
}
|
||||
|
||||
R(&SecGroupsUnionOptions{}, "secgroup-union", "Union secgroups to one secgroup", func(s *mcclient.ClientSession, args *SecGroupsUnionOptions) error {
|
||||
params := jsonutils.NewDict()
|
||||
secgroups := jsonutils.NewArray()
|
||||
for i := 0; i < len(args.SECGROUPS); i++ {
|
||||
secgroups.Add(jsonutils.NewString(args.SECGROUPS[i]))
|
||||
}
|
||||
params.Add(secgroups, "secgroups")
|
||||
secgroup, err := modules.SecGroups.PerformAction(s, args.ID, "union", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(secgroup)
|
||||
return nil
|
||||
|
||||
})
|
||||
|
||||
type SecGroupsDetailOptions struct {
|
||||
ID string `help:"ID or Name of security group"`
|
||||
}
|
||||
R(&SecGroupsDetailOptions{}, "secgroup-show", "Show details of a security group", func(s *mcclient.ClientSession, args *SecGroupsDetailOptions) error {
|
||||
result, err := modules.SecGroups.Get(s, args.ID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
R(&SecGroupsDetailOptions{}, "secgroup-delete", "Delete a security group", func(s *mcclient.ClientSession, args *SecGroupsDetailOptions) error {
|
||||
secgroups, err := modules.SecGroups.Delete(s, args.ID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(secgroups)
|
||||
return nil
|
||||
})
|
||||
|
||||
R(&SecGroupsDetailOptions{}, "secgroup-public", "Make a security group publicly available", func(s *mcclient.ClientSession, args *SecGroupsDetailOptions) error {
|
||||
result, err := modules.SecGroups.PerformAction(s, args.ID, "public", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
R(&SecGroupsDetailOptions{}, "secgroup-private", "Make a security group private", func(s *mcclient.ClientSession, args *SecGroupsDetailOptions) error {
|
||||
result, err := modules.SecGroups.PerformAction(s, args.ID, "private", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type SecGroupsUpdateOptions struct {
|
||||
ID string `help:"ID of security group"`
|
||||
Name string `help:"Name of security group to update"`
|
||||
Desc string `help:"Description of security groups"`
|
||||
}
|
||||
|
||||
R(&SecGroupsUpdateOptions{}, "secgroup-update", "Update details of a security group", func(s *mcclient.ClientSession, args *SecGroupsUpdateOptions) error {
|
||||
params := jsonutils.NewDict()
|
||||
if len(args.Name) > 0 {
|
||||
params.Add(jsonutils.NewString(args.Name), "name")
|
||||
}
|
||||
if len(args.Desc) > 0 {
|
||||
params.Add(jsonutils.NewString(args.Desc), "description")
|
||||
}
|
||||
secgroups, err := modules.SecGroups.Update(s, args.ID, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(secgroups)
|
||||
return nil
|
||||
})
|
||||
|
||||
type SecGroupsAddRuleOptions struct {
|
||||
ID string `help:"ID or Name of security group"`
|
||||
DIRECTION string `help:"Direction of rule" choices:"in|out"`
|
||||
PROTOCOL string `help:"Protocol of rule" choices:"any|tcp|udp|icmp"`
|
||||
ACTION string `help:"Actin of rule" choices:"allow|deny"`
|
||||
PRIORITY int `help:"Priority for rule, range 1 ~ 100"`
|
||||
Cidr string `help:"IP or CIRD for rule"`
|
||||
Description string `help:"Desciption for rule"`
|
||||
Ports string `help:"Port for rule"`
|
||||
}
|
||||
|
||||
R(&SecGroupsAddRuleOptions{}, "secgroup-add-rule", "Add rule for a security group", func(s *mcclient.ClientSession, args *SecGroupsAddRuleOptions) error {
|
||||
params, err := options.StructToParams(args)
|
||||
secgroups, err := modules.SecGroups.PerformAction(s, args.ID, "add-rule", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(secgroups)
|
||||
return nil
|
||||
})
|
||||
|
||||
type SecurityGroupCacheSecurityGroup struct {
|
||||
ID string `help:"ID or Name of security group"`
|
||||
VPC string `help:"ID or Name of vpc"`
|
||||
Classic *bool `help:"Is classic vpc"`
|
||||
}
|
||||
|
||||
R(&SecurityGroupCacheSecurityGroup{}, "secgroup-cache-secgroup", "Cache security group for special vpc", func(s *mcclient.ClientSession, args *SecurityGroupCacheSecurityGroup) error {
|
||||
params, err := options.StructToParams(args)
|
||||
secgroups, err := modules.SecGroups.PerformAction(s, args.ID, "cache-secgroup", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(secgroups)
|
||||
return nil
|
||||
})
|
||||
|
||||
type SecurityGroupUncacheSecurityGroup struct {
|
||||
ID string `help:"ID or Name of security group"`
|
||||
CACHE string `help:"ID of secgroup cache"`
|
||||
}
|
||||
|
||||
R(&SecurityGroupUncacheSecurityGroup{}, "secgroup-uncache-secgroup", "Unache special secgroup cache", func(s *mcclient.ClientSession, args *SecurityGroupUncacheSecurityGroup) error {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(args.CACHE), "secgroupcache")
|
||||
secgroups, err := modules.SecGroups.PerformAction(s, args.ID, "uncache-secgroup", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(secgroups)
|
||||
return nil
|
||||
})
|
||||
|
||||
cmd := shell.NewResourceCmd(&modules.SecGroups)
|
||||
cmd.List(&options.SecgroupListOptions{})
|
||||
cmd.Create(&options.SecgroupCreateOptions{})
|
||||
cmd.Show(&options.SecgroupIdOptions{})
|
||||
cmd.Update(&options.BaseUpdateOptions{})
|
||||
cmd.Delete(&options.SecgroupIdOptions{})
|
||||
cmd.Perform("merge", &options.SecgroupMergeOptions{})
|
||||
cmd.Perform("public", &options.SecgroupIdOptions{})
|
||||
cmd.Perform("private", &options.SecgroupIdOptions{})
|
||||
cmd.Perform("add-rule", &options.SecgroupsAddRuleOptions{})
|
||||
cmd.Perform("cache-secgroup", &options.SecurityGroupCacheOptions{})
|
||||
cmd.Perform("uncache-secgroup", &options.SecurityGroupUncacheSecurityGroup{})
|
||||
cmd.Perform("purge", &options.SecgroupIdOptions{})
|
||||
}
|
||||
|
||||
@@ -257,3 +257,6 @@ type SecgroupMergeInput struct {
|
||||
// Deprecated
|
||||
Secgroups []string `json:"secgroup" yunion-deprecated-by:"secgroup_ids"`
|
||||
}
|
||||
|
||||
type SecurityGroupPurgeInput struct {
|
||||
}
|
||||
|
||||
@@ -355,6 +355,39 @@ func (self *SSecurityGroupCache) GetSecgroup() (*SSecurityGroup, error) {
|
||||
return model.(*SSecurityGroup), nil
|
||||
}
|
||||
|
||||
func (self *SSecurityGroupCache) syncWithCloudSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, ext cloudprovider.ICloudSecurityGroup) error {
|
||||
_, err := db.Update(self, func() error {
|
||||
self.Status = api.SECGROUP_CACHE_STATUS_READY
|
||||
self.Name = ext.GetName()
|
||||
self.Description = ext.GetDescription()
|
||||
self.ExternalProjectId = ext.GetProjectId()
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "db.Update")
|
||||
}
|
||||
secgroup, err := self.GetSecgroup()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "GetSecurity")
|
||||
}
|
||||
cacheCount, err := secgroup.GetSecgroupCacheCount()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "GetSecgroupCacheCount")
|
||||
}
|
||||
if cacheCount > 1 {
|
||||
return nil
|
||||
}
|
||||
info, err := SecurityGroupManager.getRuleInfo(provider, ext)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "getRuleInfo")
|
||||
}
|
||||
err = secgroup.SyncSecurityGroupRules(ctx, userCred, info)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "SyncSecurityGroupRules")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (manager *SSecurityGroupCacheManager) SyncSecurityGroupCaches(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, secgroups []cloudprovider.ICloudSecurityGroup, vpc *SVpc) ([]SSecurityGroup, []cloudprovider.ICloudSecurityGroup, compare.SyncResult) {
|
||||
lockman.LockClass(ctx, manager, db.GetLockClassKey(manager, userCred))
|
||||
defer lockman.ReleaseClass(ctx, manager, db.GetLockClassKey(manager, userCred))
|
||||
@@ -415,25 +448,18 @@ func (manager *SSecurityGroupCacheManager) SyncSecurityGroupCaches(ctx context.C
|
||||
}
|
||||
|
||||
for i := 0; i < len(commondb); i++ {
|
||||
_, err = db.Update(&commondb[i], func() error {
|
||||
commondb[i].Status = api.SECGROUP_CACHE_STATUS_READY
|
||||
commondb[i].Name = commonext[i].GetName()
|
||||
commondb[i].Description = commonext[i].GetDescription()
|
||||
commondb[i].ExternalProjectId = commonext[i].GetProjectId()
|
||||
return nil
|
||||
})
|
||||
err = commondb[i].syncWithCloudSecurityGroup(ctx, userCred, provider, commonext[i])
|
||||
if err != nil {
|
||||
syncResult.UpdateError(err)
|
||||
} else {
|
||||
syncResult.Update()
|
||||
syncResult.UpdateError(errors.Wrapf(err, "syncWithCloudSecurityGroup"))
|
||||
continue
|
||||
}
|
||||
syncResult.Update()
|
||||
}
|
||||
|
||||
//相同的不能同步, 原因: 多个平台的安全组可能共用一个本地安全组,下面仅仅是新加的安全组
|
||||
for i := 0; i < len(added); i++ {
|
||||
secgroup, err := SecurityGroupManager.newFromCloudSecgroup(ctx, userCred, provider, added[i])
|
||||
if err != nil {
|
||||
syncResult.AddError(err)
|
||||
syncResult.AddError(errors.Wrapf(err, "newFromCloudSecgroup"))
|
||||
continue
|
||||
}
|
||||
if secgroup.ProjectId != provider.ProjectId {
|
||||
@@ -450,7 +476,7 @@ func (manager *SSecurityGroupCacheManager) SyncSecurityGroupCaches(ctx context.C
|
||||
}
|
||||
cache, err := manager.NewCache(ctx, userCred, secgroup.Id, vpcId, vpc.CloudregionId, provider.Id, added[i].GetProjectId())
|
||||
if err != nil {
|
||||
syncResult.AddError(fmt.Errorf("failed to create secgroup cache for secgroup %s(%s) provider: %s: %s", secgroup.Name, secgroup.Name, provider.Name, err))
|
||||
syncResult.AddError(errors.Wrapf(err, "NewCache for secgroup %s provider %s", secgroup.Name, provider.Name))
|
||||
continue
|
||||
}
|
||||
_, err = db.Update(cache, func() error {
|
||||
@@ -461,7 +487,7 @@ func (manager *SSecurityGroupCacheManager) SyncSecurityGroupCaches(ctx context.C
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
syncResult.AddError(err)
|
||||
syncResult.AddError(errors.Wrapf(err, "db.Update"))
|
||||
continue
|
||||
}
|
||||
localSecgroups = append(localSecgroups, *secgroup)
|
||||
@@ -560,3 +586,20 @@ func (manager *SSecurityGroupCacheManager) ListItemExportKeys(ctx context.Contex
|
||||
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func (self *SSecurityGroupCache) GetISecurityGroup() (cloudprovider.ICloudSecurityGroup, error) {
|
||||
if len(self.ExternalId) == 0 {
|
||||
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty externalId")
|
||||
}
|
||||
|
||||
manager := self.GetCloudprovider()
|
||||
if manager == nil {
|
||||
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "failed to found manager")
|
||||
}
|
||||
|
||||
iRegion, err := self.GetIRegion()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetIRegion")
|
||||
}
|
||||
return iRegion.GetISecurityGroupById(self.ExternalId)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/compare"
|
||||
"yunion.io/x/pkg/util/regutils"
|
||||
"yunion.io/x/pkg/util/secrules"
|
||||
"yunion.io/x/pkg/util/stringutils"
|
||||
@@ -463,8 +462,7 @@ func (manager *SSecurityGroupRuleManager) getRulesBySecurityGroup(secgroup *SSec
|
||||
return rules, nil
|
||||
}
|
||||
|
||||
func (manager *SSecurityGroupRuleManager) SyncRules(ctx context.Context, userCred mcclient.TokenCredential, secgroup *SSecurityGroup, rules cloudprovider.SecurityRuleSet) compare.SyncResult {
|
||||
syncResult := compare.SyncResult{}
|
||||
func (self *SSecurityGroup) SyncRules(ctx context.Context, userCred mcclient.TokenCredential, rules cloudprovider.SecurityRuleSet) error {
|
||||
priority, prePriority := 10, 0
|
||||
for i := 0; i < len(rules); i++ {
|
||||
// 这里避免了Rule规则优先级在 1-100之外的问题,ext.GetRules()不需要进行优先级转换
|
||||
@@ -473,19 +471,17 @@ func (manager *SSecurityGroupRuleManager) SyncRules(ctx context.Context, userCre
|
||||
}
|
||||
prePriority = rules[i].Priority
|
||||
rules[i].Priority = priority
|
||||
_, err := manager.newFromCloudSecurityGroup(ctx, userCred, rules[i], secgroup)
|
||||
_, err := self.newFromCloudSecurityGroupRule(ctx, userCred, rules[i])
|
||||
if err != nil {
|
||||
syncResult.AddError(err)
|
||||
continue
|
||||
return errors.Wrapf(err, "newFromCloudSecurityGroupRule")
|
||||
}
|
||||
syncResult.Add()
|
||||
}
|
||||
return syncResult
|
||||
return nil
|
||||
}
|
||||
|
||||
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))
|
||||
func (self *SSecurityGroup) newFromCloudSecurityGroupRule(ctx context.Context, userCred mcclient.TokenCredential, rule cloudprovider.SecurityRule) (*SSecurityGroupRule, error) {
|
||||
lockman.LockObject(ctx, self)
|
||||
defer lockman.ReleaseObject(ctx, self)
|
||||
|
||||
protocol := rule.Protocol
|
||||
if len(protocol) == 0 {
|
||||
@@ -506,11 +502,11 @@ func (manager *SSecurityGroupRuleManager) newFromCloudSecurityGroup(ctx context.
|
||||
Action: string(rule.Action),
|
||||
Description: rule.Description,
|
||||
}
|
||||
secrule.SecgroupId = secgroup.Id
|
||||
secrule.SecgroupId = self.Id
|
||||
|
||||
err := manager.TableSpec().Insert(ctx, secrule)
|
||||
err := SecurityGroupRuleManager.TableSpec().Insert(ctx, secrule)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrapf(err, "SecurityGroupRuleManager.Insert")
|
||||
}
|
||||
return secrule, nil
|
||||
}
|
||||
|
||||
+106
-38
@@ -37,6 +37,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/policy"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/compute/options"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
@@ -539,6 +540,14 @@ func totalSecurityGroupCount(scope rbacutils.TRbacScope, ownerId mcclient.IIdent
|
||||
return q.CountWithError()
|
||||
}
|
||||
|
||||
func (self *SSecurityGroup) AllowPerformPurge(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
|
||||
return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "purge")
|
||||
}
|
||||
|
||||
func (self *SSecurityGroup) PerformPurge(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
return nil, self.StartDeleteSecurityGroupTask(ctx, userCred, true, "")
|
||||
}
|
||||
|
||||
func (self *SSecurityGroup) AllowPerformUncacheSecgroup(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
|
||||
return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "uncache-secgroup")
|
||||
}
|
||||
@@ -814,7 +823,57 @@ func (manager *SSecurityGroupManager) getSecurityGroups() ([]SSecurityGroup, err
|
||||
}
|
||||
}
|
||||
|
||||
func (manager *SSecurityGroupManager) newFromCloudSecgroup(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, extSec cloudprovider.ICloudSecurityGroup) (*SSecurityGroup, error) {
|
||||
func (self *SSecurityGroup) cleanRules(ctx context.Context, userCred mcclient.TokenCredential) error {
|
||||
rules := []SSecurityGroupRule{}
|
||||
q := SecurityGroupRuleManager.Query().Equals("secgroup_id", self.Id)
|
||||
err := db.FetchModelObjects(SecurityGroupRuleManager, q, &rules)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "db.FetchModelObjects")
|
||||
}
|
||||
for i := range rules {
|
||||
err = rules[i].Delete(ctx, userCred)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "DeleteRule(%s)", rules[i].Id)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SSecurityGroup) SyncSecurityGroupRules(ctx context.Context, userCred mcclient.TokenCredential, info *sRuleInfo) error {
|
||||
inRules := cloudprovider.AddDefaultRule(info.inRules, info.defaultInRule, "in:deny any", info.order, info.minPriority, info.maxPriority, info.onlyAllowRules)
|
||||
cloudprovider.SortSecurityRule(inRules, info.order, info.onlyAllowRules)
|
||||
outRules := cloudprovider.AddDefaultRule(info.outRules, info.defaultOutRule, "out:allow any", info.order, info.minPriority, info.maxPriority, info.onlyAllowRules)
|
||||
cloudprovider.SortSecurityRule(outRules, info.order, info.onlyAllowRules)
|
||||
|
||||
err := self.cleanRules(ctx, userCred)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "cleanRules")
|
||||
}
|
||||
|
||||
err = self.SyncRules(ctx, userCred, inRules)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "SyncInRules")
|
||||
}
|
||||
err = self.SyncRules(ctx, userCred, outRules)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "SyncOutRules")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type sRuleInfo struct {
|
||||
rules []cloudprovider.SecurityRule
|
||||
inRules []cloudprovider.SecurityRule
|
||||
outRules []cloudprovider.SecurityRule
|
||||
defaultInRule cloudprovider.SecurityRule
|
||||
defaultOutRule cloudprovider.SecurityRule
|
||||
order cloudprovider.TPriorityOrder
|
||||
onlyAllowRules bool
|
||||
maxPriority int
|
||||
minPriority int
|
||||
}
|
||||
|
||||
func (manager *SSecurityGroupManager) getRuleInfo(provider *SCloudprovider, extSec cloudprovider.ICloudSecurityGroup) (*sRuleInfo, error) {
|
||||
regionDriver, err := provider.GetRegionDriver()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "provider.GetRegionDriver")
|
||||
@@ -825,36 +884,48 @@ func (manager *SSecurityGroupManager) newFromCloudSecgroup(ctx context.Context,
|
||||
return nil, errors.Wrap(err, "extSec.GetRules")
|
||||
}
|
||||
|
||||
inRules := []cloudprovider.SecurityRule{}
|
||||
outRules := []cloudprovider.SecurityRule{}
|
||||
info := &sRuleInfo{
|
||||
rules: rules,
|
||||
inRules: []cloudprovider.SecurityRule{},
|
||||
outRules: []cloudprovider.SecurityRule{},
|
||||
defaultInRule: regionDriver.GetDefaultSecurityGroupInRule(),
|
||||
defaultOutRule: regionDriver.GetDefaultSecurityGroupOutRule(),
|
||||
order: regionDriver.GetSecurityGroupRuleOrder(),
|
||||
onlyAllowRules: regionDriver.IsOnlySupportAllowRules(),
|
||||
maxPriority: regionDriver.GetSecurityGroupRuleMaxPriority(),
|
||||
minPriority: regionDriver.GetSecurityGroupRuleMinPriority(),
|
||||
}
|
||||
|
||||
for i := range rules {
|
||||
if rules[i].Direction == secrules.DIR_IN {
|
||||
inRules = append(inRules, rules[i])
|
||||
info.inRules = append(info.inRules, rules[i])
|
||||
} else {
|
||||
outRules = append(outRules, rules[i])
|
||||
info.outRules = append(info.outRules, rules[i])
|
||||
}
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
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)
|
||||
err = db.FetchModelObjects(manager, q, &secgroups)
|
||||
func (manager *SSecurityGroupManager) newFromCloudSecgroup(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, extSec cloudprovider.ICloudSecurityGroup) (*SSecurityGroup, error) {
|
||||
info, err := manager.getRuleInfo(provider, extSec)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "db.FetchModelObjects")
|
||||
return nil, errors.Wrapf(err, "getRuleInfo")
|
||||
}
|
||||
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
|
||||
|
||||
if options.Options.EnableAutoMergeSecurityGroup {
|
||||
// 查询与provider在同域的安全组,比对寻找一个与云上安全组规则相同的安全组
|
||||
secgroups := []SSecurityGroup{}
|
||||
q := manager.Query().Equals("domain_id", provider.DomainId)
|
||||
err = db.FetchModelObjects(manager, q, &secgroups)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "db.FetchModelObjects")
|
||||
}
|
||||
for i := range secgroups {
|
||||
localRules := secrules.SecurityRuleSet(secgroups[i].GetSecRules(""))
|
||||
_, inAdds, outAdds, inDels, outDels := cloudprovider.CompareRules(info.minPriority, info.maxPriority, info.order, localRules, info.rules, info.defaultInRule, info.defaultOutRule, info.onlyAllowRules, false)
|
||||
if len(inAdds) == 0 && len(outAdds) == 0 && len(inDels) == 0 && len(outDels) == 0 {
|
||||
return &secgroups[i], nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -863,31 +934,26 @@ func (manager *SSecurityGroupManager) newFromCloudSecgroup(ctx context.Context,
|
||||
|
||||
secgroup := SSecurityGroup{}
|
||||
secgroup.SetModelManager(manager, &secgroup)
|
||||
newName, err := db.GenerateName(manager, userCred, extSec.GetName())
|
||||
secgroup.Name, err = db.GenerateName(manager, userCred, extSec.GetName())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
secgroup.Name = newName
|
||||
secgroup.Description = extSec.GetDescription()
|
||||
secgroup.ProjectId = provider.ProjectId
|
||||
secgroup.DomainId = provider.DomainId
|
||||
|
||||
if err := manager.TableSpec().Insert(ctx, &secgroup); err != nil {
|
||||
return nil, err
|
||||
err = manager.TableSpec().Insert(ctx, &secgroup)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Insert")
|
||||
}
|
||||
|
||||
//这里必须先同步下规则,不然下次对比此安全组规则为空
|
||||
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)
|
||||
err = secgroup.SyncSecurityGroupRules(ctx, userCred, info)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "SyncSecurityGroupRules")
|
||||
}
|
||||
|
||||
db.OpsLog.LogEvent(&secgroup, db.ACT_CREATE, secgroup.GetShortDesc(ctx), userCred)
|
||||
|
||||
return &secgroup, nil
|
||||
}
|
||||
|
||||
@@ -1029,10 +1095,12 @@ func (self *SSecurityGroup) GetSecurityGroupCaches() ([]SSecurityGroupCache, err
|
||||
}
|
||||
|
||||
func (self *SSecurityGroup) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
|
||||
return self.StartDeleteSecurityGroupTask(ctx, userCred, jsonutils.NewDict(), "")
|
||||
return self.StartDeleteSecurityGroupTask(ctx, userCred, false, "")
|
||||
}
|
||||
|
||||
func (self *SSecurityGroup) StartDeleteSecurityGroupTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
|
||||
func (self *SSecurityGroup) StartDeleteSecurityGroupTask(ctx context.Context, userCred mcclient.TokenCredential, isPurge bool, parentTaskId string) error {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewBool(isPurge), "purge")
|
||||
self.SetStatus(userCred, api.SECGROUP_STATUS_DELETING, "")
|
||||
task, err := taskman.TaskManager.NewTask(ctx, "SecurityGroupDeleteTask", self, userCred, params, parentTaskId, "", nil)
|
||||
if err != nil {
|
||||
|
||||
@@ -145,6 +145,8 @@ type ComputeOptions struct {
|
||||
SASControllerOptions
|
||||
common_options.CommonOptions
|
||||
common_options.DBOptions
|
||||
|
||||
EnableAutoMergeSecurityGroup bool `help:"Enable auto merge secgroup when sync security group from cloud, default False" default:"false"`
|
||||
}
|
||||
|
||||
type SCapabilityOptions struct {
|
||||
|
||||
@@ -16,7 +16,6 @@ package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
@@ -26,7 +25,6 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/util/logclient"
|
||||
)
|
||||
|
||||
type SecurityGroupCacheDeleteTask struct {
|
||||
@@ -37,13 +35,9 @@ func init() {
|
||||
taskman.RegisterTask(SecurityGroupCacheDeleteTask{})
|
||||
}
|
||||
|
||||
func (self *SecurityGroupCacheDeleteTask) taskFailed(ctx context.Context, cache *models.SSecurityGroupCache, err jsonutils.JSONObject) {
|
||||
cache.SetStatus(self.UserCred, api.SECGROUP_CACHE_STATUS_DELETE_FAILED, err.String())
|
||||
secgroup, _ := cache.GetSecgroup()
|
||||
if secgroup != nil {
|
||||
logclient.AddActionLogWithStartable(self, secgroup, logclient.ACT_DELETE, err, self.UserCred, false)
|
||||
}
|
||||
self.SetStageFailed(ctx, err)
|
||||
func (self *SecurityGroupCacheDeleteTask) taskFailed(ctx context.Context, cache *models.SSecurityGroupCache, err error) {
|
||||
cache.SetStatus(self.UserCred, api.SECGROUP_CACHE_STATUS_DELETE_FAILED, err.Error())
|
||||
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
|
||||
}
|
||||
|
||||
func (self *SecurityGroupCacheDeleteTask) taskComplete(ctx context.Context, cache *models.SSecurityGroupCache) {
|
||||
@@ -54,38 +48,18 @@ func (self *SecurityGroupCacheDeleteTask) taskComplete(ctx context.Context, cach
|
||||
func (self *SecurityGroupCacheDeleteTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
|
||||
cache := obj.(*models.SSecurityGroupCache)
|
||||
|
||||
if len(cache.ExternalId) == 0 {
|
||||
self.taskComplete(ctx, cache)
|
||||
return
|
||||
}
|
||||
|
||||
_, err := models.CloudproviderManager.FetchById(cache.ManagerId)
|
||||
if err == sql.ErrNoRows {
|
||||
self.taskComplete(ctx, cache)
|
||||
return
|
||||
}
|
||||
|
||||
iRegion, err := cache.GetIRegion()
|
||||
iSecgroup, err := cache.GetISecurityGroup()
|
||||
if err != nil {
|
||||
if errors.Cause(err) == cloudprovider.ErrNotFound {
|
||||
self.taskComplete(ctx, cache)
|
||||
return
|
||||
}
|
||||
self.taskFailed(ctx, cache, jsonutils.NewString(errors.Wrap(err, "cache.GetIRegion").Error()))
|
||||
return
|
||||
}
|
||||
iSecgroup, err := iRegion.GetISecurityGroupById(cache.ExternalId)
|
||||
if err != nil {
|
||||
if err == cloudprovider.ErrNotFound {
|
||||
self.taskComplete(ctx, cache)
|
||||
return
|
||||
}
|
||||
self.taskFailed(ctx, cache, jsonutils.NewString(errors.Wrap(err, "iRegion.GetIStoragecacheById").Error()))
|
||||
self.taskFailed(ctx, cache, errors.Wrapf(err, "GetISecurityGroup"))
|
||||
return
|
||||
}
|
||||
err = iSecgroup.Delete()
|
||||
if err != nil {
|
||||
self.taskFailed(ctx, cache, jsonutils.NewString(err.Error()))
|
||||
self.taskFailed(ctx, cache, errors.Wrapf(err, "iSecgroup.Delete"))
|
||||
return
|
||||
}
|
||||
self.taskComplete(ctx, cache)
|
||||
|
||||
@@ -18,11 +18,14 @@ import (
|
||||
"context"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/util/logclient"
|
||||
)
|
||||
|
||||
type SecurityGroupDeleteTask struct {
|
||||
@@ -33,42 +36,42 @@ func init() {
|
||||
taskman.RegisterTask(SecurityGroupDeleteTask{})
|
||||
}
|
||||
|
||||
func (self *SecurityGroupDeleteTask) getErrorCount() int64 {
|
||||
count, _ := self.GetParams().Int("faild_count")
|
||||
return count
|
||||
}
|
||||
|
||||
func (self *SecurityGroupDeleteTask) addErrorCount() {
|
||||
count := self.getErrorCount()
|
||||
count += 1
|
||||
self.GetParams().Set("failed_count", jsonutils.NewInt(count))
|
||||
func (self *SecurityGroupDeleteTask) taskFailed(ctx context.Context, secgroup *models.SSecurityGroup, err error) {
|
||||
secgroup.SetStatus(self.UserCred, api.SECGROUP_STATUS_READY, "")
|
||||
logclient.AddActionLogWithContext(ctx, secgroup, logclient.ACT_DELOCATE, err, self.UserCred, false)
|
||||
self.SetStageFailed(ctx, jsonutils.Marshal(err))
|
||||
}
|
||||
|
||||
func (self *SecurityGroupDeleteTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
|
||||
self.SetStage("OnSecurityGroupUncacheComplete", nil)
|
||||
self.OnSecurityGroupUncacheComplete(ctx, obj, data)
|
||||
}
|
||||
|
||||
func (self *SecurityGroupDeleteTask) OnSecurityGroupUncacheComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
|
||||
secgroup := obj.(*models.SSecurityGroup)
|
||||
secgroupCaches, err := secgroup.GetSecurityGroupCaches()
|
||||
caches, err := secgroup.GetSecurityGroupCaches()
|
||||
if err != nil {
|
||||
secgroup.SetStatus(self.UserCred, api.SECGROUP_STATUS_READY, "")
|
||||
self.SetStageFailed(ctx, jsonutils.Marshal(err))
|
||||
self.taskFailed(ctx, secgroup, errors.Wrapf(err, "GetSecurityGroupCaches"))
|
||||
return
|
||||
}
|
||||
errCount := self.getErrorCount()
|
||||
if len(secgroupCaches) == int(errCount) {
|
||||
if errCount == 0 {
|
||||
secgroup.RealDelete(ctx, self.UserCred)
|
||||
}
|
||||
secgroup.SetStatus(self.UserCred, api.SECGROUP_STATUS_READY, "")
|
||||
self.SetStageComplete(ctx, nil)
|
||||
return
|
||||
}
|
||||
secgroupCaches[errCount].StartSecurityGroupCacheDeleteTask(ctx, self.UserCred, self.GetTaskId())
|
||||
}
|
||||
|
||||
func (self *SecurityGroupDeleteTask) OnSecurityGroupUncacheCompleteFailed(ctx context.Context, obj db.IStandaloneModel, err jsonutils.JSONObject) {
|
||||
self.addErrorCount()
|
||||
isPurge := jsonutils.QueryBoolean(self.Params, "purge", false)
|
||||
|
||||
for i := range caches {
|
||||
if !isPurge {
|
||||
iSecgroup, err := caches[i].GetISecurityGroup()
|
||||
if err != nil {
|
||||
if errors.Cause(err) == cloudprovider.ErrNotFound {
|
||||
caches[i].RealDelete(ctx, self.GetUserCred())
|
||||
continue
|
||||
}
|
||||
self.taskFailed(ctx, secgroup, errors.Wrapf(err, "GetISecurityGroup for cache %s(%s)", caches[i].Name, caches[i].Id))
|
||||
return
|
||||
}
|
||||
err = iSecgroup.Delete()
|
||||
if err != nil {
|
||||
self.taskFailed(ctx, secgroup, errors.Wrapf(err, "iSecgroup.Delete"))
|
||||
return
|
||||
}
|
||||
}
|
||||
caches[i].RealDelete(ctx, self.GetUserCred())
|
||||
}
|
||||
|
||||
secgroup.RealDelete(ctx, self.GetUserCred())
|
||||
self.SetStageComplete(ctx, nil)
|
||||
}
|
||||
|
||||
@@ -337,6 +337,17 @@ func (opts *BaseUpdateOptions) GetId() string {
|
||||
return opts.ID
|
||||
}
|
||||
|
||||
func (opts *BaseUpdateOptions) Params() (jsonutils.JSONObject, error) {
|
||||
params := jsonutils.NewDict()
|
||||
if len(opts.Name) > 0 {
|
||||
params.Add(jsonutils.NewString(opts.Name), "name")
|
||||
}
|
||||
if len(opts.Desc) > 0 {
|
||||
params.Add(jsonutils.NewString(opts.Desc), "description")
|
||||
}
|
||||
return params, nil
|
||||
}
|
||||
|
||||
type BasePublicOptions struct {
|
||||
ID string `help:"ID or name of resource" json:"-"`
|
||||
Scope string `help:"sharing scope" choices:"system|domain"`
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
// 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 options
|
||||
|
||||
import (
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/secrules"
|
||||
)
|
||||
|
||||
type SecgroupListOptions struct {
|
||||
BaseListOptions
|
||||
|
||||
Equals string `help:"Secgroup ID or Name, filter secgroups whose rules equals the specified one"`
|
||||
Server string `help:"Filter secgroups bound to specified server"`
|
||||
Ip string `help:"Filter secgroup by ip"`
|
||||
Ports string `help:"Filter secgroup by ports"`
|
||||
Direction string `help:"Filter secgroup by ports" choices:"all|in|out"`
|
||||
}
|
||||
|
||||
func (opts *SecgroupListOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return ListStructToParams(opts)
|
||||
}
|
||||
|
||||
type SecgroupCreateOptions struct {
|
||||
BaseCreateOptions
|
||||
Rules []string `help:"security rule to create"`
|
||||
}
|
||||
|
||||
func (opts *SecgroupCreateOptions) Params() (jsonutils.JSONObject, error) {
|
||||
params := jsonutils.Marshal(opts).(*jsonutils.JSONDict)
|
||||
params.Remove("rules")
|
||||
rules := []secrules.SecurityRule{}
|
||||
for i, ruleStr := range opts.Rules {
|
||||
rule, err := secrules.ParseSecurityRule(ruleStr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "ParseSecurityRule(%s)", ruleStr)
|
||||
}
|
||||
rule.Priority = i + 1
|
||||
rules = append(rules, *rule)
|
||||
}
|
||||
if len(rules) > 0 {
|
||||
params.Add(jsonutils.Marshal(rules), "rules")
|
||||
}
|
||||
return params, nil
|
||||
}
|
||||
|
||||
type SecgroupIdOptions struct {
|
||||
ID string `help:"ID or Name of security group destination"`
|
||||
}
|
||||
|
||||
func (opts *SecgroupIdOptions) GetId() string {
|
||||
return opts.ID
|
||||
}
|
||||
|
||||
func (opts *SecgroupIdOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type SecgroupMergeOptions struct {
|
||||
SecgroupIdOptions
|
||||
SECGROUPS []string `help:"source IDs or Names of secgroup"`
|
||||
}
|
||||
|
||||
func (opts *SecgroupMergeOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return jsonutils.Marshal(map[string][]string{"secgruops": opts.SECGROUPS}), nil
|
||||
}
|
||||
|
||||
type SecgroupsAddRuleOptions struct {
|
||||
SecgroupIdOptions
|
||||
DIRECTION string `help:"Direction of rule" choices:"in|out"`
|
||||
PROTOCOL string `help:"Protocol of rule" choices:"any|tcp|udp|icmp"`
|
||||
ACTION string `help:"Actin of rule" choices:"allow|deny"`
|
||||
PRIORITY int `help:"Priority for rule, range 1 ~ 100"`
|
||||
Cidr string `help:"IP or CIRD for rule"`
|
||||
Description string `help:"Desciption for rule"`
|
||||
Ports string `help:"Port for rule"`
|
||||
}
|
||||
|
||||
func (opts *SecgroupsAddRuleOptions) Params() (jsonutils.JSONObject, error) {
|
||||
params := jsonutils.Marshal(opts).(*jsonutils.JSONDict)
|
||||
params.Remove("id")
|
||||
return params, nil
|
||||
}
|
||||
|
||||
type SecurityGroupCacheOptions struct {
|
||||
SecgroupIdOptions
|
||||
VPC string `help:"ID or Name of vpc"`
|
||||
Classic *bool `help:"Is classic vpc"`
|
||||
}
|
||||
|
||||
func (opts *SecurityGroupCacheOptions) Params() (jsonutils.JSONObject, error) {
|
||||
params := jsonutils.Marshal(opts).(*jsonutils.JSONDict)
|
||||
params.Remove("id")
|
||||
return params, nil
|
||||
}
|
||||
|
||||
type SecurityGroupUncacheSecurityGroup struct {
|
||||
SecgroupIdOptions
|
||||
CACHE string `help:"ID of secgroup cache"`
|
||||
}
|
||||
|
||||
func (opts *SecurityGroupUncacheSecurityGroup) Params() (jsonutils.JSONObject, error) {
|
||||
params := jsonutils.Marshal(opts).(*jsonutils.JSONDict)
|
||||
params.Remove("id")
|
||||
return params, nil
|
||||
}
|
||||
Reference in New Issue
Block a user