diff --git a/cmd/climc/shell/secgroupcaches.go b/cmd/climc/shell/secgroupcaches.go new file mode 100644 index 0000000000..69f05e5536 --- /dev/null +++ b/cmd/climc/shell/secgroupcaches.go @@ -0,0 +1,62 @@ +// 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 shell + +import ( + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" +) + +func init() { + type SecGroupCacheListOptions struct { + options.BaseListOptions + Secgroup string `help:"Secgroup ID or Name"` + } + + R(&SecGroupCacheListOptions{}, "secgroup-cache-list", "List security group caches", func(s *mcclient.ClientSession, args *SecGroupCacheListOptions) error { + params, err := options.ListStructToParams(args) + if err != nil { + return err + } + result, err := modules.SecGroupCaches.List(s, params) + if err != nil { + return err + } + printList(result, modules.SecGroupCaches.GetColumns(s)) + return nil + }) + type SecGroupCacheIdOptions struct { + ID string `help:"ID or Name or secgroup cache"` + } + R(&SecGroupCacheIdOptions{}, "secgroup-cache-show", "Show security group cache", func(s *mcclient.ClientSession, args *SecGroupCacheIdOptions) error { + result, err := modules.SecGroupCaches.Get(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&SecGroupCacheIdOptions{}, "secgroup-cache-delete", "Delete security group cache", func(s *mcclient.ClientSession, args *SecGroupCacheIdOptions) error { + result, err := modules.SecGroupCaches.Delete(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + +} diff --git a/cmd/climc/shell/secgroups.go b/cmd/climc/shell/secgroups.go index 6005ed9e3a..7d133892fd 100644 --- a/cmd/climc/shell/secgroups.go +++ b/cmd/climc/shell/secgroups.go @@ -176,4 +176,37 @@ func init() { 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 + }) + } diff --git a/docs/index.yaml b/docs/index.yaml index 1847894673..263b0bcc3c 100644 --- a/docs/index.yaml +++ b/docs/index.yaml @@ -446,6 +446,18 @@ paths: $ref: "./secgroup/public.yaml" /secgroups/{secgroupId}/private: $ref: "./secgroup/private.yaml" + /secgroups/{secgroupId}/cache-secgroup: + $ref: "./secgroup/cache-secgroup.yaml" + /secgroups/{secgroupId}/uncache-secgroup: + $ref: "./secgroup/uncache-secgroup.yaml" + + + /secgroupcaches: + $ref: "./secgroupcache/secgroupcaches.yaml" + /secgroupcaches/{cacheId}: + $ref: "./secgroupcache/secgroupcache.yaml" + + /secgrouprules: $ref: "./secgrouprule/secgrouprules.yaml" /secgrouprules/{secgroupruleId}: diff --git a/docs/parameters/secgroupcache.yaml b/docs/parameters/secgroupcache.yaml new file mode 100644 index 0000000000..68e69b3752 --- /dev/null +++ b/docs/parameters/secgroupcache.yaml @@ -0,0 +1,13 @@ +cacheId: + name: cacheId + required: true + in: path + type: string + description: 安全组缓存ID + + +secgroup: + name: secgroup + in: query + type: string + description: 安全组ID,仅过滤此安全组底下的缓存 diff --git a/docs/schemas/secgroup.yaml b/docs/schemas/secgroup.yaml index 5310124571..ce295516b3 100644 --- a/docs/schemas/secgroup.yaml +++ b/docs/schemas/secgroup.yaml @@ -156,3 +156,26 @@ SecgroupAddRule: type: string example: test-rule description: 规则描述 + +SecgroupCache: + type: object + properties: + vpc: + type: string + example: test-vpc + required: true + description: vpc名称或ID,建议使用ID + classic: + type: boolean + default: false + example: false + description: 仅针对支持经典网络的情况,目前仅Azure支持此参数 + +SecgroupUncache: + type: object + properties: + secgroupcache: + type: string + example: 2e974625-d7e2-481b-8471-1c46fa9a65b0 + required: true + description: 安全组缓存ID diff --git a/docs/schemas/secgroupcache.yaml b/docs/schemas/secgroupcache.yaml new file mode 100644 index 0000000000..b003e97ade --- /dev/null +++ b/docs/schemas/secgroupcache.yaml @@ -0,0 +1,67 @@ +SecgroupCacheResponse: + type: object + properties: + secgroupcache: + type: object + $ref: '#/SecgroupCache' + +SecgroupCache: + allOf: + - $ref: "./common.yaml#/StatusStandaloneResponse" + - type: object + properties: + vpc_id: + type: string + example: normal + description: 云上的vpc_id,若返回normal一般是指此安全组是region级别的 + secgroup_id: + type: string + example: a9ee32d4-66f3-4d2d-89b7-b1dea778484c + desciption: 本地安全组ID + account: + type: string + example: openstack + description: 资源所属的云账号名称 + account_id: + type: string + example: a9ee32d4-66f3-4d2d-89b7-b1dea778484c + desciption: 源所属的云账号ID + account_domain: + type: string + example: Default + description: 资源账号所属的域 + account_domain_id: + type: string + example: default + description: 资源账号所属的域ID + external_id: + type: string + example: a359d7d6-54b7-4853-b200-9e4a9cfc5f42 + description: 安全组对应云上的ID + manager: + type: string + example: openstack + desciption: 安全组所属的子账号ID + provider: + type: string + example: OpenStack + description: 所属云平台 + region: + type: string + example: openstack-RegionOne + desciption: 所在区域 + + +SecgroupCacheListResponse: + type: object + properties: + limit: + type: integer + example: 20 + secgroupcaches: + type: array + items: + $ref: '#/SecgroupCache' + total: + type: integer + example: 124 diff --git a/docs/secgroup/cache-secgroup.yaml b/docs/secgroup/cache-secgroup.yaml new file mode 100644 index 0000000000..25cb7e9b7e --- /dev/null +++ b/docs/secgroup/cache-secgroup.yaml @@ -0,0 +1,16 @@ +post: + summary: 预创建安全组到云上 + parameters: + - $ref: '../parameters/secgroup.yaml#/secgroupId' + - in: body + name: secgroup + required: true + schema: + $ref: '../schemas/secgroup.yaml#/SecgroupCache' + responses: + 200: + description: 安全组信息 + schema: + $ref: '../schemas/secgroup.yaml#/SecgroupResponse' + tags: + - secgroups diff --git a/docs/secgroup/uncache-secgroup.yaml b/docs/secgroup/uncache-secgroup.yaml new file mode 100644 index 0000000000..a94de15b66 --- /dev/null +++ b/docs/secgroup/uncache-secgroup.yaml @@ -0,0 +1,16 @@ +post: + summary: 删除云上的某个安全组 + parameters: + - $ref: '../parameters/secgroup.yaml#/secgroupId' + - in: body + name: secgroup + required: true + schema: + $ref: '../schemas/secgroup.yaml#/SecgroupUncache' + responses: + 200: + description: 安全组信息 + schema: + $ref: '../schemas/secgroup.yaml#/SecgroupResponse' + tags: + - secgroups diff --git a/docs/secgroupcache/secgroupcache.yaml b/docs/secgroupcache/secgroupcache.yaml new file mode 100644 index 0000000000..938e421a46 --- /dev/null +++ b/docs/secgroupcache/secgroupcache.yaml @@ -0,0 +1,22 @@ +get: + summary: 获取指定安全组缓存详情信息 + parameters: + - $ref: '../parameters/secgroupcache.yaml#/cacheId' + responses: + 200: + description: 安全组信息 + schema: + $ref: '../schemas/secgroupcache.yaml#/SecgroupCacheResponse' + tags: + - secgroupcaches + +delete: + summary: 删除指定安全组缓存 + parameters: + - $ref: '../parameters/secgroupcache.yaml#/cacheId' + responses: + 200: + schema: + $ref: '../schemas/secgroupcache.yaml#/SecgroupCacheResponse' + tags: + - secgroupcaches diff --git a/docs/secgroupcache/secgroupcaches.yaml b/docs/secgroupcache/secgroupcaches.yaml new file mode 100644 index 0000000000..4166f1cbdc --- /dev/null +++ b/docs/secgroupcache/secgroupcaches.yaml @@ -0,0 +1,13 @@ +get: + summary: 按指定条件列出安全组缓存列表 + parameters: + - $ref: '../parameters/common.yaml#/limit' + - $ref: '../parameters/common.yaml#/offset' + - $ref: '../parameters/secgroupcache.yaml#/secgroup' + responses: + 200: + description: 安全组缓存列表信息 + schema: + $ref: '../schemas/secgroupcache.yaml#/SecgroupCacheListResponse' + tags: + - secgroupcaches diff --git a/pkg/apis/compute/secgroup.go b/pkg/apis/compute/secgroup.go index 239b38894d..ec0b61a887 100644 --- a/pkg/apis/compute/secgroup.go +++ b/pkg/apis/compute/secgroup.go @@ -57,6 +57,7 @@ type SSecgroupCreateInput struct { apis.Meta Name string + Status string Description string Rules []SSecgroupRuleCreateInput } diff --git a/pkg/apis/compute/secgroup_const.go b/pkg/apis/compute/secgroup_const.go new file mode 100644 index 0000000000..784d571e36 --- /dev/null +++ b/pkg/apis/compute/secgroup_const.go @@ -0,0 +1,20 @@ +// Copyright 2019 Yunion +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package compute + +const ( + SECGROUP_STATUS_READY = "ready" + SECGROUP_STATUS_DELETING = "deleting" +) diff --git a/pkg/apis/compute/secgroupcache_const.go b/pkg/apis/compute/secgroupcache_const.go new file mode 100644 index 0000000000..f151922330 --- /dev/null +++ b/pkg/apis/compute/secgroupcache_const.go @@ -0,0 +1,22 @@ +// Copyright 2019 Yunion +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package compute + +const ( + SECGROUP_CACHE_STATUS_READY = "ready" + SECGROUP_CACHE_STATUS_DELETING = "deleting" + SECGROUP_CACHE_STATUS_CACHING = "caching" + SECGROUP_CACHE_STATUS_DELETE_FAILED = "delete_failed" +) diff --git a/pkg/cloudprovider/fakeregion.go b/pkg/cloudprovider/fakeregion.go index a7097456e7..7f95eeff63 100644 --- a/pkg/cloudprovider/fakeregion.go +++ b/pkg/cloudprovider/fakeregion.go @@ -16,7 +16,6 @@ package cloudprovider import ( "yunion.io/x/jsonutils" - "yunion.io/x/pkg/util/secrules" ) type SFakeOnPremiseRegion struct { @@ -90,12 +89,12 @@ func (region *SFakeOnPremiseRegion) CreateEIP(eip *SEip) (ICloudEIP, error) { return nil, ErrNotSupported } -func (region *SFakeOnPremiseRegion) DeleteSecurityGroup(vpcId, secgroupId string) error { - return ErrNotSupported +func (region *SFakeOnPremiseRegion) GetISecurityGroupById(id string) (ICloudSecurityGroup, error) { + return nil, ErrNotSupported } -func (region *SFakeOnPremiseRegion) SyncSecurityGroup(secgroupId string, vpcId string, name string, desc string, rules []secrules.SecurityRule) (string, error) { - return "", ErrNotSupported +func (region *SFakeOnPremiseRegion) CreateISecurityGroup(conf *SecurityGroupCreateInput) (ICloudSecurityGroup, error) { + return nil, ErrNotSupported } func (region *SFakeOnPremiseRegion) GetILoadBalancers() ([]ICloudLoadbalancer, error) { diff --git a/pkg/cloudprovider/resources.go b/pkg/cloudprovider/resources.go index 118fe365a1..4867f6b63f 100644 --- a/pkg/cloudprovider/resources.go +++ b/pkg/cloudprovider/resources.go @@ -69,8 +69,8 @@ type ICloudRegion interface { GetIVMById(id string) (ICloudVM, error) GetIDiskById(id string) (ICloudDisk, error) - DeleteSecurityGroup(vpcId, secgroupId string) error - SyncSecurityGroup(secgroupId string, vpcId string, name string, desc string, rules []secrules.SecurityRule) (string, error) + GetISecurityGroupById(secgroupId string) (ICloudSecurityGroup, error) + CreateISecurityGroup(conf *SecurityGroupCreateInput) (ICloudSecurityGroup, error) CreateIVpc(name string, desc string, cidr string) (ICloudVpc, error) CreateEIP(eip *SEip) (ICloudEIP, error) @@ -327,6 +327,9 @@ type ICloudSecurityGroup interface { GetDescription() string GetRules() ([]secrules.SecurityRule, error) GetVpcId() string + + SyncRules(rules []secrules.SecurityRule) error + Delete() error } type ICloudRouteTable interface { diff --git a/pkg/cloudprovider/securitygroup.go b/pkg/cloudprovider/securitygroup.go new file mode 100644 index 0000000000..5fe57ce14a --- /dev/null +++ b/pkg/cloudprovider/securitygroup.go @@ -0,0 +1,24 @@ +// 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 cloudprovider + +import "yunion.io/x/pkg/util/secrules" + +type SecurityGroupCreateInput struct { + Name string + Desc string + VpcId string + Rules []secrules.SecurityRule +} diff --git a/pkg/compute/guestdrivers/azure.go b/pkg/compute/guestdrivers/azure.go index fd33341742..f3e8981cc0 100644 --- a/pkg/compute/guestdrivers/azure.go +++ b/pkg/compute/guestdrivers/azure.go @@ -17,7 +17,6 @@ package guestdrivers import ( "context" "fmt" - "strings" "yunion.io/x/jsonutils" "yunion.io/x/pkg/utils" @@ -141,14 +140,6 @@ func (self *SAzureGuestDriver) GetLinuxDefaultAccount(desc cloudprovider.SManage return api.VM_AZURE_DEFAULT_LOGIN_USER } -func (self *SAzureGuestDriver) GetGuestSecgroupVpcid(guest *models.SGuest) (string, error) { - host := guest.GetHost() - if host != nil && strings.HasSuffix(host.Name, "-classic") { - return "classic", nil - } - return api.NORMAL_VPC_ID, nil -} - func (self *SAzureGuestDriver) IsSupportedBillingCycle(bc billing.SBillingCycle) bool { return false } diff --git a/pkg/compute/guestdrivers/base.go b/pkg/compute/guestdrivers/base.go index 40ebbdf6a6..be46b3fcf6 100644 --- a/pkg/compute/guestdrivers/base.go +++ b/pkg/compute/guestdrivers/base.go @@ -303,21 +303,6 @@ func (self *SBaseGuestDriver) RequestSyncSecgroupsOnHost(ctx context.Context, gu return nil // do nothing } -func (self *SBaseGuestDriver) GetGuestSecgroupVpcid(guest *models.SGuest) (string, error) { - vpcId := "" - guestnets, err := guest.GetNetworks("") - if err != nil { - return "", err - } - for _, network := range guestnets { - if vpc := network.GetNetwork().GetVpc(); vpc != nil { - vpcId = vpc.ExternalId - break - } - } - return vpcId, nil -} - func (self *SBaseGuestDriver) CancelExpireTime( ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest) error { diff --git a/pkg/compute/guestdrivers/managedvirtual.go b/pkg/compute/guestdrivers/managedvirtual.go index 6c559e125c..f55dbeab40 100644 --- a/pkg/compute/guestdrivers/managedvirtual.go +++ b/pkg/compute/guestdrivers/managedvirtual.go @@ -292,6 +292,33 @@ func (self *SManagedVirtualizedGuestDriver) RequestDeployGuestOnHost(ctx context return err } + //创建并同步安全组规则 + { + vpc, err := guest.GetVpc() + if err != nil { + return errors.Wrap(err, "guest.GetVpc") + } + region, err := vpc.GetRegion() + if err != nil { + return errors.Wrap(err, "vpc.GetRegion") + } + + vpcId := region.GetDriver().GetSecurityGroupVpcId(ctx, task.GetUserCred(), region, host, vpc, false) + + secgroups := guest.GetSecgroups() + for i, secgroup := range secgroups { + externalId, err := region.GetDriver().RequestSyncSecurityGroup(ctx, task.GetUserCred(), vpcId, vpc, &secgroup) + if err != nil { + return errors.Wrap(err, "RequestSyncSecurityGroup") + } + + desc.ExternalSecgroupIds = append(desc.ExternalSecgroupIds, externalId) + if i == 0 { + desc.ExternalSecgroupId = externalId + } + } + } + desc.Account = guest.GetDriver().GetLinuxDefaultAccount(desc) if guest.GetDriver().IsNeedInjectPasswordByCloudInit(&desc) { @@ -865,32 +892,24 @@ func (self *SManagedVirtualizedGuestDriver) RequestSyncSecgroupsOnHost(ctx conte if err != nil { return err } - vpcId, err := guest.GetDriver().GetGuestSecgroupVpcid(guest) + + vpc, err := guest.GetVpc() if err != nil { - return err - } - iregion, err := host.GetIRegion() - if err != nil { - return err + return errors.Wrap(err, "guest.GetVpc") } + + region := host.GetRegion() + + vpcId := region.GetDriver().GetSecurityGroupVpcId(ctx, task.GetUserCred(), region, host, vpc, false) + secgroups := guest.GetSecgroups() externalIds := []string{} for _, secgroup := range secgroups { - lockman.LockRawObject(ctx, "secgroupcache", fmt.Sprintf("%s-%s", guest.SecgrpId, vpcId)) - defer lockman.ReleaseRawObject(ctx, "secgroupcache", fmt.Sprintf("%s-%s", guest.SecgrpId, vpcId)) - - secgroupCache, err := models.SecurityGroupCacheManager.Register(ctx, task.GetUserCred(), secgroup.Id, vpcId, host.GetRegion().Id, host.ManagerId) + externalId, err := region.GetDriver().RequestSyncSecurityGroup(ctx, task.GetUserCred(), vpcId, vpc, &secgroup) if err != nil { - return fmt.Errorf("failed to registor secgroupCache for secgroup: %s vpc: %s: %s", secgroup.Id, vpcId, err) + return errors.Wrap(err, "RequestSyncSecurityGroup") } - extID, err := iregion.SyncSecurityGroup(secgroupCache.ExternalId, vpcId, secgroup.Name, secgroup.Description, secgroup.GetSecRules("")) - if err != nil { - return err - } - if err = secgroupCache.SetExternalId(task.GetUserCred(), extID); err != nil { - return err - } - externalIds = append(externalIds, extID) + externalIds = append(externalIds, externalId) } return iVM.SetSecurityGroups(externalIds) } diff --git a/pkg/compute/guestdrivers/openstack.go b/pkg/compute/guestdrivers/openstack.go index f0e4f7425f..303486e63a 100644 --- a/pkg/compute/guestdrivers/openstack.go +++ b/pkg/compute/guestdrivers/openstack.go @@ -146,10 +146,6 @@ func (self *SOpenStackGuestDriver) GetGuestInitialStateAfterRebuild() string { return api.VM_READY } -func (self *SOpenStackGuestDriver) GetGuestSecgroupVpcid(guest *models.SGuest) (string, error) { - return api.NORMAL_VPC_ID, nil -} - func (self *SOpenStackGuestDriver) AllowReconfigGuest() bool { return true } diff --git a/pkg/compute/guestdrivers/qcloud.go b/pkg/compute/guestdrivers/qcloud.go index b08701d104..d8b721d1f7 100644 --- a/pkg/compute/guestdrivers/qcloud.go +++ b/pkg/compute/guestdrivers/qcloud.go @@ -234,10 +234,6 @@ func (self *SQcloudGuestDriver) GetLinuxDefaultAccount(desc cloudprovider.SManag return userName } -func (self *SQcloudGuestDriver) GetGuestSecgroupVpcid(guest *models.SGuest) (string, error) { - return api.NORMAL_VPC_ID, nil -} - func (self *SQcloudGuestDriver) AllowReconfigGuest() bool { return true } diff --git a/pkg/compute/models/cloudproviders.go b/pkg/compute/models/cloudproviders.go index 097b57898c..ea6157390b 100644 --- a/pkg/compute/models/cloudproviders.go +++ b/pkg/compute/models/cloudproviders.go @@ -1164,6 +1164,7 @@ func (self *SCloudprovider) RealDelete(ctx context.Context, userCred mcclient.To SnapshotPolicyManager, StorageManager, StoragecacheManager, + SecurityGroupCacheManager, LoadbalancerManager, LoadbalancerBackendGroupManager, CachedLoadbalancerAclManager, diff --git a/pkg/compute/models/cloudsync.go b/pkg/compute/models/cloudsync.go index 0e2648fa2a..6def6fba98 100644 --- a/pkg/compute/models/cloudsync.go +++ b/pkg/compute/models/cloudsync.go @@ -219,7 +219,9 @@ func syncRegionVPCs(ctx context.Context, userCred mcclient.TokenCredential, sync defer lockman.ReleaseObject(ctx, &localVpcs[j]) syncVpcWires(ctx, userCred, syncResults, provider, &localVpcs[j], remoteVpcs[j], syncRange) - syncVpcSecGroup(ctx, userCred, syncResults, provider, &localVpcs[j], remoteVpcs[j], syncRange) + if localRegion.GetDriver().IsSecurityGroupBelongVpc() || localRegion.GetDriver().IsSupportClassicSecurityGroup() || j == 0 { //有vpc属性的每次都同步,支持classic的vpc也同步,否则仅同步一次 + syncVpcSecGroup(ctx, userCred, syncResults, provider, &localVpcs[j], remoteVpcs[j], syncRange) + } syncVpcRouteTables(ctx, userCred, syncResults, provider, &localVpcs[j], remoteVpcs[j], syncRange) syncVpcNatgateways(ctx, userCred, syncResults, provider, &localVpcs[j], remoteVpcs[j], syncRange) }() diff --git a/pkg/compute/models/guestdrivers.go b/pkg/compute/models/guestdrivers.go index e163dbb400..d02041f647 100644 --- a/pkg/compute/models/guestdrivers.go +++ b/pkg/compute/models/guestdrivers.go @@ -100,7 +100,6 @@ type IGuestDriver interface { RequestSyncConfigOnHost(ctx context.Context, guest *SGuest, host *SHost, task taskman.ITask) error RequestSyncSecgroupsOnHost(ctx context.Context, guest *SGuest, host *SHost, task taskman.ITask) error - GetGuestSecgroupVpcid(guest *SGuest) (string, error) RequestSyncstatusOnHost(ctx context.Context, guest *SGuest, host *SHost, userCred mcclient.TokenCredential) (jsonutils.JSONObject, error) diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 5b1615d5ab..36c1ba81e4 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -3329,58 +3329,6 @@ func (self *SGuest) GetDeployConfigOnHost(ctx context.Context, userCred mcclient config.Add(jsonutils.NewString(onFinish), "on_finish") - if deployAction == "create" && !utils.IsInStringArray(self.Hypervisor, []string{api.HYPERVISOR_KVM, api.HYPERVISOR_BAREMETAL, api.HYPERVISOR_CONTAINER, api.HYPERVISOR_ESXI, api.HYPERVISOR_XEN}) { - nets, err := self.GetNetworks("") - if err != nil || len(nets) == 0 { - return nil, fmt.Errorf("failed to find network for guest %s: %s", self.Name, err) - } - net := nets[0].GetNetwork() - vpc := net.GetVpc() - registerVpcId := vpc.ExternalId - externalVpcId := vpc.ExternalId - switch self.Hypervisor { - case api.HYPERVISOR_ALIYUN, api.HYPERVISOR_HUAWEI, api.HYPERVISOR_UCLOUD: - break - case api.HYPERVISOR_AWS: - break - case api.HYPERVISOR_QCLOUD, api.HYPERVISOR_OPENSTACK: - registerVpcId = "normal" - case api.HYPERVISOR_AZURE: - registerVpcId, externalVpcId = "normal", "normal" - if strings.HasSuffix(host.Name, "-classic") { - registerVpcId, externalVpcId = "classic", "classic" - } - case api.HYPERVISOR_ZSTACK: - break - default: - return nil, fmt.Errorf("Unknown guest %s hypervisor %s for sync secgroup", self.Name, self.Hypervisor) - } - iregion, err := host.GetIRegion() - if err != nil { - return nil, fmt.Errorf("failed to get iregion for host %s error: %v", host.Name, err) - } - secgroupIds := jsonutils.NewArray() - secgroups := self.GetSecgroups() - for i, secgroup := range secgroups { - secgroupCache, err := SecurityGroupCacheManager.Register(ctx, userCred, secgroup.Id, registerVpcId, vpc.CloudregionId, vpc.ManagerId) - if err != nil { - return nil, fmt.Errorf("failed to registor secgroupCache for secgroup: %s(%s), vpc: %s: %s", secgroup.Name, secgroup.Id, vpc.Name, err) - } - - externalSecgroupId, err := iregion.SyncSecurityGroup(secgroupCache.ExternalId, externalVpcId, secgroup.Name, secgroup.Description, secgroup.GetSecRules("")) - if err != nil { - return nil, fmt.Errorf("SyncSecurityGroup fail %s", err) - } - if err := secgroupCache.SetExternalId(userCred, externalSecgroupId); err != nil { - return nil, fmt.Errorf("failed to set externalId for secgroup %s(%s) externalId %s: error: %v", secgroup.Name, secgroup.Id, externalSecgroupId, err) - } - secgroupIds.Add(jsonutils.NewString(externalSecgroupId)) - if i == 0 { - config.Add(jsonutils.NewString(externalSecgroupId), "desc", "external_secgroup_id") - } - } - config.Add(secgroupIds, "desc", "external_secgroup_ids") - } return config, nil } diff --git a/pkg/compute/models/purge.go b/pkg/compute/models/purge.go index ea87badf78..dc5f7e7097 100644 --- a/pkg/compute/models/purge.go +++ b/pkg/compute/models/purge.go @@ -1580,3 +1580,30 @@ func (manager *SElasticcacheManager) purgeAll(ctx context.Context, userCred mccl } return nil } + +func (cache *SSecurityGroupCache) purge(ctx context.Context, userCred mcclient.TokenCredential) error { + lockman.LockObject(ctx, cache) + defer lockman.ReleaseObject(ctx, cache) + + err := cache.ValidateDeleteCondition(ctx) + if err != nil { + return err + } + + return cache.RealDelete(ctx, userCred) +} + +func (manager *SSecurityGroupCacheManager) purgeAll(ctx context.Context, userCred mcclient.TokenCredential, providerId string) error { + caches := []SSecurityGroupCache{} + err := fetchByManagerId(manager, providerId, &caches) + if err != nil { + return err + } + for i := range caches { + err := caches[i].purge(ctx, userCred) + if err != nil { + return err + } + } + return nil +} diff --git a/pkg/compute/models/regiondrivers.go b/pkg/compute/models/regiondrivers.go index 6835e5de61..8d51acc9ff 100644 --- a/pkg/compute/models/regiondrivers.go +++ b/pkg/compute/models/regiondrivers.go @@ -102,6 +102,13 @@ type IRegionDriver interface { RequestBindIPToNatgateway(ctx context.Context, task taskman.ITask, natgateway *SNatGateway, eipId string) error RequestUnBindIPFromNatgateway(ctx context.Context, task taskman.ITask, nat INatHelper, natgateway *SNatGateway) error BindIPToNatgatewayRollback(ctx context.Context, eipId string) error + + 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) + IsSupportClassicSecurityGroup() bool + IsSecurityGroupBelongVpc() bool + GetDefaultSecurityGroupVpcId() string + GetSecurityGroupVpcId(ctx context.Context, userCred mcclient.TokenCredential, region *SCloudregion, host *SHost, vpc *SVpc, classic bool) string } var regionDrivers map[string]IRegionDriver diff --git a/pkg/compute/models/secgroupcache.go b/pkg/compute/models/secgroupcache.go index 2e978975df..a3bce940cb 100644 --- a/pkg/compute/models/secgroupcache.go +++ b/pkg/compute/models/secgroupcache.go @@ -21,37 +21,38 @@ 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/stringutils" "yunion.io/x/sqlchemy" + api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" + "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" ) type SSecurityGroupCacheManager struct { - db.SResourceBaseManager + db.SStatusStandaloneResourceBaseManager } type SSecurityGroupCache struct { - db.SResourceBase + db.SStatusStandaloneResourceBase + db.SExternalizedResourceBase + SCloudregionResourceBase SManagedResourceBase - Id string `width:"128" charset:"ascii" primary:"true" list:"user"` - SecgroupId string `width:"128" charset:"ascii" create:"required"` - VpcId string `width:"128" charset:"ascii" create:"required"` - CloudregionId string `width:"128" charset:"ascii" create:"required"` - ExternalId string `width:"256" charset:"utf8" index:"true" list:"admin" create:"admin_optional"` + SecgroupId string `width:"128" charset:"ascii" list:"user" create:"required"` + VpcId string `width:"128" charset:"ascii" list:"user" create:"required"` } var SecurityGroupCacheManager *SSecurityGroupCacheManager func init() { SecurityGroupCacheManager = &SSecurityGroupCacheManager{ - SResourceBaseManager: db.NewResourceBaseManager( + SStatusStandaloneResourceBaseManager: db.NewStatusStandaloneResourceBaseManager( SSecurityGroupCache{}, "secgroupcache_tbl", "secgroupcache", @@ -61,12 +62,6 @@ func init() { SecurityGroupCacheManager.SetVirtualObject(SecurityGroupCacheManager) } -func (self *SSecurityGroupCache) BeforeInsert() { - if len(self.Id) == 0 { - self.Id = stringutils.UUID4() - } -} - func (manager *SSecurityGroupCacheManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { return false } @@ -79,16 +74,8 @@ func (self *SSecurityGroupCache) AllowUpdateItem(ctx context.Context, userCred m return false } -func (self *SSecurityGroupCache) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return false -} - -func (manager *SSecurityGroupCacheManager) FilterById(q *sqlchemy.SQuery, idStr string) *sqlchemy.SQuery { - return q.Equals("id", idStr) -} - func (manager *SSecurityGroupCacheManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) { - q, err := manager.SResourceBaseManager.ListItemFilter(ctx, q, userCred, query) + q, err := manager.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query) if err != nil { return nil, err } @@ -117,22 +104,29 @@ func (self *SSecurityGroupCache) GetIRegion() (cloudprovider.ICloudRegion, error return nil, fmt.Errorf("failed to find iregion for secgroupcache %s vpc: %s externalId: %s", self.Id, self.VpcId, self.ExternalId) } -func (self *SSecurityGroupCache) DeleteCloudSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential) error { - if len(self.ExternalId) > 0 { - iregion, err := self.GetIRegion() - if err != nil { - return err - } - return iregion.DeleteSecurityGroup(self.VpcId, self.ExternalId) +func (self *SSecurityGroupCache) GetVpc() (*SVpc, error) { + vpc, err := VpcManager.FetchById(self.VpcId) + if err != nil { + return nil, err } - return nil + return vpc.(*SVpc), nil } -func (self *SSecurityGroupCache) Delete(ctx context.Context, userCred mcclient.TokenCredential) error { - if err := self.DeleteCloudSecurityGroup(ctx, userCred); err != nil { - log.Errorf("delete secgroup cache %v error: %v", self, err) +func (self *SSecurityGroupCache) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict { + extra := self.SStandaloneResourceBase.GetCustomizeColumns(ctx, userCred, query) + regionInfo := self.SCloudregionResourceBase.GetCustomizeColumns(ctx, userCred, query) + if regionInfo != nil { + extra.Update(regionInfo) } - return db.DeleteModel(ctx, userCred, self) + accountInfo := self.SManagedResourceBase.GetCustomizeColumns(ctx, userCred, query) + if accountInfo != nil { + extra.Update(accountInfo) + } + vpc, _ := self.GetVpc() + if vpc != nil { + extra.Add(jsonutils.NewString(vpc.Name), "vpc") + } + return extra } func (manager *SSecurityGroupCacheManager) GetSecgroupCache(ctx context.Context, userCred mcclient.TokenCredential, secgroupId, vpcId string, regionId string, providerId string) (*SSecurityGroupCache, error) { @@ -157,12 +151,19 @@ func (manager *SSecurityGroupCacheManager) NewCache(ctx context.Context, userCre lockman.LockClass(ctx, manager, userCred.GetProjectId()) defer lockman.ReleaseClass(ctx, manager, userCred.GetProjectId()) + secgroup, err := SecurityGroupManager.FetchById(secgroupId) + if err != nil { + return nil, errors.Wrapf(err, "SecurityGroupManager.FetchById(%s)", secgroupId) + } + secgroupCache := &SSecurityGroupCache{ - SecgroupId: secgroupId, - VpcId: vpcId, - CloudregionId: regionId, + SecgroupId: secgroupId, + VpcId: vpcId, } secgroupCache.ManagerId = providerId + secgroupCache.Status = api.SECGROUP_CACHE_STATUS_CACHING + secgroupCache.CloudregionId = regionId + secgroupCache.Name = secgroup.GetName() secgroupCache.SetModelManager(manager, secgroupCache) if err := manager.TableSpec().Insert(secgroupCache); err != nil { log.Errorf("insert secgroupcache error: %v", err) @@ -184,8 +185,14 @@ func (manager *SSecurityGroupCacheManager) Register(ctx context.Context, userCre return manager.NewCache(ctx, userCred, secgroupId, vpcId, regionId, providerId) } -func (manager *SSecurityGroupCacheManager) getSecgroupcachesByProvider(provider *SCloudprovider) ([]SSecurityGroupCache, error) { +func (manager *SSecurityGroupCacheManager) getSecgroupcachesByProvider(provider *SCloudprovider, region *SCloudregion, vpcId string) ([]SSecurityGroupCache, error) { q := manager.Query().Equals("manager_id", provider.Id) + if region != nil { + q = q.Equals("cloudregion_id", region.Id) + } + if len(vpcId) > 0 { + q = q.Equals("vpc_id", vpcId) + } caches := []SSecurityGroupCache{} if err := db.FetchModelObjects(manager, q, &caches); err != nil { return nil, err @@ -209,7 +216,22 @@ func (manager *SSecurityGroupCacheManager) SyncSecurityGroupCaches(ctx context.C remoteSecgroups := []cloudprovider.ICloudSecurityGroup{} syncResult := compare.SyncResult{} - dbSecgroupcaches, err := manager.getSecgroupcachesByProvider(provider) + region, err := vpc.GetRegion() + if err != nil { + syncResult.Error(err) + return localSecgroups, remoteSecgroups, syncResult + } + + vpcId := "" + if region.GetDriver().IsSecurityGroupBelongVpc() { + vpcId = vpc.ExternalId + } else if region.GetDriver().IsSupportClassicSecurityGroup() && len(secgroups) > 0 { + vpcId = region.GetDriver().GetSecurityGroupVpcId(ctx, userCred, region, nil, vpc, secgroups[0].GetVpcId() == "classic") + } else { + vpcId = region.GetDriver().GetDefaultSecurityGroupVpcId() + } + + dbSecgroupcaches, err := manager.getSecgroupcachesByProvider(provider, region, vpcId) if err != nil { syncResult.Error(err) return nil, nil, syncResult @@ -225,7 +247,28 @@ func (manager *SSecurityGroupCacheManager) SyncSecurityGroupCaches(ctx context.C return nil, nil, syncResult } - //removed暂时删不了, 因为不能确定是哪个vpc底下的,有可能误删 + for i := 0; i < len(removed); i++ { + err = removed[i].Delete(ctx, userCred) + if err != nil { + syncResult.DeleteError(err) + } else { + syncResult.Delete() + } + } + + 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() + return nil + }) + if err != nil { + syncResult.UpdateError(err) + } else { + syncResult.Update() + } + } //相同的不能同步, 原因: 多个平台的安全组可能共用一个本地安全组,下面仅仅是新加的安全组 for i := 0; i < len(added); i++ { @@ -234,12 +277,19 @@ func (manager *SSecurityGroupCacheManager) SyncSecurityGroupCaches(ctx context.C syncResult.AddError(err) continue } - cache, err := manager.NewCache(ctx, userCred, secgroup.Id, added[i].GetVpcId(), vpc.CloudregionId, provider.Id) + cache, err := manager.NewCache(ctx, userCred, secgroup.Id, vpcId, vpc.CloudregionId, provider.Id) 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)) continue } - if err = cache.SetExternalId(userCred, added[i].GetGlobalId()); err != nil { + _, err = db.Update(cache, func() error { + cache.Status = api.SECGROUP_CACHE_STATUS_READY + cache.Name = added[i].GetName() + cache.Description = added[i].GetDescription() + cache.ExternalId = added[i].GetGlobalId() + return nil + }) + if err != nil { syncResult.AddError(err) continue } @@ -250,18 +300,25 @@ func (manager *SSecurityGroupCacheManager) SyncSecurityGroupCaches(ctx context.C return localSecgroups, remoteSecgroups, syncResult } -func (self *SSecurityGroupCache) SetExternalId(userCred mcclient.TokenCredential, externalId string) error { - diff, err := db.Update(self, func() error { - self.ExternalId = externalId - return nil - }) - if err != nil { - return err - } - db.OpsLog.LogEvent(self, db.ACT_UPDATE, diff, userCred) +func (self *SSecurityGroupCache) Delete(ctx context.Context, userCred mcclient.TokenCredential) error { + log.Infof("do nothing for delete secgroup cache") return nil } -func (self SSecurityGroupCache) GetExternalId() string { - return self.ExternalId +func (self *SSecurityGroupCache) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error { + return self.SStatusStandaloneResourceBase.Delete(ctx, userCred) +} + +func (self *SSecurityGroupCache) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error { + return self.StartSecurityGroupCacheDeleteTask(ctx, userCred, "") +} + +func (self *SSecurityGroupCache) StartSecurityGroupCacheDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error { + self.SetStatus(userCred, api.SECGROUP_CACHE_STATUS_DELETING, "") + task, err := taskman.TaskManager.NewTask(ctx, "SecurityGroupCacheDeleteTask", self, userCred, nil, parentTaskId, "", nil) + if err != nil { + return err + } + task.ScheduleRun(nil) + return nil } diff --git a/pkg/compute/models/secgroups.go b/pkg/compute/models/secgroups.go index 6330f9485b..1ee0a85670 100644 --- a/pkg/compute/models/secgroups.go +++ b/pkg/compute/models/secgroups.go @@ -22,6 +22,7 @@ import ( "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" @@ -31,6 +32,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" + "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" @@ -225,6 +227,7 @@ func (manager *SSecurityGroupManager) ValidateCreateData( if err != nil { return nil, httperrors.NewInputParameterError("Failed to unmarshal input: %v", err) } + input.Status = api.SECGROUP_STATUS_READY for i, rule := range input.Rules { err = rule.Check() @@ -324,6 +327,59 @@ func totalSecurityGroupCount(scope rbacutils.TRbacScope, ownerId mcclient.IIdent return q.CountWithError() } +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") +} + +func (self *SSecurityGroup) PerformUncacheSecgroup(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + cacheV := validators.NewModelIdOrNameValidator("secgroupcache", "secgroupcache", nil) + err := cacheV.Validate(data.(*jsonutils.JSONDict)) + if err != nil { + return nil, err + } + cache := cacheV.Model.(*SSecurityGroupCache) + return nil, cache.StartSecurityGroupCacheDeleteTask(ctx, userCred, "") +} + +func (self *SSecurityGroup) AllowPerformCacheSecgroup(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "cache-secgroup") +} + +func (self *SSecurityGroup) PerformCacheSecgroup(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + vpcV := validators.NewModelIdOrNameValidator("vpc", "vpc", nil) + err := vpcV.Validate(data.(*jsonutils.JSONDict)) + if err != nil { + return nil, err + } + vpc := vpcV.Model.(*SVpc) + if len(vpc.ExternalId) == 0 { + return nil, httperrors.NewInputParameterError("vpc %s(%s) is not a managed resouce", vpc.Name, vpc.Id) + } + + region, err := vpc.GetRegion() + if err != nil { + return nil, err + } + classic, _ := data.Bool("classic") + if classic && !region.GetDriver().IsSupportClassicSecurityGroup() { + return nil, httperrors.NewInputParameterError("Not support cache classic security group") + } + + return nil, self.StartSecurityGroupCacheTask(ctx, userCred, vpc.Id, classic, "") +} + +func (self *SSecurityGroup) StartSecurityGroupCacheTask(ctx context.Context, userCred mcclient.TokenCredential, vpcId string, classic bool, parentTaskId string) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(vpcId), "vpc_id") + params.Add(jsonutils.NewBool(classic), "classic") + task, err := taskman.TaskManager.NewTask(ctx, "SecurityGroupCacheTask", self, userCred, params, parentTaskId, "", nil) + if err != nil { + return err + } + task.ScheduleRun(nil) + return nil +} + func (self *SSecurityGroup) AllowPerformAddRule(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "add-rule") } @@ -641,6 +697,7 @@ func (manager *SSecurityGroupManager) InitializeData() error { secGrp.SetModelManager(manager, secGrp) secGrp.Id = "default" secGrp.Name = "Default" + secGrp.Status = api.SECGROUP_STATUS_READY secGrp.ProjectId = auth.AdminCredential().GetProjectId() secGrp.DomainId = auth.AdminCredential().GetProjectDomainId() // secGrp.IsEmulated = false @@ -680,6 +737,21 @@ func (manager *SSecurityGroupManager) InitializeData() error { return nil }) } + + secgroups := []SSecurityGroup{} + q = SecurityGroupManager.Query().NotEquals("status", api.SECGROUP_STATUS_READY) + err = db.FetchModelObjects(manager, q, &secgroups) + if err != nil { + return errors.Wrap(err, "db.FetchModelObjects") + } + + for i := range secgroups { + db.Update(&secgroups[i], func() error { + secgroups[i].Status = api.SECGROUP_STATUS_READY + return nil + }) + } + return nil } @@ -712,6 +784,7 @@ func (self *SSecurityGroup) CustomizeDelete(ctx context.Context, userCred mcclie } func (self *SSecurityGroup) StartDeleteSecurityGroupTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error { + self.SetStatus(userCred, api.SECGROUP_STATUS_DELETING, "") task, err := taskman.TaskManager.NewTask(ctx, "SecurityGroupDeleteTask", self, userCred, params, parentTaskId, "", nil) if err != nil { return err @@ -721,19 +794,23 @@ func (self *SSecurityGroup) StartDeleteSecurityGroupTask(ctx context.Context, us } func (self *SSecurityGroup) Delete(ctx context.Context, userCred mcclient.TokenCredential) error { - return self.SSharableVirtualResourceBase.DoPendingDelete(ctx, userCred) + log.Infof("do nothing for delete secgroup") + return nil } func (self *SSecurityGroup) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error { rules := []SSecurityGroupRule{} q := SecurityGroupRuleManager.Query().Equals("secgroup_id", self.Id) - if err := db.FetchModelObjects(SecurityGroupRuleManager, q, &rules); err != nil { - log.Errorf("failed to fetch secgroup %s rules error: %v", self.Name, err) - return err + err := db.FetchModelObjects(SecurityGroupRuleManager, q, &rules) + if err != nil { + return errors.Wrap(err, "db.FetchModelObjects") } for i := 0; i < len(rules); i++ { - if err := rules[i].Delete(ctx, userCred); err != nil { - return err + lockman.LockObject(ctx, &rules[i]) + defer lockman.ReleaseObject(ctx, &rules[i]) + err := rules[i].Delete(ctx, userCred) + if err != nil { + return errors.Wrap(err, "rules[i].Delete") } } return self.SVirtualResourceBase.Delete(ctx, userCred) diff --git a/pkg/compute/regiondrivers/aliyun.go b/pkg/compute/regiondrivers/aliyun.go index ed6157879d..9cc6ece56c 100644 --- a/pkg/compute/regiondrivers/aliyun.go +++ b/pkg/compute/regiondrivers/aliyun.go @@ -957,6 +957,9 @@ func (self *SAliyunRegionDriver) RequestUnBindIPFromNatgateway(ctx context.Conte } func (self *SAliyunRegionDriver) BindIPToNatgatewayRollback(ctx context.Context, eipId string) error { - return nil } + +func (self *SAliyunRegionDriver) IsSecurityGroupBelongVpc() bool { + return true +} diff --git a/pkg/compute/regiondrivers/aws.go b/pkg/compute/regiondrivers/aws.go index e8cad3c2b6..0faebbf621 100644 --- a/pkg/compute/regiondrivers/aws.go +++ b/pkg/compute/regiondrivers/aws.go @@ -1209,3 +1209,7 @@ func (self *SAwsRegionDriver) RequestSyncLoadbalancerListener(ctx context.Contex }) return nil } + +func (self *SAwsRegionDriver) IsSecurityGroupBelongVpc() bool { + return true +} diff --git a/pkg/compute/regiondrivers/azure.go b/pkg/compute/regiondrivers/azure.go index cb424b0579..e8ab3e54ce 100644 --- a/pkg/compute/regiondrivers/azure.go +++ b/pkg/compute/regiondrivers/azure.go @@ -48,3 +48,7 @@ func (self *SAzureRegionDriver) ValidateCreateLoadbalancerAclData(ctx context.Co func (self *SAzureRegionDriver) ValidateCreateLoadbalancerCertificateData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { return nil, httperrors.NewNotImplementedError("%s does not currently support creating loadbalancer certificate", self.GetProvider()) } + +func (self *SAzureRegionDriver) IsSupportClassicSecurityGroup() bool { + return true +} diff --git a/pkg/compute/regiondrivers/base.go b/pkg/compute/regiondrivers/base.go index ec104a3995..a0494de77c 100644 --- a/pkg/compute/regiondrivers/base.go +++ b/pkg/compute/regiondrivers/base.go @@ -20,6 +20,7 @@ import ( "yunion.io/x/jsonutils" + api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" @@ -191,3 +192,27 @@ func (self *SBaseRegionDriver) RequestBingToNatgateway(ctx context.Context, task return fmt.Errorf("Not implement RequestBindIPToNatgateway") } + +func (self *SBaseRegionDriver) RequestCacheSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, region *models.SCloudregion, vpc *models.SVpc, secgroup *models.SSecurityGroup, classic bool, task taskman.ITask) error { + return fmt.Errorf("Not Implemented RequestCacheSecurityGroup") +} + +func (self *SBaseRegionDriver) IsSupportClassicSecurityGroup() bool { + return false +} + +func (self *SBaseRegionDriver) IsSecurityGroupBelongVpc() bool { + return false +} + +func (self *SBaseRegionDriver) GetDefaultSecurityGroupVpcId() string { + return api.NORMAL_VPC_ID +} + +func (self *SBaseRegionDriver) GetSecurityGroupVpcId(ctx context.Context, userCred mcclient.TokenCredential, region *models.SCloudregion, host *models.SHost, vpc *models.SVpc, classic bool) string { + return "" +} + +func (self *SBaseRegionDriver) RequestSyncSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, vpcId string, vpc *models.SVpc, secgroup *models.SSecurityGroup) (string, error) { + return "", fmt.Errorf("Not Implemented RequestSyncSecurityGroup") +} diff --git a/pkg/compute/regiondrivers/huawei.go b/pkg/compute/regiondrivers/huawei.go index 4588312993..5db39cb1ab 100644 --- a/pkg/compute/regiondrivers/huawei.go +++ b/pkg/compute/regiondrivers/huawei.go @@ -1526,3 +1526,7 @@ func (self *SHuaWeiRegionDriver) DealNatGatewaySpec(spec string) string { //can't arrive return "" } + +func (self *SHuaWeiRegionDriver) IsSecurityGroupBelongVpc() bool { + return true +} diff --git a/pkg/compute/regiondrivers/kvm.go b/pkg/compute/regiondrivers/kvm.go index bd67db1ffc..a1c481ac09 100644 --- a/pkg/compute/regiondrivers/kvm.go +++ b/pkg/compute/regiondrivers/kvm.go @@ -857,3 +857,7 @@ func (self *SKVMRegionDriver) RequestPreSnapshotPolicyApply(ctx context.Context, func (self *SKVMRegionDriver) BindIPToNatgatewayRollback(ctx context.Context, eipId string) error { return nil } + +func (self *SKVMRegionDriver) ValidateCacheSecgroup(ctx context.Context, userCred mcclient.TokenCredential, secgroup *models.SSecurityGroup, vpc *models.SVpc, classic bool) error { + return fmt.Errorf("No need to cache secgroup for onecloud region") +} diff --git a/pkg/compute/regiondrivers/managedvirtual.go b/pkg/compute/regiondrivers/managedvirtual.go index 5e0022c854..9e6b83ecad 100644 --- a/pkg/compute/regiondrivers/managedvirtual.go +++ b/pkg/compute/regiondrivers/managedvirtual.go @@ -18,6 +18,7 @@ import ( "context" "database/sql" "fmt" + "strings" "time" "yunion.io/x/jsonutils" @@ -1381,3 +1382,83 @@ func (self *SManagedVirtualizationRegionDriver) BindIPToNatgatewayRollback(ctx c } return nil } + +func (self *SManagedVirtualizationRegionDriver) GetSecurityGroupVpcId(ctx context.Context, userCred mcclient.TokenCredential, region *models.SCloudregion, host *models.SHost, vpc *models.SVpc, classic bool) string { + if region.GetDriver().IsSupportClassicSecurityGroup() && (classic || (host != nil && strings.HasSuffix(host.Name, "-classic"))) { + return "classic" + } else if region.GetDriver().IsSecurityGroupBelongVpc() { + return vpc.ExternalId + } + return region.GetDriver().GetDefaultSecurityGroupVpcId() +} + +func (self *SManagedVirtualizationRegionDriver) RequestSyncSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, vpcId string, vpc *models.SVpc, secgroup *models.SSecurityGroup) (string, error) { + lockman.LockRawObject(ctx, "secgroupcache", fmt.Sprintf("%s-%s-%s", secgroup.Id, vpcId, vpc.ManagerId)) + defer lockman.ReleaseRawObject(ctx, "secgroupcache", fmt.Sprintf("%s-%s-%s", secgroup.Id, vpcId, vpc.ManagerId)) + + region, err := vpc.GetRegion() + if err != nil { + return "", errors.Wrap(err, "vpc.GetRegon") + } + + cache, err := models.SecurityGroupCacheManager.Register(ctx, userCred, secgroup.Id, vpcId, region.Id, vpc.ManagerId) + if err != nil { + return "", errors.Wrap(err, "SSecurityGroupCache.Register") + } + + iRegion, err := vpc.GetIRegion() + if err != nil { + return "", errors.Wrap(err, "vpc.GetIRegion") + } + + var iSecgroup cloudprovider.ICloudSecurityGroup = nil + if len(cache.ExternalId) > 0 { + iSecgroup, err = iRegion.GetISecurityGroupById(cache.ExternalId) + if err != nil { + if err != cloudprovider.ErrNotFound { + return "", errors.Wrap(err, "iRegion.GetSecurityGroupById") + } + cache.ExternalId = "" + } + } + + if len(cache.ExternalId) == 0 { + conf := &cloudprovider.SecurityGroupCreateInput{ + Name: secgroup.Name, + Desc: secgroup.Description, + VpcId: vpcId, + Rules: secgroup.GetSecRules(""), + } + iSecgroup, err = iRegion.CreateISecurityGroup(conf) + if err != nil { + return "", errors.Wrap(err, "iRegion.CreateISecurityGroup") + } + } + + _, err = db.Update(cache, func() error { + cache.ExternalId = iSecgroup.GetGlobalId() + cache.Name = iSecgroup.GetName() + cache.Status = api.SECGROUP_CACHE_STATUS_READY + return nil + }) + + if err != nil { + return "", errors.Wrap(err, "db.Update") + } + + err = iSecgroup.SyncRules(secgroup.GetSecRules("")) + if err != nil { + return "", errors.Wrap(err, "iSecgroup.SyncRules") + } + return cache.ExternalId, nil +} + +func (self *SManagedVirtualizationRegionDriver) RequestCacheSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, region *models.SCloudregion, vpc *models.SVpc, secgroup *models.SSecurityGroup, classic bool, task taskman.ITask) error { + + vpcId := region.GetDriver().GetSecurityGroupVpcId(ctx, userCred, region, nil, vpc, classic) + taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { + _, err := self.RequestSyncSecurityGroup(ctx, userCred, vpcId, vpc, secgroup) + return nil, err + }) + return nil +} diff --git a/pkg/compute/tasks/secgroup_group_cache_task.go b/pkg/compute/tasks/secgroup_group_cache_task.go new file mode 100644 index 0000000000..6f85daca3d --- /dev/null +++ b/pkg/compute/tasks/secgroup_group_cache_task.go @@ -0,0 +1,85 @@ +// Copyright 2019 Yunion +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tasks + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" + "yunion.io/x/onecloud/pkg/compute/models" +) + +type SecurityGroupCacheTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(SecurityGroupCacheTask{}) +} + +func (self *SecurityGroupCacheTask) taskFailed(ctx context.Context, secgroup *models.SSecurityGroup, err error) { + self.SetStageFailed(ctx, err.Error()) +} + +func (self *SecurityGroupCacheTask) getVpc() (*models.SVpc, error) { + vpcId, _ := self.GetParams().GetString("vpc_id") + if len(vpcId) == 0 { + return nil, fmt.Errorf("Missing vpc_id params") + } + vpc, err := models.VpcManager.FetchById(vpcId) + if err != nil { + return nil, errors.Wrap(err, "VpcManager.FetchById") + } + return vpc.(*models.SVpc), nil +} + +func (self *SecurityGroupCacheTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + secgroup := obj.(*models.SSecurityGroup) + + vpc, err := self.getVpc() + if err != nil { + self.taskFailed(ctx, secgroup, errors.Wrap(err, "self.getVpc()")) + return + } + + region, err := vpc.GetRegion() + if err != nil { + self.taskFailed(ctx, secgroup, errors.Wrap(err, "vpc.GetRegion")) + return + } + + classic, _ := self.GetParams().Bool("classic") + + self.SetStage("OnCacheSecurityGroupComplete", nil) + + err = region.GetDriver().RequestCacheSecurityGroup(ctx, self.UserCred, region, vpc, secgroup, classic, self) + if err != nil { + self.taskFailed(ctx, secgroup, errors.Wrap(err, "RequestCacheSecgroup")) + return + } +} + +func (self *SecurityGroupCacheTask) OnCacheSecurityGroupComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + self.SetStageComplete(ctx, nil) +} + +func (self *SecurityGroupCacheTask) OnCacheSecurityGroupCompleteFailed(ctx context.Context, obj db.IStandaloneModel, err jsonutils.JSONObject) { + self.SetStageFailed(ctx, err.String()) +} diff --git a/pkg/compute/tasks/security_group_cache_delete_task.go b/pkg/compute/tasks/security_group_cache_delete_task.go new file mode 100644 index 0000000000..e685c0fce3 --- /dev/null +++ b/pkg/compute/tasks/security_group_cache_delete_task.go @@ -0,0 +1,92 @@ +// Copyright 2019 Yunion +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tasks + +import ( + "context" + "database/sql" + + "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 SecurityGroupCacheDeleteTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(SecurityGroupCacheDeleteTask{}) +} + +func (self *SecurityGroupCacheDeleteTask) taskFailed(ctx context.Context, cache *models.SSecurityGroupCache, err error) { + cache.SetStatus(self.UserCred, api.SECGROUP_CACHE_STATUS_DELETE_FAILED, err.Error()) + secgroup, _ := cache.GetSecgroup() + if secgroup != nil { + logclient.AddActionLogWithStartable(self, secgroup, logclient.ACT_DELETE, err, self.UserCred, false) + } + self.SetStageFailed(ctx, err.Error()) +} + +func (self *SecurityGroupCacheDeleteTask) taskComplete(ctx context.Context, cache *models.SSecurityGroupCache) { + cache.RealDelete(ctx, self.UserCred) + self.SetStageComplete(ctx, nil) +} + +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() + if err != nil { + if err == cloudprovider.ErrNotFound { + self.taskComplete(ctx, cache) + return + } + self.taskFailed(ctx, cache, errors.Wrap(err, "cache.GetIRegion")) + return + } + iSecgroup, err := iRegion.GetISecurityGroupById(cache.ExternalId) + if err != nil { + if err == cloudprovider.ErrNotFound { + self.taskComplete(ctx, cache) + return + } + self.taskFailed(ctx, cache, errors.Wrap(err, "iRegion.GetIStoragecacheById")) + return + } + err = iSecgroup.Delete() + if err != nil { + self.taskFailed(ctx, cache, err) + return + } + self.taskComplete(ctx, cache) +} diff --git a/pkg/compute/tasks/security_group_delete_task.go b/pkg/compute/tasks/security_group_delete_task.go index 01a68c2186..a07d34b65b 100644 --- a/pkg/compute/tasks/security_group_delete_task.go +++ b/pkg/compute/tasks/security_group_delete_task.go @@ -19,6 +19,7 @@ import ( "yunion.io/x/jsonutils" + api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" @@ -32,12 +33,37 @@ 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) 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) - secgroupCache := secgroup.GetSecurityGroupCaches() - for _, cache := range secgroupCache { - cache.Delete(ctx, self.GetUserCred()) + secgroupCaches := secgroup.GetSecurityGroupCaches() + 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 } - secgroup.RealDelete(ctx, self.GetUserCred()) - self.SetStageComplete(ctx, nil) + secgroupCaches[errCount].StartSecurityGroupCacheDeleteTask(ctx, self.UserCred, self.GetTaskId()) +} + +func (self *SecurityGroupDeleteTask) OnSecurityGroupUncacheCompleteFailed(ctx context.Context, obj db.IStandaloneModel, err jsonutils.JSONObject) { + self.addErrorCount() } diff --git a/pkg/mcclient/modules/mod_secgroupcaches.go b/pkg/mcclient/modules/mod_secgroupcaches.go new file mode 100644 index 0000000000..0fc4701674 --- /dev/null +++ b/pkg/mcclient/modules/mod_secgroupcaches.go @@ -0,0 +1,31 @@ +// 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 modules + +import "yunion.io/x/onecloud/pkg/mcclient/modulebase" + +var ( + SecGroupCaches modulebase.ResourceManager +) + +func init() { + SecGroupCaches = NewComputeManager("secgroupcache", "secgroupcaches", + []string{"ID", "Name", "Descritpion", "Status", + "Vpc_Id", "Vpc", "Region", "Account", + "Secgroup_Id"}, + []string{""}) + + registerCompute(&SecGroupCaches) +} diff --git a/pkg/multicloud/aliyun/region.go b/pkg/multicloud/aliyun/region.go index 3e7ea701ea..7f07238dce 100644 --- a/pkg/multicloud/aliyun/region.go +++ b/pkg/multicloud/aliyun/region.go @@ -747,6 +747,27 @@ func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) return &eips[0], nil } +func (region *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + secgroup, err := region.GetSecurityGroupDetails(secgroupId) + if err != nil { + return nil, err + } + vpc, err := region.getVpc(secgroup.VpcId) + if err != nil { + return nil, errors.Wrapf(err, "region.getVpc(%s)", secgroup.VpcId) + } + secgroup.vpc = vpc + return secgroup, nil +} + +func (region *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + externalId, err := region.CreateSecurityGroup(conf.VpcId, conf.Name, conf.Desc) + if err != nil { + return nil, err + } + 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) diff --git a/pkg/multicloud/aliyun/securitygroup.go b/pkg/multicloud/aliyun/securitygroup.go index b9a5db3584..aeea79d0f6 100644 --- a/pkg/multicloud/aliyun/securitygroup.go +++ b/pkg/multicloud/aliyun/securitygroup.go @@ -546,7 +546,7 @@ func (self *SRegion) leaveSecurityGroup(secgroupId, instanceId string) error { return err } -func (self *SRegion) DeleteSecurityGroup(vpcId, secGrpId string) error { +func (self *SRegion) DeleteSecurityGroup(secGrpId string) error { params := make(map[string]string) params["SecurityGroupId"] = secGrpId @@ -558,6 +558,14 @@ func (self *SRegion) DeleteSecurityGroup(vpcId, secGrpId string) error { return nil } +func (self *SSecurityGroup) Delete() error { + return self.vpc.region.DeleteSecurityGroup(self.SecurityGroupId) +} + func (self *SSecurityGroup) GetProjectId() string { return "" } + +func (self *SSecurityGroup) SyncRules(rules []secrules.SecurityRule) error { + return self.vpc.region.syncSecgroupRules(self.SecurityGroupId, rules) +} diff --git a/pkg/multicloud/aliyun/vpc.go b/pkg/multicloud/aliyun/vpc.go index f1020e3828..c656594e8d 100644 --- a/pkg/multicloud/aliyun/vpc.go +++ b/pkg/multicloud/aliyun/vpc.go @@ -240,7 +240,7 @@ func (self *SVpc) Delete() error { } for i := 0; i < len(self.secgroups); i += 1 { secgroup := self.secgroups[i].(*SSecurityGroup) - err := self.region.DeleteSecurityGroup(self.VpcId, secgroup.SecurityGroupId) + err := self.region.DeleteSecurityGroup(secgroup.SecurityGroupId) if err != nil { log.Errorf("deleteSecurityGroup for VPC delete fail %s", err) return err diff --git a/pkg/multicloud/aws/region.go b/pkg/multicloud/aws/region.go index ba8f7fa074..d626481c76 100644 --- a/pkg/multicloud/aws/region.go +++ b/pkg/multicloud/aws/region.go @@ -1014,3 +1014,25 @@ func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoad return ret, nil } + +func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + secgroups, total, err := self.GetSecurityGroups("", secgroupId, 0, 1) + if err != nil { + return nil, err + } + if total == 0 { + return nil, cloudprovider.ErrNotFound + } + if total > 1 { + return nil, cloudprovider.ErrDuplicateId + } + return &secgroups[0], nil +} + +func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + groupId, err := self.createSecurityGroup(conf.VpcId, conf.Name, "", conf.Desc) + if err != nil { + return nil, err + } + return self.GetISecurityGroupById(groupId) +} diff --git a/pkg/multicloud/aws/securitygroup.go b/pkg/multicloud/aws/securitygroup.go index 72e70c4475..07914a5a5b 100644 --- a/pkg/multicloud/aws/securitygroup.go +++ b/pkg/multicloud/aws/securitygroup.go @@ -495,3 +495,12 @@ func (self *SRegion) GetSecurityGroups(vpcId string, secgroupId string, offset i 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) Delete() error { + return self.vpc.region.DeleteSecurityGroup(self.SecurityGroupId) +} diff --git a/pkg/multicloud/aws/vpc.go b/pkg/multicloud/aws/vpc.go index edcc2c1054..1d6930a68b 100644 --- a/pkg/multicloud/aws/vpc.go +++ b/pkg/multicloud/aws/vpc.go @@ -291,7 +291,7 @@ func (self *SRegion) assignSecurityGroups(secgroupIds []*string, instanceId stri return nil } -func (self *SRegion) DeleteSecurityGroup(vpcId, secGrpId string) error { +func (self *SRegion) DeleteSecurityGroup(secGrpId string) error { params := &ec2.DeleteSecurityGroupInput{} params.SetGroupId(secGrpId) diff --git a/pkg/multicloud/azure/classic_secruitygroup.go b/pkg/multicloud/azure/classic_secruitygroup.go index d5475f91bc..887697d71f 100644 --- a/pkg/multicloud/azure/classic_secruitygroup.go +++ b/pkg/multicloud/azure/classic_secruitygroup.go @@ -30,6 +30,7 @@ import ( ) type SClassicSecurityGroup struct { + region *SRegion vpc *SClassicVpc Properties ClassicSecurityGroupProperties `json:"properties,omitempty"` ID string @@ -175,7 +176,7 @@ func (self *SClassicSecurityGroup) GetName() string { func (self *SClassicSecurityGroup) GetRules() ([]secrules.SecurityRule, error) { rules := make([]secrules.SecurityRule, 0) - secgrouprules, err := self.vpc.region.getClassicSecurityGroupRules(self.ID) + secgrouprules, err := self.region.getClassicSecurityGroupRules(self.ID) if err != nil { return nil, err } @@ -217,6 +218,7 @@ func (region *SRegion) CreateClassicSecurityGroup(name string) (*SClassicSecurit name = "Default-copy" } secgroup := SClassicSecurityGroup{ + region: region, Name: name, Type: "Microsoft.ClassicNetwork/networkSecurityGroups", Location: region.Name, @@ -248,8 +250,12 @@ func (region *SRegion) deleteClassicSecurityGroup(secgroupId string) error { return region.client.Delete(secgroupId) } +func (self *SClassicSecurityGroup) Delete() error { + return self.region.deleteClassicSecurityGroup(self.ID) +} + func (self *SClassicSecurityGroup) Refresh() error { - sec, err := self.vpc.region.GetClassicSecurityGroupDetails(self.ID) + sec, err := self.region.GetClassicSecurityGroupDetails(self.ID) if err != nil { return err } @@ -377,3 +383,8 @@ func (region *SRegion) syncClassicSecurityGroup(secgroupId, name, desc string, r 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 +} diff --git a/pkg/multicloud/azure/region.go b/pkg/multicloud/azure/region.go index b1a8071790..d2968e9e8b 100644 --- a/pkg/multicloud/azure/region.go +++ b/pkg/multicloud/azure/region.go @@ -530,30 +530,18 @@ func (region *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { return ieips, nil } -func (region *SRegion) DeleteSecurityGroup(vpcId, secgroupId string) error { - if vpcId == "classic" { - return region.deleteClassicSecurityGroup(secgroupId) +func (region *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + if strings.Contains(strings.ToLower(secgroupId), "microsoft.classicnetwork") { + return region.GetClassicSecurityGroupDetails(secgroupId) } - secgroup, err := region.GetSecurityGroupDetails(secgroupId) - if err != nil { - if err == cloudprovider.ErrNotFound { - return nil - } - return err + return region.GetSecurityGroupDetails(secgroupId) +} + +func (region *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + if conf.VpcId == "classic" { + return region.CreateClassicSecurityGroup(conf.Desc) } - if secgroup.Properties.NetworkInterfaces != nil { - for _, nic := range *secgroup.Properties.NetworkInterfaces { - nic, err := region.GetNetworkInterfaceDetail(nic.ID) - if err != nil { - return err - } - nic.Properties.NetworkSecurityGroup = nil - if err := region.client.Update(jsonutils.Marshal(nic), nil); err != nil { - return err - } - } - } - return region.client.Delete(secgroupId) + return region.CreateSecurityGroup(conf.Name) } func (region *SRegion) SyncSecurityGroup(secgroupId, vpcId, name, desc string, rules []secrules.SecurityRule) (string, error) { diff --git a/pkg/multicloud/azure/securitygroup.go b/pkg/multicloud/azure/securitygroup.go index c2b8628df1..3d8d627eaf 100644 --- a/pkg/multicloud/azure/securitygroup.go +++ b/pkg/multicloud/azure/securitygroup.go @@ -82,6 +82,7 @@ type SecurityGroupPropertiesFormat struct { } type SSecurityGroup struct { vpc *SVpc + region *SRegion Properties *SecurityGroupPropertiesFormat `json:"properties,omitempty"` ID string Name string @@ -354,6 +355,7 @@ func (region *SRegion) CreateSecurityGroup(secName string) (*SSecurityGroup, err secName = "Default-copy" } secgroup := SSecurityGroup{ + region: region, Name: secName, Type: "Microsoft.Network/networkSecurityGroups", Location: region.Name, @@ -370,6 +372,7 @@ func (region *SRegion) GetSecurityGroups() ([]SSecurityGroup, error) { result := []SSecurityGroup{} for i := 0; i < len(secgroups); i++ { if secgroups[i].Location == region.Name { + secgroups[i].region = region result = append(result, secgroups[i]) } } @@ -377,12 +380,12 @@ func (region *SRegion) GetSecurityGroups() ([]SSecurityGroup, error) { } func (region *SRegion) GetSecurityGroupDetails(secgroupId string) (*SSecurityGroup, error) { - secgroup := SSecurityGroup{} + secgroup := SSecurityGroup{region: region} return &secgroup, region.client.Get(secgroupId, []string{}, &secgroup) } func (self *SSecurityGroup) Refresh() error { - sec, err := self.vpc.region.GetSecurityGroupDetails(self.ID) + sec, err := self.region.GetSecurityGroupDetails(self.ID) if err != nil { return err } @@ -505,3 +508,24 @@ func (region *SRegion) SetSecurityGroup(instanceId, secgroupId string) error { func (self *SSecurityGroup) GetProjectId() string { return getResourceGroup(self.ID) } + +func (self *SSecurityGroup) Delete() error { + if self.Properties.NetworkInterfaces != nil { + for _, nic := range *self.Properties.NetworkInterfaces { + nic, err := self.region.GetNetworkInterfaceDetail(nic.ID) + if err != nil { + return err + } + nic.Properties.NetworkSecurityGroup = nil + if err := self.region.client.Update(jsonutils.Marshal(nic), nil); err != nil { + return err + } + } + } + return self.region.client.Delete(self.ID) +} + +func (self *SSecurityGroup) SyncRules(rules []secrules.SecurityRule) error { + _, err := self.region.updateSecurityGroupRules(self.ID, rules) + return err +} diff --git a/pkg/multicloud/huawei/region.go b/pkg/multicloud/huawei/region.go index 42e13a2cc9..3a96ab7f83 100644 --- a/pkg/multicloud/huawei/region.go +++ b/pkg/multicloud/huawei/region.go @@ -505,10 +505,18 @@ func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) } // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0060595555.html -func (self *SRegion) DeleteSecurityGroup(vpcId, secgroupId string) error { +func (self *SRegion) DeleteSecurityGroup(secgroupId string) error { return DoDelete(self.ecsClient.SecurityGroups.Delete, secgroupId, nil, nil) } +func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + return self.GetSecurityGroupDetails(secgroupId) +} + +func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + 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) @@ -520,11 +528,11 @@ func (self *SRegion) SyncSecurityGroup(secgroupId string, vpcId string, name str } if len(secgroupId) == 0 { - extID, err := self.CreateSecurityGroup(vpcId, name, desc) + secgroup, err := self.CreateSecurityGroup(vpcId, name, desc) if err != nil { return "", errors.Wrap(err, "self.CreateSecurityGroup") } - secgroupId = extID + secgroupId = secgroup.GetId() } // 华为云默认deny。不需要显式指定 @@ -684,7 +692,7 @@ func (self *SRegion) GetProvider() string { // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090615.html // 目前desc字段并没有用到 -func (self *SRegion) CreateSecurityGroup(vpcId string, name string, desc string) (string, error) { +func (self *SRegion) CreateSecurityGroup(vpcId string, name string, desc string) (*SSecurityGroup, error) { // 华为不允许创建名称为default的安全组 if strings.ToLower(name) == "default" { name = fmt.Sprintf("%s-%s", vpcId, name) @@ -698,9 +706,9 @@ func (self *SRegion) CreateSecurityGroup(vpcId string, name string, desc string) } params.Add(secgroupObj, "security_group") - secgroup := SSecurityGroup{} + secgroup := SSecurityGroup{region: self} err := DoCreate(self.ecsClient.SecurityGroups.Create, params, &secgroup) - return secgroup.GetId(), err + return &secgroup, err } func (self *SRegion) syncSecgroupRules(secgroupId string, rules []secrules.SecurityRule) error { diff --git a/pkg/multicloud/huawei/securitygroup.go b/pkg/multicloud/huawei/securitygroup.go index 4cff034498..a60c30b2cc 100644 --- a/pkg/multicloud/huawei/securitygroup.go +++ b/pkg/multicloud/huawei/securitygroup.go @@ -170,6 +170,9 @@ func (self *SSecurityGroup) GetMetadata() *jsonutils.JSONDict { } func (self *SSecurityGroup) GetDescription() string { + if self.Description == self.VpcID { + return "" + } return self.Description } @@ -332,3 +335,12 @@ func (self *SRegion) GetSecurityGroups(vpcId string) ([]SSecurityGroup, error) { func (self *SSecurityGroup) GetProjectId() string { return "" } + +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) +} diff --git a/pkg/multicloud/huawei/shell/secgroup.go b/pkg/multicloud/huawei/shell/secgroup.go index 1997851249..758b303ee2 100644 --- a/pkg/multicloud/huawei/shell/secgroup.go +++ b/pkg/multicloud/huawei/shell/secgroup.go @@ -43,4 +43,19 @@ func init() { printObject(secgrp) return nil }) + + type SecurityGroupCreateOptions struct { + NAME string `help:"secgroup name"` + VPC string `help:"ID of VPC"` + Desc string `help:"description"` + } + shellutils.R(&SecurityGroupCreateOptions{}, "security-group-create", "Create security group", func(cli *huawei.SRegion, args *SecurityGroupCreateOptions) error { + result, err := cli.CreateSecurityGroup(args.VPC, args.NAME, args.Desc) + if err != nil { + return err + } + printObject(result) + return nil + }) + } diff --git a/pkg/multicloud/objectstore/objectstore.go b/pkg/multicloud/objectstore/objectstore.go index 253236c050..5bd392e375 100644 --- a/pkg/multicloud/objectstore/objectstore.go +++ b/pkg/multicloud/objectstore/objectstore.go @@ -195,10 +195,6 @@ func (cli *SObjectStoreClient) GetIDiskById(id string) (cloudprovider.ICloudDisk return nil, cloudprovider.ErrNotSupported } -func (cli *SObjectStoreClient) DeleteSecurityGroup(vpcId, secgroupId string) error { - return cloudprovider.ErrNotSupported -} - func (cli *SObjectStoreClient) SyncSecurityGroup(secgroupId string, vpcId string, name string, desc string, rules []secrules.SecurityRule) (string, error) { return "", cloudprovider.ErrNotSupported } diff --git a/pkg/multicloud/openstack/region.go b/pkg/multicloud/openstack/region.go index 82537615ce..61bfc30992 100644 --- a/pkg/multicloud/openstack/region.go +++ b/pkg/multicloud/openstack/region.go @@ -527,3 +527,11 @@ func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { return nil, cloudprovider.ErrNotImplemented } + +func (region *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + return region.GetSecurityGroup(secgroupId) +} + +func (region *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + return region.CreateSecurityGroup(conf.Name, conf.Desc) +} diff --git a/pkg/multicloud/openstack/securitygroup.go b/pkg/multicloud/openstack/securitygroup.go index 3715b23a12..81081dcb1f 100644 --- a/pkg/multicloud/openstack/securitygroup.go +++ b/pkg/multicloud/openstack/securitygroup.go @@ -55,7 +55,7 @@ type SSecurityGroupRule struct { } type SSecurityGroup struct { - vpc *SVpc + region *SRegion Description string ID string @@ -88,7 +88,7 @@ func (region *SRegion) GetSecurityGroup(secgroupId string) (*SSecurityGroup, err if err != nil { return nil, err } - secgroup := &SSecurityGroup{} + secgroup := &SSecurityGroup{region: region} return secgroup, resp.Unmarshal(secgroup, "security_group") } @@ -121,6 +121,9 @@ func (region *SRegion) GetSecurityGroups() ([]SSecurityGroup, error) { } } } + for i := range secgroups { + secgroups[i].region = region + } return secgroups, nil } @@ -237,7 +240,7 @@ func (secgroup *SSecurityGroup) IsEmulated() bool { } func (secgroup *SSecurityGroup) Refresh() error { - new, err := secgroup.vpc.region.GetSecurityGroup(secgroup.ID) + new, err := secgroup.region.GetSecurityGroup(secgroup.ID) if err != nil { return err } @@ -419,11 +422,15 @@ func (region *SRegion) addSecurityGroupRules(secgroupId string, rule *secrules.S return err } -func (region *SRegion) DeleteSecurityGroup(vpcId, secGroupId string) error { +func (region *SRegion) DeleteSecurityGroup(secGroupId string) error { _, err := region.Delete("network", "/v2.0/security-groups/"+secGroupId, "") return err } +func (secgroup *SSecurityGroup) Delete() error { + return secgroup.region.DeleteSecurityGroup(secgroup.ID) +} + func (region *SRegion) CreateSecurityGroup(name, description string) (*SSecurityGroup, error) { params := map[string]map[string]interface{}{ "security_group": { @@ -435,10 +442,15 @@ func (region *SRegion) CreateSecurityGroup(name, description string) (*SSecurity if err != nil { return nil, err } - secgroup := &SSecurityGroup{} + secgroup := &SSecurityGroup{region: region} return secgroup, resp.Unmarshal(secgroup, "security_group") } 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 +} diff --git a/pkg/multicloud/openstack/vpc.go b/pkg/multicloud/openstack/vpc.go index 5ce99774f6..785acc08c3 100644 --- a/pkg/multicloud/openstack/vpc.go +++ b/pkg/multicloud/openstack/vpc.go @@ -126,7 +126,7 @@ func (vpc *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, erro } iSecgroups := []cloudprovider.ICloudSecurityGroup{} for i := 0; i < len(secgroups); i++ { - secgroups[i].vpc = vpc + secgroups[i].region = vpc.region iSecgroups = append(iSecgroups, &secgroups[i]) } return iSecgroups, nil diff --git a/pkg/multicloud/qcloud/region.go b/pkg/multicloud/qcloud/region.go index eb17ee169c..3b721c8815 100644 --- a/pkg/multicloud/qcloud/region.go +++ b/pkg/multicloud/qcloud/region.go @@ -796,10 +796,6 @@ func (self *SRegion) instanceOperation(instanceId string, opname string, extra m return err } -func (self *SRegion) DeleteSecurityGroup(vpcId string, secgroupId string) error { - return self.deleteSecurityGroup(secgroupId) -} - func (self *SRegion) GetInstanceVNCUrl(instanceId string) (string, error) { params := make(map[string]string) params["InstanceId"] = instanceId @@ -920,3 +916,11 @@ func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { return region.GetIBucketById(name) } + +func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + return self.GetSecurityGroupDetails(secgroupId) +} + +func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + return self.CreateSecurityGroup(conf.Name, conf.Desc) +} diff --git a/pkg/multicloud/qcloud/securitygroup.go b/pkg/multicloud/qcloud/securitygroup.go index 75b476acc8..90f017e7fa 100644 --- a/pkg/multicloud/qcloud/securitygroup.go +++ b/pkg/multicloud/qcloud/securitygroup.go @@ -31,7 +31,7 @@ import ( ) type SecurityGroupPolicy struct { - vpc *SVpc + region *SRegion PolicyIndex int // 安全组规则索引号。 Protocol string // 协议, 取值: TCP,UDP, ICMP。 Port string // 端口(all, 离散port, range)。 @@ -61,7 +61,7 @@ type SecurityGroupPolicySet struct { } type SSecurityGroup struct { - vpc *SVpc + region *SRegion SecurityGroupId string // 安全组实例ID,例如:sg-ohuuioma。 SecurityGroupName string // 安全组名称,可任意命名,但不得超过60个字符。 SecurityGroupDesc string // 安全组备注,最多100个字符。 @@ -214,7 +214,7 @@ func (self *SecurityGroupPolicy) toRules() []secrules.SecurityRule { } if len(self.AddressTemplate.AddressGroupId) > 0 { - addressGroup, total, err := self.vpc.region.AddressGroupList(self.AddressTemplate.AddressGroupId, "", 0, 1) + addressGroup, total, err := self.region.AddressGroupList(self.AddressTemplate.AddressGroupId, "", 0, 1) if err != nil { log.Errorf("Get AddressList %s failed %v", self.AddressTemplate.AddressId, err) return nil @@ -248,7 +248,7 @@ func (self *SecurityGroupPolicy) toRules() []secrules.SecurityRule { func (self *SecurityGroupPolicy) getAddressRules(rule secrules.SecurityRule, addressId string) ([]secrules.SecurityRule, error) { result := []secrules.SecurityRule{} - address, total, err := self.vpc.region.AddressList(addressId, "", 0, 1) + address, total, err := self.region.AddressList(addressId, "", 0, 1) if err != nil { log.Errorf("Get AddressList %s failed %v", self.AddressTemplate.AddressId, err) return nil, err @@ -268,7 +268,7 @@ func (self *SecurityGroupPolicy) getAddressRules(rule secrules.SecurityRule, add } func (self *SSecurityGroup) GetRules() ([]secrules.SecurityRule, error) { - secgroup, err := self.vpc.region.GetSecurityGroupDetails(self.SecurityGroupId) + secgroup, err := self.region.GetSecurityGroupDetails(self.SecurityGroupId) if err != nil { return nil, err } @@ -282,7 +282,7 @@ func (self *SSecurityGroup) GetRules() ([]secrules.SecurityRule, error) { originRules = append(originRules, secgroup.SecurityGroupPolicySet.Egress...) originRules = append(originRules, secgroup.SecurityGroupPolicySet.Ingress...) for i := 0; i < len(originRules); i++ { - originRules[i].vpc = self.vpc + originRules[i].region = self.region } sort.Sort(SecurityGroupRuleSet(originRules)) rules := []secrules.SecurityRule{} @@ -316,13 +316,18 @@ func (self *SSecurityGroup) IsEmulated() bool { } func (self *SSecurityGroup) Refresh() error { - if new, err := self.vpc.region.GetSecurityGroupDetails(self.SecurityGroupId); err != nil { + if new, err := self.region.GetSecurityGroupDetails(self.SecurityGroupId); err != nil { return err } else { return jsonutils.Update(self, new) } } +func (self *SSecurityGroup) SyncRules(rules []secrules.SecurityRule) error { + _, err := self.region.syncSecgroupRules(self.SecurityGroupId, rules) + return err +} + 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) @@ -455,7 +460,7 @@ func (self *SRegion) GetSecurityGroupDetails(secGroupId string) (*SSecurityGroup return &secgrp, nil } -func (self *SRegion) deleteSecurityGroup(secGroupId string) error { +func (self *SRegion) DeleteSecurityGroup(secGroupId string) error { params := make(map[string]string) params["Region"] = self.Region params["SecurityGroupId"] = secGroupId @@ -547,7 +552,7 @@ func (self *SRegion) CreateSecurityGroup(name, description string) (*SSecurityGr if len(description) == 0 { params["GroupDescription"] = "Customize Create" } - secgroup := SSecurityGroup{} + 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 { @@ -559,3 +564,7 @@ func (self *SRegion) CreateSecurityGroup(name, description string) (*SSecurityGr func (self *SSecurityGroup) GetProjectId() string { return "" } + +func (self *SSecurityGroup) Delete() error { + return self.region.DeleteSecurityGroup(self.SecurityGroupId) +} diff --git a/pkg/multicloud/qcloud/shell/securitygroup.go b/pkg/multicloud/qcloud/shell/securitygroup.go index 25c8f9532c..308c269b73 100644 --- a/pkg/multicloud/qcloud/shell/securitygroup.go +++ b/pkg/multicloud/qcloud/shell/securitygroup.go @@ -46,7 +46,7 @@ func init() { }) shellutils.R(&SecurityGroupOptions{}, "security-group-delete", "Delete SecurityGroup", func(cli *qcloud.SRegion, args *SecurityGroupOptions) error { - return cli.DeleteSecurityGroup("", args.ID) + return cli.DeleteSecurityGroup(args.ID) }) type SecurityGroupCreateOptions struct { diff --git a/pkg/multicloud/qcloud/vpc.go b/pkg/multicloud/qcloud/vpc.go index 855bdea06a..f130112c8c 100644 --- a/pkg/multicloud/qcloud/vpc.go +++ b/pkg/multicloud/qcloud/vpc.go @@ -97,7 +97,7 @@ func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, err } isecgroups := make([]cloudprovider.ICloudSecurityGroup, len(secgroups)) for i := 0; i < len(secgroups); i++ { - secgroups[i].vpc = self + secgroups[i].region = self.region isecgroups[i] = &secgroups[i] } return isecgroups, nil diff --git a/pkg/multicloud/ucloud/region.go b/pkg/multicloud/ucloud/region.go index d2ecfac46f..ed337ac938 100644 --- a/pkg/multicloud/ucloud/region.go +++ b/pkg/multicloud/ucloud/region.go @@ -192,12 +192,24 @@ func (self *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) { } // https://docs.ucloud.cn/api/unet-api/delete_firewall -func (self *SRegion) DeleteSecurityGroup(vpcId, secgroupId string) error { +func (self *SRegion) DeleteSecurityGroup(secgroupId string) error { params := NewUcloudParams() params.Set("FWId", secgroupId) return self.DoAction("DeleteFirewall", params, nil) } +func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + return self.GetSecurityGroupById(secgroupId) +} + +func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + externalId, err := self.CreateDefaultSecurityGroup(conf.Name, conf.Desc) + if err != nil { + return nil, err + } + return self.GetISecurityGroupById(externalId) +} + // https://docs.ucloud.cn/api/unet-api/describe_firewall // 绑定防火墙组的资源类型,默认为全部资源类型。枚举值为:"unatgw",NAT网关; "uhost",云主机; "upm",物理云主机; "hadoophost",hadoop节点; "fortresshost",堡垒机; "udhost",私有专区主机;"udockhost",容器;"dbaudit",数据库审计. // todo: 是否需要过滤出仅绑定云主机的安全组? diff --git a/pkg/multicloud/ucloud/securitygroup.go b/pkg/multicloud/ucloud/securitygroup.go index d413de47d7..eecffb0c37 100644 --- a/pkg/multicloud/ucloud/securitygroup.go +++ b/pkg/multicloud/ucloud/securitygroup.go @@ -258,3 +258,26 @@ func (self *SRegion) GetSecurityGroups(secGroupId string, resourceId string) ([] return secgroups, 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: "", + }} + } + return self.region.syncSecgroupRules(self.FWID, rules) +} + +func (self *SSecurityGroup) Delete() error { + return self.region.DeleteSecurityGroup(self.FWID) +} diff --git a/pkg/multicloud/ucloud/shell/secgroup.go b/pkg/multicloud/ucloud/shell/secgroup.go index 8f62c5d739..d82c269d4c 100644 --- a/pkg/multicloud/ucloud/shell/secgroup.go +++ b/pkg/multicloud/ucloud/shell/secgroup.go @@ -15,6 +15,8 @@ package shell import ( + "fmt" + "yunion.io/x/onecloud/pkg/multicloud/ucloud" "yunion.io/x/onecloud/pkg/util/shellutils" ) @@ -31,10 +33,10 @@ func init() { return nil }) - type SecurityGroupShowOptions struct { + type SecurityGroupIdOptions struct { ID string `help:"ID or name of security group"` } - shellutils.R(&SecurityGroupShowOptions{}, "security-group-show", "Show details of a security group", func(cli *ucloud.SRegion, args *SecurityGroupShowOptions) error { + shellutils.R(&SecurityGroupIdOptions{}, "security-group-show", "Show details of a security group", func(cli *ucloud.SRegion, args *SecurityGroupIdOptions) error { secgrp, err := cli.GetSecurityGroupById(args.ID) if err != nil { return err @@ -42,4 +44,23 @@ func init() { printObject(secgrp) return nil }) + + shellutils.R(&SecurityGroupIdOptions{}, "security-group-delete", "Show details of a security group", func(cli *ucloud.SRegion, args *SecurityGroupIdOptions) error { + return cli.DeleteSecurityGroup(args.ID) + }) + + type SecurityGroupCreateOptions struct { + NAME string `help:"Name of security group"` + Desc string `help:"Description of secgroup"` + } + + shellutils.R(&SecurityGroupCreateOptions{}, "security-group-create", "Create security group", func(cli *ucloud.SRegion, args *SecurityGroupCreateOptions) error { + secgrpId, err := cli.CreateDefaultSecurityGroup(args.NAME, args.Desc) + if err != nil { + return err + } + fmt.Println(secgrpId) + return nil + }) + } diff --git a/pkg/multicloud/zstack/region.go b/pkg/multicloud/zstack/region.go index 2670cbbbf6..68652b451b 100644 --- a/pkg/multicloud/zstack/region.go +++ b/pkg/multicloud/zstack/region.go @@ -290,10 +290,6 @@ func (region *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAc return nil, cloudprovider.ErrNotImplemented } -func (region *SRegion) DeleteSecurityGroup(vpcId, secGrpId string) error { - return cloudprovider.ErrNotImplemented -} - func (region *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { eips, err := region.GetEips("", "") if err != nil { @@ -353,6 +349,14 @@ func (region *SRegion) GetISkuById(skuId string) (cloudprovider.ICloudSku, error return region.GetInstanceOffering(skuId) } +func (region *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + return region.GetSecurityGroup(secgroupId) +} + +func (region *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + 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) diff --git a/pkg/multicloud/zstack/securitygroup.go b/pkg/multicloud/zstack/securitygroup.go index ec3e005dc5..69fae92279 100644 --- a/pkg/multicloud/zstack/securitygroup.go +++ b/pkg/multicloud/zstack/securitygroup.go @@ -265,7 +265,7 @@ func (region *SRegion) DeleteSecurityGroupRules(ruleIds []string) error { } func (region *SRegion) CreateSecurityGroup(name, desc string) (*SSecurityGroup, error) { - secgroup := &SSecurityGroup{} + secgroup := &SSecurityGroup{region: region} params := map[string]map[string]string{ "params": { "name": name, @@ -357,3 +357,11 @@ func (region *SRegion) syncSecgroupRules(secgroupId string, rules []secrules.Sec } return region.AddSecurityGroupRule(secgroupId, addRules) } + +func (self *SSecurityGroup) SyncRules(rules []secrules.SecurityRule) error { + return self.region.syncSecgroupRules(self.UUID, rules) +} + +func (self *SSecurityGroup) Delete() error { + return self.region.client.delete("security-groups", self.UUID, "Permissive") +}