yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/hcso/host.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 hcso 16 17 import ( 18 "fmt" 19 "strings" 20 21 "yunion.io/x/jsonutils" 22 "yunion.io/x/log" 23 "yunion.io/x/pkg/errors" 24 "yunion.io/x/pkg/util/osprofile" 25 26 api "yunion.io/x/cloudmux/pkg/apis/compute" 27 "yunion.io/x/cloudmux/pkg/cloudprovider" 28 "yunion.io/x/cloudmux/pkg/multicloud" 29 "yunion.io/x/onecloud/pkg/util/billing" 30 ) 31 32 type SHost struct { 33 multicloud.SHostBase 34 zone *SZone 35 vms []SInstance 36 37 // 华为私有云没有直接列出host的接口,所有账号下的host都是通过VM反向解析出来的 38 // 当账号下没有虚拟机时,如果没有host,会导致调度找不到可用的HOST。 39 // 因此,为了避免上述情况始终会在每个zone下返回一台虚拟的host 40 IsFake bool 41 projectId string 42 Id string 43 Name string 44 } 45 46 func (self *SHost) GetId() string { 47 return self.Id 48 } 49 50 func (self *SHost) GetName() string { 51 if len(self.Name) > 0 { 52 return self.Name 53 } 54 55 return self.Id 56 } 57 58 func (self *SHost) GetGlobalId() string { 59 return self.Id 60 } 61 62 func (self *SHost) GetStatus() string { 63 return api.HOST_STATUS_RUNNING 64 } 65 66 func (self *SHost) Refresh() error { 67 _, err := self.getVMs() 68 return errors.Wrap(err, "getVMs") 69 } 70 71 func (self *SHost) IsEmulated() bool { 72 return self.IsFake 73 } 74 75 func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { 76 var vms []SInstance 77 var err error 78 if self.vms != nil { 79 vms = self.vms 80 } else { 81 vms, err = self.getVMs() 82 if err != nil { 83 return nil, err 84 } 85 } 86 87 ret := make([]cloudprovider.ICloudVM, len(vms)) 88 for i := range vms { 89 vm := vms[i] 90 vm.host = self 91 ret[i] = &vm 92 } 93 94 return ret, nil 95 } 96 97 func (self *SHost) getVMs() ([]SInstance, error) { 98 vms, err := self.zone.region.GetInstances() 99 if err != nil { 100 return nil, errors.Wrap(err, "GetInstances") 101 } 102 103 ret := []SInstance{} 104 for i := range vms { 105 vm := vms[i] 106 if vm.OSEXTAZAvailabilityZone == self.GetId() && vm.HostID == self.GetId() { 107 vm.host = self 108 ret = append(ret, vm) 109 } 110 } 111 112 self.vms = ret 113 return ret, nil 114 } 115 116 func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { 117 vm, err := self.zone.region.GetInstanceByID(id) 118 if vm.HostID != self.GetId() { 119 return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetInstanceByID") 120 } 121 122 vm.host = self 123 return &vm, err 124 } 125 126 func (self *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { 127 return self.zone.GetIWires() 128 } 129 130 func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { 131 return self.zone.GetIStorages() 132 } 133 134 func (self *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { 135 return self.zone.GetIStorageById(id) 136 } 137 138 func (self *SHost) GetEnabled() bool { 139 return true 140 } 141 142 func (self *SHost) GetHostStatus() string { 143 return api.HOST_ONLINE 144 } 145 146 func (self *SHost) GetAccessIp() string { 147 return "" 148 } 149 150 func (self *SHost) GetAccessMac() string { 151 return "" 152 } 153 154 func (self *SHost) GetSysInfo() jsonutils.JSONObject { 155 info := jsonutils.NewDict() 156 info.Add(jsonutils.NewString(CLOUD_PROVIDER_HUAWEI), "manufacture") 157 info.Add(jsonutils.NewString(self.GetId()), "id") 158 info.Add(jsonutils.NewString(self.GetName()), "name") 159 return info 160 } 161 162 func (self *SHost) GetSN() string { 163 return "" 164 } 165 166 func (self *SHost) GetCpuCount() int { 167 return 0 168 } 169 170 func (self *SHost) GetNodeCount() int8 { 171 return 0 172 } 173 174 func (self *SHost) GetCpuDesc() string { 175 return "" 176 } 177 178 func (self *SHost) GetCpuMhz() int { 179 return 0 180 } 181 182 func (self *SHost) GetMemSizeMB() int { 183 return 0 184 } 185 186 func (self *SHost) GetStorageSizeMB() int { 187 return 0 188 } 189 190 func (self *SHost) GetStorageType() string { 191 return api.DISK_TYPE_HYBRID 192 } 193 194 func (self *SHost) GetHostType() string { 195 return api.HOST_TYPE_HCSO 196 } 197 198 func (self *SHost) GetIsMaintenance() bool { 199 return false 200 } 201 202 func (self *SHost) GetVersion() string { 203 return HUAWEI_API_VERSION 204 } 205 206 func (self *SHost) GetInstanceById(instanceId string) (*SInstance, error) { 207 instance, err := self.zone.region.GetInstanceByID(instanceId) 208 if err != nil { 209 return nil, err 210 } 211 212 if instance.HostID != self.GetId() { 213 return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetInstanceByID") 214 } 215 216 instance.host = self 217 return &instance, nil 218 } 219 220 func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { 221 vmId, err := self._createVM( 222 desc.Name, desc.ExternalImageId, desc.SysDisk, 223 desc.Cpu, desc.MemoryMB, desc.InstanceType, 224 desc.ExternalNetworkId, desc.IpAddr, 225 desc.Description, desc.Account, 226 desc.Password, desc.DataDisks, 227 desc.PublicKey, desc.ExternalSecgroupId, 228 desc.UserData, desc.BillingCycle, desc.ProjectId, desc.Tags) 229 if err != nil { 230 return nil, err 231 } 232 233 // VM实际调度到的host, 可能不是当前host.因此需要改写host信息 234 vm, err := self.zone.region.GetIVMById(vmId) 235 if err != nil { 236 return nil, err 237 } 238 239 return vm, err 240 } 241 242 func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { 243 return nil, cloudprovider.ErrNotSupported 244 } 245 246 func (self *SHost) _createVM(name string, imgId string, sysDisk cloudprovider.SDiskInfo, cpu int, memMB int, instanceType string, 247 networkId string, ipAddr string, desc string, account string, passwd string, 248 diskSizes []cloudprovider.SDiskInfo, publicKey string, secgroupId string, 249 userData string, bc *billing.SBillingCycle, projectId string, tags map[string]string) (string, error) { 250 net := self.zone.getNetworkById(networkId) 251 if net == nil { 252 return "", fmt.Errorf("invalid network ID %s", networkId) 253 } 254 255 if net.wire == nil { 256 log.Errorf("network's wire is empty") 257 return "", fmt.Errorf("network's wire is empty") 258 } 259 260 if net.wire.vpc == nil { 261 log.Errorf("wire's vpc is empty") 262 return "", fmt.Errorf("wire's vpc is empty") 263 } 264 265 // 同步keypair 266 var err error 267 keypair := "" 268 if len(publicKey) > 0 { 269 keypair, err = self.zone.region.syncKeypair(publicKey) 270 if err != nil { 271 return "", err 272 } 273 } 274 275 // 镜像及硬盘配置 276 img, err := self.zone.region.GetImage(imgId) 277 if err != nil { 278 log.Errorf("getiamge %s fail %s", imgId, err) 279 return "", err 280 } 281 if img.Status != ImageStatusActive { 282 log.Errorf("image %s status %s", imgId, img.Status) 283 return "", fmt.Errorf("image not ready") 284 } 285 // passwd, windows机型直接使用密码比较方便 286 if strings.ToLower(img.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) && len(passwd) > 0 { 287 keypair = "" 288 } 289 290 if strings.ToLower(img.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) { 291 if u, err := updateWindowsUserData(userData, img.OSVersion, account, passwd); err == nil { 292 userData = u 293 } else { 294 return "", errors.Wrap(err, "SHost.CreateVM.updateWindowsUserData") 295 } 296 } 297 298 disks := make([]SDisk, len(diskSizes)+1) 299 disks[0].SizeGB = img.SizeGB 300 if sysDisk.SizeGB > 0 && sysDisk.SizeGB > img.SizeGB { 301 disks[0].SizeGB = sysDisk.SizeGB 302 } 303 disks[0].VolumeType = sysDisk.StorageType 304 305 for i, dataDisk := range diskSizes { 306 disks[i+1].SizeGB = dataDisk.SizeGB 307 disks[i+1].VolumeType = dataDisk.StorageType 308 } 309 310 _, err = self.zone.region.GetSecurityGroupDetails(secgroupId) 311 if err != nil { 312 return "", errors.Wrap(err, "SHost.CreateVM.GetSecurityGroupDetails") 313 } 314 315 // 创建实例 316 if len(instanceType) > 0 { 317 log.Debugf("Try instancetype : %s", instanceType) 318 vmId, err := self.zone.region.CreateInstance(name, imgId, instanceType, networkId, secgroupId, net.VpcID, self.zone.GetId(), desc, disks, ipAddr, keypair, publicKey, passwd, userData, bc, projectId, tags) 319 if err != nil { 320 log.Errorf("Failed for %s: %s", instanceType, err) 321 return "", fmt.Errorf("create %s failed:%s", instanceType, ErrMessage(err)) 322 } else { 323 return vmId, nil 324 } 325 } 326 327 // 匹配实例类型 328 instanceTypes, err := self.zone.region.GetMatchInstanceTypes(cpu, memMB, self.zone.GetId()) 329 if err != nil { 330 return "", err 331 } 332 if len(instanceTypes) == 0 { 333 return "", fmt.Errorf("instance type %dC%dMB not avaiable", cpu, memMB) 334 } 335 336 var vmId string 337 for _, instType := range instanceTypes { 338 instanceTypeId := instType.Name 339 log.Debugf("Try instancetype : %s", instanceTypeId) 340 vmId, err = self.zone.region.CreateInstance(name, imgId, instanceTypeId, networkId, secgroupId, net.VpcID, self.zone.GetId(), desc, disks, ipAddr, keypair, publicKey, passwd, userData, bc, projectId, tags) 341 if err != nil { 342 log.Errorf("Failed for %s: %s", instanceTypeId, err) 343 } else { 344 return vmId, nil 345 } 346 } 347 348 return "", fmt.Errorf("create failed: %s", ErrMessage(err)) 349 }