yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/esxi/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 esxi 16 17 import ( 18 "context" 19 "fmt" 20 "regexp" 21 "strings" 22 23 "github.com/vmware/govmomi/object" 24 "github.com/vmware/govmomi/vim25/mo" 25 "github.com/vmware/govmomi/vim25/types" 26 27 "yunion.io/x/jsonutils" 28 "yunion.io/x/log" 29 "yunion.io/x/pkg/errors" 30 "yunion.io/x/pkg/util/netutils" 31 "yunion.io/x/pkg/util/regutils" 32 33 api "yunion.io/x/cloudmux/pkg/apis/compute" 34 "yunion.io/x/cloudmux/pkg/cloudprovider" 35 "yunion.io/x/cloudmux/pkg/multicloud" 36 ) 37 38 var ( 39 hostConfigProps = []string{"config.network", "config.storageDevice"} 40 hostSummaryProps = []string{"summary.runtime", "summary.hardware", "summary.config.product", "summary.managementServerIp"} 41 hostHardWareProps = []string{"hardware.systemInfo"} 42 ) 43 44 var HOST_SYSTEM_PROPS []string 45 46 func init() { 47 HOST_SYSTEM_PROPS = []string{"name", "parent", "vm", "datastore", "network"} 48 HOST_SYSTEM_PROPS = append(HOST_SYSTEM_PROPS, hostConfigProps...) 49 HOST_SYSTEM_PROPS = append(HOST_SYSTEM_PROPS, hostSummaryProps...) 50 HOST_SYSTEM_PROPS = append(HOST_SYSTEM_PROPS, hostHardWareProps...) 51 } 52 53 type SHostStorageAdapterInfo struct { 54 Device string 55 Model string 56 Driver string 57 Pci string 58 Drivers []*SHostStorageDriverInfo 59 Enclosure int 60 } 61 62 type SHostStorageDriverInfo struct { 63 CN string 64 Name string 65 Model string 66 Vendor string 67 Revision string 68 Status string 69 SSD bool 70 Dev string 71 Size int 72 Slot int 73 } 74 75 type SHostStorageEnclosureInfo struct { 76 CN string 77 Name string 78 Model string 79 Vendor string 80 Revision string 81 Status string 82 } 83 84 type SHostStorageInfo struct { 85 Adapter int 86 Driver string 87 Index int 88 Model string 89 Rotate bool 90 Status string 91 Size int 92 } 93 94 type SHost struct { 95 multicloud.SHostBase 96 SManagedObject 97 98 masterIp string 99 100 nicInfo []SHostNicInfo 101 storageInfo []SHostStorageInfo 102 datastores []cloudprovider.ICloudStorage 103 storageCache *SDatastoreImageCache 104 vms []cloudprovider.ICloudVM 105 parent *mo.ComputeResource 106 networks []IVMNetwork 107 tempalteVMs []*SVirtualMachine 108 } 109 110 func NewHost(manager *SESXiClient, host *mo.HostSystem, dc *SDatacenter) *SHost { 111 if host.Config == nil { 112 log.Errorf("empty host config %s", host.Name) 113 return nil 114 } 115 return &SHost{SManagedObject: newManagedObject(manager, host, dc)} 116 } 117 118 var ( 119 ip4addrPattern = regexp.MustCompile(`\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}`) 120 ) 121 122 func formatName(name string) string { 123 if ip4addrPattern.MatchString(name) { 124 return strings.Replace(name, ".", "-", -1) 125 } else { 126 dotPos := strings.IndexByte(name, '.') 127 if dotPos > 0 && !regutils.MatchIP4Addr(name) { 128 name = name[:dotPos] 129 } 130 return name 131 } 132 } 133 134 func (self *SHost) GetName() string { 135 return formatName(self.SManagedObject.GetName()) 136 } 137 138 func (self *SHost) GetSchedtags() ([]string, error) { 139 clusters, err := self.datacenter.listClusters() 140 if err != nil { 141 return nil, err 142 } 143 cpName := self.datacenter.manager.cpcfg.Name 144 reference := self.GetoHostSystem().Reference() 145 tags := make([]string, 0, 1) 146 oDatacenter := self.datacenter.getDatacenter() 147 Loop: 148 for i := range clusters { 149 oc := clusters[i].getoCluster() 150 if len(oc.Host) == 0 { 151 continue 152 } 153 for _, h := range oc.Host { 154 if h == reference { 155 tags = append(tags, fmt.Sprintf("cluster:/%s/%s/%s", cpName, oDatacenter.Name, oc.Name)) 156 continue Loop 157 } 158 } 159 } 160 return tags, nil 161 } 162 163 func (self *SHost) getHostSystem() *mo.HostSystem { 164 return self.object.(*mo.HostSystem) 165 } 166 167 func (self *SHost) GetGlobalId() string { 168 return self.GetAccessIp() 169 } 170 171 func (self *SHost) GetStatus() string { 172 /* 173 HostSystemPowerStatePoweredOn = HostSystemPowerState("poweredOn") 174 HostSystemPowerStatePoweredOff = HostSystemPowerState("poweredOff") 175 HostSystemPowerStateStandBy = HostSystemPowerState("standBy") 176 HostSystemPowerStateUnknown = HostSystemPowerState("unknown") 177 */ 178 switch self.getHostSystem().Summary.Runtime.PowerState { 179 case types.HostSystemPowerStatePoweredOn: 180 return api.HOST_STATUS_RUNNING 181 case types.HostSystemPowerStatePoweredOff: 182 return api.HOST_STATUS_READY 183 default: 184 return api.HOST_STATUS_UNKNOWN 185 } 186 } 187 188 func (self *SHost) Refresh() error { 189 base := self.SManagedObject 190 var moObj mo.HostSystem 191 err := self.manager.reference2Object(self.object.Reference(), HOST_SYSTEM_PROPS, &moObj) 192 if err != nil { 193 return err 194 } 195 base.object = &moObj 196 *self = SHost{} 197 self.SManagedObject = base 198 return nil 199 } 200 201 func (self *SHost) IsEmulated() bool { 202 return false 203 } 204 205 func (self *SHost) fetchVMs(all bool) error { 206 if self.vms != nil { 207 return nil 208 } 209 210 dc, err := self.GetDatacenter() 211 if err != nil { 212 return err 213 } 214 215 var vms []*SVirtualMachine 216 hostVms := self.getHostSystem().Vm 217 if len(hostVms) == 0 { 218 // log.Errorf("host VMs are nil!!!!!") 219 return nil 220 } 221 222 vms, err = dc.fetchVms(hostVms, all) 223 if err != nil { 224 return err 225 } 226 for _, vm := range vms { 227 if vm.IsTemplate() { 228 self.tempalteVMs = append(self.tempalteVMs, vm) 229 } else { 230 self.vms = append(self.vms, vm) 231 } 232 } 233 return nil 234 } 235 236 func (self *SHost) GetIVMs2() ([]cloudprovider.ICloudVM, error) { 237 err := self.fetchVMs(true) 238 if err != nil { 239 return nil, err 240 } 241 return self.vms, nil 242 } 243 244 func (self *SHost) GetTemplateVMs() ([]*SVirtualMachine, error) { 245 err := self.fetchVMs(false) 246 if err != nil { 247 return nil, errors.Wrap(err, "SHost.fetchVMs") 248 } 249 return self.tempalteVMs, nil 250 } 251 252 func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { 253 err := self.fetchVMs(false) 254 if err != nil { 255 return nil, err 256 } 257 return self.vms, nil 258 } 259 260 func (self *SHost) GetTemplateVMById(id string) (*SVirtualMachine, error) { 261 id = self.manager.getPrivateId(id) 262 temVms, err := self.GetTemplateVMs() 263 if err != nil { 264 return nil, err 265 } 266 for i := range temVms { 267 if temVms[i].GetGlobalId() == id { 268 return temVms[i], nil 269 } 270 } 271 return nil, cloudprovider.ErrNotFound 272 } 273 274 func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { 275 id = self.manager.getPrivateId(id) 276 277 vms, err := self.GetIVMs() 278 if err != nil { 279 return nil, err 280 } 281 for i := 0; i < len(vms); i += 1 { 282 if vms[i].GetGlobalId() == id { 283 return vms[i], nil 284 } 285 } 286 return nil, cloudprovider.ErrNotFound 287 } 288 289 func (self *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { 290 return nil, cloudprovider.ErrNotImplemented 291 } 292 293 func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { 294 return self.GetDataStores() 295 } 296 297 func (self *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { 298 istorages, err := self.GetIStorages() 299 if err != nil { 300 return nil, err 301 } 302 for i := 0; i < len(istorages); i += 1 { 303 if istorages[i].GetGlobalId() == id { 304 return istorages[i], nil 305 } 306 } 307 return nil, cloudprovider.ErrNotFound 308 } 309 310 func (self *SHost) GetEnabled() bool { 311 if self.getHostSystem().Summary.Runtime.InMaintenanceMode { 312 return false 313 } 314 return true 315 } 316 317 func (self *SHost) GetHostStatus() string { 318 /* 319 HostSystemConnectionStateConnected = HostSystemConnectionState("connected") 320 HostSystemConnectionStateNotResponding = HostSystemConnectionState("notResponding") 321 HostSystemConnectionStateDisconnected = HostSystemConnectionState("disconnected") 322 */ 323 if self.getHostSystem().Summary.Runtime.InMaintenanceMode { 324 return api.HOST_OFFLINE 325 } 326 switch self.getHostSystem().Summary.Runtime.ConnectionState { 327 case types.HostSystemConnectionStateConnected: 328 return api.HOST_ONLINE 329 default: 330 return api.HOST_OFFLINE 331 } 332 } 333 334 func findHostNicByMac(nicInfoList []SHostNicInfo, mac string) *SHostNicInfo { 335 for i := 0; i < len(nicInfoList); i += 1 { 336 if nicInfoList[i].Mac == mac { 337 return &nicInfoList[i] 338 } 339 } 340 return nil 341 } 342 343 func (self *SHost) getAdminNic() *SHostNicInfo { 344 nics := self.getNicInfo(false) 345 for i := 0; i < len(nics); i += 1 { 346 if nics[i].NicType == api.NIC_TYPE_ADMIN { 347 return &nics[i] 348 } 349 } 350 for i := 0; i < len(nics); i += 1 { 351 if len(nics[i].IpAddr) > 0 { 352 return &nics[i] 353 } 354 } 355 return nil 356 } 357 358 func (self *SHost) getNicInfo(debug bool) []SHostNicInfo { 359 if self.nicInfo == nil { 360 self.nicInfo = self.fetchNicInfo(debug) 361 } 362 return self.nicInfo 363 } 364 365 func mask2len(mask string) int8 { 366 maskAddr, _ := netutils.NewIPV4Addr(mask) 367 return netutils.Mask2Len(maskAddr) 368 } 369 370 func (self *SHost) isVnicAdmin(nic types.HostVirtualNic) bool { 371 if len(self.masterIp) > 0 { 372 if self.masterIp == nic.Spec.Ip.IpAddress { 373 return true 374 } else { 375 return false 376 } 377 } 378 exist, err := self.manager.IsHostIpExists(nic.Spec.Ip.IpAddress) 379 if err != nil { 380 log.Errorf("IsHostIpExists %s fail %s", nic.Spec.Ip.IpAddress, err) 381 return false 382 } 383 if exist { 384 self.masterIp = nic.Spec.Ip.IpAddress 385 return true 386 } 387 return false 388 } 389 390 func (self *SHost) fetchNicInfo(debug bool) []SHostNicInfo { 391 moHost := self.getHostSystem() 392 393 if moHost.Config == nil || moHost.Config.Network == nil { 394 return nil 395 } 396 397 if debug { 398 log.Debugf("%s", jsonutils.Marshal(moHost.Config.Network).PrettyString()) 399 } 400 401 nicInfoList := make([]SHostNicInfo, 0) 402 403 for i, nic := range moHost.Config.Network.Pnic { 404 info := SHostNicInfo{} 405 info.Dev = nic.Device 406 info.Driver = nic.Driver 407 info.Mac = netutils.FormatMacAddr(nic.Mac) 408 info.Index = int8(i) 409 info.LinkUp = false 410 nicInfoList = append(nicInfoList, info) 411 } 412 413 vnics := make([]types.HostVirtualNic, 0) 414 if len(moHost.Config.Network.Vnic) > 0 { 415 vnics = append(vnics, moHost.Config.Network.Vnic...) 416 } 417 if len(moHost.Config.Network.ConsoleVnic) > 0 { 418 vnics = append(vnics, moHost.Config.Network.ConsoleVnic...) 419 } 420 421 for _, nic := range vnics { 422 mac := netutils.FormatMacAddr(nic.Spec.Mac) 423 pnic := findHostNicByMac(nicInfoList, mac) 424 if pnic != nil { 425 // findMaster = true 426 pnic.IpAddr = nic.Spec.Ip.IpAddress 427 pnic.IpAddrPrefixLen = mask2len(nic.Spec.Ip.SubnetMask) 428 if nic.Spec.Ip.IpV6Config != nil && len(nic.Spec.Ip.IpV6Config.IpV6Address) > 0 { 429 pnic.IpAddr6 = nic.Spec.Ip.IpV6Config.IpV6Address[0].IpAddress 430 pnic.IpAddr6PrefixLen = int8(nic.Spec.Ip.IpV6Config.IpV6Address[0].PrefixLength) 431 } 432 if self.isVnicAdmin(nic) { 433 pnic.NicType = api.NIC_TYPE_ADMIN 434 } 435 pnic.LinkUp = true 436 pnic.Mtu = nic.Spec.Mtu 437 if nic.Spec.DistributedVirtualPort != nil { 438 pnic.DVPortGroup = nic.Spec.DistributedVirtualPort.PortgroupKey 439 } 440 } else { 441 info := SHostNicInfo{} 442 info.Dev = nic.Device 443 info.Driver = "vmkernel" 444 info.Mac = mac 445 info.Index = int8(len(nicInfoList)) 446 info.LinkUp = true 447 info.IpAddr = nic.Spec.Ip.IpAddress 448 info.IpAddrPrefixLen = mask2len(nic.Spec.Ip.SubnetMask) 449 if nic.Spec.Ip.IpV6Config != nil && len(nic.Spec.Ip.IpV6Config.IpV6Address) > 0 { 450 info.IpAddr6 = nic.Spec.Ip.IpV6Config.IpV6Address[0].IpAddress 451 info.IpAddr6PrefixLen = int8(nic.Spec.Ip.IpV6Config.IpV6Address[0].PrefixLength) 452 } 453 info.Mtu = nic.Spec.Mtu 454 if self.isVnicAdmin(nic) { 455 info.NicType = api.NIC_TYPE_ADMIN 456 } 457 if nic.Spec.DistributedVirtualPort != nil { 458 info.DVPortGroup = nic.Spec.DistributedVirtualPort.PortgroupKey 459 } 460 nicInfoList = append(nicInfoList, info) 461 } 462 } 463 464 return nicInfoList 465 } 466 467 func (self *SHost) GetAccessIp() string { 468 adminNic := self.getAdminNic() 469 if adminNic != nil { 470 return adminNic.IpAddr 471 } 472 return "" 473 } 474 475 func (self *SHost) GetAccessMac() string { 476 adminNic := self.getAdminNic() 477 if adminNic != nil { 478 return adminNic.Mac 479 } 480 return "" 481 } 482 483 type SSysInfo struct { 484 Manufacture string 485 Model string 486 SerialNumber string 487 } 488 489 func (self *SHost) GetSysInfo() jsonutils.JSONObject { 490 sysinfo := SSysInfo{} 491 host := self.getHostSystem() 492 sysinfo.Manufacture = host.Summary.Hardware.Vendor 493 sysinfo.Model = host.Summary.Hardware.Model 494 if host.Hardware != nil { 495 sysinfo.SerialNumber = host.Hardware.SystemInfo.SerialNumber 496 } 497 return jsonutils.Marshal(&sysinfo) 498 } 499 500 func (self *SHost) GetSN() string { 501 host := self.getHostSystem() 502 if host.Hardware != nil { 503 return host.Hardware.SystemInfo.SerialNumber 504 } 505 return "" 506 } 507 508 func (self *SHost) GetCpuCount() int { 509 return int(self.getHostSystem().Summary.Hardware.NumCpuThreads) 510 } 511 512 func (self *SHost) GetNodeCount() int8 { 513 return int8(self.getHostSystem().Summary.Hardware.NumCpuPkgs) 514 } 515 516 func (self *SHost) GetCpuDesc() string { 517 return self.getHostSystem().Summary.Hardware.CpuModel 518 } 519 520 func (self *SHost) GetCpuMhz() int { 521 return int(self.getHostSystem().Summary.Hardware.CpuMhz) 522 } 523 524 func (self *SHost) GetMemSizeMB() int { 525 return int(self.getHostSystem().Summary.Hardware.MemorySize / 1024 / 1024) 526 } 527 528 func (self *SHost) GetStorageInfo() []SHostStorageInfo { 529 if self.storageInfo == nil { 530 self.storageInfo = self.getStorageInfo() 531 } 532 return self.storageInfo 533 } 534 535 func (self *SHost) getStorageInfo() []SHostStorageInfo { 536 diskSlots := make(map[int]SHostStorageInfo) 537 list := self.getStorages() 538 for i := 0; i < len(list); i += 1 { 539 for j := 0; j < len(list[i].Drivers); j += 1 { 540 drv := list[i].Drivers[j] 541 info := SHostStorageInfo{ 542 Adapter: 0, 543 Driver: "Linux", 544 Index: drv.Slot, 545 Model: strings.TrimSpace(fmt.Sprintf("%s %s", drv.Vendor, drv.Model)), 546 Rotate: !drv.SSD, 547 Status: drv.Status, 548 Size: drv.Size, 549 } 550 diskSlots[info.Index] = info 551 } 552 } 553 disks := make([]SHostStorageInfo, 0) 554 idx := 0 555 for { 556 if info, ok := diskSlots[idx]; ok { 557 disks = append(disks, info) 558 idx += 1 559 } else { 560 break 561 } 562 } 563 return disks 564 } 565 566 func (self *SHost) getStorages() []*SHostStorageAdapterInfo { 567 adapterList := make([]*SHostStorageAdapterInfo, 0) 568 adapterTable := make(map[string]*SHostStorageAdapterInfo) 569 driversTable := make(map[string]*SHostStorageDriverInfo, 0) 570 enclosuresTable := make(map[string]*SHostStorageEnclosureInfo, 0) 571 moHost := self.getHostSystem() 572 573 for i := 0; i < len(moHost.Config.StorageDevice.HostBusAdapter); i += 1 { 574 ad := moHost.Config.StorageDevice.HostBusAdapter[i] 575 adinfo := ad.GetHostHostBusAdapter() 576 if adinfo == nil { 577 log.Errorf("fail to GetHostHostBusAdapter") 578 continue 579 } 580 info := SHostStorageAdapterInfo{} 581 info.Device = adinfo.Device 582 info.Model = strings.TrimSpace(adinfo.Model) 583 info.Driver = adinfo.Driver 584 info.Pci = adinfo.Pci 585 info.Drivers = make([]*SHostStorageDriverInfo, 0) 586 info.Enclosure = -1 587 588 adapterTable[adinfo.Key] = &info 589 adapterList = append(adapterList, &info) 590 } 591 592 for i := 0; i < len(moHost.Config.StorageDevice.ScsiLun); i += 1 { 593 drv := moHost.Config.StorageDevice.ScsiLun[i] 594 lunInfo := drv.GetScsiLun() 595 if lunInfo == nil { 596 log.Errorf("fail to GetScsiLun") 597 continue 598 } 599 600 if lunInfo.DeviceType == "disk" { 601 scsiDisk := drv.(*types.HostScsiDisk) 602 info := SHostStorageDriverInfo{} 603 info.CN = scsiDisk.CanonicalName 604 info.Name = scsiDisk.DisplayName 605 info.Model = strings.TrimSpace(scsiDisk.Model) 606 info.Vendor = strings.TrimSpace(scsiDisk.Vendor) 607 info.Revision = scsiDisk.Revision 608 info.Status = scsiDisk.OperationalState[0] 609 if scsiDisk.Ssd != nil && *scsiDisk.Ssd { 610 info.SSD = true 611 } 612 info.Dev = scsiDisk.DevicePath 613 info.Size = int(int64(scsiDisk.Capacity.BlockSize) * scsiDisk.Capacity.Block / 1024 / 1024) 614 615 driversTable[scsiDisk.Key] = &info 616 } else if lunInfo.DeviceType == "enclosure" { 617 enclosuresTable[lunInfo.Key] = &SHostStorageEnclosureInfo{ 618 CN: lunInfo.CanonicalName, 619 Name: lunInfo.DisplayName, 620 Model: strings.TrimSpace(lunInfo.Model), 621 Vendor: strings.TrimSpace(lunInfo.Vendor), 622 Revision: lunInfo.Revision, 623 Status: lunInfo.OperationalState[0], 624 } 625 } 626 } 627 for i := 0; i < len(moHost.Config.StorageDevice.ScsiTopology.Adapter); i += 1 { 628 ad := moHost.Config.StorageDevice.ScsiTopology.Adapter[i] 629 adapter := adapterTable[ad.Adapter] 630 for j := 0; j < len(ad.Target); j += 1 { 631 t := ad.Target[j] 632 key := t.Lun[0].ScsiLun 633 if _, ok := enclosuresTable[key]; ok { 634 adapter.Enclosure = int(t.Target) 635 } else if _, ok := driversTable[key]; ok { 636 driver := driversTable[key] 637 driver.Slot = int(t.Target) 638 adapter.Drivers = append(adapter.Drivers, driver) 639 } 640 } 641 } 642 return adapterList 643 } 644 645 func (self *SHost) GetStorageSizeMB() int { 646 storages, err := self.GetIStorages() 647 if err != nil { 648 log.Errorf("SHost.GetStorageSizeMB: SHost.GetIStorages: %s", err) 649 return 0 650 } 651 var size int64 652 for _, stor := range storages { 653 size += stor.GetCapacityMB() 654 } 655 return int(size) 656 } 657 658 func (self *SHost) GetStorageType() string { 659 ssd := 0 660 rotate := 0 661 storages := self.GetStorageInfo() 662 for i := 0; i < len(storages); i += 1 { 663 if storages[i].Rotate { 664 rotate += 1 665 } else { 666 ssd += 1 667 } 668 } 669 if ssd == 0 && rotate > 0 { 670 return api.DISK_TYPE_ROTATE 671 } else if ssd > 0 && rotate == 0 { 672 return api.DISK_TYPE_SSD 673 } else { 674 return api.DISK_TYPE_HYBRID 675 } 676 } 677 678 func (self *SHost) GetHostType() string { 679 return api.HOST_TYPE_ESXI 680 } 681 682 func (self *SHost) GetIsMaintenance() bool { 683 moHost := self.getHostSystem() 684 return moHost.Summary.Runtime.InMaintenanceMode 685 } 686 687 func (self *SHost) GetVersion() string { 688 moHost := self.getHostSystem() 689 about := moHost.Summary.Config.Product 690 return fmt.Sprintf("%s-%s", about.Version, about.Build) 691 } 692 693 func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { 694 return nil, cloudprovider.ErrNotImplemented 695 } 696 697 type SCreateVMParam struct { 698 Name string 699 Uuid string 700 OsName string 701 Cpu int 702 Mem int 703 Bios string 704 Cdrom SCdromInfo 705 Disks []SDiskInfo 706 Nics []jsonutils.JSONObject 707 ResourcePool string 708 InstanceSnapshotInfo SEsxiInstanceSnapshotInfo 709 } 710 711 type SEsxiInstanceSnapshotInfo struct { 712 InstanceSnapshotId string 713 InstanceId string 714 } 715 716 type SCdromInfo struct { 717 ImageId string 718 Path string 719 Name string 720 Size string 721 } 722 723 type SDiskInfo struct { 724 ImagePath string 725 Size int64 726 DiskId string 727 Driver string 728 ImageInfo SEsxiImageInfo 729 StorageId string 730 } 731 732 type SEsxiImageInfo struct { 733 ImageType string 734 ImageExternalId string 735 StorageCacheHostIp string 736 } 737 738 func (self *SHost) CreateVM2(ctx context.Context, ds *SDatastore, params SCreateVMParam) (needDeploy bool, vm *SVirtualMachine, err error) { 739 needDeploy = true 740 var temvm *SVirtualMachine 741 if len(params.InstanceSnapshotInfo.InstanceSnapshotId) > 0 { 742 temvm, err = self.manager.SearchVM(params.InstanceSnapshotInfo.InstanceId) 743 if err != nil { 744 err = errors.Wrapf(err, "can't find vm %q, please sync status for vm or sync cloudaccount", params.InstanceSnapshotInfo.InstanceId) 745 } 746 var isp cloudprovider.ICloudInstanceSnapshot 747 isp, err = temvm.GetInstanceSnapshot(params.InstanceSnapshotInfo.InstanceSnapshotId) 748 if err != nil { 749 err = errors.Wrap(err, "unable to GetInstanceSnapshot") 750 return 751 } 752 sp := isp.(*SVirtualMachineSnapshot) 753 vm, err = self.CloneVM(ctx, temvm, &sp.snapshotTree.Snapshot, ds, params) 754 return 755 } 756 if len(params.Disks) == 0 { 757 err = errors.Error("empty disk config") 758 return 759 } 760 imageInfo := params.Disks[0].ImageInfo 761 if imageInfo.ImageType == string(cloudprovider.ImageTypeSystem) { 762 temvm, err = self.manager.SearchTemplateVM(imageInfo.ImageExternalId) 763 if err != nil { 764 err = errors.Wrapf(err, "SEsxiClient.SearchTemplateVM for image %q", imageInfo.ImageExternalId) 765 return 766 } 767 vm, err = self.CloneVM(ctx, temvm, nil, ds, params) 768 return 769 } 770 return self.DoCreateVM(ctx, ds, params) 771 } 772 773 func (self *SHost) needScsi(disks []SDiskInfo) bool { 774 if len(disks) == 0 { 775 return false 776 } 777 for i := range disks { 778 driver := disks[i].Driver 779 if driver == "" || driver == "scsi" || driver == "pvscsi" { 780 return true 781 } 782 } 783 return false 784 } 785 786 func (self *SHost) addDisks(ctx context.Context, dc *SDatacenter, ds *SDatastore, disks []SDiskInfo, uuid string, objectVm *object.VirtualMachine) (*SVirtualMachine, error) { 787 getVM := func() (*SVirtualMachine, error) { 788 var moVM mo.VirtualMachine 789 err := self.manager.reference2Object(objectVm.Reference(), VIRTUAL_MACHINE_PROPS, &moVM) 790 if err != nil { 791 return nil, errors.Wrap(err, "fail to fetch virtual machine just created") 792 } 793 794 evm := NewVirtualMachine(self.manager, &moVM, self.datacenter) 795 if evm == nil { 796 return nil, errors.Error("create successfully but unable to NewVirtualMachine") 797 } 798 return evm, nil 799 } 800 801 if len(disks) == 0 { 802 return getVM() 803 } 804 805 var ( 806 scsiIdx = 0 807 ideIdx = 0 808 ide1un = 0 809 ide2un = 1 810 unitNumber = 0 811 ctrlKey = 0 812 ) 813 deviceChange := make([]types.BaseVirtualDeviceConfigSpec, 0, 1) 814 // add disks 815 var rootDiskSizeMb int64 816 for i, disk := range disks { 817 imagePath := disk.ImagePath 818 var size = disk.Size 819 if len(imagePath) == 0 { 820 if size == 0 { 821 size = 30 * 1024 822 } 823 } else { 824 var err error 825 imagePath, err = self.FileUrlPathToDsPath(imagePath) 826 if err != nil { 827 return nil, errors.Wrapf(err, "SHost.FileUrlPathToDsPath") 828 } 829 newImagePath := fmt.Sprintf("[%s] %s/%s.vmdk", ds.GetRelName(), uuid, uuid) 830 831 err = self.copyVirtualDisk(imagePath, newImagePath, disk.Driver) 832 if err != nil { 833 return nil, err 834 } 835 imagePath = newImagePath 836 rootDiskSizeMb = size 837 } 838 uuid, driver := disk.DiskId, "scsi" 839 if len(disk.Driver) > 0 { 840 driver = disk.Driver 841 } 842 if driver == "scsi" || driver == "pvscsi" { 843 if self.isVersion50() { 844 driver = "scsi" 845 } 846 ctrlKey = 1000 847 unitNumber = scsiIdx 848 scsiIdx += 1 849 if scsiIdx == 7 { 850 scsiIdx++ 851 } 852 } else { 853 ideno := ideIdx % 2 854 if ideno == 0 { 855 unitNumber = ideIdx/2 + ide1un 856 } else { 857 unitNumber = ideIdx/2 + ide2un 858 } 859 ctrlKey = 200 + ideno 860 ideIdx += 1 861 } 862 var tds *SDatastore 863 var err error 864 if disk.StorageId != "" { 865 tds, err = self.FindDataStoreById(disk.StorageId) 866 if err != nil { 867 return nil, errors.Wrapf(err, "unable to find ds %s from host %s", disk.StorageId, self.masterIp) 868 } 869 } else { 870 tds = ds 871 } 872 log.Debugf("ds: %s, size: %d, image path: %s, uuid: %s, index: %d, ctrlKey: %d, driver: %s, key: %d.", tds.getDatastoreObj().String(), size, imagePath, uuid, unitNumber, ctrlKey, disk.Driver, 2000+i) 873 spec := addDevSpec(NewDiskDev(size, SDiskConfig{ 874 SizeMb: size, 875 Uuid: uuid, 876 ControllerKey: int32(ctrlKey), 877 UnitNumber: int32(unitNumber), 878 Key: int32(2000 + i), 879 ImagePath: imagePath, 880 IsRoot: i == 0, 881 Datastore: tds, 882 })) 883 if len(imagePath) == 0 { 884 spec.FileOperation = "create" 885 } 886 deviceChange = append(deviceChange, spec) 887 } 888 log.Infof("deviceChange: %s", jsonutils.Marshal(deviceChange)) 889 890 configSpec := types.VirtualMachineConfigSpec{} 891 configSpec.DeviceChange = deviceChange 892 task, err := objectVm.Reconfigure(ctx, configSpec) 893 if err != nil { 894 return nil, errors.Wrap(err, "unable to reconfigure") 895 } 896 err = task.Wait(ctx) 897 if err != nil { 898 return nil, errors.Wrap(err, "task.Wait") 899 } 900 901 evm, err := getVM() 902 if err != nil { 903 return nil, err 904 } 905 906 // resize root disk 907 if rootDiskSizeMb > 0 && int64(evm.vdisks[0].GetDiskSizeMB()) != rootDiskSizeMb { 908 err = evm.vdisks[0].Resize(ctx, rootDiskSizeMb) 909 if err != nil { 910 return evm, errors.Wrap(err, "resize for root disk") 911 } 912 } 913 return evm, nil 914 } 915 916 func (self *SHost) copyVirtualDisk(srcPath, dstPath, diskDriver string) error { 917 dm := object.NewVirtualDiskManager(self.manager.client.Client) 918 spec := &types.VirtualDiskSpec{ 919 DiskType: "thin", 920 } 921 switch diskDriver { 922 case "", "scsi", "pvscsi": 923 spec.AdapterType = "lsiLogic" 924 default: 925 spec.AdapterType = "ide" 926 } 927 task, err := dm.CopyVirtualDisk(self.manager.context, srcPath, self.datacenter.getDcObj(), dstPath, self.datacenter.getDcObj(), spec, true) 928 if err != nil { 929 return errors.Wrap(err, "unable to CopyVirtualDisk") 930 } 931 err = task.Wait(self.manager.context) 932 if err == nil { 933 return nil 934 } 935 errStr := strings.ToLower(err.Error()) 936 if !strings.Contains(errStr, "the requested operation is not implemented by the server") { 937 return errors.Wrap(err, "wait CopyVirtualDiskTask") 938 } 939 task, err = dm.CopyVirtualDisk(self.manager.context, srcPath, self.datacenter.getDcObj(), dstPath, self.datacenter.getDcObj(), nil, true) 940 if err != nil { 941 return errors.Wrap(err, "unable to CopyVirtualDisk") 942 } 943 err = task.Wait(self.manager.context) 944 if err != nil { 945 return errors.Wrap(err, "wait CopyVirtualDiskTask") 946 } 947 return nil 948 } 949 950 func (self *SHost) DoCreateVM(ctx context.Context, ds *SDatastore, params SCreateVMParam) (needDeploy bool, vm *SVirtualMachine, err error) { 951 needDeploy = true 952 deviceChange := make([]types.BaseVirtualDeviceConfigSpec, 0, 5) 953 954 // uuid first 955 name := params.Name 956 if len(params.Uuid) != 0 { 957 name = params.Uuid 958 } 959 datastorePath := fmt.Sprintf("[%s] ", ds.GetRelName()) 960 961 firmware := "" 962 if len(params.Bios) != 0 { 963 if params.Bios == "BIOS" { 964 firmware = "bios" 965 } else if params.Bios == "UEFI" { 966 firmware = "efi" 967 } 968 } 969 970 guestId := "rhel6_64Guest" 971 if params.OsName == "Windows" { 972 guestId = "windows7Server64Guest" 973 } 974 975 version := "vmx-10" 976 if self.isVersion50() { 977 version = "vmx-08" 978 } 979 980 spec := types.VirtualMachineConfigSpec{ 981 Name: name, 982 Version: version, 983 Uuid: params.Uuid, 984 GuestId: guestId, 985 NumCPUs: int32(params.Cpu), 986 MemoryMB: int64(params.Mem), 987 Firmware: firmware, 988 } 989 spec.Files = &types.VirtualMachineFileInfo{ 990 VmPathName: datastorePath, 991 } 992 993 deviceChange = append(deviceChange, addDevSpec(NewIDEDev(200, 0))) 994 deviceChange = append(deviceChange, addDevSpec(NewIDEDev(200, 1))) 995 deviceChange = append(deviceChange, addDevSpec(NewSVGADev(500, 100))) 996 997 if self.needScsi(params.Disks) { 998 driver := "pvscsi" 999 if self.isVersion50() { 1000 driver = "scsi" 1001 } 1002 deviceChange = append(deviceChange, addDevSpec(NewSCSIDev(1000, 100, driver))) 1003 } 1004 cdromPath := params.Cdrom.Path 1005 if len(cdromPath) > 0 { 1006 needDeploy = false 1007 cdromPath, err = self.FileUrlPathToDsPath(cdromPath) 1008 if err != nil { 1009 err = errors.Wrapf(err, "SHost.FileUrlPathToDsPath for cdrom path") 1010 return 1011 } 1012 } 1013 deviceChange = append(deviceChange, addDevSpec(NewCDROMDev(cdromPath, 16000, 201))) 1014 1015 // add usb to support mouse 1016 usbController := addDevSpec(NewUSBController(nil)) 1017 deviceChange = append(deviceChange, usbController) 1018 1019 nics := params.Nics 1020 for _, nic := range nics { 1021 index, _ := nic.Int("index") 1022 mac, _ := nic.GetString("mac") 1023 bridge, _ := nic.GetString("bridge") 1024 driver := "e1000" 1025 if nic.Contains("driver") { 1026 driver, _ = nic.GetString("driver") 1027 } 1028 if self.isVersion50() { 1029 driver = "e1000" 1030 } 1031 var vlanId int64 = 1 1032 if nic.Contains("vlan") { 1033 vlanId, _ = nic.Int("vlan") 1034 } 1035 dev, err := NewVNICDev(self, mac, driver, bridge, int32(vlanId), 4000, 100, int32(index)) 1036 if err != nil { 1037 return needDeploy, nil, errors.Wrap(err, "NewVNICDev") 1038 } 1039 deviceChange = append(deviceChange, addDevSpec(dev)) 1040 } 1041 1042 spec.DeviceChange = deviceChange 1043 dc, err := self.GetDatacenter() 1044 if err != nil { 1045 err = errors.Wrapf(err, "SHost.GetDatacenter for host '%s'", self.GetId()) 1046 return 1047 } 1048 // get vmFloder 1049 folders, err := dc.getObjectDatacenter().Folders(ctx) 1050 if err != nil { 1051 err = errors.Wrap(err, "object.DataCenter.Folders") 1052 return 1053 } 1054 vmFolder := folders.VmFolder 1055 resourcePool, err := self.SyncResourcePool(params.ResourcePool) 1056 if err != nil { 1057 err = errors.Wrap(err, "SyncResourcePool") 1058 return 1059 } 1060 task, err := vmFolder.CreateVM(ctx, spec, resourcePool, self.GetoHostSystem()) 1061 if err != nil { 1062 err = errors.Wrap(err, "VmFolder.Create") 1063 return 1064 } 1065 1066 info, err := task.WaitForResult(ctx, nil) 1067 if err != nil { 1068 err = errors.Wrap(err, "Task.WaitForResult") 1069 return 1070 } 1071 vmRef := info.Result.(types.ManagedObjectReference) 1072 objectVM := object.NewVirtualMachine(self.manager.client.Client, vmRef) 1073 vm, err = self.addDisks(ctx, dc, ds, params.Disks, params.Uuid, objectVM) 1074 return 1075 } 1076 1077 // If snapshot is not nil, params.Disks will be ignored 1078 func (host *SHost) CloneVM(ctx context.Context, from *SVirtualMachine, snapshot *types.ManagedObjectReference, ds *SDatastore, params SCreateVMParam) (*SVirtualMachine, error) { 1079 ovm := from.getVmObj() 1080 1081 deviceChange := make([]types.BaseVirtualDeviceConfigSpec, 0, 3) 1082 1083 addDeviceChange := make([]types.BaseVirtualDeviceConfigSpec, 0, 3) 1084 1085 // change nic if set 1086 if params.Nics != nil && len(params.Nics) > 0 { 1087 // get origin nics 1088 originNics := make([]types.BaseVirtualDevice, 0, 1) 1089 for _, nic := range from.vnics { 1090 originNics = append(originNics, nic.getVirtualEthernetCard()) 1091 } 1092 nicIndex := 0 1093 nics := params.Nics 1094 for _, nic := range nics { 1095 index, _ := nic.Int("index") 1096 mac, _ := nic.GetString("mac") 1097 bridge, _ := nic.GetString("bridge") 1098 driver := "e1000" 1099 if nic.Contains("driver") { 1100 driver, _ = nic.GetString("driver") 1101 } 1102 if host.isVersion50() { 1103 driver = "e1000" 1104 } 1105 var vlanId int64 = 1 1106 if nic.Contains("vlan") { 1107 vlanId, _ = nic.Int("vlan") 1108 } 1109 dev, err := NewVNICDev(host, mac, driver, bridge, int32(vlanId), 4000, 100, int32(index)) 1110 if err != nil { 1111 return nil, errors.Wrap(err, "NewVNICDev") 1112 } 1113 op := types.VirtualDeviceConfigSpecOperationAdd 1114 if nicIndex < len(originNics) { 1115 // edit 1116 op = types.VirtualDeviceConfigSpecOperationEdit 1117 host.changeNic(originNics[nicIndex], dev) 1118 dev = originNics[nicIndex] 1119 deviceChange = append(deviceChange, &types.VirtualDeviceConfigSpec{ 1120 Operation: op, 1121 Device: dev, 1122 }) 1123 } else { 1124 addDeviceChange = append(addDeviceChange, &types.VirtualDeviceConfigSpec{ 1125 Operation: op, 1126 Device: dev, 1127 }) 1128 } 1129 nicIndex += 1 1130 } 1131 } 1132 1133 if len(params.Disks) > 0 && snapshot == nil { 1134 driver := params.Disks[0].Driver 1135 if driver == "scsi" || driver == "pvscsi" { 1136 scsiDevs, err := from.FindController(ctx, "scsi") 1137 if err != nil { 1138 return nil, errors.Wrap(err, "SVirtualMachine.FindController") 1139 } 1140 if len(scsiDevs) == 0 { 1141 key := from.FindMinDiffKey(1000) 1142 driver := "pvscsi" 1143 if host.isVersion50() { 1144 driver = "scsi" 1145 } 1146 addDeviceChange = append(deviceChange, addDevSpec(NewSCSIDev(key, 100, driver))) 1147 } 1148 } else { 1149 ideDevs, err := from.FindController(ctx, "ide") 1150 if err != nil { 1151 return nil, errors.Wrap(err, "SVirtualMachine.FindController") 1152 } 1153 if len(ideDevs) == 0 { 1154 // add ide driver 1155 addDeviceChange = append(deviceChange, addDevSpec(NewIDEDev(200, 0))) 1156 addDeviceChange = append(deviceChange, addDevSpec(NewIDEDev(200, 1))) 1157 } 1158 } 1159 } 1160 1161 dc, err := host.GetDatacenter() 1162 if err != nil { 1163 return nil, errors.Wrapf(err, "SHost.GetDatacenter for host '%s'", host.GetId()) 1164 } 1165 // get vmFloder 1166 folders, err := dc.getObjectDatacenter().Folders(ctx) 1167 if err != nil { 1168 return nil, errors.Wrap(err, "object.DataCenter.Folders") 1169 } 1170 resourcePool, err := host.SyncResourcePool(params.ResourcePool) 1171 if err != nil { 1172 return nil, errors.Wrap(err, "SyncResourcePool") 1173 } 1174 1175 folderref := folders.VmFolder.Reference() 1176 poolref := resourcePool.Reference() 1177 hostref := host.GetoHostSystem().Reference() 1178 dsref := ds.getDatastoreObj().Reference() 1179 relocateSpec := types.VirtualMachineRelocateSpec{ 1180 DeviceChange: deviceChange, 1181 Folder: &folderref, 1182 Pool: &poolref, 1183 Host: &hostref, 1184 Datastore: &dsref, 1185 } 1186 cloneSpec := &types.VirtualMachineCloneSpec{ 1187 PowerOn: false, 1188 Template: false, 1189 Location: relocateSpec, 1190 Snapshot: snapshot, 1191 } 1192 1193 // uuid first 1194 name := params.Name 1195 if len(params.Uuid) != 0 { 1196 name = params.Uuid 1197 } 1198 spec := types.VirtualMachineConfigSpec{ 1199 Name: name, 1200 Uuid: params.Uuid, 1201 NumCPUs: int32(params.Cpu), 1202 MemoryMB: int64(params.Mem), 1203 } 1204 cloneSpec.Config = &spec 1205 task, err := ovm.Clone(ctx, folders.VmFolder, name, *cloneSpec) 1206 if err != nil { 1207 return nil, errors.Wrap(err, "object.VirtualMachine.Clone") 1208 } 1209 info, err := task.WaitForResult(ctx, nil) 1210 if err != nil { 1211 return nil, errors.Wrap(err, "Task.WaitForResult") 1212 } 1213 1214 var moVM mo.VirtualMachine 1215 err = host.manager.reference2Object(info.Result.(types.ManagedObjectReference), VIRTUAL_MACHINE_PROPS, &moVM) 1216 if err != nil { 1217 return nil, errors.Wrap(err, "fail to fetch virtual machine just created") 1218 } 1219 1220 vm := NewVirtualMachine(host.manager, &moVM, host.datacenter) 1221 if vm == nil { 1222 return nil, errors.Error("clone successfully but unable to NewVirtualMachine") 1223 } 1224 1225 if snapshot != nil { 1226 return vm, nil 1227 } 1228 1229 deviceChange = addDeviceChange 1230 // adjust disk 1231 var i int 1232 if len(params.Disks) > 0 { 1233 // resize system disk 1234 sysDiskSize := params.Disks[0].Size 1235 if sysDiskSize == 0 { 1236 sysDiskSize = 30 * 1024 1237 } 1238 if int64(vm.vdisks[0].GetDiskSizeMB()) != sysDiskSize { 1239 vdisk := vm.vdisks[0].getVirtualDisk() 1240 originSize := vdisk.CapacityInKB 1241 vdisk.CapacityInKB = sysDiskSize * 1024 1242 spec := &types.VirtualDeviceConfigSpec{} 1243 spec.Operation = types.VirtualDeviceConfigSpecOperationEdit 1244 spec.Device = vdisk 1245 deviceChange = append(deviceChange, spec) 1246 log.Infof("resize system disk: %dGB => %dGB", originSize/1024/1024, sysDiskSize/1024) 1247 } 1248 // resize existed disk 1249 for i = 1; i < len(params.Disks); i++ { 1250 if i >= len(vm.vdisks) { 1251 break 1252 } 1253 wantDisk := params.Disks[i] 1254 vdisk := vm.vdisks[i] 1255 modisk := vdisk.getVirtualDisk() 1256 if wantDisk.Size <= int64(vdisk.GetDiskSizeMB()) { 1257 continue 1258 } 1259 originSize := modisk.CapacityInKB 1260 modisk.CapacityInKB = wantDisk.Size * 1024 1261 spec := &types.VirtualDeviceConfigSpec{} 1262 spec.Operation = types.VirtualDeviceConfigSpecOperationEdit 1263 spec.Device = vdisk.dev 1264 deviceChange = append(deviceChange, spec) 1265 log.Infof("resize No.%d data disk: %dGB => %dGB", i, originSize/1024/1024, wantDisk.Size/1024) 1266 } 1267 // remove extra disk 1268 for ; i < len(vm.vdisks); i++ { 1269 vdisk := vm.vdisks[i] 1270 spec := &types.VirtualDeviceConfigSpec{} 1271 spec.Operation = types.VirtualDeviceConfigSpecOperationRemove 1272 spec.Device = vdisk.dev 1273 spec.FileOperation = types.VirtualDeviceConfigSpecFileOperationDestroy 1274 deviceChange = append(deviceChange, spec) 1275 log.Infof("remove No.%d data disk", i) 1276 } 1277 if len(deviceChange) > 0 { 1278 spec = types.VirtualMachineConfigSpec{} 1279 spec.DeviceChange = deviceChange 1280 task, err = vm.getVmObj().Reconfigure(ctx, spec) 1281 if err != nil { 1282 return vm, errors.Wrap(err, "Reconfigure to resize disks") 1283 } 1284 err = task.Wait(ctx) 1285 if err != nil { 1286 return vm, errors.Wrap(err, "Wait task to resize disks") 1287 } 1288 } 1289 } 1290 // add data disk 1291 for ; i < len(params.Disks); i++ { 1292 size := params.Disks[i].Size 1293 if size == 0 { 1294 size = 30 * 1024 1295 } 1296 uuid := params.Disks[i].DiskId 1297 driver := params.Disks[i].Driver 1298 opts := &cloudprovider.GuestDiskCreateOptions{ 1299 SizeMb: int(size), 1300 UUID: uuid, 1301 Driver: driver, 1302 StorageId: params.Disks[i].StorageId, 1303 } 1304 _, err := vm.CreateDisk(ctx, opts) 1305 if err != nil { 1306 log.Errorf("unable to add No.%d disk for vm %s", i, vm.GetId()) 1307 return vm, nil 1308 } 1309 } 1310 return vm, nil 1311 } 1312 1313 func (host *SHost) changeNic(device types.BaseVirtualDevice, update types.BaseVirtualDevice) { 1314 current := device.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard() 1315 changed := update.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard() 1316 1317 current.Backing = changed.Backing 1318 if changed.MacAddress != "" { 1319 current.MacAddress = changed.MacAddress 1320 } 1321 if changed.AddressType != "" { 1322 current.AddressType = changed.AddressType 1323 } 1324 } 1325 1326 func (host *SHost) isVersion50() bool { 1327 version := host.GetVersion() 1328 if strings.HasPrefix(version, "5.") { 1329 return true 1330 } 1331 return false 1332 } 1333 1334 func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { 1335 return host.GetIHostNicsInternal(false) 1336 } 1337 1338 func (host *SHost) GetIHostNicsInternal(debug bool) ([]cloudprovider.ICloudHostNetInterface, error) { 1339 nics := host.getNicInfo(debug) 1340 inics := make([]cloudprovider.ICloudHostNetInterface, len(nics)) 1341 for i := 0; i < len(nics); i += 1 { 1342 inics[i] = &nics[i] 1343 } 1344 return inics, nil 1345 } 1346 1347 func (host *SHost) getLocalStorageCache() (*SDatastoreImageCache, error) { 1348 if host.storageCache == nil { 1349 sc, err := host.newLocalStorageCache() 1350 if err != nil { 1351 return nil, err 1352 } 1353 host.storageCache = sc 1354 } 1355 return host.storageCache, nil 1356 } 1357 1358 func (host *SHost) newLocalStorageCache() (*SDatastoreImageCache, error) { 1359 ctx := context.Background() 1360 1361 istorages, err := host.GetIStorages() 1362 if err != nil { 1363 return nil, err 1364 } 1365 var errmsg string 1366 var cacheDs *SDatastore 1367 var maxDs *SDatastore 1368 var maxCapacity int64 1369 for i := 0; i < len(istorages); i += 1 { 1370 ds := istorages[i].(*SDatastore) 1371 if !ds.isLocalVMFS() { 1372 continue 1373 } 1374 _, err := ds.CheckFile(ctx, IMAGE_CACHE_DIR_NAME) 1375 if err != nil { 1376 if errors.Cause(err) != cloudprovider.ErrNotFound { 1377 // return nil, err 1378 if len(errmsg) > 0 { 1379 errmsg += "," 1380 } 1381 errmsg += err.Error() 1382 } else if maxCapacity < ds.GetCapacityMB() { 1383 maxCapacity = ds.GetCapacityMB() 1384 maxDs = ds 1385 } 1386 } else { 1387 cacheDs = ds 1388 break 1389 } 1390 } 1391 if cacheDs == nil { 1392 // if no existing image cache dir found, use the one with maximal capacilty 1393 cacheDs = maxDs 1394 } 1395 1396 if cacheDs == nil { 1397 return nil, fmt.Errorf(errmsg) 1398 } 1399 1400 return &SDatastoreImageCache{ 1401 datastore: cacheDs, 1402 host: host, 1403 }, nil 1404 } 1405 1406 func (host *SHost) GetManagementServerIp() string { 1407 return host.getHostSystem().Summary.ManagementServerIp 1408 } 1409 1410 func (host *SHost) IsManagedByVCenter() bool { 1411 return len(host.getHostSystem().Summary.ManagementServerIp) > 0 1412 } 1413 1414 func (host *SHost) FindDataStoreById(id string) (*SDatastore, error) { 1415 datastores, err := host.GetDataStores() 1416 if err != nil { 1417 return nil, err 1418 } 1419 for i := range datastores { 1420 if datastores[i].GetGlobalId() == id { 1421 return datastores[i].(*SDatastore), nil 1422 } 1423 } 1424 return nil, fmt.Errorf("no such datastore %s", id) 1425 } 1426 1427 func (host *SHost) GetDataStores() ([]cloudprovider.ICloudStorage, error) { 1428 err := host.fetchDatastores() 1429 if err != nil { 1430 return nil, err 1431 } 1432 return host.datastores, nil 1433 } 1434 1435 func (host *SHost) fetchDatastores() error { 1436 if host.datastores != nil { 1437 return nil 1438 } 1439 1440 dc, err := host.GetDatacenter() 1441 if err != nil { 1442 return err 1443 } 1444 dss := host.getHostSystem().Datastore 1445 var datastores []mo.Datastore 1446 err = host.manager.references2Objects(dss, DATASTORE_PROPS, &datastores) 1447 if err != nil { 1448 return err 1449 } 1450 host.datastores = make([]cloudprovider.ICloudStorage, 0) 1451 for i := 0; i < len(datastores); i += 1 { 1452 ds := NewDatastore(host.manager, &datastores[i], dc) 1453 dsId := ds.GetGlobalId() 1454 if len(dsId) > 0 { 1455 host.datastores = append(host.datastores, ds) 1456 } 1457 } 1458 return nil 1459 } 1460 1461 func (host *SHost) FileUrlPathToDsPath(path string) (string, error) { 1462 var newPath string 1463 dss, err := host.GetDataStores() 1464 if err != nil { 1465 return newPath, err 1466 } 1467 for _, ds := range dss { 1468 rds := ds.(*SDatastore) 1469 log.Debugf("rds: %s", rds.GetUrl()) 1470 if strings.HasPrefix(path, rds.GetUrl()) { 1471 newPath = fmt.Sprintf("[%s] %s", rds.GetRelName(), path[len(rds.GetUrl()):]) 1472 break 1473 } 1474 } 1475 if len(newPath) == 0 { 1476 return newPath, fmt.Errorf("path '%s' don't belong any datastore of host '%s'", path, host.GetName()) 1477 } 1478 return newPath, nil 1479 } 1480 1481 func (host *SHost) FindNetworkByVlanID(vlanID int32) (IVMNetwork, error) { 1482 if host.IsActiveVlanID(vlanID) { 1483 net, err := host.findBasicNetwork(vlanID) 1484 if err != nil { 1485 return nil, errors.Wrap(err, "findBasicNetwork error") 1486 } 1487 if net != nil { 1488 return net, nil 1489 } 1490 1491 // no found in basic network 1492 dvpg, err := host.findVlanDVPG(vlanID) 1493 if err != nil { 1494 return nil, errors.Wrap(err, "findVlanDVPG") 1495 } 1496 return dvpg, nil 1497 } 1498 n, err := host.findBasicNetwork(vlanID) 1499 if err != nil { 1500 return nil, errors.Wrap(err, "find Basic network") 1501 } 1502 if n != nil { 1503 return n, err 1504 } 1505 return host.findNovlanDVPG() 1506 } 1507 1508 // IsActiveVlanID will detect if vlanID is active that means vlanID in (1, 4095). 1509 func (host *SHost) IsActiveVlanID(vlanID int32) bool { 1510 if vlanID > 1 && vlanID < 4095 { 1511 return true 1512 } 1513 return false 1514 } 1515 1516 func (host *SHost) findBasicNetwork(vlanID int32) (IVMNetwork, error) { 1517 nets, err := host.getBasicNetworks() 1518 if err != nil { 1519 return nil, err 1520 } 1521 if len(nets) == 0 { 1522 return nil, nil 1523 } 1524 if !host.IsActiveVlanID(vlanID) { 1525 return nets[0], nil 1526 } 1527 for i := range nets { 1528 if nets[i].GetVlanId() == vlanID { 1529 return nets[i], nil 1530 } 1531 } 1532 return nil, nil 1533 } 1534 1535 func (host *SHost) getBasicNetworks() ([]IVMNetwork, error) { 1536 nets, err := host.GetNetworks() 1537 if err != nil { 1538 return nil, errors.Wrap(err, "GetNetworks") 1539 } 1540 ret := make([]IVMNetwork, 0) 1541 for i := range nets { 1542 if net, ok := nets[i].(*SNetwork); ok { 1543 ret = append(ret, net) 1544 } 1545 } 1546 return ret, nil 1547 } 1548 1549 func (host *SHost) GetNetworks() ([]IVMNetwork, error) { 1550 if host.networks != nil { 1551 return host.networks, nil 1552 } 1553 netMobs := host.getHostSystem().Network 1554 netPortMobs := make([]types.ManagedObjectReference, 0) 1555 netNetMobs := make([]types.ManagedObjectReference, 0) 1556 1557 for i := range netMobs { 1558 log.Debugf("type: %s value: %s", netMobs[i].Type, netMobs[i].Value) 1559 if netMobs[i].Type == "DistributedVirtualPortgroup" { 1560 netPortMobs = append(netPortMobs, netMobs[i]) 1561 } else { 1562 netNetMobs = append(netNetMobs, netMobs[i]) 1563 } 1564 } 1565 1566 nets := make([]IVMNetwork, 0) 1567 1568 if len(netPortMobs) > 0 { 1569 moPorts := make([]mo.DistributedVirtualPortgroup, 0) 1570 err := host.manager.references2Objects(netPortMobs, DVPORTGROUP_PROPS, &moPorts) 1571 if err != nil { 1572 return nil, errors.Wrap(err, "references2Objects") 1573 } 1574 for i := range moPorts { 1575 port := NewDistributedVirtualPortgroup(host.manager, &moPorts[i], host.datacenter) 1576 nets = append(nets, port) 1577 } 1578 } 1579 if len(netNetMobs) > 0 { 1580 moNets := make([]mo.Network, 0) 1581 err := host.manager.references2Objects(netNetMobs, NETWORK_PROPS, &moNets) 1582 if err != nil { 1583 return nil, errors.Wrap(err, "references2Objects") 1584 } 1585 for i := range moNets { 1586 net := NewNetwork(host.manager, &moNets[i], host.datacenter) 1587 nets = append(nets, net) 1588 } 1589 } 1590 1591 // network map 1592 netMap := make(map[string]IVMNetwork) 1593 for i := range nets { 1594 netMap[nets[i].GetName()] = nets[i] 1595 } 1596 1597 // fetch all portgroup 1598 portgroups := host.getHostSystem().Config.Network.Portgroup 1599 for _, pg := range portgroups { 1600 net, ok := netMap[pg.Spec.Name] 1601 if !ok { 1602 log.Infof("SNetwork corresponding to the portgroup whose name is %s could not be found", pg.Spec.Name) 1603 continue 1604 } 1605 net.SetHostPortGroup(pg) 1606 } 1607 host.networks = nets 1608 return host.networks, nil 1609 } 1610 1611 func (host *SHost) findNovlanDVPG() (*SDistributedVirtualPortgroup, error) { 1612 nets, err := host.datacenter.GetNetworks() 1613 if err != nil { 1614 return nil, errors.Wrap(err, "SHost.datacenter.GetNetworks") 1615 } 1616 for _, net := range nets { 1617 dvpg, ok := net.(*SDistributedVirtualPortgroup) 1618 if !ok || !dvpg.ContainHost(host) || len(dvpg.GetActivePorts()) == 0 { 1619 continue 1620 } 1621 nvlan := dvpg.GetVlanId() 1622 if !host.IsActiveVlanID(nvlan) { 1623 return dvpg, nil 1624 } 1625 } 1626 return nil, nil 1627 } 1628 1629 func (host *SHost) findDVPGById(id string) (*SDistributedVirtualPortgroup, error) { 1630 nets, err := host.datacenter.GetNetworks() 1631 if err != nil { 1632 return nil, errors.Wrap(err, "SHost.datacenter.GetNetworks") 1633 } 1634 for _, net := range nets { 1635 if dvpg, ok := net.(*SDistributedVirtualPortgroup); ok && dvpg.GetId() == id { 1636 return dvpg, nil 1637 } 1638 } 1639 return nil, nil 1640 } 1641 1642 func (host *SHost) findVlanDVPG(vlanId int32) (*SDistributedVirtualPortgroup, error) { 1643 nets, err := host.datacenter.GetNetworks() 1644 if err != nil { 1645 return nil, errors.Wrap(err, "SHost.datacenter.GetNetworks") 1646 } 1647 for _, net := range nets { 1648 dvpg, ok := net.(*SDistributedVirtualPortgroup) 1649 if !ok || len(dvpg.GetActivePorts()) == 0 { 1650 continue 1651 } 1652 nvlan := dvpg.GetVlanId() 1653 if nvlan == vlanId { 1654 if dvpg.ContainHost(host) { 1655 return dvpg, nil 1656 } 1657 msg := "Find dvpg with correct vlan but it didn't contain this host" 1658 log.Debugf(msg) 1659 // add host to dvg 1660 // err := dvpg.AddHostToDVS(host) 1661 // if err != nil { 1662 // return nil, errors.Wrapf(err, "dvpg %s add host to dvs error", dvpg.GetName()) 1663 // } 1664 continue 1665 } 1666 } 1667 return nil, nil 1668 } 1669 1670 func (host *SHost) GetoHostSystem() *object.HostSystem { 1671 return object.NewHostSystem(host.manager.client.Client, host.getHostSystem().Reference()) 1672 } 1673 1674 func (host *SHost) GetResourcePool() (*object.ResourcePool, error) { 1675 var err error 1676 if host.parent == nil { 1677 host.parent, err = host.getParent() 1678 if err != nil { 1679 return nil, err 1680 } 1681 } 1682 return object.NewResourcePool(host.manager.client.Client, *host.parent.ResourcePool), nil 1683 } 1684 1685 func (host *SHost) getParent() (*mo.ComputeResource, error) { 1686 var mcr *mo.ComputeResource 1687 var parent interface{} 1688 1689 moHost := host.getHostSystem() 1690 1691 switch moHost.Parent.Type { 1692 case "ComputeResource": 1693 mcr = new(mo.ComputeResource) 1694 parent = mcr 1695 case "ClusterComputeResource": 1696 mcc := new(mo.ClusterComputeResource) 1697 mcr = &mcc.ComputeResource 1698 parent = mcc 1699 default: 1700 return nil, errors.Error(fmt.Sprintf("unknown host parent type: %s", moHost.Parent.Type)) 1701 } 1702 1703 err := host.manager.reference2Object(*moHost.Parent, []string{"name", "resourcePool"}, parent) 1704 if err != nil { 1705 return nil, errors.Wrap(err, "SESXiClient.reference2Object") 1706 } 1707 return mcr, nil 1708 } 1709 1710 func (host *SHost) GetResourcePools() ([]mo.ResourcePool, error) { 1711 cluster, err := host.GetCluster() 1712 if err != nil { 1713 return nil, errors.Wrap(err, "GetCluster") 1714 } 1715 return cluster.ListResourcePools() 1716 } 1717 1718 func (host *SHost) GetCluster() (*SCluster, error) { 1719 cluster, err := host.getCluster() 1720 if err != nil { 1721 return nil, errors.Wrap(err, "getCluster") 1722 } 1723 return NewCluster(host.manager, cluster, host.datacenter), nil 1724 } 1725 1726 func (host *SHost) SyncResourcePool(name string) (*object.ResourcePool, error) { 1727 cluster, err := host.GetCluster() 1728 if err != nil { 1729 log.Errorf("failed to get host %s cluster info: %v", host.GetName(), err) 1730 return host.GetResourcePool() 1731 } 1732 pool, err := cluster.SyncResourcePool(name) 1733 if err != nil { 1734 log.Errorf("failed to sync resourcePool(%s) for cluster %s error: %v", name, cluster.GetName(), err) 1735 return host.GetResourcePool() 1736 } 1737 return object.NewResourcePool(host.manager.client.Client, pool.Reference()), nil 1738 } 1739 1740 func (host *SHost) getCluster() (*mo.ClusterComputeResource, error) { 1741 moHost := host.getHostSystem() 1742 if moHost.Parent.Type != "ClusterComputeResource" { 1743 return nil, fmt.Errorf("host %s parent is not the cluster resource", host.GetName()) 1744 } 1745 cluster := &mo.ClusterComputeResource{} 1746 err := host.manager.reference2Object(*moHost.Parent, []string{"name", "resourcePool"}, cluster) 1747 if err != nil { 1748 return nil, errors.Wrap(err, "SESXiClient.reference2Object") 1749 } 1750 return cluster, nil 1751 } 1752 1753 func (host *SHost) GetSiblingHosts() ([]*SHost, error) { 1754 rp, err := host.getParent() 1755 if err != nil { 1756 return nil, err 1757 } 1758 moHosts := make([]mo.HostSystem, 0, len(rp.Host)) 1759 err = host.manager.references2Objects(rp.Host, HOST_SYSTEM_PROPS, &moHosts) 1760 if err != nil { 1761 return nil, errors.Wrap(err, "SESXiClient.references2Objects") 1762 } 1763 1764 ret := make([]*SHost, len(moHosts)) 1765 for i := range moHosts { 1766 ret[i] = NewHost(host.manager, &moHosts[i], host.datacenter) 1767 } 1768 return ret, nil 1769 }