imagecachemanager_agent.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  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/filepath"
  19. "reflect"
  20. "yunion.io/x/cloudmux/pkg/cloudprovider"
  21. "yunion.io/x/cloudmux/pkg/multicloud/esxi"
  22. "yunion.io/x/cloudmux/pkg/multicloud/esxi/vcenter"
  23. "yunion.io/x/jsonutils"
  24. "yunion.io/x/log"
  25. "yunion.io/x/pkg/errors"
  26. api "yunion.io/x/onecloud/pkg/apis/compute"
  27. comapi "yunion.io/x/onecloud/pkg/apis/compute"
  28. "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
  29. "yunion.io/x/onecloud/pkg/hostman/hostutils"
  30. )
  31. type SAgentImageCacheManager struct {
  32. imageCacheManger IImageCacheManger
  33. }
  34. func NewAgentImageCacheManager(manger IImageCacheManger) *SAgentImageCacheManager {
  35. return &SAgentImageCacheManager{manger}
  36. }
  37. type sImageCacheData struct {
  38. ImageId string
  39. HostId string
  40. HostIp string
  41. SrcHostIp string
  42. SrcPath string
  43. SrcDatastore vcenter.SVCenterAccessInfo
  44. Datastore vcenter.SVCenterAccessInfo
  45. Format string
  46. IsForce bool
  47. StoragecacheId string
  48. ImageType string
  49. ImageExternalId string
  50. StorageCacheHostIp string
  51. }
  52. func (c *SAgentImageCacheManager) PrefetchImageCache(ctx context.Context, data interface{}) (jsonutils.JSONObject, error) {
  53. dataDict, ok := data.(*jsonutils.JSONDict)
  54. if !ok {
  55. return nil, errors.Wrap(hostutils.ParamsError, "PrefetchImageCache data format error")
  56. }
  57. idata := new(sImageCacheData)
  58. err := dataDict.Unmarshal(idata)
  59. if err != nil {
  60. return nil, errors.Wrap(err, "%s: unmarshal to sImageCacheData error")
  61. }
  62. lockman.LockRawObject(ctx, idata.HostId, idata.ImageId)
  63. defer lockman.ReleaseRawObject(ctx, idata.HostId, idata.ImageId)
  64. if cloudprovider.TImageType(idata.ImageType) == cloudprovider.ImageTypeSystem {
  65. return c.perfetchTemplateVMImageCache(ctx, idata)
  66. }
  67. if len(idata.SrcHostIp) != 0 {
  68. return c.prefetchImageCacheByCopy(ctx, idata)
  69. }
  70. return c.prefetchImageCacheByUpload(ctx, idata, dataDict)
  71. }
  72. func (c *SAgentImageCacheManager) prefetchImageCacheByCopy(ctx context.Context, data *sImageCacheData) (jsonutils.JSONObject, error) {
  73. client, err := esxi.NewESXiClientFromAccessInfo(ctx, &data.Datastore)
  74. if err != nil {
  75. return nil, err
  76. }
  77. dstHost, err := client.FindHostByIp(data.HostIp)
  78. if err != nil {
  79. return nil, err
  80. }
  81. dstDs, err := dstHost.FindDataStoreById(data.Datastore.PrivateId)
  82. if err != nil {
  83. return nil, err
  84. }
  85. srcHost, err := client.FindHostByIp(data.SrcHostIp)
  86. if err != nil {
  87. return nil, err
  88. }
  89. srcDs, err := srcHost.FindDataStoreById(data.SrcDatastore.PrivateId)
  90. if err != nil {
  91. return nil, err
  92. }
  93. srcPath := data.SrcPath[len(srcDs.GetUrl()):]
  94. dstPath := fmt.Sprintf("image_cache/%s.vmdk", data.ImageId)
  95. // check if dst vmdk has been existed
  96. exists := false
  97. log.Infof("check file: src=%s, dst=%s", srcPath, dstPath)
  98. dstVmdkInfo, err := dstDs.GetVmdkInfo(ctx, dstPath)
  99. if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound {
  100. return nil, err
  101. }
  102. srcVmdkInfo, err := srcDs.GetVmdkInfo(ctx, srcPath)
  103. if err != nil {
  104. return nil, err
  105. }
  106. if dstVmdkInfo != nil && reflect.DeepEqual(dstVmdkInfo, srcVmdkInfo) {
  107. exists = true
  108. }
  109. dstUrl := dstDs.GetPathUrl(dstPath)
  110. if !exists || data.IsForce {
  111. err = dstDs.CheckDirC(filepath.Dir(dstPath))
  112. if err != nil {
  113. return nil, errors.Wrap(err, "dstDs.MakeDir")
  114. }
  115. srcUrl := srcDs.GetPathUrl(srcPath)
  116. log.Infof("Copy %s => %s", srcUrl, dstUrl)
  117. err = client.CopyDisk(ctx, srcUrl, dstUrl, data.IsForce)
  118. if err != nil {
  119. return nil, errors.Wrap(err, "client.CopyDisk")
  120. }
  121. dstVmdkInfo, err = dstDs.GetVmdkInfo(ctx, dstPath)
  122. if err != nil {
  123. return nil, errors.Wrap(err, "dstDs.GetVmdkInfo")
  124. }
  125. }
  126. dstPath = dstDs.GetFullPath(dstPath)
  127. ret := jsonutils.NewDict()
  128. ret.Add(jsonutils.NewInt(dstVmdkInfo.Size()), "size")
  129. ret.Add(jsonutils.NewString(dstPath), "path")
  130. ret.Add(jsonutils.NewString(data.ImageId), "image_id")
  131. _, err = hostutils.RemoteStoragecacheCacheImage(ctx, data.StoragecacheId, data.ImageId, comapi.CACHED_IMAGE_STATUS_ACTIVE, dstPath)
  132. if err != nil {
  133. return nil, err
  134. }
  135. return ret, nil
  136. }
  137. func (c *SAgentImageCacheManager) prefetchImageCacheByUpload(ctx context.Context, data *sImageCacheData,
  138. origin *jsonutils.JSONDict) (jsonutils.JSONObject, error) {
  139. input := api.CacheImageInput{}
  140. origin.Unmarshal(&input)
  141. localImage, err := c.imageCacheManger.PrefetchImageCache(ctx, input)
  142. if err != nil {
  143. return nil, err
  144. }
  145. localImgPath, _ := localImage.GetString("path")
  146. //localImgSize, _ := localImage.Int("size")
  147. client, err := esxi.NewESXiClientFromAccessInfo(ctx, &data.Datastore)
  148. if err != nil {
  149. return nil, errors.Wrap(err, "esxi.NewESXiClientFromJson")
  150. }
  151. host, err := client.FindHostByIp(data.HostIp)
  152. if err != nil {
  153. return nil, err
  154. }
  155. ds, err := host.FindDataStoreById(data.Datastore.PrivateId)
  156. if err != nil {
  157. return nil, errors.Wrap(err, "SHost.FindDataStoreById")
  158. }
  159. format, _ := origin.GetString("format")
  160. if format == "" {
  161. format = "vmdk"
  162. }
  163. remotePath := fmt.Sprintf("image_cache/%s.%s", data.ImageId, format)
  164. // check if dst image is exist
  165. exists := false
  166. if format == "vmdk" {
  167. err = ds.CheckVmdk(ctx, remotePath)
  168. if err != nil {
  169. log.Debugf("ds.CheckVmdk failed: %s", err)
  170. } else {
  171. exists = true
  172. }
  173. } else {
  174. _, err := ds.ListPath(ctx, remotePath)
  175. if err != nil {
  176. if errors.Cause(err) != errors.ErrNotFound {
  177. return nil, errors.Wrapf(err, "unable to check file with path %s", remotePath)
  178. }
  179. } else {
  180. exists = true
  181. }
  182. }
  183. log.Debugf("exist: %t, remotePath: %s", exists, remotePath)
  184. if !exists || data.IsForce {
  185. if format == "iso" {
  186. err := ds.ImportISO(ctx, localImgPath, remotePath)
  187. if err != nil {
  188. return nil, errors.Wrapf(err, "SDatastore.ImportISO %s -> %s", localImage, remotePath)
  189. }
  190. } else {
  191. err := ds.ImportVMDK(ctx, localImgPath, remotePath, host)
  192. if err != nil {
  193. return nil, errors.Wrap(err, "SDatastore.ImportTemplate")
  194. }
  195. }
  196. }
  197. remotePath = ds.GetFullPath(remotePath)
  198. remoteImg := localImage.(*jsonutils.JSONDict)
  199. remoteImg.Add(jsonutils.NewString(remotePath), "path")
  200. _, err = hostutils.RemoteStoragecacheCacheImage(ctx, data.StoragecacheId, data.ImageId, "active", remotePath)
  201. if err != nil {
  202. return nil, err
  203. }
  204. log.Debugf("prefetchImageCacheByUpload over")
  205. return remoteImg, nil
  206. }
  207. func (c *SAgentImageCacheManager) perfetchTemplateVMImageCache(ctx context.Context, data *sImageCacheData) (jsonutils.JSONObject, error) {
  208. client, err := esxi.NewESXiClientFromAccessInfo(ctx, &data.Datastore)
  209. if err != nil {
  210. return nil, errors.Wrap(err, "esxi.NewESXiClientFromJson")
  211. }
  212. _, err = client.SearchTemplateVM(data.ImageExternalId)
  213. if err != nil {
  214. return nil, errors.Wrapf(err, "SEsxiClient.SearchTemplateVM for image %q", data.ImageExternalId)
  215. }
  216. res := jsonutils.NewDict()
  217. res.Add(jsonutils.NewString(data.ImageExternalId), "image_id")
  218. return res, nil
  219. }
  220. func (c *SAgentImageCacheManager) DeleteImageCache(ctx context.Context, data interface{}) (jsonutils.JSONObject, error) {
  221. dataDict, ok := data.(*jsonutils.JSONDict)
  222. if !ok {
  223. return nil, errors.Wrap(hostutils.ParamsError, "DeleteImageCache data format error")
  224. }
  225. var (
  226. imageID, _ = dataDict.GetString("image_id")
  227. hostIP, _ = dataDict.GetString("host_ip")
  228. dsInfo, _ = dataDict.Get("ds_info")
  229. )
  230. client, _, err := esxi.NewESXiClientFromJson(ctx, dsInfo)
  231. if err != nil {
  232. return nil, err
  233. }
  234. host, err := client.FindHostByIp(hostIP)
  235. if err != nil {
  236. return nil, err
  237. }
  238. dsID, _ := dsInfo.GetString("private_id")
  239. ds, err := host.FindDataStoreById(dsID)
  240. if err != nil {
  241. return nil, err
  242. }
  243. remotePath := fmt.Sprintf("image_cache/%s.vmdk", imageID)
  244. return nil, ds.Delete(ctx, remotePath)
  245. }