filesystem.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  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. "strings"
  18. "time"
  19. "yunion.io/x/cloudmux/pkg/cloudprovider"
  20. "yunion.io/x/jsonutils"
  21. "yunion.io/x/log"
  22. "yunion.io/x/pkg/errors"
  23. "yunion.io/x/pkg/util/billing"
  24. "yunion.io/x/pkg/util/compare"
  25. "yunion.io/x/pkg/utils"
  26. "yunion.io/x/sqlchemy"
  27. billing_api "yunion.io/x/onecloud/pkg/apis/billing"
  28. api "yunion.io/x/onecloud/pkg/apis/compute"
  29. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  30. "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
  31. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  32. "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
  33. "yunion.io/x/onecloud/pkg/cloudcommon/validators"
  34. "yunion.io/x/onecloud/pkg/compute/options"
  35. "yunion.io/x/onecloud/pkg/httperrors"
  36. "yunion.io/x/onecloud/pkg/mcclient"
  37. "yunion.io/x/onecloud/pkg/util/stringutils2"
  38. )
  39. type SFileSystemManager struct {
  40. db.SSharableVirtualResourceBaseManager
  41. db.SExternalizedResourceBaseManager
  42. SManagedResourceBaseManager
  43. SCloudregionResourceBaseManager
  44. SZoneResourceBaseManager
  45. SDeletePreventableResourceBaseManager
  46. }
  47. var FileSystemManager *SFileSystemManager
  48. func init() {
  49. FileSystemManager = &SFileSystemManager{
  50. SSharableVirtualResourceBaseManager: db.NewSharableVirtualResourceBaseManager(
  51. SFileSystem{},
  52. "file_systems_tbl",
  53. "file_system",
  54. "file_systems",
  55. ),
  56. }
  57. FileSystemManager.SetVirtualObject(FileSystemManager)
  58. }
  59. type SFileSystem struct {
  60. db.SSharableVirtualResourceBase
  61. db.SExternalizedResourceBase
  62. SManagedResourceBase
  63. SBillingResourceBase
  64. SCloudregionResourceBase
  65. SZoneResourceBase
  66. SDeletePreventableResourceBase
  67. // 文件系统类型
  68. // enmu: extreme, standard, cpfs
  69. FileSystemType string `width:"32" charset:"ascii" nullable:"false" list:"user" create:"required"`
  70. // 存储类型
  71. // enmu: performance, capacity, standard, advance, advance_100, advance_200
  72. StorageType string `width:"32" charset:"ascii" nullable:"false" list:"user" create:"required"`
  73. // 协议类型
  74. // enum: ["NFS", "SMB", "cpfs"]
  75. Protocol string `width:"32" charset:"ascii" nullable:"false" list:"user" create:"required"`
  76. // 容量, 单位Gb
  77. Capacity int64 `nullable:"false" list:"user" create:"optional"`
  78. // 已使用容量, 单位Gb
  79. UsedCapacity int64 `nullable:"false" list:"user"`
  80. // 最多支持挂载点数量, -1代表无限制
  81. MountTargetCountLimit int `nullable:"false" list:"user" default:"-1"`
  82. }
  83. func (manager *SFileSystemManager) GetContextManagers() [][]db.IModelManager {
  84. return [][]db.IModelManager{
  85. {CloudregionManager},
  86. }
  87. }
  88. func (fileSystem *SFileSystem) GetCloudproviderId() string {
  89. return fileSystem.ManagerId
  90. }
  91. func (manager *SFileSystemManager) ListItemFilter(
  92. ctx context.Context,
  93. q *sqlchemy.SQuery,
  94. userCred mcclient.TokenCredential,
  95. query api.FileSystemListInput,
  96. ) (*sqlchemy.SQuery, error) {
  97. var err error
  98. q, err = manager.SSharableVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.SharableVirtualResourceListInput)
  99. if err != nil {
  100. return nil, errors.Wrapf(err, "SSharableVirtualResourceBaseManager.ListItemFilter")
  101. }
  102. q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
  103. if err != nil {
  104. return nil, errors.Wrapf(err, "SExternalizedResourceBaseManager.ListItemFilter")
  105. }
  106. q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput)
  107. if err != nil {
  108. return nil, errors.Wrapf(err, "SManagedResourceBaseManager.ListItemFilter")
  109. }
  110. q, err = manager.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, query.RegionalFilterListInput)
  111. if err != nil {
  112. return nil, errors.Wrapf(err, "SCloudregionResourceBaseManager.ListItemFilter")
  113. }
  114. return q, nil
  115. }
  116. func (man *SFileSystemManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.FileSystemCreateInput) (api.FileSystemCreateInput, error) {
  117. var err error
  118. if len(input.NetworkId) > 0 {
  119. net, err := validators.ValidateModel(ctx, userCred, NetworkManager, &input.NetworkId)
  120. if err != nil {
  121. return input, err
  122. }
  123. network := net.(*SNetwork)
  124. vpc, _ := network.GetVpc()
  125. input.ManagerId = vpc.ManagerId
  126. if zone, _ := network.GetZone(); zone != nil {
  127. input.ZoneId = zone.Id
  128. input.CloudregionId = zone.CloudregionId
  129. }
  130. }
  131. if len(input.ZoneId) == 0 {
  132. return input, httperrors.NewMissingParameterError("zone_id")
  133. }
  134. _zone, err := validators.ValidateModel(ctx, userCred, ZoneManager, &input.ZoneId)
  135. if err != nil {
  136. return input, err
  137. }
  138. zone := _zone.(*SZone)
  139. region, _ := zone.GetRegion()
  140. input.CloudregionId = region.Id
  141. if len(input.ManagerId) == 0 {
  142. sq := CloudproviderManager.Query().Equals("provider", api.CLOUD_PROVIDER_CEPHFS).SubQuery()
  143. q := CloudproviderRegionManager.Query().Equals("cloudregion_id", input.CloudregionId)
  144. q = q.Join(sq, sqlchemy.Equals(q.Field("cloudprovider_id"), sq.Field("id")))
  145. cprgs := []SCloudproviderregion{}
  146. err = q.All(&cprgs)
  147. if err != nil {
  148. return input, err
  149. }
  150. if len(cprgs) == 1 {
  151. input.ManagerId = cprgs[0].CloudproviderId
  152. } else {
  153. return input, httperrors.NewMissingParameterError("manager_id")
  154. }
  155. }
  156. if len(input.Duration) > 0 {
  157. billingCycle, err := billing.ParseBillingCycle(input.Duration)
  158. if err != nil {
  159. return input, httperrors.NewInputParameterError("invalid duration %s", input.Duration)
  160. }
  161. if !utils.IsInStringArray(string(input.BillingType), []string{string(billing_api.BILLING_TYPE_PREPAID), string(billing_api.BILLING_TYPE_POSTPAID)}) {
  162. input.BillingType = billing_api.BILLING_TYPE_PREPAID
  163. }
  164. if input.BillingType == billing_api.BILLING_TYPE_PREPAID {
  165. if !region.GetDriver().IsSupportedBillingCycle(billingCycle, man.KeywordPlural()) {
  166. return input, httperrors.NewInputParameterError("unsupported duration %s", input.Duration)
  167. }
  168. }
  169. input.BillingCycle = billingCycle.String()
  170. if input.BillingType == billing_api.BILLING_TYPE_POSTPAID {
  171. input.ReleaseAt = billingCycle.EndAt(time.Now())
  172. }
  173. }
  174. input.SharableVirtualResourceCreateInput, err = man.SSharableVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.SharableVirtualResourceCreateInput)
  175. if err != nil {
  176. return input, err
  177. }
  178. return input, nil
  179. }
  180. func (fileSystem *SFileSystem) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
  181. fileSystem.SSharableVirtualResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
  182. fileSystem.StartCreateTask(ctx, userCred, jsonutils.GetAnyString(data, []string{"network_id"}), "")
  183. }
  184. func (fileSystem *SFileSystem) StartCreateTask(ctx context.Context, userCred mcclient.TokenCredential, networkId string, parentTaskId string) error {
  185. var err = func() error {
  186. params := jsonutils.NewDict()
  187. params.Add(jsonutils.NewString(networkId), "network_id")
  188. task, err := taskman.TaskManager.NewTask(ctx, "FileSystemCreateTask", fileSystem, userCred, params, parentTaskId, "", nil)
  189. if err != nil {
  190. return errors.Wrapf(err, "NewTask")
  191. }
  192. return task.ScheduleRun(nil)
  193. }()
  194. if err != nil {
  195. fileSystem.SetStatus(ctx, userCred, api.NAS_STATUS_CREATE_FAILED, err.Error())
  196. return err
  197. }
  198. fileSystem.SetStatus(ctx, userCred, api.NAS_STATUS_CREATING, "")
  199. return nil
  200. }
  201. func (manager SFileSystemManager) FetchCustomizeColumns(
  202. ctx context.Context,
  203. userCred mcclient.TokenCredential,
  204. query jsonutils.JSONObject,
  205. objs []interface{},
  206. fields stringutils2.SSortedStrings,
  207. isList bool,
  208. ) []api.FileSystemDetails {
  209. rows := make([]api.FileSystemDetails, len(objs))
  210. virtRows := manager.SSharableVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  211. regionRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  212. mRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  213. zoneIds := make([]string, len(objs))
  214. for i := range rows {
  215. rows[i] = api.FileSystemDetails{
  216. SharableVirtualResourceDetails: virtRows[i],
  217. CloudregionResourceInfo: regionRows[i],
  218. ManagedResourceInfo: mRows[i],
  219. }
  220. nas := objs[i].(*SFileSystem)
  221. zoneIds[i] = nas.ZoneId
  222. }
  223. zoneMaps, err := db.FetchIdNameMap2(ZoneManager, zoneIds)
  224. if err != nil {
  225. return rows
  226. }
  227. for i := range rows {
  228. rows[i].Zone, _ = zoneMaps[zoneIds[i]]
  229. }
  230. return rows
  231. }
  232. func (manager *SFileSystemManager) ListItemExportKeys(ctx context.Context,
  233. q *sqlchemy.SQuery,
  234. userCred mcclient.TokenCredential,
  235. keys stringutils2.SSortedStrings,
  236. ) (*sqlchemy.SQuery, error) {
  237. var err error
  238. q, err = manager.SSharableVirtualResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  239. if err != nil {
  240. return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ListItemExportKeys")
  241. }
  242. q, err = manager.SCloudregionResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  243. if err != nil {
  244. return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemExportKeys")
  245. }
  246. return q, nil
  247. }
  248. func (manager *SFileSystemManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  249. var err error
  250. q, err = manager.SSharableVirtualResourceBaseManager.QueryDistinctExtraField(q, field)
  251. if err == nil {
  252. return q, nil
  253. }
  254. q, err = manager.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field)
  255. if err == nil {
  256. return q, nil
  257. }
  258. q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field)
  259. if err == nil {
  260. return q, nil
  261. }
  262. return q, httperrors.ErrNotFound
  263. }
  264. func (manager *SFileSystemManager) QueryDistinctExtraFields(q *sqlchemy.SQuery, resource string, fields []string) (*sqlchemy.SQuery, error) {
  265. var err error
  266. q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraFields(q, resource, fields)
  267. if err == nil {
  268. return q, nil
  269. }
  270. return q, httperrors.ErrNotFound
  271. }
  272. func (manager *SFileSystemManager) OrderByExtraFields(
  273. ctx context.Context,
  274. q *sqlchemy.SQuery,
  275. userCred mcclient.TokenCredential,
  276. query api.FileSystemListInput,
  277. ) (*sqlchemy.SQuery, error) {
  278. var err error
  279. q, err = manager.SSharableVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.SharableVirtualResourceListInput)
  280. if err != nil {
  281. return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.OrderByExtraFields")
  282. }
  283. q, err = manager.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput)
  284. if err != nil {
  285. return nil, errors.Wrapf(err, "SManagedResourceBaseManager.OrderByExtraFields")
  286. }
  287. q, err = manager.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.RegionalFilterListInput)
  288. if err != nil {
  289. return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.OrderByExtraFields")
  290. }
  291. return q, nil
  292. }
  293. func (region *SCloudregion) GetFileSystems(managerId string) ([]SFileSystem, error) {
  294. ret := []SFileSystem{}
  295. q := FileSystemManager.Query().Equals("cloudregion_id", region.Id)
  296. if len(managerId) > 0 {
  297. q = q.Equals("manager_id", managerId)
  298. }
  299. err := db.FetchModelObjects(FileSystemManager, q, &ret)
  300. if err != nil {
  301. return nil, errors.Wrapf(err, "db.FetchModelObjects")
  302. }
  303. return ret, nil
  304. }
  305. func (region *SCloudregion) SyncFileSystems(
  306. ctx context.Context,
  307. userCred mcclient.TokenCredential,
  308. provider *SCloudprovider,
  309. filesystems []cloudprovider.ICloudFileSystem,
  310. xor bool,
  311. ) ([]SFileSystem, []cloudprovider.ICloudFileSystem, compare.SyncResult) {
  312. lockman.LockRawObject(ctx, region.Id, FileSystemManager.Keyword())
  313. defer lockman.ReleaseRawObject(ctx, region.Id, FileSystemManager.Keyword())
  314. result := compare.SyncResult{}
  315. localFSs := []SFileSystem{}
  316. remoteFSs := []cloudprovider.ICloudFileSystem{}
  317. dbFSs, err := region.GetFileSystems(provider.Id)
  318. if err != nil {
  319. result.Error(errors.Wrapf(err, "GetFileSystems"))
  320. return localFSs, remoteFSs, result
  321. }
  322. removed := make([]SFileSystem, 0)
  323. commondb := make([]SFileSystem, 0)
  324. commonext := make([]cloudprovider.ICloudFileSystem, 0)
  325. added := make([]cloudprovider.ICloudFileSystem, 0)
  326. err = compare.CompareSets(dbFSs, filesystems, &removed, &commondb, &commonext, &added)
  327. if err != nil {
  328. result.Error(errors.Wrapf(err, "compare.CompareSets"))
  329. return localFSs, remoteFSs, result
  330. }
  331. for i := 0; i < len(removed); i += 1 {
  332. err = removed[i].syncRemove(ctx, userCred)
  333. if err != nil {
  334. result.DeleteError(err)
  335. continue
  336. }
  337. result.Delete()
  338. }
  339. for i := 0; i < len(commondb); i += 1 {
  340. if !xor {
  341. err = commondb[i].SyncWithCloudFileSystem(ctx, userCred, commonext[i])
  342. if err != nil {
  343. result.UpdateError(err)
  344. continue
  345. }
  346. }
  347. localFSs = append(localFSs, commondb[i])
  348. remoteFSs = append(remoteFSs, commonext[i])
  349. result.Update()
  350. }
  351. for i := 0; i < len(added); i += 1 {
  352. newFs, err := region.newFromCloudFileSystem(ctx, userCred, provider, added[i])
  353. if err != nil {
  354. result.AddError(err)
  355. continue
  356. }
  357. syncMetadata(ctx, userCred, newFs, added[i], false)
  358. localFSs = append(localFSs, *newFs)
  359. remoteFSs = append(remoteFSs, added[i])
  360. result.Add()
  361. }
  362. return localFSs, remoteFSs, result
  363. }
  364. func (fileSystem *SFileSystem) syncRemove(ctx context.Context, userCred mcclient.TokenCredential) error {
  365. lockman.LockObject(ctx, fileSystem)
  366. defer lockman.ReleaseObject(ctx, fileSystem)
  367. fileSystem.DeletePreventionOff(fileSystem, userCred)
  368. err := fileSystem.ValidateDeleteCondition(ctx, nil)
  369. if err != nil { // cannot delete
  370. return fileSystem.SetStatus(ctx, userCred, api.NAS_STATUS_UNKNOWN, "sync to delete")
  371. }
  372. err = fileSystem.RealDelete(ctx, userCred)
  373. if err != nil {
  374. return err
  375. }
  376. notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
  377. Obj: fileSystem,
  378. Action: notifyclient.ActionSyncDelete,
  379. })
  380. return nil
  381. }
  382. func (fileSystem *SFileSystem) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
  383. return fileSystem.StartDeleteTask(ctx, userCred, "")
  384. }
  385. func (fileSystem *SFileSystem) StartDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
  386. var err = func() error {
  387. task, err := taskman.TaskManager.NewTask(ctx, "FileSystemDeleteTask", fileSystem, userCred, nil, parentTaskId, "", nil)
  388. if err != nil {
  389. return errors.Wrapf(err, "NewTask")
  390. }
  391. return task.ScheduleRun(nil)
  392. }()
  393. if err != nil {
  394. fileSystem.SetStatus(ctx, userCred, api.NAS_STATUS_DELETE_FAILED, err.Error())
  395. return nil
  396. }
  397. fileSystem.SetStatus(ctx, userCred, api.NAS_STATUS_DELETING, "")
  398. return nil
  399. }
  400. func (fileSystem *SFileSystem) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
  401. return nil
  402. }
  403. func (fileSystem *SFileSystem) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
  404. mts, err := fileSystem.GetMountTargets()
  405. if err != nil {
  406. return errors.Wrapf(err, "GetMountTargets")
  407. }
  408. for i := range mts {
  409. err = mts[i].RealDelete(ctx, userCred)
  410. if err != nil {
  411. return errors.Wrapf(err, "mount target %s real delete", mts[i].DomainName)
  412. }
  413. }
  414. return fileSystem.SSharableVirtualResourceBase.Delete(ctx, userCred)
  415. }
  416. func (fileSystem *SFileSystem) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error {
  417. if fileSystem.DisableDelete.IsTrue() {
  418. return httperrors.NewInvalidStatusError("FileSystem is locked, cannot delete")
  419. }
  420. return fileSystem.SSharableVirtualResourceBase.ValidateDeleteCondition(ctx, nil)
  421. }
  422. func (fileSystem *SFileSystem) SyncAllWithCloudFileSystem(ctx context.Context, userCred mcclient.TokenCredential, fs cloudprovider.ICloudFileSystem) error {
  423. syncFileSystemMountTargets(ctx, userCred, fileSystem, fs, false)
  424. return fileSystem.SyncWithCloudFileSystem(ctx, userCred, fs)
  425. }
  426. func (fileSystem *SFileSystem) SyncWithCloudFileSystem(ctx context.Context, userCred mcclient.TokenCredential, fs cloudprovider.ICloudFileSystem) error {
  427. diff, err := db.Update(fileSystem, func() error {
  428. if options.Options.EnableSyncName {
  429. newName, _ := db.GenerateAlterName(fileSystem, fs.GetName())
  430. if len(newName) > 0 {
  431. fileSystem.Name = newName
  432. }
  433. }
  434. fileSystem.Status = fs.GetStatus()
  435. fileSystem.StorageType = fs.GetStorageType()
  436. fileSystem.Protocol = fs.GetProtocol()
  437. fileSystem.Capacity = fs.GetCapacityGb()
  438. fileSystem.UsedCapacity = fs.GetUsedCapacityGb()
  439. fileSystem.FileSystemType = fs.GetFileSystemType()
  440. fileSystem.MountTargetCountLimit = fs.GetMountTargetCountLimit()
  441. if zoneId := fs.GetZoneId(); len(zoneId) > 0 {
  442. region, err := fileSystem.GetRegion()
  443. if err != nil {
  444. return errors.Wrapf(err, "fileSystem.GetRegion")
  445. }
  446. fileSystem.ZoneId, _ = region.getZoneIdBySuffix(zoneId)
  447. }
  448. return nil
  449. })
  450. if err != nil {
  451. return errors.Wrapf(err, "db.Update")
  452. }
  453. if len(diff) > 0 {
  454. notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
  455. Obj: fileSystem,
  456. Action: notifyclient.ActionSyncUpdate,
  457. })
  458. }
  459. if account := fileSystem.GetCloudaccount(); account != nil {
  460. syncVirtualResourceMetadata(ctx, userCred, fileSystem, fs, account.ReadOnly)
  461. }
  462. if provider := fileSystem.GetCloudprovider(); provider != nil {
  463. SyncCloudProject(ctx, userCred, fileSystem, provider.GetOwnerId(), fs, provider)
  464. }
  465. return nil
  466. }
  467. func (region *SCloudregion) getZoneIdBySuffix(zoneId string) (string, error) {
  468. zones, err := region.GetZones()
  469. if err != nil {
  470. return "", errors.Wrapf(err, "region.GetZones")
  471. }
  472. for _, zone := range zones {
  473. if strings.HasSuffix(zone.ExternalId, zoneId) {
  474. return zone.Id, nil
  475. }
  476. }
  477. msg := zoneId
  478. return "", errors.Wrapf(cloudprovider.ErrNotFound, "%s", msg)
  479. }
  480. func (region *SCloudregion) newFromCloudFileSystem(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, fs cloudprovider.ICloudFileSystem) (*SFileSystem, error) {
  481. nas := SFileSystem{}
  482. nas.SetModelManager(FileSystemManager, &nas)
  483. nas.ExternalId = fs.GetGlobalId()
  484. nas.CloudregionId = region.Id
  485. nas.ManagerId = provider.Id
  486. nas.Status = fs.GetStatus()
  487. nas.CreatedAt = fs.GetCreatedAt()
  488. nas.StorageType = fs.GetStorageType()
  489. nas.Protocol = fs.GetProtocol()
  490. nas.Capacity = fs.GetCapacityGb()
  491. nas.UsedCapacity = fs.GetCapacityGb()
  492. nas.FileSystemType = fs.GetFileSystemType()
  493. nas.MountTargetCountLimit = fs.GetMountTargetCountLimit()
  494. if zoneId := fs.GetZoneId(); len(zoneId) > 0 {
  495. nas.ZoneId, _ = region.getZoneIdBySuffix(zoneId)
  496. }
  497. fileSystem, err := func() (*SFileSystem, error) {
  498. lockman.LockRawObject(ctx, FileSystemManager.Keyword(), "name")
  499. defer lockman.ReleaseRawObject(ctx, FileSystemManager.Keyword(), "name")
  500. var err error
  501. nas.Name, err = db.GenerateName(ctx, FileSystemManager, userCred, fs.GetName())
  502. if err != nil {
  503. return nil, errors.Wrapf(err, "db.GenerateName")
  504. }
  505. return &nas, FileSystemManager.TableSpec().Insert(ctx, &nas)
  506. }()
  507. if err != nil {
  508. return nil, err
  509. }
  510. notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
  511. Obj: &nas,
  512. Action: notifyclient.ActionSyncCreate,
  513. })
  514. if account, _ := provider.GetCloudaccount(); account != nil {
  515. syncVirtualResourceMetadata(ctx, userCred, fileSystem, fs, account.ReadOnly)
  516. }
  517. SyncCloudProject(ctx, userCred, fileSystem, provider.GetOwnerId(), fs, provider)
  518. return fileSystem, nil
  519. }
  520. // 同步NAS状态
  521. func (fileSystem *SFileSystem) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.FileSystemSyncstatusInput) (jsonutils.JSONObject, error) {
  522. var openTask = true
  523. count, err := taskman.TaskManager.QueryTasksOfObject(fileSystem, time.Now().Add(-3*time.Minute), &openTask).CountWithError()
  524. if err != nil {
  525. return nil, err
  526. }
  527. if count > 0 {
  528. return nil, httperrors.NewBadRequestError("Nas has %d task active, can't sync status", count)
  529. }
  530. return nil, fileSystem.StartSyncstatus(ctx, userCred, "")
  531. }
  532. func (fileSystem *SFileSystem) StartSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
  533. return StartResourceSyncStatusTask(ctx, userCred, fileSystem, "FileSystemSyncstatusTask", parentTaskId)
  534. }
  535. // 设置容量大小(CephFS)
  536. func (fileSystem *SFileSystem) PerformSetQuota(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.FileSystemSetQuotaInput) (jsonutils.JSONObject, error) {
  537. if input.MaxFiles == nil && input.MaxGb == nil {
  538. return nil, httperrors.NewMissingParameterError("max_gb")
  539. }
  540. var openTask = true
  541. count, err := taskman.TaskManager.QueryTasksOfObject(fileSystem, time.Now().Add(-3*time.Minute), &openTask).CountWithError()
  542. if err != nil {
  543. return nil, err
  544. }
  545. if count > 0 {
  546. return nil, httperrors.NewBadRequestError("Nas has %d task active, can't sync status", count)
  547. }
  548. return nil, fileSystem.StartSetQuotaTask(ctx, userCred, input)
  549. }
  550. func (fileSystem *SFileSystem) StartSetQuotaTask(ctx context.Context, userCred mcclient.TokenCredential, input *api.FileSystemSetQuotaInput) error {
  551. params := jsonutils.Marshal(input).(*jsonutils.JSONDict)
  552. task, err := taskman.TaskManager.NewTask(ctx, "FileSystemSetQuotaTask", fileSystem, userCred, params, "", "", nil)
  553. if err != nil {
  554. return err
  555. }
  556. fileSystem.SetStatus(ctx, userCred, api.NAS_STATUS_EXTENDING, "set quota")
  557. return task.ScheduleRun(nil)
  558. }
  559. func (fileSystem *SFileSystem) GetIRegion(ctx context.Context) (cloudprovider.ICloudRegion, error) {
  560. provider, err := fileSystem.GetDriver(ctx)
  561. if err != nil {
  562. return nil, errors.Wrapf(err, "fileSystem.GetDriver")
  563. }
  564. if provider.GetFactory().IsOnPremise() {
  565. return provider.GetOnPremiseIRegion()
  566. }
  567. region, err := fileSystem.GetRegion()
  568. if err != nil {
  569. return nil, errors.Wrapf(err, "fileSystem.GetRegion")
  570. }
  571. iRegion, err := provider.GetIRegionById(region.ExternalId)
  572. if err != nil {
  573. return nil, errors.Wrapf(err, "provider.GetIRegionById")
  574. }
  575. return iRegion, nil
  576. }
  577. func (fileSystem *SFileSystem) GetICloudFileSystem(ctx context.Context) (cloudprovider.ICloudFileSystem, error) {
  578. if len(fileSystem.ExternalId) == 0 {
  579. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty externalId")
  580. }
  581. iRegion, err := fileSystem.GetIRegion(ctx)
  582. if err != nil {
  583. return nil, errors.Wrap(err, "fileSystem.GetIRegion")
  584. }
  585. return iRegion.GetICloudFileSystemById(fileSystem.ExternalId)
  586. }
  587. func (manager *SFileSystemManager) getExpiredPostpaids() ([]SFileSystem, error) {
  588. q := ListExpiredPostpaidResources(manager.Query(), options.Options.ExpiredPrepaidMaxCleanBatchSize)
  589. fs := make([]SFileSystem, 0)
  590. err := db.FetchModelObjects(manager, q, &fs)
  591. if err != nil {
  592. return nil, errors.Wrapf(err, "db.FetchModelObjects")
  593. }
  594. return fs, nil
  595. }
  596. func (fileSystem *SFileSystem) doExternalSync(ctx context.Context, userCred mcclient.TokenCredential) error {
  597. iFs, err := fileSystem.GetICloudFileSystem(ctx)
  598. if err != nil {
  599. return errors.Wrapf(err, "GetICloudFileSystem")
  600. }
  601. return fileSystem.SyncWithCloudFileSystem(ctx, userCred, iFs)
  602. }
  603. func (manager *SFileSystemManager) DeleteExpiredPostpaids(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
  604. fss, err := manager.getExpiredPostpaids()
  605. if err != nil {
  606. log.Errorf("FileSystem getExpiredPostpaids error: %v", err)
  607. return
  608. }
  609. for i := 0; i < len(fss); i += 1 {
  610. if len(fss[i].ExternalId) > 0 {
  611. err := fss[i].doExternalSync(ctx, userCred)
  612. if err == nil && fss[i].IsValidPostPaid() {
  613. continue
  614. }
  615. }
  616. fss[i].DeletePreventionOff(&fss[i], userCred)
  617. fss[i].StartDeleteTask(ctx, userCred, "")
  618. }
  619. }
  620. func (fileSystem *SFileSystem) PerformRemoteUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.FileSystemRemoteUpdateInput) (jsonutils.JSONObject, error) {
  621. return nil, fileSystem.StartRemoteUpdateTask(ctx, userCred, (input.ReplaceTags != nil && *input.ReplaceTags), "")
  622. }
  623. func (fileSystem *SFileSystem) StartRemoteUpdateTask(ctx context.Context, userCred mcclient.TokenCredential, replaceTags bool, parentTaskId string) error {
  624. data := jsonutils.NewDict()
  625. if replaceTags {
  626. data.Add(jsonutils.JSONTrue, "replace_tags")
  627. }
  628. task, err := taskman.TaskManager.NewTask(ctx, "FileSystemRemoteUpdateTask", fileSystem, userCred, data, parentTaskId, "", nil)
  629. if err != nil {
  630. return errors.Wrap(err, "NewTask")
  631. }
  632. fileSystem.SetStatus(ctx, userCred, api.NAS_UPDATE_TAGS, "StartRemoteUpdateTask")
  633. return task.ScheduleRun(nil)
  634. }
  635. func (fileSystem *SFileSystem) OnMetadataUpdated(ctx context.Context, userCred mcclient.TokenCredential) {
  636. if len(fileSystem.ExternalId) == 0 || options.Options.KeepTagLocalization {
  637. return
  638. }
  639. if account := fileSystem.GetCloudaccount(); account != nil && account.ReadOnly {
  640. return
  641. }
  642. fileSystem.StartRemoteUpdateTask(ctx, userCred, true, "")
  643. }
  644. func (fileSystem *SFileSystem) GetShortDesc(ctx context.Context) *jsonutils.JSONDict {
  645. desc := fileSystem.SSharableVirtualResourceBase.GetShortDesc(ctx)
  646. region, _ := fileSystem.GetRegion()
  647. provider := fileSystem.GetCloudprovider()
  648. info := MakeCloudProviderInfo(region, nil, provider)
  649. desc.Set("file_system_type", jsonutils.NewString(fileSystem.FileSystemType))
  650. desc.Set("storage_type", jsonutils.NewString(fileSystem.StorageType))
  651. desc.Set("protocol", jsonutils.NewString(fileSystem.Protocol))
  652. desc.Set("capacity", jsonutils.NewInt(fileSystem.Capacity))
  653. desc.Set("used_capacity", jsonutils.NewInt(fileSystem.UsedCapacity))
  654. desc.Update(jsonutils.Marshal(&info))
  655. return desc
  656. }