fix(region): isolated device share (#22351)

This commit is contained in:
屈轩
2025-03-31 18:17:21 +08:00
committed by GitHub
parent 08bd825ef0
commit 4b8148362f
12 changed files with 173 additions and 28 deletions
@@ -17,6 +17,7 @@ package compute
import (
"yunion.io/x/onecloud/cmd/climc/shell"
modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
"yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/onecloud/pkg/mcclient/options/compute"
)
@@ -27,4 +28,6 @@ func init() {
cmd.Show(&compute.DeviceShowOptions{})
cmd.BatchDelete(&compute.DeviceDeleteOptions{})
cmd.BatchPerform("purge", &compute.DevicePurgeOptions{})
cmd.Perform("public", &options.SharableResourcePublicOptions{})
cmd.Perform("private", &options.BaseIdOptions{})
}
+1 -16
View File
@@ -39,6 +39,7 @@ func init() {
cmd.Delete(&compute_options.NetworkIdOptions{})
cmd.GetMetadata(&compute_options.NetworkIdOptions{})
cmd.Perform("private", &compute_options.NetworkIdOptions{})
cmd.Perform("public", &options.SharableResourcePublicOptions{})
cmd.Perform("syncstatus", &compute_options.NetworkIdOptions{})
cmd.Perform("sync", &compute_options.NetworkIdOptions{})
cmd.Perform("purge", &compute_options.NetworkIdOptions{})
@@ -48,22 +49,6 @@ func init() {
cmd.Perform("sync-additional-wires", &compute_options.NetworkSyncAdditionalWiresOptions{})
cmd.Get("available-addresses", &compute_options.NetworkIdOptions{})
type NetworkShareOptions struct {
ID string `help:"ID or Name of the zone to show"`
Scope string `help:"sharing scope" choices:"system|domain|project"`
SharedProjects []string `help:"Share to prjects"`
SharedDomains []string `help:"share to domains"`
}
R(&NetworkShareOptions{}, "network-public", "Make a network public", func(s *mcclient.ClientSession, args *NetworkShareOptions) error {
params := jsonutils.Marshal(args)
result, err := modules.Networks.PerformAction(s, args.ID, "public", params)
if err != nil {
return err
}
printObject(result)
return nil
})
type NetworkCreateOptions2 struct {
Wire string `help:"ID or Name of wire in which the network is created"`
Vpc string `help:"ID or Name of vpc in which the network is created"`
+1 -1
View File
@@ -93,7 +93,7 @@ require (
k8s.io/cri-api v0.22.17
k8s.io/klog/v2 v2.20.0
moul.io/http2curl/v2 v2.3.0
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250325152522-0d7006412421
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250331090349-7d6931240a65
yunion.io/x/executor v0.0.0-20241205080005-48f5b1212256
yunion.io/x/jsonutils v1.0.1-0.20240930100528-1671a2d0d22f
yunion.io/x/log v1.0.1-0.20240305175729-7cf2d6cd5a91
+2 -2
View File
@@ -1376,8 +1376,8 @@ sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250325152522-0d7006412421 h1:9q9pb2Yqv6sKN+dFL96gZmkydoWKALcU0ezQBKHKucI=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250325152522-0d7006412421/go.mod h1:FXxAEbdNfWXX9gjME3K2nJhkydHY5EKEUZb+RLEzVwQ=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250331090349-7d6931240a65 h1:q7lnCLb6PVLPhOuZWhb9pGtduL1mbksw4G47XFOiGLU=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250331090349-7d6931240a65/go.mod h1:FXxAEbdNfWXX9gjME3K2nJhkydHY5EKEUZb+RLEzVwQ=
yunion.io/x/executor v0.0.0-20241205080005-48f5b1212256 h1:kLKQ6zbgPDQflRwoHFAjxNChcbhXIFgsUVLkJwiXu/8=
yunion.io/x/executor v0.0.0-20241205080005-48f5b1212256/go.mod h1:Uxuou9WQIeJXNpy7t2fPLL0BYLvLiMvGQwY7Qc6aSws=
yunion.io/x/jsonutils v0.0.0-20190625054549-a964e1e8a051/go.mod h1:4N0/RVzsYL3kH3WE/H1BjUQdFiWu50JGCFQuuy+Z634=
+1
View File
@@ -29,6 +29,7 @@ const (
type IsolateDeviceDetails struct {
apis.StandaloneResourceDetails
apis.SharableResourceBaseInfo
HostResourceInfo
SIsolatedDevice
+44 -4
View File
@@ -181,8 +181,9 @@ func GetCapabilities(ctx context.Context, userCred mcclient.TokenCredential, que
var ownerId mcclient.IIdentityProvider
scopeStr := jsonutils.GetAnyString(query, []string{"scope"})
scope := rbacscope.String2Scope(scopeStr)
var domainId string
var domainId, tenantId string
domainStr := jsonutils.GetAnyString(query, []string{"domain", "domain_id", "project_domain", "project_domain_id"})
tenantStr := jsonutils.GetAnyString(query, []string{"tenant", "tenant_id", "project", "project_id"})
if len(domainStr) > 0 {
domain, err := db.TenantCacheManager.FetchDomainByIdOrName(ctx, domainStr)
if err != nil {
@@ -198,6 +199,16 @@ func GetCapabilities(ctx context.Context, userCred mcclient.TokenCredential, que
domainId = userCred.GetProjectDomainId()
ownerId = userCred
}
if len(tenantStr) > 0 {
project, err := db.TenantCacheManager.FetchTenantById(ctx, tenantStr)
if err != nil {
if err == sql.ErrNoRows {
return capa, httperrors.NewResourceNotFoundError2("projects", tenantStr)
}
return capa, httperrors.NewGeneralError(err)
}
tenantId = project.GetId()
}
if scope == rbacscope.ScopeSystem {
result := policy.PolicyManager.Allow(scope, userCred, consts.GetServiceType(), "capabilities", policy.PolicyActionList)
if result.Result.IsDeny() {
@@ -239,7 +250,7 @@ func GetCapabilities(ctx context.Context, userCred mcclient.TokenCredential, que
if err != nil {
return capa, errors.Wrapf(err, "getStorageTypes")
}
capa.GPUModels, capa.PCIModelTypes = getIsolatedDeviceInfo(ctx, userCred, region, zone, domainId)
capa.GPUModels, capa.PCIModelTypes = getIsolatedDeviceInfo(ctx, userCred, region, zone, domainId, tenantId)
capa.SchedPolicySupport = isSchedPolicySupported(region, zone)
capa.MinNicCount = getMinNicCount(region, zone)
capa.MaxNicCount = getMaxNicCount(region, zone)
@@ -845,13 +856,42 @@ type PCIDevModelTypes struct {
Hypervisor string
}
func getIsolatedDeviceInfo(ctx context.Context, userCred mcclient.TokenCredential, region *SCloudregion, zone *SZone, domainId string) ([]string, []PCIDevModelTypes) {
devices := IsolatedDeviceManager.Query().SubQuery()
func getIsolatedDeviceInfo(ctx context.Context, userCred mcclient.TokenCredential, region *SCloudregion, zone *SZone, domainId, tenantId string) ([]string, []PCIDevModelTypes) {
devicesQ := IsolatedDeviceManager.Query()
hostQuery := HostManager.Query()
if len(domainId) > 0 {
ownerId := &db.SOwnerId{DomainId: domainId}
hostQuery = StorageManager.FilterByOwner(ctx, hostQuery, StorageManager, userCred, ownerId, rbacscope.ScopeDomain)
}
if len(tenantId) > 0 {
subq := db.SharedResourceManager.Query("resource_id")
subq = subq.Equals("resource_type", IsolatedDeviceManager.Keyword())
subq = subq.Equals("target_project_id", tenantId)
subq = subq.Equals("target_type", db.SharedTargetProject)
conds := []sqlchemy.ICondition{
sqlchemy.AND(
sqlchemy.IsTrue(devicesQ.Field("is_public")),
sqlchemy.Equals(devicesQ.Field("public_scope"), rbacscope.ScopeSystem),
),
sqlchemy.In(devicesQ.Field("id"), subq.SubQuery()),
}
if len(domainId) > 0 {
subq2 := db.SharedResourceManager.Query("resource_id")
subq2 = subq2.Equals("resource_type", IsolatedDeviceManager.Keyword())
subq2 = subq2.Equals("target_project_id", domainId)
subq2 = subq2.Equals("target_type", db.SharedTargetDomain)
conds = append(conds, sqlchemy.AND(
sqlchemy.IsTrue(devicesQ.Field("is_public")),
sqlchemy.Equals(devicesQ.Field("public_scope"), rbacscope.ScopeDomain),
sqlchemy.OR(
sqlchemy.In(devicesQ.Field("id"), subq2.SubQuery()),
),
),
)
}
devicesQ = devicesQ.Filter(sqlchemy.OR(conds...))
}
devices := devicesQ.SubQuery()
hosts := hostQuery.SubQuery()
q := devices.Query(hosts.Field("host_type"), devices.Field("model"), devices.Field("dev_type"), devices.Field("nvme_size_mb"))
+26 -1
View File
@@ -2806,7 +2806,32 @@ func (hh *SHost) newIsolateDevice(ctx context.Context, userCred mcclient.TokenCr
ret.DevType = dev.GetDevType()
ret.NumaNode = dev.GetNumaNode()
ret.VendorDeviceId = dev.GetVendorDeviceId()
return IsolatedDeviceManager.TableSpec().Insert(ctx, ret)
err := IsolatedDeviceManager.TableSpec().Insert(ctx, ret)
if err != nil {
return err
}
sharedProjectIds, err := dev.GetSharedProjectIds()
if err != nil {
if errors.Cause(err) == cloudprovider.ErrNotImplemented {
return nil
}
return err
}
if len(sharedProjectIds) == 0 {
return nil
}
if len(sharedProjectIds) > 0 {
projectIds, err := db.FetchField(ExternalProjectManager, "tenant_id", func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
return q.Equals("manager_id", hh.ManagerId).In("external_id", sharedProjectIds)
})
if err != nil {
return err
}
input := apis.PerformPublicProjectInput{SharedProjectIds: projectIds}
input.Scope = "project"
db.SharablePerformPublic(ret, ctx, userCred, input)
}
return nil
}
func (hh *SHost) SyncHostVMs(ctx context.Context, userCred mcclient.TokenCredential, iprovider cloudprovider.ICloudProvider, vms []cloudprovider.ICloudVM, syncOwnerId mcclient.IIdentityProvider, xor bool) ([]SGuestSyncResult, compare.SyncResult) {
+72 -3
View File
@@ -35,6 +35,7 @@ import (
"yunion.io/x/pkg/utils"
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/apis"
api "yunion.io/x/onecloud/pkg/apis/compute"
hostapi "yunion.io/x/onecloud/pkg/apis/host"
"yunion.io/x/onecloud/pkg/apis/notify"
@@ -69,6 +70,7 @@ var VENDOR_ID_MAP = api.VENDOR_ID_MAP
type SIsolatedDeviceManager struct {
db.SStandaloneResourceBaseManager
db.SExternalizedResourceBaseManager
db.SSharableBaseResourceManager
SHostResourceBaseManager
}
@@ -93,7 +95,8 @@ func init() {
type SIsolatedDevice struct {
db.SStandaloneResourceBase
db.SExternalizedResourceBase
SHostResourceBase `width:"36" charset:"ascii" nullable:"false" default:"" index:"true" list:"domain" create:"domain_required"`
db.SSharableBaseResource `"is_public->create":"domain_optional" "public_scope->create":"domain_optional"`
SHostResourceBase `width:"36" charset:"ascii" nullable:"false" default:"" index:"true" list:"domain" create:"domain_required"`
// # PCI / GPU-HPC / GPU-VGA / USB / NIC
// 设备类型
@@ -1398,11 +1401,13 @@ func (manager *SIsolatedDeviceManager) FetchCustomizeColumns(
stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
hostRows := manager.SHostResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
shareRows := manager.SSharableBaseResourceManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
guestIds := make([]string, len(rows))
for i := range rows {
rows[i] = api.IsolateDeviceDetails{
StandaloneResourceDetails: stdRows[i],
HostResourceInfo: hostRows[i],
SharableResourceBaseInfo: shareRows[i],
}
guestIds[i] = objs[i].(*SIsolatedDevice).GuestId
}
@@ -1587,7 +1592,7 @@ func (manager *SIsolatedDeviceManager) NamespaceScope() rbacscope.TRbacScope {
}
func (manager *SIsolatedDeviceManager) ResourceScope() rbacscope.TRbacScope {
return rbacscope.ScopeDomain
return rbacscope.ScopeProject
}
func (manager *SIsolatedDeviceManager) FilterByOwner(ctx context.Context, q *sqlchemy.SQuery, man db.FilterByOwnerProvider, userCred mcclient.TokenCredential, owner mcclient.IIdentityProvider, scope rbacscope.TRbacScope) *sqlchemy.SQuery {
@@ -1625,7 +1630,39 @@ func (model *SIsolatedDevice) syncWithCloudIsolateDevice(ctx context.Context, us
model.VendorDeviceId = dev.GetVendorDeviceId()
return nil
})
return err
if err != nil {
return err
}
sharedProjectIds, err := dev.GetSharedProjectIds()
if err != nil {
if errors.Cause(err) == cloudprovider.ErrNotImplemented {
return nil
}
return err
}
log.Infof("share projectIds: %s", sharedProjectIds)
if len(sharedProjectIds) == 0 {
return nil
}
host := model.getHost()
if host == nil {
return nil
}
if len(sharedProjectIds) > 0 {
projectIds, err := db.FetchField(ExternalProjectManager, "tenant_id", func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
return q.Equals("manager_id", host.ManagerId).In("external_id", sharedProjectIds)
})
if err != nil {
return err
}
input := apis.PerformPublicProjectInput{SharedProjectIds: projectIds}
input.Scope = "project"
err = db.SharablePerformPublic(model, ctx, userCred, input)
if err != nil {
return errors.Wrapf(err, "SharablePerformPublic")
}
}
return nil
}
func (model *SIsolatedDevice) SetNetworkIndex(idx int) error {
@@ -1635,3 +1672,35 @@ func (model *SIsolatedDevice) SetNetworkIndex(idx int) error {
})
return err
}
func (model *SIsolatedDevice) GetRequiredSharedDomainIds() []string {
host := model.getHost()
if host != nil {
return []string{host.DomainId}
}
return []string{}
}
func (model *SIsolatedDevice) GetSharableTargetDomainIds() []string {
return nil
}
func (model *SIsolatedDevice) GetSharedDomains() []string {
return db.SharableGetSharedProjects(model, db.SharedTargetDomain)
}
func (model *SIsolatedDevice) PerformPublic(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPublicProjectInput) (jsonutils.JSONObject, error) {
err := db.SharablePerformPublic(model, ctx, userCred, input)
if err != nil {
return nil, errors.Wrap(err, "SharablePerformPublic")
}
return nil, nil
}
func (model *SIsolatedDevice) PerformPrivate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPrivateInput) (jsonutils.JSONObject, error) {
err := db.SharablePerformPrivate(model, ctx, userCred)
if err != nil {
return nil, errors.Wrap(err, "SharablePerformPrivate")
}
return nil, nil
}
@@ -51,6 +51,14 @@ func (d *SIsolatedDevice) GetVendorDeviceId() string {
return d.VendorDeviceId
}
func (d *SIsolatedDevice) GetSharedProjectIds() ([]string, error) {
ret := []string{}
for _, p := range d.SharedProjects {
ret = append(ret, p.Id)
}
return ret, nil
}
func (region *SRegion) GetIsolatedDevices(hostId string, serverId string) ([]SIsolatedDevice, error) {
params := map[string]interface{}{}
if len(hostId) > 0 {
+13
View File
@@ -51,3 +51,16 @@ type SharableResourcePublicBaseOptions struct {
SharedProjects []string `help:"Share to projects"`
SharedDomains []string `help:"Share to domains"`
}
type SharableResourcePublicOptions struct {
ID string
SharableResourcePublicBaseOptions
}
func (opts *SharableResourcePublicOptions) Params() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(opts.SharableResourcePublicBaseOptions), nil
}
func (opts *SharableResourcePublicOptions) GetId() string {
return opts.ID
}
+1 -1
View File
@@ -1785,7 +1785,7 @@ sigs.k8s.io/structured-merge-diff/v4/value
# sigs.k8s.io/yaml v1.2.0
## explicit; go 1.12
sigs.k8s.io/yaml
# yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250325152522-0d7006412421
# yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250331090349-7d6931240a65
## explicit; go 1.21
yunion.io/x/cloudmux/pkg/apis
yunion.io/x/cloudmux/pkg/apis/billing
+1
View File
@@ -331,6 +331,7 @@ type IsolateDevice interface {
GetDevType() string
GetNumaNode() int8
GetVendorDeviceId() string
GetSharedProjectIds() ([]string, error)
}
type ICloudVM interface {