mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-19 02:37:24 +08:00
402 lines
14 KiB
Go
402 lines
14 KiB
Go
// 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"
|
|
"database/sql"
|
|
"strings"
|
|
|
|
"yunion.io/x/jsonutils"
|
|
"yunion.io/x/pkg/errors"
|
|
"yunion.io/x/pkg/util/netutils"
|
|
"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/taskman"
|
|
"yunion.io/x/onecloud/pkg/cloudprovider"
|
|
"yunion.io/x/onecloud/pkg/httperrors"
|
|
"yunion.io/x/onecloud/pkg/mcclient"
|
|
"yunion.io/x/onecloud/pkg/util/stringutils2"
|
|
)
|
|
|
|
type SVpcPeeringConnectionManager struct {
|
|
db.SEnabledStatusInfrasResourceBaseManager
|
|
db.SExternalizedResourceBaseManager
|
|
SVpcResourceBaseManager
|
|
}
|
|
|
|
var VpcPeeringConnectionManager *SVpcPeeringConnectionManager
|
|
|
|
func init() {
|
|
VpcPeeringConnectionManager = &SVpcPeeringConnectionManager{
|
|
SEnabledStatusInfrasResourceBaseManager: db.NewEnabledStatusInfrasResourceBaseManager(
|
|
SVpcPeeringConnection{},
|
|
"vpc_peering_connections_tbl",
|
|
"vpc_peering_connection",
|
|
"vpc_peering_connections",
|
|
),
|
|
}
|
|
VpcPeeringConnectionManager.SetVirtualObject(VpcPeeringConnectionManager)
|
|
}
|
|
|
|
type SVpcPeeringConnection struct {
|
|
db.SEnabledStatusInfrasResourceBase
|
|
db.SExternalizedResourceBase
|
|
|
|
SVpcResourceBase
|
|
ExtPeerVpcId string `width:"36" charset:"ascii" nullable:"true" list:"domain"`
|
|
ExtPeerAccountId string `width:"36" charset:"ascii" nullable:"true" list:"domain"`
|
|
PeerVpcId string `width:"36" charset:"ascii" nullable:"true" list:"domain" create:"required" json:"peer_vpc_id"`
|
|
PeerAccountId string `width:"36" charset:"ascii" nullable:"true" list:"domain"`
|
|
Bandwidth int `nullable:"false" default:"0" list:"user" create:"optional"`
|
|
}
|
|
|
|
func (manager *SVpcPeeringConnectionManager) GetContextManagers() [][]db.IModelManager {
|
|
return [][]db.IModelManager{
|
|
{VpcManager},
|
|
}
|
|
}
|
|
|
|
// 列表
|
|
func (manager *SVpcPeeringConnectionManager) ListItemFilter(
|
|
ctx context.Context,
|
|
q *sqlchemy.SQuery,
|
|
userCred mcclient.TokenCredential,
|
|
query api.VpcPeeringConnectionListInput,
|
|
) (*sqlchemy.SQuery, error) {
|
|
var err error
|
|
q, err = manager.SEnabledStatusInfrasResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusInfrasResourceBaseListInput)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.ListItemFilter")
|
|
}
|
|
|
|
q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
|
|
}
|
|
|
|
q, err = manager.SVpcResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VpcFilterListInput)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemFilter")
|
|
}
|
|
|
|
if len(query.PeerVpcId) > 0 {
|
|
peerVpc, err := VpcManager.FetchByIdOrName(userCred, query.PeerVpcId)
|
|
if err != nil {
|
|
if errors.Cause(err) == sql.ErrNoRows {
|
|
return nil, httperrors.NewResourceNotFoundError2("peer_vpc_id", query.PeerVpcId)
|
|
}
|
|
return nil, httperrors.NewGeneralError(err)
|
|
}
|
|
q = q.Equals("peer_vpc_id", peerVpc.GetId())
|
|
}
|
|
return q, nil
|
|
}
|
|
|
|
// 创建
|
|
func (manager *SVpcPeeringConnectionManager) ValidateCreateData(
|
|
ctx context.Context,
|
|
userCred mcclient.TokenCredential,
|
|
ownerId mcclient.IIdentityProvider,
|
|
query jsonutils.JSONObject,
|
|
input api.VpcPeeringConnectionCreateInput,
|
|
) (api.VpcPeeringConnectionCreateInput, error) {
|
|
var err error
|
|
input.EnabledStatusInfrasResourceBaseCreateInput, err = manager.SEnabledStatusInfrasResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.EnabledStatusInfrasResourceBaseCreateInput)
|
|
if err != nil {
|
|
return input, err
|
|
}
|
|
if len(input.VpcId) == 0 {
|
|
return input, httperrors.NewMissingParameterError("vpc_id")
|
|
}
|
|
|
|
// get vpc ,peerVpc
|
|
_vpc, err := VpcManager.FetchByIdOrName(userCred, input.VpcId)
|
|
if err != nil {
|
|
if errors.Cause(err) == sql.ErrNoRows {
|
|
return input, httperrors.NewResourceNotFoundError2("vpc", input.VpcId)
|
|
}
|
|
return input, httperrors.NewGeneralError(err)
|
|
}
|
|
vpc := _vpc.(*SVpc)
|
|
|
|
_peerVpc, err := VpcManager.FetchByIdOrName(userCred, input.PeerVpcId)
|
|
if err != nil {
|
|
if errors.Cause(err) == sql.ErrNoRows {
|
|
return input, httperrors.NewResourceNotFoundError2("Peervpc", input.PeerVpcId)
|
|
}
|
|
return input, httperrors.NewGeneralError(err)
|
|
}
|
|
peerVpc := _peerVpc.(*SVpc)
|
|
|
|
if len(vpc.ManagerId) == 0 || len(peerVpc.ManagerId) == 0 {
|
|
return input, httperrors.NewInputParameterError("Only public cloud support vpcpeering")
|
|
}
|
|
|
|
// get account,providerFactory
|
|
account := vpc.GetCloudaccount()
|
|
peerAccount := peerVpc.GetCloudaccount()
|
|
if account.Provider != peerAccount.Provider {
|
|
return input, httperrors.NewNotSupportedError("vpc on different cloudprovider peering is not supported")
|
|
}
|
|
|
|
factory, err := cloudprovider.GetProviderFactory(account.Provider)
|
|
if err != nil {
|
|
return input, httperrors.NewGeneralError(errors.Wrapf(err, "cloudprovider.GetProviderFactory(%s)", account.Provider))
|
|
}
|
|
|
|
// check vpc ip range overlap
|
|
if !factory.IsSupportVpcPeeringVpcCidrOverlap() {
|
|
vpcIpv4Ranges := []netutils.IPV4AddrRange{}
|
|
peervpcIpv4Ranges := []netutils.IPV4AddrRange{}
|
|
vpcCidrBlocks := strings.Split(vpc.CidrBlock, ",")
|
|
peervpcCidrBlocks := strings.Split(peerVpc.CidrBlock, ",")
|
|
for i := range vpcCidrBlocks {
|
|
vpcIpv4Range, err := netutils.NewIPV4Prefix(vpcCidrBlocks[i])
|
|
if err != nil {
|
|
return input, httperrors.NewGeneralError(errors.Wrapf(err, "convert vpc cidr %s to ipv4range error", vpcCidrBlocks[i]))
|
|
}
|
|
vpcIpv4Ranges = append(vpcIpv4Ranges, vpcIpv4Range.ToIPRange())
|
|
}
|
|
|
|
for i := range peervpcCidrBlocks {
|
|
peervpcIpv4Range, err := netutils.NewIPV4Prefix(peervpcCidrBlocks[i])
|
|
if err != nil {
|
|
return input, httperrors.NewGeneralError(errors.Wrapf(err, "convert vpc cidr %s to ipv4range error", peervpcCidrBlocks[i]))
|
|
}
|
|
peervpcIpv4Ranges = append(peervpcIpv4Ranges, peervpcIpv4Range.ToIPRange())
|
|
}
|
|
for i := range vpcIpv4Ranges {
|
|
for j := range peervpcIpv4Ranges {
|
|
if vpcIpv4Ranges[i].IsOverlap(peervpcIpv4Ranges[j]) {
|
|
return input, httperrors.NewNotSupportedError("ipv4 range overlap")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CrossCloudEnv := account.AccessUrl != peerAccount.AccessUrl
|
|
CrossRegion := vpc.CloudregionId != peerVpc.CloudregionId
|
|
if CrossCloudEnv && !factory.IsSupportCrossCloudEnvVpcPeering() {
|
|
return input, httperrors.NewNotSupportedError("cloudprovider %s not supported CrossCloud vpcpeering", account.Provider)
|
|
}
|
|
if CrossRegion && !factory.IsSupportCrossRegionVpcPeering() {
|
|
return input, httperrors.NewNotSupportedError("cloudprovider %s not supported CrossRegion vpcpeering", account.Provider)
|
|
}
|
|
if CrossRegion {
|
|
err := factory.ValidateCrossRegionVpcPeeringBandWidth(input.Bandwidth)
|
|
if err != nil {
|
|
return input, err
|
|
}
|
|
}
|
|
|
|
// existed peer check
|
|
vpcPC := SVpcPeeringConnection{}
|
|
err = manager.Query().Equals("vpc_id", vpc.Id).Equals("peer_vpc_id", peerVpc.Id).First(&vpcPC)
|
|
if err == nil {
|
|
return input, httperrors.NewNotSupportedError("vpc %s and vpc %s have already connected", input.VpcId, input.PeerVpcId)
|
|
} else {
|
|
if errors.Cause(err) != sql.ErrNoRows {
|
|
return input, httperrors.NewGeneralError(err)
|
|
}
|
|
}
|
|
|
|
return input, nil
|
|
}
|
|
|
|
func (self *SVpcPeeringConnection) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
|
|
params := jsonutils.NewDict()
|
|
task, err := taskman.TaskManager.NewTask(ctx, "VpcPeeringConnectionCreateTask", self, userCred, params, "", "", nil)
|
|
if err != nil {
|
|
return
|
|
}
|
|
self.SetStatus(userCred, api.VPC_PEERING_CONNECTION_STATUS_CREATING, "")
|
|
task.ScheduleRun(nil)
|
|
}
|
|
|
|
func (manager *SVpcPeeringConnectionManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
|
|
var err error
|
|
|
|
q, err = manager.SInfrasResourceBaseManager.QueryDistinctExtraField(q, field)
|
|
if err == nil {
|
|
return q, nil
|
|
}
|
|
q, err = manager.SVpcResourceBaseManager.QueryDistinctExtraField(q, field)
|
|
if err == nil {
|
|
return q, nil
|
|
}
|
|
|
|
return q, httperrors.ErrNotFound
|
|
}
|
|
|
|
func (self *SVpcPeeringConnection) GetExtraDetails(
|
|
ctx context.Context,
|
|
userCred mcclient.TokenCredential,
|
|
query jsonutils.JSONObject,
|
|
isList bool,
|
|
) (api.VpcPeeringConnectionDetails, error) {
|
|
return api.VpcPeeringConnectionDetails{}, nil
|
|
}
|
|
|
|
func (manager *SVpcPeeringConnectionManager) FetchCustomizeColumns(
|
|
ctx context.Context,
|
|
userCred mcclient.TokenCredential,
|
|
query jsonutils.JSONObject,
|
|
objs []interface{},
|
|
fields stringutils2.SSortedStrings,
|
|
isList bool,
|
|
) []api.VpcPeeringConnectionDetails {
|
|
rows := make([]api.VpcPeeringConnectionDetails, len(objs))
|
|
stdRows := manager.SEnabledStatusInfrasResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
|
vpcIds := make([]string, len(objs))
|
|
peerVpcIds := make([]string, len(objs))
|
|
for i := range rows {
|
|
rows[i] = api.VpcPeeringConnectionDetails{
|
|
EnabledStatusInfrasResourceBaseDetails: stdRows[i],
|
|
}
|
|
vpcPC := objs[i].(*SVpcPeeringConnection)
|
|
vpcIds[i] = vpcPC.VpcId
|
|
peerVpcIds[i] = vpcPC.PeerVpcId
|
|
}
|
|
|
|
vpcMap, err := db.FetchIdNameMap2(VpcManager, vpcIds)
|
|
if err != nil {
|
|
return rows
|
|
}
|
|
peerVpcMap, err := db.FetchIdNameMap2(VpcManager, peerVpcIds)
|
|
if err != nil {
|
|
return rows
|
|
}
|
|
|
|
for i := range rows {
|
|
rows[i].VpcName, _ = vpcMap[vpcIds[i]]
|
|
rows[i].PeerVpcName, _ = peerVpcMap[peerVpcIds[i]]
|
|
}
|
|
return rows
|
|
}
|
|
|
|
func (self *SVpcPeeringConnection) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
|
|
return self.StartDeleteVpcPeeringConnectionTask(ctx, userCred)
|
|
}
|
|
|
|
func (self *SVpcPeeringConnection) StartDeleteVpcPeeringConnectionTask(ctx context.Context, userCred mcclient.TokenCredential) error {
|
|
self.SetStatus(userCred, api.VPC_PEERING_CONNECTION_STATUS_DELETING, "")
|
|
task, err := taskman.TaskManager.NewTask(ctx, "VpcPeeringConnectionDeleteTask", self, userCred, nil, "", "", nil)
|
|
if err != nil {
|
|
return errors.Wrap(err, "Start VpcPeeringConnectionDeleteTask fail")
|
|
}
|
|
task.ScheduleRun(nil)
|
|
return nil
|
|
}
|
|
|
|
func (self *SVpcPeeringConnection) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
|
|
return nil
|
|
}
|
|
|
|
func (self *SVpcPeeringConnection) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
|
|
return self.SEnabledStatusInfrasResourceBase.Delete(ctx, userCred)
|
|
}
|
|
|
|
func (self *SVpcPeeringConnection) AllowPerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
|
|
return db.IsAdminAllowPerform(userCred, self, "syncstatus")
|
|
}
|
|
|
|
// 同步状态
|
|
func (self *SVpcPeeringConnection) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.VpcSyncstatusInput) (jsonutils.JSONObject, error) {
|
|
return nil, StartResourceSyncStatusTask(ctx, userCred, self, "VpcPeeringConnectionSyncstatusTask", "")
|
|
}
|
|
|
|
func (manager *SVpcPeeringConnectionManager) OrderByExtraFields(
|
|
ctx context.Context,
|
|
q *sqlchemy.SQuery,
|
|
userCred mcclient.TokenCredential,
|
|
query api.VpcPeeringConnectionListInput,
|
|
) (*sqlchemy.SQuery, error) {
|
|
var err error
|
|
|
|
q, err = manager.SStatusInfrasResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusInfrasResourceBaseListInput)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SStatusInfrasResourceBaseManager.OrderByExtraFields")
|
|
}
|
|
|
|
q, err = manager.SVpcResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VpcFilterListInput)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SVpcResourceBaseManager.OrderByExtraFields")
|
|
}
|
|
|
|
return q, nil
|
|
}
|
|
|
|
func (manager *SVpcPeeringConnectionManager) ListItemExportKeys(ctx context.Context,
|
|
q *sqlchemy.SQuery,
|
|
userCred mcclient.TokenCredential,
|
|
keys stringutils2.SSortedStrings,
|
|
) (*sqlchemy.SQuery, error) {
|
|
q, err := manager.SEnabledStatusInfrasResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.ListItemExportKeys")
|
|
}
|
|
return q, nil
|
|
}
|
|
|
|
func (self *SVpcPeeringConnection) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.VpcPeeringConnectionUpdateInput) (api.VpcPeeringConnectionUpdateInput, error) {
|
|
var err error
|
|
input.EnabledStatusInfrasResourceBaseUpdateInput, err = self.SEnabledStatusInfrasResourceBase.ValidateUpdateData(ctx, userCred, query, input.EnabledStatusInfrasResourceBaseUpdateInput)
|
|
if err != nil {
|
|
return input, err
|
|
}
|
|
return input, nil
|
|
}
|
|
|
|
func (self *SVpcPeeringConnection) syncRemove(ctx context.Context, userCred mcclient.TokenCredential) error {
|
|
return self.RealDelete(ctx, userCred)
|
|
}
|
|
|
|
func (self *SVpcPeeringConnection) SyncWithCloudPeerConnection(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudVpcPeeringConnection, provider *SCloudprovider) error {
|
|
_, err := db.Update(self, func() error {
|
|
self.Status = ext.GetStatus()
|
|
self.ExternalId = ext.GetGlobalId()
|
|
self.ExtPeerVpcId = ext.GetPeerVpcId()
|
|
self.ExtPeerAccountId = ext.GetPeerAccountId()
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return errors.Wrapf(err, "db.Update")
|
|
}
|
|
if provider != nil {
|
|
SyncCloudDomain(userCred, self, provider.GetOwnerId())
|
|
self.SyncShareState(ctx, userCred, provider.getAccountShareInfo())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (self *SVpcPeeringConnection) GetVpc() (*SVpc, error) {
|
|
vpc, err := VpcManager.FetchById(self.VpcId)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "VpcManager.FetchById(%s)", self.VpcId)
|
|
}
|
|
return vpc.(*SVpc), nil
|
|
}
|
|
|
|
func (self *SVpcPeeringConnection) GetPeerVpc() (*SVpc, error) {
|
|
vpc, err := VpcManager.FetchById(self.PeerVpcId)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "VpcManager.FetchById(%s)", self.VpcId)
|
|
}
|
|
return vpc.(*SVpc), nil
|
|
}
|