cnware.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  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. "sort"
  19. "yunion.io/x/cloudmux/pkg/cloudprovider"
  20. "yunion.io/x/log"
  21. "yunion.io/x/pkg/errors"
  22. "yunion.io/x/pkg/util/rbacscope"
  23. "yunion.io/x/pkg/utils"
  24. api "yunion.io/x/onecloud/pkg/apis/compute"
  25. "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
  26. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  27. "yunion.io/x/onecloud/pkg/compute/models"
  28. "yunion.io/x/onecloud/pkg/compute/options"
  29. "yunion.io/x/onecloud/pkg/httperrors"
  30. "yunion.io/x/onecloud/pkg/mcclient"
  31. )
  32. type SCNwareGuestDriver struct {
  33. SManagedVirtualizedGuestDriver
  34. }
  35. func init() {
  36. driver := SCNwareGuestDriver{}
  37. models.RegisterGuestDriver(&driver)
  38. }
  39. func (self *SCNwareGuestDriver) DoScheduleCPUFilter() bool { return true }
  40. func (self *SCNwareGuestDriver) DoScheduleMemoryFilter() bool { return true }
  41. func (self *SCNwareGuestDriver) DoScheduleSKUFilter() bool { return false }
  42. func (self *SCNwareGuestDriver) DoScheduleStorageFilter() bool { return true }
  43. func (self *SCNwareGuestDriver) GetHypervisor() string {
  44. return api.HYPERVISOR_CNWARE
  45. }
  46. func (self *SCNwareGuestDriver) GetProvider() string {
  47. return api.CLOUD_PROVIDER_CNWARE
  48. }
  49. func (self *SCNwareGuestDriver) GetComputeQuotaKeys(scope rbacscope.TRbacScope, ownerId mcclient.IIdentityProvider, brand string) models.SComputeResourceKeys {
  50. keys := models.SComputeResourceKeys{}
  51. keys.SBaseProjectQuotaKeys = quotas.OwnerIdProjectQuotaKeys(scope, ownerId)
  52. keys.CloudEnv = api.CLOUD_ENV_PRIVATE_CLOUD
  53. keys.Provider = api.CLOUD_PROVIDER_CNWARE
  54. keys.Brand = brand
  55. keys.Hypervisor = api.HYPERVISOR_CNWARE
  56. return keys
  57. }
  58. func (self *SCNwareGuestDriver) GetDefaultSysDiskBackend() string {
  59. return api.STORAGE_CNWARE_LOCAL
  60. }
  61. func (self *SCNwareGuestDriver) GetMinimalSysDiskSizeGb() int {
  62. return 10
  63. }
  64. func (self *SCNwareGuestDriver) GetStorageTypes() []string {
  65. return []string{
  66. api.STORAGE_CNWARE_FCSAN,
  67. api.STORAGE_CNWARE_IPSAN,
  68. api.STORAGE_CNWARE_NAS,
  69. api.STORAGE_CNWARE_CEPH,
  70. api.STORAGE_CNWARE_LOCAL,
  71. api.STORAGE_CNWARE_NVME,
  72. }
  73. }
  74. func (self *SCNwareGuestDriver) GetMaxSecurityGroupCount() int {
  75. return 0
  76. }
  77. func (self *SCNwareGuestDriver) ChooseHostStorage(host *models.SHost, guest *models.SGuest, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) {
  78. switch {
  79. case !options.Options.LockStorageFromCachedimage:
  80. return self.SVirtualizedGuestDriver.ChooseHostStorage(host, guest, diskConfig, storageIds)
  81. case len(diskConfig.ImageId) > 0:
  82. var (
  83. image *cloudprovider.SImage
  84. err error
  85. )
  86. obj, err := models.CachedimageManager.FetchById(diskConfig.ImageId)
  87. if err != nil {
  88. return nil, errors.Wrapf(err, "unable to fetch cachedimage %s", diskConfig.ImageId)
  89. }
  90. cachedimage := obj.(*models.SCachedimage)
  91. if len(cachedimage.ExternalId) > 0 || cloudprovider.TImageType(cachedimage.ImageType) != cloudprovider.ImageTypeSystem {
  92. return self.SVirtualizedGuestDriver.ChooseHostStorage(host, guest, diskConfig, storageIds)
  93. }
  94. storages, err := cachedimage.GetStorages()
  95. if err != nil {
  96. return nil, errors.Wrapf(err, "unable to GetStorages of cachedimage %s", diskConfig.ImageId)
  97. }
  98. if len(storages) == 0 {
  99. log.Warningf("there no storage associated with cachedimage %q", image.Id)
  100. return self.SVirtualizedGuestDriver.ChooseHostStorage(host, guest, diskConfig, storageIds)
  101. }
  102. if len(storages) > 1 {
  103. log.Warningf("there are multiple storageCache associated with caheimage %q", image.Id)
  104. }
  105. wantStorageIds := make([]string, len(storages))
  106. for i := range wantStorageIds {
  107. wantStorageIds[i] = storages[i].GetId()
  108. }
  109. for i := range wantStorageIds {
  110. if utils.IsInStringArray(wantStorageIds[i], storageIds) {
  111. log.Infof("use storage %q in where cachedimage %q", wantStorageIds[i], image.Id)
  112. return &storages[i], nil
  113. }
  114. }
  115. return self.SVirtualizedGuestDriver.ChooseHostStorage(host, guest, diskConfig, storageIds)
  116. default:
  117. ispId := guest.GetMetadata(context.Background(), "__base_instance_snapshot_id", nil)
  118. if len(ispId) == 0 {
  119. return self.SVirtualizedGuestDriver.ChooseHostStorage(host, guest, diskConfig, storageIds)
  120. }
  121. obj, err := models.InstanceSnapshotManager.FetchById(ispId)
  122. if err != nil {
  123. return nil, errors.Wrapf(err, "unable to fetch InstanceSnapshot %q", ispId)
  124. }
  125. isp := obj.(*models.SInstanceSnapshot)
  126. ispGuest, err := isp.GetGuest()
  127. if err != nil {
  128. return nil, errors.Wrapf(err, "unable to fetch Guest of InstanceSnapshot %q", ispId)
  129. }
  130. storages, err := ispGuest.GetStorages()
  131. if err != nil {
  132. return nil, errors.Wrapf(err, "GetStorages")
  133. }
  134. if len(storages) == 0 {
  135. return self.SVirtualizedGuestDriver.ChooseHostStorage(host, guest, diskConfig, storageIds)
  136. }
  137. if utils.IsInStringArray(storages[0].GetId(), storageIds) {
  138. return &storages[0], nil
  139. }
  140. return self.SVirtualizedGuestDriver.ChooseHostStorage(host, guest, diskConfig, storageIds)
  141. }
  142. }
  143. func (self *SCNwareGuestDriver) GetDetachDiskStatus() ([]string, error) {
  144. return []string{api.VM_READY, api.VM_RUNNING}, nil
  145. }
  146. func (self *SCNwareGuestDriver) GetAttachDiskStatus() ([]string, error) {
  147. return []string{api.VM_READY, api.VM_RUNNING}, nil
  148. }
  149. func (self *SCNwareGuestDriver) GetRebuildRootStatus() ([]string, error) {
  150. return []string{api.VM_READY}, nil
  151. }
  152. func (self *SCNwareGuestDriver) GetChangeConfigStatus(guest *models.SGuest) ([]string, error) {
  153. return []string{api.VM_READY}, nil
  154. }
  155. func (self *SCNwareGuestDriver) GetDeployStatus() ([]string, error) {
  156. return []string{api.VM_RUNNING}, nil
  157. }
  158. func (self *SCNwareGuestDriver) IsNeedRestartForResetLoginInfo() bool {
  159. return false
  160. }
  161. func (self *SCNwareGuestDriver) ValidateResizeDisk(guest *models.SGuest, disk *models.SDisk, storage *models.SStorage) error {
  162. if !utils.IsInStringArray(guest.Status, []string{api.VM_READY, api.VM_RUNNING}) {
  163. return fmt.Errorf("Cannot resize disk when guest in status %s", guest.Status)
  164. }
  165. return nil
  166. }
  167. func (self *SCNwareGuestDriver) ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, input api.ServerCreateEipInput) error {
  168. return httperrors.NewInputParameterError("%s not support create eip, it only support bind eip", self.GetHypervisor())
  169. }
  170. func (self *SCNwareGuestDriver) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, data *api.ServerCreateInput) (*api.ServerCreateInput, error) {
  171. if data.CpuSockets > data.VcpuCount {
  172. return nil, httperrors.NewInputParameterError("The number of cpu sockets cannot be greater than the number of cpus")
  173. }
  174. // check disk config
  175. if len(data.Disks) == 0 {
  176. return data, nil
  177. }
  178. rootDisk := data.Disks[0]
  179. if len(rootDisk.ImageId) == 0 {
  180. return data, nil
  181. }
  182. image, err := models.CachedimageManager.GetImageInfo(ctx, userCred, rootDisk.ImageId, false)
  183. if err != nil {
  184. return nil, errors.Wrapf(err, "unable to GetImageInfo of image %q", rootDisk.ImageId)
  185. }
  186. if len(image.SubImages) <= 1 {
  187. return data, nil
  188. }
  189. sort.Slice(image.SubImages, func(i, j int) bool {
  190. return image.SubImages[i].Index < image.SubImages[j].Index
  191. })
  192. newDataDisks := make([]*api.DiskConfig, 0, len(image.SubImages)+len(data.Disks)-1)
  193. for i, subImage := range image.SubImages {
  194. nDataDisk := *rootDisk
  195. nDataDisk.SizeMb = subImage.MinDiskMB
  196. nDataDisk.Format = "vmdk"
  197. nDataDisk.Index = i
  198. if i > 0 {
  199. nDataDisk.ImageId = ""
  200. }
  201. newDataDisks = append(newDataDisks, &nDataDisk)
  202. }
  203. for i := 1; i < len(data.Disks); i++ {
  204. data.Disks[i].Index += len(image.SubImages) - 1
  205. newDataDisks = append(newDataDisks, data.Disks[i])
  206. }
  207. data.Disks = newDataDisks
  208. return data, nil
  209. }
  210. func (self *SCNwareGuestDriver) GetGuestInitialStateAfterCreate() string {
  211. return api.VM_RUNNING
  212. }
  213. func (self *SCNwareGuestDriver) GetGuestInitialStateAfterRebuild() string {
  214. return api.VM_READY
  215. }
  216. func (self *SCNwareGuestDriver) IsNeedInjectPasswordByCloudInit() bool {
  217. return true
  218. }
  219. func (self *SCNwareGuestDriver) GetUserDataType() string {
  220. return cloudprovider.CLOUD_SHELL
  221. }
  222. func (self *SCNwareGuestDriver) IsWindowsUserDataTypeNeedEncode() bool {
  223. return true
  224. }
  225. func (self *SCNwareGuestDriver) GetInstanceCapability() cloudprovider.SInstanceCapability {
  226. return cloudprovider.SInstanceCapability{
  227. Hypervisor: self.GetHypervisor(),
  228. Provider: self.GetProvider(),
  229. DefaultAccount: cloudprovider.SDefaultAccount{
  230. Linux: cloudprovider.SOsDefaultAccount{
  231. DefaultAccount: api.VM_DEFAULT_LINUX_LOGIN_USER,
  232. },
  233. Windows: cloudprovider.SOsDefaultAccount{
  234. DefaultAccount: api.VM_DEFAULT_WINDOWS_LOGIN_USER,
  235. },
  236. },
  237. }
  238. }
  239. func (self *SCNwareGuestDriver) AllowReconfigGuest() bool {
  240. return true
  241. }
  242. func (self *SCNwareGuestDriver) IsSupportEip() bool {
  243. return false
  244. }
  245. func (self *SCNwareGuestDriver) RequestSyncSecgroupsOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error {
  246. return nil // do nothing, not support securitygroup
  247. }
  248. func (self *SCNwareGuestDriver) DoGuestCreateDisksTask(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
  249. return nil
  250. }
  251. func (self *SCNwareGuestDriver) GetChangeInstanceTypeStatus() ([]string, error) {
  252. return []string{api.VM_READY}, nil
  253. }
  254. func (self *SCNwareGuestDriver) ValidateGuestChangeConfigInput(ctx context.Context, guest *models.SGuest, input api.ServerChangeConfigInput) (*api.ServerChangeConfigSettings, error) {
  255. confs, err := self.SBaseGuestDriver.ValidateGuestChangeConfigInput(ctx, guest, input)
  256. if err != nil {
  257. return nil, errors.Wrap(err, "SBaseGuestDriver.ValidateGuestChangeConfigInput")
  258. }
  259. sku, err := models.ServerSkuManager.FetchSkuByNameAndProvider(input.Sku, "OneCloud", true)
  260. if err != nil {
  261. return nil, errors.Wrap(err, "FetchSkuByNameAndProvider")
  262. }
  263. confs.InstanceTypeFamily = ""
  264. confs.InstanceType = ""
  265. confs.VcpuCount = sku.CpuCoreCount
  266. confs.VmemSize = sku.MemorySizeMB
  267. confs.CpuSockets = 1
  268. log.Infof("ValidateGuestChangeConfigInput: %+v", confs)
  269. if input.CpuSockets != nil && *input.CpuSockets > 0 {
  270. confs.CpuSockets = *input.CpuSockets
  271. }
  272. defaultStorageId := ""
  273. if root, _ := guest.GetSystemDisk(); root != nil {
  274. defaultStorageId = root.StorageId
  275. }
  276. storages, err := guest.GetStorages()
  277. if err != nil {
  278. return nil, errors.Wrapf(err, "GetStorages")
  279. }
  280. storageMap := map[string]string{}
  281. for _, storage := range storages {
  282. storageMap[storage.StorageType] = storage.Id
  283. if len(defaultStorageId) == 0 {
  284. defaultStorageId = storage.Id
  285. }
  286. }
  287. for i := range confs.Create {
  288. confs.Create[i].Format = "vmdk"
  289. if len(confs.Create[i].Storage) == 0 {
  290. // 若不指定存储类型,默认和系统盘一致
  291. if len(confs.Create[i].Backend) == 0 {
  292. confs.Create[i].Storage = defaultStorageId
  293. } else if storageId, ok := storageMap[confs.Create[i].Backend]; ok { // 否则和已有磁盘存储保持一致
  294. confs.Create[i].Storage = storageId
  295. }
  296. }
  297. }
  298. return confs, nil
  299. }