core.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  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 storageman
  15. import (
  16. "context"
  17. "fmt"
  18. "os"
  19. "path"
  20. "strings"
  21. "time"
  22. "yunion.io/x/cloudmux/pkg/cloudprovider"
  23. "yunion.io/x/log"
  24. "yunion.io/x/pkg/errors"
  25. "yunion.io/x/pkg/util/fileutils"
  26. "yunion.io/x/pkg/util/timeutils"
  27. "yunion.io/x/pkg/utils"
  28. api "yunion.io/x/onecloud/pkg/apis/compute"
  29. "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
  30. "yunion.io/x/onecloud/pkg/hostman/hostutils"
  31. "yunion.io/x/onecloud/pkg/hostman/hostutils/kubelet"
  32. "yunion.io/x/onecloud/pkg/hostman/options"
  33. "yunion.io/x/onecloud/pkg/hostman/storageman/storageutils"
  34. "yunion.io/x/onecloud/pkg/mcclient"
  35. "yunion.io/x/onecloud/pkg/util/fileutils2"
  36. "yunion.io/x/onecloud/pkg/util/procutils"
  37. "yunion.io/x/onecloud/pkg/util/zeroclean"
  38. )
  39. const MINIMAL_FREE_SPACE = 128
  40. type IStorageManager interface {
  41. GetZoneId() string
  42. }
  43. type SStorageManager struct {
  44. host hostutils.IHost
  45. Storages []IStorage
  46. AgentStorage IStorage
  47. LocalStorageImagecacheManager IImageCacheManger
  48. // AgentStorageImagecacheManager IImageCacheManger
  49. LVMStorageImagecacheManagers map[string]IImageCacheManger
  50. SharedLVMStorageImagecacheManagers map[string]IImageCacheManger
  51. RbdStorageImagecacheManagers map[string]IImageCacheManger
  52. SharedFileStorageImagecacheManagers map[string]IImageCacheManger
  53. }
  54. func NewStorageManager(host hostutils.IHost) (*SStorageManager, error) {
  55. var (
  56. ret = &SStorageManager{
  57. host: host,
  58. Storages: make([]IStorage, 0),
  59. }
  60. allFull = true
  61. )
  62. for i, d := range options.HostOptions.LocalImagePath {
  63. s := NewLocalStorage(ret, d, i)
  64. if err := s.Accessible(); err == nil {
  65. ret.Storages = append(ret.Storages, s)
  66. if allFull && s.GetFreeSizeMb() > MINIMAL_FREE_SPACE {
  67. allFull = false
  68. }
  69. } else {
  70. log.Errorf("storage %s not accessible error: %v", s.Path, err)
  71. }
  72. }
  73. for _, d := range options.HostOptions.SharedStorages {
  74. s := ret.NewSharedStorageInstance(d, "")
  75. if s != nil {
  76. ret.Storages = append(ret.Storages, s)
  77. allFull = false
  78. }
  79. }
  80. for _, d := range options.HostOptions.LVMVolumeGroups {
  81. s := NewLVMStorage(ret, d)
  82. if err := s.Accessible(); err == nil {
  83. ret.Storages = append(ret.Storages, s)
  84. if allFull && s.GetFreeSizeMb() > MINIMAL_FREE_SPACE {
  85. allFull = false
  86. }
  87. } else {
  88. log.Errorf("lvm storage %s not accessible error: %v", s.Path, err)
  89. }
  90. }
  91. for _, conf := range options.HostOptions.PTNVMEConfigs {
  92. diskConf := strings.Split(conf, "/")
  93. if len(diskConf) != 2 {
  94. return nil, fmt.Errorf("bad nvme config %s", conf)
  95. }
  96. var pciAddr, size = diskConf[0], diskConf[1]
  97. sizeMb, err := fileutils.GetSizeMb(size, 'M', 1024)
  98. if err != nil {
  99. return nil, errors.Wrapf(err, "failed parse pci device %s size %s", pciAddr, size)
  100. }
  101. ret.Storages = append(ret.Storages, newNVMEStorage(ret, pciAddr, sizeMb))
  102. }
  103. if allFull {
  104. return nil, fmt.Errorf("Not enough storage space!")
  105. }
  106. if err := ret.initLocalStorageImagecache(); err != nil {
  107. return nil, fmt.Errorf("Init Local storage image cache failed: %s", err)
  108. }
  109. return ret, nil
  110. }
  111. func (s *SStorageManager) Remove(storage IStorage) {
  112. storageType := storage.StorageType()
  113. if utils.IsInStringArray(storageType, api.SHARED_FILE_STORAGE) {
  114. delete(s.SharedFileStorageImagecacheManagers, storage.GetStoragecacheId())
  115. } else if storageType == api.STORAGE_RBD {
  116. delete(s.RbdStorageImagecacheManagers, storage.GetStoragecacheId())
  117. } else if storageType == api.STORAGE_LVM {
  118. delete(s.LVMStorageImagecacheManagers, storage.GetStoragecacheId())
  119. } else if storageType == api.STORAGE_CLVM || storageType == api.STORAGE_SLVM {
  120. delete(s.SharedLVMStorageImagecacheManagers, storage.GetStoragecacheId())
  121. }
  122. for index, iS := range s.Storages {
  123. if iS.GetId() == storage.GetId() {
  124. s.Storages = append(s.Storages[:index], s.Storages[index+1:]...)
  125. break
  126. }
  127. }
  128. }
  129. func (s *SStorageManager) GetZoneId() string {
  130. return s.host.GetZoneId()
  131. }
  132. func (s *SStorageManager) GetHostId() string {
  133. return s.host.GetHostId()
  134. }
  135. /*func (s *SStorageManager) GetMediumType() string {
  136. return s.host.GetMediumType()
  137. }*/
  138. func (s *SStorageManager) GetKubeletConfig() kubelet.KubeletConfig {
  139. return s.host.GetKubeletConfig()
  140. }
  141. func (s *SStorageManager) getLeasedUsedLocalStorage(cacheDir string, limit int) (string, error) {
  142. var (
  143. maxFree int
  144. spath string
  145. maxStorage IStorage
  146. )
  147. for _, storage := range s.Storages {
  148. if _, ok := storage.(*SLocalStorage); ok {
  149. cachePath := path.Join(storage.GetPath(), cacheDir)
  150. if fileutils2.Exists(cachePath) {
  151. spath = cachePath
  152. break
  153. }
  154. free := storage.GetFreeSizeMb()
  155. if maxFree < free {
  156. maxFree = free
  157. maxStorage = storage
  158. }
  159. }
  160. }
  161. if len(spath) == 0 {
  162. if maxFree >= limit*1024 {
  163. spath = path.Join(maxStorage.GetPath(), cacheDir)
  164. } else {
  165. return "", fmt.Errorf("No local storage has free space larger than %dGB", limit)
  166. }
  167. }
  168. return spath, nil
  169. }
  170. func (s *SStorageManager) initLocalStorageImagecache() error {
  171. var (
  172. cacheDir = "image_cache"
  173. cachePath = options.HostOptions.ImageCachePath
  174. // limit = options.HostOptions.ImageCacheLimit
  175. )
  176. if len(cachePath) == 0 {
  177. var err error
  178. cachePath, err = s.getLeasedUsedLocalStorage(cacheDir, 0)
  179. if err != nil {
  180. return err
  181. }
  182. }
  183. if len(cachePath) > 0 {
  184. s.LocalStorageImagecacheManager = NewLocalImageCacheManager(s, cachePath, "", nil)
  185. return nil
  186. } else {
  187. return fmt.Errorf("Cannot allocate image cache storage")
  188. }
  189. }
  190. func (s *SStorageManager) GetStorage(storageId string) IStorage {
  191. for _, storage := range s.Storages {
  192. if storage.GetId() == storageId {
  193. return storage
  194. }
  195. }
  196. return nil
  197. }
  198. func (s *SStorageManager) GetStorageDisk(storageId, diskId string) IDisk {
  199. if storage := s.GetStorage(storageId); storage != nil {
  200. disk, _ := storage.GetDiskById(diskId)
  201. return disk
  202. }
  203. return nil
  204. }
  205. func (s *SStorageManager) GetStoragesByPath(sPath string) ([]IStorage, error) {
  206. ret := []IStorage{}
  207. for i := range s.Storages {
  208. if s.Storages[i].GetPath() == sPath {
  209. ret = append(ret, s.Storages[i])
  210. }
  211. }
  212. if len(ret) == 0 {
  213. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%s", sPath)
  214. }
  215. return ret, nil
  216. }
  217. func (s *SStorageManager) GetStorageByPath(sPath string) (IStorage, error) {
  218. for _, storage := range s.Storages {
  219. if storage.GetPath() == sPath {
  220. return storage, nil
  221. }
  222. }
  223. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%s", sPath)
  224. }
  225. func (s *SStorageManager) GetDiskById(diskId string) (IDisk, error) {
  226. for _, storage := range s.Storages {
  227. disk, err := storage.GetDiskById(diskId)
  228. if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound {
  229. return nil, err
  230. }
  231. if err == nil {
  232. return disk, nil
  233. }
  234. }
  235. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%s", diskId)
  236. }
  237. func (s *SStorageManager) GetDiskByPath(diskPath string) (IDisk, error) {
  238. pos := strings.LastIndex(diskPath, "/")
  239. sPath := diskPath[:pos]
  240. diskId := diskPath[pos+1:]
  241. pos = strings.LastIndex(diskId, ".")
  242. if pos > 0 {
  243. diskId = diskId[:pos]
  244. }
  245. if strings.HasPrefix(sPath, "/dev/") {
  246. sPath = strings.TrimPrefix(sPath, "/dev/")
  247. }
  248. storages, err := s.GetStoragesByPath(sPath)
  249. if err != nil {
  250. return nil, errors.Wrapf(err, "%s", "GetStoragesByPath")
  251. }
  252. for i := range storages {
  253. disk, err := storages[i].GetDiskById(diskId)
  254. if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound {
  255. return nil, err
  256. }
  257. if err == nil {
  258. return disk, nil
  259. }
  260. }
  261. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%s", diskId)
  262. }
  263. func (s *SStorageManager) GetTotalCapacity() int {
  264. var capa = 0
  265. for _, s := range s.Storages {
  266. capa += s.GetCapacityMb()
  267. }
  268. return capa
  269. }
  270. func (s *SStorageManager) GetTotalLocalCapacity() int {
  271. var capa = 0
  272. for _, s := range s.Storages {
  273. if _, ok := s.(*SLocalStorage); ok {
  274. capa += s.GetCapacityMb()
  275. }
  276. }
  277. return capa
  278. }
  279. func (s *SStorageManager) GetStoragecacheById(scId string) IImageCacheManger {
  280. if s.LocalStorageImagecacheManager.GetId() == scId {
  281. return s.LocalStorageImagecacheManager
  282. }
  283. if sc, ok := s.SharedFileStorageImagecacheManagers[scId]; ok {
  284. return sc
  285. }
  286. if sc, ok := s.RbdStorageImagecacheManagers[scId]; ok {
  287. return sc
  288. }
  289. if sc, ok := s.LVMStorageImagecacheManagers[scId]; ok {
  290. return sc
  291. }
  292. if sc, ok := s.SharedLVMStorageImagecacheManagers[scId]; ok {
  293. return sc
  294. }
  295. return nil
  296. }
  297. func (s *SStorageManager) NewSharedStorageInstance(mountPoint, storageType string) IStorage {
  298. return NewStorage(s, mountPoint, storageType)
  299. }
  300. func (s *SStorageManager) InitSharedStorageImageCache(storageType, storagecacheId, imagecachePath string, storage IStorage) {
  301. if utils.IsInStringArray(storageType, api.SHARED_FILE_STORAGE) {
  302. s.InitSharedFileStorageImagecache(storagecacheId, imagecachePath, storage)
  303. } else if storageType == api.STORAGE_RBD {
  304. if rbdStorageCache := s.GetStoragecacheById(storagecacheId); rbdStorageCache == nil {
  305. s.AddRbdStorageImagecache(imagecachePath, storage, storagecacheId)
  306. }
  307. } else if storageType == api.STORAGE_CLVM || storageType == api.STORAGE_SLVM {
  308. if sharedLVMStorageCache := s.GetStoragecacheById(storagecacheId); sharedLVMStorageCache == nil {
  309. s.AddSharedLVMStorageImagecache(storage.GetPath(), storage, storagecacheId)
  310. }
  311. }
  312. }
  313. func (s *SStorageManager) InitLVMStorageImageCache(storagecacheId, vg string, storage IStorage) {
  314. if len(storagecacheId) == 0 {
  315. return
  316. }
  317. if s.LVMStorageImagecacheManagers == nil {
  318. s.LVMStorageImagecacheManagers = map[string]IImageCacheManger{}
  319. }
  320. if _, ok := s.LVMStorageImagecacheManagers[storagecacheId]; !ok {
  321. s.LVMStorageImagecacheManagers[storagecacheId] = NewLVMImageCacheManager(s, vg, storagecacheId, storage, false)
  322. }
  323. }
  324. func (s *SStorageManager) InitSharedFileStorageImagecache(storagecacheId, path string, storage IStorage) {
  325. if len(path) == 0 {
  326. return
  327. }
  328. if s.SharedFileStorageImagecacheManagers == nil {
  329. s.SharedFileStorageImagecacheManagers = map[string]IImageCacheManger{}
  330. }
  331. if _, ok := s.SharedFileStorageImagecacheManagers[storagecacheId]; !ok {
  332. s.SharedFileStorageImagecacheManagers[storagecacheId] = NewLocalImageCacheManager(s, path, storagecacheId, storage)
  333. }
  334. }
  335. func (s *SStorageManager) AddSharedLVMStorageImagecache(imagecachePath string, storage IStorage, storagecacheId string) {
  336. if s.SharedLVMStorageImagecacheManagers == nil {
  337. s.SharedLVMStorageImagecacheManagers = map[string]IImageCacheManger{}
  338. }
  339. if _, ok := s.SharedLVMStorageImagecacheManagers[storagecacheId]; !ok {
  340. imagecache := NewLVMImageCacheManager(s, imagecachePath, storagecacheId, storage, storage.Lvmlockd())
  341. s.SharedLVMStorageImagecacheManagers[storagecacheId] = imagecache
  342. }
  343. }
  344. func (s *SStorageManager) AddRbdStorageImagecache(imagecachePath string, storage IStorage, storagecacheId string) {
  345. if s.RbdStorageImagecacheManagers == nil {
  346. s.RbdStorageImagecacheManagers = map[string]IImageCacheManger{}
  347. }
  348. if _, ok := s.RbdStorageImagecacheManagers[storagecacheId]; !ok {
  349. if imagecache := NewImageCacheManager(s, imagecachePath, storage, storagecacheId, api.STORAGE_RBD); imagecache != nil {
  350. s.RbdStorageImagecacheManagers[storagecacheId] = imagecache
  351. return
  352. }
  353. log.Errorf("failed init storagecache %s for storage %s", storagecacheId, storage.GetStorageName())
  354. }
  355. }
  356. var storageManager *SStorageManager
  357. func GetManager() *SStorageManager {
  358. return storageManager
  359. }
  360. func Manager() *SStorageManager {
  361. return storageManager
  362. }
  363. func Init(host hostutils.IHost) error {
  364. lm := lockman.NewInMemoryLockManager()
  365. // lm := lockman.NewNoopLockManager()
  366. lockman.Init(lm)
  367. var err error
  368. storageManager, err = NewStorageManager(host)
  369. return err
  370. }
  371. func Stop() {
  372. // pass do nothing
  373. }
  374. func cleanDailyFiles(storagePath, subDir string, keepDay int) {
  375. recycleDir := path.Join(storagePath, subDir)
  376. if !fileutils2.Exists(recycleDir) {
  377. return
  378. }
  379. // before mark should be deleted
  380. markTime := timeutils.UtcNow().Add(time.Hour * 24 * -1 * time.Duration(keepDay))
  381. files, err := os.ReadDir(recycleDir)
  382. if err != nil {
  383. log.Errorln(err)
  384. return
  385. }
  386. for _, file := range files {
  387. date, err := timeutils.ParseTimeStr(file.Name())
  388. if err != nil {
  389. log.Errorln(err)
  390. continue
  391. }
  392. if date.Before(markTime) {
  393. log.Infof("Cron Job Clean Recycle Bin: start delete %s", file.Name())
  394. subDirPath := path.Join(recycleDir, file.Name())
  395. if options.HostOptions.ZeroCleanDiskData {
  396. // try to zero clean files in subdir
  397. err := zeroclean.ZeroDir(subDirPath)
  398. if err != nil {
  399. log.Errorf("zeroclean disk %s fail %s", subDirPath, err)
  400. } else {
  401. log.Debugf("zeroclean disk %s success!", subDirPath)
  402. }
  403. }
  404. if output, err := procutils.NewCommand("rm", "-rf", subDirPath).Output(); err != nil {
  405. log.Errorf("clean recycle dir %s error: %s, %s", subDirPath, err, output)
  406. }
  407. }
  408. }
  409. }
  410. func CleanRecycleDiskfiles(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
  411. if storageManager == nil {
  412. return
  413. }
  414. for _, storage := range storageManager.Storages {
  415. if utils.IsInStringArray(storage.StorageType(), api.SHARED_STORAGE) {
  416. continue
  417. }
  418. storage.CleanRecycleDiskfiles(ctx)
  419. }
  420. }
  421. func CleanImageCachefiles(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
  422. if storageManager == nil {
  423. return
  424. }
  425. storageManager.LocalStorageImagecacheManager.CleanImageCachefiles(ctx)
  426. for _, imageCacheMan := range storageManager.LVMStorageImagecacheManagers {
  427. imageCacheMan.CleanImageCachefiles(ctx)
  428. }
  429. // for _, imageCacheMan := range storageManager.SharedLVMStorageImagecacheManagers {
  430. // imageCacheMan.CleanImageCachefiles(ctx)
  431. // }
  432. // for _, imageCacheMan := range storageManager.RbdStorageImagecacheManagers {
  433. // imageCacheMan.CleanImageCachefiles(ctx)
  434. // }
  435. // for _, imageCacheMan := range storageManager.SharedFileStorageImagecacheManagers {
  436. // imageCacheMan.CleanImageCachefiles(ctx)
  437. // }
  438. }
  439. func GatherHostStorageStats(reportSharedStorages []string) api.SHostPingInput {
  440. stats := api.SHostPingInput{}
  441. stats.RootPartitionUsedCapacityMb = GetRootPartUsedCapacity()
  442. manager := GetManager()
  443. log.Debugf("report shared storages %s", reportSharedStorages)
  444. for i := 0; i < len(manager.Storages); i++ {
  445. if utils.IsInStringArray(manager.Storages[i].StorageType(), api.SHARED_STORAGE) &&
  446. !utils.IsInStringArray(manager.Storages[i].GetId(), reportSharedStorages) {
  447. log.Debugf("skip report storage %s", manager.Storages[i].GetId())
  448. continue
  449. }
  450. iS := manager.Storages[i]
  451. stat, err := iS.SyncStorageSize()
  452. if err != nil {
  453. log.Errorf("sync storage %s size failed: %s", iS.GetStorageName(), err)
  454. } else {
  455. stat.StorageId = iS.GetId()
  456. stats.StorageStats = append(stats.StorageStats, stat)
  457. }
  458. }
  459. return stats
  460. }
  461. // func StartSyncStorageSizeTask(interval time.Duration) {
  462. // log.Infof("Start sync storage size task !!!")
  463. // for {
  464. // time.Sleep(interval)
  465. // manager := GetManager()
  466. // for i := 0; i < len(manager.Storages); i++ {
  467. // iS := manager.Storages[i]
  468. // if iS.StorageType() == api.STORAGE_LOCAL || iS.StorageType() == api.STORAGE_RBD {
  469. // err := iS.SyncStorageSize()
  470. // if err != nil {
  471. // log.Errorf("sync storage %s size failed: %s", iS.GetStorageName(), err)
  472. // }
  473. // }
  474. // }
  475. // err := manager.host.SyncRootPartitionUsedCapacity()
  476. // if err != nil {
  477. // log.Errorf("sync root partition used size failed: %s", err)
  478. // }
  479. // }
  480. // }
  481. func GetRootPartTotalCapacity() int {
  482. size, err := storageutils.GetTotalSizeMb("/")
  483. if err != nil {
  484. log.Errorf("failed get path %s total size: %s", "/", err)
  485. return -1
  486. }
  487. return size
  488. }
  489. func GetRootPartUsedCapacity() int {
  490. size, err := storageutils.GetUsedSizeMb("/")
  491. if err != nil {
  492. log.Errorf("failed get path %s used size: %s", "/", err)
  493. return -1
  494. }
  495. return size
  496. }