yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/proxmox/image.go (about) 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 15 package proxmox 16 17 import ( 18 "context" 19 "fmt" 20 "net/url" 21 "regexp" 22 "strconv" 23 "strings" 24 25 "yunion.io/x/pkg/errors" 26 27 api "yunion.io/x/cloudmux/pkg/apis/compute" 28 "yunion.io/x/cloudmux/pkg/cloudprovider" 29 "yunion.io/x/cloudmux/pkg/multicloud" 30 "yunion.io/x/onecloud/pkg/util/imagetools" 31 ) 32 33 type SImage struct { 34 multicloud.SImageBase 35 ProxmoxTags 36 cache *SStoragecache 37 38 imageInfo *imagetools.ImageInfo 39 40 VmId int 41 Node string 42 Name string 43 Format string 44 SizeGB float64 45 } 46 47 func (self *SImage) GetMinRamSizeMb() int { 48 return 0 49 } 50 51 func (self *SImage) GetId() string { 52 return fmt.Sprintf("%d", self.VmId) 53 } 54 55 func (self *SImage) GetName() string { 56 return self.Name 57 } 58 59 func (self *SImage) Delete(ctx context.Context) error { 60 return cloudprovider.ErrNotImplemented 61 } 62 63 func (self *SImage) GetGlobalId() string { 64 return self.GetId() 65 } 66 67 func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { 68 return self.cache 69 } 70 71 func (self *SImage) GetStatus() string { 72 return api.CACHED_IMAGE_STATUS_ACTIVE 73 } 74 75 func (self *SImage) GetImageStatus() string { 76 return cloudprovider.IMAGE_STATUS_ACTIVE 77 } 78 79 func (self *SImage) GetImageType() cloudprovider.TImageType { 80 return cloudprovider.ImageTypeSystem 81 } 82 83 func (self *SImage) GetSizeByte() int64 { 84 return int64(self.SizeGB * 1024 * 1024) 85 } 86 87 func (img *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { 88 if img.imageInfo == nil { 89 imgInfo := imagetools.NormalizeImageInfo(img.Name, "", "", "", "") 90 img.imageInfo = &imgInfo 91 } 92 return img.imageInfo 93 } 94 95 func (img *SImage) GetOsType() cloudprovider.TOsType { 96 return cloudprovider.TOsType(img.getNormalizedImageInfo().OsType) 97 } 98 99 func (img *SImage) GetOsDist() string { 100 return img.getNormalizedImageInfo().OsDistro 101 } 102 103 func (img *SImage) GetOsVersion() string { 104 return img.getNormalizedImageInfo().OsVersion 105 } 106 107 func (img *SImage) GetOsArch() string { 108 return img.getNormalizedImageInfo().OsArch 109 } 110 111 func (img *SImage) GetOsLang() string { 112 return img.getNormalizedImageInfo().OsLang 113 } 114 115 func (img *SImage) GetFullOsName() string { 116 return img.Name 117 } 118 119 func (img *SImage) GetBios() cloudprovider.TBiosType { 120 return cloudprovider.BIOS 121 } 122 123 func (self *SImage) GetMinOsDiskSizeGb() int { 124 if self.GetOsType() == "windows" { 125 return 40 126 } 127 return 30 128 } 129 130 func (self *SImage) GetImageFormat() string { 131 return "raw" 132 } 133 134 func (self *SRegion) GetImageList() ([]SImage, error) { 135 ret := []SImage{} 136 resources, err := self.GetClusterVmResources() 137 if err != nil { 138 return nil, err 139 } 140 for _, vm := range resources { 141 if vm.Template == true { 142 image := SImage{ 143 VmId: vm.VmId, 144 Name: vm.Name, 145 Node: vm.Node, 146 } 147 148 res := fmt.Sprintf("/nodes/%s/qemu/%d/config", image.Node, image.VmId) 149 vmConfig := map[string]interface{}{} 150 err := self.get(res, url.Values{}, &vmConfig) 151 if err != nil { 152 return nil, err 153 } 154 155 diskNames := []string{} 156 for k := range vmConfig { 157 if diskName := regexp.MustCompile(`(virtio|scsi|sata)\d+`).FindStringSubmatch(k); len(diskName) > 0 { 158 diskNames = append(diskNames, diskName[0]) 159 } 160 } 161 162 for _, diskName := range diskNames { 163 diskConfStr := vmConfig[diskName].(string) 164 diskConfMap := ParsePMConf(diskConfStr, "volume") 165 166 if diskConfMap["volume"].(string) == "none" { 167 continue 168 } 169 if diskConfMap["media"] != nil { 170 continue 171 } 172 173 storageName, fileName := ParseSubConf(diskConfMap["volume"].(string), ":") 174 diskConfMap["storage"] = storageName 175 diskConfMap["file"] = fileName 176 177 // cloud-init disks not always have the size sent by the API, which results in a crash 178 if diskConfMap["size"] == nil && strings.Contains(fileName.(string), "cloudinit") { 179 diskConfMap["size"] = "4M" // default cloud-init disk size 180 } 181 182 image.SizeGB += DiskSizeGB(diskConfMap["size"]) 183 184 } 185 ret = append(ret, image) 186 } 187 } 188 189 return ret, nil 190 } 191 192 func (self *SRegion) GetImage(id string) (*SImage, error) { 193 image := &SImage{} 194 vmId, err := strconv.Atoi(id) 195 if err != nil { 196 return nil, err 197 } 198 resources, err := self.GetClusterVmResources() 199 if err != nil { 200 return nil, err 201 } 202 if resources[vmId].Template == false { 203 return nil, errors.Errorf("self.GetDisk") 204 } 205 image.VmId = resources[vmId].VmId 206 image.Name = resources[vmId].Name 207 image.Node = resources[vmId].Node 208 res := fmt.Sprintf("/nodes/%s/qemu/%d/config", image.Node, image.VmId) 209 vmConfig := map[string]interface{}{} 210 err = self.get(res, url.Values{}, &vmConfig) 211 if err != nil { 212 return nil, err 213 } 214 215 diskNames := []string{} 216 for k := range vmConfig { 217 if diskName := regexp.MustCompile(`(virtio|scsi|sata)\d+`).FindStringSubmatch(k); len(diskName) > 0 { 218 diskNames = append(diskNames, diskName[0]) 219 } 220 } 221 222 for _, diskName := range diskNames { 223 diskConfStr := vmConfig[diskName].(string) 224 diskConfMap := ParsePMConf(diskConfStr, "volume") 225 226 if diskConfMap["volume"].(string) == "none" || diskConfMap["media"].(string) == "cdrom" { 227 continue 228 } 229 230 storageName, fileName := ParseSubConf(diskConfMap["volume"].(string), ":") 231 diskConfMap["storage"] = storageName 232 diskConfMap["file"] = fileName 233 234 // cloud-init disks not always have the size sent by the API, which results in a crash 235 if diskConfMap["size"] == nil && strings.Contains(fileName.(string), "cloudinit") { 236 diskConfMap["size"] = "4M" // default cloud-init disk size 237 } 238 239 var sizeInTerabytes = regexp.MustCompile(`[0-9]+T`) 240 // Convert to gigabytes if disk size was received in terabytes 241 matched := sizeInTerabytes.MatchString(diskConfMap["size"].(string)) 242 if matched { 243 image.SizeGB += DiskSizeGB(diskConfMap["size"]) 244 } 245 246 } 247 248 return image, nil 249 }