You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

scheduler.go 5.6 kB

11 months ago
11 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
11 months ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*
  2. Copyright (c) [2023] [pcm]
  3. [pcm-coordinator] is licensed under Mulan PSL v2.
  4. You can use this software according to the terms and conditions of the Mulan PSL v2.
  5. You may obtain a copy of Mulan PSL v2 at:
  6. http://license.coscl.org.cn/MulanPSL2
  7. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
  8. EITHER EXPaRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
  9. MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
  10. See the Mulan PSL v2 for more details.
  11. */
  12. package scheduler
  13. import (
  14. "encoding/json"
  15. "github.com/pkg/errors"
  16. "github.com/zeromicro/go-zero/core/logx"
  17. "gitlink.org.cn/JointCloud/pcm-coordinator/internal/scheduler/common"
  18. "gitlink.org.cn/JointCloud/pcm-coordinator/internal/scheduler/database"
  19. "gitlink.org.cn/JointCloud/pcm-coordinator/internal/scheduler/service"
  20. "gitlink.org.cn/JointCloud/pcm-coordinator/internal/scheduler/strategy"
  21. "gitlink.org.cn/JointCloud/pcm-coordinator/pkg/response"
  22. "gorm.io/gorm"
  23. "sigs.k8s.io/yaml"
  24. "strings"
  25. "sync"
  26. )
  27. const (
  28. JOINT_CLOUD_MODE = iota + 1
  29. STORAGE_SCHEDULE_MODE
  30. )
  31. type Scheduler struct {
  32. task *response.TaskInfo
  33. participantIds []int64
  34. subSchedule SubSchedule
  35. dbEngin *gorm.DB
  36. result []string //pID:子任务yamlstring 键值对
  37. AiStorages *database.AiStorage
  38. AiService *service.AiService
  39. mu sync.RWMutex
  40. }
  41. type SubSchedule interface {
  42. GetNewStructForDb(task *response.TaskInfo, resource string, participantId int64) (interface{}, error)
  43. PickOptimalStrategy() (strategy.Strategy, error)
  44. AssignTask(clusters []*strategy.AssignedCluster, mode int) (interface{}, error)
  45. }
  46. func NewScheduler(subSchedule SubSchedule, val string, dbEngin *gorm.DB) (*Scheduler, error) {
  47. var task *response.TaskInfo
  48. err := json.Unmarshal([]byte(val), &task)
  49. if err != nil {
  50. return nil, errors.New("create scheduler failed : " + err.Error())
  51. }
  52. return &Scheduler{task: task, subSchedule: subSchedule, dbEngin: dbEngin}, nil
  53. }
  54. func NewSchdlr(aiService *service.AiService, storages *database.AiStorage) *Scheduler {
  55. return &Scheduler{AiService: aiService, AiStorages: storages}
  56. }
  57. func (s *Scheduler) SpecifyClusters() {
  58. // 如果已指定集群名,通过数据库查询后返回p端ip列表
  59. if len(s.task.Clusters) != 0 {
  60. s.dbEngin.Raw("select id from sc_participant_phy_info where `name` in (?)", s.task.Clusters).Scan(&s.participantIds)
  61. return
  62. }
  63. }
  64. func (s *Scheduler) SpecifyNsID() {
  65. // 未指定集群名,只指定nsID
  66. if len(s.task.Clusters) == 0 {
  67. if len(s.task.NsID) != 0 {
  68. var clusters string
  69. s.dbEngin.Raw("select clusters from sc_tenant_info where `tenant_name` = ?", s.task.NsID).Scan(&clusters)
  70. clusterArr := strings.Split(clusters, ",")
  71. s.dbEngin.Raw("select id from sc_participant_phy_info where `name` in (?)", clusterArr).Scan(&s.participantIds)
  72. }
  73. } else {
  74. return
  75. }
  76. }
  77. func (s *Scheduler) MatchLabels() {
  78. var ids []int64
  79. count := 0
  80. // 集群和nsID都未指定,则通过标签匹配
  81. if len(s.task.Clusters) == 0 && len(s.task.NsID) == 0 {
  82. //如果集群列表或nsID均未指定
  83. for key := range s.task.MatchLabels {
  84. var participantIds []int64
  85. s.dbEngin.Raw("select participant_id from sc_participant_label_info where `key` = ? and value = ?", key, s.task.MatchLabels[key]).Scan(&participantIds)
  86. if count == 0 {
  87. ids = participantIds
  88. }
  89. ids = common.Intersect(ids, participantIds)
  90. count++
  91. }
  92. s.participantIds = ids
  93. } else {
  94. return
  95. }
  96. }
  97. // TempAssign todo 屏蔽原调度算法
  98. func (s *Scheduler) TempAssign() error {
  99. //需要判断task中的资源类型,针对metadata中的多个kind做不同处理
  100. //输入副本数和集群列表,最终结果输出为pID对应副本数量列表,针对多个kind需要做拆分和重新拼接组合
  101. var meData []string
  102. for _, yamlString := range s.task.Metadata {
  103. var data map[string]interface{}
  104. err := yaml.Unmarshal([]byte(yamlString), &data)
  105. if err != nil {
  106. }
  107. jsonData, err := json.Marshal(data)
  108. if err != nil {
  109. }
  110. meData = append(meData, string(jsonData))
  111. }
  112. s.task.Metadata = meData
  113. return nil
  114. }
  115. func (s *Scheduler) AssignAndSchedule(ss SubSchedule, mode int, assignedClusters []*strategy.AssignedCluster) (interface{}, error) {
  116. var result interface{}
  117. switch mode {
  118. case JOINT_CLOUD_MODE:
  119. //choose strategy
  120. strategy, err := ss.PickOptimalStrategy()
  121. if err != nil {
  122. return nil, err
  123. }
  124. //schedule
  125. clusters, err := strategy.Schedule()
  126. if err != nil {
  127. return nil, err
  128. }
  129. //assign tasks to clusters
  130. resp, err := ss.AssignTask(clusters, mode)
  131. if err != nil {
  132. return nil, err
  133. }
  134. result = resp
  135. case STORAGE_SCHEDULE_MODE:
  136. //assign tasks to clusters
  137. resp, err := ss.AssignTask(assignedClusters, mode)
  138. if err != nil {
  139. return nil, err
  140. }
  141. result = resp
  142. }
  143. return result, nil
  144. }
  145. func (s *Scheduler) SaveToDb() error {
  146. for _, participantId := range s.participantIds {
  147. for _, resource := range s.task.Metadata {
  148. structForDb, err := s.subSchedule.GetNewStructForDb(s.task, resource, participantId)
  149. if err != nil {
  150. return err
  151. }
  152. tx := s.dbEngin.Create(structForDb)
  153. if tx.Error != nil {
  154. logx.Error(tx.Error)
  155. return tx.Error
  156. }
  157. }
  158. }
  159. return nil
  160. }
  161. func (s *Scheduler) CreateTask(taskName string, synergyCode int64, strategyName string, yaml string) (int64, error) {
  162. strategyCode, err := s.AiStorages.GetStrategyCode(strategyName)
  163. if err != nil {
  164. return 0, err
  165. }
  166. id, err := s.AiStorages.SaveTask(taskName, strategyCode, synergyCode, "10", yaml)
  167. if err != nil {
  168. return 0, err
  169. }
  170. return id, nil
  171. }

PCM is positioned as Software stack over Cloud, aiming to build the standards and ecology of heterogeneous cloud collaboration for JCC in a non intrusive and autonomous peer-to-peer manner.