guestdisks.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  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 models
  15. import (
  16. "context"
  17. "yunion.io/x/jsonutils"
  18. "yunion.io/x/log"
  19. "yunion.io/x/pkg/errors"
  20. "yunion.io/x/pkg/utils"
  21. "yunion.io/x/sqlchemy"
  22. api "yunion.io/x/onecloud/pkg/apis/compute"
  23. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  24. "yunion.io/x/onecloud/pkg/compute/options"
  25. "yunion.io/x/onecloud/pkg/httperrors"
  26. "yunion.io/x/onecloud/pkg/mcclient"
  27. "yunion.io/x/onecloud/pkg/util/stringutils2"
  28. )
  29. // +onecloud:swagger-gen-ignore
  30. type SGuestdiskManager struct {
  31. SGuestJointsManager
  32. SDiskResourceBaseManager
  33. }
  34. var GuestdiskManager *SGuestdiskManager
  35. func init() {
  36. db.InitManager(func() {
  37. GuestdiskManager = &SGuestdiskManager{
  38. SGuestJointsManager: NewGuestJointsManager(
  39. SGuestdisk{},
  40. "guestdisks_tbl",
  41. "guestdisk",
  42. "guestdisks",
  43. DiskManager,
  44. ),
  45. }
  46. GuestdiskManager.SetVirtualObject(GuestdiskManager)
  47. GuestdiskManager.TableSpec().AddIndex(true, "disk_id", "guest_id")
  48. })
  49. }
  50. // +onecloud:model-api-gen
  51. type SGuestdisk struct {
  52. SGuestJointsBase
  53. SDiskResourceBase `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"`
  54. // DiskId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"` // Column(VARCHAR(36, charset='ascii'), nullable=False)
  55. ImagePath string `width:"256" charset:"ascii" nullable:"false" get:"user" create:"required"` // Column(VARCHAR(256, charset='ascii'), nullable=False)
  56. Driver string `width:"32" charset:"ascii" nullable:"true" list:"user" update:"user"` // Column(VARCHAR(32, charset='ascii'), nullable=True)
  57. CacheMode string `width:"32" charset:"ascii" nullable:"true" list:"user" update:"user"` // Column(VARCHAR(32, charset='ascii'), nullable=True)
  58. AioMode string `width:"32" charset:"ascii" nullable:"true" get:"user" update:"user"` // Column(VARCHAR(32, charset='ascii'), nullable=True)
  59. Iops int `nullable:"true" default:"0" list:"user" update:"user"`
  60. Bps int `nullable:"true" default:"0" list:"user" update:"user"` // Mb
  61. Mountpoint string `width:"256" charset:"utf8" nullable:"true" get:"user"` // Column(VARCHAR(256, charset='utf8'), nullable=True)
  62. Index int8 `nullable:"false" default:"0" list:"user" update:"user"` // Column(TINYINT(4), nullable=False, default=0)
  63. BootIndex int8 `nullable:"false" default:"-1" list:"user" update:"user"`
  64. }
  65. func (manager *SGuestdiskManager) GetSlaveFieldName() string {
  66. return "disk_id"
  67. }
  68. func (self *SGuestdisk) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.GuestdiskUpdateInput) (api.GuestdiskUpdateInput, error) {
  69. if input.Index != nil {
  70. index := *input.Index
  71. guestdisk := GuestdiskManager.Query().SubQuery()
  72. count, err := guestdisk.Query().Filter(sqlchemy.Equals(guestdisk.Field("guest_id"), self.GuestId)).
  73. Filter(sqlchemy.NotEquals(guestdisk.Field("disk_id"), self.DiskId)).
  74. Filter(sqlchemy.Equals(guestdisk.Field("index"), index)).CountWithError()
  75. if err != nil {
  76. return input, httperrors.NewInternalServerError("check disk index uniqueness fail %s", err)
  77. }
  78. if count > 0 {
  79. return input, httperrors.NewInputParameterError("DISK Index %d has been occupied", index)
  80. }
  81. }
  82. if self.CacheMode != input.CacheMode {
  83. if input.CacheMode != "none" {
  84. input.AioMode = "threads"
  85. }
  86. }
  87. if self.AioMode != input.AioMode {
  88. cacheMode := self.CacheMode
  89. if input.CacheMode != "" {
  90. cacheMode = input.CacheMode
  91. }
  92. if input.AioMode == "native" && cacheMode != "none" {
  93. return input, httperrors.NewBadRequestError("Aio mode %s with cache mode %s not supported", input.AioMode, cacheMode)
  94. }
  95. }
  96. var err error
  97. input.GuestJointBaseUpdateInput, err = self.SGuestJointsBase.ValidateUpdateData(ctx, userCred, query, input.GuestJointBaseUpdateInput)
  98. if err != nil {
  99. return input, errors.Wrap(err, "SGuestJointsBase.ValidateUpdateData")
  100. }
  101. return input, nil
  102. }
  103. func (manager *SGuestdiskManager) FetchCustomizeColumns(
  104. ctx context.Context,
  105. userCred mcclient.TokenCredential,
  106. query jsonutils.JSONObject,
  107. objs []interface{},
  108. fields stringutils2.SSortedStrings,
  109. isList bool,
  110. ) []api.GuestDiskDetails {
  111. rows := make([]api.GuestDiskDetails, len(objs))
  112. guestRows := manager.SGuestJointsManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  113. diskIds := make([]string, len(rows))
  114. for i := range rows {
  115. rows[i] = api.GuestDiskDetails{
  116. GuestJointResourceDetails: guestRows[i],
  117. }
  118. diskIds[i] = objs[i].(*SGuestdisk).DiskId
  119. }
  120. disks := make(map[string]SDisk)
  121. err := db.FetchStandaloneObjectsByIds(DiskManager, diskIds, &disks)
  122. if err != nil {
  123. log.Errorf("FetchStandaloneObjectsByIds fail %s", err)
  124. return rows
  125. }
  126. for i := range rows {
  127. if disk, ok := disks[diskIds[i]]; ok {
  128. rows[i].Disk = disk.Name
  129. rows[i].Status = disk.Status
  130. rows[i].DiskSize = disk.DiskSize
  131. rows[i].DiskType = disk.DiskType
  132. rows[i].AutoReset = disk.AutoReset
  133. storage, _ := disk.GetStorage()
  134. if storage != nil {
  135. rows[i].StorageType = storage.StorageType
  136. rows[i].MediumType = storage.MediumType
  137. }
  138. }
  139. }
  140. return rows
  141. }
  142. func (self *SGuestdisk) DoSave(ctx context.Context, driver string, cache string, mountpoint string) error {
  143. self.ImagePath = ""
  144. if len(driver) == 0 {
  145. driver = options.Options.DefaultDiskDriver
  146. }
  147. if len(cache) == 0 {
  148. cache = options.Options.DefaultDiskCacheMode
  149. }
  150. if len(mountpoint) > 0 {
  151. self.Mountpoint = mountpoint
  152. }
  153. self.Driver = driver
  154. self.CacheMode = cache
  155. if cache == "none" {
  156. self.AioMode = "native"
  157. } else {
  158. self.AioMode = "threads"
  159. }
  160. return GuestdiskManager.TableSpec().Insert(ctx, self)
  161. }
  162. func (self *SGuestdisk) GetDisk() *SDisk {
  163. disk, err := DiskManager.FetchById(self.DiskId)
  164. if err != nil {
  165. log.Errorf("GetDisk %s fail: %s", self.DiskId, err)
  166. return nil
  167. }
  168. return disk.(*SDisk)
  169. }
  170. func (self *SGuestdisk) GetJsonDescAtHost(ctx context.Context, host *SHost) *api.GuestdiskJsonDesc {
  171. disk := self.GetDisk()
  172. return self.GetDiskJsonDescAtHost(ctx, host, disk)
  173. }
  174. func (self *SGuestdisk) GetDiskJsonDescAtHost(ctx context.Context, host *SHost, disk *SDisk) *api.GuestdiskJsonDesc {
  175. desc := &api.GuestdiskJsonDesc{
  176. DiskId: disk.Id,
  177. Driver: self.Driver,
  178. CacheMode: self.CacheMode,
  179. AioMode: self.AioMode,
  180. Iops: self.Iops,
  181. Throughput: disk.Throughput,
  182. Bps: self.Bps,
  183. Size: disk.DiskSize,
  184. PCIPath: disk.PCIPath,
  185. }
  186. desc.TemplateId = disk.GetTemplateId()
  187. storage, _ := disk.GetStorage()
  188. desc.StorageType = storage.StorageType
  189. if len(desc.TemplateId) > 0 {
  190. storagecacheimg := StoragecachedimageManager.GetStoragecachedimage(storage.StoragecacheId, desc.TemplateId)
  191. if storagecacheimg != nil {
  192. desc.ImagePath = storagecacheimg.Path
  193. }
  194. }
  195. if utils.IsInStringArray(host.HostType, []string{api.HOST_TYPE_HYPERVISOR, api.HOST_TYPE_CONTAINER}) {
  196. desc.StorageId = disk.StorageId
  197. localpath := disk.GetPathAtHost(host)
  198. if len(localpath) == 0 {
  199. desc.Migrating = true
  200. // not used yet
  201. // disk.SetStatus(nil, api.DISK_START_MIGRATE, "migration")
  202. } else {
  203. desc.Path = localpath
  204. }
  205. }
  206. desc.Format = disk.DiskFormat
  207. desc.Index = self.Index
  208. bootIndex := self.BootIndex
  209. desc.BootIndex = &bootIndex
  210. desc.AutoReset = disk.AutoReset
  211. if len(disk.SnapshotId) > 0 {
  212. needMerge := disk.GetMetadata(ctx, "merge_snapshot", nil)
  213. if needMerge == "true" {
  214. desc.MergeSnapshot = true
  215. }
  216. if desc.MergeSnapshot {
  217. if url, err := disk.GetSnapshotFuseUrl(); err != nil {
  218. log.Errorf("failed get snapshot fuse url: %s", err)
  219. } else {
  220. desc.Url = url
  221. }
  222. }
  223. }
  224. if fpath := disk.GetMetadata(ctx, api.DISK_META_REMOTE_ACCESS_PATH, nil); len(fpath) > 0 {
  225. guest := self.getGuest()
  226. if sid := guest.GetMetadata(ctx, api.SERVER_META_CONVERT_FROM_ESXI, nil); len(sid) > 0 {
  227. desc.EsxiFlatFilePath = fpath
  228. } else {
  229. desc.Url = fpath
  230. }
  231. desc.MergeSnapshot = true
  232. }
  233. desc.Fs = disk.GetFsFormat()
  234. desc.Mountpoint = self.Mountpoint
  235. desc.Dev = disk.getDev()
  236. desc.IsSSD = disk.IsSsd
  237. return desc
  238. }
  239. func (self *SGuestdisk) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
  240. return db.DeleteModel(ctx, userCred, self)
  241. }
  242. func (self *SGuestdisk) Detach(ctx context.Context, userCred mcclient.TokenCredential) error {
  243. return db.DetachJoint(ctx, userCred, self)
  244. }
  245. // DEPRECATE: will be remove in future, use ToDiskConfig
  246. func (self *SGuestdisk) ToDiskInfo() DiskInfo {
  247. disk := self.GetDisk()
  248. if disk == nil {
  249. return DiskInfo{}
  250. }
  251. info := disk.ToDiskInfo()
  252. info.Driver = self.Driver
  253. info.Cache = self.CacheMode
  254. return info
  255. }
  256. func (self *SGuestdisk) ToDiskConfig() *api.DiskConfig {
  257. disk := self.GetDisk()
  258. if disk == nil {
  259. return nil
  260. }
  261. conf := disk.ToDiskConfig()
  262. conf.Index = int(self.Index)
  263. conf.Mountpoint = self.Mountpoint
  264. conf.Driver = self.Driver
  265. conf.Cache = self.CacheMode
  266. return conf
  267. }
  268. func (self *SGuestdisk) SetBootIndex(bootIndex int8) error {
  269. _, err := db.Update(self, func() error {
  270. self.BootIndex = bootIndex
  271. return nil
  272. })
  273. return err
  274. }
  275. func (manager *SGuestdiskManager) ListItemFilter(
  276. ctx context.Context,
  277. q *sqlchemy.SQuery,
  278. userCred mcclient.TokenCredential,
  279. query api.GuestdiskListInput,
  280. ) (*sqlchemy.SQuery, error) {
  281. var err error
  282. q, err = manager.SGuestJointsManager.ListItemFilter(ctx, q, userCred, query.GuestJointsListInput)
  283. if err != nil {
  284. return nil, errors.Wrap(err, "SGuestJointsManager.ListItemFilter")
  285. }
  286. q, err = manager.SDiskResourceBaseManager.ListItemFilter(ctx, q, userCred, query.DiskFilterListInput)
  287. if err != nil {
  288. return nil, errors.Wrap(err, "SDiskResourceBaseManager.ListItemFilter")
  289. }
  290. if len(query.Driver) > 0 {
  291. q = q.In("driver", query.Driver)
  292. }
  293. if len(query.CacheMode) > 0 {
  294. q = q.In("cache_mode", query.CacheMode)
  295. }
  296. if len(query.AioMode) > 0 {
  297. q = q.In("aio_mode", query.AioMode)
  298. }
  299. return q, nil
  300. }
  301. func (manager *SGuestdiskManager) OrderByExtraFields(
  302. ctx context.Context,
  303. q *sqlchemy.SQuery,
  304. userCred mcclient.TokenCredential,
  305. query api.GuestdiskListInput,
  306. ) (*sqlchemy.SQuery, error) {
  307. var err error
  308. q, err = manager.SGuestJointsManager.OrderByExtraFields(ctx, q, userCred, query.GuestJointsListInput)
  309. if err != nil {
  310. return nil, errors.Wrap(err, "SGuestJointsManager.OrderByExtraFields")
  311. }
  312. q, err = manager.SDiskResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.DiskFilterListInput)
  313. if err != nil {
  314. return nil, errors.Wrap(err, "SDiskResourceBaseManager.OrderByExtraFields")
  315. }
  316. return q, nil
  317. }
  318. func (manager *SGuestdiskManager) ListItemExportKeys(ctx context.Context,
  319. q *sqlchemy.SQuery,
  320. userCred mcclient.TokenCredential,
  321. keys stringutils2.SSortedStrings,
  322. ) (*sqlchemy.SQuery, error) {
  323. var err error
  324. q, err = manager.SGuestJointsManager.ListItemExportKeys(ctx, q, userCred, keys)
  325. if err != nil {
  326. return nil, errors.Wrap(err, "SGuestJointsManager.ListItemExportKeys")
  327. }
  328. if keys.ContainsAny(manager.SDiskResourceBaseManager.GetExportKeys()...) {
  329. q, err = manager.SDiskResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  330. if err != nil {
  331. return nil, errors.Wrap(err, "SDiskResourceBaseManager.ListItemExportKeys")
  332. }
  333. }
  334. return q, nil
  335. }