sched.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package api
  15. import (
  16. "net/http" //"yunion.io/x/jsonutils"
  17. "yunion.io/x/log"
  18. "yunion.io/x/pkg/errors"
  19. computeapi "yunion.io/x/onecloud/pkg/apis/compute"
  20. "yunion.io/x/onecloud/pkg/apis/identity"
  21. api "yunion.io/x/onecloud/pkg/apis/scheduler"
  22. "yunion.io/x/onecloud/pkg/appsrv"
  23. "yunion.io/x/onecloud/pkg/cloudcommon/cmdline"
  24. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  25. "yunion.io/x/onecloud/pkg/cloudcommon/policy"
  26. "yunion.io/x/onecloud/pkg/compute/models"
  27. "yunion.io/x/onecloud/pkg/httperrors"
  28. "yunion.io/x/onecloud/pkg/mcclient"
  29. "yunion.io/x/onecloud/pkg/mcclient/auth"
  30. o "yunion.io/x/onecloud/pkg/scheduler/options"
  31. )
  32. type SchedInfo struct {
  33. *api.ScheduleInput
  34. Tag string `json:"tag"`
  35. Type string `json:"type"`
  36. IsContainer bool `json:"is_container"`
  37. PreferCandidates []string `json:"candidates"`
  38. RequiredCandidates int `json:"required_candidates"`
  39. IgnoreFilters map[string]bool `json:"ignore_filters"`
  40. IsSuggestion bool `json:"suggestion"`
  41. ShowSuggestionDetails bool `json:"suggestion_details"`
  42. Raw string
  43. InstanceGroupsDetail map[string]*models.SGroup
  44. UserCred mcclient.TokenCredential
  45. }
  46. func FetchAuthToken(req *http.Request) (mcclient.TokenCredential, error) {
  47. tokenStr := req.Header.Get(identity.AUTH_TOKEN_HEADER)
  48. if tokenStr == "" {
  49. return nil, errors.Wrap(httperrors.ErrInvalidCredential, "missing token header")
  50. }
  51. token, err := auth.Verify(req.Context(), tokenStr)
  52. if err != nil {
  53. return nil, errors.Wrap(err, "Verify")
  54. }
  55. return token, nil
  56. }
  57. func FetchUserCred(req *http.Request) (mcclient.TokenCredential, error) {
  58. token, err := FetchAuthToken(req)
  59. if err != nil {
  60. return nil, errors.Wrap(err, "fetchAuthToken")
  61. }
  62. userCred := policy.FilterPolicyCredential(token)
  63. return userCred, nil
  64. }
  65. func FetchSchedInfo(req *http.Request) (*SchedInfo, error) {
  66. userCred, err := FetchUserCred(req)
  67. if err != nil {
  68. return nil, errors.Wrap(err, "fetch user cred")
  69. }
  70. body, err := appsrv.FetchJSON(req)
  71. if err != nil {
  72. return nil, err
  73. }
  74. input, err := cmdline.FetchScheduleInputByJSON(body)
  75. if err != nil {
  76. return nil, err
  77. }
  78. input = models.ApplySchedPolicies(input)
  79. data := NewSchedInfo(input)
  80. data.UserCred = userCred
  81. if len(data.Domain) == 0 {
  82. data.Domain = userCred.GetProjectDomainId()
  83. }
  84. if len(data.Project) == 0 {
  85. data.Project = userCred.GetProjectId()
  86. }
  87. domainId := data.Domain
  88. for _, net := range data.Networks {
  89. if net.Domain == "" {
  90. net.Domain = domainId
  91. }
  92. if net.Network != "" {
  93. netObj, err := models.NetworkManager.FetchByIdOrName(req.Context(), data.UserCred, net.Network)
  94. if err != nil {
  95. return nil, errors.Wrapf(err, "fetch network %s", net.Network)
  96. }
  97. net.Network = netObj.GetId()
  98. }
  99. }
  100. if data.InstanceGroupIds == nil || len(data.InstanceGroupIds) == 0 {
  101. return data, nil
  102. }
  103. // fill instance group detail
  104. groups := make([]models.SGroup, 0, 1)
  105. q := models.GroupManager.Query().In("id", data.InstanceGroupIds)
  106. err = db.FetchModelObjects(models.GroupManager, q, &groups)
  107. if err != nil {
  108. return nil, err
  109. }
  110. details := make(map[string]*models.SGroup)
  111. for i := range groups {
  112. if groups[i].Enabled.IsFalse() {
  113. continue
  114. }
  115. details[groups[i].Id] = &groups[i]
  116. }
  117. data.InstanceGroupsDetail = details
  118. if data.Count == 0 {
  119. log.Warningf("schedule info data count is 0, set to 1")
  120. data.Count = 1
  121. }
  122. return data, nil
  123. }
  124. func NewSchedInfo(input *api.ScheduleInput) *SchedInfo {
  125. data := new(SchedInfo)
  126. data.ScheduleInput = input
  127. data.RequiredCandidates = 1
  128. if data.Hypervisor == "" || data.Hypervisor == SchedTypeKvm {
  129. data.Hypervisor = HostHypervisorForKvm
  130. }
  131. preferCandidates := make([]string, 0)
  132. if data.PreferHost != "" {
  133. preferCandidates = append(preferCandidates, data.PreferHost)
  134. }
  135. if len(data.PreferRegion) > 0 && len(data.Provider) == 0 {
  136. regionObj, _ := models.CloudregionManager.FetchById(data.PreferRegion)
  137. if regionObj != nil {
  138. region := regionObj.(*models.SCloudregion)
  139. data.Provider = region.Provider
  140. }
  141. }
  142. if len(data.Provider) == 0 {
  143. data.Provider = computeapi.CLOUD_PROVIDER_ONECLOUD
  144. }
  145. if data.Backup {
  146. if data.PreferBackupHost != "" {
  147. preferCandidates = append(preferCandidates, data.PreferBackupHost)
  148. }
  149. data.RequiredCandidates += 1
  150. } else {
  151. // make sure prefer backup is null
  152. data.PreferBackupHost = ""
  153. }
  154. if data.ResourceType == "" {
  155. data.ResourceType = computeapi.HostResourceTypeShared
  156. }
  157. if len(data.BaremetalDiskConfigs) == 0 {
  158. defaultConfs := []*computeapi.BaremetalDiskConfig{&computeapi.BaremetalDefaultDiskConfig}
  159. data.BaremetalDiskConfigs = defaultConfs
  160. log.V(4).Warningf("No baremetal_disk_config info found in json, use default baremetal disk config: %#v", defaultConfs)
  161. }
  162. data.PreferCandidates = preferCandidates
  163. data.reviseData()
  164. return data
  165. }
  166. func (data *SchedInfo) reviseData() {
  167. for _, d := range data.Disks {
  168. if len(d.Backend) == 0 {
  169. d.Backend = computeapi.STORAGE_LOCAL
  170. }
  171. }
  172. input := data.ScheduleInput
  173. if input.Count <= 0 {
  174. data.Count = 1
  175. }
  176. ignoreFilters := make(map[string]bool, len(input.IgnoreFilters))
  177. for _, filter := range input.IgnoreFilters {
  178. ignoreFilters[filter] = true
  179. }
  180. data.IgnoreFilters = ignoreFilters
  181. if data.SuggestionLimit == 0 {
  182. data.SuggestionLimit = int64(o.Options.SchedulerTestLimit)
  183. }
  184. data.Raw = input.JSON(input).String()
  185. }
  186. func (d *SchedInfo) GetCandidateHostTypes() []string {
  187. switch d.Hypervisor {
  188. case computeapi.HYPERVISOR_POD:
  189. return []string{computeapi.HOST_TYPE_CONTAINER, HostHypervisorForKvm}
  190. default:
  191. return []string{d.Hypervisor}
  192. }
  193. }
  194. func (d *SchedInfo) getDiskSize(backend string) int64 {
  195. total := int64(0)
  196. for _, disk := range d.Disks {
  197. if disk.Backend == backend {
  198. total += int64(disk.SizeMb)
  199. }
  200. }
  201. return total
  202. }
  203. func (d *SchedInfo) AllDiskBackendSize() map[string]int64 {
  204. backendSizeMap := make(map[string]int64, len(d.Disks))
  205. for _, disk := range d.Disks {
  206. newSize := int64(disk.SizeMb)
  207. if size, ok := backendSizeMap[disk.Backend]; ok {
  208. newSize += size
  209. }
  210. backendSizeMap[disk.Backend] = newSize
  211. }
  212. return backendSizeMap
  213. }
  214. type SchedResultItem interface{}
  215. type SchedResult struct {
  216. Items []SchedResultItem `json:"scheduler"`
  217. }
  218. type SchedSuccItem struct {
  219. Candidate interface{} `json:"candidate"`
  220. }
  221. type SchedErrItem struct {
  222. Error string `json:"error"`
  223. }
  224. type SchedNormalResultItem struct {
  225. ID string `json:"id"`
  226. Name string `json:"name"`
  227. Data map[string]interface{} `json:"data"`
  228. }
  229. type SchedBackupResultItem struct {
  230. MasterID string `json:"master_id"`
  231. SlaveID string `json:"slave_id"`
  232. }
  233. type SchedTestResult struct {
  234. Data interface{} `json:"data"`
  235. Total int64 `json:"total"`
  236. Limit int64 `json:"limit"`
  237. Offset int64 `json:"offset"`
  238. }
  239. type ForecastFilter struct {
  240. Filter string `json:"filter"`
  241. Messages []string `json:"messages"`
  242. Count int64 `json:"count"`
  243. }
  244. type FilteredCandidate struct {
  245. ID string `json:"id"`
  246. Name string `json:"name"`
  247. FilterName string `json:"filter_name"`
  248. Reasons []string `json:"reasons"`
  249. }
  250. type SchedForecastResult struct {
  251. CanCreate bool `json:"can_create"`
  252. Candidates []*api.CandidateResource `json:"candidates"`
  253. ReqCount int64 `json:"req_count"`
  254. AllowCount int64 `json:"allow_count"`
  255. NotAllowReasons []string `json:"not_allow_reasons"`
  256. FilteredCandidates []FilteredCandidate `json:"filtered_candidates"`
  257. }