From 3ba6d4186cb9b69fec7e7c978cc3483d66768bea Mon Sep 17 00:00:00 2001 From: Zexi Li Date: Sat, 23 Mar 2019 16:49:04 +0800 Subject: [PATCH] dynamic schedule support resource type --- cmd/climc/shell/dynamicschedtags.go | 14 +- cmd/climc/shell/schedpolicies.go | 8 +- pkg/apis/compute/api.go | 4 +- pkg/apis/scheduler/api.go | 9 ++ pkg/cloudcommon/db/db_dispatcher.go | 2 + pkg/compute/models/disks.go | 5 + pkg/compute/models/dynamicschedtags.go | 128 ++++++++++++----- pkg/compute/models/guests.go | 60 +++----- pkg/compute/models/hosts.go | 4 + pkg/compute/models/initdb.go | 1 + pkg/compute/models/schedpolicies.go | 129 ++++++++++++------ pkg/compute/models/storages.go | 4 + pkg/mcclient/modules/mod_dynamicschedtags.go | 5 +- pkg/mcclient/modules/mod_schedpolicies.go | 6 +- pkg/mcclient/options/base.go | 2 +- .../predicates/aggregate_predicate.go | 6 +- .../predicates/disk_schedtag_predicate.go | 7 +- .../algorithm/predicates/schedtag_helper.go | 6 +- 18 files changed, 264 insertions(+), 136 deletions(-) diff --git a/cmd/climc/shell/dynamicschedtags.go b/cmd/climc/shell/dynamicschedtags.go index a98d95a679..6093d4c4e1 100644 --- a/cmd/climc/shell/dynamicschedtags.go +++ b/cmd/climc/shell/dynamicschedtags.go @@ -114,14 +114,18 @@ func init() { }) type DynamicSchedtagEvaluateOptions struct { - ID string `help:"ID or name of the sched policy"` - HOST string `help:"ID or name of the host"` - SERVER string `help:"ID or name of the server"` + ID string `help:"ID or name of the sched policy"` + ResourceType string `help:"Standalone resource type" choices:"host|storage" default:"host"` + VirtaulResourceType string `help:"Virtual resource type" choices:"server|disk" default:"server"` + STANDALONERES string `help:"ID or name of the standalone resource, e.g. host, storage"` + VIRTUALRES string `help:"ID or name of the virtual resource, e.g. server, disk"` } R(&DynamicSchedtagEvaluateOptions{}, "dynamic-schedtag-evaluate", "Evaluate dynamic schedtag condition", func(s *mcclient.ClientSession, args *DynamicSchedtagEvaluateOptions) error { params := jsonutils.NewDict() - params.Add(jsonutils.NewString(args.HOST), "host") - params.Add(jsonutils.NewString(args.SERVER), "server") + params.Add(jsonutils.NewString(args.ResourceType), "resource_type") + params.Add(jsonutils.NewString(args.VirtaulResourceType), "virtual_resource_type") + params.Add(jsonutils.NewString(args.STANDALONERES), "object_id") + params.Add(jsonutils.NewString(args.VIRTUALRES), "virtual_object_id") result, err := modules.Dynamicschedtags.PerformAction(s, args.ID, "evaluate", params) if err != nil { return err diff --git a/cmd/climc/shell/schedpolicies.go b/cmd/climc/shell/schedpolicies.go index 758b6c0f86..f339f2d8a2 100644 --- a/cmd/climc/shell/schedpolicies.go +++ b/cmd/climc/shell/schedpolicies.go @@ -124,12 +124,14 @@ func init() { }) type SchedpoliciesEvaluateOptions struct { - ID string `help:"ID or name of the sched policy"` - SERVER string `help:"ID or name of the server"` + ID string `help:"ID or name of the sched policy"` + OBJECT string `help:"ID or name of the object"` + ResourceType string `help:"Resource type of the object" default:"server" choices:"server|disk" short-token:"t"` } R(&SchedpoliciesEvaluateOptions{}, "sched-policy-evaluate", "Evaluate sched policy", func(s *mcclient.ClientSession, args *SchedpoliciesEvaluateOptions) error { params := jsonutils.NewDict() - params.Add(jsonutils.NewString(args.SERVER), "server") + params.Add(jsonutils.NewString(args.OBJECT), "object") + params.Add(jsonutils.NewString(args.ResourceType), "resource_type") result, err := modules.Schedpolicies.PerformAction(s, args.ID, "evaluate", params) if err != nil { return err diff --git a/pkg/apis/compute/api.go b/pkg/apis/compute/api.go index a6fbce93b7..18259c0f2f 100644 --- a/pkg/apis/compute/api.go +++ b/pkg/apis/compute/api.go @@ -36,7 +36,7 @@ type NetworkConfig struct { StandbyPortCount int `json:"standby_port_count"` StandbyAddrCount int `json:"standby_addr_count"` - Project string `json:"project"` + Project string `json:"project_id"` Ifname string `json:"ifname"` } @@ -102,7 +102,7 @@ type ServerConfigs struct { // ResourceType "shared|prepaid|dedicated"` ResourceType string `json:"resource_type"` InstanceType string `json:"instance_type"` - Project string `json:"project"` + Project string `json:"project_id"` Backup bool `json:"backup"` Count int `json:"count"` diff --git a/pkg/apis/scheduler/api.go b/pkg/apis/scheduler/api.go index 25dfc24fb5..9cc0042a9a 100644 --- a/pkg/apis/scheduler/api.go +++ b/pkg/apis/scheduler/api.go @@ -1,6 +1,8 @@ package scheduler import ( + "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/apis" "yunion.io/x/onecloud/pkg/apis/compute" ) @@ -56,6 +58,13 @@ type ScheduleInput struct { ServerConfig } +func (input ScheduleInput) ToConditionInput() *jsonutils.JSONDict { + ret := input.JSON(input) + // old condition compatible + ret.Add(jsonutils.NewString(input.Project), "owner_tenant_id") + return ret +} + type CandidateDisk struct { Index int `json:"index"` StorageId string `json:"storage_id"` diff --git a/pkg/cloudcommon/db/db_dispatcher.go b/pkg/cloudcommon/db/db_dispatcher.go index 1375de94d1..b354f94c78 100644 --- a/pkg/cloudcommon/db/db_dispatcher.go +++ b/pkg/cloudcommon/db/db_dispatcher.go @@ -883,6 +883,8 @@ func doCreateItem(manager IModelManager, ctx context.Context, userCred mcclient. if err != nil { return nil, httperrors.NewGeneralError(err) } + // HACK: set data same as dataDict + data.(*jsonutils.JSONDict).Update(dataDict) return model, nil } diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index 966cc2dbb1..5c21f83016 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -1702,3 +1702,8 @@ func (self *SDisk) IsDetachable() bool { } return true } + +func (self *SDisk) GetDynamicConditionInput() *jsonutils.JSONDict { + conf := self.ToDiskConfig() + return conf.JSON(conf) +} diff --git a/pkg/compute/models/dynamicschedtags.go b/pkg/compute/models/dynamicschedtags.go index 5fe7c7903e..dd250bee1c 100644 --- a/pkg/compute/models/dynamicschedtags.go +++ b/pkg/compute/models/dynamicschedtags.go @@ -3,9 +3,11 @@ package models import ( "context" "database/sql" + "fmt" "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/sqlchemy" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/httperrors" @@ -13,8 +15,20 @@ import ( "yunion.io/x/onecloud/pkg/util/conditionparser" ) +type IDynamicResourceManager interface { + db.IModelManager +} + +type IDynamicResource interface { + db.IModel + GetDynamicConditionInput() *jsonutils.JSONDict +} + type SDynamicschedtagManager struct { db.SStandaloneResourceBaseManager + + StandaloneResourcesManager map[string]IDynamicResourceManager + VirtualResourcesManager map[string]IDynamicResourceManager } var DynamicschedtagManager *SDynamicschedtagManager @@ -27,9 +41,39 @@ func init() { "dynamicschedtag", "dynamicschedtags", ), + StandaloneResourcesManager: make(map[string]IDynamicResourceManager), + VirtualResourcesManager: make(map[string]IDynamicResourceManager), } } +func (man *SDynamicschedtagManager) bindDynamicResourceManager( + store map[string]IDynamicResourceManager, + ms ...IDynamicResourceManager) { + for _, m := range ms { + store[m.Keyword()] = m + } +} + +func (man *SDynamicschedtagManager) BindStandaloneResourceManager(ms ...IDynamicResourceManager) { + man.bindDynamicResourceManager(man.StandaloneResourcesManager, ms...) +} + +func (man *SDynamicschedtagManager) BindVirtualResourceManager(ms ...IDynamicResourceManager) { + man.bindDynamicResourceManager(man.VirtualResourcesManager, ms...) +} + +func (man *SDynamicschedtagManager) InitializeData() error { + man.BindStandaloneResourceManager( + HostManager, + StorageManager, + ) + man.BindVirtualResourceManager( + GuestManager, + DiskManager, + ) + return nil +} + // dynamic schedtag is called before scan host candidates, dynamically adding additional schedtag to hosts // condition examples: // host.sys_load > 1.5 || host.mem_used_percent > 0.7 => "high_load" @@ -86,7 +130,8 @@ func validateDynamicSchedtagInputData(data *jsonutils.JSONDict, create bool) err return httperrors.NewGeneralError(err) } } - data.Set("schedtag_id", jsonutils.NewString(schedObj.GetId())) + schedtag := schedObj.(*SSchedtag) + data.Set("schedtag_id", jsonutils.NewString(schedtag.GetId())) } return nil @@ -126,6 +171,7 @@ func (self *SDynamicschedtag) getMoreColumns(extra *jsonutils.JSONDict) *jsonuti schedtag := self.getSchedtag() if schedtag != nil { extra.Add(jsonutils.NewString(schedtag.GetName()), "schedtag") + extra.Add(jsonutils.NewString(schedtag.ResourceType), "resource_type") } return extra } @@ -143,17 +189,17 @@ func (self *SDynamicschedtag) GetExtraDetails(ctx context.Context, userCred mccl return self.getMoreColumns(extra), nil } -func (manager *SDynamicschedtagManager) GetAllEnabledDynamicSchedtags() []SDynamicschedtag { - return manager.getAllEnabledDynamicSchedtags() -} - -func (manager *SDynamicschedtagManager) getAllEnabledDynamicSchedtags() []SDynamicschedtag { +func (manager *SDynamicschedtagManager) GetEnabledDynamicSchedtagsByResource(resType string) []SDynamicschedtag { rules := make([]SDynamicschedtag, 0) q := DynamicschedtagManager.Query().IsTrue("enabled") + schedtags := SchedtagManager.Query().SubQuery() + q = q.Join(schedtags, sqlchemy.AND( + sqlchemy.Equals(q.Field("schedtag_id"), schedtags.Field("id")), + sqlchemy.Equals(schedtags.Field("resource_type"), resType))) err := db.FetchModelObjects(manager, q, &rules) if err != nil { - log.Errorf("getAllEnabledDynamicSchedtags fail %s", err) + log.Errorf("GetEnabledDynamicSchedtagsByResource %s fail %s", resType, err) return nil } @@ -165,44 +211,46 @@ func (self *SDynamicschedtag) AllowPerformEvaluate(ctx context.Context, userCred } func (self *SDynamicschedtag) PerformEvaluate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - serverStr := jsonutils.GetAnyString(data, []string{"server", "server_id", "guest", "guest_id"}) - serverObj, err := GuestManager.FetchByIdOrName(userCred, serverStr) - if err != nil { - if err == sql.ErrNoRows { - return nil, httperrors.NewResourceNotFoundError("server %s not found", serverStr) - } else { - return nil, httperrors.NewGeneralError(err) - } + objectId := jsonutils.GetAnyString(data, []string{"object", "object_id"}) + resType := jsonutils.GetAnyString(data, []string{"resource_type"}) + virtObjId := jsonutils.GetAnyString(data, []string{"virtual_object", "virtual_object_id"}) + virtType := jsonutils.GetAnyString(data, []string{"virtual_resource_type"}) + + objectMan := DynamicschedtagManager.StandaloneResourcesManager[resType] + if objectMan == nil { + return nil, httperrors.NewResourceNotFoundError("Resource type %s not support", resType) + } + virtObjectMan := DynamicschedtagManager.VirtualResourcesManager[virtType] + if virtObjectMan == nil { + return nil, httperrors.NewResourceNotFoundError("Virtual resource type %s not support", virtType) } - server := serverObj.(*SGuest) - srvDesc := server.getSchedDesc() - - hostStr := jsonutils.GetAnyString(data, []string{"host", "host_id"}) - hostObj, err := HostManager.FetchByIdOrName(userCred, hostStr) + object, err := FetchDynamicResourceObject(objectMan, userCred, objectId) if err != nil { - if err == sql.ErrNoRows { - return nil, httperrors.NewResourceNotFoundError("host %s not found", serverStr) - } else { - return nil, httperrors.NewGeneralError(err) - } + return nil, err + } + virtObject, err := FetchDynamicResourceObject(virtObjectMan, userCred, virtObjId) + if err != nil { + return nil, err } - host := hostObj.(*SHost) - // TODO: to fill host scheduling information - hostDesc := jsonutils.Marshal(host) + // TODO: to fill standalone resource scheduling information + standaloneDesc := object.GetDynamicConditionInput() + virtDesc := virtObject.GetDynamicConditionInput() params := jsonutils.NewDict() - params.Add(srvDesc.JSON(srvDesc), "server") - params.Add(hostDesc, "host") + params.Add(standaloneDesc, object.Keyword()) + params.Add(virtDesc, virtObject.Keyword()) + + log.V(10).Debugf("Dynamicschedtag evaluate input: %s", params.PrettyString()) meet, err := conditionparser.Eval(self.Condition, params) if err != nil { return nil, err } result := jsonutils.NewDict() - result.Add(srvDesc.JSON(srvDesc), "server") - result.Add(hostDesc, "host") + result.Add(standaloneDesc, object.Keyword()) + result.Add(virtDesc, virtObject.Keyword()) if meet { result.Add(jsonutils.JSONTrue, "result") @@ -211,3 +259,19 @@ func (self *SDynamicschedtag) PerformEvaluate(ctx context.Context, userCred mccl } return result, nil } + +func FetchDynamicResourceObject(man IDynamicResourceManager, userCred mcclient.TokenCredential, idOrName string) (IDynamicResource, error) { + obj, err := man.FetchByIdOrName(userCred, idOrName) + if err != nil { + if err == sql.ErrNoRows { + return nil, httperrors.NewResourceNotFoundError("%s %s not found", man.Keyword(), idOrName) + } else { + return nil, httperrors.NewGeneralError(err) + } + } + res, ok := obj.(IDynamicResource) + if !ok { + return nil, httperrors.NewGeneralError(fmt.Errorf("%s %s not implement IDynamicResource", obj.Keyword(), obj.GetName())) + } + return res, nil +} diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 49abcb20fc..0b47845452 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -3888,43 +3888,6 @@ func (self *SGuest) getDefaultStorageType() string { return STORAGE_LOCAL } -func (self *SGuest) getSchedDesc() *schedapi.ScheduleInput { - desc := new(schedapi.ScheduleInput) - - desc.Id = self.Id - desc.Name = self.Name - desc.Memory = self.VmemSize - desc.Ncpu = int(self.VcpuCount) - - gds := self.GetDisks() - if gds != nil { - for i := 0; i < len(gds); i += 1 { - conf := new(api.DiskConfig) - jsonutils.Marshal(gds[i].ToDiskInfo()).Unmarshal(conf) - desc.Disks = append(desc.Disks, conf) - } - } - - gns, _ := self.GetNetworks("") - if gns != nil { - for i := 0; i < len(gns); i += 1 { - desc.Networks = append(desc.Networks, &api.NetworkConfig{ - Network: gns[i].NetworkId, - Address: gns[i].IpAddr, - }) - } - } - - if len(self.HostId) > 0 && regutils.MatchUUID(self.HostId) { - desc.HostId = self.HostId - } - - desc.Project = self.ProjectId - desc.Hypervisor = self.GetHypervisor() - - return desc -} - func (self *SGuest) GetApptags() []string { tagsStr := self.GetMetadata("app_tags", nil) if len(tagsStr) > 0 { @@ -3936,13 +3899,15 @@ func (self *SGuest) GetApptags() []string { func (self *SGuest) ToSchedDesc() *schedapi.ScheduleInput { desc := new(schedapi.ScheduleInput) config := &schedapi.ServerConfig{ - Name: self.Name, - Memory: self.VmemSize, - Ncpu: int(self.VcpuCount), + Name: self.Name, + Memory: self.VmemSize, + Ncpu: int(self.VcpuCount), + ServerConfigs: new(api.ServerConfigs), } + desc.Id = self.Id //self.FillGroupSchedDesc(desc) - self.FillDiskSchedDesc(config) - self.FillNetSchedDesc(config) + self.FillDiskSchedDesc(config.ServerConfigs) + self.FillNetSchedDesc(config.ServerConfigs) if len(self.HostId) > 0 && regutils.MatchUUID(self.HostId) { config.HostId = self.HostId } @@ -3970,7 +3935,7 @@ func (self *SGuest) ToSchedDesc() *schedapi.ScheduleInput { } }*/ -func (self *SGuest) FillDiskSchedDesc(desc *schedapi.ServerConfig) { +func (self *SGuest) FillDiskSchedDesc(desc *api.ServerConfigs) { guestDisks := make([]SGuestdisk, 0) err := GuestdiskManager.Query().Equals("guest_id", self.Id).All(&guestDisks) if err != nil { @@ -3982,13 +3947,16 @@ func (self *SGuest) FillDiskSchedDesc(desc *schedapi.ServerConfig) { } } -func (self *SGuest) FillNetSchedDesc(desc *schedapi.ServerConfig) { +func (self *SGuest) FillNetSchedDesc(desc *api.ServerConfigs) { guestNetworks := make([]SGuestnetwork, 0) err := GuestnetworkManager.Query().Equals("guest_id", self.Id).All(&guestNetworks) if err != nil { log.Errorln("FillNetSchedDesc: %v", err) return } + if desc.Networks == nil { + desc.Networks = make([]*api.NetworkConfig, 0) + } for i := 0; i < len(guestNetworks); i++ { desc.Networks = append(desc.Networks, guestNetworks[i].ToNetworkConfig()) } @@ -4040,3 +4008,7 @@ func (guest *SGuest) GetDetailsTasks(ctx context.Context, userCred mcclient.Toke ret.Add(jsonutils.NewArray(objs...), "tasks") return ret, nil } + +func (guest *SGuest) GetDynamicConditionInput() *jsonutils.JSONDict { + return guest.ToSchedDesc().ToConditionInput() +} diff --git a/pkg/compute/models/hosts.go b/pkg/compute/models/hosts.go index c6473ff28e..3490b9da4e 100644 --- a/pkg/compute/models/hosts.go +++ b/pkg/compute/models/hosts.go @@ -3814,3 +3814,7 @@ func (host *SHost) PerformSetSchedtag(ctx context.Context, userCred mcclient.Tok host.ClearSchedDescCache() return nil, nil } + +func (host *SHost) GetDynamicConditionInput() *jsonutils.JSONDict { + return jsonutils.Marshal(host).(*jsonutils.JSONDict) +} diff --git a/pkg/compute/models/initdb.go b/pkg/compute/models/initdb.go index 774489d9cd..783e6a982c 100644 --- a/pkg/compute/models/initdb.go +++ b/pkg/compute/models/initdb.go @@ -28,6 +28,7 @@ func InitDB() error { LoadbalancerBackendGroupManager, LoadbalancerBackendManager, SchedtagManager, + DynamicschedtagManager, } { err := manager.InitializeData() if err != nil { diff --git a/pkg/compute/models/schedpolicies.go b/pkg/compute/models/schedpolicies.go index a70b0bf1fc..51a309505f 100644 --- a/pkg/compute/models/schedpolicies.go +++ b/pkg/compute/models/schedpolicies.go @@ -2,11 +2,11 @@ package models import ( "context" - "database/sql" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/utils" + "yunion.io/x/sqlchemy" api "yunion.io/x/onecloud/pkg/apis/compute" schedapi "yunion.io/x/onecloud/pkg/apis/scheduler" @@ -113,6 +113,7 @@ func (self *SSchedpolicy) getMoreColumns(extra *jsonutils.JSONDict) *jsonutils.J schedtag := self.getSchedtag() if schedtag != nil { extra.Add(jsonutils.NewString(schedtag.GetName()), "schedtag") + extra.Add(jsonutils.NewString(schedtag.ResourceType), "resource_type") } return extra } @@ -130,46 +131,58 @@ func (self *SSchedpolicy) GetExtraDetails(ctx context.Context, userCred mcclient return self.getMoreColumns(extra), nil } -func (manager *SSchedpolicyManager) getAllEnabledPolicies() []SSchedpolicy { +func (manager *SSchedpolicyManager) getAllEnabledPoliciesByResource(resType string) []SSchedpolicy { policies := make([]SSchedpolicy, 0) - q := SchedpolicyManager.Query().IsTrue("enabled") + schedtags := SchedtagManager.Query().SubQuery() + q = q.Join(schedtags, sqlchemy.AND( + sqlchemy.Equals(q.Field("schedtag_id"), schedtags.Field("id")), + sqlchemy.Equals(schedtags.Field("resource_type"), resType))) err := db.FetchModelObjects(manager, q, &policies) if err != nil { log.Errorf("getAllEnabledPolicies fail %s", err) return nil } - return policies } +func (manager *SSchedpolicyManager) getHostEnabledPolicies() []SSchedpolicy { + return manager.getAllEnabledPoliciesByResource(HostManager.KeywordPlural()) +} + +func (manager *SSchedpolicyManager) getStorageEnabledPolicies() []SSchedpolicy { + return manager.getAllEnabledPoliciesByResource(StorageManager.KeywordPlural()) +} + func (self *SSchedpolicy) AllowPerformEvaluate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { return db.IsAdminAllowPerform(userCred, self, "evaluate") } func (self *SSchedpolicy) PerformEvaluate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - serverStr := jsonutils.GetAnyString(data, []string{"server", "server_id", "guest", "guest_id"}) - serverObj, err := GuestManager.FetchByIdOrName(userCred, serverStr) + objectId := jsonutils.GetAnyString(data, []string{"object", "object_id"}) + resType := jsonutils.GetAnyString(data, []string{"resource_type"}) + resMan := DynamicschedtagManager.VirtualResourcesManager[resType] + if resMan == nil { + return nil, httperrors.NewNotAcceptableError("ResourceType %q not support", resType) + } + obj, err := FetchDynamicResourceObject(resMan, userCred, objectId) if err != nil { - if err == sql.ErrNoRows { - return nil, httperrors.NewResourceNotFoundError("server %s not found", serverStr) - } else { - return nil, httperrors.NewGeneralError(err) - } + return nil, err } - server := serverObj.(*SGuest) - desc := server.getSchedDesc() + desc := obj.GetDynamicConditionInput() params := jsonutils.NewDict() - params.Add(desc.JSON(desc), "server") + params.Add(desc, obj.Keyword()) + + log.V(10).Debugf("Schedpolicy evaluate input: %s", params.PrettyString()) meet, err := conditionparser.Eval(self.Condition, params) if err != nil { return nil, err } result := jsonutils.NewDict() - result.Add(desc.JSON(desc), "server") + result.Add(desc, obj.Keyword()) if meet { result.Add(jsonutils.JSONTrue, "result") } else { @@ -178,45 +191,85 @@ func (self *SSchedpolicy) PerformEvaluate(ctx context.Context, userCred mcclient return result, nil } -func ApplySchedPolicies(params *schedapi.ScheduleInput) *schedapi.ScheduleInput { - policies := SchedpolicyManager.getAllEnabledPolicies() - if policies == nil { - log.Errorf("getAllEnabledPolicies fail") - //return jsonutils.Marshal(params).(*jsonutils.JSONDict) - return params +func matchResourceSchedPolicy( + policy SSchedpolicy, + input *jsonutils.JSONDict, +) bool { + meet, err := conditionparser.Eval(policy.Condition, input) + if err != nil { + log.Errorf("Eval Condition %s error: %v", policy.Condition, err) + return false } + return meet +} +func applyResourceSchedPolicy( + policies []SSchedpolicy, + oldTags []*api.SchedtagConfig, + input *jsonutils.JSONDict, + setTags func([]*api.SchedtagConfig), +) { schedtags := make(map[string]string) - if len(params.ServerConfig.Schedtags) != 0 { - for _, tag := range params.ServerConfig.Schedtags { - schedtags[tag.Id] = tag.Strategy - } - log.Infof("original sched tag %#v", schedtags) + for _, tag := range oldTags { + schedtags[tag.Id] = tag.Strategy } - input := jsonutils.NewDict() - input.Add(jsonutils.Marshal(params), "server") + log.Infof("original schedtag %#v", schedtags) for i := 0; i < len(policies); i += 1 { - meet, err := conditionparser.Eval(policies[i].Condition, input) - if err == nil && meet { - st := policies[i].getSchedtag() - if st != nil { - schedtags[st.Name] = policies[i].Strategy - } + policy := policies[i] + st := policy.getSchedtag() + if matchResourceSchedPolicy(policy, input) { + schedtags[st.Name] = policy.Strategy } } - log.Infof("updated sched tag %s", schedtags) - params.ServerConfig.Schedtags = make([]*api.SchedtagConfig, 0) + newSchedtags := make([]*api.SchedtagConfig, 0) for name, strategy := range schedtags { - params.ServerConfig.Schedtags = append(params.ServerConfig.Schedtags, &api.SchedtagConfig{ + newSchedtags = append(newSchedtags, &api.SchedtagConfig{ Id: name, Strategy: strategy, }) } + setTags(newSchedtags) +} - return params +func GetDynamicConditionInput(man IDynamicResourceManager, input *jsonutils.JSONDict) *jsonutils.JSONDict { + ret := jsonutils.NewDict() + ret.Add(input, man.Keyword()) + return ret +} + +func applyServerSchedtags(policies []SSchedpolicy, input *schedapi.ScheduleInput) { + inputCond := GetDynamicConditionInput(GuestManager, input.ToConditionInput()) + setFunc := func(tags []*api.SchedtagConfig) { + input.Schedtags = tags + } + applyResourceSchedPolicy(policies, input.Schedtags, inputCond, setFunc) +} + +func applyDiskSchedtags(policies []SSchedpolicy, input *api.DiskConfig) { + inputCond := GetDynamicConditionInput(DiskManager, jsonutils.Marshal(input).(*jsonutils.JSONDict)) + setFunc := func(tags []*api.SchedtagConfig) { + input.Schedtags = tags + } + applyResourceSchedPolicy(policies, input.Schedtags, inputCond, setFunc) +} + +func ApplySchedPolicies(input *schedapi.ScheduleInput) *schedapi.ScheduleInput { + hostPolicies := SchedpolicyManager.getHostEnabledPolicies() + storagePolicies := SchedpolicyManager.getStorageEnabledPolicies() + + config := input.ServerConfigs + + applyServerSchedtags(hostPolicies, input) + for _, disk := range config.Disks { + applyDiskSchedtags(storagePolicies, disk) + } + + input.ServerConfig.ServerConfigs = config + + return input } diff --git a/pkg/compute/models/storages.go b/pkg/compute/models/storages.go index 4fa55dfbdc..d9baade751 100644 --- a/pkg/compute/models/storages.go +++ b/pkg/compute/models/storages.go @@ -1151,3 +1151,7 @@ func (self *SStorage) IsPrepaidRecycleResource() bool { func (self *SStorage) GetSchedtags() []SSchedtag { return GetSchedtags(StorageschedtagManager, self.Id) } + +func (self *SStorage) GetDynamicConditionInput() *jsonutils.JSONDict { + return jsonutils.Marshal(self).(*jsonutils.JSONDict) +} diff --git a/pkg/mcclient/modules/mod_dynamicschedtags.go b/pkg/mcclient/modules/mod_dynamicschedtags.go index 2cc2f1b9c8..ea66b8c44a 100644 --- a/pkg/mcclient/modules/mod_dynamicschedtags.go +++ b/pkg/mcclient/modules/mod_dynamicschedtags.go @@ -6,8 +6,9 @@ var ( func init() { Dynamicschedtags = NewComputeManager("dynamicschedtag", "dynamicschedtags", - []string{"ID", "Name", "Description", - "Condition", "Schedtag", "Schedtag_Id", "Enabled"}, + []string{ + "ID", "Name", "Description", "Condition", "Schedtag", + "Schedtag_Id", "Resource_Type", "Enabled"}, []string{}) registerComputeV2(&Dynamicschedtags) diff --git a/pkg/mcclient/modules/mod_schedpolicies.go b/pkg/mcclient/modules/mod_schedpolicies.go index eda171e212..5fac8130ca 100644 --- a/pkg/mcclient/modules/mod_schedpolicies.go +++ b/pkg/mcclient/modules/mod_schedpolicies.go @@ -6,8 +6,10 @@ var ( func init() { Schedpolicies = NewComputeManager("schedpolicy", "schedpolicies", - []string{"ID", "Name", "Description", - "Condition", "Schedtag", "Schedtag_Id", "Strategy", "Enabled"}, + []string{ + "ID", "Name", "Description", "Condition", "Schedtag", + "Resource_Type", "Schedtag_Id", "Strategy", "Enabled", + }, []string{}) registerComputeV2(&Schedpolicies) diff --git a/pkg/mcclient/options/base.go b/pkg/mcclient/options/base.go index f6fdb6cabd..f943fe83ef 100644 --- a/pkg/mcclient/options/base.go +++ b/pkg/mcclient/options/base.go @@ -178,7 +178,7 @@ type BaseListOptions struct { JointFilter []string `help:"Filters with joint table col; joint_tbl.related_key(origin_key).filter_col.filter_cond(filters)"` FilterAny *bool `help:"If true, match if any of the filters matches; otherwise, match if all of the filters match"` Admin *bool `help:"Is an admin call?"` - Tenant string `help:"Tenant ID or Name"` + Tenant string `help:"Tenant ID or Name" alias:"project"` User string `help:"User ID or Name"` System *bool `help:"Show system resource"` PendingDelete *bool `help:"Show only pending deleted resource"` diff --git a/pkg/scheduler/algorithm/predicates/aggregate_predicate.go b/pkg/scheduler/algorithm/predicates/aggregate_predicate.go index 6c4b796fd0..ef9ed70947 100644 --- a/pkg/scheduler/algorithm/predicates/aggregate_predicate.go +++ b/pkg/scheduler/algorithm/predicates/aggregate_predicate.go @@ -69,9 +69,9 @@ type schedtagCandidateW struct { func (w schedtagCandidateW) GetDynamicSchedDesc() *jsonutils.JSONDict { ret := jsonutils.NewDict() hostSchedDesc := w.GetSchedDesc() - srvSchedDesc := jsonutils.Marshal(w.schedData) - ret.Add(hostSchedDesc, "host") - ret.Add(srvSchedDesc, "server") + srvSchedDesc := w.schedData.ToConditionInput() + ret.Add(hostSchedDesc, computemodels.HostManager.Keyword()) + ret.Add(srvSchedDesc, computemodels.GuestManager.Keyword()) return ret } diff --git a/pkg/scheduler/algorithm/predicates/disk_schedtag_predicate.go b/pkg/scheduler/algorithm/predicates/disk_schedtag_predicate.go index 0011c84d79..bf4ba6bf51 100644 --- a/pkg/scheduler/algorithm/predicates/disk_schedtag_predicate.go +++ b/pkg/scheduler/algorithm/predicates/disk_schedtag_predicate.go @@ -127,7 +127,12 @@ func (w schedtagStorageW) IndexKey() string { } func (w schedtagStorageW) GetDynamicSchedDesc() *jsonutils.JSONDict { - return nil + ret := jsonutils.NewDict() + storageSchedDesc := w.candidater.GetDynamicConditionInput() + diskSchedDesc := w.disk.JSON(w.disk) + ret.Add(storageSchedDesc, models.StorageManager.Keyword()) + ret.Add(diskSchedDesc, models.DiskManager.Keyword()) + return ret } func (w schedtagStorageW) GetSchedtags() []models.SSchedtag { diff --git a/pkg/scheduler/algorithm/predicates/schedtag_helper.go b/pkg/scheduler/algorithm/predicates/schedtag_helper.go index c394914073..ea19fee9cc 100644 --- a/pkg/scheduler/algorithm/predicates/schedtag_helper.go +++ b/pkg/scheduler/algorithm/predicates/schedtag_helper.go @@ -187,11 +187,11 @@ func (c *SchedtagChecker) Contains(objectTags []models.SSchedtag, tags []compute return true, nil } -func (p *SchedtagChecker) getDynamicSchedtags(schedDesc *jsonutils.JSONDict) ([]models.SSchedtag, error) { +func (p *SchedtagChecker) getDynamicSchedtags(resType string, schedDesc *jsonutils.JSONDict) ([]models.SSchedtag, error) { if schedDesc == nil { return []models.SSchedtag{}, nil } - dynamicTags := models.DynamicschedtagManager.GetAllEnabledDynamicSchedtags() + dynamicTags := models.DynamicschedtagManager.GetEnabledDynamicSchedtagsByResource(resType) tags := []models.SSchedtag{} for _, tag := range dynamicTags { @@ -233,7 +233,7 @@ func (c *SchedtagChecker) mergeSchedtags(candiate ISchedtagCandidate, staticTags func (c *SchedtagChecker) GetCandidateSchedtags(candidate ISchedtagCandidate) ([]models.SSchedtag, error) { staticTags := candidate.GetSchedtags() - dynamicTags, err := c.getDynamicSchedtags(candidate.GetDynamicSchedDesc()) + dynamicTags, err := c.getDynamicSchedtags(candidate.ResourceType(), candidate.GetDynamicSchedDesc()) if err != nil { return nil, err }