imagecache_lvm.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  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. "path"
  19. "sync"
  20. "yunion.io/x/jsonutils"
  21. "yunion.io/x/log"
  22. "yunion.io/x/pkg/errors"
  23. "yunion.io/x/pkg/util/httputils"
  24. "yunion.io/x/pkg/util/qemuimgfmt"
  25. api "yunion.io/x/onecloud/pkg/apis/compute"
  26. "yunion.io/x/onecloud/pkg/hostman/hostutils"
  27. "yunion.io/x/onecloud/pkg/hostman/storageman/lvmutils"
  28. "yunion.io/x/onecloud/pkg/hostman/storageman/remotefile"
  29. modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
  30. "yunion.io/x/onecloud/pkg/util/procutils"
  31. "yunion.io/x/onecloud/pkg/util/qemuimg"
  32. "yunion.io/x/onecloud/pkg/util/qemutils"
  33. )
  34. type SLVMImageCache struct {
  35. imageId string
  36. cond *sync.Cond
  37. Manager IImageCacheManger
  38. }
  39. func NewLVMImageCache(imageId string, imagecacheManager IImageCacheManger) *SLVMImageCache {
  40. imageCache := new(SLVMImageCache)
  41. imageCache.imageId = imageId
  42. imageCache.Manager = imagecacheManager
  43. imageCache.cond = sync.NewCond(new(sync.Mutex))
  44. return imageCache
  45. }
  46. func (c *SLVMImageCache) GetPath() string {
  47. return path.Join("/dev", c.Manager.GetPath(), IMAGECACHE_PREFIX+c.imageId)
  48. }
  49. func (c *SLVMImageCache) GetName() string {
  50. return IMAGECACHE_PREFIX + c.imageId
  51. }
  52. func (c *SLVMImageCache) GetDesc() *remotefile.SImageDesc {
  53. var sizeMb int64
  54. img, err := qemuimg.NewQemuImage(c.GetPath())
  55. if err != nil {
  56. log.Errorf("failed NewQemuImage for imagecache %s: %s", c.GetPath(), err)
  57. } else {
  58. sizeMb = img.SizeBytes / 1024 / 1024
  59. }
  60. return &remotefile.SImageDesc{
  61. SizeMb: sizeMb,
  62. Name: c.GetName(),
  63. }
  64. }
  65. func (c *SLVMImageCache) Load() error {
  66. log.Debugf("loading lvm imagecache %s", c.GetPath())
  67. if c.Manager.Lvmlockd() {
  68. err := lvmutils.LVActive(c.GetPath(), true, false)
  69. if err != nil {
  70. return errors.Wrap(err, "lvmlockd set lv shared")
  71. }
  72. }
  73. origin, err := qemuimg.NewQemuImage(c.GetPath())
  74. if err != nil {
  75. return errors.Wrap(err, "NewQemuImage")
  76. }
  77. if origin.IsValid() {
  78. return nil
  79. }
  80. return fmt.Errorf("invalid lvm image %s", origin.String())
  81. }
  82. func (c *SLVMImageCache) Acquire(
  83. ctx context.Context, input api.CacheImageInput,
  84. callback func(progress, progressMbps float64, totalSizeMb int64),
  85. ) error {
  86. input.ImageId = c.imageId
  87. localImageCache, err := storageManager.LocalStorageImagecacheManager.AcquireImage(ctx, input, func(progress, progressMbps float64, totalSizeMb int64) {
  88. if len(input.ServerId) > 0 {
  89. hostutils.UpdateServerProgress(context.Background(), input.ServerId, progress/1.2, progressMbps)
  90. }
  91. })
  92. if err != nil {
  93. return errors.Wrapf(err, "LocalStorage.AcquireImage")
  94. }
  95. if err := c.Load(); err != nil {
  96. log.Errorf("failed load image cache %s %s, try create", c.imageId, err)
  97. localImg, err := qemuimg.NewQemuImage(localImageCache.GetPath())
  98. if err != nil {
  99. return errors.Wrapf(err, "NewQemuImage for local image path %s", localImageCache.GetPath())
  100. }
  101. lvSize := lvmutils.GetQcow2LvSize(localImg.SizeBytes/1024/1024) * 1024 * 1024
  102. err = lvmutils.LvCreate(c.Manager.GetPath(), c.GetName(), lvSize)
  103. if err != nil {
  104. return errors.Wrap(err, "lvm image cache acquire")
  105. }
  106. log.Infof("lvm lockd with cache %s %v", c.GetPath(), c.Manager.Lvmlockd())
  107. if c.Manager.Lvmlockd() {
  108. err = lvmutils.LVActive(c.GetPath(), true, false)
  109. if err != nil {
  110. return errors.Wrap(err, "lvmlockd set lv shared")
  111. }
  112. }
  113. targetImageFormat := "qcow2"
  114. if localImg.Format != qemuimgfmt.QCOW2 {
  115. targetImageFormat = "raw"
  116. }
  117. log.Infof("convert local image %s to lvm %s", c.imageId, c.GetPath())
  118. out, err := procutils.NewRemoteCommandAsFarAsPossible(qemutils.GetQemuImg(),
  119. "convert", "-W", "-m", "16", "-O", targetImageFormat, localImageCache.GetPath(), c.GetPath()).Output()
  120. if err != nil {
  121. return errors.Wrapf(err, "convert local image %s to lvm %s: %s", c.imageId, c.GetPath(), out)
  122. }
  123. if len(input.ServerId) > 0 {
  124. modules.Servers.Update(hostutils.GetComputeSession(context.Background()), input.ServerId, jsonutils.Marshal(map[string]float32{"progress": 100.0}))
  125. }
  126. }
  127. return c.Load()
  128. }
  129. func (c *SLVMImageCache) GetImageId() string {
  130. return c.imageId
  131. }
  132. func (r *SLVMImageCache) Release() {
  133. return
  134. }
  135. func (c *SLVMImageCache) Remove(ctx context.Context) error {
  136. if err := lvmutils.LvRemove(c.GetPath()); err != nil {
  137. return errors.Wrap(err, "lvmImageCache Remove")
  138. }
  139. go func() {
  140. _, err := modules.Storagecachedimages.Detach(hostutils.GetComputeSession(ctx),
  141. c.Manager.GetId(), c.imageId, nil)
  142. if err != nil && httputils.ErrorCode(err) != 404 {
  143. log.Errorf("Fail to delete host cached image: %s", err)
  144. }
  145. }()
  146. return nil
  147. }
  148. func (c *SLVMImageCache) GetAccessDirectory() (string, error) {
  149. return "", errors.ErrNotImplemented
  150. }