| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866 |
- // Copyright 2019 Yunion
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package esxi
- import (
- "context"
- "fmt"
- "reflect"
- "regexp"
- "strings"
- "time"
- "github.com/vmware/govmomi/object"
- "github.com/vmware/govmomi/vim25/mo"
- "github.com/vmware/govmomi/vim25/soap"
- "github.com/vmware/govmomi/vim25/types"
- "yunion.io/x/jsonutils"
- "yunion.io/x/log"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/pkg/util/netutils"
- "yunion.io/x/pkg/util/reflectutils"
- "yunion.io/x/pkg/util/regutils"
- "yunion.io/x/pkg/utils"
- api "yunion.io/x/cloudmux/pkg/apis/compute"
- "yunion.io/x/cloudmux/pkg/cloudprovider"
- "yunion.io/x/cloudmux/pkg/multicloud"
- )
- var (
- True bool = true
- False bool = false
- )
- var (
- hostConfigProps = []string{"config.network", "config.storageDevice"}
- hostSummaryProps = []string{"summary.runtime", "summary.hardware", "summary.config.product", "summary.managementServerIp"}
- hostHardWareProps = []string{"hardware.systemInfo"}
- )
- var HOST_SYSTEM_PROPS []string
- func init() {
- HOST_SYSTEM_PROPS = []string{"name", "parent", "vm", "datastore", "network"}
- HOST_SYSTEM_PROPS = append(HOST_SYSTEM_PROPS, hostConfigProps...)
- HOST_SYSTEM_PROPS = append(HOST_SYSTEM_PROPS, hostSummaryProps...)
- HOST_SYSTEM_PROPS = append(HOST_SYSTEM_PROPS, hostHardWareProps...)
- }
- type SHostStorageAdapterInfo struct {
- Device string
- Model string
- Driver string
- Pci string
- Drivers []*SHostStorageDriverInfo
- Enclosure int
- }
- type SHostStorageDriverInfo struct {
- CN string
- Name string
- Model string
- Vendor string
- Revision string
- Status string
- SSD bool
- Dev string
- Size int
- Slot int
- }
- type SHostStorageEnclosureInfo struct {
- CN string
- Name string
- Model string
- Vendor string
- Revision string
- Status string
- }
- type SHostStorageInfo struct {
- Adapter int
- Driver string
- Index int
- Model string
- Rotate bool
- Status string
- Size int
- }
- type SHost struct {
- multicloud.SHostBase
- SManagedObject
- masterIp string
- nicInfo []sHostNicInfo
- storageInfo []SHostStorageInfo
- datastores []cloudprovider.ICloudStorage
- storageCache *SDatastoreImageCache
- vms []cloudprovider.ICloudVM
- parent *mo.ComputeResource
- networks []IVMNetwork
- tempalteVMs []*SVirtualMachine
- }
- func NewHost(manager *SESXiClient, host *mo.HostSystem, dc *SDatacenter) *SHost {
- if host.Config == nil {
- log.Errorf("empty host config %s", host.Name)
- return nil
- }
- return &SHost{SManagedObject: newManagedObject(manager, host, dc)}
- }
- var (
- ip4addrPattern = regexp.MustCompile(`\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}`)
- )
- func formatName(name string) string {
- if ip4addrPattern.MatchString(name) {
- return strings.Replace(name, ".", "-", -1)
- } else {
- dotPos := strings.IndexByte(name, '.')
- if dotPos > 0 && !regutils.MatchIP4Addr(name) {
- name = name[:dotPos]
- }
- return name
- }
- }
- func (host *SHost) GetName() string {
- return formatName(host.SManagedObject.GetName())
- }
- func (host *SHost) getCluster() (*mo.ClusterComputeResource, error) {
- moHost := host.getHostSystem()
- if moHost.Parent.Type != "ClusterComputeResource" {
- return nil, errors.Wrapf(cloudprovider.ErrNotFound, "host %s parent is not the cluster resource", host.GetName())
- }
- cluster := &mo.ClusterComputeResource{}
- err := host.manager.reference2Object(*moHost.Parent, []string{"name", "resourcePool"}, cluster)
- if err != nil {
- return nil, errors.Wrap(err, "SESXiClient.reference2Object")
- }
- return cluster, nil
- }
- func (host *SHost) GetCluster() (*SCluster, error) {
- cluster, err := host.getCluster()
- if err != nil {
- return nil, errors.Wrap(err, "getCluster")
- }
- return NewCluster(host.manager, cluster, host.datacenter), nil
- }
- func (host *SHost) GetSchedtags() ([]cloudprovider.Schedtag, error) {
- dc, err := host.GetDatacenter()
- if err != nil {
- return nil, err
- }
- cluster, err := host.GetCluster()
- if err != nil {
- return nil, err
- }
- ret := []cloudprovider.Schedtag{}
- ret = append(ret, cloudprovider.Schedtag{
- Name: fmt.Sprintf("cluster:|%s|%s|%s", host.datacenter.manager.cpcfg.Name, dc.GetName(), cluster.GetName()),
- Id: fmt.Sprintf("%s|%s|%s", host.datacenter.manager.cpcfg.Id, dc.GetId(), cluster.GetId()),
- })
- pools, err := cluster.listResourcePools()
- if err != nil {
- return nil, err
- }
- for i := range pools {
- pool := NewResourcePool(host.manager, &pools[i], host.datacenter)
- if pool.IsDefault() {
- continue
- }
- ret = append(ret, cloudprovider.Schedtag{
- Name: fmt.Sprintf("pool:|%s|%s|%s|%s", host.datacenter.manager.cpcfg.Name, dc.GetName(), cluster.GetName(), strings.Join(pool.GetPath(), "|")),
- Id: fmt.Sprintf("%s|%s|%s|%s", host.datacenter.manager.cpcfg.Id, dc.GetId(), cluster.GetId(), pool.GetId()),
- Meta: map[string]string{
- cloudprovider.METADATA_POOL_ID: pool.GetId(),
- },
- })
- }
- return ret, nil
- }
- func (host *SHost) getHostSystem() *mo.HostSystem {
- return host.object.(*mo.HostSystem)
- }
- func (host *SHost) GetGlobalId() string {
- return host.GetAccessIp()
- }
- func (host *SHost) GetStatus() string {
- /*
- HostSystemPowerStatePoweredOn = HostSystemPowerState("poweredOn")
- HostSystemPowerStatePoweredOff = HostSystemPowerState("poweredOff")
- HostSystemPowerStateStandBy = HostSystemPowerState("standBy")
- HostSystemPowerStateUnknown = HostSystemPowerState("unknown")
- */
- switch host.getHostSystem().Summary.Runtime.PowerState {
- case types.HostSystemPowerStatePoweredOn:
- return api.HOST_STATUS_RUNNING
- case types.HostSystemPowerStatePoweredOff:
- return api.HOST_STATUS_READY
- default:
- return api.HOST_STATUS_UNKNOWN
- }
- }
- func (host *SHost) Refresh() error {
- base := host.SManagedObject
- var moObj mo.HostSystem
- err := host.manager.reference2Object(host.object.Reference(), HOST_SYSTEM_PROPS, &moObj)
- if err != nil {
- return err
- }
- base.object = &moObj
- *host = SHost{}
- host.SManagedObject = base
- return nil
- }
- func (host *SHost) IsEmulated() bool {
- return false
- }
- func (host *SHost) fetchVMs(all bool) error {
- if host.vms != nil {
- return nil
- }
- dc, err := host.GetDatacenter()
- if err != nil {
- return errors.Wrapf(err, "GetDatacenter")
- }
- var vms []*SVirtualMachine
- for i := 1; i < 3; i++ {
- hostVms := host.getHostSystem().Vm
- if len(hostVms) == 0 {
- return nil
- }
- vms, err = dc.fetchVms(hostVms, all)
- if err != nil {
- e := errors.Cause(err)
- // 机器刚删除时, hostVms若不刷新, 会有类似错误: ServerFaultCode: The object 'vim.VirtualMachine:vm-1053' has already been deleted or has not been completely created
- // https://github.com/vmware/govmomi/pull/1916/files
- if soap.IsSoapFault(e) {
- _, ok := soap.ToSoapFault(e).VimFault().(types.ManagedObjectNotFound)
- if ok {
- time.Sleep(time.Second * 10)
- host.Refresh()
- continue
- }
- }
- return errors.Wrapf(err, "dc.fetchVMs")
- }
- }
- if err != nil {
- return errors.Wrapf(err, "dc.fetchVms")
- }
- for _, vm := range vms {
- if vm.IsTemplate() {
- host.tempalteVMs = append(host.tempalteVMs, vm)
- } else {
- host.vms = append(host.vms, vm)
- }
- }
- return nil
- }
- func (host *SHost) GetIVMs2() ([]cloudprovider.ICloudVM, error) {
- err := host.fetchVMs(true)
- if err != nil {
- return nil, errors.Wrapf(err, "fetchVMs")
- }
- return host.vms, nil
- }
- func (host *SHost) GetTemplateVMs() ([]*SVirtualMachine, error) {
- err := host.fetchVMs(false)
- if err != nil {
- return nil, errors.Wrap(err, "fetchVMs")
- }
- return host.tempalteVMs, nil
- }
- func (host *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) {
- err := host.fetchVMs(false)
- if err != nil {
- return nil, err
- }
- return host.vms, nil
- }
- func (host *SHost) GetTemplateVMById(id string) (*SVirtualMachine, error) {
- id = host.manager.getPrivateId(id)
- temVms, err := host.GetTemplateVMs()
- if err != nil {
- return nil, err
- }
- for i := range temVms {
- if temVms[i].GetGlobalId() == id {
- return temVms[i], nil
- }
- }
- return nil, cloudprovider.ErrNotFound
- }
- func (host *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
- id = host.manager.getPrivateId(id)
- vms, err := host.GetIVMs()
- if err != nil {
- return nil, err
- }
- for i := 0; i < len(vms); i += 1 {
- if vms[i].GetGlobalId() == id || vms[i].GetName() == id {
- return vms[i], nil
- }
- }
- return nil, cloudprovider.ErrNotFound
- }
- func (host *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
- return host.GetDataStores()
- }
- func (host *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
- istorages, err := host.GetIStorages()
- if err != nil {
- return nil, err
- }
- for i := 0; i < len(istorages); i += 1 {
- if istorages[i].GetGlobalId() == id {
- return istorages[i], nil
- }
- }
- return nil, cloudprovider.ErrNotFound
- }
- func (host *SHost) GetEnabled() bool {
- return !host.getHostSystem().Summary.Runtime.InMaintenanceMode
- }
- func (host *SHost) GetHostStatus() string {
- /*
- HostSystemConnectionStateConnected = HostSystemConnectionState("connected")
- HostSystemConnectionStateNotResponding = HostSystemConnectionState("notResponding")
- HostSystemConnectionStateDisconnected = HostSystemConnectionState("disconnected")
- */
- if host.getHostSystem().Summary.Runtime.InMaintenanceMode {
- return api.HOST_OFFLINE
- }
- switch host.getHostSystem().Summary.Runtime.ConnectionState {
- case types.HostSystemConnectionStateConnected:
- return api.HOST_ONLINE
- default:
- return api.HOST_OFFLINE
- }
- }
- func findHostNicByMac(nicInfoList []sHostNicInfo, mac string) *sHostNicInfo {
- for i := 0; i < len(nicInfoList); i += 1 {
- if nicInfoList[i].Mac == mac {
- return &nicInfoList[i]
- }
- }
- return nil
- }
- func (host *SHost) getAdminNic() *sHostNicInfo {
- nics := host.getNicInfo(false)
- for i := 0; i < len(nics); i += 1 {
- if nics[i].NicType == api.NIC_TYPE_ADMIN {
- return &nics[i]
- }
- }
- for i := 0; i < len(nics); i += 1 {
- if len(nics[i].IpAddr) > 0 {
- return &nics[i]
- }
- }
- return nil
- }
- func (host *SHost) getNicInfo(debug bool) []sHostNicInfo {
- if host.nicInfo == nil {
- host.nicInfo = host.fetchNicInfo(debug)
- }
- return host.nicInfo
- }
- func mask2len(mask string) int8 {
- maskAddr, _ := netutils.NewIPV4Addr(mask)
- return netutils.Mask2Len(maskAddr)
- }
- func (host *SHost) isVnicAdmin(nic types.HostVirtualNic) bool {
- return host.isIpAdmin(nic.Spec.Ip.IpAddress)
- }
- func (host *SHost) isIpAdmin(ip string) bool {
- if len(host.masterIp) > 0 {
- if host.masterIp == ip {
- return true
- } else {
- return false
- }
- }
- exist, err := host.manager.IsHostIpExists(ip)
- if err != nil {
- log.Errorf("IsHostIpExists %s fail %s", ip, err)
- return false
- }
- if exist {
- host.masterIp = ip
- return true
- }
- return false
- }
- func (host *SHost) fetchNicInfo(debug bool) []sHostNicInfo {
- moHost := host.getHostSystem()
- if moHost.Config == nil || moHost.Config.Network == nil {
- return nil
- }
- if debug {
- log.Debugf("%s", jsonutils.Marshal(moHost.Config.Network).PrettyString())
- }
- nicInfoList := make([]sHostNicInfo, 0)
- for _, nic := range moHost.Config.Network.Pnic {
- // log.Debugf("pnic %d: %s %#v", i, jsonutils.Marshal(nic), nic)
- info := sHostNicInfo{
- host: host,
- }
- info.Dev = nic.Device
- info.Driver = nic.Driver
- info.Mac = netutils.FormatMacAddr(nic.Mac)
- info.Index = int8(len(nicInfoList))
- info.LinkUp = false
- nicInfoList = append(nicInfoList, info)
- }
- vnics := make([]types.HostVirtualNic, 0)
- if len(moHost.Config.Network.Vnic) > 0 {
- vnics = append(vnics, moHost.Config.Network.Vnic...)
- }
- if len(moHost.Config.Network.ConsoleVnic) > 0 {
- vnics = append(vnics, moHost.Config.Network.ConsoleVnic...)
- }
- for _, nic := range vnics {
- // log.Debugf("vnic %d: %s %#v", i, jsonutils.Marshal(nic), nic)
- mac := netutils.FormatMacAddr(nic.Spec.Mac)
- pnic := findHostNicByMac(nicInfoList, mac)
- if pnic != nil {
- if len(pnic.IpAddr) > 0 && host.isIpAdmin(pnic.IpAddr) {
- continue
- }
- // findMaster = true
- pnic.IpAddr = nic.Spec.Ip.IpAddress
- pnic.IpAddrPrefixLen = mask2len(nic.Spec.Ip.SubnetMask)
- if nic.Spec.Ip.IpV6Config != nil && len(nic.Spec.Ip.IpV6Config.IpV6Address) > 0 {
- pnic.IpAddr6 = nic.Spec.Ip.IpV6Config.IpV6Address[0].IpAddress
- pnic.IpAddr6PrefixLen = int8(nic.Spec.Ip.IpV6Config.IpV6Address[0].PrefixLength)
- }
- if host.isVnicAdmin(nic) {
- pnic.NicType = api.NIC_TYPE_ADMIN
- }
- pnic.LinkUp = true
- pnic.Mtu = nic.Spec.Mtu
- } else {
- info := sHostNicInfo{}
- info.Dev = nic.Device
- info.Driver = "vmkernel"
- info.Mac = mac
- info.Index = int8(len(nicInfoList))
- info.LinkUp = true
- info.IpAddr = nic.Spec.Ip.IpAddress
- info.IpAddrPrefixLen = mask2len(nic.Spec.Ip.SubnetMask)
- if nic.Spec.Ip.IpV6Config != nil && len(nic.Spec.Ip.IpV6Config.IpV6Address) > 0 {
- info.IpAddr6 = nic.Spec.Ip.IpV6Config.IpV6Address[0].IpAddress
- info.IpAddr6PrefixLen = int8(nic.Spec.Ip.IpV6Config.IpV6Address[0].PrefixLength)
- }
- info.Mtu = nic.Spec.Mtu
- if host.isVnicAdmin(nic) {
- info.NicType = api.NIC_TYPE_ADMIN
- }
- nicInfoList = append(nicInfoList, info)
- }
- }
- visited := make(map[string]IVMNetwork)
- dc, err := host.GetDatacenter()
- if err != nil {
- log.Errorf("fetchNicInfo GetDatacenter fail %s", err)
- } else {
- // map portgroup
- for _, pg := range moHost.Config.Network.Portgroup {
- // log.Debugf("portgroup: %s %#v", jsonutils.Marshal(pg), pg)
- netName := pg.Spec.Name
- net, _ := dc.getNetworkByName(netName)
- if net != nil {
- visited[net.GetName()] = net
- info := sHostNicInfo{
- host: host,
- network: net,
- }
- info.Dev = pg.Spec.VswitchName
- info.Driver = "portgroup"
- info.LinkUp = true
- info.Mtu = 1500
- info.Index = int8(len(nicInfoList))
- info.VlanId = int(pg.Spec.VlanId)
- nicInfoList = append(nicInfoList, info)
- }
- }
- }
- networks, err := host.GetNetworks()
- if err != nil {
- log.Errorf("GetNetworks %s", err)
- } else {
- for i := range networks {
- net := networks[i]
- if _, ok := visited[net.GetName()]; ok {
- continue
- }
- visited[net.GetName()] = net
- info := sHostNicInfo{
- host: host,
- network: net,
- }
- info.Dev = net.GetVswitchName()
- info.Driver = net.GetType()
- info.LinkUp = true
- info.Mtu = 1500
- info.Index = int8(len(nicInfoList))
- info.VlanId = int(net.GetVlanId())
- nicInfoList = append(nicInfoList, info)
- }
- }
- return nicInfoList
- }
- func (host *SHost) GetAccessIp() string {
- adminNic := host.getAdminNic()
- if adminNic != nil {
- return adminNic.IpAddr
- }
- return ""
- }
- func (host *SHost) GetAccessMac() string {
- adminNic := host.getAdminNic()
- if adminNic != nil {
- return adminNic.Mac
- }
- return ""
- }
- type SSysInfo struct {
- Manufacture string
- Model string
- SerialNumber string
- }
- func (host *SHost) GetSysInfo() jsonutils.JSONObject {
- sysinfo := SSysInfo{}
- hostsys := host.getHostSystem()
- sysinfo.Manufacture = hostsys.Summary.Hardware.Vendor
- sysinfo.Model = hostsys.Summary.Hardware.Model
- if hostsys.Hardware != nil {
- sysinfo.SerialNumber = hostsys.Hardware.SystemInfo.SerialNumber
- }
- return jsonutils.Marshal(&sysinfo)
- }
- func (host *SHost) GetSN() string {
- hostsys := host.getHostSystem()
- if hostsys.Hardware != nil {
- return hostsys.Hardware.SystemInfo.SerialNumber
- }
- return ""
- }
- func (host *SHost) GetCpuCount() int {
- return int(host.getHostSystem().Summary.Hardware.NumCpuThreads)
- }
- func (host *SHost) GetNodeCount() int8 {
- return int8(host.getHostSystem().Summary.Hardware.NumCpuPkgs)
- }
- func (host *SHost) GetCpuDesc() string {
- return host.getHostSystem().Summary.Hardware.CpuModel
- }
- func (host *SHost) GetCpuMhz() int {
- return int(host.getHostSystem().Summary.Hardware.CpuMhz)
- }
- func (host *SHost) GetMemSizeMB() int {
- return int(host.getHostSystem().Summary.Hardware.MemorySize / 1024 / 1024)
- }
- func (host *SHost) getStorageInfo() []SHostStorageInfo {
- if host.storageInfo != nil {
- return host.storageInfo
- }
- diskSlots := make(map[int]SHostStorageInfo)
- list := host.getStorages()
- for i := 0; i < len(list); i += 1 {
- for j := 0; j < len(list[i].Drivers); j += 1 {
- drv := list[i].Drivers[j]
- info := SHostStorageInfo{
- Adapter: 0,
- Driver: "Linux",
- Index: drv.Slot,
- Model: strings.TrimSpace(fmt.Sprintf("%s %s", drv.Vendor, drv.Model)),
- Rotate: !drv.SSD,
- Status: drv.Status,
- Size: drv.Size,
- }
- diskSlots[info.Index] = info
- }
- }
- disks := make([]SHostStorageInfo, 0)
- idx := 0
- for {
- if info, ok := diskSlots[idx]; ok {
- disks = append(disks, info)
- idx += 1
- } else {
- break
- }
- }
- host.storageInfo = disks
- return host.storageInfo
- }
- func (host *SHost) getStorages() []*SHostStorageAdapterInfo {
- adapterList := make([]*SHostStorageAdapterInfo, 0)
- adapterTable := make(map[string]*SHostStorageAdapterInfo)
- driversTable := make(map[string]*SHostStorageDriverInfo, 0)
- enclosuresTable := make(map[string]*SHostStorageEnclosureInfo, 0)
- moHost := host.getHostSystem()
- for i := 0; i < len(moHost.Config.StorageDevice.HostBusAdapter); i += 1 {
- ad := moHost.Config.StorageDevice.HostBusAdapter[i]
- adinfo := ad.GetHostHostBusAdapter()
- if adinfo == nil {
- log.Errorf("fail to GetHostHostBusAdapter")
- continue
- }
- info := SHostStorageAdapterInfo{}
- info.Device = adinfo.Device
- info.Model = strings.TrimSpace(adinfo.Model)
- info.Driver = adinfo.Driver
- info.Pci = adinfo.Pci
- info.Drivers = make([]*SHostStorageDriverInfo, 0)
- info.Enclosure = -1
- adapterTable[adinfo.Key] = &info
- adapterList = append(adapterList, &info)
- }
- for i := 0; i < len(moHost.Config.StorageDevice.ScsiLun); i += 1 {
- drv := moHost.Config.StorageDevice.ScsiLun[i]
- lunInfo := drv.GetScsiLun()
- if lunInfo == nil {
- log.Errorf("fail to GetScsiLun")
- continue
- }
- if lunInfo.DeviceType == "disk" {
- scsiDisk := drv.(*types.HostScsiDisk)
- info := SHostStorageDriverInfo{}
- info.CN = scsiDisk.CanonicalName
- info.Name = scsiDisk.DisplayName
- info.Model = strings.TrimSpace(scsiDisk.Model)
- info.Vendor = strings.TrimSpace(scsiDisk.Vendor)
- info.Revision = scsiDisk.Revision
- info.Status = scsiDisk.OperationalState[0]
- if scsiDisk.Ssd != nil && *scsiDisk.Ssd {
- info.SSD = true
- }
- info.Dev = scsiDisk.DevicePath
- info.Size = int(int64(scsiDisk.Capacity.BlockSize) * scsiDisk.Capacity.Block / 1024 / 1024)
- driversTable[scsiDisk.Key] = &info
- } else if lunInfo.DeviceType == "enclosure" {
- enclosuresTable[lunInfo.Key] = &SHostStorageEnclosureInfo{
- CN: lunInfo.CanonicalName,
- Name: lunInfo.DisplayName,
- Model: strings.TrimSpace(lunInfo.Model),
- Vendor: strings.TrimSpace(lunInfo.Vendor),
- Revision: lunInfo.Revision,
- Status: lunInfo.OperationalState[0],
- }
- }
- }
- for i := 0; i < len(moHost.Config.StorageDevice.ScsiTopology.Adapter); i += 1 {
- ad := moHost.Config.StorageDevice.ScsiTopology.Adapter[i]
- adapter := adapterTable[ad.Adapter]
- for j := 0; j < len(ad.Target); j += 1 {
- t := ad.Target[j]
- key := t.Lun[0].ScsiLun
- if _, ok := enclosuresTable[key]; ok {
- adapter.Enclosure = int(t.Target)
- } else if _, ok := driversTable[key]; ok {
- driver := driversTable[key]
- driver.Slot = int(t.Target)
- adapter.Drivers = append(adapter.Drivers, driver)
- }
- }
- }
- return adapterList
- }
- func (host *SHost) GetStorageSizeMB() int64 {
- storages, err := host.GetIStorages()
- if err != nil {
- log.Errorf("SHost.GetStorageSizeMB: SHost.GetIStorages: %s", err)
- return 0
- }
- var size int64
- for _, stor := range storages {
- size += stor.GetCapacityMB()
- }
- return size
- }
- func (host *SHost) GetStorageType() string {
- ssd := 0
- rotate := 0
- storages := host.getStorageInfo()
- for i := 0; i < len(storages); i += 1 {
- if storages[i].Rotate {
- rotate += 1
- } else {
- ssd += 1
- }
- }
- if ssd == 0 && rotate > 0 {
- return api.DISK_TYPE_ROTATE
- } else if ssd > 0 && rotate == 0 {
- return api.DISK_TYPE_SSD
- } else {
- return api.DISK_TYPE_HYBRID
- }
- }
- func (host *SHost) GetHostType() string {
- return api.HOST_TYPE_ESXI
- }
- func (host *SHost) GetIsMaintenance() bool {
- moHost := host.getHostSystem()
- return moHost.Summary.Runtime.InMaintenanceMode
- }
- func (host *SHost) GetVersion() string {
- moHost := host.getHostSystem()
- about := moHost.Summary.Config.Product
- return fmt.Sprintf("%s-%s", about.Version, about.Build)
- }
- func (host *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) {
- return nil, cloudprovider.ErrNotImplemented
- }
- type SCreateVMParam struct {
- Name string
- Desc string `json:"description"`
- Uuid string
- OsName string
- CpuSockets int
- Cpu int
- Mem int
- Bios string
- Cdrom SCdromInfo
- Disks []SDiskInfo
- Nics []jsonutils.JSONObject
- ProjectId string
- ResourcePool string
- InstanceSnapshotInfo SEsxiInstanceSnapshotInfo
- EnableEsxiSwap bool
- }
- type SEsxiInstanceSnapshotInfo struct {
- InstanceSnapshotId string
- InstanceId string
- }
- type SCdromInfo struct {
- ImageId string
- Path string
- Name string
- Size string
- }
- type SDiskInfo struct {
- ImagePath string
- Size int64
- DiskId string
- Driver string
- ImageInfo SEsxiImageInfo
- StorageId string
- Preallocation string
- }
- type SEsxiImageInfo struct {
- ImageType string
- ImageExternalId string
- StorageCacheHostIp string
- }
- func (host *SHost) CreateVM2(ctx context.Context, ds *SDatastore, params SCreateVMParam) (needDeploy bool, vm *SVirtualMachine, err error) {
- needDeploy = true
- var temvm *SVirtualMachine
- if len(params.InstanceSnapshotInfo.InstanceSnapshotId) > 0 {
- temvm, err = host.manager.SearchVM(params.InstanceSnapshotInfo.InstanceId)
- if err != nil {
- err = errors.Wrapf(err, "can't find vm %q, please sync status for vm or sync cloudaccount", params.InstanceSnapshotInfo.InstanceId)
- }
- var isp cloudprovider.ICloudInstanceSnapshot
- isp, err = temvm.GetInstanceSnapshot(params.InstanceSnapshotInfo.InstanceSnapshotId)
- if err != nil {
- err = errors.Wrap(err, "unable to GetInstanceSnapshot")
- return
- }
- sp := isp.(*SVirtualMachineSnapshot)
- vm, err = host.CloneVM(ctx, temvm, &sp.snapshotTree.Snapshot, ds, params)
- return
- }
- if len(params.Disks) == 0 {
- err = errors.Error("empty disk config")
- return
- }
- imageInfo := params.Disks[0].ImageInfo
- if imageInfo.ImageType == string(cloudprovider.ImageTypeSystem) {
- temvm, err = host.manager.SearchTemplateVM(imageInfo.ImageExternalId)
- if err != nil {
- err = errors.Wrapf(err, "SEsxiClient.SearchTemplateVM for image %q", imageInfo.ImageExternalId)
- return
- }
- vm, err = host.CloneVM(ctx, temvm, nil, ds, params)
- return
- }
- return host.DoCreateVM(ctx, ds, params)
- }
- func (host *SHost) SearchTemplateVM(id string) (*SVirtualMachine, error) {
- return host.manager.SearchTemplateVM(id)
- }
- func (host *SHost) needScsi(disks []SDiskInfo) bool {
- if len(disks) == 0 {
- return false
- }
- for i := range disks {
- driver := disks[i].Driver
- if driver == "" || driver == "scsi" || driver == "pvscsi" {
- return true
- }
- }
- return false
- }
- func (host *SHost) addDisks(ctx context.Context, ds *SDatastore, disks []SDiskInfo, uuid string, objectVm *object.VirtualMachine) (*SVirtualMachine, error) {
- getVM := func() (*SVirtualMachine, error) {
- var moVM mo.VirtualMachine
- err := host.manager.reference2Object(objectVm.Reference(), VIRTUAL_MACHINE_PROPS, &moVM)
- if err != nil {
- return nil, errors.Wrap(err, "fail to fetch virtual machine just created")
- }
- evm := NewVirtualMachine(host.manager, &moVM, host.datacenter)
- if evm == nil {
- return nil, errors.Error("create successfully but unable to NewVirtualMachine")
- }
- return evm, nil
- }
- if len(disks) == 0 {
- return getVM()
- }
- var (
- scsiIdx = 0
- ideIdx = 0
- ide1un = 0
- ide2un = 1
- unitNumber = 0
- ctrlKey = 0
- )
- deviceChange := make([]types.BaseVirtualDeviceConfigSpec, 0, 1)
- // add disks
- var rootDiskSizeMb int64
- for i, disk := range disks {
- imagePath := disk.ImagePath
- var size = disk.Size
- if len(imagePath) == 0 {
- if size == 0 {
- size = 30 * 1024
- }
- } else {
- var err error
- imagePath, err = host.FileUrlPathToDsPath(imagePath)
- if err != nil {
- return nil, errors.Wrapf(err, "SHost.FileUrlPathToDsPath")
- }
- newImagePath := fmt.Sprintf("[%s] %s/%s.vmdk", ds.GetRelName(), uuid, uuid)
- err = host.copyVirtualDisk(imagePath, newImagePath, disk.Driver, disk.Preallocation)
- if err != nil {
- return nil, err
- }
- imagePath = newImagePath
- rootDiskSizeMb = size
- }
- uuid, driver := disk.DiskId, "scsi"
- if len(disk.Driver) > 0 {
- driver = disk.Driver
- }
- if driver == "scsi" || driver == "pvscsi" {
- if host.isVersion50() {
- driver = "scsi"
- }
- ctrlKey = 1000
- unitNumber = scsiIdx
- scsiIdx += 1
- if scsiIdx == 7 {
- scsiIdx++
- }
- } else {
- ideno := ideIdx % 2
- if ideno == 0 {
- unitNumber = ideIdx/2 + ide1un
- } else {
- unitNumber = ideIdx/2 + ide2un
- }
- ctrlKey = 200 + ideno
- ideIdx += 1
- }
- var tds *SDatastore
- var err error
- if disk.StorageId != "" {
- tds, err = host.FindDataStoreById(disk.StorageId)
- if err != nil {
- return nil, errors.Wrapf(err, "unable to find ds %s from host %s", disk.StorageId, host.masterIp)
- }
- } else {
- tds = ds
- }
- vds, err := tds.getDatastoreObj(ctx)
- if err != nil {
- return nil, errors.Wrapf(err, "getDatastoreObj")
- }
- log.Debugf("ds: %s, size: %d, image path: %s, uuid: %s, index: %d, preallocation: %s, ctrlKey: %d, driver: %s, key: %d.", vds.String(), size, imagePath, uuid, unitNumber, disk.Preallocation, ctrlKey, disk.Driver, 2000+i)
- diskDev, err := NewDiskDev(ctx, size, SDiskConfig{
- SizeMb: size,
- Uuid: uuid,
- ControllerKey: int32(ctrlKey),
- UnitNumber: int32(unitNumber),
- Key: int32(2000 + i),
- ImagePath: imagePath,
- IsRoot: i == 0,
- Datastore: tds,
- Preallocation: disk.Preallocation,
- })
- if err != nil {
- return nil, errors.Wrapf(err, "NewDiskDev")
- }
- spec := addDevSpec(diskDev)
- if len(imagePath) == 0 {
- spec.FileOperation = "create"
- }
- deviceChange = append(deviceChange, spec)
- }
- log.Infof("deviceChange: %s", jsonutils.Marshal(deviceChange))
- configSpec := types.VirtualMachineConfigSpec{}
- configSpec.DeviceChange = deviceChange
- task, err := objectVm.Reconfigure(ctx, configSpec)
- if err != nil {
- return nil, errors.Wrap(err, "unable to reconfigure")
- }
- err = task.Wait(ctx)
- if err != nil {
- return nil, errors.Wrap(err, "task.Wait")
- }
- evm, err := getVM()
- if err != nil {
- return nil, err
- }
- // resize root disk
- if rootDiskSizeMb > 0 && int64(evm.vdisks[0].GetDiskSizeMB()) != rootDiskSizeMb {
- err = evm.vdisks[0].Resize(ctx, rootDiskSizeMb)
- if err != nil {
- return evm, errors.Wrap(err, "resize for root disk")
- }
- }
- return evm, nil
- }
- func (host *SHost) copyVirtualDisk(srcPath, dstPath, diskDriver, preallocation string) error {
- dm := object.NewVirtualDiskManager(host.manager.client.Client)
- spec := &types.VirtualDiskSpec{
- DiskType: string(types.VirtualDiskTypeThin),
- }
- switch diskDriver {
- case "", "scsi", "pvscsi":
- spec.AdapterType = "lsiLogic"
- default:
- spec.AdapterType = "ide"
- }
- task, err := dm.CopyVirtualDisk(host.manager.context, srcPath, host.datacenter.getDcObj(), dstPath, host.datacenter.getDcObj(), spec, true)
- if err != nil {
- return errors.Wrap(err, "unable to CopyVirtualDisk")
- }
- err = task.Wait(host.manager.context)
- if err == nil {
- return nil
- }
- errStr := strings.ToLower(err.Error())
- if !strings.Contains(errStr, "the requested operation is not implemented by the server") {
- return errors.Wrap(err, "wait CopyVirtualDiskTask")
- }
- task, err = dm.CopyVirtualDisk(host.manager.context, srcPath, host.datacenter.getDcObj(), dstPath, host.datacenter.getDcObj(), nil, true)
- if err != nil {
- return errors.Wrap(err, "unable to CopyVirtualDisk")
- }
- err = task.Wait(host.manager.context)
- if err != nil {
- return errors.Wrap(err, "wait CopyVirtualDiskTask")
- }
- if preallocation == api.DISK_PREALLOCATION_FULL || preallocation == api.DISK_PREALLOCATION_FALLOC {
- err = func() error {
- task, err = dm.InflateVirtualDisk(host.manager.context, dstPath, host.datacenter.getDcObj())
- if err != nil {
- return errors.Wrap(err, "unable to InflateVirtualDisk")
- }
- err = task.Wait(host.manager.context)
- if err != nil {
- return errors.Wrap(err, "wait InflateVirtualDiskTask")
- }
- return nil
- }()
- if err != nil {
- log.Errorf("inflate disk %s failed: %s", dstPath, err)
- }
- }
- return nil
- }
- func (host *SHost) DoCreateVM(ctx context.Context, ds *SDatastore, params SCreateVMParam) (needDeploy bool, vm *SVirtualMachine, err error) {
- needDeploy = true
- deviceChange := make([]types.BaseVirtualDeviceConfigSpec, 0, 5)
- name := params.Name
- if len(params.Uuid) > 0 {
- name = params.Uuid
- }
- datastorePath := fmt.Sprintf("[%s] ", ds.GetRelName())
- firmware := ""
- if len(params.Bios) != 0 {
- switch params.Bios {
- case "BIOS":
- firmware = "bios"
- case "UEFI":
- firmware = "efi"
- }
- }
- guestId := "rhel6_64Guest"
- if params.OsName == "Windows" {
- guestId = "windows7Server64Guest"
- }
- version := host.getVmVersion()
- if params.CpuSockets == 0 {
- params.CpuSockets = 1
- }
- perSocket := params.Cpu / params.CpuSockets
- spec := types.VirtualMachineConfigSpec{
- Name: name,
- Annotation: params.Desc,
- Version: version,
- Uuid: params.Uuid,
- GuestId: guestId,
- NumCPUs: int32(params.Cpu),
- NumCoresPerSocket: int32(perSocket),
- MemoryMB: int64(params.Mem),
- Firmware: firmware,
- CpuHotAddEnabled: &True,
- CpuHotRemoveEnabled: &True,
- MemoryHotAddEnabled: &True,
- ExtraConfig: []types.BaseOptionValue{},
- }
- if !params.EnableEsxiSwap {
- spec.ExtraConfig = append(spec.ExtraConfig, &types.OptionValue{
- Key: "sched.swap.vmxSwapEnabled",
- Value: "FALSE",
- })
- }
- spec.Files = &types.VirtualMachineFileInfo{
- VmPathName: datastorePath,
- }
- deviceChange = append(deviceChange, addDevSpec(NewIDEDev(200, 0)))
- deviceChange = append(deviceChange, addDevSpec(NewIDEDev(200, 1)))
- deviceChange = append(deviceChange, addDevSpec(NewSVGADev(500, 100)))
- if host.needScsi(params.Disks) {
- driver := "pvscsi"
- if host.isVersion50() {
- driver = "scsi"
- }
- deviceChange = append(deviceChange, addDevSpec(NewSCSIDev(1000, 100, driver)))
- }
- cdromPath := params.Cdrom.Path
- if len(cdromPath) > 0 {
- needDeploy = false
- cdromPath, err = host.FileUrlPathToDsPath(cdromPath)
- if err != nil {
- err = errors.Wrapf(err, "SHost.FileUrlPathToDsPath for cdrom path")
- return
- }
- }
- deviceChange = append(deviceChange, addDevSpec(NewCDROMDev(cdromPath, 16000, 201)))
- // add usb to support mouse
- usbController := addDevSpec(NewUSBController(nil))
- deviceChange = append(deviceChange, usbController)
- nics := params.Nics
- for _, nic := range nics {
- index, _ := nic.Int("index")
- mac, _ := nic.GetString("mac")
- bridge, _ := nic.GetString("bridge")
- driver := "e1000"
- if nic.Contains("driver") {
- driver, _ = nic.GetString("driver")
- }
- if host.isVersion50() {
- driver = "e1000"
- }
- var vlanId int64 = 1
- if nic.Contains("vlan") {
- vlanId, _ = nic.Int("vlan")
- }
- dev, err := NewVNICDev(host, mac, driver, bridge, int32(vlanId), 4000, 100, int32(index))
- if err != nil {
- return needDeploy, nil, errors.Wrap(err, "NewVNICDev")
- }
- deviceChange = append(deviceChange, addDevSpec(dev))
- }
- spec.DeviceChange = deviceChange
- dc, err := host.GetDatacenter()
- if err != nil {
- err = errors.Wrapf(err, "SHost.GetDatacenter for host '%s'", host.GetId())
- return
- }
- vmFolder, err := dc.GetFolder(params.ProjectId)
- if err != nil {
- err = errors.Wrap(err, "GetFolder")
- return
- }
- pool, err := host.SyncResourcePool(params.ResourcePool)
- if err != nil {
- err = errors.Wrap(err, "GetResourcePool")
- return
- }
- task, err := vmFolder.CreateVM(ctx, spec, pool, host.GetHostSystem())
- if err != nil {
- err = errors.Wrap(err, "VmFolder.Create")
- return
- }
- info, err := task.WaitForResult(ctx, nil)
- if err != nil {
- err = errors.Wrap(err, "Task.WaitForResult")
- return
- }
- vmRef := info.Result.(types.ManagedObjectReference)
- objectVM := object.NewVirtualMachine(host.manager.client.Client, vmRef)
- uuid := params.Uuid
- if len(uuid) == 0 {
- uuid = params.Name
- }
- vm, err = host.addDisks(ctx, ds, params.Disks, uuid, objectVM)
- return
- }
- // If snapshot is not nil, params.Disks will be ignored
- func (host *SHost) CloneVM(ctx context.Context, from *SVirtualMachine, snapshot *types.ManagedObjectReference, ds *SDatastore, params SCreateVMParam) (*SVirtualMachine, error) {
- ovm := from.getVmObj()
- deviceChange := make([]types.BaseVirtualDeviceConfigSpec, 0, 3)
- macAddrs := []string{}
- for _, nic := range params.Nics {
- index, _ := nic.Int("index")
- mac, _ := nic.GetString("mac")
- macAddrs = append(macAddrs, mac)
- bridge, _ := nic.GetString("bridge")
- driver := "e1000"
- if nic.Contains("driver") {
- driver, _ = nic.GetString("driver")
- }
- if host.isVersion50() {
- driver = "e1000"
- }
- var vlanId int64 = 1
- if nic.Contains("vlan") {
- vlanId, _ = nic.Int("vlan")
- }
- dev, err := NewVNICDev(host, mac, driver, bridge, int32(vlanId), 4000, 100, int32(index))
- if err != nil {
- return nil, errors.Wrap(err, "NewVNICDev")
- }
- deviceChange = append(deviceChange, &types.VirtualDeviceConfigSpec{
- Operation: types.VirtualDeviceConfigSpecOperationAdd,
- Device: dev,
- })
- }
- if len(params.Disks) > 0 && snapshot == nil {
- driver := params.Disks[0].Driver
- if driver == "scsi" || driver == "pvscsi" {
- scsiDevs, err := from.FindController(ctx, "scsi")
- if err != nil {
- return nil, errors.Wrap(err, "SVirtualMachine.FindController")
- }
- if len(scsiDevs) == 0 {
- key := from.FindMinDiffKey(1000)
- driver := "pvscsi"
- if host.isVersion50() {
- driver = "scsi"
- }
- deviceChange = append(deviceChange, addDevSpec(NewSCSIDev(key, 100, driver)))
- }
- } else {
- ideDevs, err := from.FindController(ctx, "ide")
- if err != nil {
- return nil, errors.Wrap(err, "SVirtualMachine.FindController")
- }
- if len(ideDevs) == 0 {
- // add ide driver
- deviceChange = append(deviceChange, addDevSpec(NewIDEDev(200, 0)))
- }
- }
- }
- diskPreallocationChanged := false
- diskChanged := []types.VirtualMachineRelocateSpecDiskLocator{}
- idisks, _ := from.GetIDisks()
- for i, disk := range idisks {
- if i > len(params.Disks)-1 {
- break
- }
- if len(params.Disks[i].Preallocation) > 0 && params.Disks[i].Preallocation != disk.GetPreallocation() {
- diskPreallocationChanged = true
- }
- locator := types.VirtualMachineRelocateSpecDiskLocator{}
- tds, _ := host.FindDataStoreById(params.Disks[i].StorageId)
- if tds != nil {
- locator.Datastore = tds.object.Reference()
- }
- backing := &types.VirtualDiskFlatVer2BackingInfo{}
- switch params.Disks[i].Preallocation {
- case api.DISK_PREALLOCATION_OFF, api.DISK_PREALLOCATION_METADATA, "":
- backing.ThinProvisioned = types.NewBool(true)
- case api.DISK_PREALLOCATION_FALLOC:
- backing.ThinProvisioned = types.NewBool(false)
- backing.EagerlyScrub = types.NewBool(false)
- case api.DISK_PREALLOCATION_FULL:
- backing.ThinProvisioned = types.NewBool(false)
- backing.EagerlyScrub = types.NewBool(true)
- }
- locator.DiskId = int32(2000 + i)
- locator.DiskBackingInfo = backing
- diskChanged = append(diskChanged, locator)
- }
- dc, err := host.GetDatacenter()
- if err != nil {
- return nil, errors.Wrapf(err, "SHost.GetDatacenter for host '%s'", host.GetId())
- }
- vmFolder, err := dc.GetFolder(params.ProjectId)
- if err != nil {
- return nil, errors.Wrap(err, "GetFolder")
- }
- resourcePool, err := host.SyncResourcePool(params.ResourcePool)
- if err != nil {
- return nil, errors.Wrap(err, "SyncResourcePool")
- }
- poolref := resourcePool.Reference()
- hostref := host.GetHostSystem().Reference()
- tds, err := ds.getDatastoreObj(ctx)
- if err != nil {
- return nil, errors.Wrapf(err, "getDatastoreObj")
- }
- dsref := tds.Reference()
- vmFolderRef := vmFolder.Reference()
- relocateSpec := types.VirtualMachineRelocateSpec{
- Folder: &vmFolderRef,
- Pool: &poolref,
- Host: &hostref,
- Datastore: &dsref,
- }
- if diskPreallocationChanged {
- relocateSpec.Disk = diskChanged
- }
- cloneSpec := &types.VirtualMachineCloneSpec{
- PowerOn: false,
- Template: false,
- Location: relocateSpec,
- Snapshot: snapshot,
- }
- // uuid first
- name := params.Name
- if len(params.Uuid) != 0 {
- name = params.Uuid
- }
- if params.CpuSockets == 0 {
- params.CpuSockets = 1
- }
- perSocket := params.Cpu / params.CpuSockets
- spec := types.VirtualMachineConfigSpec{
- Name: name,
- Annotation: params.Desc,
- Uuid: params.Uuid,
- NumCPUs: int32(params.Cpu),
- NumCoresPerSocket: int32(perSocket),
- MemoryMB: int64(params.Mem),
- CpuHotAddEnabled: &True,
- CpuHotRemoveEnabled: &True,
- MemoryHotAddEnabled: &True,
- ExtraConfig: []types.BaseOptionValue{},
- Firmware: "bios",
- }
- if from.GetBios() == cloudprovider.UEFI {
- spec.Firmware = "efi"
- }
- if !params.EnableEsxiSwap {
- spec.ExtraConfig = append(spec.ExtraConfig, &types.OptionValue{
- Key: "sched.swap.vmxSwapEnabled",
- Value: "FALSE",
- })
- }
- cloneSpec.Config = &spec
- task, err := ovm.Clone(ctx, vmFolder, name, *cloneSpec)
- if err != nil {
- return nil, errors.Wrap(err, "object.VirtualMachine.Clone")
- }
- info, err := task.WaitForResult(ctx, nil)
- if err != nil {
- return nil, errors.Wrap(err, "Task.WaitForResult")
- }
- var moVM mo.VirtualMachine
- err = host.manager.reference2Object(info.Result.(types.ManagedObjectReference), VIRTUAL_MACHINE_PROPS, &moVM)
- if err != nil {
- return nil, errors.Wrap(err, "fail to fetch virtual machine just created")
- }
- vm := NewVirtualMachine(host.manager, &moVM, host.datacenter)
- if vm == nil {
- return nil, errors.Error("clone successfully but unable to NewVirtualMachine")
- }
- // remove old nics
- svm := vm.getVirtualMachine()
- for i := range svm.Config.Hardware.Device {
- dev := svm.Config.Hardware.Device[i]
- devType := reflect.Indirect(reflect.ValueOf(dev)).Type()
- etherType := reflect.TypeOf((*types.VirtualEthernetCard)(nil)).Elem()
- if reflectutils.StructContains(devType, etherType) {
- nic := NewVirtualNIC(vm, dev, i)
- if !utils.IsInStringArray(nic.GetMAC(), macAddrs) {
- deviceChange = append(deviceChange, &types.VirtualDeviceConfigSpec{
- Operation: types.VirtualDeviceConfigSpecOperationRemove,
- Device: nic.getVirtualEthernetCard(),
- })
- }
- }
- }
- if snapshot != nil {
- return vm, nil
- }
- // adjust disk
- var i int
- if len(params.Disks) > 0 {
- // resize system disk
- sysDiskSize := params.Disks[0].Size
- if sysDiskSize == 0 {
- sysDiskSize = 30 * 1024
- }
- if int64(vm.vdisks[0].GetDiskSizeMB()) != sysDiskSize {
- vdisk := vm.vdisks[0].getVirtualDisk()
- originSize := vdisk.CapacityInKB
- vdisk.CapacityInKB = sysDiskSize * 1024
- spec := &types.VirtualDeviceConfigSpec{}
- spec.Operation = types.VirtualDeviceConfigSpecOperationEdit
- spec.Device = vdisk
- deviceChange = append(deviceChange, spec)
- log.Infof("resize system disk: %dGB => %dGB", originSize/1024/1024, sysDiskSize/1024)
- }
- // resize existed disk
- for i = 1; i < len(params.Disks); i++ {
- if i >= len(vm.vdisks) {
- break
- }
- wantDisk := params.Disks[i]
- vdisk := vm.vdisks[i]
- modisk := vdisk.getVirtualDisk()
- if wantDisk.Size <= int64(vdisk.GetDiskSizeMB()) {
- continue
- }
- originSize := modisk.CapacityInKB
- modisk.CapacityInKB = wantDisk.Size * 1024
- spec := &types.VirtualDeviceConfigSpec{}
- spec.Operation = types.VirtualDeviceConfigSpecOperationEdit
- spec.Device = vdisk.dev
- deviceChange = append(deviceChange, spec)
- log.Infof("resize No.%d data disk: %dGB => %dGB", i, originSize/1024/1024, wantDisk.Size/1024)
- }
- // remove extra disk
- for ; i < len(vm.vdisks); i++ {
- vdisk := vm.vdisks[i]
- spec := &types.VirtualDeviceConfigSpec{}
- spec.Operation = types.VirtualDeviceConfigSpecOperationRemove
- spec.Device = vdisk.dev
- spec.FileOperation = types.VirtualDeviceConfigSpecFileOperationDestroy
- deviceChange = append(deviceChange, spec)
- log.Infof("remove No.%d data disk", i)
- }
- if len(deviceChange) > 0 {
- spec = types.VirtualMachineConfigSpec{}
- spec.DeviceChange = deviceChange
- task, err = vm.getVmObj().Reconfigure(ctx, spec)
- if err != nil {
- return vm, errors.Wrap(err, "Reconfigure to resize disks")
- }
- err = task.Wait(ctx)
- if err != nil {
- return vm, errors.Wrap(err, "Wait task to resize disks")
- }
- }
- }
- // add data disk
- for ; i < len(params.Disks); i++ {
- size := params.Disks[i].Size
- if size == 0 {
- size = 30 * 1024
- }
- uuid := params.Disks[i].DiskId
- driver := params.Disks[i].Driver
- opts := &cloudprovider.GuestDiskCreateOptions{
- SizeMb: int(size),
- UUID: uuid,
- Driver: driver,
- StorageId: params.Disks[i].StorageId,
- Preallocation: params.Disks[i].Preallocation,
- }
- _, err := vm.CreateDisk(ctx, opts)
- if err != nil {
- log.Errorf("unable to add No.%d disk for vm %s", i, vm.GetId())
- return vm, nil
- }
- }
- task, err = vm.getVmObj().UpgradeVM(ctx, host.getVmVersion())
- if err != nil {
- log.Errorf("upgrade vm %s error: %v", vm.GetName(), err)
- return vm, nil
- }
- err = task.Wait(ctx)
- if err != nil {
- log.Errorf("wait vm %s upgrade error: %v", vm.GetName(), err)
- return vm, nil
- }
- return vm, nil
- }
- func (host *SHost) changeNic(device types.BaseVirtualDevice, update types.BaseVirtualDevice) {
- current := device.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard()
- changed := update.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard()
- current.Backing = changed.Backing
- if changed.MacAddress != "" {
- current.MacAddress = changed.MacAddress
- }
- if changed.AddressType != "" {
- current.AddressType = changed.AddressType
- }
- }
- func (host *SHost) isVersion50() bool {
- version := host.GetVersion()
- return strings.HasPrefix(version, "5.")
- }
- func (host *SHost) getVmVersion() string {
- ver := func() string {
- version := host.GetVersion()
- if len(version) >= 3 {
- return version[:3]
- }
- return version
- }()
- version, ok := map[string]string{
- "5.0": "vmx-08",
- "5.1": "vmx-09",
- "5.5": "vmx-10",
- "6.0": "vmx-11",
- "6.5": "vmx-13",
- "6.7": "vmx-14",
- "7.0": "vmx-17",
- }[ver]
- if ok {
- return version
- }
- return "vmx-10"
- }
- func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) {
- nics, err := host.GetIHostNicsInternal(false)
- if err != nil {
- return nil, errors.Wrap(err, "GetIHostNicsInternal")
- }
- return nics, nil
- }
- func (host *SHost) GetIHostNicsInternal(debug bool) ([]cloudprovider.ICloudHostNetInterface, error) {
- nics := host.getNicInfo(debug)
- inics := make([]cloudprovider.ICloudHostNetInterface, len(nics))
- for i := 0; i < len(nics); i += 1 {
- inics[i] = &nics[i]
- }
- return inics, nil
- }
- func (host *SHost) getLocalStorageCache() (*SDatastoreImageCache, error) {
- if host.storageCache == nil {
- sc, err := host.newLocalStorageCache()
- if err != nil {
- return nil, err
- }
- host.storageCache = sc
- }
- return host.storageCache, nil
- }
- func (host *SHost) newLocalStorageCache() (*SDatastoreImageCache, error) {
- ctx := context.Background()
- istorages, err := host.GetIStorages()
- if err != nil {
- return nil, err
- }
- var errmsg string
- var cacheDs *SDatastore
- var maxDs *SDatastore
- var maxCapacity int64
- for i := 0; i < len(istorages); i += 1 {
- ds := istorages[i].(*SDatastore)
- if !ds.isLocalVMFS() {
- continue
- }
- _, err := ds.CheckFile(ctx, IMAGE_CACHE_DIR_NAME)
- if err != nil {
- if errors.Cause(err) != cloudprovider.ErrNotFound {
- // return nil, err
- if len(errmsg) > 0 {
- errmsg += ","
- }
- errmsg += err.Error()
- } else if maxCapacity < ds.GetCapacityMB() {
- maxCapacity = ds.GetCapacityMB()
- maxDs = ds
- }
- } else {
- cacheDs = ds
- break
- }
- }
- if cacheDs == nil {
- // if no existing image cache dir found, use the one with maximal capacilty
- cacheDs = maxDs
- }
- if cacheDs == nil {
- return nil, fmt.Errorf("%s", errmsg)
- }
- return &SDatastoreImageCache{
- datastore: cacheDs,
- host: host,
- }, nil
- }
- func (host *SHost) GetManagementServerIp() string {
- return host.getHostSystem().Summary.ManagementServerIp
- }
- func (host *SHost) IsManagedByVCenter() bool {
- return len(host.getHostSystem().Summary.ManagementServerIp) > 0
- }
- func (host *SHost) FindDataStoreById(id string) (*SDatastore, error) {
- datastores, err := host.GetDataStores()
- if err != nil {
- return nil, err
- }
- for i := range datastores {
- if datastores[i].GetGlobalId() == id {
- return datastores[i].(*SDatastore), nil
- }
- }
- return nil, fmt.Errorf("no such datastore %s", id)
- }
- func (host *SHost) GetDataStores() ([]cloudprovider.ICloudStorage, error) {
- err := host.fetchDatastores()
- if err != nil {
- return nil, err
- }
- return host.datastores, nil
- }
- func (host *SHost) fetchDatastores() error {
- if host.datastores != nil {
- return nil
- }
- dc, err := host.GetDatacenter()
- if err != nil {
- return err
- }
- dss := host.getHostSystem().Datastore
- var datastores []mo.Datastore
- err = host.manager.references2Objects(dss, DATASTORE_PROPS, &datastores)
- if err != nil {
- return err
- }
- host.datastores = make([]cloudprovider.ICloudStorage, 0)
- for i := 0; i < len(datastores); i += 1 {
- ds := NewDatastore(host.manager, &datastores[i], dc)
- dsId := ds.GetGlobalId()
- if len(dsId) > 0 {
- host.datastores = append(host.datastores, ds)
- }
- }
- return nil
- }
- func (host *SHost) FileUrlPathToDsPath(path string) (string, error) {
- var newPath string
- dss, err := host.GetDataStores()
- if err != nil {
- return newPath, err
- }
- for _, ds := range dss {
- rds := ds.(*SDatastore)
- log.Debugf("rds: %s", rds.GetUrl())
- if strings.HasPrefix(path, rds.GetUrl()) {
- newPath = fmt.Sprintf("[%s] %s", rds.GetRelName(), path[len(rds.GetUrl()):])
- break
- }
- }
- if len(newPath) == 0 {
- return newPath, fmt.Errorf("path '%s' don't belong any datastore of host '%s'", path, host.GetName())
- }
- return newPath, nil
- }
- // IsActiveVlanID will detect if vlanID is active that means vlanID in (1, 4095).
- func (host *SHost) IsActiveVlanID(vlanID int32) bool {
- if vlanID > 1 && vlanID < 4095 {
- return true
- }
- return false
- }
- func (host *SHost) getBasicNetworks() ([]IVMNetwork, error) {
- nets, err := host.GetNetworks()
- if err != nil {
- return nil, errors.Wrap(err, "GetNetworks")
- }
- ret := make([]IVMNetwork, 0)
- for i := range nets {
- if net, ok := nets[i].(*SNetwork); ok {
- ret = append(ret, net)
- }
- }
- return ret, nil
- }
- func (host *SHost) GetNetworks() ([]IVMNetwork, error) {
- if host.networks != nil {
- return host.networks, nil
- }
- dc, err := host.GetDatacenter()
- if err != nil {
- return nil, errors.Wrap(err, "GetDatacenter")
- }
- nets, err := dc.resolveNetworks(host.getHostSystem().Network)
- if err != nil {
- return nil, errors.Wrap(err, "resolveNetworks")
- }
- host.networks = nets
- return host.networks, nil
- }
- func (host *SHost) getNetworkById(netId string) (IVMNetwork, error) {
- nets, err := host.GetNetworks()
- if err != nil {
- return nil, errors.Wrap(err, "host.GetNetworks")
- }
- for i := range nets {
- if nets[i].GetId() == netId {
- return nets[i], nil
- }
- }
- return nil, errors.ErrNotFound
- }
- func (host *SHost) findDVPGById(id string) (*SDistributedVirtualPortgroup, error) {
- nets, err := host.datacenter.GetNetworks()
- if err != nil {
- return nil, errors.Wrap(err, "SHost.datacenter.GetNetworks")
- }
- for _, net := range nets {
- if dvpg, ok := net.(*SDistributedVirtualPortgroup); ok && dvpg.GetId() == id {
- return dvpg, nil
- }
- }
- return nil, nil
- }
- func (host *SHost) GetHostSystem() *object.HostSystem {
- return object.NewHostSystem(host.manager.client.Client, host.getHostSystem().Reference())
- }
- func (host *SHost) GetResourcePool() (*object.ResourcePool, error) {
- var err error
- if host.parent == nil {
- host.parent, err = host.getParent()
- if err != nil {
- return nil, err
- }
- }
- return object.NewResourcePool(host.manager.client.Client, *host.parent.ResourcePool), nil
- }
- func (host *SHost) getParent() (*mo.ComputeResource, error) {
- var mcr *mo.ComputeResource
- var parent interface{}
- moHost := host.getHostSystem()
- switch moHost.Parent.Type {
- case "ComputeResource":
- mcr = new(mo.ComputeResource)
- parent = mcr
- case "ClusterComputeResource":
- mcc := new(mo.ClusterComputeResource)
- mcr = &mcc.ComputeResource
- parent = mcc
- default:
- return nil, errors.Error(fmt.Sprintf("unknown host parent type: %s", moHost.Parent.Type))
- }
- err := host.manager.reference2Object(*moHost.Parent, []string{"name", "resourcePool"}, parent)
- if err != nil {
- return nil, errors.Wrap(err, "SESXiClient.reference2Object")
- }
- return mcr, nil
- }
- func (host *SHost) SyncResourcePool(name string) (*object.ResourcePool, error) {
- if len(name) == 0 {
- return host.GetResourcePool()
- }
- cluster, err := host.GetCluster()
- if err != nil {
- return host.GetResourcePool()
- }
- return cluster.SyncResourcePool(name)
- }
- func (host *SHost) GetSiblingHosts() ([]*SHost, error) {
- rp, err := host.getParent()
- if err != nil {
- return nil, err
- }
- moHosts := make([]mo.HostSystem, 0, len(rp.Host))
- err = host.manager.references2Objects(rp.Host, HOST_SYSTEM_PROPS, &moHosts)
- if err != nil {
- return nil, errors.Wrap(err, "SESXiClient.references2Objects")
- }
- ret := make([]*SHost, len(moHosts))
- for i := range moHosts {
- ret[i] = NewHost(host.manager, &moHosts[i], host.datacenter)
- }
- return ret, nil
- }
|