host.go 49 KB

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