virtualization.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  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 guestdrivers
  15. import (
  16. "context"
  17. "fmt"
  18. "regexp"
  19. "yunion.io/x/jsonutils"
  20. "yunion.io/x/pkg/errors"
  21. "yunion.io/x/pkg/util/netutils"
  22. "yunion.io/x/pkg/utils"
  23. api "yunion.io/x/onecloud/pkg/apis/compute"
  24. "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
  25. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  26. "yunion.io/x/onecloud/pkg/compute/models"
  27. "yunion.io/x/onecloud/pkg/httperrors"
  28. "yunion.io/x/onecloud/pkg/mcclient"
  29. )
  30. type SVirtualizedGuestDriver struct {
  31. SBaseGuestDriver
  32. }
  33. func (d *SVirtualizedGuestDriver) DoScheduleSKUFilter() bool {
  34. return false
  35. }
  36. func (self *SVirtualizedGuestDriver) GetMaxVCpuCount() int {
  37. return 128
  38. }
  39. func (self *SVirtualizedGuestDriver) GetMaxVMemSizeGB() int {
  40. return 512
  41. }
  42. func (self *SVirtualizedGuestDriver) PrepareDiskRaidConfig(userCred mcclient.TokenCredential, host *models.SHost, params []*api.BaremetalDiskConfig, disks []*api.DiskConfig) ([]*api.DiskConfig, error) {
  43. // do nothing
  44. return nil, nil
  45. }
  46. func (self *SVirtualizedGuestDriver) GetNamedNetworkConfiguration(guest *models.SGuest, ctx context.Context, userCred mcclient.TokenCredential, host *models.SHost, netConfig *api.NetworkConfig) (*models.SNetwork, []models.SNicConfig, api.IPAllocationDirection, bool, error) {
  47. net, err := host.GetNetworkWithId(netConfig.Network, netConfig.Reserved)
  48. if err != nil {
  49. return nil, nil, "", false, errors.Wrapf(err, "get network with id %q, reserverd %v", netConfig.Network, netConfig.Reserved)
  50. }
  51. nicConfs := []models.SNicConfig{
  52. {
  53. Mac: netConfig.Mac,
  54. Index: -1,
  55. Ifname: netConfig.Ifname,
  56. },
  57. }
  58. if netConfig.RequireTeaming || netConfig.TryTeaming {
  59. nicConfs = append(nicConfs, models.SNicConfig{
  60. Mac: "",
  61. Index: -1,
  62. Ifname: "",
  63. })
  64. }
  65. // reUse := false
  66. // if len(netConfig.Address) > 0 && !options.Options.EnablePreAllocateIpAddr && !utils.IsInStringArray(host.GetProviderName(), []string{api.CLOUD_PROVIDER_ONECLOUD, api.CLOUD_PROVIDER_VMWARE, api.CLOUD_PROVIDER_CLOUDPODS}) {
  67. // reUse = true
  68. // }
  69. return net, nicConfs, api.IPAllocationStepdown, false, nil
  70. }
  71. func (self *SVirtualizedGuestDriver) GetRandomNetworkTypes() []api.TNetworkType {
  72. return []api.TNetworkType{api.NETWORK_TYPE_GUEST}
  73. }
  74. func (self *SVirtualizedGuestDriver) wireAvaiableForGuest(guest *models.SGuest, wire *models.SWire) (bool, error) {
  75. if guest.BackupHostId == "" {
  76. return true, nil
  77. } else {
  78. backupHost := models.HostManager.FetchHostById(guest.BackupHostId)
  79. attached := backupHost.IsAttach2Wire(wire.Id)
  80. return attached, nil
  81. }
  82. }
  83. func (self *SVirtualizedGuestDriver) Attach2RandomNetwork(guest *models.SGuest, ctx context.Context, userCred mcclient.TokenCredential, host *models.SHost, netConfig *api.NetworkConfig, pendingUsage quotas.IQuota) ([]models.SGuestnetwork, error) {
  84. var wirePattern *regexp.Regexp
  85. if len(netConfig.Wire) > 0 {
  86. wirePattern = regexp.MustCompile(netConfig.Wire)
  87. }
  88. hostNetifs := host.GetHostNetInterfaces()
  89. netsAvaiable := make([]models.SNetwork, 0)
  90. driver, err := guest.GetDriver()
  91. if err != nil {
  92. return nil, err
  93. }
  94. netTypes := driver.GetRandomNetworkTypes()
  95. if len(netConfig.NetType) > 0 {
  96. netTypes = []api.TNetworkType{api.TNetworkType(netConfig.NetType)}
  97. }
  98. var sriovWires []string
  99. if netConfig.SriovDevice != nil {
  100. if netConfig.SriovDevice.Id != "" {
  101. idev, err := models.IsolatedDeviceManager.FetchById(netConfig.SriovDevice.Id)
  102. if err != nil {
  103. return nil, errors.Wrap(err, "fetch isolated device")
  104. }
  105. dev, _ := idev.(*models.SIsolatedDevice)
  106. sriovWires = []string{dev.WireId}
  107. } else {
  108. wires, err := models.IsolatedDeviceManager.FindUnusedNicWiresByModel(netConfig.SriovDevice.Model)
  109. if err != nil {
  110. return nil, errors.Wrap(err, "FindUnusedNicWiresByModel")
  111. }
  112. sriovWires = wires
  113. }
  114. }
  115. for i := 0; i < len(hostNetifs); i += 1 {
  116. hostNetif := hostNetifs[i]
  117. wire := hostNetif.GetWire()
  118. if wire == nil {
  119. continue
  120. }
  121. if ok, err := self.wireAvaiableForGuest(guest, wire); err != nil {
  122. return nil, err
  123. } else if !ok {
  124. continue
  125. }
  126. if netConfig.SriovDevice != nil && !utils.IsInStringArray(wire.Id, sriovWires) {
  127. continue
  128. }
  129. // !!
  130. if wirePattern != nil && !wirePattern.MatchString(wire.Id) && !wirePattern.MatchString(wire.Name) {
  131. continue
  132. }
  133. var net *models.SNetwork
  134. if netConfig.Private {
  135. net, _ = wire.GetCandidatePrivateNetwork(ctx, userCred, userCred, models.NetworkManager.AllowScope(userCred), netConfig.Exit, netTypes)
  136. } else {
  137. net, _ = wire.GetCandidateAutoAllocNetwork(ctx, userCred, userCred, models.NetworkManager.AllowScope(userCred), netConfig.Exit, netTypes)
  138. }
  139. if net != nil {
  140. netsAvaiable = append(netsAvaiable, *net)
  141. }
  142. }
  143. if len(netsAvaiable) == 0 {
  144. return nil, fmt.Errorf("No appropriate host virtual network...")
  145. }
  146. if len(netConfig.Address) > 0 || len(netConfig.Address6) > 0 {
  147. addr, _ := netutils.NewIPV4Addr(netConfig.Address)
  148. addr6, _ := netutils.NewIPV6Addr(netConfig.Address6)
  149. netsAvaiableForAddr := make([]models.SNetwork, 0)
  150. for i := range netsAvaiable {
  151. if (len(netConfig.Address) == 0 || netsAvaiable[i].IsAddressInRange(addr)) && (len(netConfig.Address6) == 0 || netsAvaiable[i].IsAddress6InRange(addr6)) {
  152. netsAvaiableForAddr = append(netsAvaiableForAddr, netsAvaiable[i])
  153. }
  154. }
  155. if len(netsAvaiableForAddr) == 0 {
  156. if netConfig.RequireDesignatedIP {
  157. return nil, fmt.Errorf("No virtual network for IP %s", netConfig.Address)
  158. }
  159. } else {
  160. netsAvaiable = netsAvaiableForAddr
  161. }
  162. }
  163. selNet := models.ChooseCandidateNetworks(netsAvaiable, netConfig.Exit, netTypes)
  164. if selNet == nil {
  165. return nil, fmt.Errorf("Not enough address in virtual network")
  166. }
  167. nicConfs := make([]models.SNicConfig, 1)
  168. nicConfs[0] = models.SNicConfig{
  169. Mac: netConfig.Mac,
  170. Index: -1,
  171. Ifname: netConfig.Ifname,
  172. }
  173. if netConfig.RequireTeaming || netConfig.TryTeaming {
  174. nicConf := models.SNicConfig{
  175. Mac: "",
  176. Index: -1,
  177. Ifname: "",
  178. }
  179. nicConfs = append(nicConfs, nicConf)
  180. }
  181. gn, err := guest.Attach2Network(ctx, userCred, models.Attach2NetworkArgs{
  182. Network: selNet,
  183. PendingUsage: pendingUsage,
  184. IpAddr: netConfig.Address,
  185. Ip6Addr: netConfig.Address6,
  186. NicDriver: netConfig.Driver,
  187. BwLimit: netConfig.BwLimit,
  188. Virtual: netConfig.Vip,
  189. TryReserved: netConfig.Reserved,
  190. AllocDir: api.IPAllocationDefault,
  191. RequireDesignatedIP: netConfig.RequireDesignatedIP,
  192. RequireIPv6: netConfig.RequireIPv6,
  193. StrictIPv6: netConfig.StrictIPv6,
  194. NicConfs: nicConfs,
  195. IsDefault: netConfig.IsDefault,
  196. BillingType: netConfig.BillingType,
  197. ChargeType: netConfig.ChargeType,
  198. })
  199. return gn, err
  200. }
  201. func (self *SVirtualizedGuestDriver) GetStorageTypes() []string {
  202. return nil
  203. }
  204. func (self *SVirtualizedGuestDriver) ChooseHostStorage(host *models.SHost, guest *models.SGuest, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) {
  205. if len(storageIds) == 0 {
  206. return host.GetLeastUsedStorage(diskConfig.Backend), nil
  207. }
  208. ss, err := models.StorageManager.FetchStorageByIds(storageIds)
  209. if err != nil {
  210. return nil, errors.Wrapf(err, "fetch storages by ids: %v", storageIds)
  211. }
  212. var candidates []models.SStorage
  213. if len(diskConfig.Medium) > 0 {
  214. // try to find mediumType matched storage
  215. for i := range ss {
  216. if ss[i].MediumType == diskConfig.Medium {
  217. candidates = append(candidates, ss[i])
  218. }
  219. }
  220. if len(candidates) == 0 {
  221. candidates = ss
  222. }
  223. } else {
  224. candidates = ss
  225. }
  226. return models.ChooseLeastUsedStorage(candidates, ""), nil
  227. }
  228. func (self *SVirtualizedGuestDriver) RequestGuestCreateInsertIso(ctx context.Context, imageId string, bootIndex *int8, task taskman.ITask, guest *models.SGuest) error {
  229. return guest.StartInsertIsoTask(ctx, 0, imageId, true, bootIndex, guest.HostId, task.GetUserCred(), task.GetTaskId())
  230. }
  231. func (self *SVirtualizedGuestDriver) StartGuestStopTask(guest *models.SGuest, ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
  232. taskName := "GuestStopTask"
  233. if guest.BackupHostId != "" {
  234. taskName = "HAGuestStopTask"
  235. }
  236. task, err := taskman.TaskManager.NewTask(ctx, taskName, guest, userCred, params, parentTaskId, "", nil)
  237. if err != nil {
  238. return err
  239. }
  240. return task.ScheduleRun(nil)
  241. }
  242. func (self *SVirtualizedGuestDriver) StartGuestResetTask(guest *models.SGuest, ctx context.Context, userCred mcclient.TokenCredential, isHard bool, parentTaskId string) error {
  243. var taskName = "GuestSoftResetTask"
  244. if isHard {
  245. taskName = "GuestHardResetTask"
  246. }
  247. task, err := taskman.TaskManager.NewTask(ctx, taskName, guest, userCred, nil, parentTaskId, "", nil)
  248. if err != nil {
  249. return err
  250. }
  251. task.ScheduleRun(nil)
  252. return nil
  253. }
  254. func (self *SVirtualizedGuestDriver) RequestDeleteDetachedDisk(ctx context.Context, disk *models.SDisk, task taskman.ITask, isPurge bool) error {
  255. return disk.StartDiskDeleteTask(ctx, task.GetUserCred(), task.GetTaskId(), isPurge,
  256. jsonutils.QueryBoolean(task.GetParams(), "override_pending_delete", false), false)
  257. }
  258. func (self *SVirtualizedGuestDriver) StartGuestSyncstatusTask(guest *models.SGuest, ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
  259. return models.StartResourceSyncStatusTask(ctx, userCred, guest, "GuestSyncstatusTask", parentTaskId)
  260. }
  261. func (self *SVirtualizedGuestDriver) RequestStopGuestForDelete(ctx context.Context, guest *models.SGuest,
  262. host *models.SHost, task taskman.ITask) error {
  263. if host == nil {
  264. host, _ = guest.GetHost()
  265. }
  266. if host != nil && host.GetEnabled() && host.HostStatus == api.HOST_ONLINE {
  267. return guest.StartGuestStopTask(ctx, task.GetUserCred(), 0, true, false, task.GetTaskId())
  268. }
  269. if host != nil && !jsonutils.QueryBoolean(task.GetParams(), "purge", false) {
  270. return fmt.Errorf("fail to contact host")
  271. }
  272. task.ScheduleRun(nil)
  273. return nil
  274. }
  275. func (self *SVirtualizedGuestDriver) ValidateCreateDataOnHost(ctx context.Context, userCred mcclient.TokenCredential, bmName string, host *models.SHost, input *api.ServerCreateInput) (*api.ServerCreateInput, error) {
  276. if host.HostStatus != api.HOST_ONLINE {
  277. return nil, httperrors.NewInvalidStatusError("Host %s is not online", bmName)
  278. }
  279. input.PreferHost = host.Id
  280. if host.IsPrepaidRecycle() {
  281. input.VmemSize = host.MemSize
  282. input.VcpuCount = int(host.CpuCount)
  283. cnt, err := host.GetGuestCount()
  284. if err != nil {
  285. return nil, httperrors.NewInternalServerError("GetGuestCount fail %s", err)
  286. }
  287. if cnt >= 1 {
  288. return nil, httperrors.NewInsufficientResourceError("host has been occupied")
  289. }
  290. }
  291. return input, nil
  292. }
  293. func (self *SVirtualizedGuestDriver) PerformStart(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, data *jsonutils.JSONDict, parentTaskId string) error {
  294. return guest.StartGueststartTask(ctx, userCred, data, parentTaskId)
  295. }
  296. func (self *SVirtualizedGuestDriver) CheckDiskTemplateOnStorage(ctx context.Context, userCred mcclient.TokenCredential, imageId string, format string, storageId string, task taskman.ITask) error {
  297. storage := models.StorageManager.FetchStorageById(storageId)
  298. if storage == nil {
  299. return fmt.Errorf("No such storage?? %s", storageId)
  300. }
  301. cache := storage.GetStoragecache()
  302. if cache == nil {
  303. return fmt.Errorf("Cache is missing from storage")
  304. }
  305. input := api.CacheImageInput{
  306. ImageId: imageId,
  307. Format: format,
  308. ParentTaskId: task.GetTaskId(),
  309. }
  310. return cache.StartImageCacheTask(ctx, userCred, input)
  311. }
  312. func (self *SVirtualizedGuestDriver) CanKeepDetachDisk() bool {
  313. return true
  314. }
  315. func (self *SVirtualizedGuestDriver) StartGuestDetachdiskTask(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error {
  316. task, err := taskman.TaskManager.NewTask(ctx, "GuestDetachDiskTask", guest, userCred, params, parentTaskId, "", nil)
  317. if err != nil {
  318. return err
  319. }
  320. task.ScheduleRun(nil)
  321. return nil
  322. }
  323. func (self *SVirtualizedGuestDriver) StartGuestAttachDiskTask(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error {
  324. task, err := taskman.TaskManager.NewTask(ctx, "GuestAttachDiskTask", guest, userCred, params, parentTaskId, "", nil)
  325. if err != nil {
  326. return err
  327. }
  328. task.ScheduleRun(nil)
  329. return nil
  330. }
  331. func (self *SVirtualizedGuestDriver) StartSuspendTask(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error {
  332. task, err := taskman.TaskManager.NewTask(ctx, "GuestSuspendTask", guest, userCred, params, parentTaskId, "", nil)
  333. if err != nil {
  334. return err
  335. }
  336. task.ScheduleRun(nil)
  337. return nil
  338. }
  339. func (self *SVirtualizedGuestDriver) StartResumeTask(ctx context.Context, userCred mcclient.TokenCredential,
  340. guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error {
  341. task, err := taskman.TaskManager.NewTask(ctx, "GuestResumeTask", guest, userCred, params, parentTaskId, "", nil)
  342. if err != nil {
  343. return err
  344. }
  345. task.ScheduleRun(nil)
  346. return nil
  347. }
  348. func (self *SVirtualizedGuestDriver) StartGuestSaveImage(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error {
  349. guest.SetStatus(ctx, userCred, api.VM_START_SAVE_DISK, "")
  350. if task, err := taskman.TaskManager.NewTask(ctx, "GuestSaveImageTask", guest, userCred, params, parentTaskId, "", nil); err != nil {
  351. return err
  352. } else {
  353. task.ScheduleRun(nil)
  354. }
  355. return nil
  356. }
  357. func (self *SVirtualizedGuestDriver) StartGuestSaveGuestImage(ctx context.Context, userCred mcclient.TokenCredential,
  358. guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error {
  359. guest.SetStatus(ctx, userCred, api.VM_START_SAVE_DISK, "")
  360. if task, err := taskman.TaskManager.NewTask(ctx, "GuestSaveGuestImageTask", guest, userCred, params, parentTaskId,
  361. "", nil); err != nil {
  362. return err
  363. } else {
  364. task.ScheduleRun(nil)
  365. }
  366. return nil
  367. }