fix: 结构化network create list 参数

This commit is contained in:
Qu Xuan
2019-11-28 21:43:45 +08:00
parent ef9f4e341a
commit 06bc27527e
16 changed files with 894 additions and 184 deletions

View File

@@ -0,0 +1,60 @@
// 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
type CloudproviderDetails struct {
Provider string `json:"provider,omitempty"`
Brand string `json:"brand,omitempty"`
Account string `json:"account,omitempty"`
AccountId string `json:"account_id,omitempty"`
Manager string `json:"manager,omitempty"`
ManagerId string `json:"manager_id,omitempty"`
ManagerProject string `json:"manager_project,omitempty"`
ManagerProjectId string `json:"manager_project_id,omitempty"`
ManagerDomain string `json:"manager_domain,omitempty"`
ManagerDomainId string `json:"manager_domain_id,omitempty"`
Region string `json:"region,omitempty"`
RegionId string `json:"region_id,omitempty"`
CloudregionId string `json:"cloudregion_id,omitempty"`
RegionExternalId string `json:"region_external_id,omitempty"`
RegionExtId string `json:"region_ext_id,omitempty"`
Zone string `json:"zone,omitempty"`
ZoneId string `json:"zone_id,omitempty"`
ZoneExtId string `json:"zone_ext_id,omitempty"`
CloudEnv string `json:"cloud_env,omitempty"`
}
type CloudaccountListInput struct {
// List objects belonging to the cloud provider
Cloudprovider string `json:"cloudprovider"`
// List objects belonging to the cloud account
Cloudaccount string `json:"cloudprovider"`
// List objects from the providers, choices:"OneCloud|VMware|Aliyun|Qcloud|Azure|Aws|Huawei|OpenStack|Ucloud|ZStack|Google"
Providers []string `json:"providers"`
// List objects belonging to brands
Brands []string `json:"brands"`
}
type CloudTypeListInput struct {
// enum: public_cloud,private_cloud,on_premise
CloudEnv string `json:"cloud_env"`
// List objects managed by external providers
// default: false
IsManaged bool `json:"is_managed"`
}

201
pkg/apis/compute/network.go Normal file
View File

@@ -0,0 +1,201 @@
// 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 NetworkListInput struct {
apis.BaseListInput
apis.SharableVirtualResourceListInput
CloudaccountListInput
CloudTypeListInput
Zones []string `json:"zones"`
Vpc string `json:"vpc"`
Cloudregion string `json:"cloudregion"`
Usable bool `json:"usable"`
Host string `json:"host"`
City string `json:"city"`
}
type NetworkCreateInput struct {
apis.Meta
IsSystem bool `json:"is_system"`
// description: network name
// unique: true
// required: true
// example: test-network
Name string `json:"name"`
// description: network description
// required: false
// example: test create network
Description string `json:"description"`
// description: ip range of guest, if not set, you shoud set guest_ip_start,guest_ip_end and guest_ip_mask params
// example: 10.168.222.1/24
GuestIpPrefix string `json:"guest_ip_prefix"`
// description: ip range of guest ip start, if set guest_ip_prefix, this parameter will be useless
// example: 10.168.222.1
GuestIpStart string `json:"guest_ip_start"`
// description: ip range of guest ip end, if set guest_ip_prefix, this parameter will be useless
// example: 10.168.222.100
GuestIpEnd string `json:"guest_ip_end"`
// description: ip range of guest ip mask, if set guest_ip_prefix, this parameter will be useless
// example: 24
// maximum: 30
// minimum: 12
GuestIpMask int64 `json:"guest_ip_mask"`
IfnameHint string `json:"ifname_hint"`
// description: guest gateway
// example: 192.168.222.1
GuestGateway string `json:"guest_gateway"`
// description: guest dns
// example: 114.114.114.114
GuestDns string `json:"guest_dns"`
// description: guest dhcp
// example: 192.168.222.1,192.168.222.4
GuestDHCP string `json:"guest_dhcp"`
// swagger:ignore
WireId string `json:"wire_id"`
// description: wire id or name
Wire string `json:"wire"`
// description: zone id or name
Zone string `json:"zone"`
// description: vpc id or name
Vpc string `json:"vpc"`
// description: server type
// enum: guest,baremetal,pxe,ipmi
// default: guest
ServerType string `json:"server_type"`
}
type NetworkDetails struct {
apis.Meta
apis.SharableVirtualResourceDetails
CloudproviderDetails
SNetwork
Wire string `json:"wire"`
Exit bool `json:"exit"`
Ports int `json:"ports"`
PortsUsed int `json:"ports_used"`
Vnics int `json:"vnics"`
BmVnics int `json:"bm_nics"`
LbVnics int `json:"lb_vnics"`
EipVnics int `json:"eip_vnics"`
GroupVnics int `json:"group_vnics"`
ReserveVnics int `json:"reserve_vnics"`
Vpc string `json:"vpc"`
VpcId string `json:"vpc_id"`
VpcExtId string `json:"vpc_ext_id"`
Routes [][]string `json:"routes"`
Schedtags []SchedtagShortDescDetails `json:"schedtags"`
}
type NetworkReserveIpInput struct {
apis.Meta
// description: reserved ip list
// required: true
// example: [10.168.222.131, 10.168.222.134]
Ips []string `json:"ips"`
// description: the comment
// example: reserve ip for test
Notes string `json:"notes"`
Status string `json:"status"`
// description: The reserved cycle
// required: false
Duration string `json:"duration"`
}
type NetworkReleaseReservedIpInput struct {
apis.Meta
// description: IP to be released
// required: true
// example: 10.168.222.121
Ip string `json:"ip"`
}
type NetworkPurgeInput struct {
apis.Meta
}
type NetworkMergeInput struct {
apis.Meta
// description: network id or name to be merged
// required: true
// example: test-network
Target string `json:"target"`
}
type NetworkSplitInput struct {
apis.Meta
// description: The middle - separated IP must belong to the network
// required: true
// example: 10.168.222.181
SplitIp string `json:"split_ip"`
// description: another network name after split
// required: false
Name string `json:"name"`
}
type NetworkTryCreateNetworkInput struct {
apis.Meta
Ip string `json:"ip"`
Mask int `json:"mask"`
ServerType string `json:"server_type"`
IsOnPremise bool `json:"is_on_premise"`
}
type NetworkSyncInput struct {
apis.Meta
}
type NetworkStatusInput struct {
apis.Meta
// description: network status
// required: true
// example: available
// enum: available,unavailable
Status string `json:"status"`
}

View File

@@ -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
import "yunion.io/x/onecloud/pkg/apis"
type SchedtagShortDescDetails struct {
*apis.StandaloneResourceShortDescDetail
Default string `json:"default"`
}

29
pkg/apis/modelbase.go Normal file
View File

@@ -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 apis
type ModelBaseDetails struct {
CanDelete bool `json:"can_delete"`
DeleteFailReason string `json:"delete_fail_reason"`
CanUpdate bool `json:"can_update"`
UpdateFailReason string `json:"update_fail_reason"`
}
type ModelBaseShortDescDetail struct {
ResName string `json:"res_name"`
}
type ModelBaseListInput struct {
}

View File

@@ -50,28 +50,6 @@ type BaseListInput struct {
// Export field keys
ExportKeys string `json:"export_keys"`
// TODO: support this tags
// Tags []string `help:"Tags info, eg: hypervisor=aliyun, os_type=Linux, os_version" json:"-"`
// UserTags []string `help:"UserTags info, eg: group=rd" json:"-"`
// CloudTags []string `help:"CloudTags info, eg: price_key=cn-beijing" json:"-"`
// List objects belonging to the cloud provider
Manager string `json:"manager,omitempty"`
// List objects belonging to the cloud account
Account string `json:"account,omitempty"`
// List objects from the provider, choices:"OneCloud|VMware|Aliyun|Qcloud|Azure|Aws|Huawei|OpenStack|Ucloud|ZStack"
Provider []string `json:"provider,omitempty"`
// List objects belonging to a special brand
Brand []string `json:"brand"`
// Cloud environment, choices:"public|private|onpremise|private_or_onpremise"
CloudEnv string `json:"cloud_env,omitempty"`
// List objects belonging to public cloud
PublicCloud *bool `json:"public_cloud"`
// List objects belonging to private cloud
PrivateCloud *bool `json:"private_cloud"`
// List objects belonging to on premise infrastructures
IsOnPremise *bool `json:"is_on_premise"`
// List objects managed by external providers
IsManaged *bool `json:"is_managed"`
// Marker for pagination
PagingMarker string `json:"paging_marker"`
}

View File

@@ -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 apis
type SharedProject struct {
Id string `json:"id"`
Name string `json:"name"`
}
type SharableVirtualResourceDetails struct {
SharedProjects []SharedProject `json:"shared_projects"`
VirtualResourceDetails
}
type SharableVirtualResourceListInput struct {
StandaloneResourceListInput
}

View File

@@ -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 apis
type StandaloneResourceShortDescDetail struct {
ModelBaseShortDescDetail
Id string `json:"id"`
Name string `json:"name"`
}
type StandaloneResourceListInput struct {
ModelBaseListInput
Tags []string `json:"tags"`
WithoutUserMeta bool `json:"without_user_meta"`
}

View File

@@ -0,0 +1,19 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package apis
type VirtualResourceDetails struct {
ModelBaseDetails
}

View File

@@ -24,6 +24,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/apis"
"yunion.io/x/onecloud/pkg/appsrv"
"yunion.io/x/onecloud/pkg/cloudcommon/object"
"yunion.io/x/onecloud/pkg/cloudcommon/policy"
@@ -121,6 +122,10 @@ func (manager *SModelBaseManager) ListItemFilter(ctx context.Context, q *sqlchem
return q, nil
}
func (manager *SModelBaseManager) ListItemFilterV2(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input *apis.ModelBaseListInput) (*sqlchemy.SQuery, error) {
return q, nil
}
func (manager *SModelBaseManager) CustomizeFilterList(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*CustomizeListFilters, error) {
return NewCustomizeListFilters(), nil
}
@@ -415,6 +420,10 @@ func (model *SModelBase) GetShortDesc(ctx context.Context) *jsonutils.JSONDict {
return desc
}
func (model *SModelBase) GetShortDescV2(ctx context.Context) *apis.ModelBaseShortDescDetail {
return &apis.ModelBaseShortDescDetail{ResName: model.Keyword()}
}
// list hooks
func (model *SModelBase) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict {
extra := jsonutils.NewDict()
@@ -426,6 +435,22 @@ func (model *SModelBase) AllowGetDetails(ctx context.Context, userCred mcclient.
return false
}
func (model *SModelBase) GetExtraDetailsV2(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, out *apis.ModelBaseDetails) error {
out.CanDelete = true
out.CanUpdate = true
err := model.GetIModel().ValidateDeleteCondition(ctx)
if err != nil {
out.CanDelete = false
out.DeleteFailReason = err.Error()
}
err = model.GetIModel().ValidateUpdateCondition(ctx)
if err != nil {
out.CanUpdate = false
out.UpdateFailReason = err.Error()
}
return nil
}
func (model *SModelBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*jsonutils.JSONDict, error) {
extra := jsonutils.NewDict()
return getModelExtraDetails(model.GetIModel(), ctx, extra), nil

View File

@@ -22,6 +22,7 @@ import (
"yunion.io/x/pkg/utils"
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/apis"
"yunion.io/x/onecloud/pkg/cloudcommon/consts"
"yunion.io/x/onecloud/pkg/cloudcommon/policy"
"yunion.io/x/onecloud/pkg/httperrors"
@@ -277,11 +278,33 @@ func (model *SSharableVirtualResourceBase) getMoreDetails(ctx context.Context, u
return extra
}
func (model *SSharableVirtualResourceBase) getMoreDetailsV2(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) []apis.SharedProject {
out := []apis.SharedProject{}
for _, project := range model.GetSharedProjects() {
tenant, err := TenantCacheManager.FetchTenantByIdOrName(ctx, project)
if err != nil {
log.Errorf("failed fetch tenant by id %s", project)
continue
}
out = append(out, apis.SharedProject{Id: tenant.GetId(), Name: tenant.GetName()})
}
return out
}
func (model *SSharableVirtualResourceBase) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict {
extra := model.SVirtualResourceBase.GetCustomizeColumns(ctx, userCred, query)
return model.getMoreDetails(ctx, userCred, query, extra)
}
func (model *SSharableVirtualResourceBase) GetExtraDetailsV2(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, out *apis.SharableVirtualResourceDetails) error {
err := model.SVirtualResourceBase.GetExtraDetailsV2(ctx, userCred, query, &out.VirtualResourceDetails)
if err != nil {
return err
}
out.SharedProjects = model.getMoreDetailsV2(ctx, userCred, query)
return nil
}
func (model *SSharableVirtualResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*jsonutils.JSONDict, error) {
extra, err := model.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query)
if err != nil {

View File

@@ -27,6 +27,7 @@ import (
"yunion.io/x/pkg/utils"
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/apis"
"yunion.io/x/onecloud/pkg/cloudcommon/consts"
"yunion.io/x/onecloud/pkg/cloudcommon/policy"
"yunion.io/x/onecloud/pkg/httperrors"
@@ -201,6 +202,55 @@ func (manager *SStandaloneResourceBaseManager) ListItemFilter(ctx context.Contex
return q, nil
}
func (manager *SStandaloneResourceBaseManager) ListItemFilterV2(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input *apis.StandaloneResourceListInput) (*sqlchemy.SQuery, error) {
q, err := manager.SResourceBaseManager.ListItemFilterV2(ctx, q, userCred, &input.ModelBaseListInput)
if err != nil {
return q, err
}
metadataView := Metadata.Query()
for idx, tag := range input.Tags {
tagInfo := strings.Split(tag, "=")
key, value := tagInfo[0], ""
if len(tagInfo) == 2 {
value = tagInfo[1]
}
if idx == 0 {
metadataView = metadataView.Equals("key", key)
if len(value) > 0 {
metadataView = metadataView.Equals("value", value)
}
} else {
subMetataView := Metadata.Query().Equals("key", key)
if len(value) > 0 {
subMetataView = subMetataView.Equals("value", value)
}
sq := subMetataView.SubQuery()
metadataView.Join(sq, sqlchemy.Equals(metadataView.Field("id"), sq.Field("id")))
}
metadatas := metadataView.SubQuery()
fieldName := fmt.Sprintf("%s_id", manager.Keyword())
metadataSQ := metadatas.Query(
sqlchemy.REPLACE(fieldName, metadatas.Field("id"), manager.Keyword()+"::", ""),
)
sq := metadataSQ.Filter(sqlchemy.Like(metadatas.Field("id"), manager.Keyword()+"::%")).Distinct()
q = q.Filter(sqlchemy.In(q.Field("id"), sq))
}
if input.WithoutUserMeta {
metadatas := Metadata.Query().SubQuery()
fieldName := fmt.Sprintf("%s_id", manager.Keyword())
metadataSQ := metadatas.Query(
sqlchemy.REPLACE(fieldName, metadatas.Field("id"), manager.Keyword()+"::", ""),
)
sq := metadataSQ.Filter(sqlchemy.Like(metadatas.Field("key"), USER_TAG_PREFIX+"%")).Distinct()
q.Filter(sqlchemy.NotIn(q.Field("id"), sq))
}
return q, nil
}
func (model *SStandaloneResourceBase) StandaloneModelManager() IStandaloneModelManager {
return model.GetModelManager().(IStandaloneModelManager)
}
@@ -227,6 +277,14 @@ func (model *SStandaloneResourceBase) GetShortDesc(ctx context.Context) *jsonuti
return desc
}
func (model *SStandaloneResourceBase) GetShortDescV2(ctx context.Context) *apis.StandaloneResourceShortDescDetail {
desc := &apis.StandaloneResourceShortDescDetail{}
desc.ModelBaseShortDescDetail = *model.SResourceBase.GetShortDescV2(ctx)
desc.Name = model.GetName()
desc.Id = model.GetId()
return desc
}
/*
* userCred: optional
*/

View File

@@ -25,6 +25,7 @@ import (
"yunion.io/x/pkg/utils"
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/apis"
identityapi "yunion.io/x/onecloud/pkg/apis/identity"
"yunion.io/x/onecloud/pkg/cloudcommon/consts"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
@@ -313,6 +314,10 @@ func (model *SVirtualResourceBase) GetCustomizeColumns(ctx context.Context, user
return model.getMoreDetails(ctx, userCred, query, extra)
}
func (model *SVirtualResourceBase) GetExtraDetailsV2(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, out *apis.VirtualResourceDetails) error {
return model.SStandaloneResourceBase.GetExtraDetailsV2(ctx, userCred, query, &out.ModelBaseDetails)
}
func (model *SVirtualResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*jsonutils.JSONDict, error) {
extra, err := model.SStandaloneResourceBase.GetExtraDetails(ctx, userCred, query)
if err != nil {

View File

@@ -198,6 +198,39 @@ func splitProviders(providers []string) (bool, []string) {
return oneCloud, others
}
func filterByProviderStrsV2(q *sqlchemy.SQuery, filterField string, subqFunc func() *sqlchemy.SQuery, fieldName string, providerStrs []string) *sqlchemy.SQuery {
oneCloud, providers := splitProviders(providerStrs)
sq := q
if len(filterField) > 0 {
sq = subqFunc()
}
filters := make([]sqlchemy.ICondition, 0)
if len(providers) > 0 {
account := CloudaccountManager.Query().SubQuery()
providers := CloudproviderManager.Query().SubQuery()
subq := providers.Query(providers.Field("id"))
subq = subq.Join(account, sqlchemy.Equals(
account.Field("id"), providers.Field("cloudaccount_id"),
))
subq = subq.Filter(sqlchemy.In(account.Field(fieldName), providerStrs))
filters = append(filters, sqlchemy.In(sq.Field("manager_id"), subq.SubQuery()))
}
if oneCloud {
filters = append(filters, sqlchemy.IsNullOrEmpty(sq.Field("manager_id")))
}
if len(filters) == 1 {
sq = sq.Filter(filters[0])
} else if len(filters) > 1 {
sq = sq.Filter(sqlchemy.OR(filters...))
}
if len(filterField) == 0 {
q = sq
} else {
q = q.Filter(sqlchemy.In(q.Field(filterField), sq.SubQuery()))
}
return q
}
func filterByProviderStrs(q *sqlchemy.SQuery, queryDict *jsonutils.JSONDict, filterField string, subqFunc func() *sqlchemy.SQuery, fieldName string, providerStrs []string) *sqlchemy.SQuery {
queryDict.Remove(fieldName)
oneCloud, providers := splitProviders(providerStrs)
@@ -233,6 +266,54 @@ func filterByProviderStrs(q *sqlchemy.SQuery, queryDict *jsonutils.JSONDict, fil
return q
}
func managedResourceFilterByAccountV2(q *sqlchemy.SQuery, input *api.CloudaccountListInput, filterField string, subqFunc func() *sqlchemy.SQuery) (*sqlchemy.SQuery, error) {
if len(input.Cloudprovider) > 0 {
provider, err := CloudproviderManager.FetchByIdOrName(nil, input.Cloudprovider)
if err != nil {
if err == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError2(CloudproviderManager.Keyword(), input.Cloudprovider)
}
return nil, httperrors.NewGeneralError(err)
}
if len(filterField) == 0 {
q = q.Filter(sqlchemy.Equals(q.Field("manager_id"), provider.GetId()))
} else {
sq := subqFunc()
sq = sq.Filter(sqlchemy.Equals(sq.Field("manager_id"), provider.GetId()))
q = q.Filter(sqlchemy.In(q.Field(filterField), sq.SubQuery()))
}
}
if len(input.Cloudaccount) > 0 {
account, err := CloudaccountManager.FetchByIdOrName(nil, input.Cloudaccount)
if err != nil {
if err == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError2(CloudaccountManager.Keyword(), input.Cloudaccount)
}
return nil, httperrors.NewGeneralError(err)
}
subq := CloudproviderManager.Query("id").Equals("cloudaccount_id", account.GetId()).SubQuery()
if len(filterField) == 0 {
q = q.Filter(sqlchemy.In(q.Field("manager_id"), subq))
} else {
sq := subqFunc()
sq = sq.Filter(sqlchemy.In(sq.Field("manager_id"), subq))
q = q.Filter(sqlchemy.In(q.Field(filterField), sq.SubQuery()))
}
}
if len(input.Providers) > 0 {
q = filterByProviderStrsV2(q, filterField, subqFunc, "provider", input.Providers)
}
if len(input.Brands) > 0 {
q = filterByProviderStrsV2(q, filterField, subqFunc, "brand", input.Brands)
}
return q, nil
}
func managedResourceFilterByAccount(q *sqlchemy.SQuery, query jsonutils.JSONObject, filterField string, subqFunc func() *sqlchemy.SQuery) (*sqlchemy.SQuery, error) {
queryDict := query.(*jsonutils.JSONDict)
@@ -396,6 +477,61 @@ func managedResourceFilterByCloudType(q *sqlchemy.SQuery, query jsonutils.JSONOb
return q
}
func managedResourceFilterByCloudTypeV2(q *sqlchemy.SQuery, input *api.CloudTypeListInput, filterField string, subqFunc func() *sqlchemy.SQuery) *sqlchemy.SQuery {
if input.CloudEnv == api.CLOUD_ENV_PUBLIC_CLOUD {
if len(filterField) == 0 {
q = q.Filter(sqlchemy.In(q.Field("manager_id"), CloudproviderManager.GetPublicProviderIdsQuery()))
} else {
sq := subqFunc()
sq = sq.Filter(sqlchemy.In(sq.Field("manager_id"), CloudproviderManager.GetPublicProviderIdsQuery()))
q = q.Filter(sqlchemy.In(q.Field(filterField), sq.SubQuery()))
}
}
if input.CloudEnv == api.CLOUD_ENV_PRIVATE_CLOUD {
if len(filterField) == 0 {
q = q.Filter(sqlchemy.In(q.Field("manager_id"), CloudproviderManager.GetPrivateProviderIdsQuery()))
} else {
sq := subqFunc()
sq = sq.Filter(sqlchemy.In(sq.Field("manager_id"), CloudproviderManager.GetPrivateProviderIdsQuery()))
q = q.Filter(sqlchemy.In(q.Field(filterField), sq.SubQuery()))
}
}
if input.CloudEnv == api.CLOUD_ENV_ON_PREMISE {
if len(filterField) == 0 {
q = q.Filter(
sqlchemy.OR(
sqlchemy.In(q.Field("manager_id"), CloudproviderManager.GetOnPremiseProviderIdsQuery()),
sqlchemy.IsNullOrEmpty(q.Field("manager_id")),
),
)
} else {
sq := subqFunc()
sq = sq.Filter(
sqlchemy.OR(
sqlchemy.In(sq.Field("manager_id"), CloudproviderManager.GetOnPremiseProviderIdsQuery()),
sqlchemy.IsNullOrEmpty(sq.Field("manager_id")),
),
)
q = q.Filter(sqlchemy.In(q.Field(filterField), sq.SubQuery()))
}
}
if input.IsManaged {
if len(filterField) == 0 {
q = q.Filter(sqlchemy.IsNotEmpty(q.Field("manager_id")))
} else {
sq := subqFunc()
sq = sq.Filter(sqlchemy.IsNotEmpty(sq.Field("manager_id")))
q = q.Filter(sqlchemy.In(q.Field(filterField), sq.SubQuery()))
}
}
return q
}
type SCloudProviderInfo struct {
Provider string `json:",omitempty"`
Brand string `json:",omitempty"`
@@ -409,6 +545,7 @@ type SCloudProviderInfo struct {
ManagerDomainId string `json:",omitempty"`
Region string `json:",omitempty"`
RegionId string `json:",omitempty"`
CloudregionId string `json:",omitempty"`
RegionExternalId string `json:",omitempty"`
RegionExtId string `json:",omitempty"`
Zone string `json:",omitempty"`
@@ -447,6 +584,58 @@ func fetchExternalId(extId string) string {
}
}
func MakeCloudProviderInfoV2(region *SCloudregion, zone *SZone, provider *SCloudprovider) api.CloudproviderDetails {
info := api.CloudproviderDetails{}
if zone != nil {
info.Zone = zone.GetName()
info.ZoneId = zone.GetId()
}
if region != nil {
info.Region = region.GetName()
info.RegionId = region.GetId()
info.CloudregionId = region.GetId()
}
if provider != nil {
info.Manager = provider.GetName()
info.ManagerId = provider.GetId()
if len(provider.ProjectId) > 0 {
info.ManagerProjectId = provider.ProjectId
tc, err := db.TenantCacheManager.FetchTenantById(appctx.Background, provider.ProjectId)
if err == nil {
info.ManagerProject = tc.GetName()
info.ManagerDomain = tc.Domain
info.ManagerDomainId = tc.DomainId
}
}
account := provider.GetCloudaccount()
info.Account = account.GetName()
info.AccountId = account.GetId()
info.Provider = provider.Provider
info.Brand = account.Brand
info.CloudEnv = account.getCloudEnv()
if region != nil {
info.RegionExternalId = region.ExternalId
info.RegionExtId = fetchExternalId(region.ExternalId)
if zone != nil {
info.ZoneExtId = fetchExternalId(zone.ExternalId)
}
}
} else {
info.CloudEnv = api.CLOUD_ENV_ON_PREMISE
info.Provider = api.CLOUD_PROVIDER_ONECLOUD
info.Brand = api.CLOUD_PROVIDER_ONECLOUD
}
return info
}
func MakeCloudProviderInfo(region *SCloudregion, zone *SZone, provider *SCloudprovider) SCloudProviderInfo {
info := SCloudProviderInfo{}
@@ -458,6 +647,7 @@ func MakeCloudProviderInfo(region *SCloudregion, zone *SZone, provider *SCloudpr
if region != nil {
info.Region = region.GetName()
info.RegionId = region.GetId()
info.CloudregionId = region.GetId()
}
if provider != nil {

View File

@@ -985,13 +985,51 @@ func (self *SNetwork) getMoreDetails(ctx context.Context, extra *jsonutils.JSOND
return extra
}
func (self *SNetwork) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*jsonutils.JSONDict, error) {
extra, err := self.SSharableVirtualResourceBase.GetExtraDetails(ctx, userCred, query)
func (self *SNetwork) getMoreDetailsV2(ctx context.Context, out *api.NetworkDetails) {
wire := self.GetWire()
if wire != nil {
out.Wire = wire.Name
}
out.Exit = false
if self.IsExitNetwork() {
out.Exit = true
}
out.Ports = self.GetPorts()
out.PortsUsed, _ = self.GetTotalNicCount()
out.Vnics, _ = self.GetGuestnicsCount()
out.BmVnics, _ = self.GetBaremetalNicsCount()
out.LbVnics, _ = self.GetLoadbalancerIpsCount()
out.EipVnics, _ = self.GetEipsCount()
out.GroupVnics, _ = self.GetGroupNicsCount()
out.ReserveVnics, _ = self.GetReservedNicsCount()
vpc := self.getVpc()
if vpc != nil {
out.Vpc = vpc.Name
out.VpcId = vpc.Id
out.VpcExtId = vpc.ExternalId
out.CloudproviderDetails = vpc.getCloudProviderInfoV2()
}
if len(out.Zone) == 0 {
zone := self.getZone()
if zone != nil {
out.Zone = zone.Name
out.ZoneId = zone.Id
}
}
out.Routes = self.GetRoutes()
out.Schedtags = GetSchedtagsDetailsToResourceV2(self, ctx)
}
func (self *SNetwork) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*api.NetworkDetails, error) {
out := &api.NetworkDetails{}
err := self.SSharableVirtualResourceBase.GetExtraDetailsV2(ctx, userCred, query, &out.SharableVirtualResourceDetails)
if err != nil {
return nil, err
}
extra = self.getMoreDetails(ctx, extra)
return extra, nil
self.getMoreDetailsV2(ctx, out)
return out, nil
}
func (self *SNetwork) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict {
@@ -1004,35 +1042,24 @@ func (self *SNetwork) AllowPerformReserveIp(ctx context.Context, userCred mcclie
return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "reserve-ip")
}
func (self *SNetwork) PerformReserveIp(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
ips, err := data.GetArray("ips")
if err != nil {
if data.Contains("ip") {
ip, _ := data.Get("ip")
ips = []jsonutils.JSONObject{ip}
} else {
return nil, httperrors.NewMissingParameterError("ips")
}
}
notes, err := data.GetString("notes")
if err != nil {
// 预留IP
// 预留的IP不会被调度使用
func (self *SNetwork) PerformReserveIp(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.NetworkReserveIpInput) (jsonutils.JSONObject, error) {
if len(input.Ips) == 0 {
return nil, httperrors.NewMissingParameterError("ips")
}
status, _ := data.GetString("status")
var duration time.Duration
durationStr, _ := data.GetString("duration")
if len(durationStr) > 0 {
bc, err := billing.ParseBillingCycle(durationStr)
if len(input.Duration) > 0 {
bc, err := billing.ParseBillingCycle(input.Duration)
if err != nil {
return nil, httperrors.NewInputParameterError("Duration %s invalid", durationStr)
return nil, httperrors.NewInputParameterError("Duration %s invalid", input.Duration)
}
duration = bc.Duration()
}
for _, ip := range ips {
ipstr, _ := ip.GetString()
err := self.reserveIpWithDurationAndStatus(ctx, userCred, ipstr, notes, duration, status)
for _, ip := range input.Ips {
err := self.reserveIpWithDurationAndStatus(ctx, userCred, ip, input.Notes, duration, input.Status)
if err != nil {
return nil, err
}
@@ -1070,14 +1097,14 @@ func (self *SNetwork) AllowPerformReleaseReservedIp(ctx context.Context, userCre
return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "release-reserved-ip")
}
func (self *SNetwork) PerformReleaseReservedIp(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
ipstr, _ := data.GetString("ip")
if len(ipstr) == 0 {
return nil, httperrors.NewInputParameterError("Reserved ip to release must be provided")
// 释放预留IP
func (self *SNetwork) PerformReleaseReservedIp(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.NetworkReleaseReservedIpInput) (jsonutils.JSONObject, error) {
if len(input.Ip) == 0 {
return nil, httperrors.NewMissingParameterError("ip")
}
rip := ReservedipManager.getReservedIP(self, ipstr)
rip := ReservedipManager.getReservedIP(self, input.Ip)
if rip == nil {
return nil, httperrors.NewInvalidStatusError("Address %s not reserved", ipstr)
return nil, httperrors.NewInvalidStatusError("Address %s not reserved", input.Ip)
}
rip.Release(ctx, userCred, self)
return nil, nil
@@ -1142,59 +1169,51 @@ func (manager *SNetworkManager) newIfnameHint(hint string) (string, error) {
return r, nil
}
func (manager *SNetworkManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
prefixStr, _ := data.GetString("guest_ip_prefix")
var maskLen64 int64
func (manager *SNetworkManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input *api.NetworkCreateInput) (*jsonutils.JSONDict, error) {
var err error
var startIp, endIp netutils.IPV4Addr
if len(prefixStr) > 0 {
prefix, err := netutils.NewIPV4Prefix(prefixStr)
if len(input.GuestIpPrefix) > 0 {
prefix, err := netutils.NewIPV4Prefix(input.GuestIpPrefix)
if err != nil {
return nil, httperrors.NewInputParameterError("ip_prefix error: %s", err)
}
iprange := prefix.ToIPRange()
startIp = iprange.StartIp().StepUp()
endIp = iprange.EndIp().StepDown()
maskLen64 = int64(prefix.MaskLen)
input.GuestIpMask = int64(prefix.MaskLen)
} else {
ipStartStr, _ := data.GetString("guest_ip_start")
ipEndStr, _ := data.GetString("guest_ip_end")
startIp, err = netutils.NewIPV4Addr(ipStartStr)
startIp, err = netutils.NewIPV4Addr(input.GuestIpStart)
if err != nil {
return nil, httperrors.NewInputParameterError("Invalid start ip: %s %s", ipStartStr, err)
return nil, httperrors.NewInputParameterError("Invalid start ip: %s %s", input.GuestIpStart, err)
}
endIp, err = netutils.NewIPV4Addr(ipEndStr)
endIp, err = netutils.NewIPV4Addr(input.GuestIpEnd)
if err != nil {
return nil, httperrors.NewInputParameterError("invalid end ip: %s %s", ipEndStr, err)
return nil, httperrors.NewInputParameterError("invalid end ip: %s %s", input.GuestIpEnd, err)
}
if startIp > endIp {
tmp := startIp
startIp = endIp
endIp = tmp
}
maskLen64, _ = data.Int("guest_ip_mask")
}
if !isValidMaskLen(maskLen64) {
return nil, httperrors.NewInputParameterError("Invalid masklen %d", maskLen64)
input.GuestIpStart = startIp.String()
input.GuestIpEnd = endIp.String()
if !isValidMaskLen(input.GuestIpMask) {
return nil, httperrors.NewInputParameterError("Invalid masklen %d", input.GuestIpMask)
}
data.Add(jsonutils.NewInt(maskLen64), "guest_ip_mask")
data.Add(jsonutils.NewString(startIp.String()), "guest_ip_start")
data.Add(jsonutils.NewString(endIp.String()), "guest_ip_end")
{
hint, _ := data.GetString("ifname_hint")
if hint == "" {
hint, _ = data.GetString("name")
if len(input.IfnameHint) == 0 {
input.IfnameHint = input.Name
}
hint, err = manager.newIfnameHint(hint)
input.IfnameHint, err = manager.newIfnameHint(input.IfnameHint)
if err != nil {
return nil, httperrors.NewBadRequestError("cannot derive valid ifname hint: %v", err)
}
data.Set("ifname_hint", jsonutils.NewString(hint))
}
for _, key := range []string{"guest_gateway", "guest_dns", "guest_dhcp"} {
ipStr, _ := data.GetString(key)
for key, ipStr := range map[string]string{"guest_gateway": input.GuestGateway, "guest_dns": input.GuestDns, "guest_dhcp": input.GuestDHCP} {
if len(ipStr) > 0 {
if key == "guest_dhcp" {
ipList := strings.Split(ipStr, ",")
@@ -1218,36 +1237,37 @@ func (manager *SNetworkManager) ValidateCreateData(ctx context.Context, userCred
return nil, httperrors.NewInputParameterError("Conflict address space with existing networks")
}
wireStr := jsonutils.GetAnyString(data, []string{"wire", "wire_id"})
if len(wireStr) > 0 {
wireObj, err := WireManager.FetchByIdOrName(userCred, wireStr)
if len(input.WireId) > 0 {
input.Wire = input.WireId
}
if len(input.Wire) > 0 {
wireObj, err := WireManager.FetchByIdOrName(userCred, input.Wire)
if err != nil {
if err == sql.ErrNoRows {
return nil, httperrors.NewNotFoundError("wire %s not found", wireStr)
return nil, httperrors.NewNotFoundError("wire %s not found", input.Wire)
} else {
return nil, httperrors.NewInternalServerError("query wire %s error %s", wireStr, err)
return nil, httperrors.NewInternalServerError("query wire %s error %s", input.Wire, err)
}
}
data.Add(jsonutils.NewString(wireObj.GetId()), "wire_id")
input.WireId = wireObj.GetId()
} else {
zoneStr := jsonutils.GetAnyString(data, []string{"zone", "zone_id"})
if len(zoneStr) > 0 {
vpcStr := jsonutils.GetAnyString(data, []string{"vpc", "vpc_id"})
if len(vpcStr) > 0 {
zoneObj, err := ZoneManager.FetchByIdOrName(userCred, zoneStr)
if len(input.Zone) > 0 {
if len(input.Vpc) > 0 {
zoneObj, err := ZoneManager.FetchByIdOrName(userCred, input.Zone)
if err != nil {
if err == sql.ErrNoRows {
return nil, httperrors.NewNotFoundError("zone %s not found", zoneStr)
return nil, httperrors.NewNotFoundError("zone %s not found", input.Zone)
} else {
return nil, httperrors.NewInternalServerError("query zone %s error %s", zoneStr, err)
return nil, httperrors.NewInternalServerError("query zone %s error %s", input.Zone, err)
}
}
vpcObj, err := VpcManager.FetchByIdOrName(userCred, vpcStr)
vpcObj, err := VpcManager.FetchByIdOrName(userCred, input.Vpc)
if err != nil {
if err == sql.ErrNoRows {
return nil, httperrors.NewNotFoundError("vpc %s not found", vpcStr)
return nil, httperrors.NewNotFoundError("vpc %s not found", input.Vpc)
} else {
return nil, httperrors.NewInternalServerError("query vpc %s error %s", vpcStr, err)
return nil, httperrors.NewInternalServerError("query vpc %s error %s", input.Vpc, err)
}
}
vpc := vpcObj.(*SVpc)
@@ -1259,21 +1279,21 @@ func (manager *SNetworkManager) ValidateCreateData(ctx context.Context, userCred
// 华为云,ucloud wire zone_id 为空
var wires []SWire
if utils.IsInStringArray(region.Provider, []string{api.CLOUD_PROVIDER_HUAWEI, api.CLOUD_PROVIDER_UCLOUD}) {
if utils.IsInStringArray(region.Provider, api.REGIONAL_NETWORK_PROVIDERS) {
wires, err = WireManager.getWiresByVpcAndZone(vpc, nil)
} else {
wires, err = WireManager.getWiresByVpcAndZone(vpc, zone)
}
if err != nil {
return nil, httperrors.NewInternalServerError("query wire for zone %s and vpc %s: %v", zoneStr, vpcStr, err)
return nil, httperrors.NewInternalServerError("query wire for zone %s and vpc %s: %v", input.Zone, input.Vpc, err)
}
if len(wires) == 0 {
return nil, httperrors.NewNotFoundError("wire not found for zone %s and vpc %s", zoneStr, vpcStr)
return nil, httperrors.NewNotFoundError("wire not found for zone %s and vpc %s", input.Zone, input.Vpc)
} else if len(wires) > 1 {
return nil, httperrors.NewConflictError("found %d wires for zone %s and vpc %s", len(wires), zoneStr, vpcStr)
return nil, httperrors.NewConflictError("found %d wires for zone %s and vpc %s", len(wires), input.Zone, input.Vpc)
} else {
data.Add(jsonutils.NewString(wires[0].Id), "wire_id")
input.WireId = wires[0].Id
}
} else {
return nil, httperrors.NewInputParameterError("No either wire or vpc provided")
@@ -1283,13 +1303,12 @@ func (manager *SNetworkManager) ValidateCreateData(ctx context.Context, userCred
}
}
wireId, _ := data.GetString("wire_id")
if len(wireId) == 0 {
if len(input.WireId) == 0 {
return nil, httperrors.NewMissingParameterError("wire_id")
}
wire := WireManager.FetchWireById(wireId)
wire := WireManager.FetchWireById(input.WireId)
if wire == nil {
return nil, httperrors.NewResourceNotFoundError("wire %s not found", wireId)
return nil, httperrors.NewResourceNotFoundError("wire %s not found", input.WireId)
}
vpc := wire.getVpc()
if vpc == nil {
@@ -1316,15 +1335,13 @@ func (manager *SNetworkManager) ValidateCreateData(ctx context.Context, userCred
return nil, httperrors.NewInputParameterError("Network not in range of VPC cidrblock %s", vpc.CidrBlock)
}
serverTypeStr, _ := data.GetString("server_type")
if len(serverTypeStr) == 0 {
serverTypeStr = api.NETWORK_TYPE_GUEST
} else if !utils.IsInStringArray(serverTypeStr, ALL_NETWORK_TYPES) {
return nil, httperrors.NewInputParameterError("Invalid server_type: %s", serverTypeStr)
if len(input.ServerType) == 0 {
input.ServerType = api.NETWORK_TYPE_GUEST
} else if !utils.IsInStringArray(input.ServerType, ALL_NETWORK_TYPES) {
return nil, httperrors.NewInputParameterError("Invalid server_type: %s", input.ServerType)
}
data.Add(jsonutils.NewString(serverTypeStr), "server_type")
return manager.SSharableVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, data)
return manager.SSharableVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.JSON(input))
}
func (self *SNetwork) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
@@ -1613,10 +1630,10 @@ func (manager *SNetworkManager) CustomizeFilterList(ctx context.Context, q *sqlc
return filters, nil
}
func (manager *SNetworkManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) {
func (manager *SNetworkManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input *api.NetworkListInput) (*sqlchemy.SQuery, error) {
var err error
q, err = managedResourceFilterByAccount(q, query, "wire_id", func() *sqlchemy.SQuery {
q, err = managedResourceFilterByAccountV2(q, &input.CloudaccountListInput, "wire_id", func() *sqlchemy.SQuery {
wires := WireManager.Query().SubQuery()
vpcs := VpcManager.Query().SubQuery()
@@ -1628,7 +1645,7 @@ func (manager *SNetworkManager) ListItemFilter(ctx context.Context, q *sqlchemy.
return nil, err
}
q = managedResourceFilterByCloudType(q, query, "wire_id", func() *sqlchemy.SQuery {
q = managedResourceFilterByCloudTypeV2(q, &input.CloudTypeListInput, "wire_id", func() *sqlchemy.SQuery {
wires := WireManager.Query().SubQuery()
vpcs := VpcManager.Query().SubQuery()
subq := wires.Query(wires.Field("id"))
@@ -1636,21 +1653,20 @@ func (manager *SNetworkManager) ListItemFilter(ctx context.Context, q *sqlchemy.
return subq
})
q, err = manager.SSharableVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query)
q, err = manager.SSharableVirtualResourceBaseManager.ListItemFilterV2(ctx, q, userCred, &input.StandaloneResourceListInput)
if err != nil {
return nil, err
}
zones := jsonutils.GetQueryStringArray(query, "zone")
if len(zones) > 0 {
if len(input.Zones) > 0 {
zq := ZoneManager.Query().SubQuery()
regions := CloudregionManager.Query().SubQuery()
zoneQ := zq.Query(zq.Field("id"), regions.Field("id"), regions.Field("provider")).
Join(regions, sqlchemy.Equals(zq.Field("cloudregion_id"), regions.Field("id"))).
Filter(
sqlchemy.OR(
sqlchemy.In(zq.Field("id"), zones),
sqlchemy.In(zq.Field("name"), zones),
sqlchemy.In(zq.Field("id"), input.Zones),
sqlchemy.In(zq.Field("name"), input.Zones),
),
)
rows, err := zoneQ.Rows()
@@ -1690,22 +1706,20 @@ func (manager *SNetworkManager) ListItemFilter(ctx context.Context, q *sqlchemy.
q = q.In("wire_id", sq.SubQuery())
}
vpcStr, _ := query.GetString("vpc")
if len(vpcStr) > 0 {
vpcObj, err := VpcManager.FetchByIdOrName(userCred, vpcStr)
if len(input.Vpc) > 0 {
vpcObj, err := VpcManager.FetchByIdOrName(userCred, input.Vpc)
if err != nil {
return nil, httperrors.NewNotFoundError("VPC %s not found", vpcStr)
return nil, httperrors.NewNotFoundError("VPC %s not found", input.Vpc)
}
sq := WireManager.Query("id").Equals("vpc_id", vpcObj.GetId())
q = q.Filter(sqlchemy.In(q.Field("wire_id"), sq.SubQuery()))
}
regionStr := jsonutils.GetAnyString(query, []string{"region_id", "region", "cloudregion_id", "cloudregion"})
if len(regionStr) > 0 {
region, err := CloudregionManager.FetchByIdOrName(userCred, regionStr)
if len(input.Cloudregion) > 0 {
region, err := CloudregionManager.FetchByIdOrName(userCred, input.Cloudregion)
if err != nil {
if err == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError("cloud region %s not found", regionStr)
return nil, httperrors.NewResourceNotFoundError("cloud region %s not found", input.Cloudregion)
} else {
return nil, httperrors.NewGeneralError(err)
}
@@ -1719,7 +1733,7 @@ func (manager *SNetworkManager) ListItemFilter(ctx context.Context, q *sqlchemy.
q = q.Filter(sqlchemy.In(q.Field("wire_id"), sq.SubQuery()))
}
if jsonutils.QueryBoolean(query, "usable", false) {
if input.Usable {
wires := WireManager.Query().SubQuery()
zones := ZoneManager.Query().SubQuery()
vpcs := VpcManager.Query().SubQuery()
@@ -1749,25 +1763,23 @@ func (manager *SNetworkManager) ListItemFilter(ctx context.Context, q *sqlchemy.
q = q.In("wire_id", sq.SubQuery()).Equals("status", api.NETWORK_STATUS_AVAILABLE)
}
hostStr, _ := query.GetString("host")
if len(hostStr) > 0 {
hostObj, err := HostManager.FetchByIdOrName(userCred, hostStr)
if len(input.Host) > 0 {
hostObj, err := HostManager.FetchByIdOrName(userCred, input.Host)
if err != nil {
return nil, httperrors.NewResourceNotFoundError2(HostManager.Keyword(), hostStr)
return nil, httperrors.NewResourceNotFoundError2(HostManager.Keyword(), input.Host)
}
sq := HostwireManager.Query("wire_id").Equals("host_id", hostObj.GetId())
q = q.Filter(sqlchemy.In(q.Field("wire_id"), sq.SubQuery()))
}
cityStr, _ := query.GetString("city")
if len(cityStr) > 0 {
if len(input.City) > 0 {
regions := CloudregionManager.Query().SubQuery()
wires := WireManager.Query().SubQuery()
vpcs := VpcManager.Query().SubQuery()
sq := wires.Query(wires.Field("id")).
Join(vpcs, sqlchemy.Equals(wires.Field("vpc_id"), vpcs.Field("id"))).
Join(regions, sqlchemy.Equals(regions.Field("id"), vpcs.Field("cloudregion_id"))).
Filter(sqlchemy.Equals(regions.Field("city"), cityStr))
Filter(sqlchemy.Equals(regions.Field("city"), input.City))
q = q.Filter(sqlchemy.In(q.Field("wire_id"), sq.SubQuery()))
}
@@ -1846,7 +1858,9 @@ func (self *SNetwork) AllowPerformPurge(ctx context.Context, userCred mcclient.T
return db.IsAdminAllowPerform(userCred, self, "purge")
}
func (self *SNetwork) PerformPurge(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
// 清除IP子网数据
// 要求IP子网内没有被分配IP,若清除接入云,要求接入云账号处于禁用状态
func (self *SNetwork) PerformPurge(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.NetworkPurgeInput) (jsonutils.JSONObject, error) {
err := self.ValidateDeleteCondition(ctx)
if err != nil {
return nil, err
@@ -1893,14 +1907,15 @@ func (manager *SNetworkManager) handleNetworkIdChange(ctx context.Context, args
return nil
}
func (self *SNetwork) PerformMerge(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
target, err := data.GetString("target")
if err != nil {
// 合并IP子网
// 将两个相连的IP子网合并成一个IP子网
func (self *SNetwork) PerformMerge(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.NetworkMergeInput) (jsonutils.JSONObject, error) {
if len(input.Target) == 0 {
return nil, httperrors.NewMissingParameterError("target")
}
iNet, err := NetworkManager.FetchByIdOrName(userCred, target)
iNet, err := NetworkManager.FetchByIdOrName(userCred, input.Target)
if err == sql.ErrNoRows {
err = httperrors.NewNotFoundError("Network %s not found", target)
err = httperrors.NewNotFoundError("Network %s not found", input.Target)
logclient.AddActionLogWithContext(ctx, self, logclient.ACT_MERGE, err.Error(), userCred, false)
return nil, err
} else if err != nil {
@@ -1915,7 +1930,7 @@ func (self *SNetwork) PerformMerge(ctx context.Context, userCred mcclient.TokenC
return nil, err
}
if self.WireId != net.WireId || self.GuestGateway != net.GuestGateway {
err = httperrors.NewInputParameterError("Invalid Target Network: %s", target)
err = httperrors.NewInputParameterError("Invalid Target Network: %s", input.Target)
logclient.AddActionLogWithContext(ctx, self, logclient.ACT_MERGE, err.Error(), userCred, false)
return nil, err
}
@@ -1972,50 +1987,53 @@ func (self *SNetwork) PerformMerge(ctx context.Context, userCred mcclient.TokenC
return nil, nil
}
func (self *SNetwork) PerformSplit(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
splitIp, err := data.GetString("split_ip")
if err != nil {
// 分割IP子网
// 将一个IP子网分割成两个子网,仅本地IDC支持此操作
func (self *SNetwork) PerformSplit(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.NetworkSplitInput) (jsonutils.JSONObject, error) {
if len(self.ExternalId) > 0 {
return nil, httperrors.NewNotSupportedError("only on premise support this operation")
}
if len(input.SplitIp) == 0 {
return nil, httperrors.NewMissingParameterError("split_ip")
}
name, _ := data.GetString("name")
if !regutils.MatchIPAddr(splitIp) {
return nil, httperrors.NewInputParameterError("Invalid IP %s", splitIp)
if !regutils.MatchIPAddr(input.SplitIp) {
return nil, httperrors.NewInputParameterError("Invalid IP %s", input.SplitIp)
}
if splitIp == self.GuestIpStart {
return nil, httperrors.NewInputParameterError("Split IP %s is the start ip", splitIp)
if input.SplitIp == self.GuestIpStart {
return nil, httperrors.NewInputParameterError("Split IP %s is the start ip", input.SplitIp)
}
iSplitIp, err := netutils.NewIPV4Addr(splitIp)
iSplitIp, err := netutils.NewIPV4Addr(input.SplitIp)
if err != nil {
return nil, err
}
if !self.IsAddressInRange(iSplitIp) {
return nil, httperrors.NewInputParameterError("Split IP %s out of range", splitIp)
return nil, httperrors.NewInputParameterError("Split IP %s out of range", input.SplitIp)
}
lockman.LockClass(ctx, NetworkManager, db.GetLockClassKey(NetworkManager, userCred))
defer lockman.ReleaseClass(ctx, NetworkManager, db.GetLockClassKey(NetworkManager, userCred))
if len(name) > 0 {
if err := db.NewNameValidator(NetworkManager, userCred, name, ""); err != nil {
return nil, httperrors.NewInputParameterError("Duplicate name %s", name)
if len(input.Name) > 0 {
if err := db.NewNameValidator(NetworkManager, userCred, input.Name, ""); err != nil {
return nil, httperrors.NewInputParameterError("Duplicate name %s", input.Name)
}
} else {
newName, err := db.GenerateName(NetworkManager, userCred, fmt.Sprintf("%s#", self.Name))
input.Name, err = db.GenerateName(NetworkManager, userCred, fmt.Sprintf("%s#", self.Name))
if err != nil {
return nil, httperrors.NewInternalServerError("GenerateName fail %s", err)
}
name = newName
}
network := &SNetwork{}
network.Name = name
network.IfnameHint, err = NetworkManager.newIfnameHint(name)
network.Name = input.Name
network.IfnameHint, err = NetworkManager.newIfnameHint(input.Name)
if err != nil {
return nil, httperrors.NewBadRequestError("Generate ifname hint failed %s", err)
}
network.GuestIpStart = splitIp
network.GuestIpStart = input.SplitIp
network.GuestIpEnd = self.GuestIpEnd
network.GuestIpMask = self.GuestIpMask
network.GuestGateway = self.GuestGateway
@@ -2053,7 +2071,7 @@ func (self *SNetwork) PerformSplit(ctx context.Context, userCred mcclient.TokenC
return nil, err
}
note := map[string]string{"split_ip": splitIp, "end_ip": network.GuestIpEnd}
note := map[string]string{"split_ip": input.SplitIp, "end_ip": network.GuestIpEnd}
db.OpsLog.LogEvent(self, db.ACT_SPLIT, note, userCred)
logclient.AddActionLogWithContext(ctx, self, logclient.ACT_SPLIT, note, userCred, true)
db.OpsLog.LogEvent(network, db.ACT_CREATE, map[string]string{"network": self.Id}, userCred)
@@ -2064,37 +2082,34 @@ func (manager *SNetworkManager) AllowPerformTryCreateNetwork(ctx context.Context
return db.IsAdminAllowClassPerform(userCred, manager, "try-create-network")
}
func (manager *SNetworkManager) PerformTryCreateNetwork(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
ip, err := data.GetString("ip")
if err != nil {
func (manager *SNetworkManager) PerformTryCreateNetwork(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.NetworkTryCreateNetworkInput) (jsonutils.JSONObject, error) {
if len(input.Ip) == 0 {
return nil, httperrors.NewMissingParameterError("ip")
}
ipV4, err := netutils.NewIPV4Addr(ip)
ipV4, err := netutils.NewIPV4Addr(input.Ip)
if err != nil {
return nil, httperrors.NewInputParameterError("ip")
}
mask, err := data.Int("mask")
if err != nil {
if input.Mask == 0 {
return nil, httperrors.NewMissingParameterError("mask")
}
serverType, err := data.GetString("server_type")
if err != nil {
if len(input.ServerType) == 0 {
return nil, httperrors.NewMissingParameterError("server_type")
}
if serverType != api.NETWORK_TYPE_BAREMETAL {
if input.ServerType != api.NETWORK_TYPE_BAREMETAL {
return nil, httperrors.NewBadRequestError("Only support server type %s", api.NETWORK_TYPE_BAREMETAL)
}
if !jsonutils.QueryBoolean(data, "is_on_premise", false) {
if !input.IsOnPremise {
return nil, httperrors.NewBadRequestError("Only support on premise network")
}
var (
ipV4NetAddr = ipV4.NetAddr(int8(mask))
ipV4NetAddr = ipV4.NetAddr(int8(input.Mask))
nm *SNetwork
matched bool
)
q := NetworkManager.Query().Equals("server_type", serverType).Equals("guest_ip_mask", mask)
q := NetworkManager.Query().Equals("server_type", input.ServerType).Equals("guest_ip_mask", input.Mask)
q = managedResourceFilterByCloudType(q, query, "wire_id", func() *sqlchemy.SQuery {
wires := WireManager.Query().SubQuery()
vpcs := VpcManager.Query().SubQuery()
@@ -2141,14 +2156,14 @@ func (manager *SNetworkManager) PerformTryCreateNetwork(ctx context.Context, use
log.Infof("Find same subnet network %s %s/%d", nm.Name, nm.GuestGateway, nm.GuestIpMask)
newNetwork := new(SNetwork)
newNetwork.SetModelManager(NetworkManager, newNetwork)
newNetwork.GuestIpStart = ip
newNetwork.GuestIpEnd = ip
newNetwork.GuestIpStart = input.Ip
newNetwork.GuestIpEnd = input.Ip
newNetwork.GuestGateway = nm.GuestGateway
newNetwork.GuestIpMask = int8(mask)
newNetwork.GuestIpMask = int8(input.Mask)
newNetwork.GuestDns = nm.GuestDns
newNetwork.GuestDhcp = nm.GuestDhcp
newNetwork.WireId = nm.WireId
newNetwork.ServerType = serverType
newNetwork.ServerType = input.ServerType
newNetwork.IsPublic = nm.IsPublic
newNetwork.ProjectId = userCred.GetProjectId()
newNetwork.DomainId = userCred.GetProjectDomainId()
@@ -2162,11 +2177,11 @@ func (manager *SNetworkManager) PerformTryCreateNetwork(ctx context.Context, use
if err != nil {
return nil, err
}
err = newNetwork.CustomizeCreate(ctx, userCred, userCred, query, data)
err = newNetwork.CustomizeCreate(ctx, userCred, userCred, query, input.JSON(input))
if err != nil {
return nil, err
}
newNetwork.PostCreate(ctx, userCred, userCred, query, data)
newNetwork.PostCreate(ctx, userCred, userCred, query, input.JSON(input))
}
return ret, nil
}
@@ -2419,7 +2434,9 @@ func (net *SNetwork) AllowPerformSync(ctx context.Context, userCred mcclient.Tok
return net.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, net, "sync")
}
func (net *SNetwork) PerformSync(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
// 同步接入云IP子网状态
// 本地IDC不支持此操作
func (net *SNetwork) PerformSync(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.NetworkSyncInput) (jsonutils.JSONObject, error) {
vpc := net.GetVpc()
if vpc != nil && vpc.IsManaged() {
err := net.StartNetworkSyncstatusTask(ctx, userCred, "")
@@ -2444,17 +2461,17 @@ func (net *SNetwork) AllowPerformStatus(ctx context.Context, userCred mcclient.T
return net.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, net, "status")
}
func (net *SNetwork) PerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
status, _ := data.GetString("status")
if len(status) == 0 {
// 更改IP子网状态
func (net *SNetwork) PerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.NetworkStatusInput) (jsonutils.JSONObject, error) {
if len(input.Status) == 0 {
return nil, httperrors.NewMissingParameterError("status")
}
vpc := net.GetVpc()
if vpc != nil && vpc.IsManaged() {
return nil, httperrors.NewUnsupportOperationError("managed network cannot change status")
}
if !utils.IsInStringArray(status, []string{api.NETWORK_STATUS_AVAILABLE, api.NETWORK_STATUS_UNAVAILABLE}) {
return nil, httperrors.NewInputParameterError("invalid status %s", status)
if !utils.IsInStringArray(input.Status, []string{api.NETWORK_STATUS_AVAILABLE, api.NETWORK_STATUS_UNAVAILABLE}) {
return nil, httperrors.NewInputParameterError("invalid status %s", input.Status)
}
return net.SSharableVirtualResourceBase.PerformStatus(ctx, userCred, query, data)
return net.SSharableVirtualResourceBase.PerformStatus(ctx, userCred, query, input.JSON(input))
}

View File

@@ -344,6 +344,13 @@ func (self *SSchedtag) GetShortDesc(ctx context.Context) *jsonutils.JSONDict {
return desc
}
func (self *SSchedtag) GetShortDescV2(ctx context.Context) *api.SchedtagShortDescDetails {
desc := &api.SchedtagShortDescDetails{}
desc.StandaloneResourceShortDescDetail = self.SStandaloneResourceBase.GetShortDescV2(ctx)
desc.Default = self.DefaultStrategy
return desc
}
func GetResourceJointSchedtags(obj IModelWithSchedtag) ([]ISchedtagJointModel, error) {
jointMan := obj.GetSchedtagJointManager()
q := jointMan.Query().Equals(jointMan.GetMasterIdKey(jointMan), obj.GetId())
@@ -470,6 +477,18 @@ func GetSchedtagsDetailsToResource(obj IModelWithSchedtag, ctx context.Context,
return extra
}
func GetSchedtagsDetailsToResourceV2(obj IModelWithSchedtag, ctx context.Context) []api.SchedtagShortDescDetails {
info := []api.SchedtagShortDescDetails{}
schedtags := GetSchedtags(obj.GetSchedtagJointManager(), obj.GetId())
if schedtags != nil && len(schedtags) > 0 {
for i := 0; i < len(schedtags); i += 1 {
desc := schedtags[i].GetShortDescV2(ctx)
info = append(info, *desc)
}
}
return info
}
func (s *SSchedtag) AllowPerformSetScope(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return true
}

View File

@@ -226,6 +226,12 @@ func (self *SVpc) getMoreDetails(extra *jsonutils.JSONDict) *jsonutils.JSONDict
return extra
}
func (self *SVpc) getCloudProviderInfoV2() api.CloudproviderDetails {
region, _ := self.GetRegion()
provider := self.GetCloudprovider()
return MakeCloudProviderInfoV2(region, nil, provider)
}
func (self *SVpc) getCloudProviderInfo() SCloudProviderInfo {
region, _ := self.GetRegion()
provider := self.GetCloudprovider()