From c3e80baef40cf3671b1e16d2352d0406e2830b1c Mon Sep 17 00:00:00 2001 From: ioito Date: Thu, 21 Apr 2022 15:00:24 +0800 Subject: [PATCH] feat(region): ipv6 gateway sync for apsara --- cmd/climc/shell/compute/ipv6_gateways.go | 26 ++ pkg/apis/compute/ipv6_gateway.go | 36 ++ pkg/cloudprovider/consts.go | 23 +- pkg/cloudprovider/resources.go | 9 + pkg/compute/models/cloudsync.go | 29 ++ pkg/compute/models/ipv6_gateways.go | 335 ++++++++++++++++++ pkg/compute/models/networks.go | 13 - pkg/compute/service/handlers.go | 2 + .../modules/compute/mod_ipv6_gateways.go | 31 ++ pkg/mcclient/options/compute/ipv6_gateways.go | 29 ++ pkg/multicloud/apsara/apsara.go | 1 + pkg/multicloud/apsara/ipv6_gateway.go | 132 +++++++ pkg/multicloud/apsara/shell/ipv6_gateway.go | 50 +++ pkg/multicloud/vpc_base.go | 4 + 14 files changed, 696 insertions(+), 24 deletions(-) create mode 100644 cmd/climc/shell/compute/ipv6_gateways.go create mode 100644 pkg/apis/compute/ipv6_gateway.go create mode 100644 pkg/compute/models/ipv6_gateways.go create mode 100644 pkg/mcclient/modules/compute/mod_ipv6_gateways.go create mode 100644 pkg/mcclient/options/compute/ipv6_gateways.go create mode 100644 pkg/multicloud/apsara/ipv6_gateway.go create mode 100644 pkg/multicloud/apsara/shell/ipv6_gateway.go diff --git a/cmd/climc/shell/compute/ipv6_gateways.go b/cmd/climc/shell/compute/ipv6_gateways.go new file mode 100644 index 0000000000..89e3c47eb6 --- /dev/null +++ b/cmd/climc/shell/compute/ipv6_gateways.go @@ -0,0 +1,26 @@ +// Copyright 2019 Yunion +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package compute + +import ( + "yunion.io/x/onecloud/cmd/climc/shell" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" + "yunion.io/x/onecloud/pkg/mcclient/options/compute" +) + +func init() { + cmd := shell.NewResourceCmd(&modules.IPv6Gateways) + cmd.List(&compute.IPv6GatewayListOptions{}) +} diff --git a/pkg/apis/compute/ipv6_gateway.go b/pkg/apis/compute/ipv6_gateway.go new file mode 100644 index 0000000000..08edd4f3ff --- /dev/null +++ b/pkg/apis/compute/ipv6_gateway.go @@ -0,0 +1,36 @@ +// Copyright 2019 Yunion +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package compute + +import "yunion.io/x/onecloud/pkg/apis" + +type IPv6GatewayCreateInput struct { + apis.VirtualResourceCreateInput +} + +type IPv6GatewayUpdateInput struct { + apis.SharableVirtualResourceBaseUpdateInput +} + +type IPv6GatewayListInput struct { + apis.SharableVirtualResourceListInput + apis.ExternalizedResourceBaseListInput + VpcFilterListInput +} + +type IPv6GatewayDetails struct { + apis.SharableVirtualResourceDetails + VpcResourceInfo +} diff --git a/pkg/cloudprovider/consts.go b/pkg/cloudprovider/consts.go index 0150067e26..89948e7826 100644 --- a/pkg/cloudprovider/consts.go +++ b/pkg/cloudprovider/consts.go @@ -56,17 +56,18 @@ const ( CLOUD_CAPABILITY_DNSZONE = "dnszone" CLOUD_CAPABILITY_PUBLIC_IP = "public_ip" CLOUD_CAPABILITY_INTERVPCNETWORK = "intervpcnetwork" - CLOUD_CAPABILITY_SAML_AUTH = "saml_auth" // 是否支持SAML 2.0 - CLOUD_CAPABILITY_QUOTA = "quota" // 配额 - CLOUD_CAPABILITY_NAT = "nat" // NAT网关 - CLOUD_CAPABILITY_NAS = "nas" // NAS - CLOUD_CAPABILITY_WAF = "waf" // WAF - CLOUD_CAPABILITY_MONGO_DB = "mongodb" // MongoDB - CLOUD_CAPABILITY_ES = "es" // ElasticSearch - CLOUD_CAPABILITY_KAFKA = "kafka" // Kafka - CLOUD_CAPABILITY_APP = "app" // App - CLOUD_CAPABILITY_CDN = "cdn" // CDN - CLOUD_CAPABILITY_CONTAINER = "container" // 容器 + CLOUD_CAPABILITY_SAML_AUTH = "saml_auth" // 是否支持SAML 2.0 + CLOUD_CAPABILITY_QUOTA = "quota" // 配额 + CLOUD_CAPABILITY_NAT = "nat" // NAT网关 + CLOUD_CAPABILITY_NAS = "nas" // NAS + CLOUD_CAPABILITY_WAF = "waf" // WAF + CLOUD_CAPABILITY_MONGO_DB = "mongodb" // MongoDB + CLOUD_CAPABILITY_ES = "es" // ElasticSearch + CLOUD_CAPABILITY_KAFKA = "kafka" // Kafka + CLOUD_CAPABILITY_APP = "app" // App + CLOUD_CAPABILITY_CDN = "cdn" // CDN + CLOUD_CAPABILITY_CONTAINER = "container" // 容器 + CLOUD_CAPABILITY_IPV6_GATEWAY = "ipv6_gateway" // IPv6网关 ) const ( diff --git a/pkg/cloudprovider/resources.go b/pkg/cloudprovider/resources.go index 4c7c644518..bf54cf600f 100644 --- a/pkg/cloudprovider/resources.go +++ b/pkg/cloudprovider/resources.go @@ -553,6 +553,13 @@ type ICloudGlobalVpc interface { Delete() error } +type ICloudIPv6Gateway interface { + IVirtualResource + + GetCreatedAt() time.Time + GetInstanceType() string +} + type ICloudVpc interface { ICloudResource @@ -585,6 +592,8 @@ type ICloudVpc interface { GetAuthorityOwnerId() string ProposeJoinICloudInterVpcNetwork(opts *SVpcJointInterVpcNetworkOption) error + + GetICloudIPv6Gateways() ([]ICloudIPv6Gateway, error) } type ICloudInternetGateway interface { diff --git a/pkg/compute/models/cloudsync.go b/pkg/compute/models/cloudsync.go index e0af5db09a..f3db6e3721 100644 --- a/pkg/compute/models/cloudsync.go +++ b/pkg/compute/models/cloudsync.go @@ -283,6 +283,7 @@ func syncRegionVPCs(ctx context.Context, userCred mcclient.TokenCredential, sync syncVpcNatgateways(ctx, userCred, syncResults, provider, &localVpcs[j], remoteVpcs[j], syncRange) syncVpcPeerConnections(ctx, userCred, syncResults, provider, &localVpcs[j], remoteVpcs[j], syncRange) syncVpcRouteTables(ctx, userCred, syncResults, provider, &localVpcs[j], remoteVpcs[j], syncRange) + syncIPv6Gateways(ctx, userCred, syncResults, provider, &localVpcs[j], remoteVpcs[j], syncRange) }() } } @@ -460,12 +461,40 @@ func syncVpcRouteTables(ctx context.Context, userCred mcclient.TokenCredential, } } +func syncIPv6Gateways(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, provider *SCloudprovider, localVpc *SVpc, remoteVpc cloudprovider.ICloudVpc, syncRange *SSyncRange) { + exts, err := func() ([]cloudprovider.ICloudIPv6Gateway, error) { + defer syncResults.AddRequestCost(IPv6GatewayManager)() + return remoteVpc.GetICloudIPv6Gateways() + }() + if err != nil { + msg := fmt.Sprintf("GetICloudIPv6Gateways for vpc %s failed %s", remoteVpc.GetId(), err) + log.Errorf(msg) + return + } + result := func() compare.SyncResult { + defer syncResults.AddSqlCost(IPv6GatewayManager)() + return localVpc.SyncIPv6Gateways(ctx, userCred, exts, provider) + }() + + syncResults.Add(IPv6GatewayManager, result) + + msg := result.Result() + notes := fmt.Sprintf("SyncIPv6Gateways for VPC %s result: %s", localVpc.Name, msg) + log.Infof(notes) + if result.IsError() { + return + } +} + func syncVpcNatgateways(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, provider *SCloudprovider, localVpc *SVpc, remoteVpc cloudprovider.ICloudVpc, syncRange *SSyncRange) { natGateways, err := func() ([]cloudprovider.ICloudNatGateway, error) { defer syncResults.AddRequestCost(NatGatewayManager)() return remoteVpc.GetINatGateways() }() if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotImplemented { + return + } msg := fmt.Sprintf("GetINatGateways for vpc %s failed %s", remoteVpc.GetId(), err) log.Errorf(msg) return diff --git a/pkg/compute/models/ipv6_gateways.go b/pkg/compute/models/ipv6_gateways.go new file mode 100644 index 0000000000..ea6dec4679 --- /dev/null +++ b/pkg/compute/models/ipv6_gateways.go @@ -0,0 +1,335 @@ +// 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 models + +import ( + "context" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/compare" + "yunion.io/x/sqlchemy" + + "yunion.io/x/onecloud/pkg/apis" + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" + "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" + "yunion.io/x/onecloud/pkg/cloudcommon/policy" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) + +type SIPv6GatewayManager struct { + db.SSharableVirtualResourceBaseManager + db.SExternalizedResourceBaseManager + SVpcResourceBaseManager +} + +var IPv6GatewayManager *SIPv6GatewayManager + +func init() { + IPv6GatewayManager = &SIPv6GatewayManager{ + SSharableVirtualResourceBaseManager: db.NewSharableVirtualResourceBaseManager( + SIPv6Gateway{}, + "ipv6_gateways_tbl", + "ipv6_gateway", + "ipv6_gateways", + ), + } + IPv6GatewayManager.SetVirtualObject(IPv6GatewayManager) +} + +type SIPv6Gateway struct { + db.SSharableVirtualResourceBase + db.SExternalizedResourceBase + + SVpcResourceBase `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` + + InstanceType string `width:"64" charset:"utf8" nullable:"true" list:"user" create:"optional"` +} + +func (manager *SIPv6GatewayManager) GetContextManagers() [][]db.IModelManager { + return [][]db.IModelManager{ + {VpcManager}, + } +} + +func (self *SIPv6Gateway) ValidateDeleteCondition(ctx context.Context, data *api.IPv6GatewayDetails) error { + return self.SSharableVirtualResourceBase.ValidateDeleteCondition(ctx, nil) +} + +func (self *SVpc) GetIPv6Gateways() ([]SIPv6Gateway, error) { + q := IPv6GatewayManager.Query().Equals("vpc_id", self.Id) + ret := []SIPv6Gateway{} + err := db.FetchModelObjects(IPv6GatewayManager, q, &ret) + return ret, err +} + +func (self *SVpc) SyncIPv6Gateways(ctx context.Context, userCred mcclient.TokenCredential, exts []cloudprovider.ICloudIPv6Gateway, provider *SCloudprovider) compare.SyncResult { + lockman.LockRawObject(ctx, IPv6GatewayManager.Keyword(), self.Id) + defer lockman.ReleaseRawObject(ctx, IPv6GatewayManager.Keyword(), self.Id) + + result := compare.SyncResult{} + + dbRes, err := self.GetIPv6Gateways() + if err != nil { + result.Error(err) + return result + } + + removed := make([]SIPv6Gateway, 0) + commondb := make([]SIPv6Gateway, 0) + commonext := make([]cloudprovider.ICloudIPv6Gateway, 0) + added := make([]cloudprovider.ICloudIPv6Gateway, 0) + + err = compare.CompareSets(dbRes, exts, &removed, &commondb, &commonext, &added) + if err != nil { + result.Error(err) + return result + } + + for i := 0; i < len(removed); i += 1 { + err = removed[i].syncRemoveCloudIPv6Gateway(ctx, userCred) + if err != nil { + result.DeleteError(err) + } else { + result.Delete() + } + } + for i := 0; i < len(commondb); i += 1 { + err = commondb[i].SyncWithCloudIPv6Gateway(ctx, userCred, commonext[i], provider) + if err != nil { + result.UpdateError(err) + continue + } + result.Update() + } + for i := 0; i < len(added); i += 1 { + _, err := self.newFromCloudIPv6Gateway(ctx, userCred, added[i], provider) + if err != nil { + result.AddError(err) + continue + } + result.Add() + } + + return result +} + +func (self *SIPv6Gateway) syncRemoveCloudIPv6Gateway(ctx context.Context, userCred mcclient.TokenCredential) error { + lockman.LockObject(ctx, self) + defer lockman.ReleaseObject(ctx, self) + + err := self.ValidateDeleteCondition(ctx, nil) + if err != nil { // cannot delete + self.SetStatus(userCred, api.NETWORK_STATUS_UNKNOWN, "Sync to remove") + return err + } + return self.RealDelete(ctx, userCred) +} + +func (self *SIPv6Gateway) SyncWithCloudIPv6Gateway(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudIPv6Gateway, provider *SCloudprovider) error { + diff, err := db.Update(self, func() error { + self.Status = ext.GetStatus() + self.InstanceType = ext.GetInstanceType() + return nil + }) + if err != nil { + return errors.Wrapf(err, "db.Update") + } + db.OpsLog.LogSyncUpdate(self, diff, userCred) + if len(diff) > 0 { + notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{ + Obj: self, + Action: notifyclient.ActionSyncUpdate, + }) + } + + syncVirtualResourceMetadata(ctx, userCred, self, ext) + SyncCloudProject(userCred, self, provider.GetOwnerId(), ext, provider.Id) + return nil +} + +func (self *SVpc) newFromCloudIPv6Gateway(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudIPv6Gateway, provider *SCloudprovider) (*SIPv6Gateway, error) { + ret := &SIPv6Gateway{} + ret.SetModelManager(IPv6GatewayManager, ret) + + ret.Status = ext.GetStatus() + ret.ExternalId = ext.GetGlobalId() + ret.VpcId = self.Id + ret.InstanceType = ext.GetInstanceType() + + if createdAt := ext.GetCreatedAt(); !createdAt.IsZero() { + ret.CreatedAt = createdAt + } + + var err = func() error { + lockman.LockRawObject(ctx, IPv6GatewayManager.Keyword(), "name") + defer lockman.ReleaseRawObject(ctx, IPv6GatewayManager.Keyword(), "name") + + newName, err := db.GenerateName(ctx, IPv6GatewayManager, provider.GetOwnerId(), ext.GetName()) + if err != nil { + return err + } + ret.Name = newName + return IPv6GatewayManager.TableSpec().Insert(ctx, &ret) + }() + if err != nil { + return nil, errors.Wrapf(err, "Insert") + } + + syncVirtualResourceMetadata(ctx, userCred, ret, ext) + SyncCloudProject(userCred, ret, provider.GetOwnerId(), ext, self.ManagerId) + + db.OpsLog.LogEvent(ret, db.ACT_CREATE, ret.GetShortDesc(ctx), userCred) + notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{ + Obj: ret, + Action: notifyclient.ActionSyncCreate, + }) + + return ret, nil +} + +func (manager *SIPv6GatewayManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.IPv6GatewayDetails { + rows := make([]api.IPv6GatewayDetails, len(objs)) + + virtRows := manager.SSharableVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + vpcRows := manager.SVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.IPv6GatewayDetails{ + SharableVirtualResourceDetails: virtRows[i], + VpcResourceInfo: vpcRows[i], + } + } + return rows +} + +func (manager *SIPv6GatewayManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.IPv6GatewayCreateInput) (api.IPv6GatewayCreateInput, error) { + return input, httperrors.NewNotImplementedError("ValidateCreateData") +} + +func (self *SIPv6Gateway) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.IPv6GatewayUpdateInput) (api.IPv6GatewayUpdateInput, error) { + return input, httperrors.NewNotImplementedError("ValidateCreateData") +} + +func (self *SIPv6Gateway) Delete(ctx context.Context, userCred mcclient.TokenCredential) error { + self.SetStatus(userCred, apis.STATUS_DELETING, "") + return nil +} + +func (self *SIPv6Gateway) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error { + db.OpsLog.LogEvent(self, db.ACT_DELOCATE, self.GetShortDesc(ctx), userCred) + return self.SSharableVirtualResourceBase.Delete(ctx, userCred) +} + +// IPv6网关列表 +func (manager *SIPv6GatewayManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.IPv6GatewayListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SSharableVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, input.SharableVirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ListItemFilter") + } + q, err = manager.SVpcResourceBaseManager.ListItemFilter(ctx, q, userCred, input.VpcFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemFilter") + } + + q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, input.ExternalizedResourceBaseListInput) + if err != nil { + return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter") + } + + return q, nil +} + +func (manager *SIPv6GatewayManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.IPv6GatewayListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SSharableVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.SharableVirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SIPv6GatewayManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SSharableVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (self *SIPv6Gateway) ValidateUpdateCondition(ctx context.Context) error { + return self.SSharableVirtualResourceBase.ValidateUpdateCondition(ctx) +} + +func (self *SIPv6Gateway) GetChangeOwnerCandidateDomainIds() []string { + candidates := [][]string{} + vpc, _ := self.GetVpc() + if vpc != nil { + candidates = append(candidates, vpc.GetChangeOwnerCandidateDomainIds()) + } + return db.ISharableMergeChangeOwnerCandidateDomainIds(self, candidates...) +} + +func (manager *SIPv6GatewayManager) ListItemExportKeys(ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + keys stringutils2.SSortedStrings, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SSharableVirtualResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys) + if err != nil { + return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ListItemExportKeys") + } + if keys.ContainsAny(manager.SVpcResourceBaseManager.GetExportKeys()...) { + q, err = manager.SVpcResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys) + if err != nil { + return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemExportKeys") + } + } + return q, nil +} + +func (manager *SIPv6GatewayManager) AllowScope(userCred mcclient.TokenCredential) rbacutils.TRbacScope { + scope, _ := policy.PolicyManager.AllowScope(userCred, api.SERVICE_TYPE, IPv6GatewayManager.KeywordPlural(), policy.PolicyActionGet) + return scope +} diff --git a/pkg/compute/models/networks.go b/pkg/compute/models/networks.go index 9290ca86a7..5e65e384c6 100644 --- a/pkg/compute/models/networks.go +++ b/pkg/compute/models/networks.go @@ -12,19 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// -// 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 models import ( diff --git a/pkg/compute/service/handlers.go b/pkg/compute/service/handlers.go index 40a38083e5..277ec116b3 100644 --- a/pkg/compute/service/handlers.go +++ b/pkg/compute/service/handlers.go @@ -237,6 +237,8 @@ func InitHandlers(app *appsrv.Application) { models.BackupStorageManager, models.DiskBackupManager, models.InstanceBackupManager, + + models.IPv6GatewayManager, } { db.RegisterModelManager(manager) handler := db.NewModelHandler(manager) diff --git a/pkg/mcclient/modules/compute/mod_ipv6_gateways.go b/pkg/mcclient/modules/compute/mod_ipv6_gateways.go new file mode 100644 index 0000000000..7991521ec3 --- /dev/null +++ b/pkg/mcclient/modules/compute/mod_ipv6_gateways.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 compute + +import ( + "yunion.io/x/onecloud/pkg/mcclient/modulebase" + "yunion.io/x/onecloud/pkg/mcclient/modules" +) + +var ( + IPv6Gateways modulebase.ResourceManager +) + +func init() { + IPv6Gateways = modules.NewComputeManager("ipv6_gateway", "ipv6_gateways", + []string{}, + []string{}) + modules.RegisterCompute(&IPv6Gateways) +} diff --git a/pkg/mcclient/options/compute/ipv6_gateways.go b/pkg/mcclient/options/compute/ipv6_gateways.go new file mode 100644 index 0000000000..0ed21943d0 --- /dev/null +++ b/pkg/mcclient/options/compute/ipv6_gateways.go @@ -0,0 +1,29 @@ +// Copyright 2019 Yunion +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package compute + +import ( + "yunion.io/x/jsonutils" + + "yunion.io/x/onecloud/pkg/mcclient/options" +) + +type IPv6GatewayListOptions struct { + options.BaseListOptions +} + +func (opts *IPv6GatewayListOptions) Params() (jsonutils.JSONObject, error) { + return options.ListStructToParams(opts) +} diff --git a/pkg/multicloud/apsara/apsara.go b/pkg/multicloud/apsara/apsara.go index 80593454ae..3385a3eae7 100644 --- a/pkg/multicloud/apsara/apsara.go +++ b/pkg/multicloud/apsara/apsara.go @@ -490,6 +490,7 @@ func (region *SApsaraClient) GetCapabilities() []string { cloudprovider.CLOUD_CAPABILITY_RDS, cloudprovider.CLOUD_CAPABILITY_CACHE, cloudprovider.CLOUD_CAPABILITY_QUOTA + cloudprovider.READ_ONLY_SUFFIX, + cloudprovider.CLOUD_CAPABILITY_IPV6_GATEWAY + cloudprovider.READ_ONLY_SUFFIX, } return caps } diff --git a/pkg/multicloud/apsara/ipv6_gateway.go b/pkg/multicloud/apsara/ipv6_gateway.go new file mode 100644 index 0000000000..59d336a869 --- /dev/null +++ b/pkg/multicloud/apsara/ipv6_gateway.go @@ -0,0 +1,132 @@ +// 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 apsara + +import ( + "fmt" + "time" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud" +) + +type SIPv6Gateway struct { + multicloud.SResourceBase + multicloud.ApsaraTags + region *SRegion + + Status string `json:"Status"` + Description string `json:"Description"` + InstanceChargeType string `json:"InstanceChargeType"` + Ipv6GatewayId string `json:"Ipv6GatewayId"` + BusinessStatus string `json:"BusinessStatus"` + Name string `json:"Name"` + VpcID string `json:"VpcId"` + ExpiredTime string `json:"ExpiredTime"` + CreationTime time.Time `json:"CreationTime"` + RegionId string `json:"RegionId"` + Spec string `json:"Spec"` + + DepartmentInfo +} + +func (self *SIPv6Gateway) GetGlobalId() string { + return self.Ipv6GatewayId +} + +func (self *SIPv6Gateway) GetId() string { + return self.Ipv6GatewayId +} + +func (self *SIPv6Gateway) GetName() string { + if len(self.Name) > 0 { + return self.Name + } + return self.Ipv6GatewayId +} + +func (self *SIPv6Gateway) GetStatus() string { + return self.Status +} + +func (self *SIPv6Gateway) GetInstanceType() string { + return self.Spec +} + +func (self *SIPv6Gateway) GetCreatedAt() time.Time { + return self.CreationTime +} + +func (self *SRegion) GetIPv6Gateways(vpcId string, pageNumber, pageSize int) ([]SIPv6Gateway, int, error) { + if pageSize < 1 { + pageSize = 50 + } + if pageNumber < 1 { + pageNumber = 1 + } + params := map[string]string{ + "PageSize": fmt.Sprintf("%d", pageSize), + "PageNumber": fmt.Sprintf("%d", 1), + } + if len(vpcId) > 0 { + params["VpcId"] = vpcId + } + resp, err := self.vpcRequest("DescribeIpv6Gateways", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "DescribeIpv6Gateways") + } + ret := []SIPv6Gateway{} + err = resp.Unmarshal(&ret, "Ipv6Gateways", "Ipv6Gateway") + if err != nil { + return nil, 0, errors.Wrapf(err, "resp.Unmarshal") + } + totalCount, _ := resp.Int("TotalCount") + return ret, int(totalCount), nil +} + +func (self *SRegion) GetIPv6Gateway(id string) (*SIPv6Gateway, error) { + params := map[string]string{ + "Ipv6GatewayId": id, + } + resp, err := self.vpcRequest("DescribeIpv6GatewayAttribute", params) + if err != nil { + return nil, err + } + ret := &SIPv6Gateway{region: self} + return ret, resp.Unmarshal(ret) +} + +func (self *SVpc) GetICloudIPv6Gateways() ([]cloudprovider.ICloudIPv6Gateway, error) { + res, pageNumber := []SIPv6Gateway{}, 1 + for { + part, total, err := self.region.GetIPv6Gateways(self.VpcId, pageNumber, 50) + if err != nil { + return nil, err + } + res = append(res, part...) + if len(res) >= total { + break + } + pageNumber++ + } + ret := []cloudprovider.ICloudIPv6Gateway{} + for i := range res { + res[i].region = self.region + ret = append(ret, &res[i]) + } + return ret, nil +} diff --git a/pkg/multicloud/apsara/shell/ipv6_gateway.go b/pkg/multicloud/apsara/shell/ipv6_gateway.go new file mode 100644 index 0000000000..380d7e8476 --- /dev/null +++ b/pkg/multicloud/apsara/shell/ipv6_gateway.go @@ -0,0 +1,50 @@ +// 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/multicloud/apsara" + "yunion.io/x/onecloud/pkg/util/shellutils" +) + +func init() { + type IPv6GatewayListOptions struct { + VpcId string + PageSize int `default:"10"` + PageNumber int `default:"1"` + } + shellutils.R(&IPv6GatewayListOptions{}, "ipv6-gateway-list", "List IPv6 gateways", func(cli *apsara.SRegion, args *IPv6GatewayListOptions) error { + gateways, _, err := cli.GetIPv6Gateways(args.VpcId, args.PageNumber, args.PageSize) + if err != nil { + return err + } + printList(gateways, 0, 0, 0, []string{}) + return nil + }) + + type IPv6GatewayIdOptions struct { + ID string + } + + shellutils.R(&IPv6GatewayIdOptions{}, "ipv6-gateway-show", "Show IPv6 gateway", func(cli *apsara.SRegion, args *IPv6GatewayIdOptions) error { + gateway, err := cli.GetIPv6Gateway(args.ID) + if err != nil { + return err + } + printObject(gateway) + return nil + }) + +} diff --git a/pkg/multicloud/vpc_base.go b/pkg/multicloud/vpc_base.go index f1f8cc2d16..d187628ef2 100644 --- a/pkg/multicloud/vpc_base.go +++ b/pkg/multicloud/vpc_base.go @@ -88,3 +88,7 @@ func (self *SVpc) CreateIWire(opts *cloudprovider.SWireCreateOptions) (cloudprov func (self *SVpc) GetGlobalVpcId() string { return "" } + +func (self *SVpc) GetICloudIPv6Gateways() ([]cloudprovider.ICloudIPv6Gateway, error) { + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetICloudIPv6Gateways") +}