feature: system resource domainize

This commit is contained in:
Qiu Jian
2020-03-24 18:51:04 +08:00
parent 50ea3b8eda
commit 732dcdcb61
172 changed files with 4386 additions and 1449 deletions
+1 -1
View File
@@ -76,7 +76,7 @@ install: prepare_dir
gencopyright:
@sh scripts/gencopyright.sh pkg cmd
@bash scripts/gencopyright.sh pkg cmd
test:
@go test $(GO_BUILD_FLAGS) $(shell go list ./... | egrep -v 'host-image|hostimage')
+18
View File
@@ -988,4 +988,22 @@ func init() {
printObject(result)
return nil
})
type ClouaccountChangeOwnerOptions struct {
ID string `help:"ID or name of cloudaccount" json:"-"`
ProjectDomain string `json:"project_domain" help:"target domain"`
}
R(&ClouaccountChangeOwnerOptions{}, "cloud-account-change-owner", "Change owner domain of cloudaccount", func(s *mcclient.ClientSession, args *ClouaccountChangeOwnerOptions) error {
if len(args.ProjectDomain) == 0 {
return fmt.Errorf("empty project_domain")
}
params := jsonutils.Marshal(args)
ret, err := modules.Cloudaccounts.PerformAction(s, args.ID, "change-owner", params)
if err != nil {
return err
}
printObject(ret)
return nil
})
}
+17
View File
@@ -706,4 +706,21 @@ func init() {
}
return nil
})
type HostChangeOwnerOptions struct {
ID string `help:"ID or name of host" json:"-"`
ProjectDomain string `json:"project_domain" help:"target domain"`
}
R(&HostChangeOwnerOptions{}, "host-change-owner", "Change owner domain of host", func(s *mcclient.ClientSession, args *HostChangeOwnerOptions) error {
if len(args.ProjectDomain) == 0 {
return fmt.Errorf("empty project_domain")
}
params := jsonutils.Marshal(args)
ret, err := modules.Hosts.PerformAction(s, args.ID, "change-owner", params)
if err != nil {
return err
}
printObject(ret)
return nil
})
}
+14
View File
@@ -1,3 +1,17 @@
// 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 billing
import "time"
+15
View File
@@ -0,0 +1,15 @@
// 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 cloudnet // import "yunion.io/x/onecloud/pkg/apis/cloudnet"
+69
View File
@@ -0,0 +1,69 @@
// 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 cloudnet
import "yunion.io/x/onecloud/pkg/apis"
type RouterUpdateInput struct {
apis.StandaloneResourceBaseUpdateInput
User string `json:"user"`
Host string `json:"host"`
Port *int `json:"port"`
PrivateKey string `json:"private_key"`
RealizeWgIfaces *bool `json:"realize_wg_ifaces"`
RealizeRoutes *bool `json:"realize_routes"`
RealizeRules *bool `json:"realize_rules"`
OldEndpoint string `json:"_old_endpoint"`
}
type RouteUpdateInput struct {
apis.StandaloneResourceBaseUpdateInput
Network string `json:"network"`
Gateway string `json:"gateway"`
}
type RuleUpdateInput struct {
apis.StandaloneResourceBaseUpdateInput
Prio int `json:"prio"`
MatchSrcNet string `json:"match_src_net"`
MatchDestNet string `json:"match_dest_net"`
MatchProto string `json:"match_proto"`
MatchSrcPort int `json:"match_src_port"`
MatchDestPort int `json:"match_dest_port"`
MatchInIfname string `json:"match_in_ifname"`
MatchOutIfname string `json:"match_out_ifname"`
Action string `json:"action"`
ActionOptions string `json:"action_options"`
}
+22
View File
@@ -22,3 +22,25 @@ type BaremetalagentDetails struct {
SBaremetalagent
}
type BaremetalagentCreateInput struct {
apis.StandaloneResourceCreateInput
ZoneResourceInput
AccessIp string `json:"access_ip"`
ManagerUri string `json:"manager_uri"`
AgentType string `json:"agent_type"`
Version string `json:"version"`
}
type BaremetalagentUpdateInput struct {
apis.StandaloneResourceBaseUpdateInput
ZoneResourceInput
AccessIp string `json:"access_ip"`
ManagerUri string `json:"manager_uri"`
AgentType string `json:"agent_type"`
Version string `json:"version"`
}
+4
View File
@@ -116,3 +116,7 @@ type BucketListInput struct {
type BucketSyncstatusInput struct {
}
type BucketUpdateInput struct {
apis.VirtualResourceBaseUpdateInput
}
+24 -4
View File
@@ -130,7 +130,7 @@ type CloudaccountResourceInfo struct {
}
type CloudaccountCreateInput struct {
apis.EnabledStatusDomainLevelResourceCreateInput
apis.EnabledStatusInfrasResourceBaseCreateInput
// 指定云平台
// Qcloud: 腾讯云
@@ -183,7 +183,7 @@ type CloudaccountCreateInput struct {
AutoCreateProject bool `json:"auto_create_project"`
// 额外信息,例如账单的access key
Options *jsonutils.JSONObject `json:"options"`
Options *jsonutils.JSONDict `json:"options"`
// 代理配置
ProxySettingId string `json:"proxy_setting_id"`
@@ -209,7 +209,7 @@ func (i CloudaccountShareModeInput) Validate() error {
}
type CloudaccountListInput struct {
apis.EnabledStatusDomainLevelResourceListInput
apis.EnabledStatusInfrasResourceBaseListInput
ManagedResourceListInput
@@ -235,7 +235,7 @@ type ProviderProject struct {
}
type CloudaccountDetail struct {
apis.EnabledStatusDomainLevelResourceDetails
apis.EnabledStatusInfrasResourceBaseDetails
SCloudaccount
// 子订阅项目信息
@@ -295,3 +295,23 @@ type CloudaccountDetail struct {
// example: 10
StoragecacheCount int `json:"storagecache_count,allowempty"`
}
type CloudaccountUpdateInput struct {
apis.EnabledStatusInfrasResourceBaseUpdateInput
// 同步周期,单位为秒
SyncIntervalSeconds *int64 `json:"sync_interval_seconds"`
// 待更新的options key/value
Options *jsonutils.JSONDict `json:"options"`
// 带删除的options key
RemoveOptions []string `json:"remove_options"`
}
type CloudaccountPerformPublicInput struct {
apis.PerformPublicInput
// 共享模式,可能值为provider_domain, system
// example: provider_domain
ShareMode string `json:"share_mode"`
}
+16 -4
View File
@@ -139,10 +139,8 @@ type CloudproviderDetails struct {
Brand string `json:"brand"`
}
type ManagedResourceListInput struct {
apis.DomainizedResourceListInput
CloudenvResourceListInput
// 云订阅输入参数
type CloudproviderResourceInput struct {
// 列出关联指定云订阅(ID或Name)的资源
Cloudprovider string `json:"cloudprovider"`
// List objects belonging to the cloud provider
@@ -158,6 +156,13 @@ type ManagedResourceListInput struct {
// Deprecated
// description: this param will be deprecate at 3.0
CloudproviderId string `json:"cloudprovider_id" deprecated-by:"cloudprovider"`
}
type ManagedResourceListInput struct {
apis.DomainizedResourceListInput
CloudenvResourceListInput
CloudproviderResourceInput
// 列出关联指定云账号(ID或Name)的资源
Cloudaccount string `json:"cloudaccount"`
@@ -235,3 +240,10 @@ type SyncableBaseResourceListInput struct {
// 同步状态
SyncStatus []string `json:"sync_status"`
}
type CloudproviderUpdateInput struct {
apis.EnabledStatusStandaloneResourceBaseUpdateInput
}
type CloudproviderCreateInput struct {
}
+7
View File
@@ -219,3 +219,10 @@ type DiskResourceInfo struct {
type DiskSyncstatusInput struct {
}
type DiskUpdateInput struct {
apis.VirtualResourceBaseUpdateInput
// 磁盘类型
DiskType string `json:"disk_type"`
}
+18
View File
@@ -0,0 +1,18 @@
// 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 DnsRecordUpdateInput struct {
}
+9 -5
View File
@@ -18,11 +18,8 @@ import (
"yunion.io/x/onecloud/pkg/apis"
)
type RegionalFilterListInput struct {
// 过滤位于指定城市区域的资源
City string `json:"city"`
// 过滤处于指定区域内的资源
type CloudregionResourceInput struct {
// 区域名称或ID
Cloudregion string `json:"cloudregion"`
// swagger:ignore
// Deprecated
@@ -36,6 +33,13 @@ type RegionalFilterListInput struct {
// Deprecated
// description: this param will be deprecate at 3.0
RegionId string `json:"region_id" deprecated-by:"cloudregion"`
}
type RegionalFilterListInput struct {
// 过滤位于指定城市区域的资源
City string `json:"city"`
CloudregionResourceInput
// 按区域名称过滤
OrderByRegion string `json:"order_by_region"`
+10 -2
View File
@@ -19,11 +19,11 @@ import (
)
type GlobalVpcCreateInput struct {
apis.EnabledStatusStandaloneResourceCreateInput
apis.EnabledStatusInfrasResourceBaseCreateInput
}
type GlobalVpcDetails struct {
apis.EnabledStatusStandaloneResourceDetails
apis.EnabledStatusInfrasResourceBaseDetails
SGlobalVpc
}
@@ -40,3 +40,11 @@ type GlobalVpcResourceListInput struct {
// 以GlobalVpc的名称排序
OrderByGlobalvpc string `json:"order_by_globalvpc"`
}
type GlobalvpcUpdateInput struct {
apis.EnabledStatusInfrasResourceBaseUpdateInput
}
type GlobalVpcListInput struct {
apis.EnabledStatusInfrasResourceBaseListInput
}
+16
View File
@@ -50,3 +50,19 @@ type GuestdiskListInput struct {
AioMode []string `json:"aio_mode"`
}
type GuestdiskUpdateInput struct {
GuestJointBaseUpdateInput
Driver string `json:"driver"`
CacheMode string `json:"cache_mode"`
AioMode string `json:"aio_mode"`
Iops *int `json:"iops"`
Bps *int `json:"bps"`
Index *int8 `json:"index"`
}
+10
View File
@@ -53,3 +53,13 @@ type GuestnetworkListInput struct {
TeamWith []string `json:"team_with"`
}
type GuestnetworkUpdateInput struct {
GuestJointBaseUpdateInput
Driver string `json:"driver"`
BwLimit *int `json:"bw_limit"`
Index *int8 `json:"index"`
}
+4
View File
@@ -285,3 +285,7 @@ type GuestFilterListInput struct {
// pattern:asc|desc
OrderByServer string `json:"order_by_server"`
}
type GuestJointBaseUpdateInput struct {
apis.VirtualJointResourceBaseUpdateInput
}
+13 -3
View File
@@ -20,9 +20,7 @@ import (
"yunion.io/x/onecloud/pkg/apis"
)
type GuesttemplateCreateInput struct {
apis.SharableVirtualResourceCreateInput
type GuesttemplateInput struct {
// description: the content of guest template
// required: true
Content jsonutils.JSONObject `json:"content"`
@@ -35,6 +33,18 @@ type GuesttemplateCreateInput struct {
ImageId string `json:"image_id"`
}
type GuesttemplateCreateInput struct {
apis.SharableVirtualResourceCreateInput
GuesttemplateInput
}
type GuesttemplateUpdateInput struct {
apis.SharableVirtualResourceBaseUpdateInput
GuesttemplateInput
}
type GuesttemplateDetails struct {
apis.SharableVirtualResourceDetails
SGuestTemplate
+86 -2
View File
@@ -47,7 +47,7 @@ type DiskSpec struct {
}
type HostListInput struct {
apis.EnabledStatusStandaloneResourceListInput
apis.EnabledStatusInfrasResourceBaseListInput
apis.ExternalizedResourceBaseListInput
ManagedResourceListInput
@@ -111,7 +111,7 @@ type HostListInput struct {
}
type HostDetails struct {
apis.EnabledStatusStandaloneResourceDetails
apis.EnabledStatusInfrasResourceBaseDetails
ManagedResourceInfo
ZoneResourceInfo
@@ -226,3 +226,87 @@ type HostRegisterMetadata struct {
OnKubernetes bool `json:"on_kubernetes"`
Hostname string `json:"hostname"`
}
type HostAccessAttributes struct {
// 物理机管理URI
ManagerUri string `json:"manager_uri"`
// 物理机管理口IP
AccessIp string `json:"access_ip"`
// 物理机管理口MAC
AccessMac string `json:"access_mac"`
// 物理机管理口IP子网
AccessNet string `json:"access_net"`
// 物理机管理口二次网络
AccessWire string `json:"access_wire"`
}
type HostSizeAttributes struct {
// 内存大小(单位MB)
MemSize string `json:"mem_size"`
// 预留内存大小(单位MB)
MemReserved string `json:"mem_reserved"`
// CPU缓存大小(单位MB)
CpuCache string `json:"cpu_cache"`
}
type HostIpmiAttributes struct {
// username
IpmiUsername string `json:"ipmi_username"`
// password
IpmiPassword string `json:"ipmi_password"`
// ip address
IpmiIpAddr string `json:"ipmi_ip_addr"`
// presence
IpmiPresent *bool `json:"ipmi_present"`
// lan channel
IpmiLanChannel *int `json:"ipmi_lan_channel"`
// verified
IpmiVerified *bool `json:"ipmi_verified"`
// Redfish API support
IpmiRedfishApi *bool `json:"ipmi_redfish_api"`
// Cdrom boot support
IpmiCdromBoot *bool `json:"ipmi_cdrom_boot"`
// ipmi_pxe_boot
IpmiPxeBoot *bool `json:"ipmi_pxe_boot"`
}
type HostCreateInput struct {
apis.EnabledStatusInfrasResourceBaseCreateInput
ZoneResourceInput
HostAccessAttributes
HostSizeAttributes
HostIpmiAttributes
// 新建带IPMI信息的物理机时不进行IPMI信息探测
NoProbe *bool `json:"no_probe"`
// host uuid
Uuid string `json:"uuid"`
// Host类型
HostType string `json:"host_type"`
// 是否为裸金属
IsBaremetal *bool `json:"is_baremetal"`
}
type HostUpdateInput struct {
apis.EnabledStatusInfrasResourceBaseUpdateInput
HostAccessAttributes
HostSizeAttributes
HostIpmiAttributes
// IPMI info
IpmiInfo jsonutils.JSONObject `json:"ipmi_info"`
// CPU超售比上限
CpuCmtbound *float32 `json:"cpu_cmtbound"`
// 内存超售比上限
MemCmtbound *float32 `json:"mem_cmtbound"`
}
+2 -2
View File
@@ -72,7 +72,7 @@ type ExternalProjectListInput struct {
}
type RouteTableListInput struct {
apis.VirtualResourceListInput
apis.StatusInfrasResourceBaseListInput
apis.ExternalizedResourceBaseListInput
VpcFilterListInput
@@ -94,7 +94,7 @@ type SnapshotPolicyCacheListInput struct {
}
type NetworkInterfaceListInput struct {
apis.StatusStandaloneResourceListInput
apis.StatusInfrasResourceBaseListInput
apis.ExternalizedResourceBaseListInput
ManagedResourceListInput
+1 -1
View File
@@ -65,7 +65,7 @@ type SimpleNetwork struct {
}
type NatgatewayDetails struct {
apis.StatusStandaloneResourceDetails
apis.StatusInfrasResourceBaseDetails
VpcResourceInfo
+3 -3
View File
@@ -39,7 +39,7 @@ const (
)
type NatGetewayListInput struct {
apis.StatusStandaloneResourceListInput
apis.StatusInfrasResourceBaseListInput
apis.ExternalizedResourceBaseListInput
VpcFilterListInput
@@ -48,7 +48,7 @@ type NatGetewayListInput struct {
}
type NatEntryListInput struct {
apis.StatusStandaloneResourceListInput
apis.StatusInfrasResourceBaseListInput
apis.ExternalizedResourceBaseListInput
NatGatewayFilterListInput
ManagedResourceListInput
@@ -94,7 +94,7 @@ type NatGatewayFilterListInput struct {
}
type NatEntryDetails struct {
apis.StatusStandaloneResourceDetails
apis.StatusInfrasResourceBaseDetails
NatGatewayResourceInfo
// NAT ENTRY的真实名称??
+28 -19
View File
@@ -18,25 +18,6 @@ import (
"yunion.io/x/onecloud/pkg/apis"
)
type VpcFilterListInputBase struct {
// 过滤关联此VPC(ID或Name)的资源
Vpc string `json:"vpc"`
// swagger:ignore
// Deprecated
// filter by vpc Id
VpcId string `json:"vpc_id" deprecated-by:"vpc"`
// 按VPC名称排序
// pattern:asc|desc
OrderByVpc string `json:"order_by_vpc"`
}
type VpcFilterListInput struct {
VpcFilterListInputBase
RegionalFilterListInput
ManagedResourceListInput
}
type WireFilterListBase struct {
// 过滤连接此二层网络(ID或Name)的资源
Wire string `json:"wire"`
@@ -278,3 +259,31 @@ type NetworkTryCreateNetworkInput struct {
type NetworkSyncInput struct {
apis.Meta
}
type NetworkUpdateInput struct {
apis.SharableVirtualResourceBaseUpdateInput
// 起始IP地址
GuestIpStart string `json:"guest_ip_start"`
// 接收IP地址
GuestIpEnd string `json:"guest_ip_end"`
// 掩码
GuestIpMask *int8 `json:"guest_ip_mask"`
// 网关地址
GuestGateway string `json:"guest_gateway"`
// DNS
GuestDns string `json:"guest_dns"`
// allow multiple dhcp, seperated by ","
GuestDhcp string `json:"guest_dhcp"`
GuestDomain string `json:"guest_domain"`
VlanId *int `json:"vlan_id"`
// 服务器类型
// example: server
ServerType string `json:"server_type"`
// 分配策略
AllocPolicy string `json:"alloc_policy"`
}
+1 -1
View File
@@ -30,7 +30,7 @@ type NetworkInterfaceNetworkInfo struct {
}
type NetworkInterfaceDetails struct {
apis.StatusStandaloneResourceDetails
apis.StatusInfrasResourceBaseDetails
ManagedResourceInfo
CloudregionResourceInfo
+92 -2
View File
@@ -14,11 +14,101 @@
package compute
import "yunion.io/x/onecloud/pkg/apis"
import (
"net"
"reflect"
"strings"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/gotypes"
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/apis"
"yunion.io/x/onecloud/pkg/httperrors"
)
type RouteTableDetails struct {
apis.VirtualResourceDetails
apis.StatusInfrasResourceBaseDetails
VpcResourceInfo
SRouteTable
}
type SRoute struct {
Type string `json:"type"`
Cidr string `json:"cidr"`
NextHopType string `json:"next_hop_type"`
NextHopId string `json:"next_hop_id"`
}
func (route *SRoute) Validate() error {
if strings.Index(route.Cidr, "/") > 0 {
_, ipNet, err := net.ParseCIDR(route.Cidr)
if err != nil {
return errors.Wrapf(httperrors.ErrInputParameter, "net.ParseCIDR %s", err)
}
// normalize from 192.168.1.3/24 to 192.168.1.0/24
route.Cidr = ipNet.String()
} else {
ip := net.ParseIP(route.Cidr).To4()
if ip == nil {
return errors.Wrapf(httperrors.ErrInputParameter, "invalid addr %s", route.Cidr)
}
}
return nil
}
type SRoutes []*SRoute
func (routes SRoutes) String() string {
return jsonutils.Marshal(routes).String()
}
func (routes SRoutes) IsZero() bool {
if len(routes) == 0 {
return true
}
return false
}
func (routes *SRoutes) Validate() error {
if routes == nil {
*routes = SRoutes{}
return nil
}
found := map[string]struct{}{}
for _, route := range *routes {
if err := route.Validate(); err != nil {
return err
}
if _, ok := found[route.Cidr]; ok {
// error so that the user has a chance to deal with comments
return httperrors.NewInputParameterError("duplicate route cidr %s", route.Cidr)
}
// TODO aliyun: check overlap with System type route
found[route.Cidr] = struct{}{}
}
return nil
}
type RouteTableCreateInput struct {
apis.StatusInfrasResourceBaseCreateInput
VpcResourceInput
Type string `json:"type"`
Routes *SRoutes `json:"routes"`
}
type RouteTableUpdateInput struct {
apis.StatusInfrasResourceBaseUpdateInput
Routes *SRoutes `json:"routes"`
}
func init() {
gotypes.RegisterSerializable(reflect.TypeOf(&SRoutes{}), func() gotypes.ISerializable {
return &SRoutes{}
})
}
+45 -1
View File
@@ -14,7 +14,9 @@
package compute
import "yunion.io/x/onecloud/pkg/apis"
import (
"yunion.io/x/onecloud/pkg/apis"
)
type ServerSkuCreateInput struct {
apis.StatusStandaloneResourceCreateInput
@@ -139,3 +141,45 @@ type ServerSkuDetails struct {
// 绑定云主机数量
TotalGuestCount int `json:"total_guest_count"`
}
type ServerSkuUpdateInput struct {
apis.StatusStandaloneResourceBaseUpdateInput
InstanceTypeFamily string `json:"instance_type_family"`
InstanceTypeCategory string `json:"instance_type_category"`
LocalCategory string `json:"local_category"` // 记录本地分类
OsName string `json:"os_name"` // Windows|Linux|Any
SysDiskResizable *bool `json:"sys_disk_resizable"`
SysDiskType string `json:"sys_disk_type"`
SysDiskMinSizeGB *int `json:"sys_disk_min_size_gb"` // not required。 windows比较新的版本都是50G左右。
SysDiskMaxSizeGB *int `json:"sys_disk_max_size_gb"` // not required
AttachedDiskType string `json:"attached_disk_type"`
AttachedDiskSizeGB *int `json:"attached_disk_size_gb"`
AttachedDiskCount *int `json:"attached_disk_count"`
DataDiskTypes string `json:"data_disk_types"`
DataDiskMaxCount *int `json:"data_disk_max_count"`
NicType string `json:"nic_type"`
NicMaxCount *int `json:"nic_max_count"`
GpuAttachable *bool `json:"gpu_attachable"`
GpuSpec string `json:"gpu_spec"`
GpuCount *int `json:"gpu_count"`
GpuMaxCount *int `json:"gpu_max_count"`
}
+3 -8
View File
@@ -21,7 +21,7 @@ import (
)
type StorageCreateInput struct {
apis.EnabledStatusStandaloneResourceCreateInput
apis.EnabledStatusInfrasResourceBaseCreateInput
// 存储类型
//
@@ -49,12 +49,7 @@ type StorageCreateInput struct {
// required: true
MediumType string `json:"medium_type"`
// 可用区名称或ID, 建议使用ID
// required: true
Zone string `json:"zone"`
// swagger:ignore
ZoneId string
ZoneResourceInput
// ceph认证主机, storage_type为 rbd 时,此参数为必传项
// 单个ip或以逗号分隔的多个ip具体可查询 /etc/ceph/ceph.conf 文件
@@ -128,7 +123,7 @@ type SStorageCapacityInfo struct {
}
type StorageDetails struct {
apis.EnabledStatusStandaloneResourceDetails
apis.EnabledStatusInfrasResourceBaseDetails
ManagedResourceInfo
ZoneResourceInfo
+1 -1
View File
@@ -168,7 +168,7 @@ type StorageShareFilterListInput struct {
}
type StorageListInput struct {
apis.EnabledStatusStandaloneResourceListInput
apis.EnabledStatusInfrasResourceBaseListInput
apis.ExternalizedResourceBaseListInput
ManagedResourceListInput
+37 -3
View File
@@ -17,13 +17,13 @@ package compute
import "yunion.io/x/onecloud/pkg/apis"
type VpcDetails struct {
SVpc
apis.EnabledStatusStandaloneResourceDetails
apis.EnabledStatusInfrasResourceBaseDetails
ManagedResourceInfo
CloudregionResourceInfo
GlobalVpcResourceInfo
SVpc
// 二层网络数量
// example: 1
WireCount int `json:"wire_count"`
@@ -62,3 +62,37 @@ type VpcResourceInfo struct {
type VpcSyncstatusInput struct {
}
type VpcCreateInput struct {
apis.EnabledStatusInfrasResourceBaseCreateInput
CloudregionResourceInput
CloudproviderResourceInput
// CIDR_BLOCK
CidrBlock string `json:"cidr_block"`
}
type VpcResourceInput struct {
// 关联VPC(ID或Name)
Vpc string `json:"vpc"`
// swagger:ignore
// Deprecated
// filter by vpc Id
VpcId string `json:"vpc_id" deprecated-by:"vpc"`
}
type VpcFilterListInputBase struct {
VpcResourceInput
// 按VPC名称排序
// pattern:asc|desc
OrderByVpc string `json:"order_by_vpc"`
}
type VpcFilterListInput struct {
VpcFilterListInputBase
RegionalFilterListInput
ManagedResourceListInput
}
+1 -16
View File
@@ -46,7 +46,7 @@ type UsableVpcResourceListInput struct {
}
type VpcListInput struct {
apis.EnabledStatusStandaloneResourceListInput
apis.EnabledStatusInfrasResourceBaseListInput
apis.ExternalizedResourceBaseListInput
ManagedResourceListInput
@@ -68,21 +68,6 @@ type VpcListInput struct {
CidrBlock []string `json:"cidr_block"`
}
type WireListInput struct {
apis.StandaloneResourceListInput
apis.ExternalizedResourceBaseListInput
VpcFilterListInput
ZonalFilterListBase
HostResourceInput
}
type GlobalVpcListInput struct {
apis.EnabledStatusStandaloneResourceListInput
}
const (
VPC_PROVIDER_OVN = "ovn"
)
+26 -13
View File
@@ -17,7 +17,7 @@ package compute
import "yunion.io/x/onecloud/pkg/apis"
type WireCreateInput struct {
apis.StandaloneResourceCreateInput
apis.InfrasResourceBaseCreateInput
// 带宽大小,单位: Mbps
// default: 0
@@ -29,22 +29,13 @@ type WireCreateInput struct {
// default: 0
Mtu int `json:"mtu"`
// vpc名称或Id
// required: true
Vpc string `json:"vpc"`
// swagger:ignore
// Deprecated
VpcId string `json:"vpc_id" deprecated-by:"vpc"`
VpcResourceInput
// 可用区名称或Id
// required: true
Zone string `json:"zone"`
// swagger:ignore
ZoneId string
ZoneResourceInput
}
type WireDetails struct {
apis.StandaloneResourceDetails
apis.InfrasResourceBaseDetails
VpcResourceInfo
ZoneResourceInfoBase
@@ -75,3 +66,25 @@ type WireResourceInfo struct {
// 可用区
Zone string `json:"zone"`
}
type WireUpdateInput struct {
apis.InfrasResourceBaseUpdateInput
// bandwidth in MB
Bandwidth int `json:"bandwidth"`
// MTU
// example: 1500
Mtu int `json:"mtu"`
}
type WireListInput struct {
apis.InfrasResourceBaseListInput
apis.ExternalizedResourceBaseListInput
VpcFilterListInput
ZonalFilterListBase
HostResourceInput
}
-11
View File
@@ -1585,14 +1585,6 @@ type SReservedip struct {
Status string `json:"status"`
}
// SRoute is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SRoute.
type SRoute struct {
Type string `json:"type"`
Cidr string `json:"cidr"`
NextHopType string `json:"next_hop_type"`
NextHopId string `json:"next_hop_id"`
}
// SRouteTable is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SRouteTable.
type SRouteTable struct {
apis.SVirtualResourceBase
@@ -1602,9 +1594,6 @@ type SRouteTable struct {
Routes *SRoutes `json:"routes"`
}
// SRoutes is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SRoutes.
type SRoutes []*SRoute
// SSchedpolicy is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SSchedpolicy.
type SSchedpolicy struct {
apis.SStandaloneResourceBase
+1
View File
@@ -95,6 +95,7 @@ var (
"enable_rbac",
"non_default_domain_projects",
"time_zone",
"domainized_namespace",
},
}
+7
View File
@@ -25,3 +25,10 @@ type CredentialDetails struct {
Domain string `json:"domain"`
DomainId string `json:"domain_id"`
}
type CredentialUpdateInput struct {
apis.StandaloneResourceBaseUpdateInput
// enabled
Enabled *bool `json:"enabled"`
}
+6
View File
@@ -29,3 +29,9 @@ type DomainDetails struct {
PolicyCount int `json:"policy_count"`
IdpCount int `json:"idp_count"`
}
type DomainUpdateInput struct {
apis.StandaloneResourceBaseUpdateInput
Enabled *bool `json:"enabled"`
}
+63
View File
@@ -15,6 +15,7 @@
package identity
import (
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/apis"
@@ -335,3 +336,65 @@ type ServiceListInput struct {
// 是否启用/禁用
Enabled *bool `json:"enabled"`
}
type IdentityBaseUpdateInput struct {
apis.StandaloneResourceBaseUpdateInput
}
type EnabledIdentityBaseUpdateInput struct {
IdentityBaseUpdateInput
// 是否启用
Enabled *bool `json:"enabled"`
}
type GroupUpdateInput struct {
IdentityBaseUpdateInput
// display name
Displayname string `json:"displayname"`
}
type IdentityProviderUpdateInput struct {
apis.EnabledStatusStandaloneResourceBaseUpdateInput
TargetDomainId string `json:"target_domain_id"`
AutoCreateProject *bool `json:"auto_create_project"`
SyncIntervalSeconds *int `json:"sync_interval_seconds"`
}
type PolicyUpdateInput struct {
EnabledIdentityBaseUpdateInput
Type string `json:"type"`
Blob jsonutils.JSONObject `json:"blob"`
}
type ProjectUpdateInput struct {
IdentityBaseUpdateInput
}
type RoleUpdateInput struct {
IdentityBaseUpdateInput
}
type UserUpdateInput struct {
EnabledIdentityBaseUpdateInput
Email string `json:"email"`
Mobile string `json:"mobile"`
Displayname string `json:"displayname"`
IsSystemAccount *bool `json:"is_system_account"`
AllowWebConsole *bool `json:"allow_web_console"`
EnableMfa *bool `json:"enable_mfa"`
Password string `json:"password"`
}
+1
View File
@@ -1,4 +1,5 @@
// Copyright 2019 Yunion
// 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.
+23 -3
View File
@@ -120,23 +120,26 @@ type StatusStandaloneResourceCreateInput struct {
type StandaloneResourceCreateInput struct {
ResourceBaseCreateInput
// 资源名称,如果generate_name为空,则为必填项
// description: resource name, required if generated_name is not given
// unique: true
// required: true
// example: test-network
Name string `json:"name"`
// 生成资源名称的规则,如果name为空,则为必填项
// description: generated resource name, given a pattern to generate name, required if name is not given
// unique: false
// required: false
// example: test###
GenerateName string `json:"generate_name"`
// description: resource description
// 资源描述
// required: false
// example: test create network
Description string `json:"description"`
// 资源是否为模拟资源
// description: the resource is an emulated resource
// required: false
IsEmulated *bool `json:"is_emulated"`
@@ -173,16 +176,19 @@ type GetDetailsStatusOutput struct {
Status string `json:"status"`
}
type PerformProjectPublicInput struct {
type PerformPublicInput struct {
// 共享项目资源的共享范围,可能的值为:project, domain和system
// pattern: project|domain|system
Scope string `json:"scope"`
// 如果共享范围为项目,则在此列表中指定共享的目标项目
SharedProjects []string `json:"shared_projects"`
// 如果共享范围为域,则在此列表中指定共享的目标域
SharedDomains []string `json:"shared_domains"`
}
type PerformProjectPrivateInput struct {
type PerformPrivateInput struct {
}
type PerformChangeProjectOwnerInput struct {
@@ -198,3 +204,17 @@ type PerformEnableInput struct {
type PerformDisableInput struct {
}
type InfrasResourceBaseCreateInput struct {
DomainLevelResourceCreateInput
}
type StatusInfrasResourceBaseCreateInput struct {
InfrasResourceBaseCreateInput
StatusBaseResourceCreateInput
}
type EnabledStatusInfrasResourceBaseCreateInput struct {
StatusInfrasResourceBaseCreateInput
EnabledBaseResourceCreateInput
}
+17
View File
@@ -199,6 +199,8 @@ type EnabledResourceBaseListInput struct {
type SharableResourceBaseListInput struct {
// 以资源是否共享过滤列表
IsPublic *bool `json:"is_public"`
// 根据资源的共享范围过滤列表,可能值为:system, domain, project
PublicScope string `json:"public_scope"`
}
type DomainLevelResourceListInput struct {
@@ -247,3 +249,18 @@ type DeletePreventableResourceBaseListInput struct {
type ScopedResourceBaseListInput struct {
ProjectizedResourceListInput
}
type InfrasResourceBaseListInput struct {
DomainLevelResourceListInput
SharableResourceBaseListInput
}
type StatusInfrasResourceBaseListInput struct {
InfrasResourceBaseListInput
StatusResourceBaseListInput
}
type EnabledStatusInfrasResourceBaseListInput struct {
StatusInfrasResourceBaseListInput
EnabledResourceBaseListInput
}
+3 -3
View File
@@ -112,10 +112,10 @@ type AlertCreateInput struct {
}
type AlertUpdateInput struct {
apis.Meta
apis.VirtualResourceBaseUpdateInput
Message *string `json:"message"`
// 报警名称
Name *string `json:"name"`
// 报警执行频率
Frequency *int64 `json:"frequency"`
// 报警设置
+14
View File
@@ -1 +1,15 @@
// 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 monitor // import "yunion.io/x/onecloud/pkg/apis/monitor"
+2
View File
@@ -56,6 +56,8 @@ type MeterAlertDetails struct {
}
type MeterAlertUpdateInput struct {
V1AlertUpdateInput
// 比较运算符, 比如: >, <, >=, <=
Comparator *string `json:"comparator"`
// 报警阀值
+6
View File
@@ -180,6 +180,8 @@ type NodeAlertDetails struct {
}
type NodeAlertUpdateInput struct {
V1AlertUpdateInput
// 监控指标名称
Metric *string `json:"metric"`
// 监控资源类型, 比如: guest, host
@@ -203,3 +205,7 @@ type NodeAlertUpdateInput struct {
// 通知接受者
Recipients *string `json:"recipients"`
}
type V1AlertUpdateInput struct {
AlertUpdateInput
}
+29 -2
View File
@@ -39,12 +39,26 @@ type ModelBaseShortDescDetail struct {
type SharedProject struct {
Id string `json:"id"`
Name string `json:"name"`
DomainId string `json:"domain_id"`
Domain string `json:"domain"`
}
type SharedDomain struct {
Id string `json:"id"`
Name string `json:"name"`
}
type SharableResourceBaseInfo struct {
// 共享的项目列表
SharedProjects []SharedProject `json:"shared_projects"`
// 共享的域列表
SharedDomains []SharedDomain `json:"shared_domains"`
}
type SharableVirtualResourceDetails struct {
VirtualResourceDetails
SharedProjects []SharedProject `json:"shared_projects"`
SharableResourceBaseInfo
}
type AdminSharableVirtualResourceDetails struct {
@@ -129,3 +143,16 @@ type ProjectizedResourceInfo struct {
type ScopedResourceBaseInfo struct {
ProjectizedResourceInfo
}
type InfrasResourceBaseDetails struct {
DomainLevelResourceDetails
SharableResourceBaseInfo
}
type StatusInfrasResourceBaseDetails struct {
InfrasResourceBaseDetails
}
type EnabledStatusInfrasResourceBaseDetails struct {
StatusInfrasResourceBaseDetails
}
+87
View File
@@ -0,0 +1,87 @@
// 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 ModelBaseUpdateInput struct {
Meta
}
type ResourceBaseUpdateInput struct {
ModelBaseUpdateInput
}
type StandaloneResourceBaseUpdateInput struct {
ResourceBaseUpdateInput
// 资源名称
Name string `json:"name"`
// 资源描述
Description string `json:"description"`
}
type StatusStandaloneResourceBaseUpdateInput struct {
StandaloneResourceBaseUpdateInput
}
type EnabledStatusStandaloneResourceBaseUpdateInput struct {
StatusStandaloneResourceBaseUpdateInput
}
type VirtualResourceBaseUpdateInput struct {
StatusStandaloneResourceBaseUpdateInput
}
type SharableVirtualResourceBaseUpdateInput struct {
VirtualResourceBaseUpdateInput
}
type AdminSharableVirtualResourceBaseUpdateInput struct {
SharableVirtualResourceBaseUpdateInput
// 管理记录
Records string `json:"records"`
}
type DomainLevelResourceBaseUpdateInput struct {
StandaloneResourceBaseUpdateInput
}
type StatusDomainLevelResourceBaseUpdateInput struct {
DomainLevelResourceBaseUpdateInput
}
type EnabledStatusDomainLevelResourceBaseUpdateInput struct {
StatusDomainLevelResourceBaseUpdateInput
}
type JointResourceBaseUpdateInput struct {
ResourceBaseUpdateInput
}
type VirtualJointResourceBaseUpdateInput struct {
JointResourceBaseUpdateInput
}
type InfrasResourceBaseUpdateInput struct {
DomainLevelResourceBaseUpdateInput
}
type StatusInfrasResourceBaseUpdateInput struct {
InfrasResourceBaseUpdateInput
}
type EnabledStatusInfrasResourceBaseUpdateInput struct {
StatusInfrasResourceBaseUpdateInput
}
+14
View File
@@ -1 +1,15 @@
// 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 yunionconf // import "yunion.io/x/onecloud/pkg/apis/yunionconf"
+10
View File
@@ -31,6 +31,8 @@ var (
defaultPagingLimit int64 = 2048
maxPagingLimit int64 = 2048
domainizedNamespace = true
)
func SetRegion(region string) {
@@ -72,3 +74,11 @@ func GetDefaultPagingLimit() int64 {
func GetMaxPagingLimit() int64 {
return maxPagingLimit
}
func SetDomainizedNamespace(domainNS bool) {
domainizedNamespace = domainNS
}
func IsDomainizedNamespace() bool {
return nonDefaultDomainProjects && domainizedNamespace
}
+15 -1
View File
@@ -31,7 +31,7 @@ import (
type SAdminSharableVirtualResourceBase struct {
SSharableVirtualResourceBase
Records string `charset:"ascii" list:"user" create:"optional" update:"user"`
Records string `charset:"utf8" list:"user" create:"optional" update:"user"`
}
type SAdminSharableVirtualResourceBaseManager struct {
@@ -226,3 +226,17 @@ func (manager *SAdminSharableVirtualResourceBaseManager) FetchCustomizeColumns(
}
return rows
}
func (model *SAdminSharableVirtualResourceBase) ValidateUpdateData(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input apis.AdminSharableVirtualResourceBaseUpdateInput,
) (apis.AdminSharableVirtualResourceBaseUpdateInput, error) {
var err error
input.SharableVirtualResourceBaseUpdateInput, err = model.SSharableVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, input.SharableVirtualResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SSharableVirtualResourceBase.ValidateUpdateData")
}
return input, nil
}
+46
View File
@@ -20,6 +20,8 @@ import (
"reflect"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/gotypes"
"yunion.io/x/sqlchemy"
@@ -56,6 +58,50 @@ func call(obj interface{}, fName string, inputs ...interface{}) ([]reflect.Value
return callObject(reflect.ValueOf(obj), fName, inputs...)
}
func findFunc(modelVal reflect.Value, fName string) (reflect.Value, error) {
funcVal := modelVal.MethodByName(fName)
if !funcVal.IsValid() || funcVal.IsNil() {
log.Debugf("find method %s for %s", fName, modelVal.Type())
if modelVal.Kind() != reflect.Ptr {
return funcVal, errors.Wrapf(httperrors.ErrNotImplemented, "%s not implemented", fName)
}
modelVal = modelVal.Elem()
if modelVal.Kind() != reflect.Struct {
return funcVal, errors.Wrapf(httperrors.ErrNotImplemented, "%s not implemented", fName)
}
modelType := modelVal.Type()
for i := 0; i < modelType.NumField(); i += 1 {
fieldType := modelType.Field(i)
if fieldType.Anonymous {
fieldValue := modelVal.Field(i)
if fieldValue.Kind() != reflect.Ptr && fieldValue.CanAddr() {
newFuncVal, err := findFunc(fieldValue.Addr(), fName)
if err == nil {
if !funcVal.IsValid() || funcVal.IsNil() {
funcVal = newFuncVal
} else {
return funcVal, errors.Wrapf(httperrors.ErrConflict, "%s is ambiguous", fName)
}
}
} else if fieldValue.Kind() == reflect.Ptr {
newFuncVal, err := findFunc(fieldValue, fName)
if err == nil {
if !funcVal.IsValid() || funcVal.IsNil() {
funcVal = newFuncVal
} else {
return funcVal, errors.Wrapf(httperrors.ErrConflict, "%s is ambiguous", fName)
}
}
}
}
}
if !funcVal.IsValid() || funcVal.IsNil() {
return funcVal, errors.Wrapf(httperrors.ErrNotImplemented, "%s is not implemented", fName)
}
}
return funcVal, nil
}
func callObject(modelVal reflect.Value, fName string, inputs ...interface{}) ([]reflect.Value, error) {
funcVal := modelVal.MethodByName(fName)
return callFunc(funcVal, fName, inputs...)
+81
View File
@@ -16,6 +16,7 @@ package db
import (
"context"
"fmt"
"reflect"
"testing"
@@ -117,3 +118,83 @@ func Test_call(t *testing.T) {
})
}
}
type Embeded struct {
}
func (e *Embeded) Method() {
fmt.Println("Embeded Method")
}
type Struct0 struct {
Embeded
}
type Struct1 struct {
Embeded
}
type Struct2 struct {
}
func (e *Struct0) Method() {
fmt.Println("Struct0 Method")
}
type Top0 struct {
Struct0
Struct1
Struct2
}
type Top1 struct {
Struct0
Struct1
Struct2
}
func (e *Top1) Method() {
fmt.Println("Top1 Method")
}
func TestFindFunc(t *testing.T) {
cases := []struct {
obj interface{}
want bool
}{
{
obj: &Embeded{},
want: true,
},
{
obj: &Struct0{},
want: true,
},
{
obj: &Struct1{},
want: true,
},
{
obj: &Struct2{},
want: false,
},
{
obj: &Top0{},
want: true,
},
{
obj: &Top1{},
want: true,
},
}
for _, c := range cases {
t.Logf("%s is called", reflect.TypeOf(c.obj))
funcVal, err := findFunc(reflect.ValueOf(c.obj), "Method")
if funcVal.IsValid() {
funcVal.Call(nil)
}
if (c.want && err != nil) || (!c.want && err == nil) {
t.Errorf("%s want %v but err==nil %v", reflect.TypeOf(c.obj), c.want, err == nil)
}
}
}
-8
View File
@@ -1570,14 +1570,6 @@ func updateItem(manager IModelManager, item IModel, ctx context.Context, userCre
return nil, httperrors.NewInternalServerError("Invalid data JSONObject")
}
name, _ := data.GetString("name")
if len(name) > 0 {
err = alterNameValidator(item, name)
if err != nil {
return nil, err
}
}
dataDict, err = ValidateUpdateData(item, ctx, userCred, query, dataDict)
if err != nil {
errMsg := fmt.Sprintf("validate update data error: %s", err)
+8
View File
@@ -38,6 +38,14 @@ type SDomainizedResourceBase struct {
DomainId string `width:"64" charset:"ascii" default:"default" nullable:"false" index:"true" list:"user" json:"domain_id"`
}
func (manager *SDomainizedResourceBaseManager) NamespaceScope() rbacutils.TRbacScope {
if consts.IsDomainizedNamespace() {
return rbacutils.ScopeDomain
} else {
return rbacutils.ScopeSystem
}
}
func (manager *SDomainizedResourceBaseManager) ResourceScope() rbacutils.TRbacScope {
return rbacutils.ScopeDomain
}
+32 -4
View File
@@ -151,6 +151,18 @@ func (model *SDomainLevelResourceBase) PerformChangeOwner(ctx context.Context, u
})
return nil, nil
}
// change domain, do check
if managed, ok := model.GetIDomainLevelModel().(IManagedResoucceBase); ok {
if !managed.CanShareToDomain(ownerId.GetProjectDomainId()) {
return nil, errors.Wrap(httperrors.ErrForbidden, "cann't share across domain")
}
}
if !IsAdminAllowPerform(userCred, model, "change-owner") {
return nil, errors.Wrap(httperrors.ErrNotSufficientPrivilege, "require system privileges")
}
q := manager.Query().Equals("name", model.GetName())
q = manager.FilterByOwner(q, ownerId, manager.NamespaceScope())
q = manager.FilterBySystemAttributes(q, nil, nil, manager.ResourceScope())
@@ -169,10 +181,12 @@ func (model *SDomainLevelResourceBase) PerformChangeOwner(ctx context.Context, u
former = &formerObj
}
// clean shared projects before update project id
// if err := SharedResourceManager.CleanModelSharedProjects(ctx, userCred, model); err != nil {
// return nil, err
// }
// clean shared projects before update domain id
if sharedModel, ok := model.GetIDomainLevelModel().(ISharableBaseModel); ok {
if err := SharedResourceManager.CleanModelShares(ctx, userCred, sharedModel); err != nil {
return nil, err
}
}
_, err = Update(model, func() error {
model.DomainId = ownerId.GetProjectDomainId()
@@ -271,3 +285,17 @@ func (model *SDomainLevelResourceBase) SyncCloudDomainId(userCred mcclient.Token
func (model *SDomainLevelResourceBase) GetIDomainLevelModel() IDomainLevelModel {
return model.GetVirtualObject().(IDomainLevelModel)
}
func (model *SDomainLevelResourceBase) ValidateUpdateData(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input apis.DomainLevelResourceBaseUpdateInput,
) (apis.DomainLevelResourceBaseUpdateInput, error) {
var err error
input.StandaloneResourceBaseUpdateInput, err = model.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, input.StandaloneResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SStandaloneResourceBase.ValidateUpdateData")
}
return input, nil
}
@@ -146,3 +146,17 @@ func (model *SEnabledStatusDomainLevelResourceBase) GetExtraDetails(
) (apis.EnabledStatusDomainLevelResourceDetails, error) {
return apis.EnabledStatusDomainLevelResourceDetails{}, nil
}
func (model *SEnabledStatusDomainLevelResourceBase) ValidateUpdateData(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input apis.EnabledStatusDomainLevelResourceBaseUpdateInput,
) (apis.EnabledStatusDomainLevelResourceBaseUpdateInput, error) {
var err error
input.StatusDomainLevelResourceBaseUpdateInput, err = model.SStatusDomainLevelResourceBase.ValidateUpdateData(ctx, userCred, query, input.StatusDomainLevelResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SStatusDomainLevelResourceBase.ValidateUpdateData")
}
return input, nil
}
@@ -0,0 +1,162 @@
// 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 db
import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/apis"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
type SEnabledStatusInfrasResourceBase struct {
SStatusInfrasResourceBase
SEnabledResourceBase
}
type SEnabledStatusInfrasResourceBaseManager struct {
SStatusInfrasResourceBaseManager
SEnabledResourceBaseManager
}
func NewEnabledStatusInfrasResourceBaseManager(dt interface{}, tableName string, keyword string, keywordPlural string) SEnabledStatusInfrasResourceBaseManager {
return SEnabledStatusInfrasResourceBaseManager{
SStatusInfrasResourceBaseManager: NewStatusInfrasResourceBaseManager(dt, tableName, keyword, keywordPlural),
}
}
func (self *SEnabledStatusInfrasResourceBase) AllowPerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformEnableInput) bool {
return IsDomainAllowPerform(userCred, self, "enable")
}
func (self *SEnabledStatusInfrasResourceBase) PerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformEnableInput) (jsonutils.JSONObject, error) {
err := EnabledPerformEnable(self, ctx, userCred, true)
if err != nil {
return nil, errors.Wrap(err, "EnabledPerformEnable")
}
return nil, nil
}
func (self *SEnabledStatusInfrasResourceBase) AllowPerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformDisableInput) bool {
return IsDomainAllowPerform(userCred, self, "disable")
}
func (self *SEnabledStatusInfrasResourceBase) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformDisableInput) (jsonutils.JSONObject, error) {
err := EnabledPerformEnable(self, ctx, userCred, false)
if err != nil {
return nil, errors.Wrap(err, "EnabledPerformEnable")
}
return nil, nil
}
func (manager *SEnabledStatusInfrasResourceBaseManager) ValidateCreateData(
ctx context.Context,
userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject,
input apis.EnabledStatusInfrasResourceBaseCreateInput,
) (apis.EnabledStatusInfrasResourceBaseCreateInput, error) {
var err error
input.StatusInfrasResourceBaseCreateInput, err = manager.SStatusInfrasResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.StatusInfrasResourceBaseCreateInput)
if err != nil {
return input, errors.Wrap(err, "SStatusInfrasResourceBaseManager.ValidateCreateData")
}
return input, nil
}
func (manager *SEnabledStatusInfrasResourceBaseManager) ListItemFilter(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query apis.EnabledStatusInfrasResourceBaseListInput,
) (*sqlchemy.SQuery, error) {
q, err := manager.SStatusInfrasResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusInfrasResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SStatusInfrasResourceBaseManager.ListItemFilter")
}
q, err = manager.SEnabledResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SEnabledResourceBaseManager.ListItemFilter")
}
return q, nil
}
func (manager *SEnabledStatusInfrasResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
q, err := manager.SStatusInfrasResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
return q, httperrors.ErrNotFound
}
func (manager *SEnabledStatusInfrasResourceBaseManager) OrderByExtraFields(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query apis.EnabledStatusInfrasResourceBaseListInput,
) (*sqlchemy.SQuery, error) {
q, err := manager.SStatusInfrasResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusInfrasResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SStatusInfrasResourceBaseManager.OrderByExtraFields")
}
return q, nil
}
func (manager *SEnabledStatusInfrasResourceBaseManager) FetchCustomizeColumns(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
objs []interface{},
fields stringutils2.SSortedStrings,
isList bool,
) []apis.EnabledStatusInfrasResourceBaseDetails {
rows := make([]apis.EnabledStatusInfrasResourceBaseDetails, len(objs))
domainRows := manager.SStatusInfrasResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
for i := range rows {
rows[i] = apis.EnabledStatusInfrasResourceBaseDetails{
StatusInfrasResourceBaseDetails: domainRows[i],
}
}
return rows
}
func (model *SEnabledStatusInfrasResourceBase) GetExtraDetails(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
isList bool,
) (apis.EnabledStatusInfrasResourceBaseDetails, error) {
return apis.EnabledStatusInfrasResourceBaseDetails{}, nil
}
func (model *SEnabledStatusInfrasResourceBase) ValidateUpdateData(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input apis.EnabledStatusInfrasResourceBaseUpdateInput,
) (apis.EnabledStatusInfrasResourceBaseUpdateInput, error) {
var err error
input.StatusInfrasResourceBaseUpdateInput, err = model.SStatusInfrasResourceBase.ValidateUpdateData(ctx, userCred, query, input.StatusInfrasResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SStatusInfrasResourceBase.ValidateUpdateData")
}
return input, nil
}
@@ -140,3 +140,17 @@ func (model *SEnabledStatusStandaloneResourceBase) GetExtraDetails(
) (apis.EnabledStatusStandaloneResourceDetails, error) {
return apis.EnabledStatusStandaloneResourceDetails{}, nil
}
func (model *SEnabledStatusStandaloneResourceBase) ValidateUpdateData(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input apis.EnabledStatusStandaloneResourceBaseUpdateInput,
) (apis.EnabledStatusStandaloneResourceBaseUpdateInput, error) {
var err error
input.StatusStandaloneResourceBaseUpdateInput, err = model.SStatusStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, input.StatusStandaloneResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SStatusStandaloneResourceBase.ValidateUpdateData")
}
return input, nil
}
+203
View File
@@ -0,0 +1,203 @@
// 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 db
import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/apis"
"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 SInfrasResourceBaseManager struct {
SDomainLevelResourceBaseManager
SSharableBaseResourceManager
}
func NewInfrasResourceBaseManager(
dt interface{},
tableName string,
keyword string,
keywordPlural string,
) SInfrasResourceBaseManager {
return SInfrasResourceBaseManager{
SDomainLevelResourceBaseManager: NewDomainLevelResourceBaseManager(dt, tableName, keyword, keywordPlural),
}
}
type SInfrasResourceBase struct {
SDomainLevelResourceBase
SSharableBaseResource
}
func (manager *SInfrasResourceBaseManager) GetIInfrasModelManager() IInfrasModelManager {
return manager.GetVirtualObject().(IInfrasModelManager)
}
func (manager *SInfrasResourceBaseManager) FilterByOwner(q *sqlchemy.SQuery, owner mcclient.IIdentityProvider, scope rbacutils.TRbacScope) *sqlchemy.SQuery {
return SharableManagerFilterByOwner(manager.GetIInfrasModelManager(), q, owner, scope)
}
func (model *SInfrasResourceBase) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return ((model.IsOwner(userCred) || model.IsSharable(userCred)) && IsAllowGet(rbacutils.ScopeDomain, userCred, model)) || IsAllowGet(rbacutils.ScopeSystem, userCred, model)
}
func (model *SInfrasResourceBase) IsSharable(reqUsrId mcclient.IIdentityProvider) bool {
return SharableModelIsSharable(model.GetIInfrasModel(), reqUsrId)
}
func (model *SInfrasResourceBase) IsShared() bool {
return SharableModelIsShared(model)
}
func (model *SInfrasResourceBase) AllowPerformPublic(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPublicInput) bool {
return true
}
func (model *SInfrasResourceBase) PerformPublic(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPublicInput) (jsonutils.JSONObject, error) {
err := SharablePerformPublic(model, ctx, userCred, input)
if err != nil {
return nil, errors.Wrap(err, "SharablePerformPublic")
}
return nil, nil
}
func (model *SInfrasResourceBase) AllowPerformPrivate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPrivateInput) bool {
return true
}
func (model *SInfrasResourceBase) PerformPrivate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPrivateInput) (jsonutils.JSONObject, error) {
err := SharablePerformPrivate(model, ctx, userCred)
if err != nil {
return nil, errors.Wrap(err, "SharablePerformPrivate")
}
return nil, nil
}
func (model *SInfrasResourceBase) GetIInfrasModel() IInfrasModel {
return model.GetVirtualObject().(IInfrasModel)
}
func (manager *SInfrasResourceBaseManager) ValidateCreateData(
ctx context.Context,
userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject,
input apis.InfrasResourceBaseCreateInput,
) (apis.InfrasResourceBaseCreateInput, error) {
var err error
input.DomainLevelResourceCreateInput, err = manager.SDomainLevelResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.DomainLevelResourceCreateInput)
if err != nil {
return input, errors.Wrap(err, "manager.SDomainLevelResourceBaseManager.ValidateCreateData")
}
return input, nil
}
func (manager *SInfrasResourceBaseManager) ListItemFilter(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query apis.InfrasResourceBaseListInput,
) (*sqlchemy.SQuery, error) {
q, err := manager.SDomainLevelResourceBaseManager.ListItemFilter(ctx, q, userCred, query.DomainLevelResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SDomainLevelResourceBaseManager.ListItemFilter")
}
q, err = manager.SSharableBaseResourceManager.ListItemFilter(ctx, q, userCred, query.SharableResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SSharableBaseResourceManager.ListItemFilter")
}
return q, nil
}
func (manager *SInfrasResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
q, err := manager.SDomainLevelResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
return q, httperrors.ErrNotFound
}
func (manager *SInfrasResourceBaseManager) OrderByExtraFields(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query apis.InfrasResourceBaseListInput) (*sqlchemy.SQuery, error) {
q, err := manager.SDomainLevelResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.DomainLevelResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SDomainLevelResourceBaseManager.OrderByExtraFields")
}
return q, nil
}
func (model *SInfrasResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (apis.InfrasResourceBaseDetails, error) {
return apis.InfrasResourceBaseDetails{}, nil
}
func (manager *SInfrasResourceBaseManager) FetchCustomizeColumns(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
objs []interface{},
fields stringutils2.SSortedStrings,
isList bool,
) []apis.InfrasResourceBaseDetails {
rows := make([]apis.InfrasResourceBaseDetails, len(objs))
domainRows := manager.SDomainLevelResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
shareRows := manager.SSharableBaseResourceManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
for i := range rows {
rows[i] = apis.InfrasResourceBaseDetails{
DomainLevelResourceDetails: domainRows[i],
SharableResourceBaseInfo: shareRows[i],
}
}
return rows
}
func (model *SInfrasResourceBase) ValidateUpdateData(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input apis.InfrasResourceBaseUpdateInput,
) (apis.InfrasResourceBaseUpdateInput, error) {
var err error
input.DomainLevelResourceBaseUpdateInput, err = model.SDomainLevelResourceBase.ValidateUpdateData(ctx, userCred, query, input.DomainLevelResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SDomainLevelResourceBase.ValidateUpdateData")
}
return input, nil
}
func (model *SInfrasResourceBase) GetSharedDomains() []string {
return SharableGetSharedProjects(model, SharedTargetDomain)
}
func (model *SInfrasResourceBase) PerformChangeOwner(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input apis.PerformChangeDomainOwnerInput,
) (jsonutils.JSONObject, error) {
if model.IsShared() {
return nil, errors.Wrap(httperrors.ErrInvalidStatus, "cannot change owner when shared!")
}
return model.SDomainLevelResourceBase.PerformChangeOwner(ctx, userCred, query, input)
}
+19 -1
View File
@@ -276,13 +276,15 @@ type IStandaloneModel interface {
RemoveMetadata(ctx context.Context, key string, userCred mcclient.TokenCredential) error
RemoveAllMetadata(ctx context.Context, userCred mcclient.TokenCredential) error
GetAllMetadata(userCred mcclient.TokenCredential) (map[string]string, error)
IsShared() bool
}
type IDomainLevelModelManager interface {
IStandaloneModelManager
GetIDomainLevelModelManager() IDomainLevelModelManager
GetResourceCount() ([]SProjectResourceCount, error)
GetResourceCount() ([]SDomainResourceCount, error)
}
type IDomainLevelModel interface {
@@ -295,6 +297,20 @@ type IDomainLevelModel interface {
GetIDomainLevelModel() IDomainLevelModel
}
type IInfrasModelManager interface {
IDomainLevelModelManager
GetIInfrasModelManager() IInfrasModelManager
}
type IInfrasModel interface {
IDomainLevelModel
ISharableBase
GetIInfrasModel() IInfrasModel
GetSharedDomains() []string
}
type IVirtualModelManager interface {
IStandaloneModelManager
@@ -322,9 +338,11 @@ type ISharableVirtualModelManager interface {
type ISharableVirtualModel interface {
IVirtualModel
ISharableBase
GetISharableVirtualModel() ISharableVirtualModel
GetSharedProjects() []string
GetSharedDomains() []string
}
type IAdminSharableVirtualModelManager interface {
+14
View File
@@ -282,3 +282,17 @@ func (manager *SJointResourceBaseManager) OrderByExtraFields(
return q, nil
}
func (model *SJointResourceBase) ValidateUpdateData(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input apis.JointResourceBaseUpdateInput,
) (apis.JointResourceBaseUpdateInput, error) {
var err error
input.ResourceBaseUpdateInput, err = model.SResourceBase.ValidateUpdateData(ctx, userCred, query, input.ResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SResourceBase.ValidateUpdateData")
}
return input, nil
}
+19
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 db
type IManagedResoucceBase interface {
CanShareToDomain(domainId string) bool
}
+2 -2
View File
@@ -508,8 +508,8 @@ func (model *SModelBase) AllowUpdateItem(ctx context.Context, userCred mcclient.
return false
}
func (model *SModelBase) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
return data, nil
func (model *SModelBase) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.ModelBaseUpdateInput) (apis.ModelBaseUpdateInput, error) {
return input, nil
}
func (model *SModelBase) PreUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) {
+3
View File
@@ -49,6 +49,9 @@ const (
ACT_DETACH_FAIL = "detach_fail"
ACT_DELETE_FAIL = "delete_fail"
ACT_PUBLIC = "public"
ACT_PRIVATE = "private"
ACT_SYNC_UPDATE = "sync_update"
ACT_SYNC_CREATE = "sync_create"
+9
View File
@@ -176,3 +176,12 @@ func (manager *SResourceBaseManager) FetchCustomizeColumns(
func (model *SResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (apis.ResourceBaseDetails, error) {
return apis.ResourceBaseDetails{}, nil
}
func (model *SResourceBase) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.ResourceBaseUpdateInput) (apis.ResourceBaseUpdateInput, error) {
var err error
input.ModelBaseUpdateInput, err = model.SModelBase.ValidateUpdateData(ctx, userCred, query, input.ModelBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SModelBase.ValidateUpdateData")
}
return input, nil
}
+335 -95
View File
@@ -18,6 +18,8 @@ import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/apis"
@@ -26,105 +28,11 @@ import (
"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 SSharableBaseResourceManager struct{}
func (manager *SSharableBaseResourceManager) FilterByOwner(q *sqlchemy.SQuery, owner mcclient.IIdentityProvider, scope rbacutils.TRbacScope) *sqlchemy.SQuery {
if owner != nil {
switch scope {
case rbacutils.ScopeProject, rbacutils.ScopeDomain:
if len(owner.GetProjectDomainId()) > 0 {
q = q.Filter(sqlchemy.OR(
sqlchemy.Equals(q.Field("domain_id"), owner.GetProjectDomainId()),
sqlchemy.IsTrue(q.Field("is_public")),
))
}
}
}
return q
}
type SSharableBaseResource struct {
IsPublic bool `default:"false" nullable:"false" list:"user"`
}
type ISharableBase interface {
IModel
SetIsPublic(pub bool)
GetIsPublic() bool
}
func (m *SSharableBaseResource) IsSharable(ownerId mcclient.IIdentityProvider) bool {
return m.IsPublic
}
func (m *SSharableBaseResource) SetIsPublic(pub bool) {
m.IsPublic = pub
}
func (m SSharableBaseResource) GetIsPublic() bool {
return m.IsPublic
}
func SharableAllowPerformPublic(model ISharableBase, userCred mcclient.TokenCredential) bool {
return IsAllowPerform(rbacutils.ScopeSystem, userCred, model, "public")
}
func SharablePerformPublic(model ISharableBase, ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
if model.GetIsPublic() {
return nil, nil
}
scope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), model.GetModelManager().KeywordPlural(), policy.PolicyActionPerform, "public")
if scope != rbacutils.ScopeSystem {
return nil, httperrors.NewForbiddenError("not enough privilege")
}
/*ownerId := model.GetOwnerId()
if userCred.GetProjectDomainId() != ownerId.GetProjectDomainId() {
return nil, httperrors.NewForbiddenError("not owner")
}*/
diff, err := Update(model, func() error {
model.SetIsPublic(true)
return nil
})
if err == nil {
OpsLog.LogEvent(model, ACT_UPDATE, diff, userCred)
}
return nil, err
}
func SharableAllowPerformPrivate(model ISharableBase, userCred mcclient.TokenCredential) bool {
return IsAllowPerform(rbacutils.ScopeSystem, userCred, model, "private")
}
func SharablePerformPrivate(model ISharableBase, ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
if !model.GetIsPublic() {
return nil, nil
}
scope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), model.GetModelManager().KeywordPlural(), policy.PolicyActionPerform, "private")
if scope != rbacutils.ScopeSystem {
return nil, httperrors.NewForbiddenError("not enough privilege")
}
/*ownerId := model.GetOwnerId()
if userCred.GetProjectDomainId() != ownerId.GetProjectDomainId() {
return nil, httperrors.NewForbiddenError("not owner")
}*/
diff, err := Update(model, func() error {
model.SetIsPublic(false)
return nil
})
if err == nil {
OpsLog.LogEvent(model, ACT_UPDATE, diff, userCred)
}
return nil, err
}
func (manager *SSharableBaseResourceManager) ListItemFilter(
ctx context.Context,
q *sqlchemy.SQuery,
@@ -138,5 +46,337 @@ func (manager *SSharableBaseResourceManager) ListItemFilter(
q = q.IsFalse("is_public")
}
}
if len(query.PublicScope) > 0 {
q = q.Equals("public_scope", query.PublicScope)
}
return q, nil
}
func (manager *SSharableBaseResourceManager) FetchCustomizeColumns(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
objs []interface{},
fields stringutils2.SSortedStrings,
isList bool,
) []apis.SharableResourceBaseInfo {
rows := make([]apis.SharableResourceBaseInfo, len(objs))
var resType string
resIds := make([]string, len(rows))
var sharedTarget string
for i := range rows {
if model, ok := objs[i].(ISharableBaseModel); ok {
if len(resType) == 0 {
resType = model.Keyword()
}
if len(sharedTarget) == 0 {
sharedTarget = string(model.GetModelManager().ResourceScope())
}
resIds[i] = model.GetId()
}
}
q := SharedResourceManager.Query()
q = q.Equals("resource_type", resType)
q = q.Equals("target_type", sharedTarget)
sharedResourceMap := make(map[string][]SSharedResource)
err := FetchQueryObjectsByIds(q, "resource_id", resIds, &sharedResourceMap)
if err != nil {
log.Errorf("FetchQueryObjectsByIds for shared resource fail %s", err)
return rows
}
targetIds := stringutils2.NewSortedStrings([]string{})
for _, srs := range sharedResourceMap {
for _, sr := range srs {
targetIds = stringutils2.Append(targetIds, sr.TargetProjectId)
}
}
if len(targetIds) == 0 {
return rows
}
tenantMap := make(map[string]STenant)
var subq *sqlchemy.SQuery
switch sharedTarget {
case SharedTargetProject:
subq = TenantCacheManager.GetTenantQuery()
case SharedTargetDomain:
subq = TenantCacheManager.GetDomainQuery()
}
err = FetchQueryObjectsByIds(subq, "id", targetIds, &tenantMap)
if err != nil {
log.Errorf("FetchQueryObjectsByIds for tenant_cache fail %s", err)
return rows
}
for i := range rows {
resId := resIds[i]
if srs, ok := sharedResourceMap[resId]; ok {
switch sharedTarget {
case SharedTargetProject:
projects := make([]apis.SharedProject, len(srs))
for si, sr := range srs {
projects[si].Id = sr.TargetProjectId
if tenant, ok := tenantMap[sr.TargetProjectId]; ok {
projects[si].Name = tenant.Name
projects[si].Domain = tenant.Domain
projects[si].DomainId = tenant.DomainId
}
}
rows[i].SharedProjects = projects
case SharedTargetDomain:
domains := make([]apis.SharedDomain, len(srs))
for si, sr := range srs {
domains[si].Id = sr.TargetProjectId
if tenant, ok := tenantMap[sr.TargetProjectId]; ok {
domains[si].Name = tenant.Name
}
}
rows[i].SharedDomains = domains
}
}
}
return rows
}
func SharableManagerFilterByOwner(manager IStandaloneModelManager, q *sqlchemy.SQuery, owner mcclient.IIdentityProvider, scope rbacutils.TRbacScope) *sqlchemy.SQuery {
if owner != nil {
resScope := manager.ResourceScope()
if resScope == rbacutils.ScopeProject && scope == rbacutils.ScopeProject {
ownerProjectId := owner.GetProjectId()
if len(ownerProjectId) > 0 {
subq := SharedResourceManager.Query("resource_id")
subq = subq.Equals("resource_type", manager.Keyword())
subq = subq.Equals("target_project_id", ownerProjectId)
subq = subq.Equals("target_type", SharedTargetProject)
q = q.Filter(sqlchemy.OR(
sqlchemy.Equals(q.Field("tenant_id"), ownerProjectId),
sqlchemy.AND(
sqlchemy.IsTrue(q.Field("is_public")),
sqlchemy.Equals(q.Field("public_scope"), rbacutils.ScopeSystem),
),
sqlchemy.AND(
sqlchemy.IsTrue(q.Field("is_public")),
sqlchemy.Equals(q.Field("public_scope"), rbacutils.ScopeDomain),
sqlchemy.Equals(q.Field("domain_id"), owner.GetProjectDomainId()),
),
sqlchemy.In(q.Field("id"), subq.SubQuery()),
))
}
} else if (resScope == rbacutils.ScopeDomain && (scope == rbacutils.ScopeProject || scope == rbacutils.ScopeDomain)) || (resScope == rbacutils.ScopeProject && scope == rbacutils.ScopeDomain) {
ownerDomainId := owner.GetProjectDomainId()
if len(ownerDomainId) > 0 {
subq := SharedResourceManager.Query("resource_id")
subq = subq.Equals("resource_type", manager.Keyword())
subq = subq.Equals("target_project_id", ownerDomainId)
subq = subq.Equals("target_type", SharedTargetDomain)
q = q.Filter(sqlchemy.OR(
sqlchemy.Equals(q.Field("domain_id"), ownerDomainId),
sqlchemy.AND(
sqlchemy.IsTrue(q.Field("is_public")),
sqlchemy.Equals(q.Field("public_scope"), rbacutils.ScopeSystem),
),
sqlchemy.AND(
sqlchemy.IsTrue(q.Field("is_public")),
sqlchemy.In(q.Field("id"), subq.SubQuery()),
),
))
}
}
}
return q
}
type SSharableBaseResource struct {
// 是否共享
IsPublic bool `default:"false" nullable:"false" list:"user"`
// 默认共享范围
PublicScope string `width:"16" charset:"ascii" nullable:"false" default:"system" list:"user"`
}
type ISharableBaseModel interface {
IStandaloneModel
ISharableBase
}
type ISharableBase interface {
SetShare(pub bool, scoe rbacutils.TRbacScope)
GetIsPublic() bool
GetPublicScope() rbacutils.TRbacScope
}
func SharableModelIsSharable(model ISharableBaseModel, reqUsrId mcclient.IIdentityProvider) bool {
if model.GetIsPublic() && model.GetPublicScope() == rbacutils.ScopeSystem {
return true
}
ownerId := model.GetOwnerId()
if model.GetIsPublic() && model.GetPublicScope() == rbacutils.ScopeDomain {
if ownerId != nil && ownerId.GetProjectDomainId() == reqUsrId.GetProjectDomainId() {
return true
}
q := SharedResourceManager.Query().Equals("resource_id", model.GetId())
q = q.Equals("resource_type", model.Keyword())
q = q.Equals("target_project_id", reqUsrId.GetProjectDomainId())
q = q.Equals("target_type", SharedTargetDomain)
cnt, _ := q.CountWithError()
if cnt > 0 {
return true
}
}
if model.GetPublicScope() == rbacutils.ScopeProject {
if ownerId != nil && ownerId.GetProjectId() == reqUsrId.GetProjectId() {
return true
}
q := SharedResourceManager.Query().Equals("resource_id", model.GetId())
q = q.Equals("resource_type", model.Keyword())
q = q.Equals("target_project_id", reqUsrId.GetProjectId())
q = q.Equals("target_type", SharedTargetProject)
cnt, _ := q.CountWithError()
if cnt > 0 {
return true
}
}
return false
}
func (m *SSharableBaseResource) SetShare(pub bool, scope rbacutils.TRbacScope) {
m.IsPublic = pub
m.PublicScope = string(scope)
}
func (m SSharableBaseResource) GetIsPublic() bool {
return m.IsPublic
}
func (m SSharableBaseResource) GetPublicScope() rbacutils.TRbacScope {
return rbacutils.String2Scope(m.PublicScope)
}
func SharablePerformPublic(model ISharableBaseModel, ctx context.Context, userCred mcclient.TokenCredential, input apis.PerformPublicInput) error {
var err error
resourceScope := model.GetModelManager().ResourceScope()
targetScope := rbacutils.String2ScopeDefault(input.Scope, rbacutils.ScopeSystem)
if resourceScope.HigherThan(targetScope) {
return errors.Wrapf(httperrors.ErrNotSupported, "cannot share %s resource to %s", resourceScope, targetScope)
}
shareResult := apis.PerformPublicInput{
Scope: string(targetScope),
}
switch targetScope {
case rbacutils.ScopeProject:
if len(input.SharedProjects) == 0 {
return errors.Wrap(httperrors.ErrEmptyRequest, "empty shared target project list")
}
shareResult.SharedProjects, err = SharedResourceManager.shareToTarget(ctx, userCred, model, SharedTargetProject, input.SharedProjects)
if err != nil {
return errors.Wrap(err, "shareToTarget")
}
case rbacutils.ScopeDomain:
_, err = SharedResourceManager.shareToTarget(ctx, userCred, model, SharedTargetProject, nil)
if err != nil {
return errors.Wrap(err, "shareToTarget clean projects")
}
shareResult.SharedDomains, err = SharedResourceManager.shareToTarget(ctx, userCred, model, SharedTargetDomain, input.SharedDomains)
if err != nil {
return errors.Wrap(err, "shareToTarget add domains")
}
case rbacutils.ScopeSystem:
_, err = SharedResourceManager.shareToTarget(ctx, userCred, model, SharedTargetProject, nil)
if err != nil {
return errors.Wrap(err, "shareToTarget clean projects")
}
_, err = SharedResourceManager.shareToTarget(ctx, userCred, model, SharedTargetDomain, nil)
if err != nil {
return errors.Wrap(err, "shareToTarget clean domainss")
}
}
allowScope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), model.KeywordPlural(), policy.PolicyActionPerform, "public")
if targetScope.HigherThan(allowScope) {
return errors.Wrapf(httperrors.ErrNotSufficientPrivilege, "require %s allow %s", targetScope, allowScope)
}
_, err = Update(model, func() error {
model.SetShare(true, targetScope)
return nil
})
if err != nil {
return errors.Wrap(err, "Update")
}
OpsLog.LogEvent(model, ACT_PUBLIC, shareResult, userCred)
model.GetIStandaloneModel().ClearSchedDescCache()
return nil
}
func SharablePerformPrivate(model ISharableBaseModel, ctx context.Context, userCred mcclient.TokenCredential) error {
if !model.GetIsPublic() {
return nil
}
requireScope := model.GetPublicScope()
allowScope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), model.GetModelManager().KeywordPlural(), policy.PolicyActionPerform, "private")
if requireScope.HigherThan(allowScope) {
return errors.Wrapf(httperrors.ErrNotSufficientPrivilege, "require %s allow %s", requireScope, allowScope)
}
err := SharedResourceManager.CleanModelShares(ctx, userCred, model)
if err != nil {
return errors.Wrap(err, "CleanModelShares")
}
diff, err := Update(model, func() error {
model.SetShare(false, rbacutils.ScopeNone)
return nil
})
if err != nil {
return errors.Wrap(err, "Update")
}
OpsLog.LogEvent(model, ACT_PRIVATE, diff, userCred)
model.GetIStandaloneModel().ClearSchedDescCache()
return nil
}
func SharableGetSharedProjects(model ISharableBaseModel, targetType string) []string {
sharedResources := make([]SSharedResource, 0)
q := SharedResourceManager.Query()
q = q.Equals("resource_type", model.Keyword())
q = q.Equals("resource_id", model.GetId())
q = q.Equals("target_type", targetType)
err := q.All(&sharedResources)
if err != nil {
return nil
}
res := make([]string, len(sharedResources))
for i := range sharedResources {
res[i] = sharedResources[i].TargetProjectId
}
return res
}
func SharableModelIsShared(model ISharableBaseModel) bool {
q := SharedResourceManager.Query()
q = q.Equals("resource_type", model.Keyword())
q = q.Equals("resource_id", model.GetId())
cnt, _ := q.CountWithError()
if cnt > 0 {
return true
}
return false
}
+64 -237
View File
@@ -18,14 +18,10 @@ import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"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"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/rbacutils"
@@ -34,13 +30,14 @@ import (
type SSharableVirtualResourceBase struct {
SVirtualResourceBase
IsPublic bool `default:"false" nullable:"false" create:"domain_optional" list:"user" json:"is_public"`
PublicScope string `width:"16" charset:"ascii" nullable:"false" default:"system" create:"domain_optional" list:"user" json:"public_scope"`
SSharableBaseResource
// IsPublic bool `default:"false" nullable:"false" create:"domain_optional" list:"user" json:"is_public"`
// PublicScope string `width:"16" charset:"ascii" nullable:"false" default:"system" create:"domain_optional" list:"user" json:"public_scope"`
}
type SSharableVirtualResourceBaseManager struct {
SVirtualResourceBaseManager
SSharableBaseResourceManager
}
func NewSharableVirtualResourceBaseManager(dt interface{}, tableName string, keyword string, keywordPlural string) SSharableVirtualResourceBaseManager {
@@ -52,196 +49,42 @@ func (manager *SSharableVirtualResourceBaseManager) GetISharableVirtualModelMana
}
func (manager *SSharableVirtualResourceBaseManager) FilterByOwner(q *sqlchemy.SQuery, owner mcclient.IIdentityProvider, scope rbacutils.TRbacScope) *sqlchemy.SQuery {
if owner != nil {
switch scope {
case rbacutils.ScopeProject:
ownerProjectid := owner.GetProjectId()
if len(ownerProjectid) > 0 {
subq := SharedResourceManager.Query("resource_id")
subq = subq.Equals("resource_type", manager.Keyword())
subq = subq.Equals("target_project_id", ownerProjectid)
subq = subq.Equals("owner_project_id", q.Field("tenant_id"))
q = q.Filter(sqlchemy.OR(
sqlchemy.Equals(q.Field("tenant_id"), ownerProjectid),
sqlchemy.AND(
sqlchemy.IsTrue(q.Field("is_public")),
sqlchemy.Equals(q.Field("public_scope"), rbacutils.ScopeSystem),
),
sqlchemy.AND(
sqlchemy.IsTrue(q.Field("is_public")),
sqlchemy.Equals(q.Field("public_scope"), rbacutils.ScopeDomain),
sqlchemy.Equals(q.Field("domain_id"), owner.GetProjectDomainId()),
),
sqlchemy.AND(
sqlchemy.IsFalse(q.Field("is_public")),
sqlchemy.In(q.Field("id"), subq.SubQuery()),
),
))
}
case rbacutils.ScopeDomain:
if len(owner.GetProjectDomainId()) > 0 {
q = q.Filter(sqlchemy.OR(
sqlchemy.Equals(q.Field("domain_id"), owner.GetProjectDomainId()),
sqlchemy.AND(
sqlchemy.IsTrue(q.Field("is_public")),
sqlchemy.Equals(q.Field("public_scope"), rbacutils.ScopeSystem),
),
))
}
}
}
return q
return SharableManagerFilterByOwner(manager.GetISharableVirtualModelManager(), q, owner, scope)
}
func (model *SSharableVirtualResourceBase) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return model.IsOwner(userCred) || model.IsPublic || IsAllowGet(rbacutils.ScopeSystem, userCred, model)
return model.IsOwner(userCred) || model.IsSharable(userCred) || IsAllowGet(rbacutils.ScopeSystem, userCred, model)
}
func (model *SSharableVirtualResourceBase) IsSharable(reqUsrId mcclient.IIdentityProvider) bool {
if model.IsPublic {
switch rbacutils.String2Scope(model.PublicScope) {
case rbacutils.ScopeSystem:
return true
case rbacutils.ScopeDomain:
ownerId := model.GetOwnerId()
if ownerId != nil && ownerId.GetProjectDomainId() == reqUsrId.GetProjectDomainId() {
return true
}
}
}
return false
return SharableModelIsSharable(model.GetISharableVirtualModel(), reqUsrId)
}
func (model *SSharableVirtualResourceBase) AllowPerformPublic(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformProjectPublicInput) bool {
return IsAllowPerform(rbacutils.ScopeSystem, userCred, model, "public")
func (model *SSharableVirtualResourceBase) IsShared() bool {
return SharableModelIsShared(model)
}
func (model *SSharableVirtualResourceBase) PerformPublic(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformProjectPublicInput) (jsonutils.JSONObject, error) {
targetScope := rbacutils.String2ScopeDefault(input.Scope, rbacutils.ScopeSystem)
if targetScope == rbacutils.ScopeProject {
if len(input.SharedProjects) > 0 {
delProjects := make([]*SSharedResource, 0)
addProjects := make([]string, 0)
ops := make(map[string]*SSharedResource, 0)
nps := make([]string, 0)
srs := make([]SSharedResource, 0)
q := SharedResourceManager.Query()
err := q.Filter(sqlchemy.AND(
sqlchemy.Equals(q.Field("owner_project_id"), model.ProjectId),
sqlchemy.Equals(q.Field("resource_id"), model.GetId()),
sqlchemy.Equals(q.Field("resource_type"), model.GetModelManager().Keyword()),
)).All(&srs)
if err != nil {
return nil, httperrors.NewInternalServerError("Fetch project error %s", err)
}
for i := 0; i < len(srs); i++ {
ops[srs[i].TargetProjectId] = &srs[i]
}
for i := 0; i < len(input.SharedProjects); i++ {
sharedProject := input.SharedProjects[i]
tenant, err := TenantCacheManager.FetchTenantByIdOrName(ctx, sharedProject)
if err != nil {
return nil, httperrors.NewBadRequestError("fetch tenant %s error %s", sharedProject, err)
}
if tenant.DomainId != model.DomainId {
return nil, httperrors.NewBadRequestError("can't shared project to other domain")
}
if tenant.GetId() == model.ProjectId {
return nil, httperrors.NewBadRequestError("Can't share project to yourself")
}
nps = append(nps, tenant.GetId())
if _, ok := ops[tenant.GetId()]; !ok {
addProjects = append(addProjects, tenant.GetId())
}
}
for k, v := range ops {
if !utils.IsInStringArray(k, nps) {
delProjects = append(delProjects, v)
}
}
func (model *SSharableVirtualResourceBase) AllowPerformPublic(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPublicInput) bool {
return true
}
for i := 0; i < len(addProjects); i++ {
sharedResource := new(SSharedResource)
sharedResource.ResourceType = model.GetModelManager().Keyword()
sharedResource.ResourceId = model.Id
sharedResource.OwnerProjectId = model.ProjectId
sharedResource.TargetProjectId = addProjects[i]
if insetErr := SharedResourceManager.TableSpec().Insert(sharedResource); insetErr != nil {
return nil, httperrors.NewInternalServerError("Insert shared resource failed %s", insetErr)
}
}
for i := 0; i < len(delProjects); i++ {
delProjects[i].SetModelManager(SharedResourceManager, delProjects[i])
if err := delProjects[i].Delete(ctx, userCred); err != nil {
return nil, httperrors.NewInternalServerError("Unshare project failed %s", err)
}
}
if (len(addProjects) + len(srs) - len(delProjects)) > 0 {
diff, err := Update(model, func() error {
model.IsPublic = false
model.PublicScope = string(targetScope)
return nil
})
if err == nil {
OpsLog.LogEvent(model, ACT_UPDATE, diff, userCred)
} else {
return nil, err
}
}
} else {
return nil, httperrors.NewMissingParameterError("shared_projects")
}
} else {
allowScope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), model.GetModelManager().KeywordPlural(), policy.PolicyActionPerform, "public")
if targetScope.HigherThan(allowScope) {
return nil, httperrors.NewForbiddenError("not enough privilege")
}
if targetScope != rbacutils.ScopeSystem && targetScope != rbacutils.ScopeDomain {
return nil, httperrors.NewInputParameterError("invalid scope %s", targetScope)
}
diff, err := Update(model, func() error {
model.IsPublic = true
model.PublicScope = string(targetScope)
return nil
})
if err == nil {
OpsLog.LogEvent(model, ACT_UPDATE, diff, userCred)
} else {
return nil, err
}
func (model *SSharableVirtualResourceBase) PerformPublic(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPublicInput) (jsonutils.JSONObject, error) {
err := SharablePerformPublic(model, ctx, userCred, input)
if err != nil {
return nil, errors.Wrap(err, "SharablePerformPublic")
}
model.GetIStandaloneModel().ClearSchedDescCache()
return nil, nil
}
func (model *SSharableVirtualResourceBase) AllowPerformPrivate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformProjectPrivateInput) bool {
return IsAllowPerform(rbacutils.ScopeSystem, userCred, model, "private")
func (model *SSharableVirtualResourceBase) AllowPerformPrivate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPrivateInput) bool {
return true
}
func (model *SSharableVirtualResourceBase) PerformPrivate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformProjectPrivateInput) (jsonutils.JSONObject, error) {
if model.IsPublic {
allowScope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), model.GetModelManager().KeywordPlural(), policy.PolicyActionPerform, "private")
requireScope := rbacutils.String2ScopeDefault(model.PublicScope, rbacutils.ScopeSystem)
if requireScope.HigherThan(allowScope) {
return nil, httperrors.NewForbiddenError("not enough privileges: allow %s require %s", allowScope, requireScope)
}
diff, err := Update(model, func() error {
model.PublicScope = string(rbacutils.ScopeNone)
model.IsPublic = false
return nil
})
if err == nil {
OpsLog.LogEvent(model, ACT_UPDATE, diff, userCred)
} else {
return nil, httperrors.NewInternalServerError("Update shared resource error: %s", err)
}
func (model *SSharableVirtualResourceBase) PerformPrivate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPrivateInput) (jsonutils.JSONObject, error) {
err := SharablePerformPrivate(model, ctx, userCred)
if err != nil {
return nil, errors.Wrap(err, "SharablePerformPrivate")
}
if err := SharedResourceManager.CleanModelSharedProjects(ctx, userCred, &model.SVirtualResourceBase); err != nil {
return nil, err
}
model.GetIStandaloneModel().ClearSchedDescCache()
return nil, nil
}
@@ -249,34 +92,6 @@ func (model *SSharableVirtualResourceBase) GetISharableVirtualModel() ISharableV
return model.GetVirtualObject().(ISharableVirtualModel)
}
func (model *SSharableVirtualResourceBase) GetSharedProjects() []string {
sharedResources := make([]SSharedResource, 0)
res := make([]string, 0)
SharedResourceManager.Query().Equals("resource_type", model.GetModelManager().Keyword()).Equals("resource_id", model.GetId()).All(&sharedResources)
for i := 0; i < len(sharedResources); i++ {
res = append(res, sharedResources[i].TargetProjectId)
}
return res
}
/*func (model *SSharableVirtualResourceBase) getMoreDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, out apis.SharableVirtualResourceDetails) apis.SharableVirtualResourceDetails {
out.SharedProjects = []apis.SharedProject{}
projects := model.GetSharedProjects()
for i := 0; i < len(projects); i++ {
tenant, err := TenantCacheManager.FetchTenantByIdOrName(ctx, projects[i])
if err != nil {
log.Errorf("failed fetch tenant by id %s", projects[i])
continue
}
project := apis.SharedProject{
Id: tenant.GetId(),
Name: tenant.GetName(),
}
out.SharedProjects = append(out.SharedProjects, project)
}
return out
}*/
func (manager *SSharableVirtualResourceBaseManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input apis.SharableVirtualResourceCreateInput) (apis.SharableVirtualResourceCreateInput, error) {
var err error
input.VirtualResourceCreateInput, err = manager.SVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.VirtualResourceCreateInput)
@@ -296,15 +111,9 @@ func (manager *SSharableVirtualResourceBaseManager) ListItemFilter(
if err != nil {
return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter")
}
if query.IsPublic != nil {
if *query.IsPublic {
q = q.IsTrue("is_public")
} else {
q = q.IsFalse("is_public")
}
}
if len(query.PublicScope) > 0 {
q = q.Equals("public_scope", query.PublicScope)
q, err = manager.SSharableBaseResourceManager.ListItemFilter(ctx, q, userCred, query.SharableResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SSharableBaseResourceManager.ListItemFilter")
}
return q, nil
}
@@ -337,33 +146,51 @@ func (manager *SSharableVirtualResourceBaseManager) FetchCustomizeColumns(
fields stringutils2.SSortedStrings,
isList bool,
) []apis.SharableVirtualResourceDetails {
rows := make([]apis.SharableVirtualResourceDetails, len(objs))
virtRows := manager.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
resIds := make([]string, len(objs))
shareRows := manager.SSharableBaseResourceManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
for i := range rows {
resIds[i] = objs[i].(ISharableVirtualModel).GetId()
rows[i] = apis.SharableVirtualResourceDetails{
VirtualResourceDetails: virtRows[i],
}
}
tenants := TenantCacheManager.GetTenantQuery().SubQuery()
resources := SharedResourceManager.Query().Equals("resource_type", manager.Keyword()).SubQuery()
q := tenants.Query(tenants.Field("id"), tenants.Field("name"), resources.Field("resource_id"))
q = q.Join(resources, sqlchemy.Equals(q.Field("id"), resources.Field("target_project_id")))
projList := make(map[string][]apis.SharedProject)
err := FetchQueryObjectsByIds(q, "resource_id", resIds, &projList)
if err != nil {
log.Errorf("FetchQueryObjectsByIds fail %s", err)
return rows
}
for i := range rows {
if projs, ok := projList[resIds[i]]; ok {
rows[i].SharedProjects = projs
VirtualResourceDetails: virtRows[i],
SharableResourceBaseInfo: shareRows[i],
}
}
return rows
}
func (model *SSharableVirtualResourceBase) ValidateUpdateData(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input apis.SharableVirtualResourceBaseUpdateInput,
) (apis.SharableVirtualResourceBaseUpdateInput, error) {
var err error
input.VirtualResourceBaseUpdateInput, err = model.SVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, input.VirtualResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SVirtualResourceBase.ValidateUpdateData")
}
return input, nil
}
func (model *SSharableVirtualResourceBase) GetSharedProjects() []string {
return SharableGetSharedProjects(model, SharedTargetProject)
}
func (model *SSharableVirtualResourceBase) GetSharedDomains() []string {
return SharableGetSharedProjects(model, SharedTargetDomain)
}
func (model *SSharableVirtualResourceBase) PerformChangeOwner(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input apis.PerformChangeProjectOwnerInput,
) (jsonutils.JSONObject, error) {
if model.IsShared() {
return nil, errors.Wrap(httperrors.ErrInvalidStatus, "cannot change owner when shared!")
}
return model.SVirtualResourceBase.PerformChangeOwner(ctx, userCred, query, input)
}
+139 -17
View File
@@ -16,14 +16,24 @@ package db
import (
"context"
"database/sql"
"yunion.io/x/sqlchemy"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/cloudcommon/consts"
"yunion.io/x/onecloud/pkg/cloudcommon/policy"
"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"
)
// sharing resoure between project
const (
SharedTargetProject = "project"
SharedTargetDomain = "domain"
)
// sharing resource between projects/domains
type SSharedResource struct {
SResourceBase
@@ -33,6 +43,8 @@ type SSharedResource struct {
ResourceId string `width:"128" charset:"ascii" nullable:"false" index:"true" list:"user" json:"resource_id"`
OwnerProjectId string `width:"128" charset:"ascii" nullable:"false" index:"true" list:"user" json:"owner_project_id"`
TargetProjectId string `width:"128" charset:"ascii" nullable:"false" index:"true" list:"user" json:"target_project_id"`
TargetType string `width:"8" charset:"ascii" default:"project" nullable:"false" list:"user" json:"target_type"`
}
type SSharedResourceManager struct {
@@ -52,22 +64,132 @@ func init() {
}
}
func (manager *SSharedResourceManager) CleanModelSharedProjects(ctx context.Context, userCred mcclient.TokenCredential, model *SVirtualResourceBase) error {
srs := make([]SSharedResource, 0)
q := manager.Query()
err := q.Filter(sqlchemy.AND(
sqlchemy.Equals(q.Field("owner_project_id"), model.ProjectId),
sqlchemy.Equals(q.Field("resource_id"), model.GetId()),
sqlchemy.Equals(q.Field("resource_type"), model.GetModelManager().Keyword()),
)).All(&srs)
if err != nil {
return httperrors.NewInternalServerError("Fetch project error %s", err)
}
for i := 0; i < len(srs); i++ {
srs[i].SetModelManager(manager, &srs[i])
if err := srs[i].Delete(ctx, userCred); err != nil {
return httperrors.NewInternalServerError("Unshare project failed %s", err)
func (manager *SSharedResourceManager) CleanModelShares(ctx context.Context, userCred mcclient.TokenCredential, model ISharableBaseModel) error {
var err error
resScope := model.GetModelManager().ResourceScope()
switch resScope {
case rbacutils.ScopeProject:
_, err = manager.shareToTarget(ctx, userCred, model, SharedTargetProject, nil)
if err != nil {
return errors.Wrap(err, "remove shared project")
}
_, err = manager.shareToTarget(ctx, userCred, model, SharedTargetDomain, nil)
if err != nil {
return errors.Wrap(err, "remove shared domain")
}
case rbacutils.ScopeDomain:
_, err = manager.shareToTarget(ctx, userCred, model, SharedTargetDomain, nil)
if err != nil {
return errors.Wrap(err, "remove shared domain")
}
}
return nil
}
func (manager *SSharedResourceManager) shareToTarget(
ctx context.Context,
userCred mcclient.TokenCredential,
model ISharableBaseModel,
targetType string,
targetIds []string,
) ([]string, error) {
var requireScope rbacutils.TRbacScope
resScope := model.GetModelManager().ResourceScope()
switch resScope {
case rbacutils.ScopeProject:
switch targetType {
case SharedTargetProject:
// should have domain-level privileges
// cannot share to a project across domain
requireScope = rbacutils.ScopeDomain
case SharedTargetDomain:
// should have system-level privileges
requireScope = rbacutils.ScopeSystem
}
case rbacutils.ScopeDomain:
switch targetType {
case SharedTargetDomain:
// should have system-level privileges
requireScope = rbacutils.ScopeSystem
case SharedTargetProject:
return nil, errors.Wrap(httperrors.ErrNotSupported, "cannot share a domain resource to specific project")
}
default:
return nil, errors.Wrap(httperrors.ErrNotSupported, "cannot share a non-project/domain resource")
}
srs := make([]SSharedResource, 0)
q := SharedResourceManager.Query()
q = q.Equals("resource_type", model.Keyword())
q = q.Equals("resource_id", model.GetId())
q = q.Equals("target_type", targetType)
err := FetchModelObjects(SharedResourceManager, q, &srs)
if err != nil && errors.Cause(err) != sql.ErrNoRows {
return nil, errors.Wrap(err, "Fetch shared project")
}
srsMap := make(map[string]*SSharedResource)
_existIds := make([]string, len(srs))
for i := 0; i < len(srs); i++ {
_existIds[i] = srs[i].TargetProjectId
srsMap[srs[i].TargetProjectId] = &srs[i]
}
existIds := stringutils2.NewSortedStrings(_existIds)
newIds := stringutils2.NewSortedStrings([]string{})
modelOwnerId := model.GetOwnerId()
for i := 0; i < len(targetIds); i++ {
switch targetType {
case SharedTargetProject:
tenant, err := TenantCacheManager.FetchTenantByIdOrName(ctx, targetIds[i])
if err != nil {
return nil, errors.Wrapf(err, "fetch tenant %s error", targetIds[i])
}
if tenant.DomainId != modelOwnerId.GetProjectDomainId() {
return nil, httperrors.NewBadRequestError("can't shared project to other domain")
}
if tenant.GetId() == modelOwnerId.GetProjectId() {
return nil, httperrors.NewBadRequestError("can't share to self project")
}
newIds = stringutils2.Append(newIds, tenant.GetId())
case SharedTargetDomain:
domain, err := TenantCacheManager.FetchDomainByIdOrName(ctx, targetIds[i])
if err != nil {
return nil, errors.Wrapf(err, "fetch domain %s error", targetIds[i])
}
if domain.GetId() == modelOwnerId.GetProjectDomainId() {
return nil, httperrors.NewBadRequestError("can't share to self domain")
}
newIds = stringutils2.Append(newIds, domain.GetId())
}
}
delIds, keepIds, addIds := stringutils2.Split(existIds, newIds)
if len(delIds) == 0 && len(addIds) == 0 {
return keepIds, nil
}
allowScope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), model.KeywordPlural(), policy.PolicyActionPerform, "public")
if requireScope.HigherThan(allowScope) {
return nil, errors.Wrapf(httperrors.ErrNotSufficientPrivilege, "require %s allow %s", requireScope, allowScope)
}
for _, targetId := range delIds {
sr := srsMap[targetId]
if err := sr.Delete(ctx, userCred); err != nil {
return nil, errors.Wrap(err, "delete")
}
}
for _, targetId := range addIds {
sharedResource := new(SSharedResource)
sharedResource.ResourceType = model.Keyword()
sharedResource.ResourceId = model.GetId()
sharedResource.TargetProjectId = targetId
sharedResource.TargetType = targetType
if insetErr := SharedResourceManager.TableSpec().Insert(sharedResource); insetErr != nil {
return nil, httperrors.NewInternalServerError("Insert shared resource failed %s", insetErr)
}
}
keepIds = append(keepIds, addIds...)
return keepIds, nil
}
+20
View File
@@ -572,3 +572,23 @@ func (manager *SStandaloneResourceBaseManager) ListItemExportKeys(ctx context.Co
return q, nil
}
func (model *SStandaloneResourceBase) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.StandaloneResourceBaseUpdateInput) (apis.StandaloneResourceBaseUpdateInput, error) {
var err error
input.ResourceBaseUpdateInput, err = model.SResourceBase.ValidateUpdateData(ctx, userCred, query, input.ResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SModelBase.ValidateUpdateData")
}
if len(input.Name) > 0 {
err = alterNameValidator(model.GetIStandaloneModel(), input.Name)
if err != nil {
return input, errors.Wrap(err, "alterNameValidator")
}
}
return input, nil
}
func (model *SStandaloneResourceBase) IsShared() bool {
return false
}
+4 -4
View File
@@ -39,22 +39,22 @@ type SStatusResourceBase struct {
type IStatusBase interface {
IModel
SetStatusValue(status string)
GetStatusValue() string
GetStatus() string
}
func (model *SStatusResourceBase) SetStatusValue(status string) {
model.Status = status
}
func (model SStatusResourceBase) GetStatusValue() string {
func (model SStatusResourceBase) GetStatus() string {
return model.Status
}
func statusBaseSetStatus(model IStatusBase, userCred mcclient.TokenCredential, status string, reason string) error {
if model.GetStatusValue() == status {
if model.GetStatus() == status {
return nil
}
oldStatus := model.GetStatusValue()
oldStatus := model.GetStatus()
_, err := Update(model, func() error {
model.SetStatusValue(status)
return nil
@@ -146,3 +146,17 @@ func (model *SStatusDomainLevelResourceBase) GetExtraDetails(
) (apis.StatusDomainLevelResourceDetails, error) {
return apis.StatusDomainLevelResourceDetails{}, nil
}
func (model *SStatusDomainLevelResourceBase) ValidateUpdateData(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input apis.StatusDomainLevelResourceBaseUpdateInput,
) (apis.StatusDomainLevelResourceBaseUpdateInput, error) {
var err error
input.DomainLevelResourceBaseUpdateInput, err = model.SDomainLevelResourceBase.ValidateUpdateData(ctx, userCred, query, input.DomainLevelResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SDomainLevelResourceBase.ValidateUpdateData")
}
return input, nil
}
+162
View File
@@ -0,0 +1,162 @@
// 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 db
import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/apis"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
type SStatusInfrasResourceBase struct {
SInfrasResourceBase
SStatusResourceBase
}
type SStatusInfrasResourceBaseManager struct {
SInfrasResourceBaseManager
SStatusResourceBaseManager
}
func NewStatusInfrasResourceBaseManager(dt interface{}, tableName string, keyword string, keywordPlural string) SStatusInfrasResourceBaseManager {
return SStatusInfrasResourceBaseManager{
SInfrasResourceBaseManager: NewInfrasResourceBaseManager(dt, tableName, keyword, keywordPlural),
}
}
func (model *SStatusInfrasResourceBase) AllowGetDetailsStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return model.IsOwner(userCred) || IsDomainAllowGetSpec(userCred, model, "status")
}
func (self *SStatusInfrasResourceBase) AllowPerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformStatusInput) bool {
return IsDomainAllowPerform(userCred, self, "status")
}
func (self *SStatusInfrasResourceBase) PerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformStatusInput) (jsonutils.JSONObject, error) {
err := StatusBasePerformStatus(self, userCred, input)
if err != nil {
return nil, errors.Wrap(err, "StatusBasePerformStatus")
}
return nil, nil
}
func (model *SStatusInfrasResourceBase) SetStatus(userCred mcclient.TokenCredential, status string, reason string) error {
return statusBaseSetStatus(model, userCred, status, reason)
}
func (manager *SStatusInfrasResourceBaseManager) ValidateCreateData(
ctx context.Context,
userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject,
input apis.StatusInfrasResourceBaseCreateInput,
) (apis.StatusInfrasResourceBaseCreateInput, error) {
var err error
input.InfrasResourceBaseCreateInput, err = manager.SInfrasResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.InfrasResourceBaseCreateInput)
if err != nil {
return input, errors.Wrap(err, "SInfrasResourceBaseManager.ValidateCreateData")
}
return input, nil
}
func (manager *SStatusInfrasResourceBaseManager) ListItemFilter(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query apis.StatusInfrasResourceBaseListInput,
) (*sqlchemy.SQuery, error) {
q, err := manager.SInfrasResourceBaseManager.ListItemFilter(ctx, q, userCred, query.InfrasResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SInfrasResourceBaseManager.ListItemFilter")
}
q, err = manager.SStatusResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SStatusResourceBaseManager.ListItemFilter")
}
return q, nil
}
func (manager *SStatusInfrasResourceBaseManager) OrderByExtraFields(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query apis.StatusInfrasResourceBaseListInput,
) (*sqlchemy.SQuery, error) {
q, err := manager.SInfrasResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.InfrasResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SInfrasResourceBaseManager.OrderByExtraFields")
}
q, err = manager.SStatusResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SStatusResourceBaseManager.OrderByExtraFields")
}
return q, nil
}
func (manager *SStatusInfrasResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
q, err := manager.SInfrasResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
return q, httperrors.ErrNotFound
}
func (manager *SStatusInfrasResourceBaseManager) FetchCustomizeColumns(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
objs []interface{},
fields stringutils2.SSortedStrings,
isList bool,
) []apis.StatusInfrasResourceBaseDetails {
rows := make([]apis.StatusInfrasResourceBaseDetails, len(objs))
infRows := manager.SInfrasResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
for i := range rows {
rows[i] = apis.StatusInfrasResourceBaseDetails{
InfrasResourceBaseDetails: infRows[i],
}
}
return rows
}
func (model *SStatusInfrasResourceBase) GetExtraDetails(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
isList bool,
) (apis.StatusInfrasResourceBaseDetails, error) {
return apis.StatusInfrasResourceBaseDetails{}, nil
}
func (model *SStatusInfrasResourceBase) ValidateUpdateData(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input apis.StatusInfrasResourceBaseUpdateInput,
) (apis.StatusInfrasResourceBaseUpdateInput, error) {
var err error
input.InfrasResourceBaseUpdateInput, err = model.SInfrasResourceBase.ValidateUpdateData(ctx, userCred, query, input.InfrasResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SInfrasResourceBase.ValidateUpdateData")
}
return input, nil
}
+14 -4
View File
@@ -63,10 +63,6 @@ func (model *SStatusStandaloneResourceBase) SetStatus(userCred mcclient.TokenCre
return statusBaseSetStatus(model, userCred, status, reason)
}
func (model *SStatusStandaloneResourceBase) GetStatus() string {
return model.Status
}
func (manager *SStatusStandaloneResourceBaseManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input apis.StatusStandaloneResourceCreateInput) (apis.StatusStandaloneResourceCreateInput, error) {
var err error
input.StandaloneResourceCreateInput, err = manager.SStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.StandaloneResourceCreateInput)
@@ -139,3 +135,17 @@ func (model *SStatusStandaloneResourceBase) GetExtraDetails(
) (apis.StatusStandaloneResourceDetails, error) {
return apis.StatusStandaloneResourceDetails{}, nil
}
func (model *SStatusStandaloneResourceBase) ValidateUpdateData(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input apis.StatusStandaloneResourceBaseUpdateInput,
) (apis.StatusStandaloneResourceBaseUpdateInput, error) {
var err error
input.StandaloneResourceBaseUpdateInput, err = model.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, input.StandaloneResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SStandaloneResourceBase.ValidateUpdateData")
}
return input, nil
}
+9
View File
@@ -21,6 +21,8 @@ import (
"runtime/debug"
"time"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
@@ -115,6 +117,13 @@ func (manager *STenantCacheManager) fetchTenant(ctx context.Context, idStr strin
q = manager.GetTenantQuery()
}
q = filter(q)
tcnt, err := q.CountWithError()
if err != nil {
return nil, errors.Wrap(err, "CountWithError")
}
if tcnt > 1 {
return nil, httperrors.ErrDuplicateName
}
tobj, err := NewModelObject(manager)
if err != nil {
return nil, errors.Wrap(err, "NewModelObject")
+14
View File
@@ -180,3 +180,17 @@ func (manager *SVirtualJointResourceBaseManager) OrderByExtraFields(
return q, nil
}
func (self *SVirtualJointResourceBase) ValidateUpdateData(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input apis.VirtualJointResourceBaseUpdateInput,
) (apis.VirtualJointResourceBaseUpdateInput, error) {
var err error
input.JointResourceBaseUpdateInput, err = self.SJointResourceBase.ValidateUpdateData(ctx, userCred, query, input.JointResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SJointResourceBase.ValidateUpdateData")
}
return input, nil
}
+38 -2
View File
@@ -60,6 +60,7 @@ type SVirtualResourceBase struct {
// 是否是系统资源
IsSystem bool `nullable:"true" default:"false" list:"admin" create:"optional" json:"is_system"`
// 资源放入回收站时间
PendingDeletedAt time.Time `json:"pending_deleted_at"`
// 资源是否处于回收站中
PendingDeleted bool `nullable:"false" default:"false" index:"true" get:"user" list:"user" json:"pending_deleted"`
@@ -276,6 +277,25 @@ func (model *SVirtualResourceBase) PerformChangeOwner(ctx context.Context, userC
})
return nil, nil
}
var requireScope rbacutils.TRbacScope
if ownerId.GetProjectDomainId() != model.DomainId {
// change domain, do check
if managed, ok := model.GetIVirtualModel().(IManagedResoucceBase); ok {
if !managed.CanShareToDomain(ownerId.GetProjectDomainId()) {
return nil, errors.Wrap(httperrors.ErrForbidden, "cann't share across domain")
}
}
requireScope = rbacutils.ScopeSystem
} else {
requireScope = rbacutils.ScopeDomain
}
allowScope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), model.KeywordPlural(), policy.PolicyActionPerform, "change-owner")
if requireScope.HigherThan(allowScope) {
return nil, errors.Wrapf(httperrors.ErrNotSufficientPrivilege, "require %s allow %s", requireScope, allowScope)
}
q := manager.Query().Equals("name", model.GetName())
q = manager.FilterByOwner(q, ownerId, manager.NamespaceScope())
q = manager.FilterBySystemAttributes(q, nil, nil, manager.ResourceScope())
@@ -295,8 +315,10 @@ func (model *SVirtualResourceBase) PerformChangeOwner(ctx context.Context, userC
}
// clean shared projects before update project id
if err := SharedResourceManager.CleanModelSharedProjects(ctx, userCred, model); err != nil {
return nil, err
if sharedModel, ok := model.GetIVirtualModel().(ISharableBaseModel); ok {
if err := SharedResourceManager.CleanModelShares(ctx, userCred, sharedModel); err != nil {
return nil, err
}
}
_, err = Update(model, func() error {
@@ -495,3 +517,17 @@ func (manager *SVirtualResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.
}
return q, httperrors.ErrNotFound
}
func (model *SVirtualResourceBase) ValidateUpdateData(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input apis.VirtualResourceBaseUpdateInput,
) (apis.VirtualResourceBaseUpdateInput, error) {
var err error
input.StatusStandaloneResourceBaseUpdateInput, err = model.SStatusStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, input.StatusStandaloneResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SStatusStandaloneResourceBase.ValidateUpdateData")
}
return input, nil
}
+14
View File
@@ -1 +1,15 @@
// 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 elect // import "yunion.io/x/onecloud/pkg/cloudcommon/elect"
+3
View File
@@ -34,6 +34,9 @@ func OnBaseOptionsChange(oOpts, nOpts interface{}) bool {
if oldOpts.NonDefaultDomainProjects != newOpts.NonDefaultDomainProjects {
consts.SetNonDefaultDomainProjects(newOpts.NonDefaultDomainProjects)
}
if oldOpts.DomainizedNamespace != newOpts.DomainizedNamespace {
consts.SetDomainizedNamespace(newOpts.DomainizedNamespace)
}
return false
}
+4
View File
@@ -86,6 +86,8 @@ type BaseOptions struct {
TimeZone string `help:"time zone" default:"Asia/Shanghai"`
DomainizedNamespace bool `help:"turn on global name space, default is on" default:"false" json:"global_namespace,allowfalse"`
structarg.BaseOptions
}
@@ -288,4 +290,6 @@ func ParseOptions(optStruct interface{}, args []string, configFileName string, s
if len(optionsRef.Region) > 0 {
consts.SetRegion(optionsRef.Region)
}
consts.SetDomainizedNamespace(optionsRef.DomainizedNamespace)
}
+11 -11
View File
@@ -18,35 +18,35 @@ import "yunion.io/x/pkg/utils"
var (
computeSystemResources = []string{
"hosts",
"zones",
"storages",
"wires",
"globalvpcs",
"route_tables",
"cloudregions",
"serverskus",
"cachedimages",
"dynamicschedtags",
"baremetalagents",
"schedpolicies",
"isolated-devices",
"reservedips",
"dnsrecords",
"metadatas",
"loadbalancerclusters",
"loadbalanceragents",
"networkinterfaces",
"natgateways",
"natsentries",
"natdentries",
"isolated-devices",
"reservedips",
}
computeDomainResources = []string{
"cloudaccounts",
"cloudproviders",
"recyclebins",
// migrate system resources to domain resources
"hosts",
"vpcs",
"storages",
"wires",
"globalvpcs",
"route_tables",
"networkinterfaces",
"natgateways",
"natsentries",
"natdentries",
}
computeUserResources = []string{
"keypairs",
+11 -6
View File
@@ -25,6 +25,7 @@ import (
"yunion.io/x/pkg/util/netutils"
"yunion.io/x/onecloud/pkg/apis"
api "yunion.io/x/onecloud/pkg/apis/cloudnet"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
"yunion.io/x/onecloud/pkg/httperrors"
@@ -113,10 +114,14 @@ func (man *SRouterManager) getById(id string) (*SRouter, error) {
return router, err
}
func (router *SRouter) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
if _, err := router.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, data); err != nil {
return nil, err
func (router *SRouter) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.RouterUpdateInput) (api.RouterUpdateInput, error) {
var err error
input.StandaloneResourceBaseUpdateInput, err = router.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, input.StandaloneResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SStandaloneResourceBase.ValidateUpdateData")
}
data := jsonutils.Marshal(input).(*jsonutils.JSONDict)
vs := []validators.IValidator{
validators.NewStringNonEmptyValidator("user"),
validators.NewStringNonEmptyValidator("host"),
@@ -129,11 +134,11 @@ func (router *SRouter) ValidateUpdateData(ctx context.Context, userCred mcclient
for _, v := range vs {
v.Optional(true)
if err := v.Validate(data); err != nil {
return nil, err
return input, err
}
}
data.Set("_old_endpoint", jsonutils.NewString(router.endpointIP()))
return data, nil
input.OldEndpoint = router.endpointIP()
return input, nil
}
func (router *SRouter) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) {
+9 -5
View File
@@ -23,6 +23,7 @@ import (
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/apis"
api "yunion.io/x/onecloud/pkg/apis/cloudnet"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
"yunion.io/x/onecloud/pkg/httperrors"
@@ -136,10 +137,13 @@ func (man *SRouteManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery
return q, nil
}
func (route *SRoute) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
if _, err := route.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, data); err != nil {
return nil, err
func (route *SRoute) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.RouteUpdateInput) (api.RouteUpdateInput, error) {
var err error
input.StandaloneResourceBaseUpdateInput, err = route.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, input.StandaloneResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SStandaloneResourceBase.ValidateUpdateData")
}
data := jsonutils.Marshal(input).(*jsonutils.JSONDict)
vs := []validators.IValidator{
validators.NewIPv4PrefixValidator("network"),
validators.NewIPv4AddrValidator("gateway"),
@@ -147,10 +151,10 @@ func (route *SRoute) ValidateUpdateData(ctx context.Context, userCred mcclient.T
for _, v := range vs {
v.Optional(true)
if err := v.Validate(data); err != nil {
return nil, err
return input, err
}
}
return nil, nil
return input, nil
}
func (man *SRouteManager) removeByIface(ctx context.Context, userCred mcclient.TokenCredential, iface *SIface) error {
+9 -5
View File
@@ -24,6 +24,7 @@ import (
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/apis"
api "yunion.io/x/onecloud/pkg/apis/cloudnet"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
"yunion.io/x/onecloud/pkg/httperrors"
@@ -233,14 +234,17 @@ func (man *SRuleManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery,
return q, nil
}
func (rule *SRule) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
if _, err := rule.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, data); err != nil {
return nil, err
func (rule *SRule) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.RuleUpdateInput) (api.RuleUpdateInput, error) {
var err error
input.StandaloneResourceBaseUpdateInput, err = rule.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, input.StandaloneResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SStandaloneResourceBase.ValidateUpdateData")
}
data := jsonutils.Marshal(input).(*jsonutils.JSONDict)
if err := RuleManager.validateData(ctx, userCred, rule.GetOwnerId(), query, data, rule); err != nil {
return nil, err
return input, errors.Wrap(err, "validateData")
}
return nil, nil
return input, nil
}
func (man *SRuleManager) removeByRouter(ctx context.Context, userCred mcclient.TokenCredential, router *SRouter) error {
+4 -4
View File
@@ -45,11 +45,11 @@ func (self *SAzureHostDriver) GetHypervisor() string {
return api.HYPERVISOR_AZURE
}
func (self *SAzureHostDriver) ValidateUpdateDisk(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
if data.Contains("name") {
return nil, httperrors.NewInputParameterError("cannot support change azure disk name")
func (self *SAzureHostDriver) ValidateUpdateDisk(ctx context.Context, userCred mcclient.TokenCredential, input api.DiskUpdateInput) (api.DiskUpdateInput, error) {
if len(input.Name) > 0 {
return input, httperrors.NewInputParameterError("cannot support change azure disk name")
}
return data, nil
return input, nil
}
func (self *SAzureHostDriver) ValidateResetDisk(ctx context.Context, userCred mcclient.TokenCredential, disk *models.SDisk, snapshot *models.SSnapshot, guests []models.SGuest, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
+2 -2
View File
@@ -34,8 +34,8 @@ import (
type SBaseHostDriver struct {
}
func (self *SBaseHostDriver) ValidateUpdateDisk(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
return data, nil
func (self *SBaseHostDriver) ValidateUpdateDisk(ctx context.Context, userCred mcclient.TokenCredential, input api.DiskUpdateInput) (api.DiskUpdateInput, error) {
return input, nil
}
func (self *SBaseHostDriver) ValidateResetDisk(ctx context.Context, userCred mcclient.TokenCredential, disk *models.SDisk, snapshot *models.SSnapshot, guests []models.SGuest, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
+35 -18
View File
@@ -25,7 +25,6 @@ import (
"yunion.io/x/pkg/util/regutils"
"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/httperrors"
@@ -80,41 +79,59 @@ func (self *SBaremetalagent) ValidateDeleteCondition(ctx context.Context) error
return self.SStandaloneResourceBase.ValidateDeleteCondition(ctx)
}
func (self *SBaremetalagent) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
mangerUri, err := data.GetString("manager_uri")
if err == nil {
func (self *SBaremetalagent) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.BaremetalagentUpdateInput) (api.BaremetalagentUpdateInput, error) {
var err error
mangerUri := input.ManagerUri
if len(mangerUri) > 0 {
count, err := BaremetalagentManager.Query().Equals("manager_uri", mangerUri).
NotEquals("id", self.Id).CountWithError()
if err != nil {
return nil, httperrors.NewInternalServerError("check agent uniqness fail %s", err)
return input, httperrors.NewInternalServerError("check agent uniqness fail %s", err)
}
if count > 0 {
return nil, httperrors.NewConflictError("Conflict manager_uri %s", mangerUri)
return input, httperrors.NewConflictError("Conflict manager_uri %s", mangerUri)
}
}
return self.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, data)
if len(input.Zone) > 0 {
zoneObj, err := ValidateZoneResourceInput(userCred, input.ZoneResourceInput)
if err != nil {
return input, errors.Wrap(err, "ValidateZoneResourceInput")
}
input.Zone = zoneObj.GetId()
}
input.StandaloneResourceBaseUpdateInput, err = self.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, input.StandaloneResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SStandaloneResourceBase.ValidateUpdateData")
}
return input, nil
}
func (manager *SBaremetalagentManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
mangerUri, _ := data.GetString("manager_uri")
func (manager *SBaremetalagentManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.BaremetalagentCreateInput) (api.BaremetalagentCreateInput, error) {
var err error
mangerUri := input.ManagerUri
if len(mangerUri) == 0 {
return input, errors.Wrap(httperrors.ErrMissingParameter, "manager_uri")
}
count, err := manager.Query().Equals("manager_uri", mangerUri).CountWithError()
if err != nil {
return nil, httperrors.NewInternalServerError("check agent uniqness fail %s", err)
return input, httperrors.NewInternalServerError("check agent uniqness fail %s", err)
}
if count > 0 {
return nil, httperrors.NewDuplicateResourceError("Duplicate manager_uri %s", mangerUri)
return input, httperrors.NewDuplicateResourceError("Duplicate manager_uri %s", mangerUri)
}
input := apis.StandaloneResourceCreateInput{}
err = data.Unmarshal(&input)
if len(input.Zone) == 0 {
return input, errors.Wrap(httperrors.ErrMissingParameter, "zone/zone_id")
}
zoneObj, err := ValidateZoneResourceInput(userCred, input.ZoneResourceInput)
if err != nil {
return nil, httperrors.NewInternalServerError("unmarshal StandaloneResourceCreateInput fail %s", err)
return input, errors.Wrap(err, "ValidateZoneResourceInput")
}
input, err = manager.SStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input)
input.Zone = zoneObj.GetId()
input.StandaloneResourceCreateInput, err = manager.SStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.StandaloneResourceCreateInput)
if err != nil {
return nil, err
return input, errors.Wrap(err, "SStandaloneResourceBaseManager.ValidateCreateData")
}
data.Update(jsonutils.Marshal(input))
return data, nil
return input, nil
}
func (self *SBaremetalagent) AllowPerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
+11 -7
View File
@@ -486,16 +486,20 @@ func (bucket *SBucket) ValidateUpdateData(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
data *jsonutils.JSONDict,
) (*jsonutils.JSONDict, error) {
nameStr, _ := data.GetString("name")
if len(nameStr) > 0 {
err := isValidBucketName(nameStr)
input api.BucketUpdateInput,
) (api.BucketUpdateInput, error) {
var err error
if len(input.Name) > 0 {
err := isValidBucketName(input.Name)
if err != nil {
return nil, httperrors.NewInputParameterError("invalid bucket name: %s", err)
return input, httperrors.NewInputParameterError("invalid bucket name(%s): %s", input.Name, err)
}
}
return bucket.SVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, data)
input.VirtualResourceBaseUpdateInput, err = bucket.SVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, input.VirtualResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SVirtualResourceBase.ValidateUpdateData")
}
return input, nil
}
func (bucket *SBucket) RemoteCreate(ctx context.Context, userCred mcclient.TokenCredential) error {
+7 -4
View File
@@ -132,10 +132,13 @@ func getRegionZoneSubq(region *SCloudregion) *sqlchemy.SSubQuery {
}
func domainManagerFieldFilter(domainId, field string) *sqlchemy.SSubQuery {
providers := CloudproviderManager.Query().SubQuery()
accounts := CloudaccountManager.Query().SubQuery()
accounts := CloudaccountManager.Query("id")
accounts = CloudaccountManager.filterByDomainId(accounts, domainId)
accounts = accounts.Equals("status", api.CLOUD_PROVIDER_CONNECTED)
accounts = accounts.IsTrue("enabled")
q := providers.Query(providers.Field(field))
q := CloudproviderManager.Query(field).Equals("cloudaccount_id", accounts.SubQuery())
/*q := providers.Query(providers.Field(field))
q = q.Join(accounts, sqlchemy.Equals(accounts.Field("id"), providers.Field("cloudaccount_id")))
q = q.Filter(sqlchemy.OR(
sqlchemy.AND(
@@ -149,7 +152,7 @@ func domainManagerFieldFilter(domainId, field string) *sqlchemy.SSubQuery {
),
))
q = q.Filter(sqlchemy.Equals(accounts.Field("status"), api.CLOUD_PROVIDER_CONNECTED))
q = q.Filter(sqlchemy.IsTrue(accounts.Field("enabled")))
q = q.Filter(sqlchemy.IsTrue(accounts.Field("enabled")))*/
return q.SubQuery()
}
+267 -97
View File
@@ -40,7 +40,6 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/db/proxy"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudcommon/policy"
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/options"
@@ -56,7 +55,7 @@ import (
)
type SCloudaccountManager struct {
db.SEnabledStatusDomainLevelResourceBaseManager
db.SEnabledStatusInfrasResourceBaseManager
SSyncableBaseResourceManager
}
@@ -64,7 +63,7 @@ var CloudaccountManager *SCloudaccountManager
func init() {
CloudaccountManager = &SCloudaccountManager{
SEnabledStatusDomainLevelResourceBaseManager: db.NewEnabledStatusDomainLevelResourceBaseManager(
SEnabledStatusInfrasResourceBaseManager: db.NewEnabledStatusInfrasResourceBaseManager(
SCloudaccount{},
"cloudaccounts_tbl",
"cloudaccount",
@@ -77,7 +76,7 @@ func init() {
}
type SCloudaccount struct {
db.SEnabledStatusDomainLevelResourceBase
db.SEnabledStatusInfrasResourceBase `"public_scope->default":""`
SSyncableBaseResource
@@ -151,7 +150,7 @@ type SCloudaccount struct {
Options *jsonutils.JSONDict `get:"domain" create:"domain_optional" update:"domain"`
// for backward compatiblity, keep is_public field, but not usable
IsPublic bool `default:"false" nullable:"false"`
// IsPublic bool `default:"false" nullable:"false"`
// add share_mode field to indicate the share range of this account
ShareMode string `width:"32" charset:"ascii" nullable:"true" list:"domain"`
@@ -213,11 +212,11 @@ func (self *SCloudaccount) ValidateDeleteCondition(ctx context.Context) error {
}
}
return self.SEnabledStatusDomainLevelResourceBase.ValidateDeleteCondition(ctx)
return self.SEnabledStatusInfrasResourceBase.ValidateDeleteCondition(ctx)
}
func (self *SCloudaccount) enableAccountOnly(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformEnableInput) (jsonutils.JSONObject, error) {
return self.SEnabledStatusDomainLevelResourceBase.PerformEnable(ctx, userCred, query, input)
return self.SEnabledStatusInfrasResourceBase.PerformEnable(ctx, userCred, query, input)
}
func (self *SCloudaccount) PerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformEnableInput) (jsonutils.JSONObject, error) {
@@ -241,7 +240,7 @@ func (self *SCloudaccount) PerformEnable(ctx context.Context, userCred mcclient.
}
func (self *SCloudaccount) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformDisableInput) (jsonutils.JSONObject, error) {
_, err := self.SEnabledStatusDomainLevelResourceBase.PerformDisable(ctx, userCred, query, input)
_, err := self.SEnabledStatusInfrasResourceBase.PerformDisable(ctx, userCred, query, input)
if err != nil {
return nil, err
}
@@ -263,36 +262,37 @@ func (self *SCloudaccount) PerformDisable(ctx context.Context, userCred mcclient
return nil, nil
}
func (self *SCloudaccount) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
if data.Contains("sync_interval_seconds") {
syncIntervalSecs, _ := data.Int("sync_interval_seconds")
func (self *SCloudaccount) ValidateUpdateData(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input api.CloudaccountUpdateInput,
) (api.CloudaccountUpdateInput, error) {
var err error
if input.SyncIntervalSeconds != nil {
syncIntervalSecs := *input.SyncIntervalSeconds
if syncIntervalSecs == 0 {
syncIntervalSecs = int64(options.Options.DefaultSyncIntervalSeconds)
} else if syncIntervalSecs < int64(options.Options.MinimalSyncIntervalSeconds) {
syncIntervalSecs = int64(options.Options.MinimalSyncIntervalSeconds)
}
data.Set("sync_interval_seconds", jsonutils.NewInt(syncIntervalSecs))
input.SyncIntervalSeconds = &syncIntervalSecs
}
if data.Contains("options") || data.Contains("remove_options") {
if (input.Options != nil && input.Options.Length() > 0) || len(input.RemoveOptions) > 0 {
var optionsJson *jsonutils.JSONDict
if self.Options != nil {
toRemoveKeys, _ := data.GetArray("remove_options")
removes := make([]string, 0)
if len(toRemoveKeys) > 0 {
for i := range toRemoveKeys {
key, _ := toRemoveKeys[i].GetString()
removes = append(removes, key)
}
if len(input.RemoveOptions) > 0 {
removes = append(removes, input.RemoveOptions...)
}
optionsJson = self.Options.CopyExcludes(removes...)
} else {
optionsJson = jsonutils.NewDict()
}
toUpdate, _ := data.Get("options")
if toUpdate != nil {
optionsJson.Update(toUpdate)
if input.Options != nil {
optionsJson.Update(input.Options)
}
data.Set("options", optionsJson)
input.Options = optionsJson
}
v := validators.NewModelIdOrNameValidator(
@@ -304,10 +304,21 @@ func (self *SCloudaccount) ValidateUpdateData(ctx context.Context, userCred mccl
return nil, err
}
return self.SEnabledStatusDomainLevelResourceBase.ValidateUpdateData(ctx, userCred, query, data)
input.EnabledStatusInfrasResourceBaseUpdateInput, err = self.SEnabledStatusInfrasResourceBase.ValidateUpdateData(ctx, userCred, query, input.EnabledStatusInfrasResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SEnabledStatusInfrasResourceBase.ValidateUpdateData")
}
return input, nil
}
func (manager *SCloudaccountManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.CloudaccountCreateInput) (api.CloudaccountCreateInput, error) {
func (manager *SCloudaccountManager) ValidateCreateData(
ctx context.Context,
userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject,
input api.CloudaccountCreateInput,
) (api.CloudaccountCreateInput, error) {
// check domainId
err := db.ValidateCreateDomainId(ownerId.GetProjectDomainId())
if err != nil {
@@ -422,7 +433,7 @@ func (manager *SCloudaccountManager) ValidateCreateData(ctx context.Context, use
}
}
input.EnabledStatusDomainLevelResourceCreateInput, err = manager.SEnabledStatusDomainLevelResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.EnabledStatusDomainLevelResourceCreateInput)
input.EnabledStatusInfrasResourceBaseCreateInput, err = manager.SEnabledStatusInfrasResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.EnabledStatusInfrasResourceBaseCreateInput)
if err != nil {
return input, err
}
@@ -438,11 +449,11 @@ func (self *SCloudaccount) CustomizeCreate(ctx context.Context, userCred mcclien
self.DomainId = ownerId.GetProjectDomainId()
// self.EnableAutoSync = false
self.ShareMode = api.CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN
return self.SEnabledStatusDomainLevelResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
return self.SEnabledStatusInfrasResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
}
func (self *SCloudaccount) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
self.SEnabledStatusDomainLevelResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
self.SEnabledStatusInfrasResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
self.savePassword(self.Secret)
// if !self.EnableAutoSync {
@@ -1038,10 +1049,10 @@ func (manager *SCloudaccountManager) FetchCustomizeColumns(
isList bool,
) []api.CloudaccountDetail {
rows := make([]api.CloudaccountDetail, len(objs))
stdRows := manager.SEnabledStatusDomainLevelResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
stdRows := manager.SEnabledStatusInfrasResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
for i := range rows {
rows[i] = api.CloudaccountDetail{
EnabledStatusDomainLevelResourceDetails: stdRows[i],
EnabledStatusInfrasResourceBaseDetails: stdRows[i],
}
rows[i] = objs[i].(*SCloudaccount).getMoreDetails(rows[i])
}
@@ -1163,34 +1174,42 @@ func (manager *SCloudaccountManager) initializeShareMode() error {
return nil
}
func (manager *SCloudaccountManager) InitializeData() error {
cloudproviders := []SCloudprovider{}
q := CloudproviderManager.Query()
q = q.IsNullOrEmpty("cloudaccount_id")
err := db.FetchModelObjects(CloudproviderManager, q, &cloudproviders)
func (manager *SCloudaccountManager) initializePublicScope() error {
accounts := []SCloudaccount{}
q := manager.Query().IsNullOrEmpty("public_scope")
err := db.FetchModelObjects(manager, q, &accounts)
if err != nil {
log.Errorf("fetch all clound provider fail %s", err)
log.Errorf("fetch all clound account fail %v", err)
return err
}
for i := 0; i < len(cloudproviders); i++ {
err = migrateCloudprovider(&cloudproviders[i])
for i := 0; i < len(accounts); i++ {
account := &accounts[i]
_, err = db.Update(account, func() error {
switch account.ShareMode {
case api.CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN:
account.PublicScope = string(rbacutils.ScopeNone)
account.IsPublic = false
case api.CLOUD_ACCOUNT_SHARE_MODE_PROVIDER_DOMAIN:
account.PublicScope = string(rbacutils.ScopeSystem)
account.IsPublic = true
case api.CLOUD_ACCOUNT_SHARE_MODE_SYSTEM:
account.PublicScope = string(rbacutils.ScopeSystem)
account.IsPublic = true
}
return nil
})
if err != nil {
return err
}
}
err = manager.initializeBrand()
if err != nil {
return err
}
err = manager.initializeShareMode()
if err != nil {
return err
}
return nil
}
func (manager *SCloudaccountManager) initializeVMWareAccountId() error {
// init accountid
q = manager.Query().Equals("provider", api.CLOUD_PROVIDER_VMWARE)
q := manager.Query().Equals("provider", api.CLOUD_PROVIDER_VMWARE)
cloudaccounts := make([]SCloudaccount, 0)
err = db.FetchModelObjects(manager, q, &cloudaccounts)
err := db.FetchModelObjects(manager, q, &cloudaccounts)
if err != nil {
return errors.Wrap(err, "fetch vmware cloudaccount fail")
}
@@ -1218,6 +1237,41 @@ func (manager *SCloudaccountManager) InitializeData() error {
return nil
}
func (manager *SCloudaccountManager) InitializeData() error {
cloudproviders := []SCloudprovider{}
q := CloudproviderManager.Query()
q = q.IsNullOrEmpty("cloudaccount_id")
err := db.FetchModelObjects(CloudproviderManager, q, &cloudproviders)
if err != nil {
log.Errorf("fetch all clound provider fail %s", err)
return err
}
for i := 0; i < len(cloudproviders); i++ {
err = migrateCloudprovider(&cloudproviders[i])
if err != nil {
return err
}
}
err = manager.initializeBrand()
if err != nil {
return errors.Wrap(err, "initializeBrand")
}
err = manager.initializeShareMode()
if err != nil {
return errors.Wrap(err, "initializeShareMode")
}
err = manager.initializeVMWareAccountId()
if err != nil {
return errors.Wrap(err, "initializeVMWareAccountId")
}
err = manager.initializePublicScope()
if err != nil {
return errors.Wrap(err, "initializePublicScope")
}
return nil
}
func (self *SCloudaccount) GetBalance() (float64, error) {
/*driver, err := self.GetProvider()
if err != nil {
@@ -1292,19 +1346,72 @@ func (self *SCloudaccount) GetVCenterAccessInfo(privateId string) (SVCenterAcces
return info, nil
}
func (self *SCloudaccount) AllowPerformChangeProject(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
// +onecloud:swagger-gen-ignore
func (account *SCloudaccount) PerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeDomainOwnerInput) (jsonutils.JSONObject, error) {
return nil, errors.Wrap(httperrors.ErrForbidden, "can't change domain owner of cloudaccount, use PerformChangeProject instead")
}
func (self *SCloudaccount) AllowPerformChangeProject(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeProjectOwnerInput) bool {
return db.IsAdminAllowPerform(userCred, self, "change-project")
}
func (self *SCloudaccount) PerformChangeProject(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
func (self *SCloudaccount) PerformChangeProject(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeProjectOwnerInput) (jsonutils.JSONObject, error) {
if self.IsShared() {
return nil, errors.Wrap(httperrors.ErrInvalidStatus, "cannot change owner when shared!")
}
project := input.Project
tenant, err := db.TenantCacheManager.FetchTenantByIdOrName(ctx, project)
if err != nil {
return nil, httperrors.NewNotFoundError("project %s not found", project)
}
if tenant.Id == self.ProjectId {
return nil, nil
}
providers := self.GetCloudproviders()
if len(providers) > 1 {
return nil, httperrors.NewInvalidStatusError("multiple subaccounts")
if len(providers) > 0 {
for i := range providers {
if providers[i].ProjectId != self.ProjectId {
return nil, errors.Wrap(httperrors.ErrConflict, "cloudproviders' project is different from cloudaccount's")
}
}
}
if len(providers) == 0 {
return nil, httperrors.NewInvalidStatusError("no subaccount")
if tenant.DomainId != self.DomainId {
// do change domainId
input2 := apis.PerformChangeDomainOwnerInput{}
input2.ProjectDomain = tenant.DomainId
_, err := self.SEnabledStatusInfrasResourceBase.PerformChangeOwner(ctx, userCred, query, input2)
if err != nil {
return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBase.PerformChangeOwner")
}
}
return providers[0].PerformChangeProject(ctx, userCred, query, data)
// save project_id change
diff, err := db.Update(self, func() error {
self.ProjectId = tenant.Id
return nil
})
if err != nil {
return nil, errors.Wrap(err, "db.Update ProjectId")
}
db.OpsLog.LogEvent(self, db.ACT_UPDATE, diff, userCred)
if len(providers) > 0 {
for i := range providers {
_, err := providers[i].PerformChangeProject(ctx, userCred, query, input)
if err != nil {
return nil, errors.Wrapf(err, "providers[i].PerformChangeProject %s(%s)", providers[i].Name, providers[i].Id)
}
}
}
return nil, nil
}
// 云账号列表
@@ -1327,9 +1434,9 @@ func (manager *SCloudaccountManager) ListItemFilter(
q = q.Equals("id", accountObj.GetId())
}
q, err := manager.SEnabledStatusDomainLevelResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusDomainLevelResourceListInput)
q, err := manager.SEnabledStatusInfrasResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusInfrasResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SEnabledStatusDomainLevelResourceBaseManager")
return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager")
}
q, err = manager.SSyncableBaseResourceManager.ListItemFilter(ctx, q, userCred, query.SyncableBaseResourceListInput)
if err != nil {
@@ -1395,7 +1502,7 @@ func (manager *SCloudaccountManager) QueryDistinctExtraField(q *sqlchemy.SQuery,
q = q.AppendField(q.Field("name").Label("account")).Distinct()
return q, nil
}
q, err := manager.SEnabledStatusDomainLevelResourceBaseManager.QueryDistinctExtraField(q, field)
q, err := manager.SEnabledStatusInfrasResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
@@ -1408,9 +1515,9 @@ func (manager *SCloudaccountManager) OrderByExtraFields(
userCred mcclient.TokenCredential,
query api.CloudaccountListInput,
) (*sqlchemy.SQuery, error) {
q, err := manager.SEnabledStatusDomainLevelResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusDomainLevelResourceListInput)
q, err := manager.SEnabledStatusInfrasResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusInfrasResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SEnabledStatusDomainLevelResourceBaseManager.OrderByExtraFields")
return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.OrderByExtraFields")
}
return q, nil
}
@@ -1738,7 +1845,7 @@ func (self *SCloudaccount) Delete(ctx context.Context, userCred mcclient.TokenCr
func (self *SCloudaccount) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
self.SetStatus(userCred, api.CLOUD_PROVIDER_DELETED, "real delete")
return self.SEnabledStatusDomainLevelResourceBase.Delete(ctx, userCred)
return self.SEnabledStatusInfrasResourceBase.Delete(ctx, userCred)
}
func (self *SCloudaccount) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
@@ -1792,76 +1899,96 @@ func (account *SCloudaccount) setShareMode(userCred mcclient.TokenCredential, mo
return nil
}
func (account *SCloudaccount) AllowPerformPublic(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
func (account *SCloudaccount) AllowPerformPublic(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudaccountPerformPublicInput) bool {
return db.IsAllowPerform(rbacutils.ScopeSystem, userCred, account, "public")
}
func (account *SCloudaccount) PerformPublic(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
scope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), account.GetModelManager().KeywordPlural(), policy.PolicyActionPerform, "public")
if scope != rbacutils.ScopeSystem {
return nil, httperrors.NewForbiddenError("not enough privilege")
func (account *SCloudaccount) PerformPublic(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudaccountPerformPublicInput) (jsonutils.JSONObject, error) {
if input.ShareMode != api.CLOUD_ACCOUNT_SHARE_MODE_PROVIDER_DOMAIN && input.ShareMode != api.CLOUD_ACCOUNT_SHARE_MODE_SYSTEM {
return nil, errors.Wrap(httperrors.ErrInputParameter, "share_mode cannot be account_domain")
}
err := account.setShareMode(userCred, api.CLOUD_ACCOUNT_SHARE_MODE_SYSTEM)
if input.ShareMode == api.CLOUD_ACCOUNT_SHARE_MODE_PROVIDER_DOMAIN {
providers := account.GetCloudproviders()
for i := range providers {
if !utils.IsInStringArray(providers[i].DomainId, input.SharedDomains) {
log.Warningf("provider's domainId %s is outside of list of shared domains", providers[i].DomainId)
input.SharedDomains = append(input.SharedDomains, providers[i].DomainId)
}
}
}
_, err := account.SInfrasResourceBase.PerformPublic(ctx, userCred, query, input.PerformPublicInput)
if err != nil {
return nil, httperrors.NewGeneralError(err)
return nil, errors.Wrap(err, "SInfrasResourceBase.PerformPublic")
}
// scope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), account.GetModelManager().KeywordPlural(), policy.PolicyActionPerform, "public")
// if scope != rbacutils.ScopeSystem {
// return nil, httperrors.NewForbiddenError("not enough privilege")
// }
err = account.setShareMode(userCred, input.ShareMode)
if err != nil {
return nil, errors.Wrap(err, "account.setShareMode")
}
return nil, nil
}
func (account *SCloudaccount) AllowPerformPrivate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
func (account *SCloudaccount) AllowPerformPrivate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPrivateInput) bool {
return db.IsAllowPerform(rbacutils.ScopeSystem, userCred, account, "private")
}
func (account *SCloudaccount) PerformPrivate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
func (account *SCloudaccount) PerformPrivate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPrivateInput) (jsonutils.JSONObject, error) {
providers := account.GetCloudproviders()
for i := range providers {
if providers[i].DomainId != account.DomainId {
return nil, httperrors.NewConflictError("provider is shared outside of domain")
}
}
scope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), account.GetModelManager().KeywordPlural(), policy.PolicyActionPerform, "private")
if scope != rbacutils.ScopeSystem {
return nil, httperrors.NewForbiddenError("not enough privilege")
}
err := account.setShareMode(userCred, api.CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN)
_, err := account.SInfrasResourceBase.PerformPrivate(ctx, userCred, query, input)
if err != nil {
return nil, httperrors.NewGeneralError(err)
return nil, errors.Wrap(err, "SInfrasResourceBase.PerformPrivate")
}
// scope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), account.GetModelManager().KeywordPlural(), policy.PolicyActionPerform, "private")
// if scope != rbacutils.ScopeSystem {
// return nil, httperrors.NewForbiddenError("not enough privilege")
// }
err = account.setShareMode(userCred, api.CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN)
if err != nil {
return nil, errors.Wrap(err, "account.setShareMode")
}
return nil, nil
}
func (account *SCloudaccount) AllowPerformShareMode(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
func (account *SCloudaccount) AllowPerformShareMode(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudaccountShareModeInput) bool {
return db.IsAllowPerform(rbacutils.ScopeSystem, userCred, account, "share-mode")
}
func (account *SCloudaccount) PerformShareMode(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
input := api.CloudaccountShareModeInput{}
err := data.Unmarshal(&input)
func (account *SCloudaccount) PerformShareMode(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudaccountShareModeInput) (jsonutils.JSONObject, error) {
err := input.Validate()
if err != nil {
return nil, httperrors.NewInputParameterError("fail to unmarshal input: %s", err)
}
err = input.Validate()
if err != nil {
return nil, err
return nil, errors.Wrap(err, "CloudaccountShareModeInput.Validate")
}
if account.ShareMode == input.ShareMode {
return nil, nil
}
if input.ShareMode == api.CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN {
providers := account.GetCloudproviders()
for i := range providers {
if providers[i].DomainId != account.DomainId {
return nil, httperrors.NewConflictError("provider is shared outside of domain")
}
return account.PerformPrivate(ctx, userCred, query, apis.PerformPrivateInput{})
} else {
input2 := api.CloudaccountPerformPublicInput{
ShareMode: input.ShareMode,
PerformPublicInput: apis.PerformPublicInput{
Scope: string(rbacutils.ScopeSystem),
},
}
return account.PerformPublic(ctx, userCred, query, input2)
}
scope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), account.GetModelManager().KeywordPlural(), policy.PolicyActionPerform, "share-mode")
/*scope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), account.GetModelManager().KeywordPlural(), policy.PolicyActionPerform, "share-mode")
if scope != rbacutils.ScopeSystem {
return nil, httperrors.NewForbiddenError("not enough privilege")
}
@@ -1871,7 +1998,48 @@ func (account *SCloudaccount) PerformShareMode(ctx context.Context, userCred mcc
return nil, httperrors.NewGeneralError(err)
}
return nil, nil
return nil, nil*/
}
func (manager *SCloudaccountManager) filterByDomainId(q *sqlchemy.SQuery, domainId string) *sqlchemy.SQuery {
subq := db.SharedResourceManager.Query("resource_id")
subq = subq.Equals("resource_type", manager.Keyword())
subq = subq.Equals("target_project_id", domainId)
subq = subq.Equals("target_type", db.SharedTargetDomain)
cloudproviders := CloudproviderManager.Query().SubQuery()
q = q.LeftJoin(cloudproviders, sqlchemy.Equals(
q.Field("id"),
cloudproviders.Field("cloudaccount_id"),
))
q = q.Distinct()
q = q.Filter(sqlchemy.OR(
// share_mode=account_domain/private
sqlchemy.Equals(q.Field("domain_id"), domainId),
// share_mode=provider_domain/public_scope=domain
// share_mode=provider_domain/public_scope=system
sqlchemy.AND(
sqlchemy.Equals(q.Field("share_mode"), api.CLOUD_ACCOUNT_SHARE_MODE_PROVIDER_DOMAIN),
sqlchemy.Equals(cloudproviders.Field("domain_id"), domainId),
),
// share_mode=system/public_scope=domain
sqlchemy.AND(
sqlchemy.Equals(q.Field("share_mode"), api.CLOUD_ACCOUNT_SHARE_MODE_SYSTEM),
sqlchemy.In(q.Field("id"), subq.SubQuery()),
sqlchemy.IsTrue(q.Field("is_public")),
sqlchemy.Equals(q.Field("public_scope"), rbacutils.ScopeDomain),
),
// share_mode=system/public_scope=system
sqlchemy.AND(
sqlchemy.Equals(q.Field("share_mode"), api.CLOUD_ACCOUNT_SHARE_MODE_SYSTEM),
sqlchemy.IsTrue(q.Field("is_public")),
sqlchemy.Equals(q.Field("public_scope"), rbacutils.ScopeSystem),
),
))
return q
}
func (manager *SCloudaccountManager) FilterByOwner(q *sqlchemy.SQuery, owner mcclient.IIdentityProvider, scope rbacutils.TRbacScope) *sqlchemy.SQuery {
@@ -1879,7 +2047,8 @@ func (manager *SCloudaccountManager) FilterByOwner(q *sqlchemy.SQuery, owner mcc
switch scope {
case rbacutils.ScopeProject, rbacutils.ScopeDomain:
if len(owner.GetProjectDomainId()) > 0 {
cloudproviders := CloudproviderManager.Query().SubQuery()
q = manager.filterByDomainId(q, owner.GetProjectDomainId())
/*cloudproviders := CloudproviderManager.Query().SubQuery()
q = q.LeftJoin(cloudproviders, sqlchemy.Equals(
q.Field("id"),
cloudproviders.Field("cloudaccount_id"),
@@ -1895,7 +2064,7 @@ func (manager *SCloudaccountManager) FilterByOwner(q *sqlchemy.SQuery, owner mcc
sqlchemy.Equals(q.Field("share_mode"), api.CLOUD_ACCOUNT_SHARE_MODE_PROVIDER_DOMAIN),
sqlchemy.Equals(cloudproviders.Field("domain_id"), owner.GetProjectDomainId()),
),
))
))*/
}
}
}
@@ -2002,7 +2171,8 @@ func (manager *SCloudaccountManager) queryCloudAccountByCapability(region *SClou
q = q.Filter(sqlchemy.Equals(providerregions.Field("cloudregion_id"), region.Id))
}
if len(domainId) > 0 {
q = q.Filter(sqlchemy.OR(
q = manager.filterByDomainId(q, domainId)
/*q = q.Filter(sqlchemy.OR(
sqlchemy.AND(
sqlchemy.Equals(q.Field("share_mode"), api.CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN),
sqlchemy.Equals(q.Field("domain_id"), domainId),
@@ -2012,7 +2182,7 @@ func (manager *SCloudaccountManager) queryCloudAccountByCapability(region *SClou
sqlchemy.Equals(q.Field("share_mode"), api.CLOUD_ACCOUNT_SHARE_MODE_PROVIDER_DOMAIN),
sqlchemy.Equals(providers.Field("domain_id"), domainId),
),
))
))*/
}
return q
}
+21 -11
View File
@@ -292,12 +292,18 @@ func (self *SCloudprovider) getSyncRegionCount() (int, error) {
return CloudproviderRegionManager.Query().Equals("cloudprovider_id", self.Id).CountWithError()
}
func (self *SCloudprovider) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
return self.SEnabledStatusStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, data)
func (self *SCloudprovider) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudproviderUpdateInput) (api.CloudproviderUpdateInput, error) {
var err error
input.EnabledStatusStandaloneResourceBaseUpdateInput, err = self.SEnabledStatusStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, input.EnabledStatusStandaloneResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SEnabledStatusStandaloneResourceBase.ValidateUpdateData")
}
return input, nil
}
func (self *SCloudproviderManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
return nil, httperrors.NewUnsupportOperationError("Directly creating cloudprovider is not supported, create cloudaccount instead")
// +onecloud:swagger-gen-ignore
func (self *SCloudproviderManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.CloudproviderCreateInput) (api.CloudproviderCreateInput, error) {
return input, httperrors.NewUnsupportOperationError("Directly creating cloudprovider is not supported, create cloudaccount instead")
}
func (self *SCloudprovider) getAccessUrl() string {
@@ -559,15 +565,12 @@ func (self *SCloudprovider) StartSyncCloudProviderInfoTask(ctx context.Context,
return nil
}
func (self *SCloudprovider) AllowPerformChangeProject(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
func (self *SCloudprovider) AllowPerformChangeProject(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeProjectOwnerInput) bool {
return db.IsAdminAllowPerform(userCred, self, "change-project")
}
func (self *SCloudprovider) PerformChangeProject(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
project, err := data.GetString("project")
if err != nil {
return nil, httperrors.NewMissingParameterError("project")
}
func (self *SCloudprovider) PerformChangeProject(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeProjectOwnerInput) (jsonutils.JSONObject, error) {
project := input.Project
tenant, err := db.TenantCacheManager.FetchTenantByIdOrName(ctx, project)
if err != nil {
@@ -583,9 +586,16 @@ func (self *SCloudprovider) PerformChangeProject(ctx context.Context, userCred m
if !db.IsAdminAllowPerform(userCred, self, "change-project") {
return nil, httperrors.NewForbiddenError("not allow to change project across domain")
}
if account.ShareMode == api.CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN {
if account.ShareMode == api.CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN && account.DomainId != tenant.DomainId {
return nil, httperrors.NewInvalidStatusError("not a public cloud account")
}
// if account's public_scope=domain and share_mode=provider_domain, only allow to share to specific domains
if account.PublicScope == string(rbacutils.ScopeDomain) {
sharedDomains := account.GetSharedDomains()
if !utils.IsInStringArray(tenant.DomainId, sharedDomains) && account.DomainId != tenant.DomainId {
return nil, errors.Wrap(httperrors.ErrForbidden, "cannot set to domain outside of the shared domains")
}
}
// otherwise, allow change project across domain
}
+15 -4
View File
@@ -280,7 +280,7 @@ func syncVpcRouteTables(ctx context.Context, userCred mcclient.TokenCredential,
log.Errorf(msg)
return
}
_, _, result := RouteTableManager.SyncRouteTables(ctx, userCred, localVpc, routeTables)
_, _, result := RouteTableManager.SyncRouteTables(ctx, userCred, localVpc, routeTables, provider)
syncResults.Add(RouteTableManager, result)
@@ -345,7 +345,7 @@ func syncNatDTable(ctx context.Context, userCred mcclient.TokenCredential, provi
log.Errorf(msg)
return
}
result := NatDEntryManager.SyncNatDTable(ctx, userCred, provider.GetOwnerId(), provider, localNatGateway, dtable)
result := NatDEntryManager.SyncNatDTable(ctx, userCred, provider, localNatGateway, dtable)
msg := result.Result()
log.Infof("SyncNatDTable for NatGateway %s result: %s", localNatGateway.Name, msg)
if result.IsError() {
@@ -361,7 +361,7 @@ func syncNatSTable(ctx context.Context, userCred mcclient.TokenCredential, provi
log.Errorf(msg)
return
}
result := NatSEntryManager.SyncNatSTable(ctx, userCred, provider.GetOwnerId(), provider, localNatGateway, stable)
result := NatSEntryManager.SyncNatSTable(ctx, userCred, provider, localNatGateway, stable)
msg := result.Result()
log.Infof("SyncNatSTable for NatGateway %s result: %s", localNatGateway.Name, msg)
if result.IsError() {
@@ -377,7 +377,7 @@ func syncVpcWires(ctx context.Context, userCred mcclient.TokenCredential, syncRe
log.Errorf(msg)
return
}
localWires, remoteWires, result := WireManager.SyncWires(ctx, userCred, localVpc, wires)
localWires, remoteWires, result := WireManager.SyncWires(ctx, userCred, localVpc, wires, provider)
if syncResults != nil {
syncResults.Add(WireManager, result)
@@ -1212,3 +1212,14 @@ func SyncCloudProject(userCred mcclient.TokenCredential, model db.IVirtualModel,
}
model.SyncCloudProjectId(userCred, newOwnerId)
}
func SyncCloudDomain(userCred mcclient.TokenCredential, model db.IDomainLevelModel, syncOwnerId mcclient.IIdentityProvider) {
var newOwnerId mcclient.IIdentityProvider
if syncOwnerId != nil && len(syncOwnerId.GetProjectDomainId()) > 0 {
newOwnerId = syncOwnerId
}
if newOwnerId == nil {
newOwnerId = userCred
}
model.SyncCloudDomainId(userCred, newOwnerId)
}
+19 -12
View File
@@ -376,29 +376,36 @@ func (self *SDisk) CustomizeCreate(ctx context.Context, userCred mcclient.TokenC
return self.SVirtualResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
}
func (self *SDisk) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
func (self *SDisk) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.DiskUpdateInput) (api.DiskUpdateInput, error) {
var err error
if input.DiskType != "" {
if !utils.IsInStringArray(input.DiskType, []string{api.DISK_TYPE_DATA, api.DISK_TYPE_VOLUME}) {
return input, httperrors.NewInputParameterError("not support update disk_type %s", input.DiskType)
}
}
storage := self.GetStorage()
if storage == nil {
return nil, httperrors.NewNotFoundError("failed to find storage for disk %s", self.Name)
return input, httperrors.NewNotFoundError("failed to find storage for disk %s", self.Name)
}
host := storage.GetMasterHost()
if host == nil {
return nil, httperrors.NewNotFoundError("failed to find host for storage %s with disk %s", storage.Name, self.Name)
return input, httperrors.NewNotFoundError("failed to find host for storage %s with disk %s", storage.Name, self.Name)
}
if diskType, _ := data.GetString("disk_type"); diskType != "" {
if !utils.IsInStringArray(diskType, []string{api.DISK_TYPE_DATA, api.DISK_TYPE_VOLUME}) {
return nil, httperrors.NewInputParameterError("not support update disk_type %s", diskType)
}
}
data, err := host.GetHostDriver().ValidateUpdateDisk(ctx, userCred, data)
input, err = host.GetHostDriver().ValidateUpdateDisk(ctx, userCred, input)
if err != nil {
return nil, err
return input, errors.Wrap(err, "GetHostDriver().ValidateUpdateDisk")
}
return self.SVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, data)
input.VirtualResourceBaseUpdateInput, err = self.SVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, input.VirtualResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SVirtualResourceBase.ValidateUpdateData")
}
return input, nil
}
func diskCreateInput2ComputeQuotaKeys(input api.DiskCreateInput, ownerId mcclient.IIdentityProvider) SComputeResourceKeys {
+11 -1
View File
@@ -419,7 +419,17 @@ func (rec *SDnsRecord) ValidateUpdateData(ctx context.Context, userCred mcclient
}
data.Set("records", jsonutils.NewString(strings.Join(records, DNS_RECORDS_SEPARATOR)))
}
return rec.SAdminSharableVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, data)
input := apis.AdminSharableVirtualResourceBaseUpdateInput{}
err = data.Unmarshal(&input)
if err != nil {
return nil, errors.Wrap(err, "data.Unmarshal AdminSharableVirtualResourceBaseUpdateInput")
}
input, err = rec.SAdminSharableVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, input)
if err != nil {
return nil, errors.Wrap(err, "SAdminSharableVirtualResourceBase.ValidateUpdateData")
}
data.Update(jsonutils.Marshal(input))
return data, nil
}
func (rec *SDnsRecord) AddInfo(ctx context.Context, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error {
+12 -1
View File
@@ -167,7 +167,18 @@ func (self *SDynamicschedtag) ValidateUpdateData(ctx context.Context, userCred m
return nil, err
}
return self.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, data)
input := apis.StandaloneResourceBaseUpdateInput{}
err = data.Unmarshal(&input)
if err != nil {
return nil, errors.Wrap(err, "Unmarshal")
}
input, err = self.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, input)
if err != nil {
return nil, errors.Wrap(err, "SStandaloneResourceBase.ValidateUpdateData")
}
data.Update(jsonutils.Marshal(input))
return data, nil
}
func (self *SDynamicschedtag) GetExtraDetails(
+33 -17
View File
@@ -30,14 +30,14 @@ import (
)
type SGlobalVpcManager struct {
db.SEnabledStatusStandaloneResourceBaseManager
db.SEnabledStatusInfrasResourceBaseManager
}
var GlobalVpcManager *SGlobalVpcManager
func init() {
GlobalVpcManager = &SGlobalVpcManager{
SEnabledStatusStandaloneResourceBaseManager: db.NewEnabledStatusStandaloneResourceBaseManager(
SEnabledStatusInfrasResourceBaseManager: db.NewEnabledStatusInfrasResourceBaseManager(
SGlobalVpc{},
"globalvpcs_tbl",
"globalvpc",
@@ -48,7 +48,7 @@ func init() {
}
type SGlobalVpc struct {
db.SEnabledStatusStandaloneResourceBase
db.SEnabledStatusInfrasResourceBase
}
func (manager *SGlobalVpcManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
@@ -63,7 +63,7 @@ func (self *SGlobalVpc) ValidateDeleteCondition(ctx context.Context) error {
if len(vpcs) > 0 {
return fmt.Errorf("not an empty globalvpc")
}
return self.SEnabledStatusStandaloneResourceBase.ValidateDeleteCondition(ctx)
return self.SEnabledStatusInfrasResourceBase.ValidateDeleteCondition(ctx)
}
func (self *SGlobalVpc) GetVpcs() ([]SVpc, error) {
@@ -89,27 +89,43 @@ func (manager *SGlobalVpcManager) FetchCustomizeColumns(
isList bool,
) []api.GlobalVpcDetails {
rows := make([]api.GlobalVpcDetails, len(objs))
stdRows := manager.SEnabledStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
stdRows := manager.SEnabledStatusInfrasResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
for i := range rows {
rows[i] = api.GlobalVpcDetails{
EnabledStatusStandaloneResourceDetails: stdRows[i],
EnabledStatusInfrasResourceBaseDetails: stdRows[i],
}
}
return rows
}
func (manager *SGlobalVpcManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.GlobalVpcCreateInput) (api.GlobalVpcCreateInput, error) {
func (manager *SGlobalVpcManager) ValidateCreateData(
ctx context.Context,
userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject,
input api.GlobalVpcCreateInput,
) (api.GlobalVpcCreateInput, error) {
input.Status = api.GLOBAL_VPC_STATUS_AVAILABLE
var err error
input.EnabledStatusStandaloneResourceCreateInput, err = manager.SEnabledStatusStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.EnabledStatusStandaloneResourceCreateInput)
input.EnabledStatusInfrasResourceBaseCreateInput, err = manager.SEnabledStatusInfrasResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.EnabledStatusInfrasResourceBaseCreateInput)
if err != nil {
return input, errors.Wrap(err, "manager.SEnabledStatusStandaloneResourceBaseManager.ValidateCreateData")
return input, errors.Wrap(err, "manager.SEnabledStatusInfrasResourceBaseManager.ValidateCreateData")
}
return input, nil
}
func (self *SGlobalVpc) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
return self.SEnabledStatusStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, data)
func (self *SGlobalVpc) ValidateUpdateData(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input api.GlobalvpcUpdateInput,
) (api.GlobalvpcUpdateInput, error) {
var err error
input.EnabledStatusInfrasResourceBaseUpdateInput, err = self.SEnabledStatusInfrasResourceBase.ValidateUpdateData(ctx, userCred, query, input.EnabledStatusInfrasResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SEnabledStatusInfrasResourceBase.ValidateUpdateData")
}
return input, nil
}
// 全局VPC列表
@@ -119,9 +135,9 @@ func (manager *SGlobalVpcManager) ListItemFilter(
userCred mcclient.TokenCredential,
query api.GlobalVpcListInput,
) (*sqlchemy.SQuery, error) {
q, err := manager.SEnabledStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput)
q, err := manager.SEnabledStatusInfrasResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusInfrasResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.ListItemFilter")
return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.ListItemFilter")
}
return q, nil
}
@@ -132,9 +148,9 @@ func (manager *SGlobalVpcManager) OrderByExtraFields(
userCred mcclient.TokenCredential,
query api.GlobalVpcListInput,
) (*sqlchemy.SQuery, error) {
q, err := manager.SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput)
q, err := manager.SEnabledStatusInfrasResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusInfrasResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields")
return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.OrderByExtraFields")
}
return q, nil
}
@@ -142,7 +158,7 @@ func (manager *SGlobalVpcManager) OrderByExtraFields(
func (manager *SGlobalVpcManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SEnabledStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field)
q, err = manager.SEnabledStatusInfrasResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
@@ -151,5 +167,5 @@ func (manager *SGlobalVpcManager) QueryDistinctExtraField(q *sqlchemy.SQuery, fi
}
func (self *SGlobalVpc) ValidateUpdateCondition(ctx context.Context) error {
return self.SEnabledStatusStandaloneResourceBase.ValidateUpdateCondition(ctx)
return self.SEnabledStatusInfrasResourceBase.ValidateUpdateCondition(ctx)
}
+24 -12
View File
@@ -94,12 +94,13 @@ func (gtm *SGuestTemplateManager) ValidateCreateData(
query jsonutils.JSONObject,
input computeapis.GuesttemplateCreateInput,
) (computeapis.GuesttemplateCreateInput, error) {
var err error
if input.Content == nil {
return input, httperrors.NewMissingParameterError("content")
}
input, err := gtm.validateData(ctx, userCred, ownerId, query, input)
input.GuesttemplateInput, err = gtm.validateData(ctx, userCred, ownerId, query, input.GuesttemplateInput)
if err != nil {
return input, errors.Wrap(err, "gtm.validateData")
}
@@ -128,8 +129,8 @@ func (gtm *SGuestTemplateManager) validateData(
userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject,
cinput computeapis.GuesttemplateCreateInput,
) (computeapis.GuesttemplateCreateInput, error) {
cinput computeapis.GuesttemplateInput,
) (computeapis.GuesttemplateInput, error) {
if cinput.Content == nil {
return cinput, nil
}
@@ -181,15 +182,22 @@ func (gtm *SGuestTemplateManager) validateData(
return cinput, nil
}
func (gt *SGuestTemplate) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential,
query jsonutils.JSONObject, cinput *computeapis.GuesttemplateCreateInput) (*jsonutils.JSONDict, error) {
input, err := GuestTemplateManager.validateData(ctx, userCred, gt.GetOwnerId(), query, *cinput)
func (gt *SGuestTemplate) ValidateUpdateData(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input computeapis.GuesttemplateUpdateInput,
) (computeapis.GuesttemplateUpdateInput, error) {
var err error
input.GuesttemplateInput, err = GuestTemplateManager.validateData(ctx, userCred, gt.GetOwnerId(), query, input.GuesttemplateInput)
if err != nil {
return nil, nil
return input, errors.Wrap(err, "GuestTemplateManager.validateData")
}
data := input.JSON(input)
return gt.SSharableVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, data)
input.SharableVirtualResourceBaseUpdateInput, err = gt.SSharableVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, input.SharableVirtualResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SSharableVirtualResourceBase.ValidateUpdateData")
}
return input, nil
}
func (manager *SGuestTemplateManager) FetchCustomizeColumns(
@@ -364,8 +372,12 @@ func (gt *SGuestTemplate) getMoreDetails(ctx context.Context, userCred mcclient.
return out, nil
}
func (gt *SGuestTemplate) PerformPublic(ctx context.Context, userCred mcclient.TokenCredential,
query jsonutils.JSONObject, data apis.PerformProjectPublicInput) (jsonutils.JSONObject, error) {
func (gt *SGuestTemplate) PerformPublic(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
data apis.PerformPublicInput,
) (jsonutils.JSONObject, error) {
// image, network, secgroup, instancegroup
input, err := cmdline.FetchServerCreateInputByJSON(gt.Content)
+18 -16
View File
@@ -85,24 +85,26 @@ func (self *SGuestdisk) AllowDeleteItem(ctx context.Context, userCred mcclient.T
return false
}
func (self *SGuestdisk) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
if data.Contains("index") {
if index, err := data.Int("index"); err != nil {
return nil, err
} else {
guestdisk := GuestdiskManager.Query().SubQuery()
count, err := guestdisk.Query().Filter(sqlchemy.Equals(guestdisk.Field("guest_id"), self.GuestId)).
Filter(sqlchemy.NotEquals(guestdisk.Field("disk_id"), self.DiskId)).
Filter(sqlchemy.Equals(guestdisk.Field("index"), index)).CountWithError()
if err != nil {
return nil, httperrors.NewInternalServerError("check disk index uniqueness fail %s", err)
}
if count > 0 {
return nil, httperrors.NewInputParameterError("DISK Index %d has been occupied", index)
}
func (self *SGuestdisk) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.GuestdiskUpdateInput) (api.GuestdiskUpdateInput, error) {
if input.Index != nil {
index := *input.Index
guestdisk := GuestdiskManager.Query().SubQuery()
count, err := guestdisk.Query().Filter(sqlchemy.Equals(guestdisk.Field("guest_id"), self.GuestId)).
Filter(sqlchemy.NotEquals(guestdisk.Field("disk_id"), self.DiskId)).
Filter(sqlchemy.Equals(guestdisk.Field("index"), index)).CountWithError()
if err != nil {
return input, httperrors.NewInternalServerError("check disk index uniqueness fail %s", err)
}
if count > 0 {
return input, httperrors.NewInputParameterError("DISK Index %d has been occupied", index)
}
}
return self.SGuestJointsBase.ValidateUpdateData(ctx, userCred, query, data)
var err error
input.GuestJointBaseUpdateInput, err = self.SGuestJointsBase.ValidateUpdateData(ctx, userCred, query, input.GuestJointBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SGuestJointsBase.ValidateUpdateData")
}
return input, nil
}
func (joint *SGuestdisk) Master() db.IStandaloneModel {
+14
View File
@@ -150,3 +150,17 @@ func (manager *SGuestJointsManager) OrderByExtraFields(
return q, nil
}
func (self *SGuestJointsBase) ValidateUpdateData(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input api.GuestJointBaseUpdateInput,
) (api.GuestJointBaseUpdateInput, error) {
var err error
input.VirtualJointResourceBaseUpdateInput, err = self.SVirtualJointResourceBase.ValidateUpdateData(ctx, userCred, query, input.VirtualJointResourceBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SVirtualJointResourceBase.ValidateUpdateData")
}
return input, nil
}
+16 -9
View File
@@ -511,24 +511,31 @@ func (self *SGuestnetwork) GetDetailedString() string {
self.MacAddr, network.VlanId, network.Name, self.Driver, self.getBandwidth())
}
func (self *SGuestnetwork) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
if data.Contains("index") {
index, err := data.Int("index")
if err != nil {
return nil, httperrors.NewInternalServerError("fail to fetch index %s", err)
}
func (self *SGuestnetwork) ValidateUpdateData(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input api.GuestnetworkUpdateInput,
) (api.GuestnetworkUpdateInput, error) {
if input.Index != nil {
index := *input.Index
q := GuestnetworkManager.Query().SubQuery()
count, err := q.Query().Filter(sqlchemy.Equals(q.Field("guest_id"), self.GuestId)).
Filter(sqlchemy.NotEquals(q.Field("network_id"), self.NetworkId)).
Filter(sqlchemy.Equals(q.Field("index"), index)).CountWithError()
if err != nil {
return nil, httperrors.NewInternalServerError("checkout nic index uniqueness fail %s", err)
return input, httperrors.NewInternalServerError("checkout nic index uniqueness fail %s", err)
}
if count > 0 {
return nil, httperrors.NewDuplicateResourceError("NIC Index %d has been occupied", index)
return input, httperrors.NewDuplicateResourceError("NIC Index %d has been occupied", index)
}
}
return self.SJointResourceBase.ValidateUpdateData(ctx, userCred, query, data)
var err error
input.GuestJointBaseUpdateInput, err = self.SGuestJointsBase.ValidateUpdateData(ctx, userCred, query, input.GuestJointBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SGuestJointsBase.ValidateUpdateData")
}
return input, nil
}
func (manager *SGuestnetworkManager) DeleteGuestNics(ctx context.Context, userCred mcclient.TokenCredential, gns []SGuestnetwork, reserve bool) error {
+13 -1
View File
@@ -23,6 +23,8 @@ import (
"strings"
"time"
"yunion.io/x/onecloud/pkg/apis"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
@@ -863,7 +865,17 @@ func (self *SGuest) ValidateUpdateData(ctx context.Context, userCred mcclient.To
return nil, httperrors.NewInputParameterError("name is too short")
}
}
return self.SVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, data)
input := apis.VirtualResourceBaseUpdateInput{}
err = data.Unmarshal(&input)
if err != nil {
return nil, errors.Wrap(err, "data.Unmarshal")
}
input, err = self.SVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, input)
if err != nil {
return nil, errors.Wrap(err, "SVirtualResourceBase.ValidateUpdateData")
}
data.Update(jsonutils.Marshal(input))
return data, nil
}
func serverCreateInput2ComputeQuotaKeys(input api.ServerCreateInput, ownerId mcclient.IIdentityProvider) SComputeResourceKeys {
+1 -1
View File
@@ -32,7 +32,7 @@ type IHostDriver interface {
CheckAndSetCacheImage(ctx context.Context, host *SHost, storagecache *SStoragecache, task taskman.ITask) error
RequestUncacheImage(ctx context.Context, host *SHost, storageCache *SStoragecache, task taskman.ITask) error
ValidateUpdateDisk(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error)
ValidateUpdateDisk(ctx context.Context, userCred mcclient.TokenCredential, input api.DiskUpdateInput) (api.DiskUpdateInput, error)
ValidateResetDisk(ctx context.Context, userCred mcclient.TokenCredential, disk *SDisk, snapshot *SSnapshot, guests []SGuest, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error)
ValidateDiskSize(storage *SStorage, sizeGb int) error
RequestPrepareSaveDiskOnHost(ctx context.Context, host *SHost, disk *SDisk, imageId string, task taskman.ITask) error
+260 -185
View File
@@ -25,6 +25,8 @@ import (
"strings"
"time"
"yunion.io/x/onecloud/pkg/util/rbacutils"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
@@ -58,7 +60,7 @@ import (
)
type SHostManager struct {
db.SEnabledStatusStandaloneResourceBaseManager
db.SEnabledStatusInfrasResourceBaseManager
db.SExternalizedResourceBaseManager
SZoneResourceBaseManager
SManagedResourceBaseManager
@@ -68,7 +70,7 @@ var HostManager *SHostManager
func init() {
HostManager = &SHostManager{
SEnabledStatusStandaloneResourceBaseManager: db.NewEnabledStatusStandaloneResourceBaseManager(
SEnabledStatusInfrasResourceBaseManager: db.NewEnabledStatusInfrasResourceBaseManager(
SHost{},
"hosts_tbl",
"host",
@@ -80,7 +82,7 @@ func init() {
}
type SHost struct {
db.SEnabledStatusStandaloneResourceBase
db.SEnabledStatusInfrasResourceBase
db.SExternalizedResourceBase
SZoneResourceBase
SManagedResourceBase
@@ -227,9 +229,9 @@ func (manager *SHostManager) ListItemFilter(
}
}
q, err = manager.SEnabledStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput)
q, err = manager.SEnabledStatusInfrasResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusInfrasResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.ListItemFilter")
return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.ListItemFilter")
}
anyMac := query.AnyMac
@@ -436,9 +438,9 @@ func (manager *SHostManager) OrderByExtraFields(
query api.HostListInput,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput)
q, err = manager.SEnabledStatusInfrasResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusInfrasResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields")
return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.OrderByExtraFields")
}
q, err = manager.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput)
if err != nil {
@@ -453,7 +455,7 @@ func (manager *SHostManager) OrderByExtraFields(
func (manager *SHostManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SEnabledStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field)
q, err = manager.SEnabledStatusInfrasResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
@@ -610,7 +612,7 @@ func (self *SHost) validateDeleteCondition(ctx context.Context, purge bool) erro
}
}
return self.SEnabledStatusStandaloneResourceBase.ValidateDeleteCondition(ctx)
return self.SEnabledStatusInfrasResourceBase.ValidateDeleteCondition(ctx)
}
func (self *SHost) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
@@ -677,7 +679,7 @@ func (self *SHost) RealDelete(ctx context.Context, userCred mcclient.TokenCreden
store.Delete(ctx, userCred)
}
}
return self.SEnabledStatusStandaloneResourceBase.Delete(ctx, userCred)
return self.SEnabledStatusInfrasResourceBase.Delete(ctx, userCred)
}
func (self *SHost) GetHoststoragesQuery() *sqlchemy.SQuery {
@@ -1183,6 +1185,18 @@ func (self *SHost) GetAttachedLocalStorageCapacity() SStorageCapacity {
return ret
}
func (self *SHost) GetAttachedLocalStorages() []SStorage {
ret := make([]SStorage, 0)
storages := self.GetAttachedStorages("")
for _, s := range storages {
if !utils.IsInStringArray(s.StorageType, api.HOST_STORAGE_LOCAL_TYPES) {
continue
}
ret = append(ret, s)
}
return ret
}
func _getLeastUsedStorage(storages []SStorage, backends []string) *SStorage {
var best *SStorage
var bestCap int64
@@ -1505,7 +1519,7 @@ func (manager *SHostManager) SyncHosts(ctx context.Context, userCred mcclient.To
}
}
for i := 0; i < len(commondb); i += 1 {
err = commondb[i].syncWithCloudHost(ctx, userCred, commonext[i])
err = commondb[i].syncWithCloudHost(ctx, userCred, commonext[i], provider.GetOwnerId())
if err != nil {
syncResult.UpdateError(err)
} else {
@@ -1551,7 +1565,7 @@ func (self *SHost) syncRemoveCloudHost(ctx context.Context, userCred mcclient.To
return err
}
func (self *SHost) syncWithCloudHost(ctx context.Context, userCred mcclient.TokenCredential, extHost cloudprovider.ICloudHost) error {
func (self *SHost) syncWithCloudHost(ctx context.Context, userCred mcclient.TokenCredential, extHost cloudprovider.ICloudHost, syncOwnerId mcclient.IIdentityProvider) error {
diff, err := db.UpdateWithLock(ctx, self, func() error {
// self.Name = extHost.GetName()
@@ -1597,6 +1611,8 @@ func (self *SHost) syncWithCloudHost(ctx context.Context, userCred mcclient.Toke
db.OpsLog.LogSyncUpdate(self, diff, userCred)
SyncCloudDomain(userCred, self, syncOwnerId)
if err := HostManager.ClearSchedDescCache(self.Id); err != nil {
log.Errorf("ClearSchedDescCache for host %s error %v", self.Name, err)
}
@@ -1693,6 +1709,9 @@ func (manager *SHostManager) newFromCloudHost(ctx context.Context, userCred mccl
host.IsMaintenance = extHost.GetIsMaintenance()
host.Version = extHost.GetVersion()
host.IsPublic = false
host.PublicScope = string(rbacutils.ScopeNone)
err = manager.TableSpec().Insert(&host)
if err != nil {
log.Errorf("newFromCloudHost fail %s", err)
@@ -1701,6 +1720,8 @@ func (manager *SHostManager) newFromCloudHost(ctx context.Context, userCred mccl
db.OpsLog.LogEvent(&host, db.ACT_CREATE, host.GetShortDesc(ctx), userCred)
SyncCloudDomain(userCred, &host, provider.GetOwnerId())
if err := manager.ClearSchedDescCache(host.Id); err != nil {
log.Errorf("ClearSchedDescCache for host %s error %v", host.Name, err)
}
@@ -1802,7 +1823,7 @@ func (self *SHost) syncWithCloudHostStorage(ctx context.Context, userCred mcclie
return err
}
s := hs.GetStorage()
err = s.syncWithCloudStorage(ctx, userCred, extStorage)
err = s.syncWithCloudStorage(ctx, userCred, extStorage, nil)
return err
}
@@ -2550,12 +2571,12 @@ func (manager *SHostManager) FetchCustomizeColumns(
isList bool,
) []api.HostDetails {
rows := make([]api.HostDetails, len(objs))
stdRows := manager.SEnabledStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
stdRows := manager.SEnabledStatusInfrasResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
managerRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
zoneRows := manager.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
for i := range rows {
rows[i] = api.HostDetails{
EnabledStatusStandaloneResourceDetails: stdRows[i],
EnabledStatusInfrasResourceBaseDetails: stdRows[i],
ManagedResourceInfo: managerRows[i],
ZoneResourceInfo: zoneRows[i],
}
@@ -2642,37 +2663,50 @@ func (self *SHost) GetStoragecache() *SStoragecache {
return nil
}
func (self *SHost) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
self.SEnabledStatusStandaloneResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
kwargs := data.(*jsonutils.JSONDict)
ipmiInfo, err := fetchIpmiInfo(kwargs, self.Id)
func (self *SHost) PostCreate(
ctx context.Context,
userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject,
data jsonutils.JSONObject,
) {
self.SEnabledStatusInfrasResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
input := api.HostCreateInput{}
err := data.Unmarshal(&input)
if err != nil {
log.Errorln(err.Error())
} else if ipmiInfo.Length() > 0 {
log.Errorf("data.Unmarshal fail %s", err)
return
}
kwargs := data.(*jsonutils.JSONDict)
ipmiInfo, err := fetchIpmiInfo(input.HostIpmiAttributes, self.Id)
if err != nil {
log.Errorf("fetchIpmiInfo fail %s", err)
return
}
ipmiInfoJson := jsonutils.Marshal(ipmiInfo).(*jsonutils.JSONDict)
if ipmiInfoJson.Length() > 0 {
_, err := self.SaveUpdates(func() error {
self.IpmiInfo = ipmiInfo
self.IpmiInfo = ipmiInfoJson
return nil
})
if err != nil {
log.Errorln(err.Error())
} else {
ipmiIp, _ := ipmiInfo.GetString("ip_addr")
if len(ipmiIp) > 0 {
self.setIpmiIp(userCred, ipmiIp)
}
} else if len(ipmiInfo.IpAddr) > 0 {
self.setIpmiIp(userCred, ipmiInfo.IpAddr)
}
}
accessIp, _ := data.GetString("access_ip")
if len(accessIp) > 0 {
self.setAccessIp(userCred, accessIp)
if len(input.AccessIp) > 0 {
self.setAccessIp(userCred, input.AccessIp)
}
accessMac, _ := data.GetString("access_mac")
if len(accessMac) > 0 {
self.setAccessMac(userCred, accessMac)
if len(input.AccessMac) > 0 {
self.setAccessMac(userCred, input.AccessMac)
}
noProbe := false
if input.NoProbe != nil {
noProbe = *input.NoProbe
}
noProbe := jsonutils.QueryBoolean(data, "no_probe", false)
if len(self.ZoneId) > 0 && self.HostType == api.HOST_TYPE_BAREMETAL && !noProbe {
ipmiInfo, _ := self.GetIpmiInfo()
// ipmiInfo, _ := self.GetIpmiInfo()
if len(ipmiInfo.IpAddr) > 0 {
self.StartBaremetalCreateTask(ctx, userCred, kwargs, "")
}
@@ -2689,49 +2723,51 @@ func (self *SHost) StartBaremetalCreateTask(ctx context.Context, userCred mcclie
}
}
func (manager *SHostManager) ValidateSizeParams(data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
memStr, _ := data.GetString("mem_size")
func (manager *SHostManager) ValidateSizeParams(input api.HostSizeAttributes) (api.HostSizeAttributes, error) {
memStr := input.MemSize
if len(memStr) > 0 {
if !regutils.MatchSize(memStr) {
return nil, fmt.Errorf("Memory size must be number[+unit], like 256M, 1G or 256")
return input, errors.Wrap(httperrors.ErrInputParameter, "Memory size must be number[+unit], like 256M, 1G or 256")
}
memSize, err := fileutils.GetSizeMb(memStr, 'M', 1024)
if err != nil {
return nil, err
return input, errors.Wrap(err, "fileutils.GetSizeMb")
}
data.Set("mem_size", jsonutils.NewInt(int64(memSize)))
input.MemSize = strconv.FormatInt(int64(memSize), 10)
// data.Set("mem_size", jsonutils.NewInt(int64(memSize)))
}
memReservedStr, _ := data.GetString("mem_reserved")
memReservedStr := input.MemReserved
if len(memReservedStr) > 0 {
if !regutils.MatchSize(memReservedStr) {
return nil, fmt.Errorf("Memory size must be number[+unit], like 256M, 1G or 256")
return input, errors.Wrap(httperrors.ErrInputParameter, "Memory size must be number[+unit], like 256M, 1G or 256")
}
memSize, err := fileutils.GetSizeMb(memReservedStr, 'M', 1024)
if err != nil {
return nil, err
return input, errors.Wrap(err, "fileutils.GetSizeMb")
}
data.Set("mem_reserved", jsonutils.NewInt(int64(memSize)))
input.MemReserved = strconv.FormatInt(int64(memSize), 10)
// data.Set("mem_reserved", jsonutils.NewInt(int64(memSize)))
}
cpuCacheStr, _ := data.GetString("cpu_cache")
cpuCacheStr := input.CpuCache
if len(cpuCacheStr) > 0 {
if !regutils.MatchSize(cpuCacheStr) {
return nil, fmt.Errorf("Illegal cpu cache size %s", cpuCacheStr)
return input, errors.Wrapf(httperrors.ErrInputParameter, "Illegal cpu cache size %s", cpuCacheStr)
}
cpuCache, err := fileutils.GetSizeKb(cpuCacheStr, 'K', 1024)
if err != nil {
return nil, err
return input, errors.Wrap(err, "fileutils.GetSizeKb")
}
data.Set("cpu_cache", jsonutils.NewInt(int64(cpuCache)))
input.CpuCache = strconv.FormatInt(int64(cpuCache), 10)
// data.Set("cpu_cache", jsonutils.NewInt(int64(cpuCache)))
}
return data, nil
return input, nil
}
func (manager *SHostManager) inputUniquenessCheck(data *jsonutils.JSONDict, zoneId string, hostId string) (*jsonutils.JSONDict, error) {
for _, key := range []string{
"manager_uri",
"access_ip",
func (manager *SHostManager) inputUniquenessCheck(input api.HostAccessAttributes, zoneId string, hostId string) (api.HostAccessAttributes, error) {
for key, val := range map[string]string{
"manager_uri": input.ManagerUri,
"access_ip": input.AccessIp,
} {
val, _ := data.GetString(key)
if len(val) > 0 {
q := manager.Query().Equals(key, val)
if len(zoneId) > 0 {
@@ -2744,19 +2780,19 @@ func (manager *SHostManager) inputUniquenessCheck(data *jsonutils.JSONDict, zone
}
cnt, err := q.CountWithError()
if err != nil {
return nil, httperrors.NewInternalServerError("check %s duplication fail %s", key, err)
return input, httperrors.NewInternalServerError("check %s duplication fail %s", key, err)
}
if cnt > 0 {
return nil, httperrors.NewConflictError("duplicate %s %s", key, val)
return input, httperrors.NewConflictError("duplicate %s %s", key, val)
}
}
}
accessMac, _ := data.GetString("access_mac")
accessMac := input.AccessMac
if len(accessMac) > 0 {
accessMac2 := netutils.FormatMacAddr(accessMac)
if len(accessMac2) == 0 {
return nil, httperrors.NewInputParameterError("invalid macAddr %s", accessMac)
return input, httperrors.NewInputParameterError("invalid macAddr %s", accessMac)
}
if accessMac2 != api.ACCESS_MAC_ANY {
q := manager.Query().Equals("access_mac", accessMac2)
@@ -2765,71 +2801,76 @@ func (manager *SHostManager) inputUniquenessCheck(data *jsonutils.JSONDict, zone
}
cnt, err := q.CountWithError()
if err != nil {
return nil, httperrors.NewInternalServerError("check access_mac duplication fail %s", err)
return input, httperrors.NewInternalServerError("check access_mac duplication fail %s", err)
}
if cnt > 0 {
return nil, httperrors.NewConflictError("duplicate access_mac %s", accessMac)
return input, httperrors.NewConflictError("duplicate access_mac %s", accessMac)
}
data.Set("access_mac", jsonutils.NewString(accessMac2))
input.AccessMac = accessMac2
}
}
return data, nil
return input, nil
}
func (manager *SHostManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
zoneId, zoneKey := jsonutils.GetAnyString2(data, []string{"zone_id", "zone"})
if len(zoneId) > 0 {
data.Remove(zoneKey)
zoneObj, err := ZoneManager.FetchByIdOrName(userCred, zoneId)
func (manager *SHostManager) ValidateCreateData(
ctx context.Context,
userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject,
input api.HostCreateInput,
) (api.HostCreateInput, error) {
var err error
if len(input.Zone) > 0 {
zoneObj, err := ValidateZoneResourceInput(userCred, input.ZoneResourceInput)
if err != nil {
if err == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError2(ZoneManager.Keyword(), zoneId)
} else {
return nil, httperrors.NewGeneralError(err)
}
return input, errors.Wrap(err, "ValidateZoneResourceInput")
}
zoneId = zoneObj.GetId()
data.Set("zone_id", jsonutils.NewString(zoneObj.GetId()))
input.Zone = zoneObj.GetId()
}
noProbe := jsonutils.QueryBoolean(data, "no_probe", false)
data, err := manager.inputUniquenessCheck(data, zoneId, "")
if err != nil {
return nil, err
noProbe := false
if input.NoProbe != nil {
noProbe = *input.NoProbe
}
data, err = manager.ValidateSizeParams(data)
input.HostAccessAttributes, err = manager.inputUniquenessCheck(input.HostAccessAttributes, input.Zone, "")
if err != nil {
return nil, httperrors.NewInputParameterError(err.Error())
return input, errors.Wrap(err, "manager.inputUniquenessCheck")
}
memReserved, err := data.Int("mem_reserved")
input.HostSizeAttributes, err = manager.ValidateSizeParams(input.HostSizeAttributes)
if err != nil {
hostType, _ := data.GetString("host_type")
if hostType != api.HOST_TYPE_BAREMETAL {
memSize, _ := data.Int("mem_size")
memReserved = memSize / 8
return input, errors.Wrap(err, "manager.ValidateSizeParams")
}
if len(input.MemReserved) == 0 {
if input.HostType != api.HOST_TYPE_BAREMETAL {
memSize, _ := strconv.ParseInt(input.MemSize, 10, 64)
memReserved := memSize / 8
if memReserved > 4096 {
memReserved = 4096
}
data.Set("mem_reserved", jsonutils.NewInt(memReserved))
input.MemReserved = strconv.FormatInt(memReserved, 10)
// data.Set("mem_reserved", jsonutils.NewInt(memReserved))
} else {
data.Set("mem_reserved", jsonutils.NewInt(0))
input.MemReserved = "0"
// data.Set("mem_reserved", jsonutils.NewInt(0))
}
}
ipmiInfo, err := fetchIpmiInfo(data, "")
ipmiInfo, err := fetchIpmiInfo(input.HostIpmiAttributes, "")
if err != nil {
log.Errorln(err.Error())
return nil, httperrors.NewInputParameterError("%s", err)
return input, errors.Wrap(err, "fetchIpmiInfo")
}
ipmiIpAddr, _ := ipmiInfo.GetString("ip_addr")
ipmiIpAddr := ipmiInfo.IpAddr
if len(ipmiIpAddr) == 0 {
noProbe = true
}
if len(ipmiIpAddr) > 0 && !noProbe {
net, _ := NetworkManager.GetOnPremiseNetworkOfIP(ipmiIpAddr, "", tristate.None)
if net == nil {
return nil, httperrors.NewInputParameterError("%s is out of network IP ranges", ipmiIpAddr)
return input, httperrors.NewInputParameterError("%s is out of network IP ranges", ipmiIpAddr)
}
// check ip has been reserved
rip := ReservedipManager.GetReservedIP(net, ipmiIpAddr)
@@ -2837,49 +2878,50 @@ func (manager *SHostManager) ValidateCreateData(ctx context.Context, userCred mc
// if not, reserve this IP temporarily
err := net.reserveIpWithDuration(ctx, userCred, ipmiIpAddr, "reserve for baremetal ipmi IP", 30*time.Minute)
if err != nil {
return nil, errors.Wrap(err, "net.reserveIpWithDuration")
return input, errors.Wrap(err, "net.reserveIpWithDuration")
}
}
zoneObj := net.GetZone()
if zoneObj == nil {
return nil, httperrors.NewInputParameterError("IPMI network has no zone???")
return input, httperrors.NewInputParameterError("IPMI network has no zone???")
}
originZoneId, _ := data.GetString("zone_id")
originZoneId := input.Zone
if len(originZoneId) > 0 && originZoneId != zoneObj.GetId() {
return nil, httperrors.NewInputParameterError("IPMI address located in different zone than specified")
return input, httperrors.NewInputParameterError("IPMI address located in different zone than specified")
}
data.Set("zone_id", jsonutils.NewString(zoneObj.GetId()))
input.Zone = zoneObj.GetId()
// data.Set("zone_id", jsonutils.NewString(zoneObj.GetId()))
}
if !noProbe {
var accessNet *SNetwork
accessIpAddr, _ := data.GetString("access_ip")
accessIpAddr := input.AccessIp // tString("access_ip")
if len(accessIpAddr) > 0 {
net, _ := NetworkManager.GetOnPremiseNetworkOfIP(accessIpAddr, "", tristate.None)
if net == nil {
return nil, httperrors.NewInputParameterError("%s is out of network IP ranges", accessIpAddr)
return input, httperrors.NewInputParameterError("%s is out of network IP ranges", accessIpAddr)
}
accessNet = net
} else {
accessNetStr, _ := data.GetString("access_net")
accessNetStr := input.AccessNet // data.GetString("access_net")
if len(accessNetStr) > 0 {
netObj, err := NetworkManager.FetchByIdOrName(userCred, accessNetStr)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError2("network", accessNetStr)
return input, httperrors.NewResourceNotFoundError2("network", accessNetStr)
} else {
return nil, httperrors.NewGeneralError(err)
return input, httperrors.NewGeneralError(err)
}
}
accessNet = netObj.(*SNetwork)
} else {
accessWireStr, _ := data.GetString("access_wire")
accessWireStr := input.AccessWire // data.GetString("access_wire")
if len(accessWireStr) > 0 {
wireObj, err := WireManager.FetchByIdOrName(userCred, accessWireStr)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError2("wire", accessWireStr)
return input, httperrors.NewResourceNotFoundError2("wire", accessWireStr)
} else {
return nil, httperrors.NewGeneralError(err)
return input, httperrors.NewGeneralError(err)
}
}
wire := wireObj.(*SWire)
@@ -2887,7 +2929,7 @@ func (manager *SHostManager) ValidateCreateData(ctx context.Context, userCred mc
defer lockman.ReleaseObject(ctx, wire)
net, err := wire.GetCandidatePrivateNetwork(userCred, false, []string{api.NETWORK_TYPE_PXE, api.NETWORK_TYPE_BAREMETAL, api.NETWORK_TYPE_GUEST})
if err != nil {
return nil, httperrors.NewGeneralError(err)
return input, httperrors.NewGeneralError(err)
}
accessNet = net
}
@@ -2899,20 +2941,20 @@ func (manager *SHostManager) ValidateCreateData(ctx context.Context, userCred mc
accessIp, err := accessNet.GetFreeIP(ctx, userCred, nil, nil, accessIpAddr, api.IPAllocationNone, true)
if err != nil {
return nil, httperrors.NewGeneralError(err)
return input, httperrors.NewGeneralError(err)
}
if len(accessIpAddr) > 0 && accessIpAddr != accessIp {
return nil, httperrors.NewConflictError("Access ip %s has been used", accessIpAddr)
return input, httperrors.NewConflictError("Access ip %s has been used", accessIpAddr)
}
zoneObj := accessNet.GetZone()
if zoneObj == nil {
return nil, httperrors.NewInputParameterError("Access network has no zone???")
return input, httperrors.NewInputParameterError("Access network has no zone???")
}
originZoneId, _ := data.GetString("zone_id")
originZoneId := input.Zone // data.GetString("zone_id")
if len(originZoneId) > 0 && originZoneId != zoneObj.GetId() {
return nil, httperrors.NewInputParameterError("Access address located in different zone than specified")
return input, httperrors.NewInputParameterError("Access address located in different zone than specified")
}
// check ip has been reserved
@@ -2921,90 +2963,93 @@ func (manager *SHostManager) ValidateCreateData(ctx context.Context, userCred mc
// if not reserved, reserve this IP temporarily
err = accessNet.reserveIpWithDuration(ctx, userCred, accessIp, "reserve for baremetal access IP", 30*time.Minute)
if err != nil {
return nil, err
return input, err
}
}
data.Set("access_ip", jsonutils.NewString(accessIp))
data.Set("zone_id", jsonutils.NewString(zoneObj.GetId()))
input.AccessIp = accessIp
input.Zone = zoneObj.GetId()
// data.Set("access_ip", jsonutils.NewString(accessIp))
// data.Set("zone_id", jsonutils.NewString(zoneObj.GetId()))
}
}
// only baremetal can be created
hostType, _ := data.GetString("host_type")
hostType := input.HostType // .GetString("host_type")
if len(hostType) == 0 {
hostType = api.HOST_TYPE_BAREMETAL
data.Set("host_type", jsonutils.NewString(hostType))
input.HostType = hostType
// data.Set("host_type", jsonutils.NewString(hostType))
}
if hostType == api.HOST_TYPE_BAREMETAL {
data.Set("is_baremetal", jsonutils.JSONTrue)
isBaremetal := true
input.IsBaremetal = &isBaremetal
// data.Set("is_baremetal", jsonutils.JSONTrue)
}
if noProbe {
accessMac, _ := data.GetString("access_mac")
uuid, _ := data.GetString("uuid")
if len(accessMac) == 0 && len(uuid) == 0 {
return nil, httperrors.NewInputParameterError("missing access_mac and uuid in no_probe mode")
// accessMac := input.AccessMac // data.GetString("access_mac")
// uuid := input.Uuid // data.GetString("uuid")
if len(input.AccessMac) == 0 && len(input.Uuid) == 0 {
return input, httperrors.NewInputParameterError("missing access_mac and uuid in no_probe mode")
}
}
input := apis.EnabledStatusStandaloneResourceCreateInput{}
err = data.Unmarshal(&input)
input.EnabledStatusInfrasResourceBaseCreateInput, err = manager.SEnabledStatusInfrasResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.EnabledStatusInfrasResourceBaseCreateInput)
if err != nil {
return nil, httperrors.NewInternalServerError("unmarshal EnabledStatusStandaloneCreateInput fail %s", err)
return input, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.ValidateCreateData")
}
input, err = manager.SEnabledStatusStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input)
if err != nil {
return nil, err
}
data.Update(jsonutils.Marshal(input))
return data, nil
return input, nil
}
func (self *SHost) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
data, err := HostManager.inputUniquenessCheck(data, self.ZoneId, self.Id)
func (self *SHost) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.HostUpdateInput) (api.HostUpdateInput, error) {
var err error
input.HostAccessAttributes, err = HostManager.inputUniquenessCheck(input.HostAccessAttributes, self.ZoneId, self.Id)
if err != nil {
return nil, err
return input, errors.Wrap(err, "inputUniquenessCheck")
}
data, err = HostManager.ValidateSizeParams(data)
input.HostSizeAttributes, err = HostManager.ValidateSizeParams(input.HostSizeAttributes)
if err != nil {
return nil, httperrors.NewInputParameterError(err.Error())
return input, errors.Wrap(err, "ValidateSizeParams")
}
ipmiInfo, err := fetchIpmiInfo(data, self.Id)
ipmiInfo, err := fetchIpmiInfo(input.HostIpmiAttributes, self.Id)
if err != nil {
return nil, err
return input, errors.Wrap(err, "fetchIpmiInfo")
}
if ipmiInfo.Length() > 0 {
ipmiIpAddr, _ := ipmiInfo.GetString("ip_addr")
ipmiInfoJson := jsonutils.Marshal(ipmiInfo).(*jsonutils.JSONDict)
if ipmiInfoJson.Length() > 0 {
ipmiIpAddr := ipmiInfo.IpAddr
if len(ipmiIpAddr) > 0 {
net, _ := NetworkManager.GetOnPremiseNetworkOfIP(ipmiIpAddr, "", tristate.None)
if net == nil {
return nil, httperrors.NewInputParameterError("%s is out of network IP ranges", ipmiIpAddr)
return input, httperrors.NewInputParameterError("%s is out of network IP ranges", ipmiIpAddr)
}
zoneObj := net.GetZone()
if zoneObj == nil {
return nil, httperrors.NewInputParameterError("IPMI network has not zone???")
return input, httperrors.NewInputParameterError("IPMI network has not zone???")
}
if zoneObj.GetId() != self.ZoneId {
return nil, httperrors.NewInputParameterError("New IPMI address located in another zone!")
return input, httperrors.NewInputParameterError("New IPMI address located in another zone!")
}
}
val := jsonutils.NewDict()
val.Update(self.IpmiInfo)
val.Update(ipmiInfo)
data.Set("ipmi_info", val)
val.Update(ipmiInfoJson)
input.IpmiInfo = val
}
data, err = self.SEnabledStatusStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, data)
input.EnabledStatusInfrasResourceBaseUpdateInput, err = self.SEnabledStatusInfrasResourceBase.ValidateUpdateData(ctx, userCred, query, input.EnabledStatusInfrasResourceBaseUpdateInput)
if err != nil {
return nil, err
return input, errors.Wrap(err, "SEnabledStatusInfrasResourceBase.ValidateUpdateData")
}
if data.Contains("name") {
if len(input.Name) > 0 {
self.UpdateDnsRecords(false)
}
return data, nil
return input, nil
}
func (self *SHost) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) {
self.SEnabledStatusStandaloneResourceBase.PostUpdate(ctx, userCred, query, data)
self.SEnabledStatusInfrasResourceBase.PostUpdate(ctx, userCred, query, data)
if data.Contains("cpu_cmtbound") || data.Contains("mem_cmtbound") {
self.ClearSchedDescCache()
@@ -3043,33 +3088,44 @@ func (self *SHost) GetNetifName(netif *SNetInterface) string {
return ""
}
func fetchIpmiInfo(data *jsonutils.JSONDict, hostId string) (*jsonutils.JSONDict, error) {
IPMI_KEY_PERFIX := "ipmi_"
ipmiInfo := jsonutils.NewDict()
kv, _ := data.GetMap()
var err error
for key := range kv {
if strings.HasPrefix(key, IPMI_KEY_PERFIX) {
value, _ := data.GetString(key)
subkey := key[len(IPMI_KEY_PERFIX):]
if subkey == "password" && len(hostId) > 0 {
value, err = utils.EncryptAESBase64(hostId, value)
if err != nil {
log.Errorf("encrypt password failed %s", err)
return nil, err
}
} else if subkey == "ip_addr" {
if !regutils.MatchIP4Addr(value) {
msg := fmt.Sprintf("%s: %s not valid ipv4 address", key, value)
log.Errorf(msg)
err = fmt.Errorf(msg)
return nil, err
}
}
ipmiInfo.Set(subkey, jsonutils.NewString(value))
func fetchIpmiInfo(data api.HostIpmiAttributes, hostId string) (types.SIPMIInfo, error) {
info := types.SIPMIInfo{}
info.Username = data.IpmiUsername
if len(hostId) > 0 {
value, err := utils.EncryptAESBase64(hostId, data.IpmiPassword)
if err != nil {
log.Errorf("encrypt password failed %s", err)
return info, errors.Wrap(err, "utils.EncryptAESBase64")
}
info.Password = value
} else {
info.Password = data.IpmiPassword
}
return ipmiInfo, nil
if len(data.IpmiIpAddr) > 0 && !regutils.MatchIP4Addr(data.IpmiIpAddr) {
msg := fmt.Sprintf("ipmi_ip_addr: %s not valid ipv4 address", data.IpmiIpAddr)
log.Errorf(msg)
return info, errors.Wrap(httperrors.ErrInvalidFormat, msg)
}
info.IpAddr = data.IpmiIpAddr
if data.IpmiPresent != nil {
info.Present = *data.IpmiPresent
}
if data.IpmiLanChannel != nil {
info.LanChannel = *data.IpmiLanChannel
}
if data.IpmiVerified != nil {
info.Verified = *data.IpmiVerified
}
if data.IpmiRedfishApi != nil {
info.RedfishApi = *data.IpmiRedfishApi
}
if data.IpmiCdromBoot != nil {
info.CdromBoot = *data.IpmiCdromBoot
}
if data.IpmiPxeBoot != nil {
info.PxeBoot = *data.IpmiPxeBoot
}
return info, nil
}
func (self *SHost) AllowPerformStart(ctx context.Context,
@@ -3986,7 +4042,7 @@ func (self *SHost) AllowPerformEnable(
query jsonutils.JSONObject,
input apis.PerformEnableInput,
) bool {
return self.SEnabledStatusStandaloneResourceBase.AllowPerformEnable(ctx, userCred, query, input)
return self.SEnabledStatusInfrasResourceBase.AllowPerformEnable(ctx, userCred, query, input)
}
func (self *SHost) PerformEnable(
@@ -3996,9 +4052,9 @@ func (self *SHost) PerformEnable(
input apis.PerformEnableInput,
) (jsonutils.JSONObject, error) {
if !self.GetEnabled() {
_, err := self.SEnabledStatusStandaloneResourceBase.PerformEnable(ctx, userCred, query, input)
_, err := self.SEnabledStatusInfrasResourceBase.PerformEnable(ctx, userCred, query, input)
if err != nil {
return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBase.PerformEnable")
return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBase.PerformEnable")
}
self.SyncAttachedStorageStatus()
}
@@ -4011,14 +4067,14 @@ func (self *SHost) AllowPerformDisable(
query jsonutils.JSONObject,
input apis.PerformDisableInput,
) bool {
return self.SEnabledStatusStandaloneResourceBase.AllowPerformDisable(ctx, userCred, query, input)
return self.SEnabledStatusInfrasResourceBase.AllowPerformDisable(ctx, userCred, query, input)
}
func (self *SHost) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformDisableInput) (jsonutils.JSONObject, error) {
if self.GetEnabled() {
_, err := self.SEnabledStatusStandaloneResourceBase.PerformDisable(ctx, userCred, query, input)
_, err := self.SEnabledStatusInfrasResourceBase.PerformDisable(ctx, userCred, query, input)
if err != nil {
return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBase.PerformDisable")
return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBase.PerformDisable")
}
self.SyncAttachedStorageStatus()
}
@@ -4449,7 +4505,7 @@ func (self *SHost) getCloudProviderInfo() SCloudProviderInfo {
}
func (self *SHost) GetShortDesc(ctx context.Context) *jsonutils.JSONDict {
desc := self.SEnabledStatusStandaloneResourceBase.GetShortDesc(ctx)
desc := self.SEnabledStatusInfrasResourceBase.GetShortDesc(ctx)
info := self.getCloudProviderInfo()
desc.Update(jsonutils.Marshal(&info))
return desc
@@ -4505,9 +4561,9 @@ func (host *SHost) GetDynamicConditionInput() *jsonutils.JSONDict {
}
func (host *SHost) PerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformStatusInput) (jsonutils.JSONObject, error) {
ret, err := host.SEnabledStatusStandaloneResourceBase.PerformStatus(ctx, userCred, query, input)
ret, err := host.SEnabledStatusInfrasResourceBase.PerformStatus(ctx, userCred, query, input)
if err != nil {
return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBase.PerformStatus")
return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBase.PerformStatus")
}
host.ClearSchedDescCache()
return ret, nil
@@ -4598,7 +4654,7 @@ func (host *SHost) PerformHostMaintenance(ctx context.Context, userCred mcclient
}
func (host *SHost) SetStatus(userCred mcclient.TokenCredential, status string, reason string) error {
err := host.SEnabledStatusStandaloneResourceBase.SetStatus(userCred, status, reason)
err := host.SEnabledStatusInfrasResourceBase.SetStatus(userCred, status, reason)
if err != nil {
return err
}
@@ -4850,3 +4906,22 @@ func (self *SHost) StartSyncConfig(ctx context.Context, userCred mcclient.TokenC
task.ScheduleRun(nil)
return nil
}
func (model *SHost) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
// make host default public
model.IsPublic = true
model.PublicScope = string(rbacutils.ScopeSystem)
return model.SEnabledStatusInfrasResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
}
func (host *SHost) PerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeDomainOwnerInput) (jsonutils.JSONObject, error) {
localStorages := host.GetAttachedLocalStorages()
for i := range localStorages {
_, err := localStorages[i].PerformChangeOwner(ctx, userCred, query, input)
if err != nil {
return nil, errors.Wrap(err, "local storage change owner")
}
}
return host.SEnabledStatusInfrasResourceBase.PerformChangeOwner(ctx, userCred, query, input)
}

Some files were not shown because too many files have changed in this diff Show More