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  }