disk_base.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  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. "net/http"
  19. "path"
  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/onecloud/pkg/apis"
  25. api "yunion.io/x/onecloud/pkg/apis/compute"
  26. container_storage "yunion.io/x/onecloud/pkg/hostman/container/storage"
  27. "yunion.io/x/onecloud/pkg/hostman/guestman/desc"
  28. deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
  29. "yunion.io/x/onecloud/pkg/hostman/hostdeployer/deployclient"
  30. "yunion.io/x/onecloud/pkg/mcclient/auth"
  31. "yunion.io/x/onecloud/pkg/util/qemuimg"
  32. "yunion.io/x/onecloud/pkg/util/seclib2"
  33. )
  34. type IDisk interface {
  35. GetType() string
  36. GetId() string
  37. Probe() error
  38. GetPath() string
  39. GetFormat() (string, error)
  40. GetDiskDesc() jsonutils.JSONObject
  41. GetDiskSetupScripts(idx int) string
  42. OnRebuildRoot(ctx context.Context, params api.DiskAllocateInput) error
  43. GetSnapshotDir() string
  44. DoDeleteSnapshot(snapshotId string) error
  45. GetSnapshotLocation() string
  46. GetSnapshotPath(snapshotId string) string
  47. RollbackDiskOnSnapshotFail(snapshotId string) error
  48. GetStorage() IStorage
  49. DeleteAllSnapshot(skipRecycle bool) error
  50. DiskSnapshot(ctx context.Context, params interface{}) (jsonutils.JSONObject, error)
  51. DiskDeleteSnapshot(ctx context.Context, params interface{}) (jsonutils.JSONObject, error)
  52. Delete(ctx context.Context, params interface{}) (jsonutils.JSONObject, error)
  53. Resize(ctx context.Context, params *SDiskResizeInput) (jsonutils.JSONObject, error)
  54. PreResize(ctx context.Context, sizeMb int64) error
  55. PrepareSaveToGlance(ctx context.Context, params interface{}) (jsonutils.JSONObject, error)
  56. ResetFromSnapshot(ctx context.Context, params interface{}) (jsonutils.JSONObject, error)
  57. CleanupSnapshots(ctx context.Context, params interface{}) (jsonutils.JSONObject, error)
  58. PrepareMigrate(liveMigrate bool) ([]string, string, bool, error)
  59. RebuildSlaveDisk(diskUri string) error
  60. CreateFromUrl(ctx context.Context, url string, size int64, callback func(progress, progressMbps float64, totalSizeMb int64)) error
  61. CreateFromTemplate(context.Context, string, string, int64, *apis.SEncryptInfo) (jsonutils.JSONObject, error)
  62. CreateFromSnapshotLocation(ctx context.Context, location string, size int64, encryptInfo *apis.SEncryptInfo) (jsonutils.JSONObject, error)
  63. CreateFromRbdSnapshot(ctx context.Context, snapshotId, srcDiskId, srcPool string) error
  64. CreateFromRemoteHostImage(ctx context.Context, url string, size int64, encryptInfo *apis.SEncryptInfo) error
  65. CreateRaw(ctx context.Context, sizeMb int, diskFormat string, fsFormat string, fsFeatures *api.DiskFsFeatures, encryptInfo *apis.SEncryptInfo, diskId string, back string) (jsonutils.JSONObject, error)
  66. PostCreateFromRemoteHostImage(diskUrl string)
  67. CreateSnapshot(snapshotId string, encryptKey string, encFormat qemuimg.TEncryptFormat, encAlg seclib2.TSymEncAlg) error
  68. DeleteSnapshot(snapshotId, convertSnapshot string, blockStream bool, encryptInfo apis.SEncryptInfo) error
  69. DeployGuestFs(diskInfo *deployapi.DiskInfo, guestDesc *desc.SGuestDesc,
  70. deployInfo *deployapi.DeployInfo) (jsonutils.JSONObject, error)
  71. ConvertSnapshotRelyOnReloadDisk(convertSnapshotId string, encryptInfo apis.SEncryptInfo) (func() error, error)
  72. // GetBackupDir() string
  73. DiskBackup(ctx context.Context, params interface{}) (jsonutils.JSONObject, error)
  74. IsFile() bool
  75. GetContainerStorageDriver() (container_storage.IContainerStorage, error)
  76. }
  77. type SBaseDisk struct {
  78. Id string
  79. Storage IStorage
  80. }
  81. func NewBaseDisk(storage IStorage, id string) *SBaseDisk {
  82. var ret = new(SBaseDisk)
  83. ret.Storage = storage
  84. ret.Id = id
  85. return ret
  86. }
  87. func (d *SBaseDisk) GetId() string {
  88. return d.Id
  89. }
  90. func (d *SBaseDisk) GetStorage() IStorage {
  91. return d.Storage
  92. }
  93. func (d *SBaseDisk) GetPath() string {
  94. return path.Join(d.Storage.GetPath(), d.Id)
  95. }
  96. func (d *SBaseDisk) GetFormat() (string, error) {
  97. return "", nil
  98. }
  99. func (d *SBaseDisk) OnRebuildRoot(ctx context.Context, params api.DiskAllocateInput) error {
  100. return errors.Errorf("unsupported operation")
  101. }
  102. func (d *SBaseDisk) CreateFromUrl(ctx context.Context, url string, size int64, callback func(progress, progressMbps float64, totalSizeMb int64)) error {
  103. return errors.Errorf("unsupported operation")
  104. }
  105. func (d *SBaseDisk) CreateFromTemplate(context.Context, string, string, int64, *apis.SEncryptInfo) (jsonutils.JSONObject, error) {
  106. return nil, errors.Errorf("unsupported operation")
  107. }
  108. func (d *SBaseDisk) CreateFromSnapshotLocation(ctx context.Context, location string, size int64, encryptInfo *apis.SEncryptInfo) (jsonutils.JSONObject, error) {
  109. return nil, errors.Errorf("Not implemented")
  110. }
  111. func (d *SBaseDisk) CreateFromRemoteHostImage(ctx context.Context, url string, size int64, encryptInfo *apis.SEncryptInfo) error {
  112. return errors.Errorf("unsupported operation")
  113. }
  114. func (d *SBaseDisk) Resize(context.Context, *SDiskResizeInput) (jsonutils.JSONObject, error) {
  115. return nil, errors.Errorf("unsupported operation")
  116. }
  117. func (d *SBaseDisk) PreResize(ctx context.Context, sizeMb int64) error {
  118. return nil
  119. }
  120. func (d *SBaseDisk) CreateSnapshot(snapshotId string, encryptKey string, encFormat qemuimg.TEncryptFormat, encAlg seclib2.TSymEncAlg) error {
  121. return errors.Errorf("unsupported operation")
  122. }
  123. func (d *SBaseDisk) ConvertSnapshotRelyOnReloadDisk(convertSnapshotId string, encryptInfo apis.SEncryptInfo) (func() error, error) {
  124. return nil, errors.Errorf("unsupported operation")
  125. }
  126. func (d *SBaseDisk) DeleteSnapshot(snapshotId, convertSnapshot string, blockStream bool, encryptInfo apis.SEncryptInfo) error {
  127. return errors.Errorf("unsupported operation")
  128. }
  129. func (d *SBaseDisk) DeleteAllSnapshot(skipRecycle bool) error {
  130. return errors.Errorf("unsupported operation")
  131. }
  132. func (d *SBaseDisk) PrepareSaveToGlance(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {
  133. return nil, errors.Errorf("unsupported operation")
  134. }
  135. func (d *SBaseDisk) ResetFromSnapshot(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {
  136. return nil, errors.Errorf("unsupported operation")
  137. }
  138. func (d *SBaseDisk) CleanupSnapshots(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {
  139. return nil, errors.Errorf("unsupported operation")
  140. }
  141. func (d *SBaseDisk) PrepareMigrate(liveMigrate bool) ([]string, string, bool, error) {
  142. return nil, "", false, errors.Errorf("unsupported operation")
  143. }
  144. func (d *SBaseDisk) RebuildSlaveDisk(diskUri string) error {
  145. return nil
  146. }
  147. func (d *SBaseDisk) PostCreateFromRemoteHostImage(string) {
  148. }
  149. func (d *SBaseDisk) GetZoneId() string {
  150. return d.Storage.GetZoneId()
  151. }
  152. func (d *SBaseDisk) DeployGuestFs(diskInfo *deployapi.DiskInfo, guestDesc *desc.SGuestDesc,
  153. deployInfo *deployapi.DeployInfo) (jsonutils.JSONObject, error) {
  154. deployGuestDesc := deployapi.GuestStructDescToDeployDesc(guestDesc)
  155. deployGuestDesc.Hypervisor = api.HYPERVISOR_KVM
  156. ret, err := deployclient.GetDeployClient().DeployGuestFs(
  157. context.Background(), &deployapi.DeployParams{
  158. DiskInfo: diskInfo,
  159. GuestDesc: deployGuestDesc,
  160. DeployInfo: deployInfo,
  161. },
  162. )
  163. if err != nil {
  164. return nil, errors.Wrap(err, "request deploy guest fs")
  165. }
  166. return jsonutils.Marshal(ret), nil
  167. }
  168. func (d *SBaseDisk) ResizeFs(resizeDiskInput *deployapi.DiskInfo, guestDesc *deployapi.GuestDesc) error {
  169. _, err := deployclient.GetDeployClient().ResizeFs(
  170. context.Background(), &deployapi.ResizeFsParams{
  171. DiskInfo: resizeDiskInput,
  172. GuestDesc: guestDesc,
  173. })
  174. return err
  175. }
  176. func (d *SBaseDisk) GetDiskSetupScripts(diskIndex int) string {
  177. return ""
  178. }
  179. func (d *SBaseDisk) GetSnapshotLocation() string {
  180. return ""
  181. }
  182. func (d *SBaseDisk) GetSnapshotPath(snapshotId string) string {
  183. return ""
  184. }
  185. func ConvertDiskFsFeaturesToDeploy(fsFeatures *api.DiskFsFeatures) *deployapi.FsFeatures {
  186. if fsFeatures == nil {
  187. return nil
  188. }
  189. ret := &deployapi.FsFeatures{}
  190. if fsFeatures.Ext4 != nil {
  191. ret.Ext4 = &deployapi.FsExt4Features{
  192. CaseInsensitive: fsFeatures.Ext4.CaseInsensitive,
  193. ReservedBlocksPercentage: int32(fsFeatures.Ext4.ReservedBlocksPercentage),
  194. }
  195. }
  196. if fsFeatures.F2fs != nil {
  197. ret.F2Fs = &deployapi.FsF2FsFeatures{
  198. CaseInsensitive: fsFeatures.F2fs.CaseInsensitive,
  199. OverprovisionRatioPercentage: int32((fsFeatures.F2fs.OverprovisionRatioPercentage)),
  200. }
  201. }
  202. return ret
  203. }
  204. func (d *SBaseDisk) FormatFs(fsFormat string, fsFeatures *api.DiskFsFeatures, uuid string, diskInfo *deployapi.DiskInfo) error {
  205. log.Infof("Make disk %s fs %s, features: %s", uuid, fsFormat, jsonutils.Marshal(fsFeatures))
  206. _, err := deployclient.GetDeployClient().FormatFs(
  207. context.Background(),
  208. &deployapi.FormatFsParams{
  209. DiskInfo: diskInfo,
  210. FsFormat: fsFormat,
  211. FsFeatures: ConvertDiskFsFeaturesToDeploy(fsFeatures),
  212. Uuid: uuid,
  213. },
  214. )
  215. if err != nil {
  216. log.Errorf("Format fs error : %s", err)
  217. return err
  218. }
  219. return nil
  220. }
  221. func (d *SBaseDisk) DiskSnapshot(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {
  222. return nil, fmt.Errorf("Not implement disk.DiskSnapshot")
  223. }
  224. func (d *SBaseDisk) DiskDeleteSnapshot(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {
  225. return nil, fmt.Errorf("Not implement disk.DiskDeleteSnapshot")
  226. }
  227. func (d *SBaseDisk) CreateFromRbdSnapshot(ctx context.Context, napshotUrl, srcDiskId, srcPool string) error {
  228. return fmt.Errorf("Not implement disk.CreateFromRbdSnapshot")
  229. }
  230. func (d *SBaseDisk) DoDeleteSnapshot(snapshotId string) error {
  231. return fmt.Errorf("Not implement disk.DoDeleteSnapshot")
  232. }
  233. func (d *SBaseDisk) RollbackDiskOnSnapshotFail(snapshotId string) error {
  234. return errors.Errorf("Not implement disk.DoDeleteSnapshot")
  235. }
  236. func (d *SBaseDisk) GetBackupDir() string {
  237. return ""
  238. }
  239. func (d *SBaseDisk) GetContainerStorageDriver() (container_storage.IContainerStorage, error) {
  240. return nil, errors.Wrap(errors.ErrNotImplemented, "GetContainerStorageDriver")
  241. }
  242. func (d *SBaseDisk) RequestExportNbdImage(ctx context.Context, url string, encryptInfo *apis.SEncryptInfo) (int64, error) {
  243. body := jsonutils.NewDict()
  244. body.Set("disk_id", jsonutils.NewString(d.GetId()))
  245. header := http.Header{}
  246. userCred := auth.AdminCredential()
  247. header.Set("X-Auth-Token", userCred.GetTokenString())
  248. if encryptInfo != nil {
  249. header.Set("X-Encrypt-Key", encryptInfo.Key)
  250. header.Set("X-Encrypt-Alg", string(encryptInfo.Alg))
  251. }
  252. url = fmt.Sprintf("%s/%s", url, "nbd-export")
  253. httpClient := httputils.GetDefaultClient()
  254. _, respBody, err := httputils.JSONRequest(httpClient, ctx, "POST", url, header, body, false)
  255. if err != nil {
  256. return -1, errors.Wrap(err, "request export image")
  257. }
  258. nbdPort, err := respBody.Int("nbd_port")
  259. if err != nil {
  260. return -1, errors.Wrapf(err, "failed get nbd port from %s", url)
  261. }
  262. return nbdPort, nil
  263. }
  264. func (d *SBaseDisk) RequestCloseNbdImage(ctx context.Context, url string) error {
  265. body := jsonutils.NewDict()
  266. body.Set("disk_id", jsonutils.NewString(d.GetId()))
  267. header := http.Header{}
  268. userCred := auth.AdminCredential()
  269. header.Set("X-Auth-Token", userCred.GetTokenString())
  270. url = fmt.Sprintf("%s/%s", url, "nbd-close")
  271. httpClient := httputils.GetDefaultClient()
  272. _, _, err := httputils.JSONRequest(httpClient, ctx, "POST", url, header, body, false)
  273. if err != nil {
  274. return errors.Wrap(err, "request close image")
  275. }
  276. return nil
  277. }