image.go 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. // Copyright 2023 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 volcengine
  15. import (
  16. "context"
  17. "fmt"
  18. "strings"
  19. "time"
  20. "yunion.io/x/jsonutils"
  21. "yunion.io/x/pkg/errors"
  22. "yunion.io/x/pkg/util/imagetools"
  23. "yunion.io/x/pkg/util/osprofile"
  24. api "yunion.io/x/cloudmux/pkg/apis/compute"
  25. "yunion.io/x/cloudmux/pkg/cloudprovider"
  26. "yunion.io/x/cloudmux/pkg/multicloud"
  27. )
  28. type ImageStatusType string
  29. const (
  30. ImageStatusCreating ImageStatusType = "creating"
  31. ImageStatusAvailable ImageStatusType = "available"
  32. ImageStatusError ImageStatusType = "error"
  33. )
  34. type ImageOwnerType string
  35. const (
  36. ImageOwnerPrivate ImageOwnerType = "private"
  37. ImageOwnerShared ImageOwnerType = "shared"
  38. ImageOwnerPublic ImageOwnerType = "public"
  39. )
  40. type SImage struct {
  41. multicloud.SImageBase
  42. VolcEngineTags
  43. storageCache *SStoragecache
  44. // normalized image info
  45. imgInfo *imagetools.ImageInfo
  46. Architecture string
  47. CreationTime time.Time
  48. Description string
  49. ImageId string
  50. ImageName string
  51. OSName string
  52. OSType string
  53. Visibility string
  54. IsSupportCloudinit bool
  55. IsSupportIoOptimized bool
  56. Platform string
  57. Size int
  58. Status ImageStatusType
  59. Usage string
  60. BootMode string
  61. }
  62. func (img *SImage) GetMinRamSizeMb() int {
  63. return 0
  64. }
  65. func (img *SImage) GetId() string {
  66. return img.ImageId
  67. }
  68. func (img *SImage) GetName() string {
  69. return img.ImageName
  70. }
  71. func (img *SImage) Delete(ctx context.Context) error {
  72. return img.storageCache.region.DeleteImage(img.ImageId)
  73. }
  74. func (img *SImage) GetGlobalId() string {
  75. return img.ImageId
  76. }
  77. func (img *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache {
  78. return img.storageCache
  79. }
  80. func (img *SImage) GetStatus() string {
  81. switch img.Status {
  82. case ImageStatusCreating:
  83. return api.CACHED_IMAGE_STATUS_SAVING
  84. case ImageStatusAvailable:
  85. return api.CACHED_IMAGE_STATUS_ACTIVE
  86. case ImageStatusError:
  87. return api.CACHED_IMAGE_STATUS_CACHE_FAILED
  88. default:
  89. return api.CACHED_IMAGE_STATUS_CACHE_FAILED
  90. }
  91. }
  92. func (region *SRegion) ImportImage(name string, osArch string, osType string, platform, platformVersion string, bucket string, key string) (string, error) {
  93. params := map[string]string{
  94. "Architecture": osArch,
  95. "OsType": osType,
  96. "Platform": platform,
  97. "PlatformVersion": platformVersion,
  98. "Tags.1.Key": "Name",
  99. "Tags.2.Value": name,
  100. "Url": fmt.Sprintf("https://%s.%s/%s", bucket, region.getS3Endpoint(), key),
  101. }
  102. body, err := region.ecsRequest("ImportImage", params)
  103. if err != nil {
  104. return "", errors.Wrapf(err, "ImportImage")
  105. }
  106. imageId, err := body.GetString("ImageId")
  107. if err != nil {
  108. return "", errors.Wrap(err, "Unmarsh imageId failed")
  109. }
  110. return imageId, nil
  111. }
  112. func (region *SRegion) ExportImage(imageId, bucketName string) (string, error) {
  113. params := make(map[string]string)
  114. params["RegionId"] = region.RegionId
  115. params["ImageId"] = imageId
  116. params["OssBucket"] = bucketName
  117. params["OssPrefix"] = fmt.Sprintf("%sexport", strings.Replace(imageId, "-", "", -1))
  118. body, err := region.ecsRequest("ExportImage", params)
  119. if err != nil {
  120. return "", errors.Wrapf(err, "ExportImage")
  121. }
  122. taskId, err := body.GetString("TaskId")
  123. if err != nil {
  124. return "", errors.Wrapf(err, "Unmarshal")
  125. }
  126. return taskId, nil
  127. }
  128. func (img *SImage) GetImageStatus() string {
  129. switch img.Status {
  130. case ImageStatusCreating:
  131. return cloudprovider.IMAGE_STATUS_QUEUED
  132. case ImageStatusAvailable:
  133. return cloudprovider.IMAGE_STATUS_ACTIVE
  134. case ImageStatusError:
  135. return cloudprovider.IMAGE_STATUS_DELETED
  136. default:
  137. return cloudprovider.IMAGE_STATUS_KILLED
  138. }
  139. }
  140. func (img *SImage) Refresh() error {
  141. image, err := img.storageCache.region.GetImage(img.ImageId)
  142. if err != nil {
  143. return err
  144. }
  145. return jsonutils.Update(img, image)
  146. }
  147. func (img *SImage) GetImageType() cloudprovider.TImageType {
  148. switch img.Visibility {
  149. case string(ImageOwnerPublic):
  150. return cloudprovider.ImageTypeSystem
  151. case string(ImageOwnerPrivate), string(ImageOwnerShared):
  152. return cloudprovider.ImageTypeCustomized
  153. default:
  154. return cloudprovider.ImageTypeCustomized
  155. }
  156. }
  157. func (img *SImage) GetSizeByte() int64 {
  158. return int64(img.Size) * 1024 * 1024 * 1024
  159. }
  160. func (img *SImage) GetOsType() cloudprovider.TOsType {
  161. return cloudprovider.TOsType(img.getNormalizedImageInfo().OsType)
  162. }
  163. func (img *SImage) GetOsDist() string {
  164. return img.getNormalizedImageInfo().OsDistro
  165. }
  166. func (img *SImage) getNormalizedImageInfo() *imagetools.ImageInfo {
  167. if img.imgInfo == nil {
  168. imgInfo := imagetools.NormalizeImageInfo(img.OSName, img.Architecture, img.OSType, img.Platform, "")
  169. img.imgInfo = &imgInfo
  170. }
  171. return img.imgInfo
  172. }
  173. func (img *SImage) GetFullOsName() string {
  174. return img.OSName
  175. }
  176. func (img *SImage) GetOsVersion() string {
  177. return img.getNormalizedImageInfo().OsVersion
  178. }
  179. func (img *SImage) GetOsLang() string {
  180. return img.getNormalizedImageInfo().OsLang
  181. }
  182. func (img *SImage) GetOsArch() string {
  183. if strings.Contains(img.Architecture, "arm") {
  184. return osprofile.OS_ARCH_ARM
  185. }
  186. return osprofile.OS_ARCH_X86_64
  187. }
  188. func (img *SImage) GetBios() cloudprovider.TBiosType {
  189. if img.BootMode == "UEFI" {
  190. return cloudprovider.UEFI
  191. }
  192. return cloudprovider.BIOS
  193. }
  194. func (img *SImage) GetMinOsDiskSizeGb() int {
  195. return 40
  196. }
  197. func (img *SImage) GetImageFormat() string {
  198. return "vhd"
  199. }
  200. func (img *SImage) GetCreatedAt() time.Time {
  201. return img.CreationTime
  202. }
  203. func (region *SRegion) GetImage(imageId string) (*SImage, error) {
  204. images, err := region.GetImages("", []string{imageId}, "")
  205. if err != nil {
  206. return nil, err
  207. }
  208. for i := range images {
  209. if images[i].ImageId == imageId {
  210. images[i].storageCache = region.getStoragecache()
  211. return &images[i], nil
  212. }
  213. }
  214. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%s", imageId)
  215. }
  216. func (region *SRegion) GetImageByName(name string) (*SImage, error) {
  217. images, err := region.GetImages("", nil, name)
  218. if err != nil {
  219. return nil, err
  220. }
  221. for i := range images {
  222. if images[i].ImageName == name {
  223. return &images[i], nil
  224. }
  225. }
  226. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%s", name)
  227. }
  228. func (region *SRegion) GetImageStatus(imageId string) (ImageStatusType, error) {
  229. image, err := region.GetImage(imageId)
  230. if err != nil {
  231. return "", err
  232. }
  233. return image.Status, nil
  234. }
  235. func (region *SRegion) GetImages(visibility string, imageIds []string, name string) ([]SImage, error) {
  236. params := make(map[string]string)
  237. params["MaxResults"] = "100"
  238. for i, id := range imageIds {
  239. params[fmt.Sprintf("ImageIds.%d", i+1)] = id
  240. }
  241. if len(visibility) > 0 {
  242. params["Visibility"] = visibility
  243. }
  244. if len(name) > 0 {
  245. params["ImageName"] = name
  246. }
  247. ret := []SImage{}
  248. for {
  249. resp, err := region.ecsRequest("DescribeImages", params)
  250. if err != nil {
  251. return nil, errors.Wrapf(err, "DescribeImages")
  252. }
  253. part := struct {
  254. Images []SImage
  255. NextToken string
  256. }{}
  257. err = resp.Unmarshal(&part)
  258. if err != nil {
  259. return nil, err
  260. }
  261. ret = append(ret, part.Images...)
  262. if len(part.NextToken) == 0 || len(part.Images) == 0 {
  263. break
  264. }
  265. params["NextToken"] = part.NextToken
  266. }
  267. return ret, nil
  268. }
  269. func (region *SRegion) DeleteImage(imageId string) error {
  270. params := make(map[string]string)
  271. params["RegionId"] = region.RegionId
  272. params["ImageId"] = imageId
  273. params["Force"] = "true"
  274. _, err := region.ecsRequest("DeleteImage", params)
  275. if err != nil {
  276. return errors.Wrapf(err, "DeleteImage fail")
  277. }
  278. return nil
  279. }