storages.go 71 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176
  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. "database/sql"
  18. "fmt"
  19. "path"
  20. "strconv"
  21. "strings"
  22. "yunion.io/x/cloudmux/pkg/cloudprovider"
  23. "yunion.io/x/jsonutils"
  24. "yunion.io/x/log"
  25. "yunion.io/x/pkg/errors"
  26. "yunion.io/x/pkg/gotypes"
  27. "yunion.io/x/pkg/tristate"
  28. "yunion.io/x/pkg/util/compare"
  29. "yunion.io/x/pkg/util/rbacscope"
  30. "yunion.io/x/pkg/utils"
  31. "yunion.io/x/sqlchemy"
  32. "yunion.io/x/onecloud/pkg/apis"
  33. billing_api "yunion.io/x/onecloud/pkg/apis/billing"
  34. api "yunion.io/x/onecloud/pkg/apis/compute"
  35. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  36. "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
  37. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  38. "yunion.io/x/onecloud/pkg/cloudcommon/validators"
  39. "yunion.io/x/onecloud/pkg/compute/options"
  40. "yunion.io/x/onecloud/pkg/httperrors"
  41. "yunion.io/x/onecloud/pkg/mcclient"
  42. "yunion.io/x/onecloud/pkg/util/logclient"
  43. "yunion.io/x/onecloud/pkg/util/rbacutils"
  44. "yunion.io/x/onecloud/pkg/util/stringutils2"
  45. )
  46. type SStorageManager struct {
  47. db.SEnabledStatusInfrasResourceBaseManager
  48. db.SExternalizedResourceBaseManager
  49. SManagedResourceBaseManager
  50. SZoneResourceBaseManager
  51. }
  52. var StorageManager *SStorageManager
  53. func init() {
  54. StorageManager = &SStorageManager{
  55. SEnabledStatusInfrasResourceBaseManager: db.NewEnabledStatusInfrasResourceBaseManager(
  56. SStorage{},
  57. "storages_tbl",
  58. "storage",
  59. "storages",
  60. ),
  61. }
  62. StorageManager.SetVirtualObject(StorageManager)
  63. StorageManager.TableSpec().AddIndex(false, "deleted", "status", "enabled", "zone_id", "storagecache_id")
  64. }
  65. type SStorage struct {
  66. db.SEnabledStatusInfrasResourceBase `"status->default":"offline" "status->update":"domain" "enabled->default":"true"`
  67. db.SExternalizedResourceBase
  68. SManagedResourceBase
  69. SZoneResourceBase `update:""`
  70. // 容量大小,单位Mb
  71. Capacity int64 `nullable:"false" list:"user" update:"domain" create:"domain_required"`
  72. // 实际容量大小,单位Mb
  73. // we always expect actual capacity great or equal than zero, otherwise something wrong
  74. ActualCapacityUsed int64 `nullable:"true" list:"user" update:"domain" create:"domain_optional"`
  75. // 预留容量大小
  76. Reserved int64 `nullable:"true" default:"0" list:"domain" update:"domain" create:"domain_optional"`
  77. // 存储类型
  78. // example: local
  79. StorageType string `width:"64" charset:"ascii" nullable:"false" list:"user" create:"domain_required"`
  80. // 介质类型
  81. // example: ssd
  82. MediumType string `width:"32" charset:"ascii" nullable:"false" list:"user" update:"domain" create:"domain_required"`
  83. // 超售比
  84. Cmtbound float32 `nullable:"true" list:"domain"`
  85. // 存储配置信息
  86. StorageConf jsonutils.JSONObject `nullable:"true" get:"domain" list:"domain" update:"domain"`
  87. // 存储缓存Id
  88. StoragecacheId string `width:"36" charset:"ascii" nullable:"true" list:"domain" get:"domain" update:"domain" create:"domain_optional"`
  89. // master host id
  90. MasterHost string `width:"36" charset:"ascii" nullable:"true" list:"user" json:"master_host"`
  91. // indicating whether system disk can be allocated in this storage
  92. // 是否可以用作系统盘存储
  93. // example: true
  94. IsSysDiskStore tristate.TriState `default:"true" list:"user" create:"optional" update:"domain"`
  95. }
  96. func (manager *SStorageManager) GetContextManagers() [][]db.IModelManager {
  97. return [][]db.IModelManager{
  98. {ZoneManager},
  99. {StoragecacheManager},
  100. }
  101. }
  102. func (self *SStorage) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.StorageUpdateInput) (api.StorageUpdateInput, error) {
  103. var err error
  104. input.EnabledStatusInfrasResourceBaseUpdateInput, err = self.SEnabledStatusInfrasResourceBase.ValidateUpdateData(ctx, userCred, query, input.EnabledStatusInfrasResourceBaseUpdateInput)
  105. if err != nil {
  106. return input, err
  107. }
  108. if gotypes.IsNil(input.StorageConf) {
  109. input.StorageConf = jsonutils.NewDict()
  110. }
  111. if self.StorageConf != nil {
  112. confs, _ := self.StorageConf.GetMap()
  113. for k, v := range confs {
  114. if input.StorageConf.Contains(k) {
  115. continue
  116. }
  117. input.StorageConf.Set(k, v)
  118. }
  119. }
  120. if input.MasterHost != "" {
  121. host, err := HostManager.FetchByIdOrName(ctx, userCred, input.MasterHost)
  122. if err != nil {
  123. return input, httperrors.NewInputParameterError("get host %s failed", input.MasterHost)
  124. }
  125. input.MasterHost = host.GetId()
  126. }
  127. driver := GetStorageDriver(self.StorageType)
  128. if driver != nil {
  129. return driver.ValidateUpdateData(ctx, userCred, input)
  130. }
  131. return input, nil
  132. }
  133. func (self *SStorage) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) {
  134. self.SEnabledStatusInfrasResourceBase.PostUpdate(ctx, userCred, query, data)
  135. if err := self.setHardwareInfoByData(ctx, userCred, data); err != nil {
  136. log.Errorf("setHardwareInfo when post update eror: %v", err)
  137. }
  138. if data.Contains("cmtbound") || data.Contains("capacity") {
  139. hosts, _ := self.GetAttachedHosts()
  140. for _, host := range hosts {
  141. if err := host.ClearSchedDescCache(); err != nil {
  142. log.Errorf("clear host %s sched cache failed %v", host.GetName(), err)
  143. }
  144. }
  145. }
  146. if masterHost, _ := data.GetString("master_host"); masterHost != "" {
  147. storageCache := self.GetStoragecache()
  148. if storageCache.MasterHost != masterHost {
  149. _, err := db.Update(storageCache, func() error {
  150. storageCache.MasterHost = masterHost
  151. return nil
  152. })
  153. if err != nil {
  154. log.Errorf("failed update storage master host")
  155. }
  156. }
  157. }
  158. if update, _ := data.Bool("update_storage_conf"); update {
  159. self.StartStorageUpdateTask(ctx, userCred)
  160. }
  161. }
  162. func (self *SStorage) StartStorageUpdateTask(ctx context.Context, userCred mcclient.TokenCredential) error {
  163. task, err := taskman.TaskManager.NewTask(ctx, "StorageUpdateTask", self, userCred, nil, "", "", nil)
  164. if err != nil {
  165. return err
  166. }
  167. task.ScheduleRun(nil)
  168. return nil
  169. }
  170. func (self *SStorage) getFakeDeletedSnapshots() ([]SSnapshot, error) {
  171. q := SnapshotManager.Query().Equals("storage_id", self.Id).IsTrue("fake_deleted")
  172. snapshots := make([]SSnapshot, 0)
  173. err := db.FetchModelObjects(SnapshotManager, q, &snapshots)
  174. if err != nil {
  175. return nil, errors.Wrap(err, "FetchModelObjects")
  176. }
  177. return snapshots, nil
  178. }
  179. func (self *SStorage) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
  180. ok, err := self.IsNeedDeleteStoragecache()
  181. if err != nil {
  182. return err
  183. }
  184. if ok {
  185. cache := self.GetStoragecache()
  186. if cache != nil {
  187. cache.Delete(ctx, userCred)
  188. }
  189. }
  190. if len(self.ManagerId) > 0 {
  191. db.SharedResourceManager.CleanModelShares(ctx, userCred, self.GetIInfrasModel())
  192. return self.purge(ctx, userCred)
  193. }
  194. return self.purge(ctx, userCred)
  195. }
  196. func (self *SStorage) IsNeedDeleteStoragecache() (bool, error) {
  197. q := StorageManager.Query().Equals("storagecache_id", self.StoragecacheId).NotEquals("id", self.Id)
  198. cnt, err := q.CountWithError()
  199. if err != nil {
  200. return false, err
  201. }
  202. return cnt == 0, nil
  203. }
  204. func (manager *SStorageManager) GetStorageTypesByProvider(provider string) ([]string, error) {
  205. q := manager.Query("storage_type")
  206. providers := CloudproviderManager.Query().SubQuery()
  207. q = q.Join(providers, sqlchemy.Equals(q.Field("manager_id"), providers.Field("id"))).
  208. Filter(sqlchemy.Equals(providers.Field("provider"), provider)).Distinct()
  209. storages := []string{}
  210. rows, err := q.Rows()
  211. if err != nil {
  212. return nil, err
  213. }
  214. defer rows.Close()
  215. for rows.Next() {
  216. var storage string
  217. err = rows.Scan(&storage)
  218. if err != nil {
  219. return nil, errors.Wrap(err, "rows.Scan(&storage)")
  220. }
  221. storages = append(storages, storage)
  222. }
  223. return storages, nil
  224. }
  225. func (self *SStorage) IsNeedDeactivateOnAllHost() bool {
  226. return self.StorageType == api.STORAGE_SLVM
  227. }
  228. func (manager *SStorageManager) GetStorageTypesByHostType(hostType string) ([]string, error) {
  229. q := manager.Query("storage_type")
  230. hosts := HostManager.Query().SubQuery()
  231. hs := HoststorageManager.Query().SubQuery()
  232. q = q.Join(hs, sqlchemy.Equals(q.Field("id"), hs.Field("storage_id"))).
  233. Join(hosts, sqlchemy.Equals(hosts.Field("id"), hs.Field("host_id"))).
  234. Filter(sqlchemy.Equals(hosts.Field("host_type"), hostType)).Distinct()
  235. storages := []string{}
  236. rows, err := q.Rows()
  237. if err != nil {
  238. return nil, err
  239. }
  240. defer rows.Close()
  241. for rows.Next() {
  242. var storage string
  243. err = rows.Scan(&storage)
  244. if err != nil {
  245. return nil, errors.Wrap(err, "rows.Scan(&storage)")
  246. }
  247. storages = append(storages, storage)
  248. }
  249. return storages, nil
  250. }
  251. func (manager *SStorageManager) ValidateCreateData(
  252. ctx context.Context,
  253. userCred mcclient.TokenCredential,
  254. ownerId mcclient.IIdentityProvider,
  255. query jsonutils.JSONObject,
  256. input api.StorageCreateInput,
  257. ) (api.StorageCreateInput, error) {
  258. if !utils.IsInStringArray(input.StorageType, api.STORAGE_TYPES) {
  259. return input, httperrors.NewInputParameterError("Invalid storage type %s", input.StorageType)
  260. }
  261. if len(input.MediumType) == 0 {
  262. input.MediumType = api.DISK_TYPE_SSD
  263. }
  264. if !utils.IsInStringArray(input.MediumType, api.DISK_TYPES) {
  265. return input, httperrors.NewInputParameterError("Invalid medium type %s", input.MediumType)
  266. }
  267. if len(input.ZoneId) == 0 {
  268. return input, httperrors.NewMissingParameterError("zone_id")
  269. }
  270. _, err := validators.ValidateModel(ctx, userCred, ZoneManager, &input.ZoneId)
  271. if err != nil {
  272. return input, err
  273. }
  274. storageDirver := GetStorageDriver(input.StorageType)
  275. if storageDirver == nil {
  276. return input, httperrors.NewUnsupportOperationError("Not support create %s storage", input.StorageType)
  277. }
  278. err = storageDirver.ValidateCreateData(ctx, userCred, &input)
  279. if err != nil {
  280. return input, errors.Wrap(err, "storageDirver.ValidateCreateData")
  281. }
  282. input.EnabledStatusInfrasResourceBaseCreateInput, err = manager.SEnabledStatusInfrasResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.EnabledStatusInfrasResourceBaseCreateInput)
  283. if err != nil {
  284. return input, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.ValidateCreateData")
  285. }
  286. return input, nil
  287. }
  288. func (self *SStorage) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
  289. self.SetEnabled(true)
  290. self.SetStatus(ctx, userCred, api.STORAGE_UNMOUNT, "CustomizeCreate")
  291. if err := self.setHardwareInfoByData(ctx, userCred, data); err != nil {
  292. return errors.Wrap(err, "setHardwareInfo")
  293. }
  294. return self.SEnabledStatusInfrasResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
  295. }
  296. func (self *SStorage) setHardwareInfoByData(ctx context.Context, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error {
  297. var hdInfo *api.StorageHardwareInfo = nil
  298. if data.Contains("hardware_info") {
  299. hdInfo = new(api.StorageHardwareInfo)
  300. data.Unmarshal(hdInfo, "hardware_info")
  301. }
  302. if err := self.setHardwareInfo(ctx, userCred, hdInfo); err != nil {
  303. return errors.Wrap(err, "setHardwareInfo")
  304. }
  305. return nil
  306. }
  307. func (self *SStorage) setHardwareInfo(ctx context.Context, userCred mcclient.TokenCredential, info *api.StorageHardwareInfo) error {
  308. if info == nil {
  309. return nil
  310. }
  311. for k, v := range map[string]*string{
  312. api.STORAGE_METADATA_MODEL: info.Model,
  313. api.STORAGE_METADATA_VENDOR: info.Vendor,
  314. } {
  315. if v != nil {
  316. if err := self.SetMetadata(ctx, k, *v, userCred); err != nil {
  317. return errors.Wrapf(err, "set metadata %s = %s", k, *v)
  318. }
  319. }
  320. }
  321. if info.Bandwidth != 0 {
  322. if err := self.SetMetadata(ctx, api.STORAGE_METADATA_BANDWIDTH, info.Bandwidth, userCred); err != nil {
  323. return errors.Wrapf(err, "set metadata %s = %f", api.STORAGE_METADATA_BANDWIDTH, info.Bandwidth)
  324. }
  325. }
  326. return nil
  327. }
  328. func (self *SStorage) ValidateDeleteCondition(ctx context.Context, info api.StorageDetails) error {
  329. if !info.IsZero() {
  330. return httperrors.NewNotEmptyError("storage has resources with %s", jsonutils.Marshal(info.StorageUsage).String())
  331. }
  332. return self.SEnabledStatusInfrasResourceBase.ValidateDeleteCondition(ctx, nil)
  333. }
  334. func (self *SStorage) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
  335. self.SEnabledStatusInfrasResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
  336. storageDriver := GetStorageDriver(self.StorageType)
  337. if storageDriver != nil {
  338. storageDriver.PostCreate(ctx, userCred, self, data)
  339. }
  340. }
  341. func (self *SStorage) SetStatus(ctx context.Context, userCred mcclient.TokenCredential, status string, reason string) error {
  342. if self.Status == status {
  343. return nil
  344. }
  345. oldStatus := self.Status
  346. _, err := db.Update(self, func() error {
  347. self.Status = status
  348. return nil
  349. })
  350. if err != nil {
  351. return err
  352. }
  353. if userCred != nil {
  354. notes := fmt.Sprintf("%s=>%s", oldStatus, status)
  355. if len(reason) > 0 {
  356. notes = fmt.Sprintf("%s: %s", notes, reason)
  357. }
  358. db.OpsLog.LogEvent(self, db.ACT_UPDATE_STATUS, notes, userCred)
  359. // if strings.Contains(notes, "fail") {
  360. // logclient.AddActionLogWithContext(ctx, self, logclient.ACT_VM_SYNC_STATUS, notes, userCred, false)
  361. // }
  362. }
  363. return nil
  364. }
  365. func (self *SStorage) PerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  366. if self.Enabled.IsFalse() {
  367. _, err := db.Update(self, func() error {
  368. self.Enabled = tristate.True
  369. return nil
  370. })
  371. if err != nil {
  372. log.Errorf("PerformEnable save update fail %s", err)
  373. return nil, err
  374. }
  375. db.OpsLog.LogEvent(self, db.ACT_ENABLE, "", userCred)
  376. logclient.AddSimpleActionLog(self, logclient.ACT_ENABLE, nil, userCred, true)
  377. self.ClearSchedDescCache()
  378. }
  379. return nil, nil
  380. }
  381. func (self *SStorage) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  382. if self.Enabled.IsTrue() {
  383. _, err := db.Update(self, func() error {
  384. self.Enabled = tristate.False
  385. return nil
  386. })
  387. if err != nil {
  388. log.Errorf("PerformDisable save update fail %s", err)
  389. return nil, err
  390. }
  391. db.OpsLog.LogEvent(self, db.ACT_DISABLE, "", userCred)
  392. logclient.AddSimpleActionLog(self, logclient.ACT_DISABLE, nil, userCred, true)
  393. self.ClearSchedDescCache()
  394. }
  395. return nil, nil
  396. }
  397. func (self *SStorage) PerformOnline(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  398. if self.Status != api.STORAGE_ONLINE {
  399. err := self.SetStatus(ctx, userCred, api.STORAGE_ONLINE, "")
  400. if err != nil {
  401. return nil, err
  402. }
  403. db.OpsLog.LogEvent(self, db.ACT_ONLINE, "", userCred)
  404. self.ClearSchedDescCache()
  405. }
  406. return nil, nil
  407. }
  408. func (self *SStorage) PerformOffline(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  409. if self.Status != api.STORAGE_OFFLINE {
  410. err := self.SetStatus(ctx, userCred, api.STORAGE_OFFLINE, data.String())
  411. if err != nil {
  412. return nil, err
  413. }
  414. db.OpsLog.LogEvent(self, db.ACT_OFFLINE, "", userCred)
  415. self.ClearSchedDescCache()
  416. }
  417. return nil, nil
  418. }
  419. func (self *SStorage) GetHostCount() (int, error) {
  420. return HoststorageManager.Query().Equals("storage_id", self.Id).CountWithError()
  421. }
  422. func (self *SStorage) GetDiskCount() (int, error) {
  423. return DiskManager.Query().Equals("storage_id", self.Id).CountWithError()
  424. }
  425. func (self *SStorage) GetDisks() []SDisk {
  426. disks := make([]SDisk, 0)
  427. q := DiskManager.Query().Equals("storage_id", self.Id)
  428. err := db.FetchModelObjects(DiskManager, q, &disks)
  429. if err != nil {
  430. log.Errorf("GetDisks fail %s", err)
  431. return nil
  432. }
  433. return disks
  434. }
  435. func (self *SStorage) GetVisibleSnapshotCount() (int, error) {
  436. return SnapshotManager.Query().Equals("storage_id", self.Id).IsFalse("fake_deleted").CountWithError()
  437. }
  438. func (self *SStorage) IsLocal() bool {
  439. return utils.IsInStringArray(self.StorageType, api.HOST_STORAGE_LOCAL_TYPES)
  440. }
  441. func (self *SStorage) GetStorageCachePath(mountPoint, imageCachePath string) string {
  442. if utils.IsInStringArray(self.StorageType, api.SHARED_FILE_STORAGE) {
  443. return path.Join(mountPoint, imageCachePath)
  444. } else if self.StorageType == api.STORAGE_LVM {
  445. return mountPoint
  446. } else {
  447. return imageCachePath
  448. }
  449. }
  450. func (self *SStorage) getStorageCapacity() SStorageCapacity {
  451. capa := SStorageCapacity{}
  452. capa.Capacity = self.GetCapacity()
  453. capa.Used = self.GetUsedCapacity(tristate.True)
  454. capa.Wasted = self.GetUsedCapacity(tristate.False)
  455. capa.VCapacity = int64(float32(self.GetCapacity()) * self.GetOvercommitBound())
  456. capa.ActualUsed = self.ActualCapacityUsed
  457. return capa
  458. }
  459. type sStorageSchedtag struct {
  460. Id string
  461. Name string
  462. StorageId string
  463. DefaultStrategy string
  464. }
  465. func (self *sStorageSchedtag) GetShortDesc() api.SchedtagShortDescDetails {
  466. return api.SchedtagShortDescDetails{
  467. StandaloneResourceShortDescDetail: &apis.StandaloneResourceShortDescDetail{
  468. StandaloneAnonResourceShortDescDetail: apis.StandaloneAnonResourceShortDescDetail{
  469. Id: self.Id,
  470. },
  471. Name: self.Name,
  472. },
  473. Default: self.DefaultStrategy,
  474. }
  475. }
  476. func (sm *SStorageManager) query(manager db.IModelManager, field string, storageIds []string, filter func(*sqlchemy.SQuery) *sqlchemy.SQuery) *sqlchemy.SSubQuery {
  477. q := manager.Query()
  478. if filter != nil {
  479. q = filter(q)
  480. }
  481. sq := q.SubQuery()
  482. return sq.Query(
  483. sq.Field("storage_id"),
  484. sqlchemy.COUNT(field),
  485. ).In("storage_id", storageIds).GroupBy(sq.Field("storage_id")).SubQuery()
  486. }
  487. type StorageUsageCount struct {
  488. Id string
  489. api.StorageUsage
  490. }
  491. func (manager *SStorageManager) TotalResourceCount(storageIds []string) (map[string]api.StorageUsage, error) {
  492. ret := map[string]api.StorageUsage{}
  493. hostSQ := manager.query(HoststorageManager, "host_cnt", storageIds, nil)
  494. diskSQ := manager.query(DiskManager, "disk_cnt", storageIds, nil)
  495. diskUsed := DiskManager.Query().Equals("status", api.DISK_READY)
  496. _diskUsedSQ := diskUsed.SubQuery()
  497. diskUsedSQ := _diskUsedSQ.Query(
  498. _diskUsedSQ.Field("storage_id"),
  499. sqlchemy.SUM("disk_used", _diskUsedSQ.Field("disk_size")),
  500. ).In("storage_id", storageIds).GroupBy(_diskUsedSQ.Field("storage_id")).SubQuery()
  501. diskWasted := DiskManager.Query().NotEquals("status", api.DISK_READY)
  502. _diskWastedSQ := diskWasted.SubQuery()
  503. diskWastedSQ := _diskWastedSQ.Query(
  504. _diskWastedSQ.Field("storage_id"),
  505. sqlchemy.SUM("disk_wasted", _diskWastedSQ.Field("disk_size")),
  506. ).In("storage_id", storageIds).GroupBy(_diskWastedSQ.Field("storage_id")).SubQuery()
  507. snapshotSQ := manager.query(SnapshotManager, "snapshot_cnt", storageIds, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  508. return q.IsFalse("fake_deleted")
  509. })
  510. storages := manager.Query().SubQuery()
  511. storageQ := storages.Query(
  512. sqlchemy.SUM("host_count", hostSQ.Field("host_cnt")),
  513. sqlchemy.SUM("disk_count", diskSQ.Field("disk_cnt")),
  514. sqlchemy.SUM("snapshot_count", snapshotSQ.Field("snapshot_cnt")),
  515. sqlchemy.SUM("used", diskUsedSQ.Field("disk_used")),
  516. sqlchemy.SUM("wasted", diskWastedSQ.Field("disk_wasted")),
  517. )
  518. storageQ.AppendField(storageQ.Field("id"))
  519. storageQ = storageQ.LeftJoin(hostSQ, sqlchemy.Equals(storageQ.Field("id"), hostSQ.Field("storage_id")))
  520. storageQ = storageQ.LeftJoin(diskSQ, sqlchemy.Equals(storageQ.Field("id"), diskSQ.Field("storage_id")))
  521. storageQ = storageQ.LeftJoin(snapshotSQ, sqlchemy.Equals(storageQ.Field("id"), snapshotSQ.Field("storage_id")))
  522. storageQ = storageQ.LeftJoin(diskUsedSQ, sqlchemy.Equals(storageQ.Field("id"), diskUsedSQ.Field("storage_id")))
  523. storageQ = storageQ.LeftJoin(diskWastedSQ, sqlchemy.Equals(storageQ.Field("id"), diskWastedSQ.Field("storage_id")))
  524. storageQ = storageQ.Filter(sqlchemy.In(storageQ.Field("id"), storageIds)).GroupBy(storageQ.Field("id"))
  525. counts := []StorageUsageCount{}
  526. err := storageQ.All(&counts)
  527. if err != nil {
  528. return nil, errors.Wrapf(err, "storageQ.All")
  529. }
  530. for i := range counts {
  531. ret[counts[i].Id] = counts[i].StorageUsage
  532. }
  533. return ret, nil
  534. }
  535. func (manager *SStorageManager) FetchCustomizeColumns(
  536. ctx context.Context,
  537. userCred mcclient.TokenCredential,
  538. query jsonutils.JSONObject,
  539. objs []interface{},
  540. fields stringutils2.SSortedStrings,
  541. isList bool,
  542. ) []api.StorageDetails {
  543. rows := make([]api.StorageDetails, len(objs))
  544. stdRows := manager.SEnabledStatusInfrasResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  545. zoneRows := manager.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  546. manageRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  547. storageIds := make([]string, len(objs))
  548. for i := range rows {
  549. rows[i] = api.StorageDetails{
  550. EnabledStatusInfrasResourceBaseDetails: stdRows[i],
  551. ZoneResourceInfo: zoneRows[i],
  552. ManagedResourceInfo: manageRows[i],
  553. }
  554. storage := objs[i].(*SStorage)
  555. storageIds[i] = storage.Id
  556. if rows[i].ManagerId == "" && rows[i].MasterHost == "" &&
  557. utils.IsInStringArray(storage.StorageType, api.SHARED_STORAGE) {
  558. if host, err := storage.GetMasterHost(); host != nil {
  559. rows[i].MasterHost = host.Id
  560. rows[i].MasterHostName = host.Name
  561. } else {
  562. log.Errorf("storage %s failed get master host %s", storageIds[i], err)
  563. }
  564. }
  565. if rows[i].MasterHost != "" && rows[i].MasterHostName == "" {
  566. if host := HostManager.FetchHostById(rows[i].MasterHost); host != nil {
  567. rows[i].MasterHostName = host.Name
  568. }
  569. }
  570. rows[i].Capacity = storage.GetCapacity()
  571. rows[i].VCapacity = int64(float32(rows[i].Capacity) * storage.GetOvercommitBound())
  572. rows[i].ActualUsed = storage.ActualCapacityUsed
  573. rows[i].CommitBound = storage.GetOvercommitBound()
  574. }
  575. count, err := manager.TotalResourceCount(storageIds)
  576. if err != nil {
  577. log.Errorf("TotalResourceCount error: %v", err)
  578. return rows
  579. }
  580. tags := make([]sStorageSchedtag, 0)
  581. schedtags := SchedtagManager.Query().SubQuery()
  582. storagetags := StorageschedtagManager.Query().IsFalse("deleted").In("storage_id", storageIds).SubQuery()
  583. q := schedtags.Query(
  584. schedtags.Field("id"),
  585. schedtags.Field("name"),
  586. schedtags.Field("default_strategy"),
  587. storagetags.Field("storage_id"),
  588. )
  589. q = q.LeftJoin(storagetags, sqlchemy.Equals(storagetags.Field("schedtag_id"), schedtags.Field("id")))
  590. err = q.All(&tags)
  591. if err != nil {
  592. log.Errorf("tagQ.All error: %v", err)
  593. return rows
  594. }
  595. tagMap := map[string][]api.SchedtagShortDescDetails{}
  596. for i := range tags {
  597. desc := tags[i].GetShortDesc()
  598. _, ok := tagMap[tags[i].StorageId]
  599. if !ok {
  600. tagMap[tags[i].StorageId] = []api.SchedtagShortDescDetails{}
  601. }
  602. tagMap[tags[i].StorageId] = append(tagMap[tags[i].StorageId], desc)
  603. }
  604. sq := HoststorageManager.Query().In("storage_id", storageIds).SubQuery()
  605. hosts := HostManager.Query().SubQuery()
  606. q = sq.Query(
  607. sq.Field("storage_id"),
  608. sq.Field("host_id"),
  609. hosts.Field("name"),
  610. hosts.Field("status"),
  611. hosts.Field("host_status"),
  612. ).LeftJoin(hosts, sqlchemy.Equals(sq.Field("host_id"), hosts.Field("id")))
  613. hs := []struct {
  614. StorageId string
  615. HostId string
  616. Name string
  617. Status string
  618. HostStatus string
  619. }{}
  620. err = q.All(&hs)
  621. if err != nil {
  622. log.Errorf("query host error: %v", err)
  623. return rows
  624. }
  625. hoststorages := map[string][]api.StorageHost{}
  626. for _, h := range hs {
  627. _, ok := hoststorages[h.StorageId]
  628. if !ok {
  629. hoststorages[h.StorageId] = []api.StorageHost{}
  630. }
  631. hoststorages[h.StorageId] = append(hoststorages[h.StorageId], api.StorageHost{
  632. Id: h.HostId,
  633. Name: h.Name,
  634. Status: h.Status,
  635. HostStatus: h.HostStatus,
  636. })
  637. }
  638. for i := range rows {
  639. rows[i].Hosts, _ = hoststorages[storageIds[i]]
  640. tags, ok := tagMap[storageIds[i]]
  641. if ok {
  642. rows[i].Schedtags = tags
  643. }
  644. cnt, ok := count[storageIds[i]]
  645. if ok {
  646. rows[i].StorageUsage = cnt
  647. }
  648. capa := SStorageCapacity{
  649. Capacity: rows[i].Capacity,
  650. VCapacity: rows[i].VCapacity,
  651. ActualUsed: rows[i].ActualUsed,
  652. Used: rows[i].Used,
  653. Wasted: rows[i].Wasted,
  654. }
  655. rows[i].SStorageCapacityInfo = capa.toCapacityInfo()
  656. }
  657. return rows
  658. }
  659. func (self *SStorage) GetUsedCapacity(isReady tristate.TriState) int64 {
  660. disks := DiskManager.Query().SubQuery()
  661. q := disks.Query(sqlchemy.SUM("sum", disks.Field("disk_size"))).Equals("storage_id", self.Id)
  662. switch isReady {
  663. case tristate.True:
  664. q = q.Equals("status", api.DISK_READY)
  665. case tristate.False:
  666. q = q.NotEquals("status", api.DISK_READY)
  667. }
  668. row := q.Row()
  669. // sum can be null, deal with null:
  670. // https://github.com/golang/go/wiki/SQLInterface#dealing-with-null
  671. var sum sql.NullInt64
  672. err := row.Scan(&sum)
  673. if err != nil {
  674. log.Errorf("GetUsedCapacity fail: %s", err)
  675. return 0
  676. }
  677. if sum.Valid {
  678. return sum.Int64
  679. } else {
  680. return 0
  681. }
  682. }
  683. func (storage *SStorage) GetOvercommitBound() float32 {
  684. if storage.Cmtbound > 0 {
  685. return storage.Cmtbound
  686. } else {
  687. return options.Options.DefaultStorageOvercommitBound
  688. }
  689. }
  690. func (self *SStorage) GetMasterHost() (*SHost, error) {
  691. if self.MasterHost != "" {
  692. host := HostManager.FetchHostById(self.MasterHost)
  693. if host != nil && host.Enabled.IsTrue() && host.HostStatus == api.HOST_ONLINE {
  694. return host, nil
  695. }
  696. }
  697. hosts := HostManager.Query().SubQuery()
  698. hoststorages := HoststorageManager.Query().SubQuery()
  699. q := hosts.Query().Join(hoststorages, sqlchemy.Equals(hoststorages.Field("host_id"), hosts.Field("id")))
  700. q = q.Filter(sqlchemy.Equals(hoststorages.Field("storage_id"), self.Id))
  701. q = q.IsTrue("enabled")
  702. q = q.Equals("host_status", api.HOST_ONLINE).Asc("id")
  703. host := SHost{}
  704. host.SetModelManager(HostManager, &host)
  705. err := q.First(&host)
  706. if err != nil {
  707. return nil, errors.Wrapf(err, "q.First")
  708. }
  709. if utils.IsInStringArray(self.StorageType, api.SHARED_STORAGE) {
  710. if err := self.UpdateMasterHost(host.Id); err != nil {
  711. log.Errorf("storage %s udpate master host failed %s: %s", self.GetName(), host.Id, err)
  712. }
  713. }
  714. return &host, nil
  715. }
  716. func (self *SStorage) UpdateMasterHost(hostId string) error {
  717. _, err := db.Update(self, func() error {
  718. self.MasterHost = hostId
  719. return nil
  720. })
  721. return err
  722. }
  723. func (self *SStorage) GetZoneId() string {
  724. if len(self.ZoneId) > 0 {
  725. return self.ZoneId
  726. }
  727. host, _ := self.GetMasterHost()
  728. if host != nil {
  729. _, err := db.Update(self, func() error {
  730. self.ZoneId = host.ZoneId
  731. return nil
  732. })
  733. if err != nil {
  734. log.Errorf("%s", err)
  735. return ""
  736. }
  737. return self.ZoneId
  738. } else {
  739. log.Errorf("No mater host for storage")
  740. return ""
  741. }
  742. }
  743. func (self *SStorage) getZone() (*SZone, error) {
  744. zoneId := self.GetZoneId()
  745. if len(zoneId) > 0 {
  746. zone, err := ZoneManager.FetchById(zoneId)
  747. if err != nil {
  748. return nil, errors.Wrapf(err, "GetZone(%s)", zoneId)
  749. }
  750. return zone.(*SZone), nil
  751. }
  752. return nil, fmt.Errorf("empty zoneId for storage %s(%s)", self.Name, self.Id)
  753. }
  754. func (self *SStorage) GetRegion() (*SCloudregion, error) {
  755. zone, err := self.getZone()
  756. if err != nil {
  757. return nil, errors.Wrapf(err, "getZone")
  758. }
  759. return zone.GetRegion()
  760. }
  761. func (self *SStorage) GetReserved() int64 {
  762. return self.Reserved
  763. }
  764. func (self *SStorage) GetCapacity() int64 {
  765. return self.Capacity - self.GetReserved()
  766. }
  767. func (self *SStorage) GetFreeCapacity() int64 {
  768. return int64(float32(self.GetCapacity())*self.GetOvercommitBound()) - self.GetUsedCapacity(tristate.None)
  769. }
  770. func (self *SStorage) GetAttachedHosts() ([]SHost, error) {
  771. hosts := HostManager.Query().SubQuery()
  772. hoststorages := HoststorageManager.Query().SubQuery()
  773. q := hosts.Query()
  774. q = q.Join(hoststorages, sqlchemy.Equals(hoststorages.Field("host_id"), hosts.Field("id")))
  775. q = q.Filter(sqlchemy.Equals(hoststorages.Field("storage_id"), self.Id))
  776. hostList := make([]SHost, 0)
  777. err := db.FetchModelObjects(HostManager, q, &hostList)
  778. if err != nil {
  779. return nil, errors.Wrapf(err, "GetAttachedHosts")
  780. }
  781. return hostList, nil
  782. }
  783. func (self *SStorage) SyncStatusWithHosts(ctx context.Context) {
  784. hosts, err := self.GetAttachedHosts()
  785. if err != nil {
  786. log.Errorf("storage.SyncStatusWithHosts: GetAttachedHosts fail %s", err)
  787. return
  788. }
  789. total := 0
  790. online := 0
  791. offline := 0
  792. for _, h := range hosts {
  793. if h.HostStatus == api.HOST_ONLINE {
  794. online += 1
  795. } else {
  796. offline += 1
  797. }
  798. total += 1
  799. }
  800. var status string
  801. if !self.IsLocal() {
  802. status = self.Status
  803. if online == 0 {
  804. status = api.STORAGE_OFFLINE
  805. } else {
  806. status = api.STORAGE_ONLINE
  807. }
  808. } else if online > 0 {
  809. status = api.STORAGE_ONLINE
  810. } else if offline > 0 {
  811. status = api.STORAGE_OFFLINE
  812. } else {
  813. status = api.STORAGE_OFFLINE
  814. }
  815. if len(hosts) == 0 {
  816. status = api.STORAGE_UNMOUNT
  817. }
  818. if status != self.Status {
  819. log.Infof("Storage %s(%s) status %s expect %s online %d", self.Name, self.Id, self.Status, status, online)
  820. self.SetStatus(ctx, nil, status, "SyncStatusWithHosts")
  821. }
  822. }
  823. func (manager *SStorageManager) getStoragesByZone(zone *SZone, provider *SCloudprovider) ([]SStorage, error) {
  824. storages := make([]SStorage, 0)
  825. q := manager.Query()
  826. if zone != nil {
  827. q = q.Equals("zone_id", zone.Id)
  828. }
  829. if provider != nil {
  830. q = q.Equals("manager_id", provider.Id)
  831. }
  832. err := db.FetchModelObjects(manager, q, &storages)
  833. if err != nil {
  834. log.Errorf("getStoragesByZoneId fail %s", err)
  835. return nil, err
  836. }
  837. return storages, nil
  838. }
  839. func (manager *SStorageManager) GetStorageByStoragecache(storagecacheId string) (*SStorage, error) {
  840. s := SStorage{}
  841. s.SetModelManager(StorageManager, &s)
  842. err := manager.Query().Equals("storagecache_id", storagecacheId).First(&s)
  843. if err != nil {
  844. return nil, errors.Wrap(err, "get storage by storagecache")
  845. }
  846. return &s, nil
  847. }
  848. func (manager *SStorageManager) scanLegacyStorages() error {
  849. storages := make([]SStorage, 0)
  850. table := manager.Query().SubQuery()
  851. q := table.Query().Filter(sqlchemy.OR(sqlchemy.IsNull(table.Field("zone_id")), sqlchemy.IsEmpty(table.Field("zone_id"))))
  852. err := db.FetchModelObjects(manager, q, &storages)
  853. if err != nil {
  854. log.Errorf("getLegacyStoragesByZoneId fail %s", err)
  855. return err
  856. }
  857. for i := 0; i < len(storages); i += 1 {
  858. storages[i].GetZoneId()
  859. }
  860. return nil
  861. }
  862. func (manager *SStorageManager) SyncStorages(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, zone *SZone, storages []cloudprovider.ICloudStorage, xor bool) ([]SStorage, []cloudprovider.ICloudStorage, compare.SyncResult) {
  863. var resId string
  864. if zone != nil {
  865. resId = fmt.Sprintf("%s-%s", provider.Id, zone.Id)
  866. } else {
  867. resId = provider.Id
  868. }
  869. lockman.LockRawObject(ctx, "storages", resId)
  870. defer lockman.ReleaseRawObject(ctx, "storages", resId)
  871. localStorages := make([]SStorage, 0)
  872. remoteStorages := make([]cloudprovider.ICloudStorage, 0)
  873. syncResult := compare.SyncResult{}
  874. err := manager.scanLegacyStorages()
  875. if err != nil {
  876. syncResult.Error(err)
  877. return nil, nil, syncResult
  878. }
  879. dbStorages, err := manager.getStoragesByZone(zone, provider)
  880. if err != nil {
  881. syncResult.Error(err)
  882. return nil, nil, syncResult
  883. }
  884. removed := make([]SStorage, 0)
  885. commondb := make([]SStorage, 0)
  886. commonext := make([]cloudprovider.ICloudStorage, 0)
  887. added := make([]cloudprovider.ICloudStorage, 0)
  888. err = compare.CompareSets(dbStorages, storages, &removed, &commondb, &commonext, &added)
  889. if err != nil {
  890. syncResult.Error(err)
  891. return nil, nil, syncResult
  892. }
  893. for i := 0; i < len(removed); i += 1 {
  894. // may be a fake storage for prepaid recycle host
  895. if removed[i].IsPrepaidRecycleResource() {
  896. continue
  897. }
  898. err = removed[i].syncRemoveCloudStorage(ctx, userCred)
  899. if err != nil {
  900. syncResult.DeleteError(err)
  901. } else {
  902. syncResult.Delete()
  903. }
  904. }
  905. for i := 0; i < len(commondb); i += 1 {
  906. if !xor {
  907. err = commondb[i].syncWithCloudStorage(ctx, userCred, commonext[i], provider)
  908. if err != nil {
  909. syncResult.UpdateError(err)
  910. continue
  911. }
  912. }
  913. localStorages = append(localStorages, commondb[i])
  914. remoteStorages = append(remoteStorages, commonext[i])
  915. syncResult.Update()
  916. }
  917. for i := 0; i < len(added); i += 1 {
  918. storage, err := manager.newFromCloudStorage(ctx, userCred, added[i], provider, zone)
  919. if err != nil {
  920. syncResult.AddError(err)
  921. continue
  922. }
  923. localStorages = append(localStorages, *storage)
  924. remoteStorages = append(remoteStorages, added[i])
  925. syncResult.Add()
  926. }
  927. return localStorages, remoteStorages, syncResult
  928. }
  929. func (self *SStorage) syncRemoveCloudStorage(ctx context.Context, userCred mcclient.TokenCredential) error {
  930. lockman.LockObject(ctx, self)
  931. defer lockman.ReleaseObject(ctx, self)
  932. return self.purge(ctx, userCred)
  933. }
  934. var CapacityUsedCloudStorageProvider = []string{
  935. api.CLOUD_PROVIDER_VMWARE,
  936. }
  937. func (sm *SStorageManager) SyncCapacityUsedForEsxiStorage(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
  938. cpQ := CloudproviderManager.Query("id").Equals("provider", api.CLOUD_PROVIDER_VMWARE)
  939. cloudproviders := make([]SCloudprovider, 0)
  940. err := db.FetchModelObjects(CloudproviderManager, cpQ, &cloudproviders)
  941. if err != nil {
  942. log.Errorf("unable to FetchModelObjects: %v", err)
  943. }
  944. for i := range cloudproviders {
  945. cp := cloudproviders[i]
  946. icp, err := cp.GetProvider(ctx)
  947. if err != nil {
  948. log.Errorf("unable to GetProvider: %v", err)
  949. continue
  950. }
  951. iregion, err := icp.GetOnPremiseIRegion()
  952. if err != nil {
  953. log.Errorf("unable to GetOnPremiseIRegion: %v", err)
  954. continue
  955. }
  956. css, err := iregion.GetIStorages()
  957. if err != nil {
  958. log.Errorf("unable to GetIStorages: %v", err)
  959. continue
  960. }
  961. storageSizeMap := make(map[string]int64, len(css))
  962. for i := range css {
  963. id := css[i].GetGlobalId()
  964. size := css[i].GetCapacityUsedMB()
  965. storageSizeMap[id] = size
  966. }
  967. sQ := sm.Query().Equals("manager_id", cp.GetId())
  968. storages := make([]SStorage, 0, 5)
  969. err = db.FetchModelObjects(sm, sQ, &storages)
  970. if err != nil {
  971. log.Errorf("unable to fetch storages with sql %q: %v", sQ.String(), err)
  972. continue
  973. }
  974. for i := range storages {
  975. s := &storages[i]
  976. newSize, ok := storageSizeMap[s.GetExternalId()]
  977. if !ok {
  978. log.Warningf("can't find usedSize for storage %q", s.GetId())
  979. continue
  980. }
  981. _, err = db.Update(s, func() error {
  982. s.ActualCapacityUsed = newSize
  983. return nil
  984. })
  985. if err != nil {
  986. log.Errorf("unable to udpate storage %q: %v", s.GetId(), err)
  987. }
  988. }
  989. }
  990. }
  991. func (self *SStorage) syncWithCloudStorage(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudStorage, provider *SCloudprovider) error {
  992. diff, err := db.UpdateWithLock(ctx, self, func() error {
  993. // self.Name = extStorage.GetName()
  994. self.Status = ext.GetStatus()
  995. self.StorageType = ext.GetStorageType()
  996. if provider != nil && !utils.IsInStringArray(provider.Provider, strings.Split(options.Options.SkipSyncStorageConfigInfoProviders, ",")) {
  997. self.MediumType = ext.GetMediumType()
  998. if capacity := ext.GetCapacityMB(); capacity != 0 {
  999. self.Capacity = capacity
  1000. }
  1001. if capacity := ext.GetCapacityUsedMB(); capacity != 0 {
  1002. self.ActualCapacityUsed = capacity
  1003. }
  1004. }
  1005. self.StorageConf = ext.GetStorageConf()
  1006. self.Enabled = tristate.NewFromBool(ext.GetEnabled())
  1007. self.IsEmulated = ext.IsEmulated()
  1008. self.IsSysDiskStore = tristate.NewFromBool(ext.IsSysDiskStore())
  1009. return nil
  1010. })
  1011. if err != nil {
  1012. log.Errorf("syncWithCloudZone error %s", err)
  1013. return err
  1014. }
  1015. if provider != nil {
  1016. SyncCloudDomain(userCred, self, provider.GetOwnerId())
  1017. self.SyncShareState(ctx, userCred, provider.getAccountShareInfo())
  1018. if account, _ := provider.GetCloudaccount(); account != nil {
  1019. syncMetadata(ctx, userCred, self, ext, account.ReadOnly)
  1020. }
  1021. }
  1022. db.OpsLog.LogSyncUpdate(self, diff, userCred)
  1023. return nil
  1024. }
  1025. func (manager *SStorageManager) newFromCloudStorage(ctx context.Context, userCred mcclient.TokenCredential, extStorage cloudprovider.ICloudStorage, provider *SCloudprovider, zone *SZone) (*SStorage, error) {
  1026. storage := SStorage{}
  1027. storage.SetModelManager(manager, &storage)
  1028. storage.Status = extStorage.GetStatus()
  1029. storage.ExternalId = extStorage.GetGlobalId()
  1030. storage.ZoneId = zone.Id
  1031. storage.StorageType = extStorage.GetStorageType()
  1032. storage.MediumType = extStorage.GetMediumType()
  1033. storage.StorageConf = extStorage.GetStorageConf()
  1034. storage.Capacity = extStorage.GetCapacityMB()
  1035. storage.ActualCapacityUsed = extStorage.GetCapacityUsedMB()
  1036. storage.Cmtbound = 1.0
  1037. storage.Enabled = tristate.NewFromBool(extStorage.GetEnabled())
  1038. storage.IsEmulated = extStorage.IsEmulated()
  1039. storage.ManagerId = provider.Id
  1040. storage.IsSysDiskStore = tristate.NewFromBool(extStorage.IsSysDiskStore())
  1041. var err = func() error {
  1042. lockman.LockRawObject(ctx, manager.Keyword(), "name")
  1043. defer lockman.ReleaseRawObject(ctx, manager.Keyword(), "name")
  1044. newName, err := db.GenerateName(ctx, manager, userCred, extStorage.GetName())
  1045. if err != nil {
  1046. return err
  1047. }
  1048. storage.Name = newName
  1049. return manager.TableSpec().Insert(ctx, &storage)
  1050. }()
  1051. if err != nil {
  1052. return nil, errors.Wrapf(err, "Insert")
  1053. }
  1054. SyncCloudDomain(userCred, &storage, provider.GetOwnerId())
  1055. syncMetadata(ctx, userCred, &storage, extStorage, false)
  1056. if provider != nil {
  1057. storage.SyncShareState(ctx, userCred, provider.getAccountShareInfo())
  1058. }
  1059. db.OpsLog.LogEvent(&storage, db.ACT_CREATE, storage.GetShortDesc(ctx), userCred)
  1060. return &storage, nil
  1061. }
  1062. type StorageCapacityStat struct {
  1063. TotalSize int64
  1064. TotalSizeVirtual float64
  1065. }
  1066. func filterDisksByScope(ctx context.Context, scope rbacscope.TRbacScope, ownerId mcclient.IIdentityProvider, pendingDeleted bool, includeSystem bool, policyResult rbacutils.SPolicyResult) *sqlchemy.SSubQuery {
  1067. q := DiskManager.Query()
  1068. switch scope {
  1069. case rbacscope.ScopeSystem:
  1070. case rbacscope.ScopeDomain:
  1071. q = q.Filter(sqlchemy.Equals(q.Field("domain_id"), ownerId.GetProjectDomainId()))
  1072. case rbacscope.ScopeProject:
  1073. q = q.Filter(sqlchemy.Equals(q.Field("tenant_id"), ownerId.GetProjectId()))
  1074. }
  1075. if pendingDeleted {
  1076. q = q.IsTrue("pending_deleted")
  1077. } else {
  1078. q = q.IsFalse("pending_deleted")
  1079. }
  1080. if !includeSystem {
  1081. q = q.IsFalse("is_system")
  1082. }
  1083. return db.ObjectIdQueryWithPolicyResult(ctx, q, DiskManager, policyResult).SubQuery()
  1084. }
  1085. func (manager *SStorageManager) disksReadyQ(ctx context.Context, scope rbacscope.TRbacScope, ownerId mcclient.IIdentityProvider, pendingDeleted bool, includeSystem bool, policyResult rbacutils.SPolicyResult) *sqlchemy.SSubQuery {
  1086. disks := filterDisksByScope(ctx, scope, ownerId, pendingDeleted, includeSystem, policyResult)
  1087. q := disks.Query(
  1088. disks.Field("storage_id"),
  1089. sqlchemy.SUM("used_capacity", disks.Field("disk_size")),
  1090. sqlchemy.COUNT("used_count"),
  1091. ).Equals("status", api.DISK_READY)
  1092. q = q.GroupBy(disks.Field("storage_id"))
  1093. return q.SubQuery()
  1094. }
  1095. func (manager *SStorageManager) diskIsAttachedQ(ctx context.Context, isAttached bool, scope rbacscope.TRbacScope, ownerId mcclient.IIdentityProvider, pendingDeleted bool, includeSystem bool, policyResult rbacutils.SPolicyResult) *sqlchemy.SSubQuery {
  1096. sumKey := "attached_used_capacity"
  1097. countKey := "attached_count"
  1098. cond := sqlchemy.In
  1099. if !isAttached {
  1100. sumKey = "detached_used_capacity"
  1101. countKey = "detached_count"
  1102. cond = sqlchemy.NotIn
  1103. }
  1104. sq := GuestdiskManager.Query("disk_id").SubQuery()
  1105. disks := filterDisksByScope(ctx, scope, ownerId, pendingDeleted, includeSystem, policyResult)
  1106. disks = disks.Query().Filter(cond(disks.Field("id"), sq)).SubQuery()
  1107. q := disks.Query(
  1108. disks.Field("storage_id"),
  1109. sqlchemy.SUM(sumKey, disks.Field("disk_size")),
  1110. sqlchemy.COUNT(countKey),
  1111. ).Equals("status", api.DISK_READY).GroupBy(disks.Field("storage_id"))
  1112. return q.SubQuery()
  1113. }
  1114. func (manager *SStorageManager) diskAttachedQ(ctx context.Context, scope rbacscope.TRbacScope, ownerId mcclient.IIdentityProvider, pendingDeleted bool, includeSystem bool, policyResult rbacutils.SPolicyResult) *sqlchemy.SSubQuery {
  1115. return manager.diskIsAttachedQ(ctx, true, scope, ownerId, pendingDeleted, includeSystem, policyResult)
  1116. }
  1117. func (manager *SStorageManager) diskDetachedQ(ctx context.Context, scope rbacscope.TRbacScope, ownerId mcclient.IIdentityProvider, pendingDeleted bool, includeSystem bool, policyResult rbacutils.SPolicyResult) *sqlchemy.SSubQuery {
  1118. return manager.diskIsAttachedQ(ctx, false, scope, ownerId, pendingDeleted, includeSystem, policyResult)
  1119. }
  1120. func (manager *SStorageManager) disksFailedQ(ctx context.Context, scope rbacscope.TRbacScope, ownerId mcclient.IIdentityProvider, pendingDeleted bool, includeSystem bool, policyResult rbacutils.SPolicyResult) *sqlchemy.SSubQuery {
  1121. disks := filterDisksByScope(ctx, scope, ownerId, pendingDeleted, includeSystem, policyResult)
  1122. q := disks.Query(
  1123. disks.Field("storage_id"),
  1124. sqlchemy.SUM("failed_capacity", disks.Field("disk_size")),
  1125. sqlchemy.COUNT("failed_count"),
  1126. ).NotEquals("status", api.DISK_READY)
  1127. q = q.GroupBy(disks.Field("storage_id"))
  1128. return q.SubQuery()
  1129. }
  1130. func (manager *SStorageManager) totalCapacityQ(
  1131. ctx context.Context,
  1132. rangeObjs []db.IStandaloneModel, hostTypes []string,
  1133. resourceTypes []string,
  1134. providers []string, brands []string, cloudEnv string,
  1135. scope rbacscope.TRbacScope, ownerId mcclient.IIdentityProvider,
  1136. pendingDeleted bool, includeSystem bool,
  1137. storageOwnership bool,
  1138. policyResult rbacutils.SPolicyResult,
  1139. ) *sqlchemy.SQuery {
  1140. stmt := manager.disksReadyQ(ctx, scope, ownerId, pendingDeleted, includeSystem, policyResult)
  1141. stmt2 := manager.disksFailedQ(ctx, scope, ownerId, pendingDeleted, includeSystem, policyResult)
  1142. attachedDisks := manager.diskAttachedQ(ctx, scope, ownerId, pendingDeleted, includeSystem, policyResult)
  1143. detachedDisks := manager.diskDetachedQ(ctx, scope, ownerId, pendingDeleted, includeSystem, policyResult)
  1144. sq := manager.Query()
  1145. if len(hostTypes) > 0 || len(resourceTypes) > 0 || len(rangeObjs) > 0 {
  1146. hosts := HostManager.Query().SubQuery()
  1147. subq := HoststorageManager.Query("storage_id")
  1148. subq = subq.Join(hosts, sqlchemy.Equals(hosts.Field("id"), subq.Field("host_id")))
  1149. subq = subq.Filter(sqlchemy.IsTrue(hosts.Field("enabled")))
  1150. subq = subq.Filter(sqlchemy.Equals(hosts.Field("host_status"), api.HOST_ONLINE))
  1151. subq = AttachUsageQuery(subq, hosts, hostTypes, resourceTypes, nil, nil, "", rangeObjs)
  1152. sq = sq.Filter(sqlchemy.In(sq.Field("id"), subq.SubQuery()))
  1153. }
  1154. if len(rangeObjs) > 0 || len(providers) > 0 || len(brands) > 0 || cloudEnv != "" {
  1155. sq = CloudProviderFilter(sq, sq.Field("manager_id"), providers, brands, cloudEnv)
  1156. sq = RangeObjectsFilter(sq, rangeObjs, nil, sq.Field("zone_id"), sq.Field("manager_id"), nil, sq.Field("id"))
  1157. }
  1158. if storageOwnership {
  1159. switch scope {
  1160. case rbacscope.ScopeSystem:
  1161. case rbacscope.ScopeDomain, rbacscope.ScopeProject:
  1162. sq = sq.Equals("domain_id", ownerId.GetProjectDomainId())
  1163. }
  1164. }
  1165. sq = db.ObjectIdQueryWithPolicyResult(ctx, sq, manager, policyResult)
  1166. storages := sq.SubQuery()
  1167. q := storages.Query(
  1168. storages.Field("capacity"),
  1169. storages.Field("reserved"),
  1170. storages.Field("cmtbound"),
  1171. storages.Field("actual_capacity_used"),
  1172. storages.Field("storage_type"),
  1173. storages.Field("medium_type"),
  1174. stmt.Field("used_capacity"),
  1175. stmt.Field("used_count"),
  1176. stmt2.Field("failed_capacity"),
  1177. stmt2.Field("failed_count"),
  1178. attachedDisks.Field("attached_used_capacity"),
  1179. attachedDisks.Field("attached_count"),
  1180. detachedDisks.Field("detached_used_capacity"),
  1181. detachedDisks.Field("detached_count"),
  1182. )
  1183. q = q.LeftJoin(stmt, sqlchemy.Equals(stmt.Field("storage_id"), storages.Field("id")))
  1184. q = q.LeftJoin(stmt2, sqlchemy.Equals(stmt2.Field("storage_id"), storages.Field("id")))
  1185. q = q.LeftJoin(attachedDisks, sqlchemy.Equals(attachedDisks.Field("storage_id"), storages.Field("id")))
  1186. q = q.LeftJoin(detachedDisks, sqlchemy.Equals(detachedDisks.Field("storage_id"), storages.Field("id")))
  1187. return q
  1188. }
  1189. type StorageStat struct {
  1190. Capacity int
  1191. Reserved int
  1192. Cmtbound float32
  1193. ActualCapacityUsed int64
  1194. StorageType string
  1195. MediumType string
  1196. UsedCapacity int
  1197. UsedCount int
  1198. FailedCapacity int
  1199. FailedCount int
  1200. AttachedUsedCapacity int
  1201. AttachedCount int
  1202. DetachedUsedCapacity int
  1203. DetachedCount int
  1204. }
  1205. type StoragesCapacityStat struct {
  1206. Capacity int64
  1207. CapacityVirtual float64
  1208. CapacityUsed int64
  1209. ActualCapacityUsed int64
  1210. CountUsed int
  1211. CapacityUnready int64
  1212. CountUnready int
  1213. AttachedCapacity int64
  1214. CountAttached int
  1215. DetachedCapacity int64
  1216. CountDetached int
  1217. MediumeCapacity map[string]int64
  1218. StorageTypeCapacity map[string]int64
  1219. MediumeCapacityUsed map[string]int64
  1220. StorageTypeCapacityUsed map[string]int64
  1221. AttachedMediumeCapacity map[string]int64
  1222. AttachedStorageTypeCapacity map[string]int64
  1223. DetachedMediumeCapacity map[string]int64
  1224. DetachedStorageTypeCapacity map[string]int64
  1225. }
  1226. func (manager *SStorageManager) calculateCapacity(q *sqlchemy.SQuery) StoragesCapacityStat {
  1227. stats := make([]StorageStat, 0)
  1228. err := q.All(&stats)
  1229. if err != nil {
  1230. log.Errorf("calculateCapacity: %v", err)
  1231. }
  1232. var (
  1233. tCapa int64 = 0
  1234. tVCapa float64 = 0
  1235. tUsed int64 = 0
  1236. aUsed int64 = 0
  1237. cUsed int = 0
  1238. tFailed int64 = 0
  1239. cFailed int = 0
  1240. atCapa int64 = 0
  1241. atCount int = 0
  1242. dtCapa int64 = 0
  1243. dtCount int = 0
  1244. mCapa = map[string]int64{}
  1245. sCapa = map[string]int64{}
  1246. mFailed = map[string]int64{}
  1247. sFailed = map[string]int64{}
  1248. matCapa = map[string]int64{}
  1249. satCapa = map[string]int64{}
  1250. mdtCapa = map[string]int64{}
  1251. sdtCapa = map[string]int64{}
  1252. mCapaUsed = map[string]int64{}
  1253. sCapaUsed = map[string]int64{}
  1254. )
  1255. var add = func(m, s map[string]int64, mediumType, storageType string, capa int64) (map[string]int64, map[string]int64) {
  1256. _, ok := m[mediumType]
  1257. if !ok {
  1258. m[mediumType] = 0
  1259. }
  1260. m[mediumType] += capa
  1261. _, ok = s[storageType]
  1262. if !ok {
  1263. s[storageType] = 0
  1264. }
  1265. s[storageType] += capa
  1266. return m, s
  1267. }
  1268. for _, stat := range stats {
  1269. tCapa += int64(stat.Capacity - stat.Reserved)
  1270. if stat.Cmtbound == 0 {
  1271. stat.Cmtbound = options.Options.DefaultStorageOvercommitBound
  1272. }
  1273. mCapa, sCapa = add(mCapa, sCapa, stat.MediumType, stat.StorageType, int64(stat.Capacity-stat.Reserved))
  1274. tVCapa += float64(stat.Capacity-stat.Reserved) * float64(stat.Cmtbound)
  1275. mCapaUsed, sCapaUsed = add(mCapaUsed, sCapaUsed, stat.MediumType, stat.StorageType, int64(stat.UsedCapacity))
  1276. tUsed += int64(stat.UsedCapacity)
  1277. aUsed += int64(stat.ActualCapacityUsed)
  1278. cUsed += stat.UsedCount
  1279. tFailed += int64(stat.FailedCapacity)
  1280. mFailed, sFailed = add(mFailed, sFailed, stat.MediumType, stat.StorageType, int64(stat.FailedCapacity))
  1281. cFailed += stat.FailedCount
  1282. atCapa += int64(stat.AttachedUsedCapacity)
  1283. matCapa, satCapa = add(matCapa, satCapa, stat.MediumType, stat.StorageType, int64(stat.AttachedUsedCapacity))
  1284. atCount += stat.AttachedCount
  1285. dtCapa += int64(stat.DetachedUsedCapacity)
  1286. mdtCapa, sdtCapa = add(mdtCapa, sdtCapa, stat.MediumType, stat.StorageType, int64(stat.DetachedUsedCapacity))
  1287. dtCount += stat.DetachedCount
  1288. }
  1289. return StoragesCapacityStat{
  1290. Capacity: tCapa,
  1291. MediumeCapacity: mCapa,
  1292. StorageTypeCapacity: sCapa,
  1293. CapacityVirtual: tVCapa,
  1294. CapacityUsed: tUsed,
  1295. ActualCapacityUsed: aUsed,
  1296. MediumeCapacityUsed: mCapaUsed,
  1297. StorageTypeCapacityUsed: sCapaUsed,
  1298. CountUsed: cUsed,
  1299. CapacityUnready: tFailed,
  1300. CountUnready: cFailed,
  1301. AttachedCapacity: atCapa,
  1302. AttachedMediumeCapacity: matCapa,
  1303. AttachedStorageTypeCapacity: satCapa,
  1304. CountAttached: atCount,
  1305. DetachedCapacity: dtCapa,
  1306. DetachedMediumeCapacity: mdtCapa,
  1307. DetachedStorageTypeCapacity: sdtCapa,
  1308. CountDetached: dtCount,
  1309. }
  1310. }
  1311. func (manager *SStorageManager) TotalCapacity(
  1312. ctx context.Context,
  1313. rangeObjs []db.IStandaloneModel,
  1314. hostTypes []string,
  1315. resourceTypes []string,
  1316. providers []string, brands []string, cloudEnv string,
  1317. scope rbacscope.TRbacScope,
  1318. ownerId mcclient.IIdentityProvider,
  1319. pendingDeleted bool, includeSystem bool,
  1320. storageOwnership bool,
  1321. policyResult rbacutils.SPolicyResult,
  1322. ) StoragesCapacityStat {
  1323. res1 := manager.calculateCapacity(
  1324. manager.totalCapacityQ(
  1325. ctx,
  1326. rangeObjs,
  1327. hostTypes,
  1328. resourceTypes,
  1329. providers, brands, cloudEnv,
  1330. scope, ownerId,
  1331. pendingDeleted, includeSystem,
  1332. storageOwnership,
  1333. policyResult,
  1334. ),
  1335. )
  1336. return res1
  1337. }
  1338. func (self *SStorage) createDisk(ctx context.Context, name string, diskConfig *api.DiskConfig, userCred mcclient.TokenCredential,
  1339. ownerId mcclient.IIdentityProvider, autoDelete bool, isSystem bool,
  1340. billingType billing_api.TBillingType, billingCycle string,
  1341. encryptKeyId string,
  1342. ) (*SDisk, error) {
  1343. disk := SDisk{}
  1344. disk.SetModelManager(DiskManager, &disk)
  1345. disk.Name = name
  1346. if err := disk.fetchDiskInfo(diskConfig); err != nil {
  1347. return nil, errors.Wrap(err, "fetchDiskInfo")
  1348. }
  1349. disk.StorageId = self.Id
  1350. disk.AutoDelete = autoDelete
  1351. disk.ProjectId = ownerId.GetProjectId()
  1352. disk.ProjectSrc = string(apis.OWNER_SOURCE_LOCAL)
  1353. disk.DomainId = ownerId.GetProjectDomainId()
  1354. disk.IsSystem = isSystem
  1355. disk.Iops = diskConfig.Iops
  1356. disk.Throughput = diskConfig.Throughput
  1357. disk.Preallocation = diskConfig.Preallocation
  1358. disk.AutoReset = diskConfig.AutoReset
  1359. if self.MediumType == api.DISK_TYPE_SSD {
  1360. disk.IsSsd = true
  1361. } else {
  1362. disk.IsSsd = false
  1363. }
  1364. disk.BillingType = billingType
  1365. disk.BillingCycle = billingCycle
  1366. disk.EncryptKeyId = encryptKeyId
  1367. err := disk.GetModelManager().TableSpec().Insert(ctx, &disk)
  1368. if err != nil {
  1369. return nil, err
  1370. }
  1371. db.OpsLog.LogEvent(&disk, db.ACT_CREATE, disk.GetShortDesc(ctx), userCred)
  1372. return &disk, nil
  1373. }
  1374. func (self *SStorage) GetAllAttachingHosts() []SHost {
  1375. hosts := HostManager.Query().SubQuery()
  1376. hoststorages := HoststorageManager.Query().SubQuery()
  1377. q := hosts.Query()
  1378. q = q.Join(hoststorages, sqlchemy.Equals(hoststorages.Field("host_id"), hosts.Field("id")))
  1379. q = q.Filter(sqlchemy.Equals(hoststorages.Field("storage_id"), self.Id))
  1380. q = q.Filter(sqlchemy.IsTrue(hosts.Field("enabled")))
  1381. q = q.Filter(sqlchemy.Equals(hosts.Field("host_status"), api.HOST_ONLINE))
  1382. ret := make([]SHost, 0)
  1383. err := db.FetchModelObjects(HostManager, q, &ret)
  1384. if err != nil {
  1385. log.Errorf("%s", err)
  1386. return nil
  1387. }
  1388. return ret
  1389. }
  1390. func (self *SStorage) SetStoragecache(userCred mcclient.TokenCredential, cache *SStoragecache) error {
  1391. if self.StoragecacheId == cache.Id {
  1392. return nil
  1393. }
  1394. diff, err := db.Update(self, func() error {
  1395. self.StoragecacheId = cache.Id
  1396. return nil
  1397. })
  1398. if err != nil {
  1399. return err
  1400. }
  1401. db.OpsLog.LogEvent(self, db.ACT_UPDATE, diff, userCred)
  1402. return nil
  1403. }
  1404. func (self *SStorage) GetStoragecache() *SStoragecache {
  1405. obj, err := StoragecacheManager.FetchById(self.StoragecacheId)
  1406. if err != nil {
  1407. log.Errorf("cannot find storage cache??? %s", err)
  1408. return nil
  1409. }
  1410. return obj.(*SStoragecache)
  1411. }
  1412. func (self *SStorage) PerformCacheImage(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CacheImageInput) (jsonutils.JSONObject, error) {
  1413. cache := self.GetStoragecache()
  1414. if cache == nil {
  1415. return nil, httperrors.NewInternalServerError("storage cache is missing")
  1416. }
  1417. return cache.PerformCacheImage(ctx, userCred, query, input)
  1418. }
  1419. func (self *SStorage) PerformUncacheImage(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  1420. cache := self.GetStoragecache()
  1421. if cache == nil {
  1422. return nil, httperrors.NewInternalServerError("storage cache is missing")
  1423. }
  1424. return cache.PerformUncacheImage(ctx, userCred, query, data)
  1425. }
  1426. func (self *SStorage) GetIStorage(ctx context.Context) (cloudprovider.ICloudStorage, error) {
  1427. provider, err := self.GetDriver(ctx)
  1428. if err != nil {
  1429. return nil, errors.Wrap(err, "self.GetDriver")
  1430. }
  1431. var iRegion cloudprovider.ICloudRegion
  1432. if provider.GetFactory().IsOnPremise() {
  1433. iRegion, err = provider.GetOnPremiseIRegion()
  1434. } else {
  1435. region, _ := self.GetRegion()
  1436. if region == nil {
  1437. msg := "cannot find region for storage???"
  1438. log.Errorf("%s", msg)
  1439. return nil, fmt.Errorf("%s", msg)
  1440. }
  1441. iRegion, err = provider.GetIRegionById(region.ExternalId)
  1442. }
  1443. if err != nil {
  1444. return nil, errors.Wrap(err, "provider.GetIRegionById")
  1445. }
  1446. istore, err := iRegion.GetIStorageById(self.GetExternalId())
  1447. if err != nil {
  1448. log.Errorf("iRegion.GetIStorageById fail %s", err)
  1449. return nil, errors.Wrapf(err, "iRegion.GetIStorageById(%s)", self.GetExternalId())
  1450. }
  1451. return istore, nil
  1452. }
  1453. func (manager *SStorageManager) FetchStorageById(storageId string) *SStorage {
  1454. obj, err := manager.FetchById(storageId)
  1455. if err != nil {
  1456. log.Errorf("%s", err)
  1457. return nil
  1458. }
  1459. return obj.(*SStorage)
  1460. }
  1461. func (manager *SStorageManager) FetchStorageByIds(ids []string) ([]SStorage, error) {
  1462. objs := make([]SStorage, 0)
  1463. q := manager.Query().In("id", ids)
  1464. if err := db.FetchModelObjects(manager, q, &objs); err != nil {
  1465. return nil, err
  1466. }
  1467. return objs, nil
  1468. }
  1469. func (manager *SStorageManager) InitializeData() error {
  1470. storages := make([]SStorage, 0)
  1471. q := manager.Query()
  1472. q = q.Filter(
  1473. sqlchemy.OR(
  1474. sqlchemy.IsNullOrEmpty(q.Field("zone_id")),
  1475. sqlchemy.AND(
  1476. sqlchemy.IsNullOrEmpty(q.Field("storagecache_id")),
  1477. sqlchemy.Equals(q.Field("storage_type"), api.STORAGE_RBD),
  1478. ),
  1479. ),
  1480. )
  1481. err := db.FetchModelObjects(manager, q, &storages)
  1482. if err != nil {
  1483. return err
  1484. }
  1485. for _, s := range storages {
  1486. if len(s.ZoneId) == 0 {
  1487. zoneId := ""
  1488. hosts, _ := s.GetAttachedHosts()
  1489. if hosts != nil && len(hosts) > 0 {
  1490. zoneId = hosts[0].ZoneId
  1491. } else {
  1492. log.Fatalf("Cannot locate zoneId for storage %s", s.Name)
  1493. }
  1494. db.Update(&s, func() error {
  1495. s.ZoneId = zoneId
  1496. return nil
  1497. })
  1498. }
  1499. if len(s.StoragecacheId) == 0 && s.StorageType == api.STORAGE_RBD {
  1500. storagecache := &SStoragecache{}
  1501. storagecache.SetModelManager(StoragecacheManager, storagecache)
  1502. storagecache.Name = "rbd-" + s.Id
  1503. if pool, err := s.StorageConf.GetString("pool"); err != nil {
  1504. log.Fatalf("Get storage %s pool info error", s.Name)
  1505. } else {
  1506. storagecache.Path = "rbd:" + pool
  1507. if err := StoragecacheManager.TableSpec().Insert(context.TODO(), storagecache); err != nil {
  1508. log.Fatalf("Cannot Add storagecache for %s", s.Name)
  1509. } else {
  1510. db.Update(&s, func() error {
  1511. s.StoragecacheId = storagecache.Id
  1512. return nil
  1513. })
  1514. }
  1515. }
  1516. }
  1517. }
  1518. sq := CloudproviderManager.Query("id").Equals("provider", api.CLOUD_PROVIDER_ALIYUN).SubQuery()
  1519. q = manager.Query().NotEquals("medium_type", api.DISK_TYPE_SSD).In("manager_id", sq)
  1520. storages = make([]SStorage, 0)
  1521. err = db.FetchModelObjects(manager, q, &storages)
  1522. if err != nil {
  1523. return err
  1524. }
  1525. for i := range storages {
  1526. db.Update(&storages[i], func() error {
  1527. storages[i].MediumType = api.DISK_TYPE_SSD
  1528. return nil
  1529. })
  1530. }
  1531. return nil
  1532. }
  1533. func (manager *SStorageManager) IsStorageTypeExist(storageType string) (string, bool) {
  1534. storages := []SStorage{}
  1535. q := manager.Query().Equals("storage_type", storageType)
  1536. if err := db.FetchModelObjects(manager, q, &storages); err != nil {
  1537. return "", false
  1538. }
  1539. if len(storages) == 0 {
  1540. return "", false
  1541. }
  1542. return storages[0].StorageType, true
  1543. }
  1544. // 块存储列表
  1545. func (manager *SStorageManager) ListItemFilter(
  1546. ctx context.Context,
  1547. q *sqlchemy.SQuery,
  1548. userCred mcclient.TokenCredential,
  1549. query api.StorageListInput,
  1550. ) (*sqlchemy.SQuery, error) {
  1551. var err error
  1552. q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput)
  1553. if err != nil {
  1554. return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter")
  1555. }
  1556. q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
  1557. if err != nil {
  1558. return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
  1559. }
  1560. q, err = manager.SZoneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ZonalFilterListInput)
  1561. if err != nil {
  1562. return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemFilter")
  1563. }
  1564. q, err = manager.SEnabledStatusInfrasResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusInfrasResourceBaseListInput)
  1565. if err != nil {
  1566. return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.ListItemFilter")
  1567. }
  1568. if query.Share != nil && *query.Share {
  1569. q = q.Filter(sqlchemy.NotIn(q.Field("storage_type"), api.STORAGE_LOCAL_TYPES))
  1570. }
  1571. if query.Local != nil && *query.Local {
  1572. q = q.Filter(sqlchemy.In(q.Field("storage_type"), api.STORAGE_LOCAL_TYPES))
  1573. }
  1574. if len(query.StorageType) > 0 {
  1575. q = q.Equals("storage_type", query.StorageType)
  1576. }
  1577. if len(query.SchedtagId) > 0 {
  1578. schedTag, err := SchedtagManager.FetchByIdOrName(ctx, nil, query.SchedtagId)
  1579. if err != nil {
  1580. if errors.Cause(err) == sql.ErrNoRows {
  1581. return nil, httperrors.NewResourceNotFoundError2(SchedtagManager.Keyword(), query.SchedtagId)
  1582. }
  1583. return nil, httperrors.NewGeneralError(err)
  1584. }
  1585. sq := StorageschedtagManager.Query("storage_id").Equals("schedtag_id", schedTag.GetId()).SubQuery()
  1586. q = q.In("id", sq)
  1587. }
  1588. if query.Usable != nil && *query.Usable {
  1589. hostStorageTable := HoststorageManager.Query().SubQuery()
  1590. hostTable := HostManager.Query().SubQuery()
  1591. sq1 := hostStorageTable.Query(hostStorageTable.Field("storage_id")).
  1592. Join(hostTable, sqlchemy.Equals(hostTable.Field("id"), hostStorageTable.Field("host_id"))).
  1593. Filter(sqlchemy.Equals(hostTable.Field("host_status"), api.HOST_ONLINE)).
  1594. Filter(sqlchemy.IsTrue(hostTable.Field("enabled"))).
  1595. Filter(sqlchemy.IsNullOrEmpty(hostTable.Field("manager_id")))
  1596. providerTable := usableCloudProviders().SubQuery()
  1597. sq2 := hostStorageTable.Query(hostStorageTable.Field("storage_id")).
  1598. Join(hostTable, sqlchemy.Equals(hostTable.Field("id"), hostStorageTable.Field("host_id"))).
  1599. Join(providerTable, sqlchemy.Equals(hostTable.Field("manager_id"), providerTable.Field("id")))
  1600. q = q.Filter(
  1601. sqlchemy.OR(
  1602. sqlchemy.In(q.Field("id"), sq1),
  1603. sqlchemy.In(q.Field("id"), sq2),
  1604. )).
  1605. Filter(sqlchemy.In(q.Field("status"), []string{api.STORAGE_ENABLED, api.STORAGE_ONLINE})).
  1606. Filter(sqlchemy.IsTrue(q.Field("enabled")))
  1607. }
  1608. if len(query.HostSchedtagId) > 0 {
  1609. schedTagObj, err := SchedtagManager.FetchByIdOrName(ctx, userCred, query.HostSchedtagId)
  1610. if err != nil {
  1611. if errors.Cause(err) == sql.ErrNoRows {
  1612. return nil, errors.Wrapf(httperrors.ErrResourceNotFound, "%s %s", SchedtagManager.Keyword(), query.HostSchedtagId)
  1613. } else {
  1614. return nil, errors.Wrap(err, "SchedtagManager.FetchByIdOrName")
  1615. }
  1616. }
  1617. subq := HoststorageManager.Query("storage_id")
  1618. hostschedtags := HostschedtagManager.Query().Equals("schedtag_id", schedTagObj.GetId()).SubQuery()
  1619. subq = subq.Join(hostschedtags, sqlchemy.Equals(hostschedtags.Field("host_id"), subq.Field("host_id")))
  1620. q = q.In("id", subq.SubQuery())
  1621. }
  1622. if len(query.ImageId) > 0 {
  1623. image, err := CachedimageManager.getImageInfo(ctx, userCred, query.ImageId, false)
  1624. if err != nil {
  1625. return nil, errors.Wrap(err, "CachedimageManager.getImageInfo")
  1626. }
  1627. subq := StorageManager.Query("id")
  1628. storagecaches := StoragecachedimageManager.Query("storagecache_id").Equals("cachedimage_id", image.Id).SubQuery()
  1629. subq = subq.Join(storagecaches, sqlchemy.Equals(subq.Field("storagecache_id"), storagecaches.Field("storagecache_id")))
  1630. q = q.In("id", subq.SubQuery())
  1631. }
  1632. if len(query.ServerId) > 0 {
  1633. guest, err := GuestManager.FetchByIdOrName(ctx, userCred, query.ServerId)
  1634. if err != nil {
  1635. if errors.Cause(err) == sql.ErrNoRows {
  1636. return nil, errors.Wrapf(httperrors.ErrResourceNotFound, "%s %s", GuestManager.Keyword(), query.ServerId)
  1637. } else {
  1638. return nil, errors.Wrapf(err, "GuestManager.FetchByIdOrName %s", query.ServerId)
  1639. }
  1640. }
  1641. query.HostId = guest.(*SGuest).HostId
  1642. }
  1643. if len(query.HostId) > 0 {
  1644. host, err := HostManager.FetchByIdOrName(ctx, userCred, query.HostId)
  1645. if err != nil {
  1646. if errors.Cause(err) == sql.ErrNoRows {
  1647. return nil, errors.Wrapf(httperrors.ErrResourceNotFound, "%s %s", HostManager.Keyword(), query.HostId)
  1648. } else {
  1649. return nil, errors.Wrapf(err, "HostManager.FetchByIdOrName %s", query.HostId)
  1650. }
  1651. }
  1652. sq := HoststorageManager.Query("storage_id").Equals("host_id", host.GetId())
  1653. q = q.In("id", sq.SubQuery())
  1654. }
  1655. if query.IsBaremetal != nil {
  1656. qf := q.NotEquals
  1657. if *query.IsBaremetal {
  1658. qf = q.Equals
  1659. }
  1660. q = qf("storage_type", api.STORAGE_BAREMETAL)
  1661. }
  1662. return q, err
  1663. }
  1664. func (manager *SStorageManager) OrderByExtraFields(
  1665. ctx context.Context,
  1666. q *sqlchemy.SQuery,
  1667. userCred mcclient.TokenCredential,
  1668. query api.StorageListInput,
  1669. ) (*sqlchemy.SQuery, error) {
  1670. q, err := manager.SEnabledStatusInfrasResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusInfrasResourceBaseListInput)
  1671. if err != nil {
  1672. return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.OrderByExtraFields")
  1673. }
  1674. q, err = manager.SZoneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ZonalFilterListInput)
  1675. if err != nil {
  1676. return nil, errors.Wrap(err, "SZoneResourceBaseManager.OrderByExtraFields")
  1677. }
  1678. q, err = manager.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput)
  1679. if err != nil {
  1680. return nil, errors.Wrap(err, "SManagedResourceBaseManager.OrderByExtraFields")
  1681. }
  1682. return q, nil
  1683. }
  1684. func (manager *SStorageManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  1685. var err error
  1686. q, err = manager.SEnabledStatusInfrasResourceBaseManager.QueryDistinctExtraField(q, field)
  1687. if err == nil {
  1688. return q, nil
  1689. }
  1690. q, err = manager.SZoneResourceBaseManager.QueryDistinctExtraField(q, field)
  1691. if err == nil {
  1692. return q, nil
  1693. }
  1694. q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field)
  1695. if err == nil {
  1696. return q, nil
  1697. }
  1698. return q, httperrors.ErrNotFound
  1699. }
  1700. func (manager *SStorageManager) QueryDistinctExtraFields(q *sqlchemy.SQuery, resource string, fields []string) (*sqlchemy.SQuery, error) {
  1701. var err error
  1702. q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraFields(q, resource, fields)
  1703. if err == nil {
  1704. return q, nil
  1705. }
  1706. return q, httperrors.ErrNotFound
  1707. }
  1708. func (self *SStorage) ClearSchedDescCache() error {
  1709. hosts := self.GetAllAttachingHosts()
  1710. if hosts == nil {
  1711. msg := "get attaching host error"
  1712. log.Errorf("%s", msg)
  1713. return fmt.Errorf("%s", msg)
  1714. }
  1715. for i := 0; i < len(hosts); i += 1 {
  1716. err := hosts[i].ClearSchedDescCache()
  1717. if err != nil {
  1718. log.Errorf("host CleanHostSchedCache error: %v", err)
  1719. return err
  1720. }
  1721. }
  1722. return nil
  1723. }
  1724. func (self *SStorage) getCloudProviderInfo() SCloudProviderInfo {
  1725. var region *SCloudregion
  1726. zone, _ := self.getZone()
  1727. if zone != nil {
  1728. region, _ = zone.GetRegion()
  1729. }
  1730. provider := self.GetCloudprovider()
  1731. return MakeCloudProviderInfo(region, zone, provider)
  1732. }
  1733. func (self *SStorage) GetShortDesc(ctx context.Context) *jsonutils.JSONDict {
  1734. desc := self.SStandaloneResourceBase.GetShortDesc(ctx)
  1735. info := self.getCloudProviderInfo()
  1736. desc.Update(jsonutils.Marshal(&info))
  1737. return desc
  1738. }
  1739. func (self *SStorage) IsPrepaidRecycleResource() bool {
  1740. if !self.IsLocal() {
  1741. return false
  1742. }
  1743. hosts, _ := self.GetAttachedHosts()
  1744. if len(hosts) != 1 {
  1745. return false
  1746. }
  1747. return hosts[0].IsPrepaidRecycleResource()
  1748. }
  1749. func (self *SStorage) GetSchedtags() []SSchedtag {
  1750. return GetSchedtags(StorageschedtagManager, self.Id)
  1751. }
  1752. func (self *SStorage) GetDynamicConditionInput() *jsonutils.JSONDict {
  1753. return jsonutils.Marshal(self).(*jsonutils.JSONDict)
  1754. }
  1755. func (self *SStorage) PerformSetSchedtag(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  1756. return PerformSetResourceSchedtag(self, ctx, userCred, query, data)
  1757. }
  1758. func (self *SStorage) PerformSetCommitBound(
  1759. ctx context.Context,
  1760. userCred mcclient.TokenCredential,
  1761. query jsonutils.JSONObject,
  1762. input api.StorageSetCmtBoundInput,
  1763. ) (jsonutils.JSONObject, error) {
  1764. _, err := db.Update(self, func() error {
  1765. if input.Cmtbound != nil {
  1766. self.Cmtbound = *input.Cmtbound
  1767. }
  1768. return nil
  1769. })
  1770. if err != nil {
  1771. return nil, err
  1772. }
  1773. db.OpsLog.LogEvent(self, db.ACT_SET_COMMIT_BOUND, input, userCred)
  1774. logclient.AddActionLogWithContext(ctx, self, logclient.ACT_SET_COMMIT_BOUND, input, userCred, true)
  1775. return nil, nil
  1776. }
  1777. func (self *SStorage) GetSchedtagJointManager() ISchedtagJointManager {
  1778. return StorageschedtagManager
  1779. }
  1780. func (self *SStorage) StartDeleteRbdDisks(ctx context.Context, userCred mcclient.TokenCredential, disksId []string) error {
  1781. data := jsonutils.NewDict()
  1782. data.Add(jsonutils.NewStringArray(disksId), "disks_id")
  1783. task, err := taskman.TaskManager.NewTask(ctx, "StorageDeleteRbdDiskTask", self, userCred, data, "", "", nil)
  1784. if err != nil {
  1785. return err
  1786. }
  1787. task.ScheduleRun(nil)
  1788. return nil
  1789. }
  1790. func (storage *SStorage) PerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeDomainOwnerInput) (jsonutils.JSONObject, error) {
  1791. // not allow to perform public for locally connected storage
  1792. if storage.IsLocal() {
  1793. hosts, _ := storage.GetAttachedHosts()
  1794. if len(hosts) > 0 {
  1795. return nil, errors.Wrap(httperrors.ErrForbidden, "not allow to change owner for local storage")
  1796. }
  1797. }
  1798. return storage.performChangeOwnerInternal(ctx, userCred, query, input)
  1799. }
  1800. func (storage *SStorage) performChangeOwnerInternal(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeDomainOwnerInput) (jsonutils.JSONObject, error) {
  1801. return storage.SEnabledStatusInfrasResourceBase.PerformChangeOwner(ctx, userCred, query, input)
  1802. }
  1803. func (storage *SStorage) GetChangeOwnerRequiredDomainIds() []string {
  1804. requires := stringutils2.SSortedStrings{}
  1805. disks := storage.GetDisks()
  1806. for i := range disks {
  1807. requires = stringutils2.Append(requires, disks[i].DomainId)
  1808. }
  1809. return requires
  1810. }
  1811. func (storage *SStorage) PerformPublic(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPublicDomainInput) (jsonutils.JSONObject, error) {
  1812. // not allow to perform public for locally connected storage
  1813. if storage.IsLocal() {
  1814. hosts, _ := storage.GetAttachedHosts()
  1815. if len(hosts) > 0 {
  1816. return nil, errors.Wrap(httperrors.ErrForbidden, "not allow to perform public for local storage")
  1817. }
  1818. }
  1819. return storage.performPublicInternal(ctx, userCred, query, input)
  1820. }
  1821. func (storage *SStorage) performPublicInternal(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPublicDomainInput) (jsonutils.JSONObject, error) {
  1822. return storage.SEnabledStatusInfrasResourceBase.PerformPublic(ctx, userCred, query, input)
  1823. }
  1824. func (storage *SStorage) PerformPrivate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPrivateInput) (jsonutils.JSONObject, error) {
  1825. // not allow to perform private for locally conencted storage
  1826. if storage.IsLocal() {
  1827. hosts, _ := storage.GetAttachedHosts()
  1828. if len(hosts) > 0 {
  1829. return nil, errors.Wrap(httperrors.ErrForbidden, "not allow to perform private for local storage")
  1830. }
  1831. }
  1832. return storage.performPrivateInternal(ctx, userCred, query, input)
  1833. }
  1834. func (storage *SStorage) performPrivateInternal(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPrivateInput) (jsonutils.JSONObject, error) {
  1835. return storage.SEnabledStatusInfrasResourceBase.PerformPrivate(ctx, userCred, query, input)
  1836. }
  1837. func (manager *SStorageManager) ListItemExportKeys(ctx context.Context,
  1838. q *sqlchemy.SQuery,
  1839. userCred mcclient.TokenCredential,
  1840. keys stringutils2.SSortedStrings,
  1841. ) (*sqlchemy.SQuery, error) {
  1842. q, err := manager.SEnabledStatusInfrasResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  1843. if err != nil {
  1844. return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.ListItemExportKeys")
  1845. }
  1846. if keys.ContainsAny(manager.SManagedResourceBaseManager.GetExportKeys()...) {
  1847. q, err = manager.SManagedResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  1848. if err != nil {
  1849. return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemExportKeys")
  1850. }
  1851. }
  1852. if keys.ContainsAny(manager.SZoneResourceBaseManager.GetExportKeys()...) {
  1853. q, err = manager.SZoneResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  1854. if err != nil {
  1855. return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemExportKeys")
  1856. }
  1857. }
  1858. if keys.Contains("schedtag") {
  1859. schedtagsQ := SchedtagManager.Query("id", "name").SubQuery()
  1860. storageSchedtagQ := StorageschedtagManager.Query("storage_id", "schedtag_id").SubQuery()
  1861. subQ := storageSchedtagQ.Query(storageSchedtagQ.Field("storage_id"), sqlchemy.GROUP_CONCAT("schedtag", schedtagsQ.Field("name")))
  1862. subQ = subQ.Join(schedtagsQ, sqlchemy.Equals(schedtagsQ.Field("id"), storageSchedtagQ.Field("schedtag_id")))
  1863. subQ = subQ.GroupBy(storageSchedtagQ.Field("storage_id"))
  1864. subQT := subQ.SubQuery()
  1865. q = q.LeftJoin(subQT, sqlchemy.Equals(q.Field("id"), subQT.Field("storage_id")))
  1866. q = q.AppendField(subQT.Field("schedtag"))
  1867. }
  1868. return q, nil
  1869. }
  1870. func (storage *SStorage) PerformForceDetachHost(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.StorageForceDetachHostInput) (jsonutils.JSONObject, error) {
  1871. if storage.Enabled.Bool() {
  1872. return nil, httperrors.NewBadRequestError("storage is enabled")
  1873. }
  1874. iHost, err := HostManager.FetchByIdOrName(ctx, userCred, input.HostId)
  1875. if err == sql.ErrNoRows {
  1876. return nil, httperrors.NewNotFoundError("host %s not found", input.HostId)
  1877. } else if err != nil {
  1878. return nil, err
  1879. }
  1880. host := iHost.(*SHost)
  1881. if host.Status == api.HOST_ONLINE {
  1882. return nil, httperrors.NewBadRequestError("can't detach host in status online")
  1883. }
  1884. iHostStorage, err := db.FetchJointByIds(HoststorageManager, host.GetId(), storage.Id, nil)
  1885. if err == sql.ErrNoRows {
  1886. return nil, httperrors.NewNotFoundError("host %s storage %s not found", input.HostId, storage.Name)
  1887. } else if err != nil {
  1888. return nil, err
  1889. }
  1890. hostStorage := iHostStorage.(*SHoststorage)
  1891. hostStorage.SetModelManager(HoststorageManager, hostStorage)
  1892. err = hostStorage.Delete(ctx, userCred)
  1893. if err == nil {
  1894. db.OpsLog.LogDetachEvent(ctx, db.JointMaster(hostStorage), db.JointSlave(hostStorage), userCred, jsonutils.NewString("force detach"))
  1895. }
  1896. return nil, err
  1897. }
  1898. func (storage *SStorage) GetDetailsHardwareInfo(ctx context.Context, userCred mcclient.TokenCredential, _ jsonutils.JSONObject) (*api.StorageHardwareInfo, error) {
  1899. info := new(api.StorageHardwareInfo)
  1900. model := storage.GetMetadata(ctx, api.STORAGE_METADATA_MODEL, userCred)
  1901. if model != "" {
  1902. info.Model = &model
  1903. }
  1904. vendor := storage.GetMetadata(ctx, api.STORAGE_METADATA_VENDOR, userCred)
  1905. if vendor != "" {
  1906. info.Vendor = &vendor
  1907. }
  1908. bw := storage.GetMetadata(ctx, api.STORAGE_METADATA_BANDWIDTH, userCred)
  1909. if bw != "" {
  1910. bwNum, err := strconv.ParseFloat(bw, 64)
  1911. if err != nil {
  1912. return nil, errors.Wrapf(err, "parse bandwidth string: %s", bw)
  1913. }
  1914. info.Bandwidth = bwNum
  1915. }
  1916. return info, nil
  1917. }
  1918. func (storage *SStorage) PerformSetHardwareInfo(ctx context.Context, userCred mcclient.TokenCredential, _ jsonutils.JSONObject, data *api.StorageHardwareInfo) (*api.StorageHardwareInfo, error) {
  1919. return data, storage.setHardwareInfo(ctx, userCred, data)
  1920. }
  1921. func StoragesCleanRecycleDiskfiles(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
  1922. // get shared storages
  1923. q := StorageManager.Query().IsNullOrEmpty("manager_id")
  1924. q = q.In("storage_type", api.SHARED_STORAGE)
  1925. storages := make([]SStorage, 0)
  1926. err := q.All(&storages)
  1927. if err != nil {
  1928. log.Errorf("StoragesCleanRecycleDiskfiles failed get storages %s", err)
  1929. return
  1930. }
  1931. for i := range storages {
  1932. storages[i].SetModelManager(StorageManager, &storages[i])
  1933. log.Infof("storage %s start clean recycle diskfiles", storages[i].GetName())
  1934. host, err := storages[i].GetMasterHost()
  1935. if err != nil {
  1936. log.Errorf("StoragesCleanRecycleDiskfiles storage %s failed get master host: %s", storages[i].GetName(), err)
  1937. continue
  1938. }
  1939. url := fmt.Sprintf("/storages/%s/clean-recycle-diskfiles", storages[i].Id)
  1940. body := jsonutils.NewDict()
  1941. _, err = host.Request(ctx, userCred, "POST", url, mcclient.GetTokenHeaders(userCred), body)
  1942. if err != nil {
  1943. log.Errorf("StoragesCleanRecycleDiskfiles storage %s request failed %s", storages[i].GetName(), err)
  1944. continue
  1945. }
  1946. }
  1947. }